dvt-core 0.52.2__cp310-cp310-macosx_10_9_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of dvt-core might be problematic. Click here for more details.

Files changed (275) hide show
  1. dbt/__init__.py +7 -0
  2. dbt/_pydantic_shim.py +26 -0
  3. dbt/artifacts/__init__.py +0 -0
  4. dbt/artifacts/exceptions/__init__.py +1 -0
  5. dbt/artifacts/exceptions/schemas.py +31 -0
  6. dbt/artifacts/resources/__init__.py +116 -0
  7. dbt/artifacts/resources/base.py +67 -0
  8. dbt/artifacts/resources/types.py +93 -0
  9. dbt/artifacts/resources/v1/analysis.py +10 -0
  10. dbt/artifacts/resources/v1/catalog.py +23 -0
  11. dbt/artifacts/resources/v1/components.py +274 -0
  12. dbt/artifacts/resources/v1/config.py +277 -0
  13. dbt/artifacts/resources/v1/documentation.py +11 -0
  14. dbt/artifacts/resources/v1/exposure.py +51 -0
  15. dbt/artifacts/resources/v1/function.py +52 -0
  16. dbt/artifacts/resources/v1/generic_test.py +31 -0
  17. dbt/artifacts/resources/v1/group.py +21 -0
  18. dbt/artifacts/resources/v1/hook.py +11 -0
  19. dbt/artifacts/resources/v1/macro.py +29 -0
  20. dbt/artifacts/resources/v1/metric.py +172 -0
  21. dbt/artifacts/resources/v1/model.py +145 -0
  22. dbt/artifacts/resources/v1/owner.py +10 -0
  23. dbt/artifacts/resources/v1/saved_query.py +111 -0
  24. dbt/artifacts/resources/v1/seed.py +41 -0
  25. dbt/artifacts/resources/v1/semantic_layer_components.py +72 -0
  26. dbt/artifacts/resources/v1/semantic_model.py +314 -0
  27. dbt/artifacts/resources/v1/singular_test.py +14 -0
  28. dbt/artifacts/resources/v1/snapshot.py +91 -0
  29. dbt/artifacts/resources/v1/source_definition.py +84 -0
  30. dbt/artifacts/resources/v1/sql_operation.py +10 -0
  31. dbt/artifacts/resources/v1/unit_test_definition.py +77 -0
  32. dbt/artifacts/schemas/__init__.py +0 -0
  33. dbt/artifacts/schemas/base.py +191 -0
  34. dbt/artifacts/schemas/batch_results.py +24 -0
  35. dbt/artifacts/schemas/catalog/__init__.py +11 -0
  36. dbt/artifacts/schemas/catalog/v1/__init__.py +0 -0
  37. dbt/artifacts/schemas/catalog/v1/catalog.py +59 -0
  38. dbt/artifacts/schemas/freshness/__init__.py +1 -0
  39. dbt/artifacts/schemas/freshness/v3/__init__.py +0 -0
  40. dbt/artifacts/schemas/freshness/v3/freshness.py +158 -0
  41. dbt/artifacts/schemas/manifest/__init__.py +2 -0
  42. dbt/artifacts/schemas/manifest/v12/__init__.py +0 -0
  43. dbt/artifacts/schemas/manifest/v12/manifest.py +211 -0
  44. dbt/artifacts/schemas/results.py +147 -0
  45. dbt/artifacts/schemas/run/__init__.py +2 -0
  46. dbt/artifacts/schemas/run/v5/__init__.py +0 -0
  47. dbt/artifacts/schemas/run/v5/run.py +184 -0
  48. dbt/artifacts/schemas/upgrades/__init__.py +4 -0
  49. dbt/artifacts/schemas/upgrades/upgrade_manifest.py +174 -0
  50. dbt/artifacts/schemas/upgrades/upgrade_manifest_dbt_version.py +2 -0
  51. dbt/artifacts/utils/validation.py +153 -0
  52. dbt/cli/__init__.py +1 -0
  53. dbt/cli/context.py +17 -0
  54. dbt/cli/exceptions.py +57 -0
  55. dbt/cli/flags.py +560 -0
  56. dbt/cli/main.py +2039 -0
  57. dbt/cli/option_types.py +121 -0
  58. dbt/cli/options.py +80 -0
  59. dbt/cli/params.py +804 -0
  60. dbt/cli/requires.py +490 -0
  61. dbt/cli/resolvers.py +50 -0
  62. dbt/cli/types.py +40 -0
  63. dbt/clients/__init__.py +0 -0
  64. dbt/clients/checked_load.py +83 -0
  65. dbt/clients/git.py +164 -0
  66. dbt/clients/jinja.py +206 -0
  67. dbt/clients/jinja_static.py +245 -0
  68. dbt/clients/registry.py +192 -0
  69. dbt/clients/yaml_helper.py +68 -0
  70. dbt/compilation.py +876 -0
  71. dbt/compute/__init__.py +14 -0
  72. dbt/compute/engines/__init__.py +12 -0
  73. dbt/compute/engines/spark_engine.py +624 -0
  74. dbt/compute/federated_executor.py +837 -0
  75. dbt/compute/filter_pushdown.cpython-310-darwin.so +0 -0
  76. dbt/compute/filter_pushdown.py +273 -0
  77. dbt/compute/jar_provisioning.cpython-310-darwin.so +0 -0
  78. dbt/compute/jar_provisioning.py +255 -0
  79. dbt/compute/java_compat.cpython-310-darwin.so +0 -0
  80. dbt/compute/java_compat.py +689 -0
  81. dbt/compute/jdbc_utils.cpython-310-darwin.so +0 -0
  82. dbt/compute/jdbc_utils.py +678 -0
  83. dbt/compute/smart_selector.cpython-310-darwin.so +0 -0
  84. dbt/compute/smart_selector.py +311 -0
  85. dbt/compute/strategies/__init__.py +54 -0
  86. dbt/compute/strategies/base.py +165 -0
  87. dbt/compute/strategies/dataproc.py +207 -0
  88. dbt/compute/strategies/emr.py +203 -0
  89. dbt/compute/strategies/local.py +364 -0
  90. dbt/compute/strategies/standalone.py +262 -0
  91. dbt/config/__init__.py +4 -0
  92. dbt/config/catalogs.py +94 -0
  93. dbt/config/compute.cpython-310-darwin.so +0 -0
  94. dbt/config/compute.py +547 -0
  95. dbt/config/dvt_profile.cpython-310-darwin.so +0 -0
  96. dbt/config/dvt_profile.py +342 -0
  97. dbt/config/profile.py +422 -0
  98. dbt/config/project.py +873 -0
  99. dbt/config/project_utils.py +28 -0
  100. dbt/config/renderer.py +231 -0
  101. dbt/config/runtime.py +553 -0
  102. dbt/config/selectors.py +208 -0
  103. dbt/config/utils.py +77 -0
  104. dbt/constants.py +28 -0
  105. dbt/context/__init__.py +0 -0
  106. dbt/context/base.py +745 -0
  107. dbt/context/configured.py +135 -0
  108. dbt/context/context_config.py +382 -0
  109. dbt/context/docs.py +82 -0
  110. dbt/context/exceptions_jinja.py +178 -0
  111. dbt/context/macro_resolver.py +195 -0
  112. dbt/context/macros.py +171 -0
  113. dbt/context/manifest.py +72 -0
  114. dbt/context/providers.py +2249 -0
  115. dbt/context/query_header.py +13 -0
  116. dbt/context/secret.py +58 -0
  117. dbt/context/target.py +74 -0
  118. dbt/contracts/__init__.py +0 -0
  119. dbt/contracts/files.py +413 -0
  120. dbt/contracts/graph/__init__.py +0 -0
  121. dbt/contracts/graph/manifest.py +1904 -0
  122. dbt/contracts/graph/metrics.py +97 -0
  123. dbt/contracts/graph/model_config.py +70 -0
  124. dbt/contracts/graph/node_args.py +42 -0
  125. dbt/contracts/graph/nodes.py +1806 -0
  126. dbt/contracts/graph/semantic_manifest.py +232 -0
  127. dbt/contracts/graph/unparsed.py +811 -0
  128. dbt/contracts/project.py +417 -0
  129. dbt/contracts/results.py +53 -0
  130. dbt/contracts/selection.py +23 -0
  131. dbt/contracts/sql.py +85 -0
  132. dbt/contracts/state.py +68 -0
  133. dbt/contracts/util.py +46 -0
  134. dbt/deprecations.py +346 -0
  135. dbt/deps/__init__.py +0 -0
  136. dbt/deps/base.py +152 -0
  137. dbt/deps/git.py +195 -0
  138. dbt/deps/local.py +79 -0
  139. dbt/deps/registry.py +130 -0
  140. dbt/deps/resolver.py +149 -0
  141. dbt/deps/tarball.py +120 -0
  142. dbt/docs/source/_ext/dbt_click.py +119 -0
  143. dbt/docs/source/conf.py +32 -0
  144. dbt/env_vars.py +64 -0
  145. dbt/event_time/event_time.py +40 -0
  146. dbt/event_time/sample_window.py +60 -0
  147. dbt/events/__init__.py +15 -0
  148. dbt/events/base_types.py +36 -0
  149. dbt/events/core_types_pb2.py +2 -0
  150. dbt/events/logging.py +108 -0
  151. dbt/events/types.py +2516 -0
  152. dbt/exceptions.py +1486 -0
  153. dbt/flags.py +89 -0
  154. dbt/graph/__init__.py +11 -0
  155. dbt/graph/cli.py +247 -0
  156. dbt/graph/graph.py +172 -0
  157. dbt/graph/queue.py +214 -0
  158. dbt/graph/selector.py +374 -0
  159. dbt/graph/selector_methods.py +975 -0
  160. dbt/graph/selector_spec.py +222 -0
  161. dbt/graph/thread_pool.py +18 -0
  162. dbt/hooks.py +21 -0
  163. dbt/include/README.md +49 -0
  164. dbt/include/__init__.py +3 -0
  165. dbt/include/starter_project/.gitignore +4 -0
  166. dbt/include/starter_project/README.md +15 -0
  167. dbt/include/starter_project/__init__.py +3 -0
  168. dbt/include/starter_project/analyses/.gitkeep +0 -0
  169. dbt/include/starter_project/dbt_project.yml +36 -0
  170. dbt/include/starter_project/macros/.gitkeep +0 -0
  171. dbt/include/starter_project/models/example/my_first_dbt_model.sql +27 -0
  172. dbt/include/starter_project/models/example/my_second_dbt_model.sql +6 -0
  173. dbt/include/starter_project/models/example/schema.yml +21 -0
  174. dbt/include/starter_project/seeds/.gitkeep +0 -0
  175. dbt/include/starter_project/snapshots/.gitkeep +0 -0
  176. dbt/include/starter_project/tests/.gitkeep +0 -0
  177. dbt/internal_deprecations.py +26 -0
  178. dbt/jsonschemas/__init__.py +3 -0
  179. dbt/jsonschemas/jsonschemas.py +309 -0
  180. dbt/jsonschemas/project/0.0.110.json +4717 -0
  181. dbt/jsonschemas/project/0.0.85.json +2015 -0
  182. dbt/jsonschemas/resources/0.0.110.json +2636 -0
  183. dbt/jsonschemas/resources/0.0.85.json +2536 -0
  184. dbt/jsonschemas/resources/latest.json +6773 -0
  185. dbt/links.py +4 -0
  186. dbt/materializations/__init__.py +0 -0
  187. dbt/materializations/incremental/__init__.py +0 -0
  188. dbt/materializations/incremental/microbatch.py +236 -0
  189. dbt/mp_context.py +8 -0
  190. dbt/node_types.py +37 -0
  191. dbt/parser/__init__.py +23 -0
  192. dbt/parser/analysis.py +21 -0
  193. dbt/parser/base.py +548 -0
  194. dbt/parser/common.py +266 -0
  195. dbt/parser/docs.py +52 -0
  196. dbt/parser/fixtures.py +51 -0
  197. dbt/parser/functions.py +30 -0
  198. dbt/parser/generic_test.py +100 -0
  199. dbt/parser/generic_test_builders.py +333 -0
  200. dbt/parser/hooks.py +118 -0
  201. dbt/parser/macros.py +137 -0
  202. dbt/parser/manifest.py +2204 -0
  203. dbt/parser/models.py +573 -0
  204. dbt/parser/partial.py +1178 -0
  205. dbt/parser/read_files.py +445 -0
  206. dbt/parser/schema_generic_tests.py +422 -0
  207. dbt/parser/schema_renderer.py +111 -0
  208. dbt/parser/schema_yaml_readers.py +935 -0
  209. dbt/parser/schemas.py +1466 -0
  210. dbt/parser/search.py +149 -0
  211. dbt/parser/seeds.py +28 -0
  212. dbt/parser/singular_test.py +20 -0
  213. dbt/parser/snapshots.py +44 -0
  214. dbt/parser/sources.py +558 -0
  215. dbt/parser/sql.py +62 -0
  216. dbt/parser/unit_tests.py +621 -0
  217. dbt/plugins/__init__.py +20 -0
  218. dbt/plugins/contracts.py +9 -0
  219. dbt/plugins/exceptions.py +2 -0
  220. dbt/plugins/manager.py +163 -0
  221. dbt/plugins/manifest.py +21 -0
  222. dbt/profiler.py +20 -0
  223. dbt/py.typed +1 -0
  224. dbt/query_analyzer.cpython-310-darwin.so +0 -0
  225. dbt/query_analyzer.py +410 -0
  226. dbt/runners/__init__.py +2 -0
  227. dbt/runners/exposure_runner.py +7 -0
  228. dbt/runners/no_op_runner.py +45 -0
  229. dbt/runners/saved_query_runner.py +7 -0
  230. dbt/selected_resources.py +8 -0
  231. dbt/task/__init__.py +0 -0
  232. dbt/task/base.py +503 -0
  233. dbt/task/build.py +197 -0
  234. dbt/task/clean.py +56 -0
  235. dbt/task/clone.py +161 -0
  236. dbt/task/compile.py +150 -0
  237. dbt/task/compute.py +454 -0
  238. dbt/task/debug.py +505 -0
  239. dbt/task/deps.py +280 -0
  240. dbt/task/docs/__init__.py +3 -0
  241. dbt/task/docs/generate.py +660 -0
  242. dbt/task/docs/index.html +250 -0
  243. dbt/task/docs/serve.py +29 -0
  244. dbt/task/freshness.py +322 -0
  245. dbt/task/function.py +121 -0
  246. dbt/task/group_lookup.py +46 -0
  247. dbt/task/init.py +553 -0
  248. dbt/task/java.py +316 -0
  249. dbt/task/list.py +236 -0
  250. dbt/task/printer.py +175 -0
  251. dbt/task/retry.py +175 -0
  252. dbt/task/run.py +1306 -0
  253. dbt/task/run_operation.py +141 -0
  254. dbt/task/runnable.py +758 -0
  255. dbt/task/seed.py +103 -0
  256. dbt/task/show.py +149 -0
  257. dbt/task/snapshot.py +56 -0
  258. dbt/task/spark.py +414 -0
  259. dbt/task/sql.py +110 -0
  260. dbt/task/target_sync.py +759 -0
  261. dbt/task/test.py +464 -0
  262. dbt/tests/fixtures/__init__.py +1 -0
  263. dbt/tests/fixtures/project.py +620 -0
  264. dbt/tests/util.py +651 -0
  265. dbt/tracking.py +529 -0
  266. dbt/utils/__init__.py +3 -0
  267. dbt/utils/artifact_upload.py +151 -0
  268. dbt/utils/utils.py +408 -0
  269. dbt/version.py +268 -0
  270. dvt_cli/__init__.py +72 -0
  271. dvt_core-0.52.2.dist-info/METADATA +286 -0
  272. dvt_core-0.52.2.dist-info/RECORD +275 -0
  273. dvt_core-0.52.2.dist-info/WHEEL +5 -0
  274. dvt_core-0.52.2.dist-info/entry_points.txt +2 -0
  275. dvt_core-0.52.2.dist-info/top_level.txt +2 -0
