Edit on GitHub

sqlmesh.core.config.base

  1from __future__ import annotations
  2
  3import typing as t
  4from enum import Enum, auto
  5
  6from sqlmesh.utils.errors import ConfigError
  7from sqlmesh.utils.pydantic import PydanticModel
  8
  9T = t.TypeVar("T", bound="BaseConfig")
 10
 11
 12class UpdateStrategy(Enum):
 13    """Supported strategies for adding new config to existing config"""
 14
 15    REPLACE = auto()  # Replace with new value
 16    EXTEND = auto()  # Extend list to existing list
 17    KEY_UPDATE = auto()  # Update dict key value with new dict key value
 18    KEY_EXTEND = auto()  # Extend dict key value to existing dict key value
 19    IMMUTABLE = auto()  # Raise if a key tries to change this value
 20    NESTED_UPDATE = auto()  # Recursively updates the nested config
 21
 22
 23def update_field(
 24    old: t.Optional[t.Any],
 25    new: t.Any,
 26    update_strategy: t.Optional[UpdateStrategy] = None,
 27) -> t.Any:
 28    """
 29    Update config field with new config value
 30
 31    Args:
 32        old: The existing config value
 33        new: The new config value
 34        update_strategy: The strategy to use when updating the field
 35
 36
 37        The updated field
 38    """
 39    if not old:
 40        return new
 41
 42    update_strategy = update_strategy or UpdateStrategy.REPLACE
 43
 44    if update_strategy == UpdateStrategy.IMMUTABLE:
 45        raise ConfigError(f"Cannot modify property: {old}.")
 46
 47    if update_strategy == UpdateStrategy.REPLACE:
 48        return new
 49    if update_strategy == UpdateStrategy.EXTEND:
 50        if not isinstance(old, list) or not isinstance(new, list):
 51            raise ConfigError("EXTEND behavior requires list field.")
 52
 53        return old + new
 54    if update_strategy == UpdateStrategy.KEY_UPDATE:
 55        if not isinstance(old, dict) or not isinstance(new, dict):
 56            raise ConfigError("KEY_UPDATE behavior requires dictionary field.")
 57
 58        combined = old.copy()
 59        combined.update(new)
 60        return combined
 61    if update_strategy == UpdateStrategy.KEY_EXTEND:
 62        if not isinstance(old, dict) or not isinstance(new, dict):
 63            raise ConfigError("KEY_EXTEND behavior requires dictionary field.")
 64
 65        combined = old.copy()
 66        for key, value in new.items():
 67            if not isinstance(value, list):
 68                raise ConfigError("KEY_EXTEND behavior requires list values in dictionary.")
 69
 70            old_value = combined.get(key)
 71            if old_value:
 72                if not isinstance(old_value, list):
 73                    raise ConfigError("KEY_EXTEND behavior requires list values in dictionary.")
 74
 75                combined[key] = old_value + value
 76            else:
 77                combined[key] = value
 78
 79        return combined
 80    if update_strategy == UpdateStrategy.NESTED_UPDATE:
 81        if not isinstance(old, BaseConfig):
 82            raise ConfigError(
 83                f"NESTED_UPDATE behavior requires a config object. {type(old)} was given instead."
 84            )
 85
 86        if type(new) != type(old):
 87            raise ConfigError(
 88                "NESTED_UPDATE behavior requires both values to have the same type. "
 89                f"{type(old)} and {type(new)} were given instead."
 90            )
 91
 92        return old.update_with(new)
 93
 94    raise ConfigError(f"Unknown update strategy {update_strategy}.")
 95
 96
 97class BaseConfig(PydanticModel):
 98    """Base configuration functionality for configuration classes."""
 99
