dvt-core 1.11.0b4__py3-none-any.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 (261) hide show
  1. dvt/__init__.py +7 -0
  2. dvt/_pydantic_shim.py +26 -0
  3. dvt/adapters/__init__.py +16 -0
  4. dvt/adapters/multi_adapter_manager.py +268 -0
  5. dvt/artifacts/__init__.py +0 -0
  6. dvt/artifacts/exceptions/__init__.py +1 -0
  7. dvt/artifacts/exceptions/schemas.py +31 -0
  8. dvt/artifacts/resources/__init__.py +116 -0
  9. dvt/artifacts/resources/base.py +68 -0
  10. dvt/artifacts/resources/types.py +93 -0
  11. dvt/artifacts/resources/v1/analysis.py +10 -0
  12. dvt/artifacts/resources/v1/catalog.py +23 -0
  13. dvt/artifacts/resources/v1/components.py +275 -0
  14. dvt/artifacts/resources/v1/config.py +282 -0
  15. dvt/artifacts/resources/v1/documentation.py +11 -0
  16. dvt/artifacts/resources/v1/exposure.py +52 -0
  17. dvt/artifacts/resources/v1/function.py +53 -0
  18. dvt/artifacts/resources/v1/generic_test.py +32 -0
  19. dvt/artifacts/resources/v1/group.py +22 -0
  20. dvt/artifacts/resources/v1/hook.py +11 -0
  21. dvt/artifacts/resources/v1/macro.py +30 -0
  22. dvt/artifacts/resources/v1/metric.py +173 -0
  23. dvt/artifacts/resources/v1/model.py +146 -0
  24. dvt/artifacts/resources/v1/owner.py +10 -0
  25. dvt/artifacts/resources/v1/saved_query.py +112 -0
  26. dvt/artifacts/resources/v1/seed.py +42 -0
  27. dvt/artifacts/resources/v1/semantic_layer_components.py +72 -0
  28. dvt/artifacts/resources/v1/semantic_model.py +315 -0
  29. dvt/artifacts/resources/v1/singular_test.py +14 -0
  30. dvt/artifacts/resources/v1/snapshot.py +92 -0
  31. dvt/artifacts/resources/v1/source_definition.py +85 -0
  32. dvt/artifacts/resources/v1/sql_operation.py +10 -0
  33. dvt/artifacts/resources/v1/unit_test_definition.py +78 -0
  34. dvt/artifacts/schemas/__init__.py +0 -0
  35. dvt/artifacts/schemas/base.py +191 -0
  36. dvt/artifacts/schemas/batch_results.py +24 -0
  37. dvt/artifacts/schemas/catalog/__init__.py +12 -0
  38. dvt/artifacts/schemas/catalog/v1/__init__.py +0 -0
  39. dvt/artifacts/schemas/catalog/v1/catalog.py +60 -0
  40. dvt/artifacts/schemas/freshness/__init__.py +1 -0
  41. dvt/artifacts/schemas/freshness/v3/__init__.py +0 -0
  42. dvt/artifacts/schemas/freshness/v3/freshness.py +159 -0
  43. dvt/artifacts/schemas/manifest/__init__.py +2 -0
  44. dvt/artifacts/schemas/manifest/v12/__init__.py +0 -0
  45. dvt/artifacts/schemas/manifest/v12/manifest.py +212 -0
  46. dvt/artifacts/schemas/results.py +148 -0
  47. dvt/artifacts/schemas/run/__init__.py +2 -0
  48. dvt/artifacts/schemas/run/v5/__init__.py +0 -0
  49. dvt/artifacts/schemas/run/v5/run.py +184 -0
  50. dvt/artifacts/schemas/upgrades/__init__.py +4 -0
  51. dvt/artifacts/schemas/upgrades/upgrade_manifest.py +174 -0
  52. dvt/artifacts/schemas/upgrades/upgrade_manifest_dbt_version.py +2 -0
  53. dvt/artifacts/utils/validation.py +153 -0
  54. dvt/cli/__init__.py +1 -0
  55. dvt/cli/context.py +16 -0
  56. dvt/cli/exceptions.py +56 -0
  57. dvt/cli/flags.py +558 -0
  58. dvt/cli/main.py +971 -0
  59. dvt/cli/option_types.py +121 -0
  60. dvt/cli/options.py +79 -0
  61. dvt/cli/params.py +803 -0
  62. dvt/cli/requires.py +478 -0
  63. dvt/cli/resolvers.py +32 -0
  64. dvt/cli/types.py +40 -0
  65. dvt/clients/__init__.py +0 -0
  66. dvt/clients/checked_load.py +82 -0
  67. dvt/clients/git.py +164 -0
  68. dvt/clients/jinja.py +206 -0
  69. dvt/clients/jinja_static.py +245 -0
  70. dvt/clients/registry.py +192 -0
  71. dvt/clients/yaml_helper.py +68 -0
  72. dvt/compilation.py +833 -0
  73. dvt/compute/__init__.py +26 -0
  74. dvt/compute/base.py +288 -0
  75. dvt/compute/engines/__init__.py +13 -0
  76. dvt/compute/engines/duckdb_engine.py +368 -0
  77. dvt/compute/engines/spark_engine.py +273 -0
  78. dvt/compute/query_analyzer.py +212 -0
  79. dvt/compute/router.py +483 -0
  80. dvt/config/__init__.py +4 -0
  81. dvt/config/catalogs.py +95 -0
  82. dvt/config/compute_config.py +406 -0
  83. dvt/config/profile.py +411 -0
  84. dvt/config/profiles_v2.py +464 -0
  85. dvt/config/project.py +893 -0
  86. dvt/config/renderer.py +232 -0
  87. dvt/config/runtime.py +491 -0
  88. dvt/config/selectors.py +209 -0
  89. dvt/config/utils.py +78 -0
  90. dvt/connectors/.gitignore +6 -0
  91. dvt/connectors/README.md +306 -0
  92. dvt/connectors/catalog.yml +217 -0
  93. dvt/connectors/download_connectors.py +300 -0
  94. dvt/constants.py +29 -0
  95. dvt/context/__init__.py +0 -0
  96. dvt/context/base.py +746 -0
  97. dvt/context/configured.py +136 -0
  98. dvt/context/context_config.py +350 -0
  99. dvt/context/docs.py +82 -0
  100. dvt/context/exceptions_jinja.py +179 -0
  101. dvt/context/macro_resolver.py +195 -0
  102. dvt/context/macros.py +171 -0
  103. dvt/context/manifest.py +73 -0
  104. dvt/context/providers.py +2198 -0
  105. dvt/context/query_header.py +14 -0
  106. dvt/context/secret.py +59 -0
  107. dvt/context/target.py +74 -0
  108. dvt/contracts/__init__.py +0 -0
  109. dvt/contracts/files.py +413 -0
  110. dvt/contracts/graph/__init__.py +0 -0
  111. dvt/contracts/graph/manifest.py +1904 -0
  112. dvt/contracts/graph/metrics.py +98 -0
  113. dvt/contracts/graph/model_config.py +71 -0
  114. dvt/contracts/graph/node_args.py +42 -0
  115. dvt/contracts/graph/nodes.py +1806 -0
  116. dvt/contracts/graph/semantic_manifest.py +233 -0
  117. dvt/contracts/graph/unparsed.py +812 -0
  118. dvt/contracts/project.py +417 -0
  119. dvt/contracts/results.py +53 -0
  120. dvt/contracts/selection.py +23 -0
  121. dvt/contracts/sql.py +86 -0
  122. dvt/contracts/state.py +69 -0
  123. dvt/contracts/util.py +46 -0
  124. dvt/deprecations.py +347 -0
  125. dvt/deps/__init__.py +0 -0
  126. dvt/deps/base.py +153 -0
  127. dvt/deps/git.py +196 -0
  128. dvt/deps/local.py +80 -0
  129. dvt/deps/registry.py +131 -0
  130. dvt/deps/resolver.py +149 -0
  131. dvt/deps/tarball.py +121 -0
  132. dvt/docs/source/_ext/dbt_click.py +118 -0
  133. dvt/docs/source/conf.py +32 -0
  134. dvt/env_vars.py +64 -0
  135. dvt/event_time/event_time.py +40 -0
  136. dvt/event_time/sample_window.py +60 -0
  137. dvt/events/__init__.py +16 -0
  138. dvt/events/base_types.py +37 -0
  139. dvt/events/core_types_pb2.py +2 -0
  140. dvt/events/logging.py +109 -0
  141. dvt/events/types.py +2534 -0
  142. dvt/exceptions.py +1487 -0
  143. dvt/flags.py +89 -0
  144. dvt/graph/__init__.py +11 -0
  145. dvt/graph/cli.py +248 -0
  146. dvt/graph/graph.py +172 -0
  147. dvt/graph/queue.py +213 -0
  148. dvt/graph/selector.py +375 -0
  149. dvt/graph/selector_methods.py +976 -0
  150. dvt/graph/selector_spec.py +223 -0
  151. dvt/graph/thread_pool.py +18 -0
  152. dvt/hooks.py +21 -0
  153. dvt/include/README.md +49 -0
  154. dvt/include/__init__.py +3 -0
  155. dvt/include/global_project.py +4 -0
  156. dvt/include/starter_project/.gitignore +4 -0
  157. dvt/include/starter_project/README.md +15 -0
  158. dvt/include/starter_project/__init__.py +3 -0
  159. dvt/include/starter_project/analyses/.gitkeep +0 -0
  160. dvt/include/starter_project/dvt_project.yml +36 -0
  161. dvt/include/starter_project/macros/.gitkeep +0 -0
  162. dvt/include/starter_project/models/example/my_first_dbt_model.sql +27 -0
  163. dvt/include/starter_project/models/example/my_second_dbt_model.sql +6 -0
  164. dvt/include/starter_project/models/example/schema.yml +21 -0
  165. dvt/include/starter_project/seeds/.gitkeep +0 -0
  166. dvt/include/starter_project/snapshots/.gitkeep +0 -0
  167. dvt/include/starter_project/tests/.gitkeep +0 -0
  168. dvt/internal_deprecations.py +27 -0
  169. dvt/jsonschemas/__init__.py +3 -0
  170. dvt/jsonschemas/jsonschemas.py +309 -0
  171. dvt/jsonschemas/project/0.0.110.json +4717 -0
  172. dvt/jsonschemas/project/0.0.85.json +2015 -0
  173. dvt/jsonschemas/resources/0.0.110.json +2636 -0
  174. dvt/jsonschemas/resources/0.0.85.json +2536 -0
  175. dvt/jsonschemas/resources/latest.json +6773 -0
  176. dvt/links.py +4 -0
  177. dvt/materializations/__init__.py +0 -0
  178. dvt/materializations/incremental/__init__.py +0 -0
  179. dvt/materializations/incremental/microbatch.py +235 -0
  180. dvt/mp_context.py +8 -0
  181. dvt/node_types.py +37 -0
  182. dvt/parser/__init__.py +23 -0
  183. dvt/parser/analysis.py +21 -0
  184. dvt/parser/base.py +549 -0
  185. dvt/parser/common.py +267 -0
  186. dvt/parser/docs.py +52 -0
  187. dvt/parser/fixtures.py +51 -0
  188. dvt/parser/functions.py +30 -0
  189. dvt/parser/generic_test.py +100 -0
  190. dvt/parser/generic_test_builders.py +334 -0
  191. dvt/parser/hooks.py +119 -0
  192. dvt/parser/macros.py +137 -0
  193. dvt/parser/manifest.py +2204 -0
  194. dvt/parser/models.py +574 -0
  195. dvt/parser/partial.py +1179 -0
  196. dvt/parser/read_files.py +445 -0
  197. dvt/parser/schema_generic_tests.py +423 -0
  198. dvt/parser/schema_renderer.py +111 -0
  199. dvt/parser/schema_yaml_readers.py +936 -0
  200. dvt/parser/schemas.py +1467 -0
  201. dvt/parser/search.py +149 -0
  202. dvt/parser/seeds.py +28 -0
  203. dvt/parser/singular_test.py +20 -0
  204. dvt/parser/snapshots.py +44 -0
  205. dvt/parser/sources.py +557 -0
  206. dvt/parser/sql.py +63 -0
  207. dvt/parser/unit_tests.py +622 -0
  208. dvt/plugins/__init__.py +20 -0
  209. dvt/plugins/contracts.py +10 -0
  210. dvt/plugins/exceptions.py +2 -0
  211. dvt/plugins/manager.py +164 -0
  212. dvt/plugins/manifest.py +21 -0
  213. dvt/profiler.py +20 -0
  214. dvt/py.typed +1 -0
  215. dvt/runners/__init__.py +2 -0
  216. dvt/runners/exposure_runner.py +7 -0
  217. dvt/runners/no_op_runner.py +46 -0
  218. dvt/runners/saved_query_runner.py +7 -0
  219. dvt/selected_resources.py +8 -0
  220. dvt/task/__init__.py +0 -0
  221. dvt/task/base.py +504 -0
  222. dvt/task/build.py +197 -0
  223. dvt/task/clean.py +57 -0
  224. dvt/task/clone.py +162 -0
  225. dvt/task/compile.py +151 -0
  226. dvt/task/compute.py +366 -0
  227. dvt/task/debug.py +650 -0
  228. dvt/task/deps.py +280 -0
  229. dvt/task/docs/__init__.py +3 -0
  230. dvt/task/docs/generate.py +408 -0
  231. dvt/task/docs/index.html +250 -0
  232. dvt/task/docs/serve.py +28 -0
  233. dvt/task/freshness.py +323 -0
  234. dvt/task/function.py +122 -0
  235. dvt/task/group_lookup.py +46 -0
  236. dvt/task/init.py +374 -0
  237. dvt/task/list.py +237 -0
  238. dvt/task/printer.py +176 -0
  239. dvt/task/profiles.py +256 -0
  240. dvt/task/retry.py +175 -0
  241. dvt/task/run.py +1146 -0
  242. dvt/task/run_operation.py +142 -0
  243. dvt/task/runnable.py +802 -0
  244. dvt/task/seed.py +104 -0
  245. dvt/task/show.py +150 -0
  246. dvt/task/snapshot.py +57 -0
  247. dvt/task/sql.py +111 -0
  248. dvt/task/test.py +464 -0
  249. dvt/tests/fixtures/__init__.py +1 -0
  250. dvt/tests/fixtures/project.py +620 -0
  251. dvt/tests/util.py +651 -0
  252. dvt/tracking.py +529 -0
  253. dvt/utils/__init__.py +3 -0
  254. dvt/utils/artifact_upload.py +151 -0
  255. dvt/utils/utils.py +408 -0
  256. dvt/version.py +249 -0
  257. dvt_core-1.11.0b4.dist-info/METADATA +252 -0
  258. dvt_core-1.11.0b4.dist-info/RECORD +261 -0
  259. dvt_core-1.11.0b4.dist-info/WHEEL +5 -0
  260. dvt_core-1.11.0b4.dist-info/entry_points.txt +2 -0
  261. dvt_core-1.11.0b4.dist-info/top_level.txt +1 -0
