dvt-pro 0.2.0__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.
Files changed (254) hide show
  1. dbt/__init__.py +7 -0
  2. dbt/artifacts/__init__.py +0 -0
  3. dbt/artifacts/exceptions/__init__.py +1 -0
  4. dbt/artifacts/exceptions/schemas.py +31 -0
  5. dbt/artifacts/resources/__init__.py +98 -0
  6. dbt/artifacts/resources/base.py +67 -0
  7. dbt/artifacts/resources/types.py +77 -0
  8. dbt/artifacts/resources/v1/analysis.py +10 -0
  9. dbt/artifacts/resources/v1/components.py +248 -0
  10. dbt/artifacts/resources/v1/config.py +265 -0
  11. dbt/artifacts/resources/v1/documentation.py +11 -0
  12. dbt/artifacts/resources/v1/exposure.py +49 -0
  13. dbt/artifacts/resources/v1/generic_test.py +31 -0
  14. dbt/artifacts/resources/v1/group.py +13 -0
  15. dbt/artifacts/resources/v1/hook.py +11 -0
  16. dbt/artifacts/resources/v1/macro.py +29 -0
  17. dbt/artifacts/resources/v1/metric.py +147 -0
  18. dbt/artifacts/resources/v1/model.py +56 -0
  19. dbt/artifacts/resources/v1/owner.py +10 -0
  20. dbt/artifacts/resources/v1/saved_query.py +105 -0
  21. dbt/artifacts/resources/v1/seed.py +43 -0
  22. dbt/artifacts/resources/v1/semantic_layer_components.py +50 -0
  23. dbt/artifacts/resources/v1/semantic_model.py +272 -0
  24. dbt/artifacts/resources/v1/singular_test.py +14 -0
  25. dbt/artifacts/resources/v1/snapshot.py +93 -0
  26. dbt/artifacts/resources/v1/source_definition.py +82 -0
  27. dbt/artifacts/resources/v1/sql_operation.py +10 -0
  28. dbt/artifacts/resources/v1/unit_test_definition.py +77 -0
  29. dbt/artifacts/schemas/__init__.py +0 -0
  30. dbt/artifacts/schemas/base.py +178 -0
  31. dbt/artifacts/schemas/batch_results.py +24 -0
  32. dbt/artifacts/schemas/catalog/__init__.py +11 -0
  33. dbt/artifacts/schemas/catalog/v1/__init__.py +0 -0
  34. dbt/artifacts/schemas/catalog/v1/catalog.py +59 -0
  35. dbt/artifacts/schemas/freshness/__init__.py +1 -0
  36. dbt/artifacts/schemas/freshness/v3/__init__.py +0 -0
  37. dbt/artifacts/schemas/freshness/v3/freshness.py +158 -0
  38. dbt/artifacts/schemas/manifest/__init__.py +2 -0
  39. dbt/artifacts/schemas/manifest/v12/__init__.py +0 -0
  40. dbt/artifacts/schemas/manifest/v12/manifest.py +182 -0
  41. dbt/artifacts/schemas/results.py +145 -0
  42. dbt/artifacts/schemas/run/__init__.py +2 -0
  43. dbt/artifacts/schemas/run/v5/__init__.py +0 -0
  44. dbt/artifacts/schemas/run/v5/run.py +182 -0
  45. dbt/artifacts/schemas/upgrades/__init__.py +1 -0
  46. dbt/artifacts/schemas/upgrades/upgrade_manifest.py +174 -0
  47. dbt/artifacts/utils/validation.py +153 -0
  48. dbt/cli/__init__.py +1 -0
  49. dbt/cli/context.py +17 -0
  50. dbt/cli/exceptions.py +57 -0
  51. dbt/cli/flags.py +541 -0
  52. dbt/cli/main.py +835 -0
  53. dbt/cli/option_types.py +90 -0
  54. dbt/cli/options.py +80 -0
  55. dbt/cli/params.py +759 -0
  56. dbt/cli/requires.py +360 -0
  57. dbt/cli/resolvers.py +32 -0
  58. dbt/cli/types.py +40 -0
  59. dbt/clients/__init__.py +0 -0
  60. dbt/clients/git.py +164 -0
  61. dbt/clients/jinja.py +206 -0
  62. dbt/clients/jinja_static.py +245 -0
  63. dbt/clients/registry.py +192 -0
  64. dbt/clients/yaml_helper.py +68 -0
  65. dbt/compilation.py +642 -0
  66. dbt/config/__init__.py +4 -0
  67. dbt/config/profile.py +408 -0
  68. dbt/config/project.py +839 -0
  69. dbt/config/renderer.py +231 -0
  70. dbt/config/runtime.py +480 -0
  71. dbt/config/selectors.py +206 -0
  72. dbt/config/utils.py +66 -0
  73. dbt/constants.py +24 -0
  74. dbt/context/__init__.py +0 -0
  75. dbt/context/base.py +737 -0
  76. dbt/context/configured.py +135 -0
  77. dbt/context/context_config.py +343 -0
  78. dbt/context/docs.py +82 -0
  79. dbt/context/exceptions_jinja.py +178 -0
  80. dbt/context/macro_resolver.py +195 -0
  81. dbt/context/macros.py +171 -0
  82. dbt/context/manifest.py +72 -0
  83. dbt/context/providers.py +1985 -0
  84. dbt/context/query_header.py +13 -0
  85. dbt/context/secret.py +58 -0
  86. dbt/context/target.py +74 -0
  87. dbt/contracts/__init__.py +0 -0
  88. dbt/contracts/files.py +410 -0
  89. dbt/contracts/graph/__init__.py +0 -0
  90. dbt/contracts/graph/manifest.py +1813 -0
  91. dbt/contracts/graph/metrics.py +97 -0
  92. dbt/contracts/graph/model_config.py +66 -0
  93. dbt/contracts/graph/node_args.py +40 -0
  94. dbt/contracts/graph/nodes.py +1757 -0
  95. dbt/contracts/graph/semantic_manifest.py +231 -0
  96. dbt/contracts/graph/unparsed.py +802 -0
  97. dbt/contracts/project.py +405 -0
  98. dbt/contracts/results.py +53 -0
  99. dbt/contracts/selection.py +23 -0
  100. dbt/contracts/sql.py +79 -0
  101. dbt/contracts/state.py +67 -0
  102. dbt/contracts/util.py +46 -0
  103. dbt/deprecations.py +200 -0
  104. dbt/deps/__init__.py +0 -0
  105. dbt/deps/base.py +152 -0
  106. dbt/deps/git.py +195 -0
  107. dbt/deps/local.py +79 -0
  108. dbt/deps/registry.py +130 -0
  109. dbt/deps/resolver.py +149 -0
  110. dbt/deps/tarball.py +120 -0
  111. dbt/docs/source/_ext/dbt_click.py +119 -0
  112. dbt/docs/source/conf.py +32 -0
  113. dbt/events/__init__.py +15 -0
  114. dbt/events/base_types.py +37 -0
  115. dbt/events/core_types_pb2.py +822 -0
  116. dbt/events/logging.py +116 -0
  117. dbt/events/types.py +2169 -0
  118. dbt/exceptions.py +1486 -0
  119. dbt/flags.py +89 -0
  120. dbt/graph/__init__.py +11 -0
  121. dbt/graph/cli.py +247 -0
  122. dbt/graph/graph.py +160 -0
  123. dbt/graph/queue.py +214 -0
  124. dbt/graph/selector.py +367 -0
  125. dbt/graph/selector_methods.py +961 -0
  126. dbt/graph/selector_spec.py +222 -0
  127. dbt/graph/thread_pool.py +18 -0
  128. dbt/hooks.py +21 -0
  129. dbt/include/README.md +63 -0
  130. dbt/include/__init__.py +3 -0
  131. dbt/include/starter_project/.gitignore +5 -0
  132. dbt/include/starter_project/README.md +15 -0
  133. dbt/include/starter_project/__init__.py +3 -0
  134. dbt/include/starter_project/analyses/.gitkeep +0 -0
  135. dbt/include/starter_project/dbt_project.yml +36 -0
  136. dbt/include/starter_project/macros/.gitkeep +0 -0
  137. dbt/include/starter_project/models/example/my_first_dbt_model.sql +27 -0
  138. dbt/include/starter_project/models/example/my_second_dbt_model.sql +6 -0
  139. dbt/include/starter_project/models/example/schema.yml +21 -0
  140. dbt/include/starter_project/seeds/.gitkeep +0 -0
  141. dbt/include/starter_project/snapshots/.gitkeep +0 -0
  142. dbt/include/starter_project/tests/.gitkeep +0 -0
  143. dbt/internal_deprecations.py +26 -0
  144. dbt/links.py +4 -0
  145. dbt/materializations/__init__.py +0 -0
  146. dbt/materializations/incremental/__init__.py +0 -0
  147. dbt/materializations/incremental/microbatch.py +236 -0
  148. dbt/mp_context.py +8 -0
  149. dbt/node_types.py +36 -0
  150. dbt/parser/__init__.py +23 -0
  151. dbt/parser/analysis.py +21 -0
  152. dbt/parser/base.py +511 -0
  153. dbt/parser/common.py +252 -0
  154. dbt/parser/docs.py +51 -0
  155. dbt/parser/fixtures.py +51 -0
  156. dbt/parser/generic_test.py +100 -0
  157. dbt/parser/generic_test_builders.py +389 -0
  158. dbt/parser/hooks.py +118 -0
  159. dbt/parser/macros.py +119 -0
  160. dbt/parser/manifest.py +2086 -0
  161. dbt/parser/models.py +569 -0
  162. dbt/parser/partial.py +1129 -0
  163. dbt/parser/read_files.py +440 -0
  164. dbt/parser/schema_generic_tests.py +418 -0
  165. dbt/parser/schema_renderer.py +100 -0
  166. dbt/parser/schema_yaml_readers.py +871 -0
  167. dbt/parser/schemas.py +1249 -0
  168. dbt/parser/search.py +135 -0
  169. dbt/parser/seeds.py +28 -0
  170. dbt/parser/singular_test.py +20 -0
  171. dbt/parser/snapshots.py +44 -0
  172. dbt/parser/sources.py +468 -0
  173. dbt/parser/sql.py +62 -0
  174. dbt/parser/unit_tests.py +615 -0
  175. dbt/plugins/__init__.py +20 -0
  176. dbt/plugins/contracts.py +9 -0
  177. dbt/plugins/exceptions.py +2 -0
  178. dbt/plugins/manager.py +163 -0
  179. dbt/plugins/manifest.py +21 -0
  180. dbt/profiler.py +20 -0
  181. dbt/py.typed +1 -0
  182. dbt/selected_resources.py +8 -0
  183. dbt/task/__init__.py +0 -0
  184. dbt/task/base.py +497 -0
  185. dbt/task/build.py +233 -0
  186. dbt/task/clean.py +56 -0
  187. dbt/task/clone.py +161 -0
  188. dbt/task/compile.py +150 -0
  189. dbt/task/debug.py +502 -0
  190. dbt/task/deps.py +277 -0
  191. dbt/task/docs/__init__.py +3 -0
  192. dbt/task/docs/generate.py +406 -0
  193. dbt/task/docs/index.html +250 -0
  194. dbt/task/docs/serve.py +29 -0
  195. dbt/task/freshness.py +301 -0
  196. dbt/task/group_lookup.py +46 -0
  197. dbt/task/init.py +346 -0
  198. dbt/task/list.py +214 -0
  199. dbt/task/printer.py +166 -0
  200. dbt/task/retry.py +174 -0
  201. dbt/task/run.py +1115 -0
  202. dbt/task/run_operation.py +144 -0
  203. dbt/task/runnable.py +743 -0
  204. dbt/task/seed.py +101 -0
  205. dbt/task/show.py +150 -0
  206. dbt/task/snapshot.py +54 -0
  207. dbt/task/sql.py +110 -0
  208. dbt/task/test.py +463 -0
  209. dbt/tests/fixtures/__init__.py +1 -0
  210. dbt/tests/fixtures/project.py +609 -0
  211. dbt/tests/util.py +651 -0
  212. dbt/tracking.py +515 -0
  213. dbt/utils.py +408 -0
  214. dbt/version.py +232 -0
  215. dvt/__init__.py +3 -0
  216. dvt/cli/__init__.py +63 -0
  217. dvt/cli/main.py +855 -0
  218. dvt/config/__init__.py +0 -0
  219. dvt/config/parse_state.py +156 -0
  220. dvt/config/source_connections.py +195 -0
  221. dvt/config/target_resolver.py +199 -0
  222. dvt/exceptions.py +92 -0
  223. dvt/extraction/__init__.py +0 -0
  224. dvt/extraction/connection_mapper.py +269 -0
  225. dvt/extraction/sling_client.py +400 -0
  226. dvt/extraction/watermark_formatter.py +249 -0
  227. dvt/federation/__init__.py +0 -0
  228. dvt/federation/duckdb_compute.py +123 -0
  229. dvt/federation/dvt_cache.py +223 -0
  230. dvt/federation/optimizer.py +348 -0
  231. dvt/loading/__init__.py +0 -0
  232. dvt/runners/__init__.py +0 -0
  233. dvt/runners/model_runner.py +599 -0
  234. dvt/runners/seed_runner.py +159 -0
  235. dvt/sync/__init__.py +0 -0
  236. dvt/sync/adapter_installer.py +213 -0
  237. dvt/sync/cloud_deps.py +48 -0
  238. dvt/sync/duckdb_extensions.py +71 -0
  239. dvt/sync/profiles_reader.py +90 -0
  240. dvt/sync/sling_checker.py +124 -0
  241. dvt/tasks/__init__.py +0 -0
  242. dvt/tasks/build.py +23 -0
  243. dvt/tasks/debug.py +290 -0
  244. dvt/tasks/docs.py +390 -0
  245. dvt/tasks/retract.py +278 -0
  246. dvt/tasks/run.py +191 -0
  247. dvt/tasks/seed.py +49 -0
  248. dvt/tasks/show.py +308 -0
  249. dvt/tasks/sync.py +250 -0
  250. dvt_pro-0.2.0.dist-info/METADATA +407 -0
  251. dvt_pro-0.2.0.dist-info/RECORD +254 -0
  252. dvt_pro-0.2.0.dist-info/WHEEL +5 -0
  253. dvt_pro-0.2.0.dist-info/entry_points.txt +3 -0
  254. dvt_pro-0.2.0.dist-info/top_level.txt +2 -0
