Edit on GitHub

sqlmesh.core.config.common

  1from __future__ import annotations
  2
  3import typing as t
  4from enum import Enum
  5import re
  6
  7from sqlmesh.utils import classproperty
  8from sqlmesh.utils.errors import ConfigError
  9from sqlmesh.utils.pydantic import field_validator
 10
 11# Config files that can be present in the project dir
 12ALL_CONFIG_FILENAMES = ("config.py", "config.yml", "config.yaml", "sqlmesh.yml", "sqlmesh.yaml")
 13
 14# For personal paths (~/.sqlmesh/) where python config is not supported
 15YAML_CONFIG_FILENAMES = tuple(n for n in ALL_CONFIG_FILENAMES if not n.endswith(".py"))
 16
 17# Note: is here to prevent having to import from sqlmesh.dbt.loader which introduces a dependency
 18# on dbt-core in a native project
 19DBT_PROJECT_FILENAME = "dbt_project.yml"
 20
 21
 22class EnvironmentSuffixTarget(str, Enum):
 23    # Intended to create virtual environments in their own schemas, with names like "<model_schema_name>__<env name>". The view name is untouched.
 24    # For example, a model named 'sqlmesh_example.full_model' created in an environment called 'dev'
 25    # would have its virtual layer view created as 'sqlmesh_example__dev.full_model'
 26    SCHEMA = "schema"
 27
 28    # Intended to create virtual environments in the same schema as their production counterparts by adjusting the table name.
 29    # For example, a model named 'sqlmesh_example.full_model' created in an environment called 'dev'
 30    # would have its virtual layer view created as "sqlmesh_example.full_model__dev"
 31    TABLE = "table"
 32
 33    # Intended to create virtual environments in their own catalogs to preserve the schema and view name of the models
 34    # For example, a model named 'sqlmesh_example.full_model' created in an environment called 'dev'
 35    # with a default catalog of "warehouse" would have its virtual layer view created as "warehouse__dev.sqlmesh_example.full_model"
 36    # note: this only works for engines that can query across catalogs
 37    CATALOG = "catalog"
 38
 39    @property
 40    def is_schema(self) -> bool:
 41        return self == EnvironmentSuffixTarget.SCHEMA
 42
 43    @property
 44    def is_table(self) -> bool:
 45        return self == EnvironmentSuffixTarget.TABLE
 46
 47    @property
 48    def is_catalog(self) -> bool:
 49        return self == EnvironmentSuffixTarget.CATALOG
 50
 51    @classproperty
 52    def default(cls) -> EnvironmentSuffixTarget:
 53        return EnvironmentSuffixTarget.SCHEMA
 54
 55    def __str__(self) -> str:
 56        return self.name
 57
 58    def __repr__(self) -> str:
 59        return str(self)
 60
 61
 62class VirtualEnvironmentMode(str, Enum):
 63    """Mode for virtual environment behavior.
 64
 65    FULL: Use full virtual environment functionality with versioned table names and virtual layer updates.
 66    DEV_ONLY: Bypass virtual environments in production, using original unversioned model names.
 67    """
 68
 69    FULL = "full"
 70    DEV_ONLY = "dev_only"
 71
 72    @property
 73    def is_full(self) -> bool:
 74        return self == VirtualEnvironmentMode.FULL
 75
 76    @property
 77    def is_dev_only(self) -> bool:
 78        return self == VirtualEnvironmentMode.DEV_ONLY
 79
 80    @classproperty
 81    def default(cls) -> VirtualEnvironmentMode:
 82        return VirtualEnvironmentMode.FULL
 83
 84    def __str__(self) -> str:
 85        return self.name
 86
 87    def __repr__(self) -> str:
 88        return str(self)
 89
 90
 91class TableNamingConvention(str, Enum):
 92    # Causes table names at the physical layer to follow the convention:
 93    # <schema-name>__<table-name>__<fingerprint>
 94    SCHEMA_AND_TABLE = "schema_and_table"
 95
 96    # Causes table names at the physical layer to follow the convention:
 97    # <table-name>__<fingerprint>
 98    TABLE_ONLY = "table_only"
 99
