Contracts Overview
Relevant source files
The following files were used as context for generating this wiki page:
The dbt-common contracts system provides a robust framework for defining, validating, and merging configuration data and internal state structures. It leverages Python dataclasses combined with mashumaro for serialization and jsonschema for structural validation. This system ensures that configuration objects used across dbt-core and its adapters maintain high data integrity and consistent behavior.
At its core, the contracts module defines how configuration objects interact, how they are updated from raw dictionaries, and how different levels of configuration (e.g., project-level vs. adapter-level) are merged using specific behaviors like appending lists or updating dictionaries.
Sources: dbt_common/contracts/config/base.py, dbt_common/dataclass_schema.py
Core Architecture and Data Schema
The foundation of the contracts system is the dbtClassMixin, which integrates serialization and validation logic into standard Python dataclasses. This mixin provides the mechanism to generate JSON schemas from class definitions and validate data against those schemas.
Schema Validation and Serialization
The system uses mashumaro to handle the conversion between Python objects and JSON-encodable dictionaries. A custom configuration class, dbtMashConfig, defines serialization strategies for specific types, such as datetime (using ISO format with UTC assumption) and bool (ensuring uncoerced types for strict validation).
Sources: dbt_common/dataclass_schema.py:46-86
The diagram shows the inheritance structure where BaseConfig serves as the primary base for all configuration objects, inheriting validation, extra property handling, and replacement capabilities.
Sources: dbt_common/contracts/config/base.py:20-25, dbt_common/dataclass_schema.py:82-95
Configuration Management
The BaseConfig class implements dictionary-like access to dataclass fields, allowing developers to interact with config objects using keys while maintaining type safety.
Field Access Logic
The get method provides a prioritized lookup strategy for configuration values:
- It first checks if the key exists as a formal attribute/field of the dataclass.
- If not found, it checks the
_extradictionary (for additional properties). - If still not found, it checks the
metaattribute. If a key is found only inmeta, aGetMetaKeyWarningis fired to encourage explicit metadata access methods.
Sources: dbt_common/contracts/config/base.py:27-41
Merge Behaviors
Merging is a critical component of the contracts system, especially when combining project-level configurations with model-level or adapter-level overrides. The MergeBehavior enum defines five distinct strategies:
| Strategy | Description |
|---|---|
| Clobber | The new value completely overwrites the existing value. This is the default. |
| Append | Combines two lists (e.g., tags or hooks). |
| Update | Merges two dictionaries using the dict.update() method. |
| DictKeyAppend | Merges dictionaries where specific keys might represent lists that should be extended. |
| Object | Merges complex nested objects. |
| Sources: dbt_common/contracts/config/base.py:165-177, dbt_common/contracts/config/base.py:246-311 |
Data Flow: Configuration Updates
Updating a configuration object involves merging a raw input dictionary into an existing instance, validating the result, and returning a new instance.
This flow illustrates the update_from logic, which ensures that fields are merged according to their metadata-defined behaviors before the final object is validated and instantiated.
Sources: dbt_common/contracts/config/base.py:126-150
Metadata and Field Decoration
Behaviors for merging, comparing, and displaying fields are controlled via metadata attached to the dataclass fields.
Behavior Controls
- MergeBehavior: Defined in field metadata under the key
"merge". It determines howupdate_fromandmerge_config_dictshandle the field. - CompareBehavior: Defined under the key
"compare". It indicates whether a field should be considered when checking if two configuration objects have thesame_contents. - ShowBehavior: Controls the visibility of fields in specific contexts.
Sources: dbt_common/contracts/config/base.py:165-197, dbt_common/contracts/config/metadata.py
Example: Field Definition with Metadata
@dataclass
class ExampleConfig(BaseConfig):
tags: List[str] = field(
metadata={"merge": MergeBehavior.Append},
default_factory=list
)
meta: Dict[str, Any] = field(
metadata={"merge": MergeBehavior.Update},
default_factory=dict
)
Sources: dbt_common/contracts/config/base.py:250-260 (Derived logic)
Utility Types
The contracts system includes specialized helper types to manage common dbt patterns like inclusion/exclusion rules and error handling options.
IncludeExclude
The IncludeExclude class manages sets of items, allowing for explicit inclusion or exclusion, or the use of wildcards like * or all. It validates that a configuration does not attempt to both include and exclude specific items simultaneously (unless using a wildcard).
Sources: dbt_common/helper_types.py:13-39
WarnErrorOptions
This structure defines how dbt should treat specific events—whether they should be treated as errors, warnings, or silenced entirely. It supports specific event names as well as categories like Deprecations.
Sources: dbt_common/helper_types.py:42-126
Summary
The Contracts system in dbt-common provides a rigorous, metadata-driven approach to configuration management. By combining the flexibility of Python dataclasses with strict JSON schema validation and sophisticated merging logic, it allows dbt to handle complex, multi-layered configurations reliably across different adapters and environments.
Sources: dbt_common/contracts/config/base.py, dbt_common/dataclass_schema.py