100    _FIELD_UPDATE_STRATEGY: t.ClassVar[t.Dict[str, UpdateStrategy]] = {}
101
102    def update_with(self: T, other: t.Union[t.Dict[str, t.Any], T]) -> T:
103        """Updates this instance's fields with the passed in config fields and returns a new instance.
104
105        Args:
106            other: Other configuration.
107
108        Returns:
109            New instance updated with the passed in config fields
110        """
111        if isinstance(other, dict):
112            other = self.__class__(**other)
113
114        updated_fields = {}
115
116        for field in other.fields_set:
117            if field in self.all_field_infos():
118                updated_fields[field] = update_field(
119                    getattr(self, field),
120                    getattr(other, field),
121                    self._FIELD_UPDATE_STRATEGY.get(field),
122                )
123            else:
124                updated_fields[field] = getattr(other, field)
125
126        # Assign each field to trigger assignment validators
127        updated = self.copy()
128        for field, value in updated_fields.items():
129            setattr(updated, field, value)
130
131        return updated
class UpdateStrategy(enum.Enum):
13class UpdateStrategy(Enum):
14    """Supported strategies for adding new config to existing config"""
15
16    REPLACE = auto()  # Replace with new value
17    EXTEND = auto()  # Extend list to existing list
18    KEY_UPDATE = auto()  # Update dict key value with new dict key value
19    KEY_EXTEND = auto()  # Extend dict key value to existing dict key value
20    IMMUTABLE = auto()  # Raise if a key tries to change this value
21    NESTED_UPDATE = auto()  # Recursively updates the nested config

Supported strategies for adding new config to existing config

REPLACE = <UpdateStrategy.REPLACE: 1>
EXTEND = <UpdateStrategy.EXTEND: 2>
KEY_UPDATE = <UpdateStrategy.KEY_UPDATE: 3>
KEY_EXTEND = <UpdateStrategy.KEY_EXTEND: 4>
IMMUTABLE = <UpdateStrategy.IMMUTABLE: 5>
NESTED_UPDATE = <UpdateStrategy.NESTED_UPDATE: 6>
Inherited Members
enum.Enum
name
value
def update_field( old: Union[Any, NoneType], new: Any, update_strategy: Union[sqlmesh.core.config.base.UpdateStrategy, NoneType] = None) -> Any:
24def update_field(
25    old: t.Optional[t.Any],
26    new: t.Any,
27    update_strategy: t.Optional[UpdateStrategy] = None,
28) -> t.Any:
29    """
30    Update config field with new config value
31
32    Args:
33        old: The existing config value
34        new: The new config value
35        update_strategy: The strategy to use when updating the field
36
37
38        The updated field
39    """
40    if not old:
41        return new
42
43    update_strategy = update_strategy or UpdateStrategy.REPLACE
44
45    if update_strategy == UpdateStrategy.IMMUTABLE:
46        raise ConfigError(f"Cannot modify property: {old}.")
47
48    if update_strategy == UpdateStrategy.REPLACE:
49        return new
50    if update_strategy == UpdateStrategy.EXTEND:
51        if not isinstance(old, list) or not isinstance(new, list):
52            raise ConfigError("EXTEND behavior requires list field.")
53
54        return old + new
55    if update_strategy == UpdateStrategy.KEY_UPDATE:
56        if not isinstance(old, dict) or not isinstance(new, dict):
57            raise ConfigError("KEY_UPDATE behavior requires dictionary field.")
58
59        combined = old.copy()
60        combined.update(new)
61        return combined
62    if update_strategy == UpdateStrategy.KEY_EXTEND:
63        if not isinstance(old, dict) or not isinstance(new, dict):
64            raise ConfigError("KEY_EXTEND behavior requires dictionary field.")
65
66        combined = old.copy()
67        for key, value in new.items():
68            if not isinstance(value, list):
69                raise ConfigError("KEY_EXTEND behavior requires list values in dictionary.")
70
71            old_value = combined.get(key)
72            if old_value:
73                if not isinstance(old_value, list):
74                    raise ConfigError("KEY_EXTEND behavior requires list values in dictionary.")
75
76                combined[key] = old_value + value
77            else:
78                combined[key] = value
79
80        return combined
81    if update_strategy == UpdateStrategy.NESTED_UPDATE:
82        if not isinstance(old, BaseConfig):
83            raise ConfigError(
84                f"NESTED_UPDATE behavior requires a config object. {type(old)} was given instead."
85            )
86
87        if type(new) != type(old):
88            raise ConfigError(
89                "NESTED_UPDATE behavior requires both values to have the same type. "
90                f"{type(old)} and {type(new)} were given instead."
91            )
92
93        return old.update_with(new)
94
95    raise ConfigError(f"Unknown update strategy {update_strategy}.")