dbt/__init__.py ADDED
@@ -0,0 +1,7 @@
1
+ # N.B.
2
+ # This will add to the package’s __path__ all subdirectories of directories on sys.path named after the package which effectively combines both modules into a single namespace (dbt.adapters)
3
+ # The matching statement is in plugins/postgres/dbt/__init__.py
4
+
5
+ from pkgutil import extend_path
6
+
7
+ __path__ = extend_path(__path__, __name__)
File without changes
@@ -0,0 +1 @@
1
+ from dbt.artifacts.exceptions.schemas import IncompatibleSchemaError
@@ -0,0 +1,31 @@
1
+ from typing import Optional
2
+
3
+ from dbt_common.exceptions import DbtRuntimeError
4
+
5
+
6
+ class IncompatibleSchemaError(DbtRuntimeError):
7
+ def __init__(self, expected: str, found: Optional[str] = None) -> None:
8
+ self.expected = expected
9
+ self.found = found
10
+ self.filename = "input file"
11
+
12
+ super().__init__(msg=self.get_message())
13
+
14
+ def add_filename(self, filename: str):
15
+ self.filename = filename
16
+ self.msg = self.get_message()
17
+
18
+ def get_message(self) -> str:
19
+ found_str = "nothing"
20
+ if self.found is not None:
21
+ found_str = f'"{self.found}"'
22
+
23
+ msg = (
24
+ f'Expected a schema version of "{self.expected}" in '
25
+ f"{self.filename}, but found {found_str}. Are you running with a "
26
+ f"different version of dbt?"
27
+ )
28
+ return msg
29
+
30
+ CODE = 10014
31
+ MESSAGE = "Incompatible Schema"
@@ -0,0 +1,98 @@
1
+ from dbt.artifacts.resources.base import BaseResource, Docs, FileHash, GraphResource
2
+ from dbt.artifacts.resources.v1.analysis import Analysis
3
+
4
+ # alias to latest resource definitions
5
+ from dbt.artifacts.resources.v1.components import (
6
+ ColumnConfig,
7
+ ColumnInfo,
8
+ CompiledResource,
9
+ Contract,
10
+ DeferRelation,
11
+ DependsOn,
12
+ FreshnessThreshold,
13
+ HasRelationMetadata,
14
+ InjectedCTE,
15
+ NodeVersion,
16
+ ParsedResource,
17
+ ParsedResourceMandatory,
18
+ Quoting,
19
+ RefArgs,
20
+ Time,
21
+ )
22
+ from dbt.artifacts.resources.v1.config import (
23
+ Hook,
24
+ NodeAndTestConfig,
25
+ NodeConfig,
26
+ TestConfig,
27
+ )
28
+ from dbt.artifacts.resources.v1.documentation import Documentation
29
+ from dbt.artifacts.resources.v1.exposure import (
30
+ Exposure,
31
+ ExposureConfig,
32
+ ExposureType,
33
+ MaturityType,
34
+ )
35
+ from dbt.artifacts.resources.v1.generic_test import GenericTest, TestMetadata
36
+ from dbt.artifacts.resources.v1.group import Group
37
+ from dbt.artifacts.resources.v1.hook import HookNode
38
+ from dbt.artifacts.resources.v1.macro import Macro, MacroArgument, MacroDependsOn
39
+ from dbt.artifacts.resources.v1.metric import (
40
+ ConstantPropertyInput,
41
+ ConversionTypeParams,
42
+ CumulativeTypeParams,
43
+ Metric,
44
+ MetricConfig,
45
+ MetricInput,
46
+ MetricInputMeasure,
47
+ MetricTimeWindow,
48
+ MetricTypeParams,
49
+ )
50
+ from dbt.artifacts.resources.v1.model import Model, ModelConfig, TimeSpine
51
+ from dbt.artifacts.resources.v1.owner import Owner
52
+ from dbt.artifacts.resources.v1.saved_query import (
53
+ Export,
54
+ ExportConfig,
55
+ QueryParams,
56
+ SavedQuery,
57
+ SavedQueryConfig,
58
+ SavedQueryMandatory,
59
+ )
60
+ from dbt.artifacts.resources.v1.seed import Seed, SeedConfig
61
+ from dbt.artifacts.resources.v1.semantic_layer_components import (
62
+ FileSlice,
63
+ SourceFileMetadata,
64
+ WhereFilter,
65
+ WhereFilterIntersection,
66
+ )
67
+ from dbt.artifacts.resources.v1.semantic_model import (
68
+ Defaults,
69
+ Dimension,
70
+ DimensionTypeParams,
71
+ DimensionValidityParams,
72
+ Entity,
73
+ Measure,
74
+ MeasureAggregationParameters,
75
+ NodeRelation,
76
+ NonAdditiveDimension,
77
+ SemanticModel,
78
+ SemanticModelConfig,
79
+ )
80
+ from dbt.artifacts.resources.v1.singular_test import SingularTest
81
+ from dbt.artifacts.resources.v1.snapshot import Snapshot, SnapshotConfig
82
+ from dbt.artifacts.resources.v1.source_definition import (
83
+ ExternalPartition,
84
+ ExternalTable,
85
+ ParsedSourceMandatory,
86
+ SourceConfig,
87
+ SourceDefinition,
88
+ )
89
+ from dbt.artifacts.resources.v1.sql_operation import SqlOperation
90
+ from dbt.artifacts.resources.v1.unit_test_definition import (
91
+ UnitTestConfig,
92
+ UnitTestDefinition,
93
+ UnitTestFormat,
94
+ UnitTestInputFixture,
95
+ UnitTestNodeVersions,
96
+ UnitTestOutputFixture,
97
+ UnitTestOverrides,
98
+ )
@@ -0,0 +1,67 @@
1
+ import hashlib
2
+ from dataclasses import dataclass
3
+ from typing import List, Optional
4
+
5
+ from dbt.artifacts.resources.types import NodeType
6
+ from dbt_common.dataclass_schema import dbtClassMixin
7
+
8
+
9
+ @dataclass
10
+ class BaseResource(dbtClassMixin):
11
+ name: str
12
+ resource_type: NodeType
13
+ package_name: str
14
+ path: str
15
+ original_file_path: str
16
+ unique_id: str
17
+
18
+
19
+ @dataclass
20
+ class GraphResource(BaseResource):
21
+ fqn: List[str]
22
+
23
+
24
+ @dataclass
25
+ class FileHash(dbtClassMixin):
26
+ name: str # the hash type name
27
+ checksum: str # the hashlib.hash_type().hexdigest() of the file contents
28
+
29
+ @classmethod
30
+ def empty(cls):
31
+ return FileHash(name="none", checksum="")
32
+
33
+ @classmethod
34
+ def path(cls, path: str):
35
+ return FileHash(name="path", checksum=path)
36
+
37
+ def __eq__(self, other):
38
+ if not isinstance(other, FileHash):
39
+ return NotImplemented
40
+
41
+ if self.name == "none" or self.name != other.name:
42
+ return False
43
+
44
+ return self.checksum == other.checksum
45
+
46
+ def compare(self, contents: str) -> bool:
47
+ """Compare the file contents with the given hash"""
48
+ if self.name == "none":
49
+ return False
50
+
51
+ return self.from_contents(contents, name=self.name) == self.checksum
52
+
53
+ @classmethod
54
+ def from_contents(cls, contents: str, name="sha256") -> "FileHash":
55
+ """Create a file hash from the given file contents. The hash is always
56
+ the utf-8 encoding of the contents given, because dbt only reads files
57
+ as utf-8.
58
+ """
59
+ data = contents.encode("utf-8")
60
+ checksum = hashlib.new(name, data).hexdigest()
61
+ return cls(name=name, checksum=checksum)
62
+
63
+
64
+ @dataclass
65
+ class Docs(dbtClassMixin):
66
+ show: bool = True
67
+ node_color: Optional[str] = None
@@ -0,0 +1,77 @@
1
+ from dbt_common.dataclass_schema import StrEnum
2
+
3
+
4
+ class AccessType(StrEnum):
5
+ Private = "private"
6
+ Protected = "protected"
7
+ Public = "public"
8
+
9
+ @classmethod
10
+ def is_valid(cls, item):
11
+ try:
12
+ cls(item)
13
+ except ValueError:
14
+ return False
15
+ return True
16
+
17
+
18
+ class NodeType(StrEnum):
19
+ Model = "model"
20
+ Analysis = "analysis"
21
+ Test = "test" # renamed to 'data_test'; preserved as 'test' here for back-compat
22
+ Snapshot = "snapshot"
23
+ Operation = "operation"
24
+ Seed = "seed"
25
+ # TODO: rm?
26
+ RPCCall = "rpc"
27
+ SqlOperation = "sql_operation"
28
+ Documentation = "doc"
29
+ Source = "source"
30
+ Macro = "macro"
31
+ Exposure = "exposure"
32
+ Metric = "metric"
33
+ Group = "group"
34
+ SavedQuery = "saved_query"
35
+ SemanticModel = "semantic_model"
36
+ Unit = "unit_test"
37
+ Fixture = "fixture"
38
+
39
+ def pluralize(self) -> str:
40
+ if self is self.Analysis:
41
+ return "analyses"
42
+ elif self is self.SavedQuery:
43
+ return "saved_queries"
44
+ elif self is self.Test:
45
+ return "data_tests"
46
+ return f"{self}s"
47
+
48
+
49
+ class RunHookType(StrEnum):
50
+ Start = "on-run-start"
51
+ End = "on-run-end"
52
+
53
+
54
+ class ModelLanguage(StrEnum):
55
+ python = "python"
56
+ sql = "sql"
57
+
58
+
59
+ class ModelHookType(StrEnum):
60
+ PreHook = "pre-hook"
61
+ PostHook = "post-hook"
62
+
63
+
64
+ class TimePeriod(StrEnum):
65
+ minute = "minute"
66
+ hour = "hour"
67
+ day = "day"
68
+
69
+ def plural(self) -> str:
70
+ return str(self) + "s"
71
+
72
+
73
+ class BatchSize(StrEnum):
74
+ hour = "hour"
75
+ day = "day"
76
+ month = "month"
77
+ year = "year"
@@ -0,0 +1,10 @@
1
+ from dataclasses import dataclass
2
+ from typing import Literal
3
+
4
+ from dbt.artifacts.resources.types import NodeType
5
+ from dbt.artifacts.resources.v1.components import CompiledResource
6
+
7
+
8
+ @dataclass
9
+ class Analysis(CompiledResource):
10
+ resource_type: Literal[NodeType.Analysis]
@@ -0,0 +1,248 @@
1
+ import time
2
+ from dataclasses import dataclass, field
3
+ from datetime import timedelta
4
+ from typing import Any, Dict, List, Optional, Union
5
+
6
+ from dbt.artifacts.resources.base import Docs, FileHash, GraphResource
7
+ from dbt.artifacts.resources.types import NodeType, TimePeriod
8
+ from dbt.artifacts.resources.v1.config import NodeConfig
9
+ from dbt_common.contracts.config.base import BaseConfig, MergeBehavior
10
+ from dbt_common.contracts.config.properties import AdditionalPropertiesMixin
11
+ from dbt_common.contracts.constraints import ColumnLevelConstraint
12
+ from dbt_common.contracts.util import Mergeable
13
+ from dbt_common.dataclass_schema import ExtensibleDbtClassMixin, dbtClassMixin
14
+ from dbt_semantic_interfaces.type_enums import TimeGranularity
15
+
16
+ NodeVersion = Union[str, float]
17
+
18
+
19
+ @dataclass
20
+ class MacroDependsOn(dbtClassMixin):
21
+ macros: List[str] = field(default_factory=list)
22
+
23
+ # 'in' on lists is O(n) so this is O(n^2) for # of macros
24
+ def add_macro(self, value: str):
25
+ if value not in self.macros:
26
+ self.macros.append(value)
27
+
28
+
29
+ @dataclass
30
+ class DependsOn(MacroDependsOn):
31
+ nodes: List[str] = field(default_factory=list)
32
+
33
+ def add_node(self, value: str):
34
+ if value not in self.nodes:
35
+ self.nodes.append(value)
36
+
37
+
38
+ @dataclass
39
+ class RefArgs(dbtClassMixin):
40
+ name: str
41
+ package: Optional[str] = None
42
+ version: Optional[NodeVersion] = None
43
+
44
+ @property
45
+ def positional_args(self) -> List[str]:
46
+ if self.package:
47
+ return [self.package, self.name]
48
+ else:
49
+ return [self.name]
50
+
51
+ @property
52
+ def keyword_args(self) -> Dict[str, Optional[NodeVersion]]:
53
+ if self.version:
54
+ return {"version": self.version}
55
+ else:
56
+ return {}
57
+
58
+
59
+ @dataclass
60
+ class ColumnConfig(BaseConfig):
61
+ meta: Dict[str, Any] = field(default_factory=dict, metadata=MergeBehavior.Update.meta())
62
+ tags: List[str] = field(default_factory=list)
63
+
64
+
65
+ @dataclass
66
+ class ColumnInfo(AdditionalPropertiesMixin, ExtensibleDbtClassMixin):
67
+ """Used in all ManifestNodes and SourceDefinition"""
68
+
69
+ name: str
70
+ description: str = ""
71
+ meta: Dict[str, Any] = field(default_factory=dict)
72
+ data_type: Optional[str] = None
73
+ constraints: List[ColumnLevelConstraint] = field(default_factory=list)
74
+ quote: Optional[bool] = None
75
+ config: ColumnConfig = field(default_factory=ColumnConfig)
76
+ tags: List[str] = field(default_factory=list)
77
+ _extra: Dict[str, Any] = field(default_factory=dict)
78
+ granularity: Optional[TimeGranularity] = None
79
+
80
+
81
+ @dataclass
82
+ class InjectedCTE(dbtClassMixin):
83
+ """Used in CompiledNodes as part of ephemeral model processing"""
84
+
85
+ id: str
86
+ sql: str
87
+
88
+
89
+ @dataclass
90
+ class Contract(dbtClassMixin):
91
+ enforced: bool = False
92
+ alias_types: bool = True
93
+ checksum: Optional[str] = None
94
+
95
+
96
+ @dataclass
97
+ class Quoting(dbtClassMixin, Mergeable):
98
+ database: Optional[bool] = None
99
+ schema: Optional[bool] = None
100
+ identifier: Optional[bool] = None
101
+ column: Optional[bool] = None
102
+
103
+
104
+ @dataclass
105
+ class Time(dbtClassMixin, Mergeable):
106
+ count: Optional[int] = None
107
+ period: Optional[TimePeriod] = None
108
+
109
+ def exceeded(self, actual_age: float) -> bool:
110
+ if self.period is None or self.count is None:
111
+ return False
112
+ kwargs: Dict[str, int] = {self.period.plural(): self.count}
113
+ difference = timedelta(**kwargs).total_seconds()
114
+ return actual_age > difference
115
+
116
+ def __bool__(self):
117
+ return self.count is not None and self.period is not None
118
+
119
+
120
+ @dataclass
121
+ class FreshnessThreshold(dbtClassMixin, Mergeable):
122
+ warn_after: Optional[Time] = field(default_factory=Time)
123
+ error_after: Optional[Time] = field(default_factory=Time)
124
+ filter: Optional[str] = None
125
+
126
+ def status(self, age: float) -> "dbt.artifacts.schemas.results.FreshnessStatus": # type: ignore # noqa F821
127
+ from dbt.artifacts.schemas.results import FreshnessStatus
128
+
129
+ if self.error_after and self.error_after.exceeded(age):
130
+ return FreshnessStatus.Error
131
+ elif self.warn_after and self.warn_after.exceeded(age):
132
+ return FreshnessStatus.Warn
133
+ else:
134
+ return FreshnessStatus.Pass
135
+
136
+ def __bool__(self):
137
+ return bool(self.warn_after) or bool(self.error_after)
138
+
139
+
140
+ @dataclass
141
+ class HasRelationMetadata(dbtClassMixin):
142
+ database: Optional[str]
143
+ schema: str
144
+
145
+ # Can't set database to None like it ought to be
146
+ # because it messes up the subclasses and default parameters
147
+ # so hack it here
148
+ @classmethod
149
+ def __pre_deserialize__(cls, data):
150
+ data = super().__pre_deserialize__(data)
151
+ if "database" not in data:
152
+ data["database"] = None
153
+ return data
154
+
155
+ @property
156
+ def quoting_dict(self) -> Dict[str, bool]:
157
+ if hasattr(self, "quoting"):
158
+ return self.quoting.to_dict(omit_none=True)
159
+ else:
160
+ return {}
161
+
162
+
163
+ @dataclass
164
+ class DeferRelation(HasRelationMetadata):
165
+ alias: str
166
+ relation_name: Optional[str]
167
+ # The rest of these fields match RelationConfig protocol exactly
168
+ resource_type: NodeType
169
+ name: str
170
+ description: str
171
+ compiled_code: Optional[str]
172
+ meta: Dict[str, Any]
173
+ tags: List[str]
174
+ config: Optional[NodeConfig]
175
+
176
+ @property
177
+ def identifier(self):
178
+ return self.alias
179
+
180
+
181
+ @dataclass
182
+ class ParsedResourceMandatory(GraphResource, HasRelationMetadata):
183
+ alias: str
184
+ checksum: FileHash
185
+ config: NodeConfig = field(default_factory=NodeConfig)
186
+
187
+ @property
188
+ def identifier(self):
189
+ return self.alias
190
+
191
+
192
+ @dataclass
193
+ class ParsedResource(ParsedResourceMandatory):
194
+ tags: List[str] = field(default_factory=list)
195
+ description: str = field(default="")
196
+ columns: Dict[str, ColumnInfo] = field(default_factory=dict)
197
+ meta: Dict[str, Any] = field(default_factory=dict)
198
+ group: Optional[str] = None
199
+ docs: Docs = field(default_factory=Docs)
200
+ patch_path: Optional[str] = None
201
+ build_path: Optional[str] = None
202
+ unrendered_config: Dict[str, Any] = field(default_factory=dict)
203
+ created_at: float = field(default_factory=lambda: time.time())
204
+ config_call_dict: Dict[str, Any] = field(default_factory=dict)
205
+ unrendered_config_call_dict: Dict[str, Any] = field(default_factory=dict)
206
+ relation_name: Optional[str] = None
207
+ raw_code: str = ""
208
+
209
+ def __post_serialize__(self, dct: Dict, context: Optional[Dict] = None):
210
+ dct = super().__post_serialize__(dct, context)
211
+ if context and context.get("artifact") and "config_call_dict" in dct:
212
+ del dct["config_call_dict"]
213
+ if context and context.get("artifact") and "unrendered_config_call_dict" in dct:
214
+ del dct["unrendered_config_call_dict"]
215
+ return dct
216
+
217
+
218
+ @dataclass
219
+ class CompiledResource(ParsedResource):
220
+ """Contains attributes necessary for SQL files and nodes with refs, sources, etc,
221
+ so all ManifestNodes except SeedNode."""
222
+
223
+ language: str = "sql"
224
+ refs: List[RefArgs] = field(default_factory=list)
225
+ sources: List[List[str]] = field(default_factory=list)
226
+ metrics: List[List[str]] = field(default_factory=list)
227
+ depends_on: DependsOn = field(default_factory=DependsOn)
228
+ compiled_path: Optional[str] = None
229
+ compiled: bool = False
230
+ compiled_code: Optional[str] = None
231
+ extra_ctes_injected: bool = False
232
+ extra_ctes: List[InjectedCTE] = field(default_factory=list)
233
+ _pre_injected_sql: Optional[str] = None
234
+ contract: Contract = field(default_factory=Contract)
235
+
236
+ def __post_serialize__(self, dct: Dict, context: Optional[Dict] = None):
237
+ dct = super().__post_serialize__(dct, context)
238
+ if "_pre_injected_sql" in dct:
239
+ del dct["_pre_injected_sql"]
240
+ # Remove compiled attributes
241
+ if "compiled" in dct and dct["compiled"] is False:
242
+ del dct["compiled"]
243
+ del dct["extra_ctes_injected"]
244
+ del dct["extra_ctes"]
245
+ # "omit_none" means these might not be in the dictionary
246
+ if "compiled_code" in dct:
247
+ del dct["compiled_code"]
248
+ return dct