dvt-core 0.59.0a51__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.
- dbt/__init__.py +7 -0
- dbt/_pydantic_shim.py +26 -0
- dbt/artifacts/__init__.py +0 -0
- dbt/artifacts/exceptions/__init__.py +1 -0
- dbt/artifacts/exceptions/schemas.py +31 -0
- dbt/artifacts/resources/__init__.py +116 -0
- dbt/artifacts/resources/base.py +67 -0
- dbt/artifacts/resources/types.py +93 -0
- dbt/artifacts/resources/v1/analysis.py +10 -0
- dbt/artifacts/resources/v1/catalog.py +23 -0
- dbt/artifacts/resources/v1/components.py +274 -0
- dbt/artifacts/resources/v1/config.py +277 -0
- dbt/artifacts/resources/v1/documentation.py +11 -0
- dbt/artifacts/resources/v1/exposure.py +51 -0
- dbt/artifacts/resources/v1/function.py +52 -0
- dbt/artifacts/resources/v1/generic_test.py +31 -0
- dbt/artifacts/resources/v1/group.py +21 -0
- dbt/artifacts/resources/v1/hook.py +11 -0
- dbt/artifacts/resources/v1/macro.py +29 -0
- dbt/artifacts/resources/v1/metric.py +172 -0
- dbt/artifacts/resources/v1/model.py +145 -0
- dbt/artifacts/resources/v1/owner.py +10 -0
- dbt/artifacts/resources/v1/saved_query.py +111 -0
- dbt/artifacts/resources/v1/seed.py +41 -0
- dbt/artifacts/resources/v1/semantic_layer_components.py +72 -0
- dbt/artifacts/resources/v1/semantic_model.py +314 -0
- dbt/artifacts/resources/v1/singular_test.py +14 -0
- dbt/artifacts/resources/v1/snapshot.py +91 -0
- dbt/artifacts/resources/v1/source_definition.py +84 -0
- dbt/artifacts/resources/v1/sql_operation.py +10 -0
- dbt/artifacts/resources/v1/unit_test_definition.py +77 -0
- dbt/artifacts/schemas/__init__.py +0 -0
- dbt/artifacts/schemas/base.py +191 -0
- dbt/artifacts/schemas/batch_results.py +24 -0
- dbt/artifacts/schemas/catalog/__init__.py +11 -0
- dbt/artifacts/schemas/catalog/v1/__init__.py +0 -0
- dbt/artifacts/schemas/catalog/v1/catalog.py +59 -0
- dbt/artifacts/schemas/freshness/__init__.py +1 -0
- dbt/artifacts/schemas/freshness/v3/__init__.py +0 -0
- dbt/artifacts/schemas/freshness/v3/freshness.py +158 -0
- dbt/artifacts/schemas/manifest/__init__.py +2 -0
- dbt/artifacts/schemas/manifest/v12/__init__.py +0 -0
- dbt/artifacts/schemas/manifest/v12/manifest.py +211 -0
- dbt/artifacts/schemas/results.py +147 -0
- dbt/artifacts/schemas/run/__init__.py +2 -0
- dbt/artifacts/schemas/run/v5/__init__.py +0 -0
- dbt/artifacts/schemas/run/v5/run.py +184 -0
- dbt/artifacts/schemas/upgrades/__init__.py +4 -0
- dbt/artifacts/schemas/upgrades/upgrade_manifest.py +174 -0
- dbt/artifacts/schemas/upgrades/upgrade_manifest_dbt_version.py +2 -0
- dbt/artifacts/utils/validation.py +153 -0
- dbt/cli/__init__.py +1 -0
- dbt/cli/context.py +17 -0
- dbt/cli/exceptions.py +57 -0
- dbt/cli/flags.py +560 -0
- dbt/cli/main.py +2660 -0
- dbt/cli/option_types.py +121 -0
- dbt/cli/options.py +80 -0
- dbt/cli/params.py +844 -0
- dbt/cli/requires.py +490 -0
- dbt/cli/resolvers.py +60 -0
- dbt/cli/types.py +40 -0
- dbt/clients/__init__.py +0 -0
- dbt/clients/checked_load.py +83 -0
- dbt/clients/git.py +164 -0
- dbt/clients/jinja.py +206 -0
- dbt/clients/jinja_static.py +245 -0
- dbt/clients/registry.py +192 -0
- dbt/clients/yaml_helper.py +68 -0
- dbt/compilation.py +876 -0
- dbt/compute/__init__.py +14 -0
- dbt/compute/engines/__init__.py +12 -0
- dbt/compute/engines/spark_engine.py +642 -0
- dbt/compute/federated_executor.py +1080 -0
- dbt/compute/filter_pushdown.py +273 -0
- dbt/compute/jar_provisioning.py +273 -0
- dbt/compute/java_compat.py +689 -0
- dbt/compute/jdbc_utils.py +1252 -0
- dbt/compute/metadata/__init__.py +63 -0
- dbt/compute/metadata/adapters_registry.py +370 -0
- dbt/compute/metadata/catalog_store.py +1036 -0
- dbt/compute/metadata/registry.py +674 -0
- dbt/compute/metadata/store.py +1020 -0
- dbt/compute/smart_selector.py +377 -0
- dbt/compute/spark_logger.py +272 -0
- dbt/compute/strategies/__init__.py +55 -0
- dbt/compute/strategies/base.py +165 -0
- dbt/compute/strategies/dataproc.py +207 -0
- dbt/compute/strategies/emr.py +203 -0
- dbt/compute/strategies/local.py +472 -0
- dbt/compute/strategies/standalone.py +262 -0
- dbt/config/__init__.py +4 -0
- dbt/config/catalogs.py +94 -0
- dbt/config/compute.py +513 -0
- dbt/config/dvt_profile.py +408 -0
- dbt/config/profile.py +422 -0
- dbt/config/project.py +888 -0
- dbt/config/project_utils.py +48 -0
- dbt/config/renderer.py +231 -0
- dbt/config/runtime.py +564 -0
- dbt/config/selectors.py +208 -0
- dbt/config/utils.py +77 -0
- dbt/constants.py +28 -0
- dbt/context/__init__.py +0 -0
- dbt/context/base.py +745 -0
- dbt/context/configured.py +135 -0
- dbt/context/context_config.py +382 -0
- dbt/context/docs.py +82 -0
- dbt/context/exceptions_jinja.py +178 -0
- dbt/context/macro_resolver.py +195 -0
- dbt/context/macros.py +171 -0
- dbt/context/manifest.py +72 -0
- dbt/context/providers.py +2249 -0
- dbt/context/query_header.py +13 -0
- dbt/context/secret.py +58 -0
- dbt/context/target.py +74 -0
- dbt/contracts/__init__.py +0 -0
- dbt/contracts/files.py +413 -0
- dbt/contracts/graph/__init__.py +0 -0
- dbt/contracts/graph/manifest.py +1904 -0
- dbt/contracts/graph/metrics.py +97 -0
- dbt/contracts/graph/model_config.py +70 -0
- dbt/contracts/graph/node_args.py +42 -0
- dbt/contracts/graph/nodes.py +1806 -0
- dbt/contracts/graph/semantic_manifest.py +232 -0
- dbt/contracts/graph/unparsed.py +811 -0
- dbt/contracts/project.py +419 -0
- dbt/contracts/results.py +53 -0
- dbt/contracts/selection.py +23 -0
- dbt/contracts/sql.py +85 -0
- dbt/contracts/state.py +68 -0
- dbt/contracts/util.py +46 -0
- dbt/deprecations.py +348 -0
- dbt/deps/__init__.py +0 -0
- dbt/deps/base.py +152 -0
- dbt/deps/git.py +195 -0
- dbt/deps/local.py +79 -0
- dbt/deps/registry.py +130 -0
- dbt/deps/resolver.py +149 -0
- dbt/deps/tarball.py +120 -0
- dbt/docs/source/_ext/dbt_click.py +119 -0
- dbt/docs/source/conf.py +32 -0
- dbt/env_vars.py +64 -0
- dbt/event_time/event_time.py +40 -0
- dbt/event_time/sample_window.py +60 -0
- dbt/events/__init__.py +15 -0
- dbt/events/base_types.py +36 -0
- dbt/events/core_types_pb2.py +2 -0
- dbt/events/logging.py +108 -0
- dbt/events/types.py +2516 -0
- dbt/exceptions.py +1486 -0
- dbt/flags.py +89 -0
- dbt/graph/__init__.py +11 -0
- dbt/graph/cli.py +249 -0
- dbt/graph/graph.py +172 -0
- dbt/graph/queue.py +214 -0
- dbt/graph/selector.py +374 -0
- dbt/graph/selector_methods.py +975 -0
- dbt/graph/selector_spec.py +222 -0
- dbt/graph/thread_pool.py +18 -0
- dbt/hooks.py +21 -0
- dbt/include/README.md +49 -0
- dbt/include/__init__.py +3 -0
- dbt/include/data/adapters_registry.duckdb +0 -0
- dbt/include/data/build_comprehensive_registry.py +1254 -0
- dbt/include/data/build_registry.py +242 -0
- dbt/include/data/csv/adapter_queries.csv +33 -0
- dbt/include/data/csv/syntax_rules.csv +9 -0
- dbt/include/data/csv/type_mappings_bigquery.csv +28 -0
- dbt/include/data/csv/type_mappings_databricks.csv +30 -0
- dbt/include/data/csv/type_mappings_mysql.csv +40 -0
- dbt/include/data/csv/type_mappings_oracle.csv +30 -0
- dbt/include/data/csv/type_mappings_postgres.csv +56 -0
- dbt/include/data/csv/type_mappings_redshift.csv +33 -0
- dbt/include/data/csv/type_mappings_snowflake.csv +38 -0
- dbt/include/data/csv/type_mappings_sqlserver.csv +35 -0
- dbt/include/dvt_starter_project/README.md +15 -0
- dbt/include/dvt_starter_project/__init__.py +3 -0
- dbt/include/dvt_starter_project/analyses/PLACEHOLDER +0 -0
- dbt/include/dvt_starter_project/dvt_project.yml +39 -0
- dbt/include/dvt_starter_project/logs/PLACEHOLDER +0 -0
- dbt/include/dvt_starter_project/macros/PLACEHOLDER +0 -0
- dbt/include/dvt_starter_project/models/example/my_first_dbt_model.sql +27 -0
- dbt/include/dvt_starter_project/models/example/my_second_dbt_model.sql +6 -0
- dbt/include/dvt_starter_project/models/example/schema.yml +21 -0
- dbt/include/dvt_starter_project/seeds/PLACEHOLDER +0 -0
- dbt/include/dvt_starter_project/snapshots/PLACEHOLDER +0 -0
- dbt/include/dvt_starter_project/tests/PLACEHOLDER +0 -0
- dbt/internal_deprecations.py +26 -0
- dbt/jsonschemas/__init__.py +3 -0
- dbt/jsonschemas/jsonschemas.py +309 -0
- dbt/jsonschemas/project/0.0.110.json +4717 -0
- dbt/jsonschemas/project/0.0.85.json +2015 -0
- dbt/jsonschemas/resources/0.0.110.json +2636 -0
- dbt/jsonschemas/resources/0.0.85.json +2536 -0
- dbt/jsonschemas/resources/latest.json +6773 -0
- dbt/links.py +4 -0
- dbt/materializations/__init__.py +0 -0
- dbt/materializations/incremental/__init__.py +0 -0
- dbt/materializations/incremental/microbatch.py +236 -0
- dbt/mp_context.py +8 -0
- dbt/node_types.py +37 -0
- dbt/parser/__init__.py +23 -0
- dbt/parser/analysis.py +21 -0
- dbt/parser/base.py +548 -0
- dbt/parser/common.py +266 -0
- dbt/parser/docs.py +52 -0
- dbt/parser/fixtures.py +51 -0
- dbt/parser/functions.py +30 -0
- dbt/parser/generic_test.py +100 -0
- dbt/parser/generic_test_builders.py +333 -0
- dbt/parser/hooks.py +122 -0
- dbt/parser/macros.py +137 -0
- dbt/parser/manifest.py +2208 -0
- dbt/parser/models.py +573 -0
- dbt/parser/partial.py +1178 -0
- dbt/parser/read_files.py +445 -0
- dbt/parser/schema_generic_tests.py +422 -0
- dbt/parser/schema_renderer.py +111 -0
- dbt/parser/schema_yaml_readers.py +935 -0
- dbt/parser/schemas.py +1466 -0
- dbt/parser/search.py +149 -0
- dbt/parser/seeds.py +28 -0
- dbt/parser/singular_test.py +20 -0
- dbt/parser/snapshots.py +44 -0
- dbt/parser/sources.py +558 -0
- dbt/parser/sql.py +62 -0
- dbt/parser/unit_tests.py +621 -0
- dbt/plugins/__init__.py +20 -0
- dbt/plugins/contracts.py +9 -0
- dbt/plugins/exceptions.py +2 -0
- dbt/plugins/manager.py +163 -0
- dbt/plugins/manifest.py +21 -0
- dbt/profiler.py +20 -0
- dbt/py.typed +1 -0
- dbt/query_analyzer.py +410 -0
- dbt/runners/__init__.py +2 -0
- dbt/runners/exposure_runner.py +7 -0
- dbt/runners/no_op_runner.py +45 -0
- dbt/runners/saved_query_runner.py +7 -0
- dbt/selected_resources.py +8 -0
- dbt/task/__init__.py +0 -0
- dbt/task/base.py +506 -0
- dbt/task/build.py +197 -0
- dbt/task/clean.py +56 -0
- dbt/task/clone.py +161 -0
- dbt/task/compile.py +150 -0
- dbt/task/compute.py +458 -0
- dbt/task/debug.py +513 -0
- dbt/task/deps.py +280 -0
- dbt/task/docs/__init__.py +3 -0
- dbt/task/docs/api/__init__.py +23 -0
- dbt/task/docs/api/catalog.py +204 -0
- dbt/task/docs/api/lineage.py +234 -0
- dbt/task/docs/api/profile.py +204 -0
- dbt/task/docs/api/spark.py +186 -0
- dbt/task/docs/generate.py +1002 -0
- dbt/task/docs/index.html +250 -0
- dbt/task/docs/serve.py +174 -0
- dbt/task/dvt_output.py +509 -0
- dbt/task/dvt_run.py +282 -0
- dbt/task/dvt_seed.py +806 -0
- dbt/task/freshness.py +322 -0
- dbt/task/function.py +121 -0
- dbt/task/group_lookup.py +46 -0
- dbt/task/init.py +1022 -0
- dbt/task/java.py +316 -0
- dbt/task/list.py +236 -0
- dbt/task/metadata.py +804 -0
- dbt/task/migrate.py +714 -0
- dbt/task/printer.py +175 -0
- dbt/task/profile.py +1489 -0
- dbt/task/profile_serve.py +662 -0
- dbt/task/retract.py +441 -0
- dbt/task/retry.py +175 -0
- dbt/task/run.py +1647 -0
- dbt/task/run_operation.py +141 -0
- dbt/task/runnable.py +758 -0
- dbt/task/seed.py +103 -0
- dbt/task/show.py +149 -0
- dbt/task/snapshot.py +56 -0
- dbt/task/spark.py +414 -0
- dbt/task/sql.py +110 -0
- dbt/task/target_sync.py +814 -0
- dbt/task/test.py +464 -0
- dbt/tests/fixtures/__init__.py +1 -0
- dbt/tests/fixtures/project.py +620 -0
- dbt/tests/util.py +651 -0
- dbt/tracking.py +529 -0
- dbt/utils/__init__.py +3 -0
- dbt/utils/artifact_upload.py +151 -0
- dbt/utils/utils.py +408 -0
- dbt/version.py +271 -0
- dvt_cli/__init__.py +158 -0
- dvt_core-0.59.0a51.dist-info/METADATA +288 -0
- dvt_core-0.59.0a51.dist-info/RECORD +299 -0
- dvt_core-0.59.0a51.dist-info/WHEEL +5 -0
- dvt_core-0.59.0a51.dist-info/entry_points.txt +2 -0
- dvt_core-0.59.0a51.dist-info/top_level.txt +2 -0
dbt/config/runtime.py
ADDED
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
import itertools
|
|
2
|
+
import os
|
|
3
|
+
from copy import deepcopy
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import (
|
|
7
|
+
Any,
|
|
8
|
+
Dict,
|
|
9
|
+
Iterable,
|
|
10
|
+
Iterator,
|
|
11
|
+
Mapping,
|
|
12
|
+
MutableSet,
|
|
13
|
+
Optional,
|
|
14
|
+
Tuple,
|
|
15
|
+
Type,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from dbt import tracking
|
|
19
|
+
from dbt.adapters.contracts.connection import (
|
|
20
|
+
AdapterRequiredConfig,
|
|
21
|
+
Credentials,
|
|
22
|
+
HasCredentials,
|
|
23
|
+
)
|
|
24
|
+
from dbt.adapters.contracts.relation import ComponentName
|
|
25
|
+
from dbt.adapters.factory import get_include_paths, get_relation_class_by_name
|
|
26
|
+
from dbt.artifacts.resources import Quoting
|
|
27
|
+
from dbt.config.project import load_raw_project
|
|
28
|
+
from dbt.contracts.graph.manifest import ManifestMetadata
|
|
29
|
+
from dbt.contracts.project import Configuration
|
|
30
|
+
from dbt.events.types import UnusedResourceConfigPath
|
|
31
|
+
from dbt.exceptions import (
|
|
32
|
+
ConfigContractBrokenError,
|
|
33
|
+
DbtProjectError,
|
|
34
|
+
DbtRuntimeError,
|
|
35
|
+
NonUniquePackageNameError,
|
|
36
|
+
UninstalledPackagesFoundError,
|
|
37
|
+
)
|
|
38
|
+
from dbt.flags import get_flags
|
|
39
|
+
from dbt_common.dataclass_schema import ValidationError
|
|
40
|
+
from dbt_common.events.functions import warn_or_error
|
|
41
|
+
from dbt_common.helper_types import DictDefaultEmptyStr, FQNPath, PathSet
|
|
42
|
+
|
|
43
|
+
from .profile import Profile
|
|
44
|
+
from .dvt_profile import DVTProfile # DVT: Multi-connection support
|
|
45
|
+
from .project import Project
|
|
46
|
+
from .renderer import DbtProjectYamlRenderer, ProfileRenderer
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# Called by RuntimeConfig.collect_parts class method
|
|
50
|
+
def load_project(
|
|
51
|
+
project_root: str,
|
|
52
|
+
version_check: bool,
|
|
53
|
+
profile: HasCredentials,
|
|
54
|
+
cli_vars: Optional[Dict[str, Any]] = None,
|
|
55
|
+
validate: bool = False,
|
|
56
|
+
) -> Project:
|
|
57
|
+
# get the project with all of the provided information
|
|
58
|
+
project_renderer = DbtProjectYamlRenderer(profile, cli_vars)
|
|
59
|
+
project = Project.from_project_root(
|
|
60
|
+
project_root, project_renderer, verify_version=version_check, validate=validate
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
# Save env_vars encountered in rendering for partial parsing
|
|
64
|
+
project.project_env_vars = project_renderer.ctx_obj.env_vars
|
|
65
|
+
return project
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def load_profile(
|
|
69
|
+
project_root: str,
|
|
70
|
+
cli_vars: Dict[str, Any],
|
|
71
|
+
profile_name_override: Optional[str] = None,
|
|
72
|
+
target_override: Optional[str] = None,
|
|
73
|
+
threads_override: Optional[int] = None,
|
|
74
|
+
) -> DVTProfile: # DVT: Return DVTProfile instead of Profile
|
|
75
|
+
raw_project = load_raw_project(project_root)
|
|
76
|
+
raw_profile_name = raw_project.get("profile")
|
|
77
|
+
profile_renderer = ProfileRenderer(cli_vars)
|
|
78
|
+
profile_name = profile_renderer.render_value(raw_profile_name)
|
|
79
|
+
# DVT: Use DVTProfile.render instead of Profile.render
|
|
80
|
+
profile = DVTProfile.render(
|
|
81
|
+
profile_renderer, profile_name, profile_name_override, target_override, threads_override
|
|
82
|
+
)
|
|
83
|
+
# Save env_vars encountered in rendering for partial parsing
|
|
84
|
+
profile.profile_env_vars = profile_renderer.ctx_obj.env_vars
|
|
85
|
+
return profile
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _project_quoting_dict(proj: Project, profile: Profile) -> Dict[ComponentName, bool]:
|
|
89
|
+
src: Dict[str, Any] = profile.credentials.translate_aliases(proj.quoting)
|
|
90
|
+
result: Dict[ComponentName, bool] = {}
|
|
91
|
+
for key in ComponentName:
|
|
92
|
+
if key in src:
|
|
93
|
+
value = src[key]
|
|
94
|
+
if isinstance(value, bool):
|
|
95
|
+
result[key] = value
|
|
96
|
+
return result
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@dataclass
|
|
100
|
+
class RuntimeConfig(Project, Profile, AdapterRequiredConfig):
|
|
101
|
+
args: Any
|
|
102
|
+
profile_name: str
|
|
103
|
+
cli_vars: Dict[str, Any]
|
|
104
|
+
dependencies: Optional[Mapping[str, "RuntimeConfig"]] = None
|
|
105
|
+
# DVT: Add adapter registry for multi-connection support
|
|
106
|
+
adapters: Optional[Dict[str, Any]] = None # Dict[connection_name, BaseAdapter]
|
|
107
|
+
outputs: Optional[Dict[str, Any]] = None # Multi-connection outputs from DVTProfile
|
|
108
|
+
|
|
109
|
+
def __post_init__(self):
|
|
110
|
+
self.validate()
|
|
111
|
+
# DVT: Eagerly register all adapters from outputs
|
|
112
|
+
if hasattr(self, 'outputs') and self.outputs:
|
|
113
|
+
self.adapters = {}
|
|
114
|
+
# Register all adapters up-front for federated execution
|
|
115
|
+
for connection_name in self.outputs.keys():
|
|
116
|
+
try:
|
|
117
|
+
self._register_connection_adapter(connection_name)
|
|
118
|
+
except Exception:
|
|
119
|
+
# Adapter registration can fail (missing dependencies, etc.)
|
|
120
|
+
# We'll handle errors when adapter is actually used
|
|
121
|
+
pass
|
|
122
|
+
|
|
123
|
+
def _register_connection_adapter(self, connection_name: str):
|
|
124
|
+
"""Lazily register and return adapter for a specific connection."""
|
|
125
|
+
from dbt.adapters.factory import get_adapter, register_adapter
|
|
126
|
+
from dbt.mp_context import get_mp_context
|
|
127
|
+
from copy import copy
|
|
128
|
+
from argparse import Namespace
|
|
129
|
+
|
|
130
|
+
if connection_name not in self.outputs:
|
|
131
|
+
raise DbtRuntimeError(
|
|
132
|
+
f"Connection '{connection_name}' not found in outputs. "
|
|
133
|
+
f"Available: {list(self.outputs.keys())}"
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
credentials = self.outputs[connection_name]
|
|
137
|
+
|
|
138
|
+
# Create a config proxy that inherits from this RuntimeConfig
|
|
139
|
+
# but uses different credentials
|
|
140
|
+
config_proxy = copy(self)
|
|
141
|
+
config_proxy.credentials = credentials
|
|
142
|
+
config_proxy.target_name = connection_name
|
|
143
|
+
|
|
144
|
+
# DVT v0.59.0: For non-default connections, we need to clear the CLI TARGET
|
|
145
|
+
# override so that macro contexts use the correct adapter for this connection.
|
|
146
|
+
# Without this, _select_adapter_for_node always returns the CLI --target adapter.
|
|
147
|
+
if hasattr(self, 'args') and hasattr(self.args, 'TARGET') and self.args.TARGET:
|
|
148
|
+
if self.args.TARGET != connection_name:
|
|
149
|
+
# Create a copy of args with TARGET set to this connection
|
|
150
|
+
args_copy = Namespace(**vars(self.args))
|
|
151
|
+
args_copy.TARGET = connection_name
|
|
152
|
+
config_proxy.args = args_copy
|
|
153
|
+
|
|
154
|
+
# Register and get adapter for this connection
|
|
155
|
+
register_adapter(config_proxy, get_mp_context())
|
|
156
|
+
adapter = get_adapter(config_proxy)
|
|
157
|
+
self.adapters[connection_name] = adapter
|
|
158
|
+
return adapter
|
|
159
|
+
|
|
160
|
+
def get_adapter(self, connection_name: Optional[str] = None):
|
|
161
|
+
"""Get adapter for a specific connection (with lazy initialization)."""
|
|
162
|
+
if not connection_name:
|
|
163
|
+
# Return default adapter
|
|
164
|
+
from dbt.adapters.factory import get_adapter
|
|
165
|
+
return get_adapter(self)
|
|
166
|
+
|
|
167
|
+
# Check if we have outputs (multi-connection mode)
|
|
168
|
+
if self.outputs and connection_name in self.outputs:
|
|
169
|
+
# Check if adapter already registered
|
|
170
|
+
if self.adapters and connection_name in self.adapters:
|
|
171
|
+
return self.adapters[connection_name]
|
|
172
|
+
else:
|
|
173
|
+
# Lazily register the adapter
|
|
174
|
+
return self._register_connection_adapter(connection_name)
|
|
175
|
+
|
|
176
|
+
# Fallback to default
|
|
177
|
+
from dbt.adapters.factory import get_adapter
|
|
178
|
+
return get_adapter(self)
|
|
179
|
+
|
|
180
|
+
@classmethod
|
|
181
|
+
def get_profile(
|
|
182
|
+
cls,
|
|
183
|
+
project_root: str,
|
|
184
|
+
cli_vars: Dict[str, Any],
|
|
185
|
+
args: Any,
|
|
186
|
+
) -> Profile:
|
|
187
|
+
return load_profile(
|
|
188
|
+
project_root,
|
|
189
|
+
cli_vars,
|
|
190
|
+
args.profile,
|
|
191
|
+
args.target,
|
|
192
|
+
args.threads,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
# Called by 'new_project' and 'from_args'
|
|
196
|
+
@classmethod
|
|
197
|
+
def from_parts(
|
|
198
|
+
cls,
|
|
199
|
+
project: Project,
|
|
200
|
+
profile: Profile,
|
|
201
|
+
args: Any,
|
|
202
|
+
dependencies: Optional[Mapping[str, "RuntimeConfig"]] = None,
|
|
203
|
+
) -> "RuntimeConfig":
|
|
204
|
+
"""Instantiate a RuntimeConfig from its components.
|
|
205
|
+
|
|
206
|
+
:param profile: A parsed dbt Profile.
|
|
207
|
+
:param project: A parsed dbt Project.
|
|
208
|
+
:param args: The parsed command-line arguments.
|
|
209
|
+
:returns RuntimeConfig: The new configuration.
|
|
210
|
+
"""
|
|
211
|
+
quoting: Dict[str, Any] = (
|
|
212
|
+
get_relation_class_by_name(profile.credentials.type)
|
|
213
|
+
.get_default_quote_policy()
|
|
214
|
+
.replace_dict(_project_quoting_dict(project, profile))
|
|
215
|
+
).to_dict(omit_none=True)
|
|
216
|
+
|
|
217
|
+
cli_vars: Dict[str, Any] = getattr(args, "vars", {})
|
|
218
|
+
log_cache_events: bool = getattr(args, "log_cache_events", profile.log_cache_events)
|
|
219
|
+
|
|
220
|
+
return cls(
|
|
221
|
+
project_name=project.project_name,
|
|
222
|
+
version=project.version,
|
|
223
|
+
project_root=project.project_root,
|
|
224
|
+
model_paths=project.model_paths,
|
|
225
|
+
macro_paths=project.macro_paths,
|
|
226
|
+
seed_paths=project.seed_paths,
|
|
227
|
+
test_paths=project.test_paths,
|
|
228
|
+
analysis_paths=project.analysis_paths,
|
|
229
|
+
docs_paths=project.docs_paths,
|
|
230
|
+
asset_paths=project.asset_paths,
|
|
231
|
+
function_paths=project.function_paths,
|
|
232
|
+
target_path=project.target_path,
|
|
233
|
+
snapshot_paths=project.snapshot_paths,
|
|
234
|
+
clean_targets=project.clean_targets,
|
|
235
|
+
log_path=project.log_path,
|
|
236
|
+
packages_install_path=project.packages_install_path,
|
|
237
|
+
packages_specified_path=project.packages_specified_path,
|
|
238
|
+
quoting=quoting,
|
|
239
|
+
models=project.models,
|
|
240
|
+
on_run_start=project.on_run_start,
|
|
241
|
+
on_run_end=project.on_run_end,
|
|
242
|
+
dispatch=project.dispatch,
|
|
243
|
+
seeds=project.seeds,
|
|
244
|
+
snapshots=project.snapshots,
|
|
245
|
+
dbt_version=project.dbt_version,
|
|
246
|
+
packages=project.packages,
|
|
247
|
+
manifest_selectors=project.manifest_selectors,
|
|
248
|
+
selectors=project.selectors,
|
|
249
|
+
query_comment=project.query_comment,
|
|
250
|
+
sources=project.sources,
|
|
251
|
+
data_tests=project.data_tests,
|
|
252
|
+
unit_tests=project.unit_tests,
|
|
253
|
+
metrics=project.metrics,
|
|
254
|
+
semantic_models=project.semantic_models,
|
|
255
|
+
saved_queries=project.saved_queries,
|
|
256
|
+
exposures=project.exposures,
|
|
257
|
+
functions=project.functions,
|
|
258
|
+
vars=project.vars,
|
|
259
|
+
config_version=project.config_version,
|
|
260
|
+
unrendered=project.unrendered,
|
|
261
|
+
project_env_vars=project.project_env_vars,
|
|
262
|
+
restrict_access=project.restrict_access,
|
|
263
|
+
profile_env_vars=profile.profile_env_vars,
|
|
264
|
+
profile_name=profile.profile_name,
|
|
265
|
+
target_name=profile.target_name,
|
|
266
|
+
threads=profile.threads,
|
|
267
|
+
credentials=profile.credentials,
|
|
268
|
+
args=args,
|
|
269
|
+
cli_vars=cli_vars,
|
|
270
|
+
log_cache_events=log_cache_events,
|
|
271
|
+
dependencies=dependencies,
|
|
272
|
+
dbt_cloud=project.dbt_cloud,
|
|
273
|
+
flags=project.flags,
|
|
274
|
+
outputs=getattr(profile, 'outputs', None), # DVT: Pass multi-connection outputs
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
# Called by 'load_projects' in this class
|
|
278
|
+
def new_project(self, project_root: str) -> "RuntimeConfig":
|
|
279
|
+
"""Given a new project root, read in its project dictionary, supply the
|
|
280
|
+
existing project's profile info, and create a new project file.
|
|
281
|
+
|
|
282
|
+
:param project_root: A filepath to a dbt project.
|
|
283
|
+
:raises DbtProfileError: If the profile is invalid.
|
|
284
|
+
:raises DbtProjectError: If project is missing or invalid.
|
|
285
|
+
:returns: The new configuration.
|
|
286
|
+
"""
|
|
287
|
+
# copy profile
|
|
288
|
+
profile = Profile(**self.to_profile_info())
|
|
289
|
+
profile.validate()
|
|
290
|
+
|
|
291
|
+
# load the new project and its packages. Don't pass cli variables.
|
|
292
|
+
renderer = DbtProjectYamlRenderer(profile)
|
|
293
|
+
project = Project.from_project_root(
|
|
294
|
+
project_root,
|
|
295
|
+
renderer,
|
|
296
|
+
verify_version=bool(getattr(self.args, "VERSION_CHECK", True)),
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
runtime_config = self.from_parts(
|
|
300
|
+
project=project,
|
|
301
|
+
profile=profile,
|
|
302
|
+
args=deepcopy(self.args),
|
|
303
|
+
)
|
|
304
|
+
# force our quoting back onto the new project.
|
|
305
|
+
runtime_config.quoting = deepcopy(self.quoting)
|
|
306
|
+
return runtime_config
|
|
307
|
+
|
|
308
|
+
def serialize(self) -> Dict[str, Any]:
|
|
309
|
+
"""Serialize the full configuration to a single dictionary. For any
|
|
310
|
+
instance that has passed validate() (which happens in __init__), it
|
|
311
|
+
matches the Configuration contract.
|
|
312
|
+
|
|
313
|
+
Note that args are not serialized.
|
|
314
|
+
|
|
315
|
+
:returns dict: The serialized configuration.
|
|
316
|
+
"""
|
|
317
|
+
result = self.to_project_config(with_packages=True)
|
|
318
|
+
result.update(self.to_profile_info(serialize_credentials=True))
|
|
319
|
+
result["cli_vars"] = deepcopy(self.cli_vars)
|
|
320
|
+
return result
|
|
321
|
+
|
|
322
|
+
def validate(self):
|
|
323
|
+
"""Validate the configuration against its contract.
|
|
324
|
+
|
|
325
|
+
:raises DbtProjectError: If the configuration fails validation.
|
|
326
|
+
"""
|
|
327
|
+
try:
|
|
328
|
+
Configuration.validate(self.serialize())
|
|
329
|
+
except ValidationError as e:
|
|
330
|
+
raise ConfigContractBrokenError(e) from e
|
|
331
|
+
|
|
332
|
+
# Called by RuntimeConfig.from_args
|
|
333
|
+
@classmethod
|
|
334
|
+
def collect_parts(cls: Type["RuntimeConfig"], args: Any) -> Tuple[Project, Profile]:
|
|
335
|
+
# profile_name from the project
|
|
336
|
+
project_root = args.project_dir if args.project_dir else os.getcwd()
|
|
337
|
+
cli_vars: Dict[str, Any] = getattr(args, "vars", {})
|
|
338
|
+
profile = cls.get_profile(
|
|
339
|
+
project_root,
|
|
340
|
+
cli_vars,
|
|
341
|
+
args,
|
|
342
|
+
)
|
|
343
|
+
flags = get_flags()
|
|
344
|
+
project = load_project(project_root, bool(flags.VERSION_CHECK), profile, cli_vars)
|
|
345
|
+
return project, profile
|
|
346
|
+
|
|
347
|
+
# Called in task/base.py, in BaseTask.from_args
|
|
348
|
+
@classmethod
|
|
349
|
+
def from_args(cls, args: Any) -> "RuntimeConfig":
|
|
350
|
+
"""Given arguments, read in dbt_project.yml from the current directory,
|
|
351
|
+
read in packages.yml if it exists, and use them to find the profile to
|
|
352
|
+
load.
|
|
353
|
+
|
|
354
|
+
:param args: The arguments as parsed from the cli.
|
|
355
|
+
:raises DbtProjectError: If the project is invalid or missing.
|
|
356
|
+
:raises DbtProfileError: If the profile is invalid or missing.
|
|
357
|
+
:raises DbtValidationError: If the cli variables are invalid.
|
|
358
|
+
"""
|
|
359
|
+
project, profile = cls.collect_parts(args)
|
|
360
|
+
|
|
361
|
+
return cls.from_parts(
|
|
362
|
+
project=project,
|
|
363
|
+
profile=profile,
|
|
364
|
+
args=args,
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
def get_metadata(self) -> ManifestMetadata:
|
|
368
|
+
return ManifestMetadata(
|
|
369
|
+
project_name=self.project_name,
|
|
370
|
+
project_id=self.hashed_name(),
|
|
371
|
+
user_id=tracking.active_user.id if tracking.active_user else None,
|
|
372
|
+
send_anonymous_usage_stats=(
|
|
373
|
+
get_flags().SEND_ANONYMOUS_USAGE_STATS if tracking.active_user else None
|
|
374
|
+
),
|
|
375
|
+
adapter_type=self.credentials.type,
|
|
376
|
+
quoting=Quoting(
|
|
377
|
+
database=self.quoting.get("database", None),
|
|
378
|
+
schema=self.quoting.get("schema", None),
|
|
379
|
+
identifier=self.quoting.get("identifier", None),
|
|
380
|
+
column=self.quoting.get("column", None),
|
|
381
|
+
),
|
|
382
|
+
run_started_at=(
|
|
383
|
+
tracking.active_user.run_started_at if tracking.active_user is not None else None
|
|
384
|
+
),
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
def _get_v2_config_paths(
|
|
388
|
+
self,
|
|
389
|
+
config,
|
|
390
|
+
path: FQNPath,
|
|
391
|
+
paths: MutableSet[FQNPath],
|
|
392
|
+
) -> PathSet:
|
|
393
|
+
for key, value in config.items():
|
|
394
|
+
if isinstance(value, dict) and not key.startswith("+"):
|
|
395
|
+
self._get_config_paths(value, path + (key,), paths)
|
|
396
|
+
else:
|
|
397
|
+
paths.add(path)
|
|
398
|
+
return frozenset(paths)
|
|
399
|
+
|
|
400
|
+
def _get_config_paths(
|
|
401
|
+
self,
|
|
402
|
+
config: Dict[str, Any],
|
|
403
|
+
path: FQNPath = (),
|
|
404
|
+
paths: Optional[MutableSet[FQNPath]] = None,
|
|
405
|
+
) -> PathSet:
|
|
406
|
+
if paths is None:
|
|
407
|
+
paths = set()
|
|
408
|
+
|
|
409
|
+
for key, value in config.items():
|
|
410
|
+
if isinstance(value, dict) and not key.startswith("+"):
|
|
411
|
+
self._get_v2_config_paths(value, path + (key,), paths)
|
|
412
|
+
else:
|
|
413
|
+
paths.add(path)
|
|
414
|
+
return frozenset(paths)
|
|
415
|
+
|
|
416
|
+
def get_resource_config_paths(self) -> Dict[str, PathSet]:
|
|
417
|
+
"""Return a dictionary with resource type keys whose values are
|
|
418
|
+
lists of lists of strings, where each inner list of strings represents
|
|
419
|
+
a configured path in the resource.
|
|
420
|
+
"""
|
|
421
|
+
return {
|
|
422
|
+
"models": self._get_config_paths(self.models),
|
|
423
|
+
"seeds": self._get_config_paths(self.seeds),
|
|
424
|
+
"snapshots": self._get_config_paths(self.snapshots),
|
|
425
|
+
"sources": self._get_config_paths(self.sources),
|
|
426
|
+
"data_tests": self._get_config_paths(self.data_tests),
|
|
427
|
+
"unit_tests": self._get_config_paths(self.unit_tests),
|
|
428
|
+
"metrics": self._get_config_paths(self.metrics),
|
|
429
|
+
"semantic_models": self._get_config_paths(self.semantic_models),
|
|
430
|
+
"saved_queries": self._get_config_paths(self.saved_queries),
|
|
431
|
+
"exposures": self._get_config_paths(self.exposures),
|
|
432
|
+
"functions": self._get_config_paths(self.functions),
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
def warn_for_unused_resource_config_paths(
|
|
436
|
+
self,
|
|
437
|
+
resource_fqns: Mapping[str, PathSet],
|
|
438
|
+
disabled: PathSet,
|
|
439
|
+
) -> None:
|
|
440
|
+
"""Return a list of lists of strings, where each inner list of strings
|
|
441
|
+
represents a type + FQN path of a resource configuration that is not
|
|
442
|
+
used.
|
|
443
|
+
"""
|
|
444
|
+
disabled_fqns = frozenset(tuple(fqn) for fqn in disabled)
|
|
445
|
+
resource_config_paths = self.get_resource_config_paths()
|
|
446
|
+
unused_resource_config_paths = []
|
|
447
|
+
for resource_type, config_paths in resource_config_paths.items():
|
|
448
|
+
used_fqns = resource_fqns.get(resource_type, frozenset())
|
|
449
|
+
fqns = used_fqns | disabled_fqns
|
|
450
|
+
|
|
451
|
+
for config_path in config_paths:
|
|
452
|
+
if not _is_config_used(config_path, fqns):
|
|
453
|
+
resource_path = ".".join(i for i in ((resource_type,) + config_path))
|
|
454
|
+
unused_resource_config_paths.append(resource_path)
|
|
455
|
+
|
|
456
|
+
if len(unused_resource_config_paths) == 0:
|
|
457
|
+
return
|
|
458
|
+
|
|
459
|
+
warn_or_error(UnusedResourceConfigPath(unused_config_paths=unused_resource_config_paths))
|
|
460
|
+
|
|
461
|
+
def load_dependencies(self, base_only=False) -> Mapping[str, "RuntimeConfig"]:
|
|
462
|
+
if self.dependencies is None:
|
|
463
|
+
all_projects = {self.project_name: self}
|
|
464
|
+
internal_packages = get_include_paths(self.credentials.type)
|
|
465
|
+
if base_only:
|
|
466
|
+
# Test setup -- we want to load macros without dependencies
|
|
467
|
+
project_paths = itertools.chain(internal_packages)
|
|
468
|
+
else:
|
|
469
|
+
# raise exception if fewer installed packages than in packages.yml
|
|
470
|
+
count_packages_specified = len(self.packages.packages) # type: ignore
|
|
471
|
+
count_packages_installed = len(tuple(self._get_project_directories()))
|
|
472
|
+
if count_packages_specified > count_packages_installed:
|
|
473
|
+
raise UninstalledPackagesFoundError(
|
|
474
|
+
count_packages_specified,
|
|
475
|
+
count_packages_installed,
|
|
476
|
+
self.packages_specified_path,
|
|
477
|
+
self.packages_install_path,
|
|
478
|
+
)
|
|
479
|
+
project_paths = itertools.chain(internal_packages, self._get_project_directories())
|
|
480
|
+
for project_name, project in self.load_projects(project_paths):
|
|
481
|
+
if project_name in all_projects:
|
|
482
|
+
raise NonUniquePackageNameError(project_name)
|
|
483
|
+
all_projects[project_name] = project
|
|
484
|
+
self.dependencies = all_projects
|
|
485
|
+
return self.dependencies
|
|
486
|
+
|
|
487
|
+
def clear_dependencies(self):
|
|
488
|
+
self.dependencies = None
|
|
489
|
+
|
|
490
|
+
# Called by 'load_dependencies' in this class
|
|
491
|
+
def load_projects(self, paths: Iterable[Path]) -> Iterator[Tuple[str, "RuntimeConfig"]]:
|
|
492
|
+
for path in paths:
|
|
493
|
+
try:
|
|
494
|
+
project = self.new_project(str(path))
|
|
495
|
+
except DbtProjectError as e:
|
|
496
|
+
raise DbtProjectError(
|
|
497
|
+
f"Failed to read package: {e}",
|
|
498
|
+
result_type="invalid_project",
|
|
499
|
+
path=path,
|
|
500
|
+
) from e
|
|
501
|
+
else:
|
|
502
|
+
yield project.project_name, project
|
|
503
|
+
|
|
504
|
+
def _get_project_directories(self) -> Iterator[Path]:
|
|
505
|
+
root = Path(self.project_root) / self.packages_install_path
|
|
506
|
+
|
|
507
|
+
if root.exists():
|
|
508
|
+
for path in root.iterdir():
|
|
509
|
+
if path.is_dir() and not path.name.startswith("__"):
|
|
510
|
+
yield path
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
class UnsetCredentials(Credentials):
|
|
514
|
+
def __init__(self) -> None:
|
|
515
|
+
super().__init__("", "")
|
|
516
|
+
|
|
517
|
+
@property
|
|
518
|
+
def type(self):
|
|
519
|
+
return None
|
|
520
|
+
|
|
521
|
+
@property
|
|
522
|
+
def unique_field(self):
|
|
523
|
+
return None
|
|
524
|
+
|
|
525
|
+
def connection_info(self, *args, **kwargs):
|
|
526
|
+
return {}
|
|
527
|
+
|
|
528
|
+
def _connection_keys(self):
|
|
529
|
+
return ()
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
# This is used by commands which do not require
|
|
533
|
+
# a profile, i.e. dbt deps and clean
|
|
534
|
+
class UnsetProfile(Profile):
|
|
535
|
+
def __init__(self):
|
|
536
|
+
self.credentials = UnsetCredentials()
|
|
537
|
+
self.profile_name = ""
|
|
538
|
+
self.target_name = ""
|
|
539
|
+
self.threads = -1
|
|
540
|
+
|
|
541
|
+
def to_target_dict(self):
|
|
542
|
+
return DictDefaultEmptyStr({})
|
|
543
|
+
|
|
544
|
+
def __getattribute__(self, name):
|
|
545
|
+
if name in {"profile_name", "target_name", "threads"}:
|
|
546
|
+
raise DbtRuntimeError(f'Error: disallowed attribute "{name}" - no profile!')
|
|
547
|
+
|
|
548
|
+
return Profile.__getattribute__(self, name)
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
UNUSED_RESOURCE_CONFIGURATION_PATH_MESSAGE = """\
|
|
552
|
+
Configuration paths exist in your dvt_project.yml file which do not \
|
|
553
|
+
apply to any resources.
|
|
554
|
+
There are {} unused configuration paths:
|
|
555
|
+
{}
|
|
556
|
+
"""
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
def _is_config_used(path, fqns):
|
|
560
|
+
if fqns:
|
|
561
|
+
for fqn in fqns:
|
|
562
|
+
if len(path) <= len(fqn) and fqn[: len(path)] == path:
|
|
563
|
+
return True
|
|
564
|
+
return False
|