100    # Takes the table name that would be returned from SCHEMA_AND_TABLE and wraps it in md5()
101    # to generate a hash and prefixes the has with `sqlmesh_md5__`, for the following reasons:
102    # - at a glance, you can still see it's managed by sqlmesh and that md5 was used to generate the hash
103    # - unquoted identifiers that start with numbers can trip up DB engine parsers, so having a text prefix prevents this
104    # This causes table names at the physical layer to follow the convention:
105    # sqlmesh_md5__3b07384d113edec49eaa6238ad5ff00d
106    HASH_MD5 = "hash_md5"
107
108    @classproperty
109    def default(cls) -> TableNamingConvention:
110        return TableNamingConvention.SCHEMA_AND_TABLE
111
112    def __str__(self) -> str:
113        return self.name
114
115    def __repr__(self) -> str:
116        return str(self)
117
118
119def _concurrent_tasks_validator(v: t.Any) -> int:
120    if isinstance(v, str):
121        v = int(v)
122    if not isinstance(v, int) or v <= 0:
123        raise ConfigError(
124            f"The number of concurrent tasks must be an integer value greater than 0. '{v}' was provided"
125        )
126    return v
127
128
129concurrent_tasks_validator = field_validator(
130    "backfill_concurrent_tasks",
131    "ddl_concurrent_tasks",
132    "concurrent_tasks",
133    mode="before",
134    check_fields=False,
135)(_concurrent_tasks_validator)
136
137
138def _http_headers_validator(v: t.Any) -> t.Any:
139    if isinstance(v, dict):
140        return [(key, value) for key, value in v.items()]
141    return v
142
143
144http_headers_validator = field_validator(
145    "http_headers",
146    mode="before",
147    check_fields=False,
148)(_http_headers_validator)
149
150
151def _variables_validator(value: t.Dict[str, t.Any]) -> t.Dict[str, t.Any]:
152    if not isinstance(value, dict):
153        raise ConfigError(f"Variables must be a dictionary, not {type(value)}")
154
155    def _validate_type(v: t.Any) -> None:
156        if isinstance(v, list):
157            for item in v:
158                _validate_type(item)
159        elif isinstance(v, dict):
160            for item in v.values():
161                _validate_type(item)
162        elif v is not None and not isinstance(v, (str, int, float, bool)):
163            raise ConfigError(f"Unsupported variable value type: {type(v)}")
164
165    _validate_type(value)
166    return {k.lower(): v for k, v in value.items()}
167
168
169variables_validator = field_validator(
170    "variables",
171    mode="before",
172    check_fields=False,
173)(_variables_validator)
174
175
176def compile_regex_mapping(value: t.Dict[str | re.Pattern, t.Any]) -> t.Dict[re.Pattern, t.Any]:
177    """
178    Utility function to compile a dict of { "string regex pattern" : "string value" } into { "<re.Pattern>": "string value" }
179    """
180    compiled_regexes = {}
181    for k, v in value.items():
182        try:
183            compiled_regexes[re.compile(k)] = v
184        except re.error:
185            raise ConfigError(f"`{k}` is not a valid regular expression.")
186    return compiled_regexes
ALL_CONFIG_FILENAMES = ('config.py', 'config.yml', 'config.yaml', 'sqlmesh.yml', 'sqlmesh.yaml')
YAML_CONFIG_FILENAMES = ('config.yml', 'config.yaml', 'sqlmesh.yml', 'sqlmesh.yaml')
DBT_PROJECT_FILENAME = 'dbt_project.yml'
class EnvironmentSuffixTarget(builtins.str, enum.Enum):
23class EnvironmentSuffixTarget(str, Enum):
24    # Intended to create virtual environments in their own schemas, with names like "<model_schema_name>__<env name>". The view name is untouched.
25    # For example, a model named 'sqlmesh_example.full_model' created in an environment called 'dev'
26    # would have its virtual layer view created as 'sqlmesh_example__dev.full_model'
27    SCHEMA = "schema"
28
29    # Intended to create virtual environments in the same schema as their production counterparts by adjusting the table name.
30    # For example, a model named 'sqlmesh_example.full_model' created in an environment called 'dev'
31    # would have its virtual layer view created as "sqlmesh_example.full_model__dev"
32    TABLE = "table"
33
34    # Intended to create virtual environments in their own catalogs to preserve the schema and view name of the models
35    # For example, a model named 'sqlmesh_example.full_model' created in an environment called 'dev'
36    # with a default catalog of "warehouse" would have its virtual layer view created as "warehouse__dev.sqlmesh_example.full_model"
37    # note: this only works for engines that can query across catalogs
38    CATALOG = "catalog"
39
40    @property
41    def is_schema(self) -> bool:
42        return self == EnvironmentSuffixTarget.SCHEMA
43
44    @property
45    def is_table(self) -> bool:
46        return self == EnvironmentSuffixTarget.TABLE
47
48    @property
49    def is_catalog(self) -> bool:
50        return self == EnvironmentSuffixTarget.CATALOG
51
52    @classproperty
53    def default(cls) -> EnvironmentSuffixTarget:
54        return EnvironmentSuffixTarget.SCHEMA
55
56    def __str__(self) -> str:
57        return self.name
58
59    def __repr__(self) -> str:
60        return str(self)