Update config field with new config value

Arguments:
  • old: The existing config value
  • new: The new config value
  • update_strategy: The strategy to use when updating the field
  • The updated field
class BaseConfig(sqlmesh.utils.pydantic.PydanticModel):
 98class BaseConfig(PydanticModel):
 99    """Base configuration functionality for configuration classes."""
100
101    _FIELD_UPDATE_STRATEGY: t.ClassVar[t.Dict[str, UpdateStrategy]] = {}
102
103    def update_with(self: T, other: t.Union[t.Dict[str, t.Any], T]) -> T:
104        """Updates this instance's fields with the passed in config fields and returns a new instance.
105
106        Args:
107            other: Other configuration.
108
109        Returns:
110            New instance updated with the passed in config fields
111        """
112        if isinstance(other, dict):
113            other = self.__class__(**other)
114
115        updated_fields = {}
116
117        for field in other.fields_set:
118            if field in self.all_field_infos():
119                updated_fields[field] = update_field(
120                    getattr(self, field),
121                    getattr(other, field),
122                    self._FIELD_UPDATE_STRATEGY.get(field),
123                )
124            else:
125                updated_fields[field] = getattr(other, field)
126
127        # Assign each field to trigger assignment validators
128        updated = self.copy()
129        for field, value in updated_fields.items():
130            setattr(updated, field, value)
131
132        return updated

Base configuration functionality for configuration classes.

def update_with(self: ~T, other: Union[Dict[str, Any], ~T]) -> ~T:
103    def update_with(self: T, other: t.Union[t.Dict[str, t.Any], T]) -> T:
104        """Updates this instance's fields with the passed in config fields and returns a new instance.
105
106        Args:
107            other: Other configuration.
108
109        Returns:
110            New instance updated with the passed in config fields
111        """
112        if isinstance(other, dict):
113            other = self.__class__(**other)
114
115        updated_fields = {}
116
117        for field in other.fields_set:
118            if field in self.all_field_infos():
119                updated_fields[field] = update_field(
120                    getattr(self, field),
121                    getattr(other, field),
122                    self._FIELD_UPDATE_STRATEGY.get(field),
123                )
124            else:
125                updated_fields[field] = getattr(other, field)
126
127        # Assign each field to trigger assignment validators
128        updated = self.copy()
129        for field, value in updated_fields.items():
130            setattr(updated, field, value)
131
132        return updated

Updates this instance's fields with the passed in config fields and returns a new instance.

Arguments:
  • other: Other configuration.
Returns:

New instance updated with the passed in config fields

def model_post_init(self: pydantic.main.BaseModel, _ModelMetaclass__context: Any) -> None:
102                    def wrapped_model_post_init(self: BaseModel, __context: Any) -> None:
103                        """We need to both initialize private attributes and call the user-defined model_post_init
104                        method.
105                        """
106                        init_private_attributes(self, __context)
107                        original_model_post_init(self, __context)

Override this method to perform additional initialization after __init__ and model_construct. This is useful if you want to do some validation that requires the entire model to be initialized.

Inherited Members
pydantic.main.BaseModel
BaseModel
model_extra
model_fields_set
model_construct
model_copy
model_dump
model_dump_json
model_json_schema
model_parametrized_name
model_rebuild
model_validate
model_validate_json
model_validate_strings
parse_file
from_orm
construct
schema
schema_json
validate
update_forward_refs
sqlmesh.utils.pydantic.PydanticModel
dict
json
copy
parse_obj
parse_raw
missing_required_fields
extra_fields
all_fields
all_field_infos
required_fields