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,417 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Any, ClassVar, Dict, List, Optional, Union
3
+
4
+ from dvt.contracts.util import Identifier, list_str
5
+ from mashumaro.jsonschema.annotations import Pattern
6
+ from mashumaro.types import SerializableType
7
+ from typing_extensions import Annotated
8
+
9
+ from dbt.adapters.contracts.connection import QueryComment
10
+ from dbt_common.contracts.util import Mergeable
11
+ from dbt_common.dataclass_schema import (
12
+ ExtensibleDbtClassMixin,
13
+ ValidationError,
14
+ dbtClassMixin,
15
+ dbtMashConfig,
16
+ )
17
+ from dbt_common.helper_types import NoValue
18
+
19
+ DEFAULT_SEND_ANONYMOUS_USAGE_STATS = True
20
+
21
+
22
+ class SemverString(str, SerializableType):
23
+ def _serialize(self) -> str:
24
+ return self
25
+
26
+ @classmethod
27
+ def _deserialize(cls, value: str) -> "SemverString":
28
+ return SemverString(value)
29
+
30
+
31
+ # This supports full semver, but also allows for 2 group version numbers, (allows '1.0').
32
+ sem_ver_pattern = r"^(0|[1-9]\d*)\.(0|[1-9]\d*)(\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)?$"
33
+
34
+
35
+ @dataclass
36
+ class Quoting(dbtClassMixin, Mergeable):
37
+ schema: Optional[bool] = None
38
+ database: Optional[bool] = None
39
+ project: Optional[bool] = None
40
+ identifier: Optional[bool] = None
41
+ snowflake_ignore_case: Optional[bool] = None
42
+
43
+
44
+ @dataclass
45
+ class Package(dbtClassMixin):
46
+
47
+ # Exclude {'name': None} from to_dict result to avoid changing sha1_hash result
48
+ # when user has not changed their 'packages' configuration.
49
+ def __post_serialize__(self, data, context: Optional[Dict]):
50
+ if "name" in data.keys() and data["name"] is None:
51
+ data.pop("name")
52
+ return data
53
+ return data
54
+
55
+
56
+ @dataclass
57
+ class LocalPackage(Package):
58
+ local: str
59
+ unrendered: Dict[str, Any] = field(default_factory=dict)
60
+ name: Optional[str] = None
61
+
62
+
63
+ # `float` also allows `int`, according to PEP484 (and jsonschema!)
64
+ RawVersion = Union[str, float]
65
+
66
+
67
+ @dataclass
68
+ class TarballPackage(Package):
69
+ tarball: str
70
+ name: str
71
+ unrendered: Dict[str, Any] = field(default_factory=dict)
72
+
73
+
74
+ @dataclass
75
+ class GitPackage(Package):
76
+ git: str
77
+ revision: Optional[RawVersion] = None
78
+ warn_unpinned: Optional[bool] = field(default=None, metadata={"alias": "warn-unpinned"})
79
+ subdirectory: Optional[str] = None
80
+ unrendered: Dict[str, Any] = field(default_factory=dict)
81
+ name: Optional[str] = None
82
+
83
+ def get_revisions(self) -> List[str]:
84
+ if self.revision is None:
85
+ return []
86
+ else:
87
+ return [str(self.revision)]
88
+
89
+
90
+ @dataclass
91
+ class PrivatePackage(Package):
92
+ private: str
93
+ provider: Optional[str] = None
94
+ revision: Optional[RawVersion] = None
95
+ warn_unpinned: Optional[bool] = field(default=None, metadata={"alias": "warn-unpinned"})
96
+ subdirectory: Optional[str] = None
97
+ unrendered: Dict[str, Any] = field(default_factory=dict)
98
+ name: Optional[str] = None
99
+
100
+
101
+ @dataclass
102
+ class RegistryPackage(Package):
103
+ package: str
104
+ version: Union[RawVersion, List[RawVersion]]
105
+ install_prerelease: Optional[bool] = False
106
+ unrendered: Dict[str, Any] = field(default_factory=dict)
107
+ name: Optional[str] = None
108
+
109
+ def get_versions(self) -> List[str]:
110
+ if isinstance(self.version, list):
111
+ return [str(v) for v in self.version]
112
+ else:
113
+ return [str(self.version)]
114
+
115
+
116
+ PackageSpec = Union[LocalPackage, TarballPackage, GitPackage, RegistryPackage, PrivatePackage]
117
+
118
+
119
+ @dataclass
120
+ class PackageConfig(dbtClassMixin):
121
+ packages: List[PackageSpec]
122
+
123
+ @classmethod
124
+ def validate(cls, data):
125
+ for package in data.get("packages", data):
126
+ # This can happen when the target is a variable that is not filled and results in hangs
127
+ if isinstance(package, dict):
128
+ if package.get("package") == "":
129
+ raise ValidationError(
130
+ "A hub package is missing the value. It is a required property."
131
+ )
132
+ if package.get("local") == "":
133
+ raise ValidationError(
134
+ "A local package is missing the value. It is a required property."
135
+ )
136
+ if package.get("git") == "":
137
+ raise ValidationError(
138
+ "A git package is missing the value. It is a required property."
139
+ )
140
+ if isinstance(package, dict) and package.get("package"):
141
+ if not package["version"]:
142
+ raise ValidationError(
143
+ f"{package['package']} is missing the version. When installing from the Hub "
144
+ "package index, version is a required property"
145
+ )
146
+ if "/" not in package["package"]:
147
+ raise ValidationError(
148
+ f"{package['package']} was not found in the package index. Packages on the index "
149
+ "require a namespace, e.g dbt-labs/dbt_utils"
150
+ )
151
+ super().validate(data)
152
+
153
+
154
+ @dataclass
155
+ class ProjectPackageMetadata:
156
+ name: str
157
+ packages: List[PackageSpec]
158
+
159
+ @classmethod
160
+ def from_project(cls, project):
161
+ return cls(name=project.project_name, packages=project.packages.packages)
162
+
163
+
164
+ @dataclass
165
+ class Downloads(ExtensibleDbtClassMixin):
166
+ tarball: str
167
+
168
+
169
+ @dataclass
170
+ class RegistryPackageMetadata(
171
+ ExtensibleDbtClassMixin,
172
+ ProjectPackageMetadata,
173
+ ):
174
+ downloads: Downloads
175
+
176
+
177
+ # A list of all the reserved words that packages may not have as names.
178
+ BANNED_PROJECT_NAMES = {
179
+ "_sql_results",
180
+ "adapter",
181
+ "api",
182
+ "column",
183
+ "config",
184
+ "context",
185
+ "database",
186
+ "env",
187
+ "env_var",
188
+ "exceptions",
189
+ "execute",
190
+ "flags",
191
+ "fromjson",
192
+ "fromyaml",
193
+ "graph",
194
+ "invocation_id",
195
+ "load_agate_table",
196
+ "load_result",
197
+ "log",
198
+ "model",
199
+ "modules",
200
+ "post_hooks",
201
+ "pre_hooks",
202
+ "ref",
203
+ "render",
204
+ "return",
205
+ "run_started_at",
206
+ "schema",
207
+ "source",
208
+ "sql",
209
+ "sql_now",
210
+ "store_result",
211
+ "store_raw_result",
212
+ "target",
213
+ "this",
214
+ "tojson",
215
+ "toyaml",
216
+ "try_or_compiler_error",
217
+ "var",
218
+ "write",
219
+ }
220
+
221
+
222
+ @dataclass
223
+ class Project(dbtClassMixin):
224
+ _hyphenated: ClassVar[bool] = True
225
+ # Annotated is used by mashumaro for jsonschema generation
226
+ name: Annotated[Identifier, Pattern(r"^[^\d\W]\w*$")]
227
+ config_version: Optional[int] = 2
228
+ # Annotated is used by mashumaro for jsonschema generation
229
+ version: Optional[Union[Annotated[SemverString, Pattern(sem_ver_pattern)], float]] = None
230
+ project_root: Optional[str] = None
231
+ source_paths: Optional[List[str]] = None
232
+ model_paths: Optional[List[str]] = None
233
+ macro_paths: Optional[List[str]] = None
234
+ data_paths: Optional[List[str]] = None # deprecated
235
+ seed_paths: Optional[List[str]] = None
236
+ test_paths: Optional[List[str]] = None
237
+ analysis_paths: Optional[List[str]] = None
238
+ docs_paths: Optional[List[str]] = None
239
+ asset_paths: Optional[List[str]] = None
240
+ function_paths: Optional[List[str]] = None
241
+ target_path: Optional[str] = None
242
+ snapshot_paths: Optional[List[str]] = None
243
+ clean_targets: Optional[List[str]] = None
244
+ profile: Optional[str] = None
245
+ log_path: Optional[str] = None
246
+ packages_install_path: Optional[str] = None
247
+ quoting: Optional[Quoting] = None
248
+ on_run_start: Optional[List[str]] = field(default_factory=list_str)
249
+ on_run_end: Optional[List[str]] = field(default_factory=list_str)
250
+ require_dbt_version: Optional[Union[List[str], str]] = None
251
+ dispatch: List[Dict[str, Any]] = field(default_factory=list)
252
+ models: Dict[str, Any] = field(default_factory=dict)
253
+ seeds: Dict[str, Any] = field(default_factory=dict)
254
+ snapshots: Dict[str, Any] = field(default_factory=dict)
255
+ analyses: Dict[str, Any] = field(default_factory=dict)
256
+ sources: Dict[str, Any] = field(default_factory=dict)
257
+ tests: Dict[str, Any] = field(default_factory=dict) # deprecated
258
+ data_tests: Dict[str, Any] = field(default_factory=dict)
259
+ unit_tests: Dict[str, Any] = field(default_factory=dict)
260
+ metrics: Dict[str, Any] = field(default_factory=dict)
261
+ semantic_models: Dict[str, Any] = field(default_factory=dict)
262
+ saved_queries: Dict[str, Any] = field(default_factory=dict)
263
+ exposures: Dict[str, Any] = field(default_factory=dict)
264
+ functions: Dict[str, Any] = field(default_factory=dict)
265
+ vars: Optional[Dict[str, Any]] = field(
266
+ default=None,
267
+ metadata=dict(
268
+ description="map project names to their vars override dicts",
269
+ ),
270
+ )
271
+ packages: List[PackageSpec] = field(default_factory=list)
272
+ query_comment: Optional[Union[QueryComment, NoValue, str]] = field(default_factory=NoValue)
273
+ restrict_access: bool = False
274
+ dbt_cloud: Optional[Dict[str, Any]] = None
275
+ flags: Dict[str, Any] = field(default_factory=dict)
276
+
277
+ class Config(dbtMashConfig):
278
+ # These tell mashumaro to use aliases for jsonschema and for "from_dict"
279
+ aliases = {
280
+ "config_version": "config-version",
281
+ "project_root": "project-root",
282
+ "source_paths": "source-paths",
283
+ "model_paths": "model-paths",
284
+ "macro_paths": "macro-paths",
285
+ "data_paths": "data-paths",
286
+ "seed_paths": "seed-paths",
287
+ "test_paths": "test-paths",
288
+ "analysis_paths": "analysis-paths",
289
+ "docs_paths": "docs-paths",
290
+ "asset_paths": "asset-paths",
291
+ "function_paths": "function-paths",
292
+ "target_path": "target-path",
293
+ "snapshot_paths": "snapshot-paths",
294
+ "clean_targets": "clean-targets",
295
+ "log_path": "log-path",
296
+ "packages_install_path": "packages-install-path",
297
+ "on_run_start": "on-run-start",
298
+ "on_run_end": "on-run-end",
299
+ "require_dbt_version": "require-dbt-version",
300
+ "query_comment": "query-comment",
301
+ "restrict_access": "restrict-access",
302
+ "semantic_models": "semantic-models",
303
+ "saved_queries": "saved-queries",
304
+ "dbt_cloud": "dbt-cloud",
305
+ }
306
+
307
+ @classmethod
308
+ def validate(cls, data):
309
+ super().validate(data)
310
+ if data["name"] in BANNED_PROJECT_NAMES:
311
+ raise ValidationError(f"Invalid project name: {data['name']} is a reserved word")
312
+ # validate dispatch config
313
+ if "dispatch" in data and data["dispatch"]:
314
+ entries = data["dispatch"]
315
+ for entry in entries:
316
+ if (
317
+ "macro_namespace" not in entry
318
+ or "search_order" not in entry
319
+ or not isinstance(entry["search_order"], list)
320
+ ):
321
+ raise ValidationError(f"Invalid project dispatch config: {entry}")
322
+ if "dbt_cloud" in data and not isinstance(data["dbt_cloud"], dict):
323
+ raise ValidationError(
324
+ f"Invalid dbt_cloud config. Expected a 'dict' but got '{type(data['dbt_cloud'])}'"
325
+ )
326
+ if data.get("tests", None) and data.get("data_tests", None):
327
+ raise ValidationError(
328
+ "Invalid project config: cannot have both 'tests' and 'data_tests' defined"
329
+ )
330
+
331
+
332
+ @dataclass
333
+ class ProjectFlags(ExtensibleDbtClassMixin):
334
+ cache_selected_only: Optional[bool] = None
335
+ debug: Optional[bool] = None
336
+ fail_fast: Optional[bool] = None
337
+ indirect_selection: Optional[str] = None
338
+ log_format: Optional[str] = None
339
+ log_format_file: Optional[str] = None
340
+ log_level: Optional[str] = None
341
+ log_level_file: Optional[str] = None
342
+ partial_parse: Optional[bool] = None
343
+ populate_cache: Optional[bool] = None
344
+ printer_width: Optional[int] = None
345
+ send_anonymous_usage_stats: bool = DEFAULT_SEND_ANONYMOUS_USAGE_STATS
346
+ static_parser: Optional[bool] = None
347
+ use_colors: Optional[bool] = None
348
+ use_colors_file: Optional[bool] = None
349
+ use_experimental_parser: Optional[bool] = None
350
+ version_check: Optional[bool] = None
351
+ warn_error: Optional[bool] = None
352
+ warn_error_options: Optional[Dict[str, Union[str, List[str]]]] = None
353
+ write_json: Optional[bool] = None
354
+
355
+ # legacy behaviors - https://github.com/dbt-labs/dbt-core/blob/main/docs/guides/behavior-change-flags.md
356
+ require_batched_execution_for_custom_microbatch_strategy: bool = False
357
+ require_event_names_in_deprecations: bool = False
358
+ require_explicit_package_overrides_for_builtin_materializations: bool = True
359
+ require_resource_names_without_spaces: bool = True
360
+ source_freshness_run_project_hooks: bool = True
361
+ skip_nodes_if_on_run_start_fails: bool = False
362
+ state_modified_compare_more_unrendered_values: bool = False
363
+ state_modified_compare_vars: bool = False
364
+ require_yaml_configuration_for_mf_time_spines: bool = False
365
+ require_nested_cumulative_type_params: bool = False
366
+ validate_macro_args: bool = False
367
+ require_all_warnings_handled_by_warn_error: bool = False
368
+ require_generic_test_arguments_property: bool = True
369
+
370
+ @property
371
+ def project_only_flags(self) -> Dict[str, Any]:
372
+ return {
373
+ "require_batched_execution_for_custom_microbatch_strategy": self.require_batched_execution_for_custom_microbatch_strategy,
374
+ "require_explicit_package_overrides_for_builtin_materializations": self.require_explicit_package_overrides_for_builtin_materializations,
375
+ "require_resource_names_without_spaces": self.require_resource_names_without_spaces,
376
+ "source_freshness_run_project_hooks": self.source_freshness_run_project_hooks,
377
+ "skip_nodes_if_on_run_start_fails": self.skip_nodes_if_on_run_start_fails,
378
+ "state_modified_compare_more_unrendered_values": self.state_modified_compare_more_unrendered_values,
379
+ "state_modified_compare_vars": self.state_modified_compare_vars,
380
+ "require_yaml_configuration_for_mf_time_spines": self.require_yaml_configuration_for_mf_time_spines,
381
+ "require_nested_cumulative_type_params": self.require_nested_cumulative_type_params,
382
+ "validate_macro_args": self.validate_macro_args,
383
+ "require_all_warnings_handled_by_warn_error": self.require_all_warnings_handled_by_warn_error,
384
+ "require_generic_test_arguments_property": self.require_generic_test_arguments_property,
385
+ }
386
+
387
+
388
+ @dataclass
389
+ class ProfileConfig(dbtClassMixin):
390
+ profile_name: str
391
+ target_name: str
392
+ threads: int
393
+ # TODO: make this a dynamic union of some kind?
394
+ credentials: Optional[Dict[str, Any]]
395
+
396
+
397
+ @dataclass
398
+ class ConfiguredQuoting(Quoting):
399
+ identifier: bool = True
400
+ schema: bool = True
401
+ database: Optional[bool] = None
402
+ project: Optional[bool] = None
403
+ snowflake_ignore_case: Optional[bool] = None
404
+
405
+
406
+ @dataclass
407
+ class Configuration(Project, ProfileConfig):
408
+ cli_vars: Dict[str, Any] = field(
409
+ default_factory=dict,
410
+ metadata={"preserve_underscore": True},
411
+ )
412
+ quoting: Optional[ConfiguredQuoting] = None
413
+
414
+
415
+ @dataclass
416
+ class ProjectList(dbtClassMixin):
417
+ projects: Dict[str, Project]
@@ -0,0 +1,53 @@
1
+ # flake8: noqa
2
+
3
+ # This file is temporary, in order to not break various adapter tests, etc, until
4
+ # they are updated to use the new locations.
5
+
6
+ from dvt.artifacts.schemas.base import (
7
+ ArtifactMixin,
8
+ BaseArtifactMetadata,
9
+ VersionedSchema,
10
+ schema_version,
11
+ )
12
+ from dvt.artifacts.schemas.catalog import (
13
+ CatalogArtifact,
14
+ CatalogKey,
15
+ CatalogMetadata,
16
+ CatalogResults,
17
+ CatalogTable,
18
+ ColumnMetadata,
19
+ StatsItem,
20
+ TableMetadata,
21
+ )
22
+ from dvt.artifacts.schemas.freshness import (
23
+ FreshnessErrorEnum,
24
+ FreshnessExecutionResultArtifact,
25
+ FreshnessMetadata,
26
+ FreshnessNodeOutput,
27
+ FreshnessNodeResult,
28
+ FreshnessResult,
29
+ PartialSourceFreshnessResult,
30
+ SourceFreshnessOutput,
31
+ SourceFreshnessResult,
32
+ SourceFreshnessRuntimeError,
33
+ process_freshness_result,
34
+ )
35
+ from dvt.artifacts.schemas.results import (
36
+ BaseResult,
37
+ ExecutionResult,
38
+ FreshnessStatus,
39
+ NodeResult,
40
+ NodeStatus,
41
+ RunningStatus,
42
+ RunStatus,
43
+ TestStatus,
44
+ TimingInfo,
45
+ collect_timing_info,
46
+ )
47
+ from dvt.artifacts.schemas.run import (
48
+ RunExecutionResult,
49
+ RunResult,
50
+ RunResultsArtifact,
51
+ RunResultsMetadata,
52
+ process_run_result,
53
+ )
@@ -0,0 +1,23 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any, Dict, List, Union
3
+
4
+ from dbt_common.dataclass_schema import dbtClassMixin
5
+
6
+
7
+ @dataclass
8
+ class SelectorDefinition(dbtClassMixin):
9
+ name: str
10
+ definition: Union[str, Dict[str, Any]]
11
+ description: str = ""
12
+ default: bool = False
13
+
14
+
15
+ @dataclass
16
+ class SelectorFile(dbtClassMixin):
17
+ selectors: List[SelectorDefinition]
18
+ version: int = 2
19
+
20
+
21
+ # @dataclass
22
+ # class SelectorCollection:
23
+ # packages: Dict[str, List[SelectorFile]] = field(default_factory=dict)
dvt/contracts/sql.py ADDED
@@ -0,0 +1,86 @@
1
+ import uuid
2
+ from dataclasses import dataclass, field
3
+ from datetime import datetime, timezone
4
+ from typing import Any, Dict, List, Optional, Sequence
5
+
6
+ from dvt.artifacts.schemas.base import VersionedSchema, schema_version
7
+ from dvt.artifacts.schemas.results import ExecutionResult, TimingInfo
8
+ from dvt.artifacts.schemas.run import RunExecutionResult, RunResult, RunResultsArtifact
9
+ from dvt.contracts.graph.nodes import ResultNode
10
+ from dvt.events.types import ArtifactWritten
11
+
12
+ from dbt_common.dataclass_schema import dbtClassMixin
13
+ from dbt_common.events.functions import fire_event
14
+
15
+ TaskTags = Optional[Dict[str, Any]]
16
+ TaskID = uuid.UUID
17
+
18
+ # Outputs
19
+
20
+
21
+ @dataclass
22
+ class RemoteCompileResultMixin(VersionedSchema):
23
+ raw_code: str
24
+ compiled_code: str
25
+ node: ResultNode
26
+ timing: List[TimingInfo]
27
+
28
+
29
+ @dataclass
30
+ @schema_version("remote-compile-result", 1)
31
+ class RemoteCompileResult(RemoteCompileResultMixin):
32
+ generated_at: datetime = field(
33
+ default_factory=lambda: datetime.now(timezone.utc).replace(tzinfo=None)
34
+ )
35
+
36
+ @property
37
+ def error(self) -> None:
38
+ # TODO: Can we delete this? It's never set anywhere else and never accessed
39
+ return None
40
+
41
+
42
+ @dataclass
43
+ @schema_version("remote-execution-result", 1)
44
+ class RemoteExecutionResult(ExecutionResult):
45
+ results: Sequence[RunResult]
46
+ args: Dict[str, Any] = field(default_factory=dict)
47
+ generated_at: datetime = field(
48
+ default_factory=lambda: datetime.now(timezone.utc).replace(tzinfo=None)
49
+ )
50
+
51
+ def write(self, path: str) -> None:
52
+ writable = RunResultsArtifact.from_execution_results(
53
+ generated_at=self.generated_at,
54
+ results=self.results,
55
+ elapsed_time=self.elapsed_time,
56
+ args=self.args,
57
+ )
58
+ writable.write(path)
59
+ fire_event(ArtifactWritten(artifact_type=writable.__class__.__name__, artifact_path=path))
60
+
61
+ @classmethod
62
+ def from_local_result(
63
+ cls,
64
+ base: RunExecutionResult,
65
+ ) -> "RemoteExecutionResult":
66
+ return cls(
67
+ generated_at=base.generated_at,
68
+ results=base.results,
69
+ elapsed_time=base.elapsed_time,
70
+ args=base.args,
71
+ )
72
+
73
+
74
+ @dataclass
75
+ class ResultTable(dbtClassMixin):
76
+ column_names: List[str]
77
+ rows: List[Any]
78
+
79
+
80
+ @dataclass
81
+ @schema_version("remote-run-result", 1)
82
+ class RemoteRunResult(RemoteCompileResultMixin):
83
+ table: ResultTable
84
+ generated_at: datetime = field(
85
+ default_factory=lambda: datetime.now(timezone.utc).replace(tzinfo=None)
86
+ )
dvt/contracts/state.py ADDED
@@ -0,0 +1,69 @@
1
+ from pathlib import Path
2
+ from typing import Optional
3
+
4
+ from dvt.artifacts.exceptions import IncompatibleSchemaError
5
+ from dvt.artifacts.schemas.freshness import FreshnessExecutionResultArtifact
6
+ from dvt.artifacts.schemas.manifest import WritableManifest
7
+ from dvt.artifacts.schemas.run import RunResultsArtifact
8
+ from dvt.constants import RUN_RESULTS_FILE_NAME
9
+ from dvt.contracts.graph.manifest import Manifest
10
+ from dvt.events.types import WarnStateTargetEqual
11
+
12
+ from dbt_common.events.functions import fire_event
13
+
14
+
15
+ def load_result_state(results_path) -> Optional[RunResultsArtifact]:
16
+ if results_path.exists() and results_path.is_file():
17
+ try:
18
+ return RunResultsArtifact.read_and_check_versions(str(results_path))
19
+ except IncompatibleSchemaError as exc:
20
+ exc.add_filename(str(results_path))
21
+ raise
22
+ return None
23
+
24
+
25
+ class PreviousState:
26
+ def __init__(self, state_path: Path, target_path: Path, project_root: Path) -> None:
27
+ self.state_path: Path = state_path
28
+ self.target_path: Path = target_path
29
+ self.project_root: Path = project_root
30
+ self.manifest: Optional[Manifest] = None
31
+ self.results: Optional[RunResultsArtifact] = None
32
+ self.sources: Optional[FreshnessExecutionResultArtifact] = None
33
+ self.sources_current: Optional[FreshnessExecutionResultArtifact] = None
34
+
35
+ if self.state_path == self.target_path:
36
+ fire_event(WarnStateTargetEqual(state_path=str(self.state_path)))
37
+
38
+ # Note: if state_path is absolute, project_root will be ignored.
39
+ manifest_path = self.project_root / self.state_path / "manifest.json"
40
+ if manifest_path.exists() and manifest_path.is_file():
41
+ try:
42
+ writable_manifest = WritableManifest.read_and_check_versions(str(manifest_path))
43
+ self.manifest = Manifest.from_writable_manifest(writable_manifest)
44
+ except IncompatibleSchemaError as exc:
45
+ exc.add_filename(str(manifest_path))
46
+ raise
47
+
48
+ results_path = self.project_root / self.state_path / RUN_RESULTS_FILE_NAME
49
+ self.results = load_result_state(results_path)
50
+
51
+ sources_path = self.project_root / self.state_path / "sources.json"
52
+ if sources_path.exists() and sources_path.is_file():
53
+ try:
54
+ self.sources = FreshnessExecutionResultArtifact.read_and_check_versions(
55
+ str(sources_path)
56
+ )
57
+ except IncompatibleSchemaError as exc:
58
+ exc.add_filename(str(sources_path))
59
+ raise
60
+
61
+ sources_current_path = self.project_root / self.target_path / "sources.json"
62
+ if sources_current_path.exists() and sources_current_path.is_file():
63
+ try:
64
+ self.sources_current = FreshnessExecutionResultArtifact.read_and_check_versions(
65
+ str(sources_current_path)
66
+ )
67
+ except IncompatibleSchemaError as exc:
68
+ exc.add_filename(str(sources_current_path))
69
+ raise
dvt/contracts/util.py ADDED
@@ -0,0 +1,46 @@
1
+ from typing import Any, List, Tuple
2
+
3
+ # Leave imports of `Mergeable` to preserve import paths
4
+ from dbt_common.contracts.util import Mergeable # noqa:F401
5
+ from dbt_common.dataclass_schema import ValidatedStringMixin, ValidationError
6
+
7
+ SourceKey = Tuple[str, str]
8
+
9
+
10
+ def list_str() -> List[str]:
11
+ """Mypy gets upset about stuff like:
12
+
13
+ from dataclasses import dataclass, field
14
+ from typing import Optional, List
15
+
16
+ @dataclass
17
+ class Foo:
18
+ x: Optional[List[str]] = field(default_factory=list)
19
+
20
+
21
+ Because `list` could be any kind of list, I guess
22
+ """
23
+ return []
24
+
25
+
26
+ class Identifier(ValidatedStringMixin):
27
+ """Our definition of a valid Identifier is the same as what's valid for an unquoted database table name.
28
+
29
+ That is:
30
+ 1. It can contain a-z, A-Z, 0-9, and _
31
+ 1. It cannot start with a number
32
+ """
33
+
34
+ ValidationRegex = r"^[^\d\W]\w*$"
35
+
36
+ @classmethod
37
+ def is_valid(cls, value: Any) -> bool:
38
+ if not isinstance(value, str):
39
+ return False
40
+
41
+ try:
42
+ cls.validate(value)
43
+ except ValidationError:
44
+ return False
45
+
46
+ return True