An enumeration.

SCHEMA = SCHEMA
TABLE = TABLE
CATALOG = CATALOG
is_schema: bool
40    @property
41    def is_schema(self) -> bool:
42        return self == EnvironmentSuffixTarget.SCHEMA
is_table: bool
44    @property
45    def is_table(self) -> bool:
46        return self == EnvironmentSuffixTarget.TABLE
is_catalog: bool
48    @property
49    def is_catalog(self) -> bool:
50        return self == EnvironmentSuffixTarget.CATALOG
default: EnvironmentSuffixTarget
52    @classproperty
53    def default(cls) -> EnvironmentSuffixTarget:
54        return EnvironmentSuffixTarget.SCHEMA

An enumeration.

Inherited Members
enum.Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
class VirtualEnvironmentMode(builtins.str, enum.Enum):
63class VirtualEnvironmentMode(str, Enum):
64    """Mode for virtual environment behavior.
65
66    FULL: Use full virtual environment functionality with versioned table names and virtual layer updates.
67    DEV_ONLY: Bypass virtual environments in production, using original unversioned model names.
68    """
69
70    FULL = "full"
71    DEV_ONLY = "dev_only"
72
73    @property
74    def is_full(self) -> bool:
75        return self == VirtualEnvironmentMode.FULL
76
77    @property
78    def is_dev_only(self) -> bool:
79        return self == VirtualEnvironmentMode.DEV_ONLY
80
81    @classproperty
82    def default(cls) -> VirtualEnvironmentMode:
83        return VirtualEnvironmentMode.FULL
84
85    def __str__(self) -> str:
86        return self.name
87
88    def __repr__(self) -> str:
89        return str(self)

Mode for virtual environment behavior.

FULL: Use full virtual environment functionality with versioned table names and virtual layer updates. DEV_ONLY: Bypass virtual environments in production, using original unversioned model names.

FULL = FULL
DEV_ONLY = DEV_ONLY
is_full: bool
73    @property
74    def is_full(self) -> bool:
75        return self == VirtualEnvironmentMode.FULL
is_dev_only: bool
77    @property
78    def is_dev_only(self) -> bool:
79        return self == VirtualEnvironmentMode.DEV_ONLY
default: VirtualEnvironmentMode
81    @classproperty
82    def default(cls) -> VirtualEnvironmentMode:
83        return VirtualEnvironmentMode.FULL

Mode for virtual environment behavior.