@@ -0,0 +1,315 @@
1
+ import time
2
+ from dataclasses import dataclass, field
3
+ from typing import Any, Dict, List, Optional, Sequence
4
+
5
+ from dvt.artifacts.resources import SourceFileMetadata
6
+ from dvt.artifacts.resources.base import GraphResource
7
+ from dvt.artifacts.resources.v1.components import DependsOn, RefArgs
8
+ from dvt.artifacts.resources.v1.metric import Metric
9
+ from dvt.artifacts.resources.v1.semantic_layer_components import (
10
+ MeasureAggregationParameters,
11
+ NonAdditiveDimension,
12
+ )
13
+
14
+ from dbt_common.contracts.config.base import BaseConfig, CompareBehavior, MergeBehavior
15
+ from dbt_common.dataclass_schema import dbtClassMixin
16
+ from dbt_semantic_interfaces.references import (
17
+ DimensionReference,
18
+ EntityReference,
19
+ LinkableElementReference,
20
+ MeasureReference,
21
+ SemanticModelReference,
22
+ TimeDimensionReference,
23
+ )
24
+ from dbt_semantic_interfaces.type_enums import (
25
+ AggregationType,
26
+ DimensionType,
27
+ EntityType,
28
+ MetricType,
29
+ TimeGranularity,
30
+ )
31
+
32
+ """
33
+ The classes in this file are dataclasses which are used to construct the Semantic
34
+ Model node in dbt-core. Additionally, these classes need to at a minimum support
35
+ what is specified in their protocol definitions in dbt-semantic-interfaces.
36
+ Their protocol definitions can be found here:
37
+ https://github.com/dbt-labs/dbt-semantic-interfaces/blob/main/dbt_semantic_interfaces/protocols/semantic_model.py
38
+ """
39
+
40
+
41
+ @dataclass
42
+ class SemanticLayerElementConfig(dbtClassMixin):
43
+ meta: Dict[str, Any] = field(
44
+ default_factory=dict,
45
+ metadata=MergeBehavior.Update.meta(),
46
+ )
47
+
48
+
49
+ @dataclass
50
+ class Defaults(dbtClassMixin):
51
+ agg_time_dimension: Optional[str] = None
52
+
53
+
54
+ @dataclass
55
+ class NodeRelation(dbtClassMixin):
56
+ alias: str
57
+ schema_name: str # TODO: Could this be called simply "schema" so we could reuse StateRelation?
58
+ database: Optional[str] = None
59
+ relation_name: Optional[str] = ""
60
+
61
+
62
+ # ====================================
63
+ # Dimension objects
64
+ # Dimension protocols: https://github.com/dbt-labs/dbt-semantic-interfaces/blob/main/dbt_semantic_interfaces/protocols/dimension.py
65
+ # ====================================
66
+
67
+
68
+ @dataclass
69
+ class DimensionValidityParams(dbtClassMixin):
70
+ is_start: bool = False
71
+ is_end: bool = False
72
+
73
+
74
+ @dataclass
75
+ class DimensionTypeParams(dbtClassMixin):
76
+ time_granularity: TimeGranularity
77
+ validity_params: Optional[DimensionValidityParams] = None
78
+
79
+
80
+ @dataclass
81
+ class Dimension(dbtClassMixin):
82
+ name: str
83
+ type: DimensionType
84
+ description: Optional[str] = None
85
+ label: Optional[str] = None
86
+ is_partition: bool = False
87
+ type_params: Optional[DimensionTypeParams] = None
88
+ expr: Optional[str] = None
89
+ metadata: Optional[SourceFileMetadata] = None
90
+ config: Optional[SemanticLayerElementConfig] = None
91
+
92
+ @property
93
+ def reference(self) -> DimensionReference:
94
+ return DimensionReference(element_name=self.name)
95
+
96
+ @property
97
+ def time_dimension_reference(self) -> Optional[TimeDimensionReference]:
98
+ if self.type == DimensionType.TIME:
99
+ return TimeDimensionReference(element_name=self.name)
100
+ else:
101
+ return None
102
+
103
+ @property
104
+ def validity_params(self) -> Optional[DimensionValidityParams]:
105
+ if self.type_params:
106
+ return self.type_params.validity_params
107
+ else:
108
+ return None
109
+
110
+
111
+ # ====================================
112
+ # Entity objects
113
+ # Entity protocols: https://github.com/dbt-labs/dbt-semantic-interfaces/blob/main/dbt_semantic_interfaces/protocols/entity.py
114
+ # ====================================
115
+
116
+
117
+ @dataclass
118
+ class Entity(dbtClassMixin):
119
+ name: str
120
+ type: EntityType
121
+ description: Optional[str] = None
122
+ label: Optional[str] = None
123
+ role: Optional[str] = None
124
+ expr: Optional[str] = None
125
+ config: Optional[SemanticLayerElementConfig] = None
126
+
127
+ @property
128
+ def reference(self) -> EntityReference:
129
+ return EntityReference(element_name=self.name)
130
+
131
+ @property
132
+ def is_linkable_entity_type(self) -> bool:
133
+ return self.type in (EntityType.PRIMARY, EntityType.UNIQUE, EntityType.NATURAL)
134
+
135
+
136
+ # ====================================
137
+ # Measure object
138
+ # Measure protocols: https://github.com/dbt-labs/dbt-semantic-interfaces/blob/main/dbt_semantic_interfaces/protocols/measure.py
139
+ # ====================================
140
+
141
+
142
+ @dataclass
143
+ class Measure(dbtClassMixin):
144
+ name: str
145
+ agg: AggregationType
146
+ description: Optional[str] = None
147
+ label: Optional[str] = None
148
+ create_metric: bool = False
149
+ expr: Optional[str] = None
150
+ agg_params: Optional[MeasureAggregationParameters] = None
151
+ non_additive_dimension: Optional[NonAdditiveDimension] = None
152
+ agg_time_dimension: Optional[str] = None
153
+ config: Optional[SemanticLayerElementConfig] = None
154
+
155
+ @property
156
+ def reference(self) -> MeasureReference:
157
+ return MeasureReference(element_name=self.name)
158
+
159
+
160
+ # ====================================
161
+ # SemanticModel final parts
162
+ # ====================================
163
+
164
+
165
+ @dataclass
166
+ class SemanticModelConfig(BaseConfig):
167
+ enabled: bool = True
168
+ group: Optional[str] = field(
169
+ default=None,
170
+ metadata=CompareBehavior.Exclude.meta(),
171
+ )
172
+ meta: Dict[str, Any] = field(
173
+ default_factory=dict,
174
+ metadata=MergeBehavior.Update.meta(),
175
+ )
176
+
177
+
178
+ @dataclass
179
+ class SemanticModel(GraphResource):
180
+ model: str
181
+ node_relation: Optional[NodeRelation]
182
+ description: Optional[str] = None
183
+ label: Optional[str] = None
184
+ defaults: Optional[Defaults] = None
185
+ entities: Sequence[Entity] = field(default_factory=list)
186
+ measures: Sequence[Measure] = field(default_factory=list)
187
+ dimensions: Sequence[Dimension] = field(default_factory=list)
188
+ metadata: Optional[SourceFileMetadata] = None
189
+ depends_on: DependsOn = field(default_factory=DependsOn)
190
+ refs: List[RefArgs] = field(default_factory=list)
191
+ created_at: float = field(default_factory=lambda: time.time())
192
+ config: SemanticModelConfig = field(default_factory=SemanticModelConfig)
193
+ unrendered_config: Dict[str, Any] = field(default_factory=dict)
194
+ primary_entity: Optional[str] = None
195
+ group: Optional[str] = None
196
+
197
+ @property
198
+ def entity_references(self) -> List[LinkableElementReference]:
199
+ return [entity.reference for entity in self.entities]
200
+
201
+ @property
202
+ def dimension_references(self) -> List[LinkableElementReference]:
203
+ return [dimension.reference for dimension in self.dimensions]
204
+
205
+ @property
206
+ def measure_references(self) -> List[MeasureReference]:
207
+ return [measure.reference for measure in self.measures]
208
+
209
+ @property
210
+ def has_validity_dimensions(self) -> bool:
211
+ return any([dim.validity_params is not None for dim in self.dimensions])
212
+
213
+ @property
214
+ def validity_start_dimension(self) -> Optional[Dimension]:
215
+ validity_start_dims = [
216
+ dim for dim in self.dimensions if dim.validity_params and dim.validity_params.is_start
217
+ ]
218
+ if not validity_start_dims:
219
+ return None
220
+ return validity_start_dims[0]
221
+
222
+ @property
223
+ def validity_end_dimension(self) -> Optional[Dimension]:
224
+ validity_end_dims = [
225
+ dim for dim in self.dimensions if dim.validity_params and dim.validity_params.is_end
226
+ ]
227
+ if not validity_end_dims:
228
+ return None
229
+ return validity_end_dims[0]
230
+
231
+ @property
232
+ def partitions(self) -> List[Dimension]: # noqa: D
233
+ return [dim for dim in self.dimensions or [] if dim.is_partition]
234
+
235
+ @property
236
+ def partition(self) -> Optional[Dimension]:
237
+ partitions = self.partitions
238
+ if not partitions:
239
+ return None
240
+ return partitions[0]
241
+
242
+ @property
243
+ def reference(self) -> SemanticModelReference:
244
+ return SemanticModelReference(semantic_model_name=self.name)
245
+
246
+ def checked_agg_time_dimension_for_measure(
247
+ self, measure_reference: MeasureReference
248
+ ) -> TimeDimensionReference:
249
+ measure: Optional[Measure] = None
250
+ for measure in self.measures:
251
+ if measure.reference == measure_reference:
252
+ measure = measure
253
+
254
+ assert (
255
+ measure is not None
256
+ ), f"No measure with name ({measure_reference.element_name}) in semantic_model with name ({self.name})"
257
+
258
+ default_agg_time_dimension = (
259
+ self.defaults.agg_time_dimension if self.defaults is not None else None
260
+ )
261
+
262
+ agg_time_dimension_name = measure.agg_time_dimension or default_agg_time_dimension
263
+ assert agg_time_dimension_name is not None, (
264
+ f"Aggregation time dimension for measure {measure.name} on semantic model {self.name} is not set! "
265
+ "To fix this either specify a default `agg_time_dimension` for the semantic model or define an "
266
+ "`agg_time_dimension` on the measure directly."
267
+ )
268
+ return TimeDimensionReference(element_name=agg_time_dimension_name)
269
+
270
+ def checked_agg_time_dimension_for_simple_metric(
271
+ self, metric: Metric
272
+ ) -> TimeDimensionReference:
273
+ assert (
274
+ metric.type == MetricType.SIMPLE
275
+ ), "Only simple metrics can have an agg time dimension."
276
+ metric_agg_params = metric.type_params.metric_aggregation_params
277
+ # There are validations elsewhere to check this for metrics and provide messaging for it.
278
+ assert metric_agg_params, "Simple metrics must have metric_aggregation_params."
279
+ # This indicates a validation bug / dev error, not a user error that should appear
280
+ # in a user's YAML.
281
+ assert (
282
+ metric_agg_params.semantic_model == self.name
283
+ ), "Cannot retrieve the agg time dimension for a metric from a different model "
284
+ f"than the one that the metric belongs to. Metric `{metric.name}` belongs to model "
285
+ f"`{metric_agg_params.semantic_model}`, but we requested the agg time dimension from model `{self.name}`."
286
+
287
+ metric_time_dimension_name = None
288
+ if (
289
+ metric.type_params
290
+ and metric.type_params.metric_aggregation_params
291
+ and metric.type_params.metric_aggregation_params.agg_time_dimension
292
+ ):
293
+ metric_time_dimension_name = (
294
+ metric.type_params.metric_aggregation_params.agg_time_dimension
295
+ )
296
+
297
+ default_agg_time_dimension = (
298
+ self.defaults.agg_time_dimension if self.defaults is not None else None
299
+ )
300
+ agg_time_dimension_name = metric_time_dimension_name or default_agg_time_dimension
301
+
302
+ assert agg_time_dimension_name is not None, (
303
+ f"Aggregation time dimension for metric {metric.name} is not set! This should either be set directly on "
304
+ f"the metric specification in the model, or else defaulted to the time dimension in the data "
305
+ f"source containing the metric."
306
+ )
307
+ return TimeDimensionReference(element_name=agg_time_dimension_name)
308
+
309
+ @property
310
+ def primary_entity_reference(self) -> Optional[EntityReference]:
311
+ return (
312
+ EntityReference(element_name=self.primary_entity)
313
+ if self.primary_entity is not None
314
+ else None
315
+ )
@@ -0,0 +1,14 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Literal
3
+
4
+ from dvt.artifacts.resources.types import NodeType
5
+ from dvt.artifacts.resources.v1.components import CompiledResource
6
+ from dvt.artifacts.resources.v1.config import TestConfig
7
+
8
+
9
+ @dataclass
10
+ class SingularTest(CompiledResource):
11
+ resource_type: Literal[NodeType.Test]
12
+ # Was not able to make mypy happy and keep the code working. We need to
13
+ # refactor the various configs.
14
+ config: TestConfig = field(default_factory=TestConfig) # type: ignore
@@ -0,0 +1,92 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Dict, List, Literal, Optional, Union
3
+
4
+ from dvt.artifacts.resources.types import NodeType
5
+ from dvt.artifacts.resources.v1.components import CompiledResource, DeferRelation
6
+ from dvt.artifacts.resources.v1.config import NodeConfig
7
+
8
+ from dbt_common.dataclass_schema import ValidationError, dbtClassMixin
9
+
10
+
11
+ @dataclass
12
+ class SnapshotMetaColumnNames(dbtClassMixin):
13
+ dbt_valid_to: Optional[str] = None
14
+ dbt_valid_from: Optional[str] = None
15
+ dbt_scd_id: Optional[str] = None
16
+ dbt_updated_at: Optional[str] = None
17
+ dbt_is_deleted: Optional[str] = None
18
+
19
+
20
+ @dataclass
21
+ class SnapshotConfig(NodeConfig):
22
+ materialized: str = "snapshot"
23
+ strategy: Optional[str] = None
24
+ unique_key: Union[str, List[str], None] = None
25
+ target_schema: Optional[str] = None
26
+ target_database: Optional[str] = None
27
+ updated_at: Optional[str] = None
28
+ # Not using Optional because of serialization issues with a Union of str and List[str]
29
+ check_cols: Union[str, List[str], None] = None
30
+ snapshot_meta_column_names: SnapshotMetaColumnNames = field(
31
+ default_factory=SnapshotMetaColumnNames
32
+ )
33
+ dbt_valid_to_current: Optional[str] = None
34
+
35
+ @property
36
+ def snapshot_table_column_names(self):
37
+ return {
38
+ "dbt_valid_from": self.snapshot_meta_column_names.dbt_valid_from or "dbt_valid_from",
39
+ "dbt_valid_to": self.snapshot_meta_column_names.dbt_valid_to or "dbt_valid_to",
40
+ "dbt_scd_id": self.snapshot_meta_column_names.dbt_scd_id or "dbt_scd_id",
41
+ "dbt_updated_at": self.snapshot_meta_column_names.dbt_updated_at or "dbt_updated_at",
42
+ "dbt_is_deleted": self.snapshot_meta_column_names.dbt_is_deleted or "dbt_is_deleted",
43
+ }
44
+
45
+ def final_validate(self):
46
+ if not self.strategy or not self.unique_key:
47
+ raise ValidationError(
48
+ "Snapshots must be configured with a 'strategy' and 'unique_key'."
49
+ )
50
+ if self.strategy == "check":
51
+ if not self.check_cols:
52
+ raise ValidationError(
53
+ "A snapshot configured with the check strategy must "
54
+ "specify a check_cols configuration."
55
+ )
56
+ if isinstance(self.check_cols, str) and self.check_cols != "all":
57
+ raise ValidationError(
58
+ f"Invalid value for 'check_cols': {self.check_cols}. "
59
+ "Expected 'all' or a list of strings."
60
+ )
61
+ elif self.strategy == "timestamp":
62
+ if not self.updated_at:
63
+ raise ValidationError(
64
+ "A snapshot configured with the timestamp strategy "
65
+ "must specify an updated_at configuration."
66
+ )
67
+ if self.check_cols:
68
+ raise ValidationError("A 'timestamp' snapshot should not have 'check_cols'")
69
+ # If the strategy is not 'check' or 'timestamp' it's a custom strategy,
70
+ # formerly supported with GenericSnapshotConfig
71
+
72
+ if self.materialized and self.materialized != "snapshot":
73
+ raise ValidationError("A snapshot must have a materialized value of 'snapshot'")
74
+
75
+ # Called by "calculate_node_config_dict" in ContextConfigGenerator
76
+ def finalize_and_validate(self):
77
+ data = self.to_dict(omit_none=True)
78
+ self.validate(data)
79
+ return self.from_dict(data)
80
+
81
+
82
+ @dataclass
83
+ class Snapshot(CompiledResource):
84
+ resource_type: Literal[NodeType.Snapshot]
85
+ config: SnapshotConfig
86
+ defer_relation: Optional[DeferRelation] = None
87
+
88
+ def __post_serialize__(self, dct, context: Optional[Dict] = None):
89
+ dct = super().__post_serialize__(dct, context)
90
+ if context and context.get("artifact") and "defer_relation" in dct:
91
+ del dct["defer_relation"]
92
+ return dct
@@ -0,0 +1,85 @@
1
+ import time
2
+ from dataclasses import dataclass, field
3
+ from typing import Any, Dict, List, Literal, Optional, Union
4
+
5
+ from dvt.artifacts.resources.base import GraphResource
6
+ from dvt.artifacts.resources.types import NodeType
7
+ from dvt.artifacts.resources.v1.components import (
8
+ ColumnInfo,
9
+ FreshnessThreshold,
10
+ HasRelationMetadata,
11
+ Quoting,
12
+ )
13
+ from dvt.artifacts.resources.v1.config import BaseConfig, MergeBehavior
14
+
15
+ from dbt_common.contracts.config.properties import AdditionalPropertiesAllowed
16
+ from dbt_common.contracts.util import Mergeable
17
+ from dbt_common.exceptions import CompilationError
18
+
19
+
20
+ @dataclass
21
+ class SourceConfig(BaseConfig):
22
+ enabled: bool = True
23
+ event_time: Any = None
24
+ freshness: Optional[FreshnessThreshold] = field(default_factory=FreshnessThreshold)
25
+ loaded_at_field: Optional[str] = None
26
+ loaded_at_query: Optional[str] = None
27
+ meta: Dict[str, Any] = field(default_factory=dict, metadata=MergeBehavior.Update.meta())
28
+ tags: List[str] = field(default_factory=list)
29
+
30
+
31
+ @dataclass
32
+ class ExternalPartition(AdditionalPropertiesAllowed):
33
+ name: str = ""
34
+ description: str = ""
35
+ data_type: str = ""
36
+ meta: Dict[str, Any] = field(default_factory=dict)
37
+
38
+ def __post_init__(self):
39
+ if self.name == "" or self.data_type == "":
40
+ raise CompilationError("External partition columns must have names and data types")
41
+
42
+
43
+ @dataclass
44
+ class ExternalTable(AdditionalPropertiesAllowed, Mergeable):
45
+ location: Optional[str] = None
46
+ file_format: Optional[str] = None
47
+ row_format: Optional[str] = None
48
+ tbl_properties: Optional[str] = None
49
+ partitions: Optional[Union[List[str], List[ExternalPartition]]] = None
50
+
51
+ def __bool__(self):
52
+ return self.location is not None
53
+
54
+
55
+ @dataclass
56
+ class ParsedSourceMandatory(GraphResource, HasRelationMetadata):
57
+ source_name: str
58
+ source_description: str
59
+ loader: str
60
+ identifier: str
61
+ resource_type: Literal[NodeType.Source]
62
+
63
+
64
+ @dataclass
65
+ class SourceDefinition(ParsedSourceMandatory):
66
+ quoting: Quoting = field(default_factory=Quoting)
67
+ loaded_at_field: Optional[str] = None
68
+ loaded_at_query: Optional[str] = None
69
+ freshness: Optional[FreshnessThreshold] = None
70
+ external: Optional[ExternalTable] = None
71
+ description: str = ""
72
+ columns: Dict[str, ColumnInfo] = field(default_factory=dict)
73
+ meta: Dict[str, Any] = field(default_factory=dict)
74
+ source_meta: Dict[str, Any] = field(default_factory=dict)
75
+ tags: List[str] = field(default_factory=list)
76
+ config: SourceConfig = field(default_factory=SourceConfig)
77
+ patch_path: Optional[str] = None
78
+ unrendered_config: Dict[str, Any] = field(default_factory=dict)
79
+ relation_name: Optional[str] = None
80
+ created_at: float = field(default_factory=lambda: time.time())
81
+ unrendered_database: Optional[str] = None
82
+ unrendered_schema: Optional[str] = None
83
+ doc_blocks: List[str] = field(default_factory=list)
84
+ # DVT-specific: profile reference for multi-source support
85
+ profile: Optional[str] = None
@@ -0,0 +1,10 @@
1
+ from dataclasses import dataclass
2
+ from typing import Literal
3
+
4
+ from dvt.artifacts.resources.types import NodeType
5
+ from dvt.artifacts.resources.v1.components import CompiledResource
6
+
7
+
8
+ @dataclass
9
+ class SqlOperation(CompiledResource):
10
+ resource_type: Literal[NodeType.SqlOperation]
@@ -0,0 +1,78 @@
1
+ import time
2
+ from dataclasses import dataclass, field
3
+ from typing import Any, Dict, List, Optional, Sequence, Union
4
+
5
+ from dvt.artifacts.resources import DependsOn, NodeVersion
6
+ from dvt.artifacts.resources.base import GraphResource
7
+ from dvt.artifacts.resources.v1.config import list_str, metas
8
+
9
+ from dbt_common.contracts.config.base import BaseConfig, CompareBehavior, MergeBehavior
10
+ from dbt_common.contracts.config.metadata import ShowBehavior
11
+ from dbt_common.dataclass_schema import StrEnum, dbtClassMixin
12
+
13
+
14
+ @dataclass
15
+ class UnitTestConfig(BaseConfig):
16
+ tags: Union[str, List[str]] = field(
17
+ default_factory=list_str,
18
+ metadata=metas(ShowBehavior.Hide, MergeBehavior.Append, CompareBehavior.Exclude),
19
+ )
20
+ meta: Dict[str, Any] = field(
21
+ default_factory=dict,
22
+ metadata=MergeBehavior.Update.meta(),
23
+ )
24
+ enabled: bool = True
25
+
26
+
27
+ class UnitTestFormat(StrEnum):
28
+ CSV = "csv"
29
+ Dict = "dict"
30
+ SQL = "sql"
31
+
32
+
33
+ @dataclass
34
+ class UnitTestInputFixture(dbtClassMixin):
35
+ input: str
36
+ rows: Optional[Union[str, List[Dict[str, Any]]]] = None
37
+ format: UnitTestFormat = UnitTestFormat.Dict
38
+ fixture: Optional[str] = None
39
+
40
+
41
+ @dataclass
42
+ class UnitTestOverrides(dbtClassMixin):
43
+ macros: Dict[str, Any] = field(default_factory=dict)
44
+ vars: Dict[str, Any] = field(default_factory=dict)
45
+ env_vars: Dict[str, Any] = field(default_factory=dict)
46
+
47
+
48
+ @dataclass
49
+ class UnitTestNodeVersions(dbtClassMixin):
50
+ include: Optional[List[NodeVersion]] = None
51
+ exclude: Optional[List[NodeVersion]] = None
52
+
53
+
54
+ @dataclass
55
+ class UnitTestOutputFixture(dbtClassMixin):
56
+ rows: Optional[Union[str, List[Dict[str, Any]]]] = None
57
+ format: UnitTestFormat = UnitTestFormat.Dict
58
+ fixture: Optional[str] = None
59
+
60
+
61
+ @dataclass
62
+ class UnitTestDefinitionMandatory:
63
+ model: str
64
+ given: Sequence[UnitTestInputFixture]
65
+ expect: UnitTestOutputFixture
66
+
67
+
68
+ @dataclass
69
+ class UnitTestDefinition(GraphResource, UnitTestDefinitionMandatory):
70
+ description: str = ""
71
+ overrides: Optional[UnitTestOverrides] = None
72
+ depends_on: DependsOn = field(default_factory=DependsOn)
73
+ config: UnitTestConfig = field(default_factory=UnitTestConfig)
74
+ checksum: Optional[str] = None
75
+ schema: Optional[str] = None
76
+ created_at: float = field(default_factory=lambda: time.time())
77
+ versions: Optional[UnitTestNodeVersions] = None
78
+ version: Optional[NodeVersion] = None
File without changes