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
dvt/__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__)
dvt/_pydantic_shim.py ADDED
@@ -0,0 +1,26 @@
1
+ # type: ignore
2
+
3
+ """Shim to allow support for both Pydantic 1 and Pydantic 2.
4
+
5
+ dbt-core must support both major versions of Pydantic because dbt-core users might be using an environment with
6
+ either version, and we can't restrict them to one or the other. Here, we essentially import all Pydantic objects
7
+ from version 1 that we use. Throughout the repo, we import these objects from this file instead of from Pydantic
8
+ directly, meaning that we essentially only use Pydantic 1 in dbt-core currently, but without forcing that restriction
9
+ on dbt users. The development environment for this repo should be pinned to Pydantic 1 to ensure devs get appropriate
10
+ type hints.
11
+ """
12
+
13
+ from importlib.metadata import version
14
+
15
+ pydantic_version = version("pydantic")
16
+ # Pydantic uses semantic versioning, i.e. <major>.<minor>.<patch>, and we need to know the major
17
+ pydantic_major = pydantic_version.split(".")[0]
18
+
19
+ if pydantic_major == "1":
20
+ from pydantic import BaseSettings # noqa: F401
21
+ elif pydantic_major == "2":
22
+ from pydantic.v1 import BaseSettings # noqa: F401
23
+ else:
24
+ raise RuntimeError(
25
+ f"Currently only pydantic 1 and 2 are supported, found pydantic {pydantic_version}"
26
+ )
@@ -0,0 +1,16 @@
1
+ """
2
+ DVT adapter management extensions.
3
+
4
+ This module extends dbt's adapter system to support multi-profile
5
+ source connections and compute layer integration.
6
+ """
7
+
8
+ from dvt.adapters.multi_adapter_manager import (
9
+ MultiAdapterManager,
10
+ create_multi_adapter_manager,
11
+ )
12
+
13
+ __all__ = [
14
+ "MultiAdapterManager",
15
+ "create_multi_adapter_manager",
16
+ ]
@@ -0,0 +1,268 @@
1
+ """
2
+ Multi-adapter management for DVT.
3
+
4
+ This module extends dbt's single-adapter model to support multiple
5
+ adapter instances for different profiles (sources + targets).
6
+ """
7
+
8
+ from multiprocessing.context import SpawnContext
9
+ from typing import Any, Dict, Optional
10
+
11
+ from dvt.config.profiles_v2 import (
12
+ ProfileReference,
13
+ ProfileRegistry,
14
+ UnifiedProfileConfig,
15
+ )
16
+
17
+ from dbt.adapters.factory import FACTORY, get_adapter_class_by_name, load_plugin
18
+ from dbt.adapters.protocol import AdapterProtocol
19
+ from dbt_common.events.base_types import EventLevel
20
+ from dbt_common.events.functions import fire_event
21
+ from dbt_common.events.types import Note
22
+ from dbt_common.exceptions import DbtRuntimeError
23
+
24
+
25
+ class MultiAdapterManager:
26
+ """
27
+ Manages multiple adapter instances for different profiles.
28
+
29
+ DVT extends dbt's single-adapter model by allowing:
30
+ 1. Multiple source connections (each with its own profile)
31
+ 2. Target connection (standard dbt output)
32
+ 3. Each profile can use a different adapter type
33
+
34
+ Architecture:
35
+ - Profile name -> Adapter instance mapping
36
+ - Lazy initialization (create adapter when first referenced)
37
+ - Cleanup management for all adapters
38
+ - Integration with dbt's existing adapter factory
39
+ """
40
+
41
+ def __init__(self, unified_profiles: UnifiedProfileConfig, mp_context: SpawnContext):
42
+ """
43
+ Initialize MultiAdapterManager.
44
+
45
+ Args:
46
+ unified_profiles: Unified profile configuration
47
+ mp_context: Multiprocessing context for adapter initialization
48
+ """
49
+ self.unified_profiles = unified_profiles
50
+ self.mp_context = mp_context
51
+ self._adapters: Dict[str, AdapterProtocol] = {}
52
+ self._profile_to_adapter_type: Dict[str, str] = {}
53
+
54
+ def get_or_create_adapter(
55
+ self,
56
+ profile_name: str,
57
+ adapter_registered_log_level: Optional[EventLevel] = EventLevel.INFO,
58
+ ) -> AdapterProtocol:
59
+ """
60
+ Get or create adapter instance for a profile.
61
+
62
+ This is the main entry point for getting adapters by profile name.
63
+ It handles:
64
+ 1. Checking if adapter already exists (cache)
65
+ 2. Loading profile configuration
66
+ 3. Loading adapter plugin if needed
67
+ 4. Creating and registering the adapter
68
+ 5. Caching for future use
69
+
70
+ Args:
71
+ profile_name: Name of the profile to get adapter for
72
+ adapter_registered_log_level: Log level for adapter registration
73
+
74
+ Returns:
75
+ Adapter instance
76
+
77
+ Raises:
78
+ DbtRuntimeError: If profile not found or adapter creation fails
79
+ """
80
+ # Check cache
81
+ if profile_name in self._adapters:
82
+ return self._adapters[profile_name]
83
+
84
+ # Get profile configuration
85
+ profile = self.unified_profiles.get_profile(profile_name)
86
+ if not profile:
87
+ raise DbtRuntimeError(
88
+ f"Profile '{profile_name}' not found in profiles configuration. "
89
+ f"Available profiles: {', '.join(self.unified_profiles.list_profiles())}"
90
+ )
91
+
92
+ # Ensure adapter plugin is loaded
93
+ adapter_type = profile.adapter
94
+ try:
95
+ load_plugin(adapter_type)
96
+ except Exception as e:
97
+ raise DbtRuntimeError(
98
+ f"Failed to load adapter plugin '{adapter_type}' for profile '{profile_name}': {e}"
99
+ )
100
+
101
+ # Create adapter configuration
102
+ # For DVT, we need to create a minimal AdapterRequiredConfig
103
+ # The actual credentials will come from the profile
104
+ adapter_config = self._create_adapter_config(profile)
105
+
106
+ # Check if an adapter of this type already exists in dbt's FACTORY
107
+ # If so, we can reuse it if the configuration matches
108
+ # Otherwise, create a new instance
109
+ try:
110
+ existing_adapter = FACTORY.lookup_adapter(adapter_type)
111
+ # Check if credentials match - if so, reuse
112
+ if self._credentials_match(existing_adapter, profile):
113
+ # Reusing existing adapter
114
+ self._adapters[profile_name] = existing_adapter
115
+ self._profile_to_adapter_type[profile_name] = adapter_type
116
+ return existing_adapter
117
+ except KeyError:
118
+ # No existing adapter of this type
119
+ pass
120
+
121
+ # Create new adapter instance
122
+ adapter_class = get_adapter_class_by_name(adapter_type)
123
+ adapter_instance = adapter_class(adapter_config, self.mp_context) # type: ignore[call-arg]
124
+
125
+ # Cache the adapter
126
+ self._adapters[profile_name] = adapter_instance
127
+ self._profile_to_adapter_type[profile_name] = adapter_type
128
+
129
+ return adapter_instance
130
+
131
+ def _create_adapter_config(self, profile: ProfileReference) -> Any:
132
+ """
133
+ Create adapter configuration from ProfileReference.
134
+
135
+ This converts DVT's ProfileReference to dbt's expected config format.
136
+ We create a minimal config object that satisfies adapter requirements.
137
+
138
+ Args:
139
+ profile: Profile reference
140
+
141
+ Returns:
142
+ Configuration object for adapter initialization
143
+ """
144
+ # Import credentials class for this adapter type
145
+ adapter_class = get_adapter_class_by_name(profile.adapter)
146
+ credentials_class = adapter_class.Credentials # type: ignore[attr-defined]
147
+
148
+ # Create credentials instance from profile
149
+ credentials_dict = {
150
+ "type": profile.adapter,
151
+ **profile.credentials,
152
+ }
153
+ credentials = credentials_class.from_dict(credentials_dict) # type: ignore[attr-defined]
154
+
155
+ # Create minimal config object
156
+ # Note: This is a simplified config for DVT multi-adapter support
157
+ # Full RuntimeConfig would have more fields, but adapters primarily need credentials
158
+ class MinimalAdapterConfig:
159
+ def __init__(self, creds, name, threads):
160
+ self.credentials = creds
161
+ self.project_name = name
162
+ self.profile_name = name
163
+ self.target_name = name
164
+ self.threads = threads
165
+ # Required protocol fields
166
+ self.query_comment: Dict[str, Any] = {}
167
+ self.cli_vars: Dict[str, Any] = {}
168
+ self.target_path = "target"
169
+ self.log_cache_events = False
170
+
171
+ config = MinimalAdapterConfig(credentials, profile.name, profile.threads)
172
+ return config
173
+
174
+ def _credentials_match(self, adapter: AdapterProtocol, profile: ProfileReference) -> bool:
175
+ """
176
+ Check if adapter's credentials match the profile.
177
+
178
+ Args:
179
+ adapter: Existing adapter instance
180
+ profile: Profile reference to compare
181
+
182
+ Returns:
183
+ True if credentials match, False otherwise
184
+ """
185
+ # Get adapter's credentials
186
+ adapter_creds = adapter.config.credentials.to_dict() # type: ignore[attr-defined]
187
+ profile_creds = {
188
+ "type": profile.adapter,
189
+ **profile.credentials,
190
+ }
191
+
192
+ # Compare key fields (excluding transient fields like query comments)
193
+ key_fields = ["type", "host", "port", "user", "database", "schema"]
194
+ for field in key_fields:
195
+ if field in adapter_creds or field in profile_creds:
196
+ if adapter_creds.get(field) != profile_creds.get(field):
197
+ return False
198
+
199
+ return True
200
+
201
+ def get_adapter_for_source(self, source_node) -> AdapterProtocol:
202
+ """
203
+ Get adapter for a source node.
204
+
205
+ Args:
206
+ source_node: Source node with profile reference
207
+
208
+ Returns:
209
+ Adapter instance for the source's profile
210
+
211
+ Raises:
212
+ DbtRuntimeError: If source has no profile or profile not found
213
+ """
214
+ if not hasattr(source_node, "profile") or not source_node.profile:
215
+ raise DbtRuntimeError(
216
+ f"Source '{source_node.name}' has no profile reference. "
217
+ "Sources must specify a profile in sources.yml"
218
+ )
219
+
220
+ return self.get_or_create_adapter(source_node.profile)
221
+
222
+ def cleanup_all_adapters(self) -> None:
223
+ """Clean up all managed adapters."""
224
+ for profile_name, adapter in self._adapters.items():
225
+ try:
226
+ adapter.cleanup_connections() # type: ignore[attr-defined]
227
+ fire_event(Note(msg="Cleaned up adapter for profile '{}'".format(profile_name)))
228
+ except Exception as e:
229
+ fire_event(
230
+ Note(
231
+ msg="Error cleaning up adapter for profile '{}': {}".format(
232
+ profile_name, e
233
+ )
234
+ )
235
+ )
236
+
237
+ self._adapters.clear()
238
+ self._profile_to_adapter_type.clear()
239
+
240
+ def list_active_adapters(self) -> Dict[str, str]:
241
+ """
242
+ List all active adapters.
243
+
244
+ Returns:
245
+ Dictionary mapping profile name to adapter type
246
+ """
247
+ return dict(self._profile_to_adapter_type)
248
+
249
+ def get_adapter_count(self) -> int:
250
+ """Get number of active adapters."""
251
+ return len(self._adapters)
252
+
253
+
254
+ def create_multi_adapter_manager(
255
+ unified_profiles: UnifiedProfileConfig,
256
+ mp_context: SpawnContext,
257
+ ) -> MultiAdapterManager:
258
+ """
259
+ Create MultiAdapterManager instance.
260
+
261
+ Args:
262
+ unified_profiles: Unified profile configuration
263
+ mp_context: Multiprocessing context
264
+
265
+ Returns:
266
+ MultiAdapterManager instance
267
+ """
268
+ return MultiAdapterManager(unified_profiles, mp_context)
File without changes
@@ -0,0 +1 @@
1
+ from dvt.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,116 @@
1
+ from dvt.artifacts.resources.base import BaseResource, Docs, FileHash, GraphResource
2
+ from dvt.artifacts.resources.v1.analysis import Analysis
3
+ from dvt.artifacts.resources.v1.catalog import Catalog, CatalogWriteIntegrationConfig
4
+
5
+ # alias to latest resource definitions
6
+ from dvt.artifacts.resources.v1.components import (
7
+ ColumnConfig,
8
+ ColumnInfo,
9
+ CompiledResource,
10
+ Contract,
11
+ DeferRelation,
12
+ DependsOn,
13
+ FreshnessThreshold,
14
+ HasRelationMetadata,
15
+ InjectedCTE,
16
+ NodeVersion,
17
+ ParsedResource,
18
+ ParsedResourceMandatory,
19
+ Quoting,
20
+ RefArgs,
21
+ Time,
22
+ )
23
+ from dvt.artifacts.resources.v1.config import (
24
+ Hook,
25
+ NodeAndTestConfig,
26
+ NodeConfig,
27
+ TestConfig,
28
+ list_str,
29
+ metas,
30
+ )
31
+ from dvt.artifacts.resources.v1.documentation import Documentation
32
+ from dvt.artifacts.resources.v1.exposure import (
33
+ Exposure,
34
+ ExposureConfig,
35
+ ExposureType,
36
+ MaturityType,
37
+ )
38
+ from dvt.artifacts.resources.v1.function import (
39
+ Function,
40
+ FunctionArgument,
41
+ FunctionConfig,
42
+ FunctionMandatory,
43
+ FunctionReturns,
44
+ )
45
+ from dvt.artifacts.resources.v1.generic_test import GenericTest, TestMetadata
46
+ from dvt.artifacts.resources.v1.group import Group, GroupConfig
47
+ from dvt.artifacts.resources.v1.hook import HookNode
48
+ from dvt.artifacts.resources.v1.macro import Macro, MacroArgument, MacroDependsOn
49
+ from dvt.artifacts.resources.v1.metric import (
50
+ ConstantPropertyInput,
51
+ ConversionTypeParams,
52
+ CumulativeTypeParams,
53
+ Metric,
54
+ MetricAggregationParams,
55
+ MetricConfig,
56
+ MetricInput,
57
+ MetricInputMeasure,
58
+ MetricTimeWindow,
59
+ MetricTypeParams,
60
+ )
61
+ from dvt.artifacts.resources.v1.model import (
62
+ CustomGranularity,
63
+ Model,
64
+ ModelConfig,
65
+ ModelFreshness,
66
+ TimeSpine,
67
+ )
68
+ from dvt.artifacts.resources.v1.owner import Owner
69
+ from dvt.artifacts.resources.v1.saved_query import (
70
+ Export,
71
+ ExportConfig,
72
+ QueryParams,
73
+ SavedQuery,
74
+ SavedQueryConfig,
75
+ SavedQueryMandatory,
76
+ )
77
+ from dvt.artifacts.resources.v1.seed import Seed, SeedConfig
78
+ from dvt.artifacts.resources.v1.semantic_layer_components import (
79
+ FileSlice,
80
+ MeasureAggregationParameters,
81
+ NonAdditiveDimension,
82
+ SourceFileMetadata,
83
+ WhereFilter,
84
+ WhereFilterIntersection,
85
+ )
86
+ from dvt.artifacts.resources.v1.semantic_model import (
87
+ Defaults,
88
+ Dimension,
89
+ DimensionTypeParams,
90
+ DimensionValidityParams,
91
+ Entity,
92
+ Measure,
93
+ NodeRelation,
94
+ SemanticLayerElementConfig,
95
+ SemanticModel,
96
+ SemanticModelConfig,
97
+ )
98
+ from dvt.artifacts.resources.v1.singular_test import SingularTest
99
+ from dvt.artifacts.resources.v1.snapshot import Snapshot, SnapshotConfig
100
+ from dvt.artifacts.resources.v1.source_definition import (
101
+ ExternalPartition,
102
+ ExternalTable,
103
+ ParsedSourceMandatory,
104
+ SourceConfig,
105
+ SourceDefinition,
106
+ )
107
+ from dvt.artifacts.resources.v1.sql_operation import SqlOperation
108
+ from dvt.artifacts.resources.v1.unit_test_definition import (
109
+ UnitTestConfig,
110
+ UnitTestDefinition,
111
+ UnitTestFormat,
112
+ UnitTestInputFixture,
113
+ UnitTestNodeVersions,
114
+ UnitTestOutputFixture,
115
+ UnitTestOverrides,
116
+ )
@@ -0,0 +1,68 @@
1
+ import hashlib
2
+ from dataclasses import dataclass
3
+ from typing import List, Optional
4
+
5
+ from dvt.artifacts.resources.types import NodeType
6
+
7
+ from dbt_common.dataclass_schema import dbtClassMixin
8
+
9
+
10
+ @dataclass
11
+ class BaseResource(dbtClassMixin):
12
+ name: str
13
+ resource_type: NodeType
14
+ package_name: str
15
+ path: str
16
+ original_file_path: str
17
+ unique_id: str
18
+
19
+
20
+ @dataclass
21
+ class GraphResource(BaseResource):
22
+ fqn: List[str]
23
+
24
+
25
+ @dataclass
26
+ class FileHash(dbtClassMixin):
27
+ name: str # the hash type name
28
+ checksum: str # the hashlib.hash_type().hexdigest() of the file contents
29
+
30
+ @classmethod
31
+ def empty(cls):
32
+ return FileHash(name="none", checksum="")
33
+
34
+ @classmethod
35
+ def path(cls, path: str):
36
+ return FileHash(name="path", checksum=path)
37
+
38
+ def __eq__(self, other):
39
+ if not isinstance(other, FileHash):
40
+ return NotImplemented
41
+
42
+ if self.name == "none" or self.name != other.name:
43
+ return False
44
+
45
+ return self.checksum == other.checksum
46
+
47
+ def compare(self, contents: str) -> bool:
48
+ """Compare the file contents with the given hash"""
49
+ if self.name == "none":
50
+ return False
51
+
52
+ return self.from_contents(contents, name=self.name) == self.checksum
53
+
54
+ @classmethod
55
+ def from_contents(cls, contents: str, name="sha256") -> "FileHash":
56
+ """Create a file hash from the given file contents. The hash is always
57
+ the utf-8 encoding of the contents given, because dbt only reads files
58
+ as utf-8.
59
+ """
60
+ data = contents.encode("utf-8")
61
+ checksum = hashlib.new(name, data).hexdigest()
62
+ return cls(name=name, checksum=checksum)
63
+
64
+
65
+ @dataclass
66
+ class Docs(dbtClassMixin):
67
+ show: bool = True
68
+ node_color: Optional[str] = None
@@ -0,0 +1,93 @@
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
+ Function = "function"
39
+
40
+ def pluralize(self) -> str:
41
+ if self is self.Analysis:
42
+ return "analyses"
43
+ elif self is self.SavedQuery:
44
+ return "saved_queries"
45
+ elif self is self.Test:
46
+ return "data_tests"
47
+ return f"{self}s"
48
+
49
+
50
+ class RunHookType(StrEnum):
51
+ Start = "on-run-start"
52
+ End = "on-run-end"
53
+
54
+
55
+ class ModelLanguage(StrEnum):
56
+ python = "python"
57
+ sql = "sql"
58
+
59
+
60
+ class ModelHookType(StrEnum):
61
+ PreHook = "pre-hook"
62
+ PostHook = "post-hook"
63
+
64
+
65
+ class TimePeriod(StrEnum):
66
+ minute = "minute"
67
+ hour = "hour"
68
+ day = "day"
69
+
70
+ def plural(self) -> str:
71
+ return str(self) + "s"
72
+
73
+
74
+ class BatchSize(StrEnum):
75
+ hour = "hour"
76
+ day = "day"
77
+ month = "month"
78
+ year = "year"
79
+
80
+ def plural(self) -> str:
81
+ return str(self) + "s"
82
+
83
+
84
+ class FunctionType(StrEnum):
85
+ Scalar = "scalar"
86
+ Aggregate = "aggregate"
87
+ Table = "table"
88
+
89
+
90
+ class FunctionVolatility(StrEnum):
91
+ Deterministic = "deterministic"
92
+ Stable = "stable"
93
+ NonDeterministic = "non-deterministic"
@@ -0,0 +1,10 @@
1
+ from dataclasses import dataclass
2
+ from typing import Literal
3
+
4
+ from dvt.artifacts.resources.types import NodeType
5
+ from dvt.artifacts.resources.v1.components import CompiledResource
6
+
7
+
8
+ @dataclass
9
+ class Analysis(CompiledResource):
10
+ resource_type: Literal[NodeType.Analysis]
@@ -0,0 +1,23 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Any, Dict, List, Optional
3
+
4
+ from dbt.adapters.catalogs import CatalogIntegrationConfig
5
+ from dbt_common.dataclass_schema import dbtClassMixin
6
+
7
+
8
+ @dataclass
9
+ class CatalogWriteIntegrationConfig(CatalogIntegrationConfig):
10
+ name: str
11
+ catalog_type: str
12
+ external_volume: Optional[str] = None
13
+ table_format: Optional[str] = None
14
+ catalog_name: Optional[str] = None
15
+ file_format: Optional[str] = None
16
+ adapter_properties: Dict[str, Any] = field(default_factory=dict)
17
+
18
+
19
+ @dataclass
20
+ class Catalog(dbtClassMixin):
21
+ name: str
22
+ active_write_integration: Optional[str] = None
23
+ write_integrations: List[CatalogWriteIntegrationConfig] = field(default_factory=list)