FULL: Use full virtual environment functionality with versioned table names and virtual layer updates. DEV_ONLY: Bypass virtual environments in production, using original unversioned model names.

Inherited Members
enum.Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
class TableNamingConvention(builtins.str, enum.Enum):
 92class TableNamingConvention(str, Enum):
 93    # Causes table names at the physical layer to follow the convention:
 94    # <schema-name>__<table-name>__<fingerprint>
 95    SCHEMA_AND_TABLE = "schema_and_table"
 96
 97    # Causes table names at the physical layer to follow the convention:
 98    # <table-name>__<fingerprint>
 99    TABLE_ONLY = "table_only"
100
101    # Takes the table name that would be returned from SCHEMA_AND_TABLE and wraps it in md5()
102    # to generate a hash and prefixes the has with `sqlmesh_md5__`, for the following reasons:
103    # - at a glance, you can still see it's managed by sqlmesh and that md5 was used to generate the hash
104    # - unquoted identifiers that start with numbers can trip up DB engine parsers, so having a text prefix prevents this
105    # This causes table names at the physical layer to follow the convention:
106    # sqlmesh_md5__3b07384d113edec49eaa6238ad5ff00d
107    HASH_MD5 = "hash_md5"
108
109    @classproperty
110    def default(cls) -> TableNamingConvention:
111        return TableNamingConvention.SCHEMA_AND_TABLE
112
113    def __str__(self) -> str:
114        return self.name
115
116    def __repr__(self) -> str:
117        return str(self)

An enumeration.

SCHEMA_AND_TABLE = SCHEMA_AND_TABLE
TABLE_ONLY = TABLE_ONLY
HASH_MD5 = HASH_MD5
default: TableNamingConvention
109    @classproperty
110    def default(cls) -> TableNamingConvention:
111        return TableNamingConvention.SCHEMA_AND_TABLE

An enumeration.

Inherited Members
enum.Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
def concurrent_tasks_validator(unknown):

Wrap a classmethod, staticmethod, property or unbound function and act as a descriptor that allows us to detect decorated items from the class' attributes.

This class' __get__ returns the wrapped item's __get__ result, which makes it transparent for classmethods and staticmethods.

Attributes:
  • wrapped: The decorator that has to be wrapped.
  • decorator_info: The decorator info.
  • shim: A wrapper function to wrap V1 style function.
def http_headers_validator(unknown):

Wrap a classmethod, staticmethod, property or unbound function and act as a descriptor that allows us to detect decorated items from the class' attributes.

This class' __get__ returns the wrapped item's __get__ result, which makes it transparent for classmethods and staticmethods.

Attributes:
  • wrapped: The decorator that has to be wrapped.
  • decorator_info: The decorator info.
  • shim: A wrapper function to wrap V1 style function.
def variables_validator(unknown):

Wrap a classmethod, staticmethod, property or unbound function and act as a descriptor that allows us to detect decorated items from the class' attributes.

This class' __get__ returns the wrapped item's __get__ result, which makes it transparent for classmethods and staticmethods.

Attributes:
  • wrapped: The decorator that has to be wrapped.
  • decorator_info: The decorator info.
  • shim: A wrapper function to wrap V1 style function.
def compile_regex_mapping(value: Dict[str | re.Pattern, Any]) -> Dict[re.Pattern, Any]:
177def compile_regex_mapping(value: t.Dict[str | re.Pattern, t.Any]) -> t.Dict[re.Pattern, t.Any]:
178    """
179    Utility function to compile a dict of { "string regex pattern" : "string value" } into { "<re.Pattern>": "string value" }
180    """
181    compiled_regexes = {}
182    for k, v in value.items():
183        try:
184            compiled_regexes[re.compile(k)] = v
185        except re.error:
186            raise ConfigError(f"`{k}` is not a valid regular expression.")
187    return compiled_regexes

Utility function to compile a dict of { "string regex pattern" : "string value" } into { "": "string value" }