@@ -0,0 +1,145 @@
1
+ import enum
2
+ from dataclasses import dataclass, field
3
+ from datetime import datetime
4
+ from typing import Dict, List, Literal, Optional
5
+
6
+ from dbt.artifacts.resources.types import AccessType, NodeType, TimePeriod
7
+ from dbt.artifacts.resources.v1.components import (
8
+ CompiledResource,
9
+ DeferRelation,
10
+ NodeVersion,
11
+ )
12
+ from dbt.artifacts.resources.v1.config import NodeConfig
13
+ from dbt_common.contracts.config.base import MergeBehavior
14
+ from dbt_common.contracts.constraints import ModelLevelConstraint
15
+ from dbt_common.contracts.util import Mergeable
16
+ from dbt_common.dataclass_schema import (
17
+ ExtensibleDbtClassMixin,
18
+ ValidationError,
19
+ dbtClassMixin,
20
+ )
21
+
22
+
23
+ class ModelFreshnessUpdatesOnOptions(enum.Enum):
24
+ all = "all"
25
+ any = "any"
26
+
27
+
28
+ @dataclass
29
+ class ModelBuildAfter(ExtensibleDbtClassMixin):
30
+ count: Optional[int] = None
31
+ period: Optional[TimePeriod] = None
32
+ updates_on: ModelFreshnessUpdatesOnOptions = ModelFreshnessUpdatesOnOptions.any
33
+
34
+
35
+ @dataclass
36
+ class ModelFreshness(ExtensibleDbtClassMixin, Mergeable):
37
+ build_after: ModelBuildAfter
38
+
39
+
40
+ def merge_model_freshness(*thresholds: Optional[ModelFreshness]) -> Optional[ModelFreshness]:
41
+ if not thresholds:
42
+ return None
43
+
44
+ current_merged_value: Optional[ModelFreshness] = thresholds[0]
45
+
46
+ for i in range(1, len(thresholds)):
47
+ base = current_merged_value
48
+ update = thresholds[i]
49
+
50
+ if base is not None and update is not None:
51
+ # When both base and update freshness are defined,
52
+ # create a new ModelFreshness instance using the build_after from the 'update'.
53
+ # This effectively means 'update's build_after configuration takes precedence.
54
+ merged_freshness_obj = base.merged(update)
55
+ if (
56
+ base.build_after.updates_on == ModelFreshnessUpdatesOnOptions.all
57
+ or update.build_after.updates_on == ModelFreshnessUpdatesOnOptions.all
58
+ ):
59
+ merged_freshness_obj.build_after.updates_on = ModelFreshnessUpdatesOnOptions.all
60
+ current_merged_value = merged_freshness_obj
61
+ elif base is None and update is not None:
62
+ # If the current merged value is None but the new update is defined,
63
+ # take the update.
64
+ current_merged_value = update
65
+ else:
66
+ # This covers cases where 'update' is None (regardless of 'base'),
67
+ # or both 'base' and 'update' are None.
68
+ # The result of the pair-merge is None.
69
+ current_merged_value = base
70
+
71
+ return current_merged_value
72
+
73
+
74
+ @dataclass
75
+ class ModelConfig(NodeConfig):
76
+ access: AccessType = field(
77
+ default=AccessType.Protected,
78
+ metadata=MergeBehavior.Clobber.meta(),
79
+ )
80
+ freshness: Optional[ModelFreshness] = None
81
+
82
+ def __post_init__(self):
83
+ super().__post_init__()
84
+ if (
85
+ self.freshness
86
+ and self.freshness.build_after.period
87
+ and self.freshness.build_after.count is None
88
+ ):
89
+ raise ValidationError(
90
+ "`freshness.build_after` must have a value for `count` if a `period` is provided"
91
+ )
92
+ elif (
93
+ self.freshness
94
+ and self.freshness.build_after.count is not None
95
+ and not self.freshness.build_after.period
96
+ ):
97
+ raise ValidationError(
98
+ "`freshness.build_after` must have a value for `period` if a `count` is provided"
99
+ )
100
+
101
+ @classmethod
102
+ def __pre_deserialize__(cls, data):
103
+ data = super().__pre_deserialize__(data)
104
+ # scrub out model configs where "build_after" is not defined
105
+ if (
106
+ "freshness" in data
107
+ and isinstance(data["freshness"], dict)
108
+ and "build_after" in data["freshness"]
109
+ ):
110
+ data["freshness"] = ModelFreshness.from_dict(data["freshness"]).to_dict()
111
+ else:
112
+ data.pop("freshness", None)
113
+ return data
114
+
115
+
116
+ @dataclass
117
+ class CustomGranularity(dbtClassMixin):
118
+ name: str
119
+ column_name: Optional[str] = None
120
+
121
+
122
+ @dataclass
123
+ class TimeSpine(dbtClassMixin):
124
+ standard_granularity_column: str
125
+ custom_granularities: List[CustomGranularity] = field(default_factory=list)
126
+
127
+
128
+ @dataclass
129
+ class Model(CompiledResource):
130
+ resource_type: Literal[NodeType.Model]
131
+ access: AccessType = AccessType.Protected
132
+ config: ModelConfig = field(default_factory=ModelConfig)
133
+ constraints: List[ModelLevelConstraint] = field(default_factory=list)
134
+ version: Optional[NodeVersion] = None
135
+ latest_version: Optional[NodeVersion] = None
136
+ deprecation_date: Optional[datetime] = None
137
+ defer_relation: Optional[DeferRelation] = None
138
+ primary_key: List[str] = field(default_factory=list)
139
+ time_spine: Optional[TimeSpine] = None
140
+
141
+ def __post_serialize__(self, dct: Dict, context: Optional[Dict] = None):
142
+ dct = super().__post_serialize__(dct, context)
143
+ if context and context.get("artifact") and "defer_relation" in dct:
144
+ del dct["defer_relation"]
145
+ return dct
@@ -0,0 +1,10 @@
1
+ from dataclasses import dataclass
2
+ from typing import List, Optional, Union
3
+
4
+ from dbt_common.contracts.config.properties import AdditionalPropertiesAllowed
5
+
6
+
7
+ @dataclass
8
+ class Owner(AdditionalPropertiesAllowed):
9
+ email: Union[str, List[str], None] = None
10
+ name: Optional[str] = None
@@ -0,0 +1,111 @@
1
+ from __future__ import annotations
2
+
3
+ import time
4
+ from dataclasses import dataclass, field
5
+ from typing import Any, Dict, List, Literal, Optional, Union
6
+
7
+ from dbt.artifacts.resources.base import GraphResource
8
+ from dbt.artifacts.resources.types import NodeType
9
+ from dbt.artifacts.resources.v1.components import DependsOn, RefArgs
10
+ from dbt.artifacts.resources.v1.config import list_str, metas
11
+ from dbt.artifacts.resources.v1.semantic_layer_components import (
12
+ SourceFileMetadata,
13
+ WhereFilterIntersection,
14
+ )
15
+ from dbt_common.contracts.config.base import BaseConfig, CompareBehavior, MergeBehavior
16
+ from dbt_common.contracts.config.metadata import ShowBehavior
17
+ from dbt_common.dataclass_schema import dbtClassMixin
18
+ from dbt_semantic_interfaces.type_enums.export_destination_type import (
19
+ ExportDestinationType,
20
+ )
21
+
22
+
23
+ @dataclass
24
+ class ExportConfig(dbtClassMixin):
25
+ """Nested configuration attributes for exports."""
26
+
27
+ export_as: ExportDestinationType
28
+ schema_name: Optional[str] = None
29
+ alias: Optional[str] = None
30
+ database: Optional[str] = None
31
+
32
+
33
+ @dataclass
34
+ class Export(dbtClassMixin):
35
+ """Configuration for writing query results to a table."""
36
+
37
+ name: str
38
+ config: ExportConfig
39
+ unrendered_config: Dict[str, str] = field(default_factory=dict)
40
+
41
+
42
+ @dataclass
43
+ class QueryParams(dbtClassMixin):
44
+ """The query parameters for the saved query"""
45
+
46
+ metrics: List[str]
47
+ group_by: List[str]
48
+ where: Optional[WhereFilterIntersection]
49
+ order_by: List[str] = field(default_factory=list)
50
+ limit: Optional[int] = None
51
+
52
+
53
+ @dataclass
54
+ class SavedQueryCache(dbtClassMixin):
55
+ enabled: bool = False
56
+
57
+
58
+ @dataclass
59
+ class SavedQueryConfig(BaseConfig):
60
+ """Where config options for SavedQueries are stored.
61
+
62
+ This class is much like many other node config classes. It's likely that
63
+ this class will expand in the direction of what's in the `NodeAndTestConfig`
64
+ class. It might make sense to clean the various *Config classes into one at
65
+ some point.
66
+ """
67
+
68
+ enabled: bool = True
69
+ group: Optional[str] = field(
70
+ default=None,
71
+ metadata=CompareBehavior.Exclude.meta(),
72
+ )
73
+ meta: Dict[str, Any] = field(
74
+ default_factory=dict,
75
+ metadata=MergeBehavior.Update.meta(),
76
+ )
77
+ export_as: Optional[ExportDestinationType] = None
78
+ schema: Optional[str] = None
79
+ cache: SavedQueryCache = field(default_factory=SavedQueryCache)
80
+
81
+
82
+ @dataclass
83
+ class SavedQueryMandatory(GraphResource):
84
+ query_params: QueryParams
85
+ exports: List[Export]
86
+
87
+
88
+ @dataclass
89
+ class SavedQuery(SavedQueryMandatory):
90
+ resource_type: Literal[NodeType.SavedQuery]
91
+ description: Optional[str] = None
92
+ label: Optional[str] = None
93
+ metadata: Optional[SourceFileMetadata] = None
94
+ config: SavedQueryConfig = field(default_factory=SavedQueryConfig)
95
+ unrendered_config: Dict[str, Any] = field(default_factory=dict)
96
+ group: Optional[str] = None
97
+ depends_on: DependsOn = field(default_factory=DependsOn)
98
+ created_at: float = field(default_factory=lambda: time.time())
99
+ refs: List[RefArgs] = field(default_factory=list)
100
+ tags: Union[List[str], str] = field(
101
+ default_factory=list_str,
102
+ metadata=metas(ShowBehavior.Hide, MergeBehavior.Append, CompareBehavior.Exclude),
103
+ )
104
+
105
+ @property
106
+ def metrics(self) -> List[str]:
107
+ return self.query_params.metrics
108
+
109
+ @property
110
+ def depends_on_nodes(self):
111
+ return self.depends_on.nodes
@@ -0,0 +1,41 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Dict, Literal, Optional
3
+
4
+ from dbt.artifacts.resources.types import NodeType
5
+ from dbt.artifacts.resources.v1.components import (
6
+ DeferRelation,
7
+ MacroDependsOn,
8
+ ParsedResource,
9
+ )
10
+ from dbt.artifacts.resources.v1.config import NodeConfig
11
+ from dbt_common.dataclass_schema import ValidationError
12
+
13
+
14
+ @dataclass
15
+ class SeedConfig(NodeConfig):
16
+ materialized: str = "seed"
17
+ delimiter: str = ","
18
+ quote_columns: Optional[bool] = None
19
+
20
+ @classmethod
21
+ def validate(cls, data):
22
+ super().validate(data)
23
+ if data.get("materialized") and data.get("materialized") != "seed":
24
+ raise ValidationError("A seed must have a materialized value of 'seed'")
25
+
26
+
27
+ @dataclass
28
+ class Seed(ParsedResource): # No SQLDefaults!
29
+ resource_type: Literal[NodeType.Seed]
30
+ config: SeedConfig = field(default_factory=SeedConfig)
31
+ # seeds need the root_path because the contents are not loaded initially
32
+ # and we need the root_path to load the seed later
33
+ root_path: Optional[str] = None
34
+ depends_on: MacroDependsOn = field(default_factory=MacroDependsOn)
35
+ defer_relation: Optional[DeferRelation] = None
36
+
37
+ def __post_serialize__(self, dct: Dict, context: Optional[Dict] = None):
38
+ dct = super().__post_serialize__(dct, context)
39
+ if context and context.get("artifact") and "defer_relation" in dct:
40
+ del dct["defer_relation"]
41
+ return dct
@@ -0,0 +1,72 @@
1
+ from dataclasses import dataclass
2
+ from typing import List, Optional, Sequence, Tuple
3
+
4
+ from dbt_common.dataclass_schema import dbtClassMixin
5
+ from dbt_semantic_interfaces.call_parameter_sets import JinjaCallParameterSets
6
+ from dbt_semantic_interfaces.parsing.where_filter.jinja_object_parser import (
7
+ JinjaObjectParser,
8
+ QueryItemLocation,
9
+ )
10
+ from dbt_semantic_interfaces.type_enums import AggregationType
11
+
12
+
13
+ @dataclass
14
+ class WhereFilter(dbtClassMixin):
15
+ where_sql_template: str
16
+
17
+ def call_parameter_sets(
18
+ self, custom_granularity_names: Sequence[str]
19
+ ) -> JinjaCallParameterSets:
20
+ return JinjaObjectParser.parse_call_parameter_sets(
21
+ self.where_sql_template,
22
+ custom_granularity_names=custom_granularity_names,
23
+ query_item_location=QueryItemLocation.NON_ORDER_BY,
24
+ )
25
+
26
+
27
+ @dataclass
28
+ class WhereFilterIntersection(dbtClassMixin):
29
+ where_filters: List[WhereFilter]
30
+
31
+ def filter_expression_parameter_sets(
32
+ self, custom_granularity_names: Sequence[str]
33
+ ) -> Sequence[Tuple[str, JinjaCallParameterSets]]:
34
+ raise NotImplementedError
35
+
36
+
37
+ @dataclass
38
+ class FileSlice(dbtClassMixin):
39
+ """Provides file slice level context about what something was created from.
40
+
41
+ Implementation of the dbt-semantic-interfaces `FileSlice` protocol
42
+ """
43
+
44
+ filename: str
45
+ content: str
46
+ start_line_number: int
47
+ end_line_number: int
48
+
49
+
50
+ @dataclass
51
+ class SourceFileMetadata(dbtClassMixin):
52
+ """Provides file context about what something was created from.
53
+
54
+ Implementation of the dbt-semantic-interfaces `Metadata` protocol
55
+ """
56
+
57
+ repo_file_path: str
58
+ file_slice: FileSlice
59
+
60
+
61
+ @dataclass
62
+ class MeasureAggregationParameters(dbtClassMixin):
63
+ percentile: Optional[float] = None
64
+ use_discrete_percentile: bool = False
65
+ use_approximate_percentile: bool = False
66
+
67
+
68
+ @dataclass
69
+ class NonAdditiveDimension(dbtClassMixin):
70
+ name: str
71
+ window_choice: AggregationType
72
+ window_groupings: List[str]
@@ -0,0 +1,314 @@
1
+ import time
2
+ from dataclasses import dataclass, field
3
+ from typing import Any, Dict, List, Optional, Sequence
4
+
5
+ from dbt.artifacts.resources import SourceFileMetadata
6
+ from dbt.artifacts.resources.base import GraphResource
7
+ from dbt.artifacts.resources.v1.components import DependsOn, RefArgs
8
+ from dbt.artifacts.resources.v1.metric import Metric
9
+ from dbt.artifacts.resources.v1.semantic_layer_components import (
10
+ MeasureAggregationParameters,
11
+ NonAdditiveDimension,
12
+ )
13
+ from dbt_common.contracts.config.base import BaseConfig, CompareBehavior, MergeBehavior
14
+ from dbt_common.dataclass_schema import dbtClassMixin
15
+ from dbt_semantic_interfaces.references import (
16
+ DimensionReference,
17
+ EntityReference,
18
+ LinkableElementReference,
19
+ MeasureReference,
20
+ SemanticModelReference,
21
+ TimeDimensionReference,
22
+ )
23
+ from dbt_semantic_interfaces.type_enums import (
24
+ AggregationType,
25
+ DimensionType,
26
+ EntityType,
27
+ MetricType,
28
+ TimeGranularity,
29
+ )
30
+
31
+ """
32
+ The classes in this file are dataclasses which are used to construct the Semantic
33
+ Model node in dbt-core. Additionally, these classes need to at a minimum support
34
+ what is specified in their protocol definitions in dbt-semantic-interfaces.
35
+ Their protocol definitions can be found here:
36
+ https://github.com/dbt-labs/dbt-semantic-interfaces/blob/main/dbt_semantic_interfaces/protocols/semantic_model.py
37
+ """
38
+
39
+
40
+ @dataclass
41
+ class SemanticLayerElementConfig(dbtClassMixin):
42
+ meta: Dict[str, Any] = field(
43
+ default_factory=dict,
44
+ metadata=MergeBehavior.Update.meta(),
45
+ )
46
+
47
+
48
+ @dataclass
49
+ class Defaults(dbtClassMixin):
50
+ agg_time_dimension: Optional[str] = None
51
+
52
+
53
+ @dataclass
54
+ class NodeRelation(dbtClassMixin):
55
+ alias: str
56
+ schema_name: str # TODO: Could this be called simply "schema" so we could reuse StateRelation?
57
+ database: Optional[str] = None
58
+ relation_name: Optional[str] = ""
59
+
60
+
61
+ # ====================================
62
+ # Dimension objects
63
+ # Dimension protocols: https://github.com/dbt-labs/dbt-semantic-interfaces/blob/main/dbt_semantic_interfaces/protocols/dimension.py
64
+ # ====================================
65
+
66
+
67
+ @dataclass
68
+ class DimensionValidityParams(dbtClassMixin):
69
+ is_start: bool = False
70
+ is_end: bool = False
71
+
72
+
73
+ @dataclass
74
+ class DimensionTypeParams(dbtClassMixin):
75
+ time_granularity: TimeGranularity
76
+ validity_params: Optional[DimensionValidityParams] = None
77
+
78
+
79
+ @dataclass
80
+ class Dimension(dbtClassMixin):
81
+ name: str
82
+ type: DimensionType
83
+ description: Optional[str] = None
84
+ label: Optional[str] = None
85
+ is_partition: bool = False
86
+ type_params: Optional[DimensionTypeParams] = None
87
+ expr: Optional[str] = None
88
+ metadata: Optional[SourceFileMetadata] = None
89
+ config: Optional[SemanticLayerElementConfig] = None
90
+
91
+ @property
92
+ def reference(self) -> DimensionReference:
93
+ return DimensionReference(element_name=self.name)
94
+
95
+ @property
96
+ def time_dimension_reference(self) -> Optional[TimeDimensionReference]:
97
+ if self.type == DimensionType.TIME:
98
+ return TimeDimensionReference(element_name=self.name)
99
+ else:
100
+ return None
101
+
102
+ @property
103
+ def validity_params(self) -> Optional[DimensionValidityParams]:
104
+ if self.type_params:
105
+ return self.type_params.validity_params
106
+ else:
107
+ return None
108
+
109
+
110
+ # ====================================
111
+ # Entity objects
112
+ # Entity protocols: https://github.com/dbt-labs/dbt-semantic-interfaces/blob/main/dbt_semantic_interfaces/protocols/entity.py
113
+ # ====================================
114
+
115
+
116
+ @dataclass
117
+ class Entity(dbtClassMixin):
118
+ name: str
119
+ type: EntityType
120
+ description: Optional[str] = None
121
+ label: Optional[str] = None
122
+ role: Optional[str] = None
123
+ expr: Optional[str] = None
124
+ config: Optional[SemanticLayerElementConfig] = None
125
+
126
+ @property
127
+ def reference(self) -> EntityReference:
128
+ return EntityReference(element_name=self.name)
129
+
130
+ @property
131
+ def is_linkable_entity_type(self) -> bool:
132
+ return self.type in (EntityType.PRIMARY, EntityType.UNIQUE, EntityType.NATURAL)
133
+
134
+
135
+ # ====================================
136
+ # Measure object
137
+ # Measure protocols: https://github.com/dbt-labs/dbt-semantic-interfaces/blob/main/dbt_semantic_interfaces/protocols/measure.py
138
+ # ====================================
139
+
140
+
141
+ @dataclass
142
+ class Measure(dbtClassMixin):
143
+ name: str
144
+ agg: AggregationType
145
+ description: Optional[str] = None
146
+ label: Optional[str] = None
147
+ create_metric: bool = False
148
+ expr: Optional[str] = None
149
+ agg_params: Optional[MeasureAggregationParameters] = None
150
+ non_additive_dimension: Optional[NonAdditiveDimension] = None
151
+ agg_time_dimension: Optional[str] = None
152
+ config: Optional[SemanticLayerElementConfig] = None
153
+
154
+ @property
155
+ def reference(self) -> MeasureReference:
156
+ return MeasureReference(element_name=self.name)
157
+
158
+
159
+ # ====================================
160
+ # SemanticModel final parts
161
+ # ====================================
162
+
163
+
164
+ @dataclass
165
+ class SemanticModelConfig(BaseConfig):
166
+ enabled: bool = True
167
+ group: Optional[str] = field(
168
+ default=None,
169
+ metadata=CompareBehavior.Exclude.meta(),
170
+ )
171
+ meta: Dict[str, Any] = field(
172
+ default_factory=dict,
173
+ metadata=MergeBehavior.Update.meta(),
174
+ )
175
+
176
+
177
+ @dataclass
178
+ class SemanticModel(GraphResource):
179
+ model: str
180
+ node_relation: Optional[NodeRelation]
181
+ description: Optional[str] = None
182
+ label: Optional[str] = None
183
+ defaults: Optional[Defaults] = None
184
+ entities: Sequence[Entity] = field(default_factory=list)
185
+ measures: Sequence[Measure] = field(default_factory=list)
186
+ dimensions: Sequence[Dimension] = field(default_factory=list)
187
+ metadata: Optional[SourceFileMetadata] = None
188
+ depends_on: DependsOn = field(default_factory=DependsOn)
189
+ refs: List[RefArgs] = field(default_factory=list)
190
+ created_at: float = field(default_factory=lambda: time.time())
191
+ config: SemanticModelConfig = field(default_factory=SemanticModelConfig)
192
+ unrendered_config: Dict[str, Any] = field(default_factory=dict)
193
+ primary_entity: Optional[str] = None
194
+ group: Optional[str] = None
195
+
196
+ @property
197
+ def entity_references(self) -> List[LinkableElementReference]:
198
+ return [entity.reference for entity in self.entities]
199
+
200
+ @property
201
+ def dimension_references(self) -> List[LinkableElementReference]:
202
+ return [dimension.reference for dimension in self.dimensions]
203
+
204
+ @property
205
+ def measure_references(self) -> List[MeasureReference]:
206
+ return [measure.reference for measure in self.measures]
207
+
208
+ @property
209
+ def has_validity_dimensions(self) -> bool:
210
+ return any([dim.validity_params is not None for dim in self.dimensions])
211
+
212
+ @property
213
+ def validity_start_dimension(self) -> Optional[Dimension]:
214
+ validity_start_dims = [
215
+ dim for dim in self.dimensions if dim.validity_params and dim.validity_params.is_start
216
+ ]
217
+ if not validity_start_dims:
218
+ return None
219
+ return validity_start_dims[0]
220
+
221
+ @property
222
+ def validity_end_dimension(self) -> Optional[Dimension]:
223
+ validity_end_dims = [
224
+ dim for dim in self.dimensions if dim.validity_params and dim.validity_params.is_end
225
+ ]
226
+ if not validity_end_dims:
227
+ return None
228
+ return validity_end_dims[0]
229
+
230
+ @property
231
+ def partitions(self) -> List[Dimension]: # noqa: D
232
+ return [dim for dim in self.dimensions or [] if dim.is_partition]
233
+
234
+ @property
235
+ def partition(self) -> Optional[Dimension]:
236
+ partitions = self.partitions
237
+ if not partitions:
238
+ return None
239
+ return partitions[0]
240
+
241
+ @property
242
+ def reference(self) -> SemanticModelReference:
243
+ return SemanticModelReference(semantic_model_name=self.name)
244
+
245
+ def checked_agg_time_dimension_for_measure(
246
+ self, measure_reference: MeasureReference
247
+ ) -> TimeDimensionReference:
248
+ measure: Optional[Measure] = None
249
+ for measure in self.measures:
250
+ if measure.reference == measure_reference:
251
+ measure = measure
252
+
253
+ assert (
254
+ measure is not None
255
+ ), f"No measure with name ({measure_reference.element_name}) in semantic_model with name ({self.name})"
256
+
257
+ default_agg_time_dimension = (
258
+ self.defaults.agg_time_dimension if self.defaults is not None else None
259
+ )
260
+
261
+ agg_time_dimension_name = measure.agg_time_dimension or default_agg_time_dimension
262
+ assert agg_time_dimension_name is not None, (
263
+ f"Aggregation time dimension for measure {measure.name} on semantic model {self.name} is not set! "
264
+ "To fix this either specify a default `agg_time_dimension` for the semantic model or define an "
265
+ "`agg_time_dimension` on the measure directly."
266
+ )
267
+ return TimeDimensionReference(element_name=agg_time_dimension_name)
268
+
269
+ def checked_agg_time_dimension_for_simple_metric(
270
+ self, metric: Metric
271
+ ) -> TimeDimensionReference:
272
+ assert (
273
+ metric.type == MetricType.SIMPLE
274
+ ), "Only simple metrics can have an agg time dimension."
275
+ metric_agg_params = metric.type_params.metric_aggregation_params
276
+ # There are validations elsewhere to check this for metrics and provide messaging for it.
277
+ assert metric_agg_params, "Simple metrics must have metric_aggregation_params."
278
+ # This indicates a validation bug / dev error, not a user error that should appear
279
+ # in a user's YAML.
280
+ assert (
281
+ metric_agg_params.semantic_model == self.name
282
+ ), "Cannot retrieve the agg time dimension for a metric from a different model "
283
+ f"than the one that the metric belongs to. Metric `{metric.name}` belongs to model "
284
+ f"`{metric_agg_params.semantic_model}`, but we requested the agg time dimension from model `{self.name}`."
285
+
286
+ metric_time_dimension_name = None
287
+ if (
288
+ metric.type_params
289
+ and metric.type_params.metric_aggregation_params
290
+ and metric.type_params.metric_aggregation_params.agg_time_dimension
291
+ ):
292
+ metric_time_dimension_name = (
293
+ metric.type_params.metric_aggregation_params.agg_time_dimension
294
+ )
295
+
296
+ default_agg_time_dimension = (
297
+ self.defaults.agg_time_dimension if self.defaults is not None else None
298
+ )
299
+ agg_time_dimension_name = metric_time_dimension_name or default_agg_time_dimension
300
+
301
+ assert agg_time_dimension_name is not None, (
302
+ f"Aggregation time dimension for metric {metric.name} is not set! This should either be set directly on "
303
+ f"the metric specification in the model, or else defaulted to the time dimension in the data "
304
+ f"source containing the metric."
305
+ )
306
+ return TimeDimensionReference(element_name=agg_time_dimension_name)
307
+
308
+ @property
309
+ def primary_entity_reference(self) -> Optional[EntityReference]:
310
+ return (
311
+ EntityReference(element_name=self.primary_entity)
312
+ if self.primary_entity is not None
313
+ else None
314
+ )