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.
- dvt/__init__.py +7 -0
- dvt/_pydantic_shim.py +26 -0
- dvt/adapters/__init__.py +16 -0
- dvt/adapters/multi_adapter_manager.py +268 -0
- dvt/artifacts/__init__.py +0 -0
- dvt/artifacts/exceptions/__init__.py +1 -0
- dvt/artifacts/exceptions/schemas.py +31 -0
- dvt/artifacts/resources/__init__.py +116 -0
- dvt/artifacts/resources/base.py +68 -0
- dvt/artifacts/resources/types.py +93 -0
- dvt/artifacts/resources/v1/analysis.py +10 -0
- dvt/artifacts/resources/v1/catalog.py +23 -0
- dvt/artifacts/resources/v1/components.py +275 -0
- dvt/artifacts/resources/v1/config.py +282 -0
- dvt/artifacts/resources/v1/documentation.py +11 -0
- dvt/artifacts/resources/v1/exposure.py +52 -0
- dvt/artifacts/resources/v1/function.py +53 -0
- dvt/artifacts/resources/v1/generic_test.py +32 -0
- dvt/artifacts/resources/v1/group.py +22 -0
- dvt/artifacts/resources/v1/hook.py +11 -0
- dvt/artifacts/resources/v1/macro.py +30 -0
- dvt/artifacts/resources/v1/metric.py +173 -0
- dvt/artifacts/resources/v1/model.py +146 -0
- dvt/artifacts/resources/v1/owner.py +10 -0
- dvt/artifacts/resources/v1/saved_query.py +112 -0
- dvt/artifacts/resources/v1/seed.py +42 -0
- dvt/artifacts/resources/v1/semantic_layer_components.py +72 -0
- dvt/artifacts/resources/v1/semantic_model.py +315 -0
- dvt/artifacts/resources/v1/singular_test.py +14 -0
- dvt/artifacts/resources/v1/snapshot.py +92 -0
- dvt/artifacts/resources/v1/source_definition.py +85 -0
- dvt/artifacts/resources/v1/sql_operation.py +10 -0
- dvt/artifacts/resources/v1/unit_test_definition.py +78 -0
- dvt/artifacts/schemas/__init__.py +0 -0
- dvt/artifacts/schemas/base.py +191 -0
- dvt/artifacts/schemas/batch_results.py +24 -0
- dvt/artifacts/schemas/catalog/__init__.py +12 -0
- dvt/artifacts/schemas/catalog/v1/__init__.py +0 -0
- dvt/artifacts/schemas/catalog/v1/catalog.py +60 -0
- dvt/artifacts/schemas/freshness/__init__.py +1 -0
- dvt/artifacts/schemas/freshness/v3/__init__.py +0 -0
- dvt/artifacts/schemas/freshness/v3/freshness.py +159 -0
- dvt/artifacts/schemas/manifest/__init__.py +2 -0
- dvt/artifacts/schemas/manifest/v12/__init__.py +0 -0
- dvt/artifacts/schemas/manifest/v12/manifest.py +212 -0
- dvt/artifacts/schemas/results.py +148 -0
- dvt/artifacts/schemas/run/__init__.py +2 -0
- dvt/artifacts/schemas/run/v5/__init__.py +0 -0
- dvt/artifacts/schemas/run/v5/run.py +184 -0
- dvt/artifacts/schemas/upgrades/__init__.py +4 -0
- dvt/artifacts/schemas/upgrades/upgrade_manifest.py +174 -0
- dvt/artifacts/schemas/upgrades/upgrade_manifest_dbt_version.py +2 -0
- dvt/artifacts/utils/validation.py +153 -0
- dvt/cli/__init__.py +1 -0
- dvt/cli/context.py +16 -0
- dvt/cli/exceptions.py +56 -0
- dvt/cli/flags.py +558 -0
- dvt/cli/main.py +971 -0
- dvt/cli/option_types.py +121 -0
- dvt/cli/options.py +79 -0
- dvt/cli/params.py +803 -0
- dvt/cli/requires.py +478 -0
- dvt/cli/resolvers.py +32 -0
- dvt/cli/types.py +40 -0
- dvt/clients/__init__.py +0 -0
- dvt/clients/checked_load.py +82 -0
- dvt/clients/git.py +164 -0
- dvt/clients/jinja.py +206 -0
- dvt/clients/jinja_static.py +245 -0
- dvt/clients/registry.py +192 -0
- dvt/clients/yaml_helper.py +68 -0
- dvt/compilation.py +833 -0
- dvt/compute/__init__.py +26 -0
- dvt/compute/base.py +288 -0
- dvt/compute/engines/__init__.py +13 -0
- dvt/compute/engines/duckdb_engine.py +368 -0
- dvt/compute/engines/spark_engine.py +273 -0
- dvt/compute/query_analyzer.py +212 -0
- dvt/compute/router.py +483 -0
- dvt/config/__init__.py +4 -0
- dvt/config/catalogs.py +95 -0
- dvt/config/compute_config.py +406 -0
- dvt/config/profile.py +411 -0
- dvt/config/profiles_v2.py +464 -0
- dvt/config/project.py +893 -0
- dvt/config/renderer.py +232 -0
- dvt/config/runtime.py +491 -0
- dvt/config/selectors.py +209 -0
- dvt/config/utils.py +78 -0
- dvt/connectors/.gitignore +6 -0
- dvt/connectors/README.md +306 -0
- dvt/connectors/catalog.yml +217 -0
- dvt/connectors/download_connectors.py +300 -0
- dvt/constants.py +29 -0
- dvt/context/__init__.py +0 -0
- dvt/context/base.py +746 -0
- dvt/context/configured.py +136 -0
- dvt/context/context_config.py +350 -0
- dvt/context/docs.py +82 -0
- dvt/context/exceptions_jinja.py +179 -0
- dvt/context/macro_resolver.py +195 -0
- dvt/context/macros.py +171 -0
- dvt/context/manifest.py +73 -0
- dvt/context/providers.py +2198 -0
- dvt/context/query_header.py +14 -0
- dvt/context/secret.py +59 -0
- dvt/context/target.py +74 -0
- dvt/contracts/__init__.py +0 -0
- dvt/contracts/files.py +413 -0
- dvt/contracts/graph/__init__.py +0 -0
- dvt/contracts/graph/manifest.py +1904 -0
- dvt/contracts/graph/metrics.py +98 -0
- dvt/contracts/graph/model_config.py +71 -0
- dvt/contracts/graph/node_args.py +42 -0
- dvt/contracts/graph/nodes.py +1806 -0
- dvt/contracts/graph/semantic_manifest.py +233 -0
- dvt/contracts/graph/unparsed.py +812 -0
- dvt/contracts/project.py +417 -0
- dvt/contracts/results.py +53 -0
- dvt/contracts/selection.py +23 -0
- dvt/contracts/sql.py +86 -0
- dvt/contracts/state.py +69 -0
- dvt/contracts/util.py +46 -0
- dvt/deprecations.py +347 -0
- dvt/deps/__init__.py +0 -0
- dvt/deps/base.py +153 -0
- dvt/deps/git.py +196 -0
- dvt/deps/local.py +80 -0
- dvt/deps/registry.py +131 -0
- dvt/deps/resolver.py +149 -0
- dvt/deps/tarball.py +121 -0
- dvt/docs/source/_ext/dbt_click.py +118 -0
- dvt/docs/source/conf.py +32 -0
- dvt/env_vars.py +64 -0
- dvt/event_time/event_time.py +40 -0
- dvt/event_time/sample_window.py +60 -0
- dvt/events/__init__.py +16 -0
- dvt/events/base_types.py +37 -0
- dvt/events/core_types_pb2.py +2 -0
- dvt/events/logging.py +109 -0
- dvt/events/types.py +2534 -0
- dvt/exceptions.py +1487 -0
- dvt/flags.py +89 -0
- dvt/graph/__init__.py +11 -0
- dvt/graph/cli.py +248 -0
- dvt/graph/graph.py +172 -0
- dvt/graph/queue.py +213 -0
- dvt/graph/selector.py +375 -0
- dvt/graph/selector_methods.py +976 -0
- dvt/graph/selector_spec.py +223 -0
- dvt/graph/thread_pool.py +18 -0
- dvt/hooks.py +21 -0
- dvt/include/README.md +49 -0
- dvt/include/__init__.py +3 -0
- dvt/include/global_project.py +4 -0
- dvt/include/starter_project/.gitignore +4 -0
- dvt/include/starter_project/README.md +15 -0
- dvt/include/starter_project/__init__.py +3 -0
- dvt/include/starter_project/analyses/.gitkeep +0 -0
- dvt/include/starter_project/dvt_project.yml +36 -0
- dvt/include/starter_project/macros/.gitkeep +0 -0
- dvt/include/starter_project/models/example/my_first_dbt_model.sql +27 -0
- dvt/include/starter_project/models/example/my_second_dbt_model.sql +6 -0
- dvt/include/starter_project/models/example/schema.yml +21 -0
- dvt/include/starter_project/seeds/.gitkeep +0 -0
- dvt/include/starter_project/snapshots/.gitkeep +0 -0
- dvt/include/starter_project/tests/.gitkeep +0 -0
- dvt/internal_deprecations.py +27 -0
- dvt/jsonschemas/__init__.py +3 -0
- dvt/jsonschemas/jsonschemas.py +309 -0
- dvt/jsonschemas/project/0.0.110.json +4717 -0
- dvt/jsonschemas/project/0.0.85.json +2015 -0
- dvt/jsonschemas/resources/0.0.110.json +2636 -0
- dvt/jsonschemas/resources/0.0.85.json +2536 -0
- dvt/jsonschemas/resources/latest.json +6773 -0
- dvt/links.py +4 -0
- dvt/materializations/__init__.py +0 -0
- dvt/materializations/incremental/__init__.py +0 -0
- dvt/materializations/incremental/microbatch.py +235 -0
- dvt/mp_context.py +8 -0
- dvt/node_types.py +37 -0
- dvt/parser/__init__.py +23 -0
- dvt/parser/analysis.py +21 -0
- dvt/parser/base.py +549 -0
- dvt/parser/common.py +267 -0
- dvt/parser/docs.py +52 -0
- dvt/parser/fixtures.py +51 -0
- dvt/parser/functions.py +30 -0
- dvt/parser/generic_test.py +100 -0
- dvt/parser/generic_test_builders.py +334 -0
- dvt/parser/hooks.py +119 -0
- dvt/parser/macros.py +137 -0
- dvt/parser/manifest.py +2204 -0
- dvt/parser/models.py +574 -0
- dvt/parser/partial.py +1179 -0
- dvt/parser/read_files.py +445 -0
- dvt/parser/schema_generic_tests.py +423 -0
- dvt/parser/schema_renderer.py +111 -0
- dvt/parser/schema_yaml_readers.py +936 -0
- dvt/parser/schemas.py +1467 -0
- dvt/parser/search.py +149 -0
- dvt/parser/seeds.py +28 -0
- dvt/parser/singular_test.py +20 -0
- dvt/parser/snapshots.py +44 -0
- dvt/parser/sources.py +557 -0
- dvt/parser/sql.py +63 -0
- dvt/parser/unit_tests.py +622 -0
- dvt/plugins/__init__.py +20 -0
- dvt/plugins/contracts.py +10 -0
- dvt/plugins/exceptions.py +2 -0
- dvt/plugins/manager.py +164 -0
- dvt/plugins/manifest.py +21 -0
- dvt/profiler.py +20 -0
- dvt/py.typed +1 -0
- dvt/runners/__init__.py +2 -0
- dvt/runners/exposure_runner.py +7 -0
- dvt/runners/no_op_runner.py +46 -0
- dvt/runners/saved_query_runner.py +7 -0
- dvt/selected_resources.py +8 -0
- dvt/task/__init__.py +0 -0
- dvt/task/base.py +504 -0
- dvt/task/build.py +197 -0
- dvt/task/clean.py +57 -0
- dvt/task/clone.py +162 -0
- dvt/task/compile.py +151 -0
- dvt/task/compute.py +366 -0
- dvt/task/debug.py +650 -0
- dvt/task/deps.py +280 -0
- dvt/task/docs/__init__.py +3 -0
- dvt/task/docs/generate.py +408 -0
- dvt/task/docs/index.html +250 -0
- dvt/task/docs/serve.py +28 -0
- dvt/task/freshness.py +323 -0
- dvt/task/function.py +122 -0
- dvt/task/group_lookup.py +46 -0
- dvt/task/init.py +374 -0
- dvt/task/list.py +237 -0
- dvt/task/printer.py +176 -0
- dvt/task/profiles.py +256 -0
- dvt/task/retry.py +175 -0
- dvt/task/run.py +1146 -0
- dvt/task/run_operation.py +142 -0
- dvt/task/runnable.py +802 -0
- dvt/task/seed.py +104 -0
- dvt/task/show.py +150 -0
- dvt/task/snapshot.py +57 -0
- dvt/task/sql.py +111 -0
- dvt/task/test.py +464 -0
- dvt/tests/fixtures/__init__.py +1 -0
- dvt/tests/fixtures/project.py +620 -0
- dvt/tests/util.py +651 -0
- dvt/tracking.py +529 -0
- dvt/utils/__init__.py +3 -0
- dvt/utils/artifact_upload.py +151 -0
- dvt/utils/utils.py +408 -0
- dvt/version.py +249 -0
- dvt_core-1.11.0b4.dist-info/METADATA +252 -0
- dvt_core-1.11.0b4.dist-info/RECORD +261 -0
- dvt_core-1.11.0b4.dist-info/WHEEL +5 -0
- dvt_core-1.11.0b4.dist-info/entry_points.txt +2 -0
- 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)
|
|
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
|
+
)
|
|
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
|
+
)
|