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,191 @@
1
+ import dataclasses
2
+ import functools
3
+ from datetime import datetime, timezone
4
+ from typing import Any, ClassVar, Dict, Optional, Type, TypeVar
5
+
6
+ from dvt.artifacts.exceptions import IncompatibleSchemaError
7
+ from dvt.version import __version__
8
+ from mashumaro.jsonschema import build_json_schema
9
+ from mashumaro.jsonschema.dialects import DRAFT_2020_12
10
+
11
+ from dbt_common.clients.system import read_json, write_json
12
+ from dbt_common.dataclass_schema import dbtClassMixin
13
+ from dbt_common.events.functions import get_metadata_vars
14
+ from dbt_common.exceptions import DbtInternalError, DbtRuntimeError
15
+ from dbt_common.invocation import get_invocation_id, get_invocation_started_at
16
+
17
+ BASE_SCHEMAS_URL = "https://schemas.getdbt.com/"
18
+ SCHEMA_PATH = "dbt/{name}/v{version}.json"
19
+
20
+
21
+ @dataclasses.dataclass
22
+ class SchemaVersion:
23
+ name: str
24
+ version: int
25
+
26
+ @property
27
+ def path(self) -> str:
28
+ return SCHEMA_PATH.format(name=self.name, version=self.version)
29
+
30
+ def __str__(self) -> str:
31
+ return BASE_SCHEMAS_URL + self.path
32
+
33
+
34
+ class Writable:
35
+ def write(self, path: str):
36
+ write_json(path, self.to_dict(omit_none=False, context={"artifact": True})) # type: ignore
37
+
38
+
39
+ class Readable:
40
+ @classmethod
41
+ def read(cls, path: str):
42
+ try:
43
+ data = read_json(path)
44
+ except (EnvironmentError, ValueError) as exc:
45
+ raise DbtRuntimeError(
46
+ f'Could not read {cls.__name__} at "{path}" as JSON: {exc}'
47
+ ) from exc
48
+
49
+ return cls.from_dict(data) # type: ignore
50
+
51
+
52
+ # This is used in the ManifestMetadata, RunResultsMetadata, RunOperationResultMetadata,
53
+ # FreshnessMetadata, and CatalogMetadata classes
54
+ @dataclasses.dataclass
55
+ class BaseArtifactMetadata(dbtClassMixin):
56
+ dbt_schema_version: str
57
+ dbt_version: str = __version__
58
+ generated_at: datetime = dataclasses.field(
59
+ default_factory=lambda: datetime.now(timezone.utc).replace(tzinfo=None)
60
+ )
61
+ invocation_id: Optional[str] = dataclasses.field(default_factory=get_invocation_id)
62
+ invocation_started_at: Optional[datetime] = dataclasses.field(
63
+ default_factory=get_invocation_started_at
64
+ )
65
+ env: Dict[str, str] = dataclasses.field(default_factory=get_metadata_vars)
66
+
67
+ def __post_serialize__(self, dct: Dict, context: Optional[Dict] = None):
68
+ dct = super().__post_serialize__(dct, context)
69
+ if dct["generated_at"] and dct["generated_at"].endswith("+00:00"):
70
+ dct["generated_at"] = dct["generated_at"].replace("+00:00", "") + "Z"
71
+ return dct
72
+
73
+
74
+ # This is used as a class decorator to set the schema_version in the
75
+ # 'dbt_schema_version' class attribute. (It's copied into the metadata objects.)
76
+ # Name attributes of SchemaVersion in classes with the 'schema_version' decorator:
77
+ # manifest
78
+ # run-results
79
+ # run-operation-result
80
+ # sources
81
+ # catalog
82
+ # remote-compile-result
83
+ # remote-execution-result
84
+ # remote-run-result
85
+ S = TypeVar("S", bound="VersionedSchema")
86
+
87
+
88
+ def schema_version(name: str, version: int):
89
+ def inner(cls: Type[S]):
90
+ cls.dbt_schema_version = SchemaVersion(
91
+ name=name,
92
+ version=version,
93
+ )
94
+ return cls
95
+
96
+ return inner
97
+
98
+
99
+ # This is used in the ArtifactMixin and RemoteCompileResultMixin classes
100
+ @dataclasses.dataclass
101
+ class VersionedSchema(dbtClassMixin):
102
+ dbt_schema_version: ClassVar[SchemaVersion]
103
+
104
+ @classmethod
105
+ @functools.lru_cache
106
+ def json_schema(cls) -> Dict[str, Any]:
107
+ json_schema_obj = build_json_schema(cls, dialect=DRAFT_2020_12, with_dialect_uri=True)
108
+ json_schema = json_schema_obj.to_dict()
109
+ json_schema["$id"] = str(cls.dbt_schema_version)
110
+ return json_schema
111
+
112
+ @classmethod
113
+ def is_compatible_version(cls, schema_version):
114
+ compatible_versions = [str(cls.dbt_schema_version)]
115
+ if hasattr(cls, "compatible_previous_versions"):
116
+ for name, version in cls.compatible_previous_versions():
117
+ compatible_versions.append(str(SchemaVersion(name, version)))
118
+ return str(schema_version) in compatible_versions
119
+
120
+ @classmethod
121
+ def read_and_check_versions(cls, path: str):
122
+ try:
123
+ data = read_json(path)
124
+ except (EnvironmentError, ValueError) as exc:
125
+ raise DbtRuntimeError(
126
+ f'Could not read {cls.__name__} at "{path}" as JSON: {exc}'
127
+ ) from exc
128
+
129
+ # Check metadata version. There is a class variable 'dbt_schema_version', but
130
+ # that doesn't show up in artifacts, where it only exists in the 'metadata'
131
+ # dictionary.
132
+ if hasattr(cls, "dbt_schema_version"):
133
+ if "metadata" in data and "dbt_schema_version" in data["metadata"]:
134
+ previous_schema_version = data["metadata"]["dbt_schema_version"]
135
+ # cls.dbt_schema_version is a SchemaVersion object
136
+ if not cls.is_compatible_version(previous_schema_version):
137
+ raise IncompatibleSchemaError(
138
+ expected=str(cls.dbt_schema_version),
139
+ found=previous_schema_version,
140
+ )
141
+
142
+ return cls.upgrade_schema_version(data)
143
+
144
+ @classmethod
145
+ def upgrade_schema_version(cls, data):
146
+ """This will modify the data (dictionary) passed in to match the current
147
+ artifact schema code, if necessary. This is the default method, which
148
+ just returns the instantiated object via from_dict."""
149
+ return cls.from_dict(data)
150
+
151
+
152
+ T = TypeVar("T", bound="ArtifactMixin")
153
+
154
+
155
+ # metadata should really be a Generic[T_M] where T_M is a TypeVar bound to
156
+ # BaseArtifactMetadata. Unfortunately this isn't possible due to a mypy issue:
157
+ # https://github.com/python/mypy/issues/7520
158
+ # This is used in the WritableManifest, RunResultsArtifact, RunOperationResultsArtifact,
159
+ # and CatalogArtifact
160
+ @dataclasses.dataclass(init=False)
161
+ class ArtifactMixin(VersionedSchema, Writable, Readable):
162
+ metadata: BaseArtifactMetadata
163
+
164
+ @classmethod
165
+ def validate(cls, data):
166
+ super().validate(data)
167
+ if cls.dbt_schema_version is None:
168
+ raise DbtInternalError("Cannot call from_dict with no schema version!")
169
+
170
+
171
+ def get_artifact_schema_version(dct: dict) -> int:
172
+ schema_version = dct.get("metadata", {}).get("dbt_schema_version", None)
173
+ if not schema_version:
174
+ raise ValueError("Artifact is missing schema version")
175
+
176
+ # schema_version is in this format: https://schemas.getdbt.com/dbt/manifest/v10.json
177
+ # What the code below is doing:
178
+ # 1. Split on "/" – v10.json
179
+ # 2. Split on "." – v10
180
+ # 3. Skip first character – 10
181
+ # 4. Convert to int
182
+ # TODO: If this gets more complicated, turn into a regex
183
+ return int(schema_version.split("/")[-1].split(".")[0][1:])
184
+
185
+
186
+ def get_artifact_dbt_version(dct: dict) -> Optional[str]:
187
+ dbt_version = dct.get("metadata", {}).get("dbt_version", None)
188
+ if dbt_version is None:
189
+ return None
190
+
191
+ return str(dbt_version)
@@ -0,0 +1,24 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from datetime import datetime
5
+ from typing import List, Tuple
6
+
7
+ from dbt_common.dataclass_schema import dbtClassMixin
8
+
9
+ BatchType = Tuple[datetime, datetime]
10
+
11
+
12
+ @dataclass
13
+ class BatchResults(dbtClassMixin):
14
+ successful: List[BatchType] = field(default_factory=list)
15
+ failed: List[BatchType] = field(default_factory=list)
16
+
17
+ def __add__(self, other: BatchResults) -> BatchResults:
18
+ return BatchResults(
19
+ successful=self.successful + other.successful,
20
+ failed=self.failed + other.failed,
21
+ )
22
+
23
+ def __len__(self):
24
+ return len(self.successful) + len(self.failed)
@@ -0,0 +1,12 @@
1
+ # alias to latest
2
+ from dvt.artifacts.schemas.catalog.v1.catalog import * # noqa
3
+
4
+ from dbt_common.contracts.metadata import (
5
+ CatalogKey,
6
+ CatalogTable,
7
+ ColumnMap,
8
+ ColumnMetadata,
9
+ StatsDict,
10
+ StatsItem,
11
+ TableMetadata,
12
+ )
File without changes
@@ -0,0 +1,60 @@
1
+ from dataclasses import dataclass, field
2
+ from datetime import datetime
3
+ from typing import Any, Dict, List, Optional, Union
4
+
5
+ from dvt.artifacts.schemas.base import (
6
+ ArtifactMixin,
7
+ BaseArtifactMetadata,
8
+ schema_version,
9
+ )
10
+
11
+ from dbt_common.contracts.metadata import CatalogTable
12
+ from dbt_common.dataclass_schema import dbtClassMixin
13
+
14
+ Primitive = Union[bool, str, float, None]
15
+ PrimitiveDict = Dict[str, Primitive]
16
+
17
+
18
+ @dataclass
19
+ class CatalogMetadata(BaseArtifactMetadata):
20
+ dbt_schema_version: str = field(
21
+ default_factory=lambda: str(CatalogArtifact.dbt_schema_version)
22
+ )
23
+
24
+
25
+ @dataclass
26
+ class CatalogResults(dbtClassMixin):
27
+ nodes: Dict[str, CatalogTable]
28
+ sources: Dict[str, CatalogTable]
29
+ errors: Optional[List[str]] = None
30
+ _compile_results: Optional[Any] = None
31
+
32
+ def __post_serialize__(self, dct: Dict, context: Optional[Dict] = None):
33
+ dct = super().__post_serialize__(dct, context)
34
+ if "_compile_results" in dct:
35
+ del dct["_compile_results"]
36
+ return dct
37
+
38
+
39
+ @dataclass
40
+ @schema_version("catalog", 1)
41
+ class CatalogArtifact(CatalogResults, ArtifactMixin):
42
+ metadata: CatalogMetadata
43
+
44
+ @classmethod
45
+ def from_results(
46
+ cls,
47
+ generated_at: datetime,
48
+ nodes: Dict[str, CatalogTable],
49
+ sources: Dict[str, CatalogTable],
50
+ compile_results: Optional[Any],
51
+ errors: Optional[List[str]],
52
+ ) -> "CatalogArtifact":
53
+ meta = CatalogMetadata(generated_at=generated_at)
54
+ return cls(
55
+ metadata=meta,
56
+ nodes=nodes,
57
+ sources=sources,
58
+ errors=errors,
59
+ _compile_results=compile_results,
60
+ )
@@ -0,0 +1 @@
1
+ from dvt.artifacts.schemas.freshness.v3.freshness import * # noqa
File without changes
@@ -0,0 +1,159 @@
1
+ from dataclasses import dataclass, field
2
+ from datetime import datetime
3
+ from typing import Any, Dict, List, Optional, Sequence, Union
4
+
5
+ from dvt.artifacts.resources import FreshnessThreshold
6
+ from dvt.artifacts.schemas.base import (
7
+ ArtifactMixin,
8
+ BaseArtifactMetadata,
9
+ VersionedSchema,
10
+ schema_version,
11
+ )
12
+ from dvt.artifacts.schemas.results import (
13
+ ExecutionResult,
14
+ FreshnessStatus,
15
+ NodeResult,
16
+ TimingInfo,
17
+ )
18
+ from dvt.contracts.graph.nodes import SourceDefinition
19
+
20
+ from dbt_common.dataclass_schema import StrEnum, dbtClassMixin
21
+ from dbt_common.exceptions import DbtInternalError
22
+
23
+
24
+ @dataclass
25
+ class SourceFreshnessResult(NodeResult):
26
+ node: SourceDefinition
27
+ status: FreshnessStatus
28
+ max_loaded_at: datetime
29
+ snapshotted_at: datetime
30
+ age: float
31
+
32
+ @property
33
+ def skipped(self):
34
+ return False
35
+
36
+
37
+ @dataclass
38
+ class PartialSourceFreshnessResult(NodeResult):
39
+ status: FreshnessStatus
40
+
41
+ @property
42
+ def skipped(self):
43
+ return False
44
+
45
+
46
+ FreshnessNodeResult = Union[PartialSourceFreshnessResult, SourceFreshnessResult]
47
+
48
+
49
+ @dataclass
50
+ class FreshnessMetadata(BaseArtifactMetadata):
51
+ dbt_schema_version: str = field(
52
+ default_factory=lambda: str(FreshnessExecutionResultArtifact.dbt_schema_version)
53
+ )
54
+
55
+
56
+ @dataclass
57
+ class FreshnessResult(ExecutionResult):
58
+ metadata: FreshnessMetadata
59
+ results: Sequence[FreshnessNodeResult]
60
+
61
+ @classmethod
62
+ def from_node_results(
63
+ cls,
64
+ results: List[FreshnessNodeResult],
65
+ elapsed_time: float,
66
+ generated_at: datetime,
67
+ ):
68
+ meta = FreshnessMetadata(generated_at=generated_at)
69
+ return cls(metadata=meta, results=results, elapsed_time=elapsed_time)
70
+
71
+ def write(self, path):
72
+ FreshnessExecutionResultArtifact.from_result(self).write(path)
73
+
74
+
75
+ @dataclass
76
+ class SourceFreshnessOutput(dbtClassMixin):
77
+ unique_id: str
78
+ max_loaded_at: datetime
79
+ snapshotted_at: datetime
80
+ max_loaded_at_time_ago_in_s: float
81
+ status: FreshnessStatus
82
+ criteria: FreshnessThreshold
83
+ adapter_response: Dict[str, Any]
84
+ timing: List[TimingInfo]
85
+ thread_id: str
86
+ execution_time: float
87
+
88
+
89
+ class FreshnessErrorEnum(StrEnum):
90
+ runtime_error = "runtime error"
91
+
92
+
93
+ @dataclass
94
+ class SourceFreshnessRuntimeError(dbtClassMixin):
95
+ unique_id: str
96
+ error: Optional[Union[str, int]]
97
+ status: FreshnessErrorEnum
98
+
99
+
100
+ FreshnessNodeOutput = Union[SourceFreshnessRuntimeError, SourceFreshnessOutput]
101
+
102
+
103
+ @dataclass
104
+ @schema_version("sources", 3)
105
+ class FreshnessExecutionResultArtifact(
106
+ ArtifactMixin,
107
+ VersionedSchema,
108
+ ):
109
+ metadata: FreshnessMetadata
110
+ results: Sequence[FreshnessNodeOutput]
111
+ elapsed_time: float
112
+
113
+ @classmethod
114
+ def from_result(cls, base: FreshnessResult):
115
+ processed = [
116
+ process_freshness_result(r)
117
+ for r in base.results
118
+ if isinstance(r, SourceFreshnessResult)
119
+ ]
120
+ return cls(
121
+ metadata=base.metadata,
122
+ results=processed,
123
+ elapsed_time=base.elapsed_time,
124
+ )
125
+
126
+
127
+ def process_freshness_result(result: FreshnessNodeResult) -> FreshnessNodeOutput:
128
+ unique_id = result.node.unique_id
129
+ if result.status == FreshnessStatus.RuntimeErr:
130
+ return SourceFreshnessRuntimeError(
131
+ unique_id=unique_id,
132
+ error=result.message,
133
+ status=FreshnessErrorEnum.runtime_error,
134
+ )
135
+
136
+ # we know that this must be a SourceFreshnessResult
137
+ if not isinstance(result, SourceFreshnessResult):
138
+ raise DbtInternalError(
139
+ "Got {} instead of a SourceFreshnessResult for a "
140
+ "non-error result in freshness execution!".format(type(result))
141
+ )
142
+ # if we're here, we must have a non-None freshness threshold
143
+ criteria = result.node.freshness
144
+ if criteria is None:
145
+ raise DbtInternalError(
146
+ "Somehow evaluated a freshness result for a source that has no freshness criteria!"
147
+ )
148
+ return SourceFreshnessOutput(
149
+ unique_id=unique_id,
150
+ max_loaded_at=result.max_loaded_at,
151
+ snapshotted_at=result.snapshotted_at,
152
+ max_loaded_at_time_ago_in_s=result.age,
153
+ status=result.status,
154
+ criteria=criteria,
155
+ adapter_response=result.adapter_response,
156
+ timing=result.timing,
157
+ thread_id=result.thread_id,
158
+ execution_time=result.execution_time,
159
+ )
@@ -0,0 +1,2 @@
1
+ # alias to latest
2
+ from dvt.artifacts.schemas.manifest.v12.manifest import * # noqa
File without changes
@@ -0,0 +1,212 @@
1
+ from dataclasses import dataclass, field
2
+ from datetime import datetime
3
+ from typing import Any, Dict, Iterable, List, Mapping, Optional, Tuple, Union
4
+ from uuid import UUID
5
+
6
+ from dvt import tracking
7
+ from dvt.artifacts.resources import (
8
+ Analysis,
9
+ Documentation,
10
+ Exposure,
11
+ Function,
12
+ GenericTest,
13
+ Group,
14
+ HookNode,
15
+ Macro,
16
+ Metric,
17
+ Model,
18
+ SavedQuery,
19
+ Seed,
20
+ SemanticModel,
21
+ SingularTest,
22
+ Snapshot,
23
+ SourceDefinition,
24
+ SqlOperation,
25
+ UnitTestDefinition,
26
+ )
27
+ from dvt.artifacts.resources.v1.components import Quoting
28
+ from dvt.artifacts.schemas.base import (
29
+ ArtifactMixin,
30
+ BaseArtifactMetadata,
31
+ get_artifact_dbt_version,
32
+ get_artifact_schema_version,
33
+ schema_version,
34
+ )
35
+ from dvt.artifacts.schemas.upgrades import (
36
+ upgrade_manifest_json,
37
+ upgrade_manifest_json_dbt_version,
38
+ )
39
+ from dvt.version import __version__
40
+
41
+ from dbt_common.exceptions import DbtInternalError
42
+
43
+ NodeEdgeMap = Dict[str, List[str]]
44
+ UniqueID = str
45
+ ManifestResource = Union[
46
+ Seed, Analysis, SingularTest, HookNode, Model, SqlOperation, GenericTest, Snapshot, Function
47
+ ]
48
+ DisabledManifestResource = Union[
49
+ ManifestResource,
50
+ SourceDefinition,
51
+ Exposure,
52
+ Metric,
53
+ SavedQuery,
54
+ SemanticModel,
55
+ UnitTestDefinition,
56
+ ]
57
+
58
+
59
+ @dataclass
60
+ class ManifestMetadata(BaseArtifactMetadata):
61
+ """Metadata for the manifest."""
62
+
63
+ dbt_schema_version: str = field(
64
+ default_factory=lambda: str(WritableManifest.dbt_schema_version)
65
+ )
66
+ project_name: Optional[str] = field(
67
+ default=None,
68
+ metadata={
69
+ "description": "Name of the root project",
70
+ },
71
+ )
72
+ project_id: Optional[str] = field(
73
+ default=None,
74
+ metadata={
75
+ "description": "A unique identifier for the project, hashed from the project name",
76
+ },
77
+ )
78
+ user_id: Optional[UUID] = field(
79
+ default=None,
80
+ metadata={
81
+ "description": "A unique identifier for the user",
82
+ },
83
+ )
84
+ send_anonymous_usage_stats: Optional[bool] = field(
85
+ default=None,
86
+ metadata=dict(
87
+ description=("Whether dbt is configured to send anonymous usage statistics")
88
+ ),
89
+ )
90
+ adapter_type: Optional[str] = field(
91
+ default=None,
92
+ metadata=dict(description="The type name of the adapter"),
93
+ )
94
+ quoting: Optional[Quoting] = field(
95
+ default_factory=Quoting,
96
+ metadata=dict(description="The quoting configuration for the project"),
97
+ )
98
+ run_started_at: Optional[datetime] = field(
99
+ default=tracking.active_user.run_started_at if tracking.active_user is not None else None,
100
+ metadata=dict(description="The timestamp when the run started"),
101
+ )
102
+
103
+ @classmethod
104
+ def default(cls):
105
+ return cls(
106
+ dbt_schema_version=str(WritableManifest.dbt_schema_version),
107
+ )
108
+
109
+
110
+ @dataclass
111
+ @schema_version("manifest", 12)
112
+ class WritableManifest(ArtifactMixin):
113
+ nodes: Mapping[UniqueID, ManifestResource] = field(
114
+ metadata=dict(description=("The nodes defined in the dbt project and its dependencies"))
115
+ )
116
+ sources: Mapping[UniqueID, SourceDefinition] = field(
117
+ metadata=dict(description=("The sources defined in the dbt project and its dependencies"))
118
+ )
119
+ macros: Mapping[UniqueID, Macro] = field(
120
+ metadata=dict(description=("The macros defined in the dbt project and its dependencies"))
121
+ )
122
+ docs: Mapping[UniqueID, Documentation] = field(
123
+ metadata=dict(description=("The docs defined in the dbt project and its dependencies"))
124
+ )
125
+ exposures: Mapping[UniqueID, Exposure] = field(
126
+ metadata=dict(
127
+ description=("The exposures defined in the dbt project and its dependencies")
128
+ )
129
+ )
130
+ metrics: Mapping[UniqueID, Metric] = field(
131
+ metadata=dict(description=("The metrics defined in the dbt project and its dependencies"))
132
+ )
133
+ groups: Mapping[UniqueID, Group] = field(
134
+ metadata=dict(description=("The groups defined in the dbt project"))
135
+ )
136
+ selectors: Mapping[UniqueID, Any] = field(
137
+ metadata=dict(description=("The selectors defined in selectors.yml"))
138
+ )
139
+ disabled: Optional[Mapping[UniqueID, List[DisabledManifestResource]]] = field(
140
+ metadata=dict(description="A mapping of the disabled nodes in the target")
141
+ )
142
+ parent_map: Optional[NodeEdgeMap] = field(
143
+ metadata=dict(
144
+ description="A mapping from child nodes to their dependencies",
145
+ )
146
+ )
147
+ child_map: Optional[NodeEdgeMap] = field(
148
+ metadata=dict(
149
+ description="A mapping from parent nodes to their dependents",
150
+ )
151
+ )
152
+ group_map: Optional[NodeEdgeMap] = field(
153
+ metadata=dict(
154
+ description="A mapping from group names to their nodes",
155
+ )
156
+ )
157
+ saved_queries: Mapping[UniqueID, SavedQuery] = field(
158
+ metadata=dict(description=("The saved queries defined in the dbt project"))
159
+ )
160
+ semantic_models: Mapping[UniqueID, SemanticModel] = field(
161
+ metadata=dict(description=("The semantic models defined in the dbt project"))
162
+ )
163
+ metadata: ManifestMetadata = field(
164
+ metadata=dict(
165
+ description="Metadata about the manifest",
166
+ )
167
+ )
168
+ unit_tests: Mapping[UniqueID, UnitTestDefinition] = field(
169
+ metadata=dict(
170
+ description="The unit tests defined in the project",
171
+ )
172
+ )
173
+ functions: Mapping[UniqueID, Function] = field(
174
+ default_factory=dict,
175
+ metadata=dict(description=("The functions defined in the dbt project")),
176
+ )
177
+
178
+ @classmethod
179
+ def compatible_previous_versions(cls) -> Iterable[Tuple[str, int]]:
180
+ return [
181
+ ("manifest", 4),
182
+ ("manifest", 5),
183
+ ("manifest", 6),
184
+ ("manifest", 7),
185
+ ("manifest", 8),
186
+ ("manifest", 9),
187
+ ("manifest", 10),
188
+ ("manifest", 11),
189
+ ]
190
+
191
+ @classmethod
192
+ def upgrade_schema_version(cls, data):
193
+ """This overrides the "upgrade_schema_version" call in VersionedSchema (via
194
+ ArtifactMixin) to modify the dictionary passed in from earlier versions of the manifest."""
195
+ manifest_schema_version = get_artifact_schema_version(data)
196
+ if manifest_schema_version < cls.dbt_schema_version.version:
197
+ data = upgrade_manifest_json(data, manifest_schema_version)
198
+
199
+ manifest_dbt_version = get_artifact_dbt_version(data)
200
+ if manifest_dbt_version and manifest_dbt_version != __version__:
201
+ data = upgrade_manifest_json_dbt_version(data)
202
+ return cls.from_dict(data)
203
+
204
+ @classmethod
205
+ def validate(cls, _):
206
+ # When dbt try to load an artifact with additional optional fields
207
+ # that are not present in the schema, from_dict will work fine.
208
+ # As long as validate is not called, the schema will not be enforced.
209
+ # This is intentional, as it allows for safer schema upgrades.
210
+ raise DbtInternalError(
211
+ "The WritableManifest should never be validated directly to allow for schema upgrades."
212
+ )