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/task/deps.py
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from hashlib import sha1
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any, Dict, List, Optional
|
|
5
|
+
|
|
6
|
+
import yaml
|
|
7
|
+
|
|
8
|
+
import dbt.deprecations
|
|
9
|
+
import dbt.exceptions
|
|
10
|
+
import dbt.utils
|
|
11
|
+
from dbt.config import Project
|
|
12
|
+
from dbt.config.project import load_yml_dict, package_config_from_data
|
|
13
|
+
from dbt.config.renderer import PackageRenderer
|
|
14
|
+
from dbt.constants import PACKAGE_LOCK_FILE_NAME, PACKAGE_LOCK_HASH_KEY
|
|
15
|
+
from dbt.contracts.project import PackageSpec
|
|
16
|
+
from dbt.deps.base import downloads_directory
|
|
17
|
+
from dbt.deps.registry import RegistryPinnedPackage
|
|
18
|
+
from dbt.deps.resolver import resolve_lock_packages, resolve_packages
|
|
19
|
+
from dbt.events.types import (
|
|
20
|
+
DepsAddPackage,
|
|
21
|
+
DepsFoundDuplicatePackage,
|
|
22
|
+
DepsInstallInfo,
|
|
23
|
+
DepsListSubdirectory,
|
|
24
|
+
DepsLockUpdating,
|
|
25
|
+
DepsNoPackagesFound,
|
|
26
|
+
DepsNotifyUpdatesAvailable,
|
|
27
|
+
DepsStartPackageInstall,
|
|
28
|
+
DepsUpdateAvailable,
|
|
29
|
+
DepsUpToDate,
|
|
30
|
+
)
|
|
31
|
+
from dbt.task.base import BaseTask, move_to_nearest_project_dir
|
|
32
|
+
from dbt_common.clients import system
|
|
33
|
+
from dbt_common.events.functions import fire_event
|
|
34
|
+
from dbt_common.events.types import Formatting
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class dbtPackageDumper(yaml.Dumper):
|
|
38
|
+
def increase_indent(self, flow=False, indentless=False):
|
|
39
|
+
return super(dbtPackageDumper, self).increase_indent(flow, False)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _create_sha1_hash(packages: List[PackageSpec]) -> str:
|
|
43
|
+
"""Create a SHA1 hash of the packages list,
|
|
44
|
+
this is used to determine if the packages for current execution matches
|
|
45
|
+
the previous lock.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
list[Packages]: list of packages specified that are already rendered
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
str: SHA1 hash of the packages list
|
|
52
|
+
"""
|
|
53
|
+
package_strs = [json.dumps(package.to_dict(), sort_keys=True) for package in packages]
|
|
54
|
+
package_strs = sorted(package_strs)
|
|
55
|
+
|
|
56
|
+
return sha1("\n".join(package_strs).encode("utf-8")).hexdigest()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _create_packages_yml_entry(package: str, version: Optional[str], source: str) -> dict:
|
|
60
|
+
"""Create a formatted entry to add to `packages.yml` or `package-lock.yml` file
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
package (str): Name of package to download
|
|
64
|
+
version (str): Version of package to download
|
|
65
|
+
source (str): Source of where to download package from
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
dict: Formatted dict to write to `packages.yml` or `package-lock.yml` file
|
|
69
|
+
"""
|
|
70
|
+
package_key = source
|
|
71
|
+
version_key = "version"
|
|
72
|
+
|
|
73
|
+
if source == "hub":
|
|
74
|
+
package_key = "package"
|
|
75
|
+
|
|
76
|
+
packages_yml_entry = {package_key: package}
|
|
77
|
+
|
|
78
|
+
if source == "git":
|
|
79
|
+
version_key = "revision"
|
|
80
|
+
|
|
81
|
+
if version:
|
|
82
|
+
if "," in version:
|
|
83
|
+
version = version.split(",") # type: ignore
|
|
84
|
+
|
|
85
|
+
packages_yml_entry[version_key] = version
|
|
86
|
+
|
|
87
|
+
return packages_yml_entry
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class DepsTask(BaseTask):
|
|
91
|
+
def __init__(self, args: Any, project: Project) -> None:
|
|
92
|
+
super().__init__(args=args)
|
|
93
|
+
# N.B. This is a temporary fix for a bug when using relative paths via
|
|
94
|
+
# --project-dir with deps. A larger overhaul of our path handling methods
|
|
95
|
+
# is needed to fix this the "right" way.
|
|
96
|
+
# See GH-7615
|
|
97
|
+
project.project_root = str(Path(project.project_root).resolve())
|
|
98
|
+
self.project = project
|
|
99
|
+
self.cli_vars = args.vars
|
|
100
|
+
|
|
101
|
+
def track_package_install(
|
|
102
|
+
self, package_name: str, source_type: str, version: Optional[str]
|
|
103
|
+
) -> None:
|
|
104
|
+
# Hub packages do not need to be hashed, as they are public
|
|
105
|
+
if source_type == "local":
|
|
106
|
+
package_name = dbt.utils.md5(package_name)
|
|
107
|
+
version = "local"
|
|
108
|
+
elif source_type == "tarball":
|
|
109
|
+
package_name = dbt.utils.md5(package_name)
|
|
110
|
+
version = "tarball"
|
|
111
|
+
elif source_type != "hub":
|
|
112
|
+
package_name = dbt.utils.md5(package_name)
|
|
113
|
+
version = dbt.utils.md5(version)
|
|
114
|
+
|
|
115
|
+
dbt.tracking.track_package_install(
|
|
116
|
+
"deps",
|
|
117
|
+
self.project.hashed_name(),
|
|
118
|
+
{"name": package_name, "source": source_type, "version": version},
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
def check_for_duplicate_packages(self, packages_yml):
|
|
122
|
+
"""Loop through contents of `packages.yml` to ensure no duplicate package names + versions.
|
|
123
|
+
|
|
124
|
+
This duplicate check will take into consideration exact match of a package name, as well as
|
|
125
|
+
a check to see if a package name exists within a name (i.e. a package name inside a git URL).
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
packages_yml (dict): In-memory read of `packages.yml` contents
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
dict: Updated or untouched packages_yml contents
|
|
132
|
+
"""
|
|
133
|
+
for i, pkg_entry in enumerate(packages_yml["packages"]):
|
|
134
|
+
for val in pkg_entry.values():
|
|
135
|
+
if self.args.add_package["name"] in val:
|
|
136
|
+
del packages_yml["packages"][i]
|
|
137
|
+
|
|
138
|
+
fire_event(DepsFoundDuplicatePackage(removed_package=pkg_entry))
|
|
139
|
+
|
|
140
|
+
return packages_yml
|
|
141
|
+
|
|
142
|
+
def add(self):
|
|
143
|
+
packages_yml_filepath = (
|
|
144
|
+
f"{self.project.project_root}/{self.project.packages_specified_path}"
|
|
145
|
+
)
|
|
146
|
+
if not system.path_exists(packages_yml_filepath):
|
|
147
|
+
with open(packages_yml_filepath, "w") as package_yml:
|
|
148
|
+
yaml.safe_dump({"packages": []}, package_yml)
|
|
149
|
+
fire_event(Formatting("Created packages.yml"))
|
|
150
|
+
|
|
151
|
+
new_package_entry = _create_packages_yml_entry(
|
|
152
|
+
self.args.add_package["name"], self.args.add_package["version"], self.args.source
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
with open(packages_yml_filepath, "r") as user_yml_obj:
|
|
156
|
+
packages_yml = yaml.safe_load(user_yml_obj)
|
|
157
|
+
packages_yml = self.check_for_duplicate_packages(packages_yml)
|
|
158
|
+
packages_yml["packages"].append(new_package_entry)
|
|
159
|
+
|
|
160
|
+
self.project.packages.packages = package_config_from_data(packages_yml).packages
|
|
161
|
+
|
|
162
|
+
if packages_yml:
|
|
163
|
+
with open(packages_yml_filepath, "w") as pkg_obj:
|
|
164
|
+
pkg_obj.write(
|
|
165
|
+
yaml.dump(packages_yml, Dumper=dbtPackageDumper, default_flow_style=False)
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
fire_event(
|
|
169
|
+
DepsAddPackage(
|
|
170
|
+
package_name=self.args.add_package["name"],
|
|
171
|
+
version=self.args.add_package["version"],
|
|
172
|
+
packages_filepath=packages_yml_filepath,
|
|
173
|
+
)
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
def lock(self) -> None:
|
|
177
|
+
lock_filepath = f"{self.project.project_root}/{PACKAGE_LOCK_FILE_NAME}"
|
|
178
|
+
|
|
179
|
+
packages = self.project.packages.packages
|
|
180
|
+
packages_installed: Dict[str, Any] = {"packages": []}
|
|
181
|
+
|
|
182
|
+
if not packages:
|
|
183
|
+
fire_event(DepsNoPackagesFound())
|
|
184
|
+
return
|
|
185
|
+
|
|
186
|
+
with downloads_directory():
|
|
187
|
+
resolved_deps = resolve_packages(packages, self.project, self.cli_vars)
|
|
188
|
+
|
|
189
|
+
# this loop is to create the package-lock.yml in the same format as original packages.yml
|
|
190
|
+
# package-lock.yml includes both the stated packages in packages.yml along with dependent packages
|
|
191
|
+
renderer = PackageRenderer(self.cli_vars)
|
|
192
|
+
for package in resolved_deps:
|
|
193
|
+
package_dict = package.to_dict()
|
|
194
|
+
package_dict["name"] = package.get_project_name(self.project, renderer)
|
|
195
|
+
packages_installed["packages"].append(package_dict)
|
|
196
|
+
|
|
197
|
+
packages_installed[PACKAGE_LOCK_HASH_KEY] = _create_sha1_hash(
|
|
198
|
+
self.project.packages.packages
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
with open(lock_filepath, "w") as lock_obj:
|
|
202
|
+
yaml.dump(packages_installed, lock_obj, Dumper=dbtPackageDumper)
|
|
203
|
+
|
|
204
|
+
fire_event(DepsLockUpdating(lock_filepath=lock_filepath))
|
|
205
|
+
|
|
206
|
+
def run(self) -> None:
|
|
207
|
+
move_to_nearest_project_dir(self.args.project_dir)
|
|
208
|
+
if self.args.add_package:
|
|
209
|
+
self.add()
|
|
210
|
+
|
|
211
|
+
# Check lock file exist and generated by the same packages.yml
|
|
212
|
+
# or dependencies.yml.
|
|
213
|
+
lock_file_path = f"{self.project.project_root}/{PACKAGE_LOCK_FILE_NAME}"
|
|
214
|
+
if not system.path_exists(lock_file_path):
|
|
215
|
+
self.lock()
|
|
216
|
+
elif self.args.upgrade:
|
|
217
|
+
self.lock()
|
|
218
|
+
else:
|
|
219
|
+
# Check dependency definition is modified or not.
|
|
220
|
+
current_hash = _create_sha1_hash(self.project.packages.packages)
|
|
221
|
+
previous_hash = load_yml_dict(lock_file_path).get(PACKAGE_LOCK_HASH_KEY, None)
|
|
222
|
+
if previous_hash != current_hash:
|
|
223
|
+
self.lock()
|
|
224
|
+
|
|
225
|
+
# Early return when 'dbt deps --lock'
|
|
226
|
+
# Just resolve packages and write lock file, don't actually install packages
|
|
227
|
+
if self.args.lock:
|
|
228
|
+
return
|
|
229
|
+
|
|
230
|
+
if system.path_exists(self.project.packages_install_path):
|
|
231
|
+
system.rmtree(self.project.packages_install_path)
|
|
232
|
+
|
|
233
|
+
system.make_directory(self.project.packages_install_path)
|
|
234
|
+
|
|
235
|
+
packages_lock_dict = load_yml_dict(f"{self.project.project_root}/{PACKAGE_LOCK_FILE_NAME}")
|
|
236
|
+
|
|
237
|
+
renderer = PackageRenderer(self.cli_vars)
|
|
238
|
+
packages_lock_config = package_config_from_data(
|
|
239
|
+
renderer.render_data(packages_lock_dict), packages_lock_dict
|
|
240
|
+
).packages
|
|
241
|
+
|
|
242
|
+
if not packages_lock_config:
|
|
243
|
+
fire_event(DepsNoPackagesFound())
|
|
244
|
+
return
|
|
245
|
+
|
|
246
|
+
with downloads_directory():
|
|
247
|
+
lock_defined_deps = resolve_lock_packages(packages_lock_config)
|
|
248
|
+
renderer = PackageRenderer(self.cli_vars)
|
|
249
|
+
|
|
250
|
+
packages_to_upgrade = []
|
|
251
|
+
|
|
252
|
+
for package in lock_defined_deps:
|
|
253
|
+
package_name = package.name
|
|
254
|
+
source_type = package.source_type()
|
|
255
|
+
version = package.get_version()
|
|
256
|
+
|
|
257
|
+
fire_event(DepsStartPackageInstall(package_name=package_name))
|
|
258
|
+
package.install(self.project, renderer)
|
|
259
|
+
|
|
260
|
+
fire_event(DepsInstallInfo(version_name=package.nice_version_name()))
|
|
261
|
+
|
|
262
|
+
if isinstance(package, RegistryPinnedPackage):
|
|
263
|
+
version_latest = package.get_version_latest()
|
|
264
|
+
|
|
265
|
+
if version_latest != version:
|
|
266
|
+
packages_to_upgrade.append(package_name)
|
|
267
|
+
fire_event(DepsUpdateAvailable(version_latest=version_latest))
|
|
268
|
+
else:
|
|
269
|
+
fire_event(DepsUpToDate())
|
|
270
|
+
|
|
271
|
+
if package.get_subdirectory():
|
|
272
|
+
fire_event(DepsListSubdirectory(subdirectory=package.get_subdirectory()))
|
|
273
|
+
|
|
274
|
+
self.track_package_install(
|
|
275
|
+
package_name=package_name, source_type=source_type, version=version
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
if packages_to_upgrade:
|
|
279
|
+
fire_event(Formatting(""))
|
|
280
|
+
fire_event(DepsNotifyUpdatesAvailable(packages=packages_to_upgrade))
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DVT Docs Serve API
|
|
3
|
+
|
|
4
|
+
v0.56.0: FastAPI routers for enhanced docs serve with 3-tab web UI.
|
|
5
|
+
|
|
6
|
+
Endpoints:
|
|
7
|
+
- /api/catalog/* - Catalog nodes and search
|
|
8
|
+
- /api/profile/* - Profile results and alerts
|
|
9
|
+
- /api/lineage/* - Lineage graph and traversal
|
|
10
|
+
- /api/spark/* - Spark status (local only)
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from dbt.task.docs.api.catalog import router as catalog_router
|
|
14
|
+
from dbt.task.docs.api.profile import router as profile_router
|
|
15
|
+
from dbt.task.docs.api.lineage import router as lineage_router
|
|
16
|
+
from dbt.task.docs.api.spark import router as spark_router
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"catalog_router",
|
|
20
|
+
"profile_router",
|
|
21
|
+
"lineage_router",
|
|
22
|
+
"spark_router",
|
|
23
|
+
]
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DVT Docs Serve - Catalog API
|
|
3
|
+
|
|
4
|
+
v0.56.0: Catalog nodes, search, and node details.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any, Dict, List, Optional
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
from fastapi import APIRouter, HTTPException, Query
|
|
12
|
+
except ImportError:
|
|
13
|
+
# Provide stub for when FastAPI is not installed
|
|
14
|
+
class APIRouter:
|
|
15
|
+
def __init__(self, *args, **kwargs):
|
|
16
|
+
pass
|
|
17
|
+
def get(self, *args, **kwargs):
|
|
18
|
+
def decorator(func):
|
|
19
|
+
return func
|
|
20
|
+
return decorator
|
|
21
|
+
class HTTPException(Exception):
|
|
22
|
+
def __init__(self, status_code, detail):
|
|
23
|
+
self.status_code = status_code
|
|
24
|
+
self.detail = detail
|
|
25
|
+
def Query(*args, **kwargs):
|
|
26
|
+
return None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
router = APIRouter(prefix="/api/catalog", tags=["catalog"])
|
|
30
|
+
|
|
31
|
+
# Will be set by serve.py
|
|
32
|
+
_project_root: Optional[Path] = None
|
|
33
|
+
_store_initialized: bool = False
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def set_project_root(project_root: Path) -> None:
|
|
37
|
+
"""Set project root for API access."""
|
|
38
|
+
global _project_root, _store_initialized
|
|
39
|
+
_project_root = project_root
|
|
40
|
+
_store_initialized = True # Assume serve.py already initialized
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _get_store():
|
|
44
|
+
"""Get metadata store instance (lazy initialization)."""
|
|
45
|
+
global _store_initialized
|
|
46
|
+
|
|
47
|
+
if _project_root is None:
|
|
48
|
+
raise HTTPException(status_code=500, detail="Project root not configured")
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
from dbt.compute.metadata import ProjectMetadataStore
|
|
52
|
+
store = ProjectMetadataStore(_project_root)
|
|
53
|
+
# Only initialize if not already done by serve.py
|
|
54
|
+
if not _store_initialized:
|
|
55
|
+
store.initialize()
|
|
56
|
+
_store_initialized = True
|
|
57
|
+
return store
|
|
58
|
+
except Exception as e:
|
|
59
|
+
raise HTTPException(status_code=500, detail=f"Could not open metadata store: {e}")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@router.get("/nodes")
|
|
63
|
+
async def list_catalog_nodes(
|
|
64
|
+
resource_type: Optional[str] = Query(None, description="Filter by type: model, source, test, seed, snapshot"),
|
|
65
|
+
) -> List[Dict[str, Any]]:
|
|
66
|
+
"""
|
|
67
|
+
List all catalog nodes.
|
|
68
|
+
|
|
69
|
+
Returns all nodes from the catalog, optionally filtered by resource type.
|
|
70
|
+
"""
|
|
71
|
+
store = _get_store()
|
|
72
|
+
|
|
73
|
+
try:
|
|
74
|
+
if resource_type:
|
|
75
|
+
nodes = store.get_catalog_nodes_by_type(resource_type)
|
|
76
|
+
else:
|
|
77
|
+
nodes = store.get_all_catalog_nodes()
|
|
78
|
+
|
|
79
|
+
return [
|
|
80
|
+
{
|
|
81
|
+
"unique_id": n.unique_id,
|
|
82
|
+
"resource_type": n.resource_type,
|
|
83
|
+
"name": n.name,
|
|
84
|
+
"schema": n.schema_name,
|
|
85
|
+
"database": n.database,
|
|
86
|
+
"connection": n.connection_name,
|
|
87
|
+
"adapter": n.adapter_type,
|
|
88
|
+
"description": n.description,
|
|
89
|
+
"icon": n.icon_type,
|
|
90
|
+
"color": n.color_hex,
|
|
91
|
+
"materialized": n.materialized,
|
|
92
|
+
"row_count": n.row_count,
|
|
93
|
+
}
|
|
94
|
+
for n in nodes
|
|
95
|
+
]
|
|
96
|
+
finally:
|
|
97
|
+
store.close()
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@router.get("/nodes/{unique_id}")
|
|
101
|
+
async def get_catalog_node(unique_id: str) -> Dict[str, Any]:
|
|
102
|
+
"""
|
|
103
|
+
Get a specific catalog node by unique ID.
|
|
104
|
+
|
|
105
|
+
Returns full node details including columns.
|
|
106
|
+
"""
|
|
107
|
+
import json
|
|
108
|
+
|
|
109
|
+
store = _get_store()
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
node = store.get_catalog_node(unique_id)
|
|
113
|
+
if not node:
|
|
114
|
+
raise HTTPException(status_code=404, detail=f"Node not found: {unique_id}")
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
"unique_id": node.unique_id,
|
|
118
|
+
"resource_type": node.resource_type,
|
|
119
|
+
"name": node.name,
|
|
120
|
+
"schema": node.schema_name,
|
|
121
|
+
"database": node.database,
|
|
122
|
+
"connection": node.connection_name,
|
|
123
|
+
"adapter": node.adapter_type,
|
|
124
|
+
"description": node.description,
|
|
125
|
+
"icon": node.icon_type,
|
|
126
|
+
"color": node.color_hex,
|
|
127
|
+
"materialized": node.materialized,
|
|
128
|
+
"tags": json.loads(node.tags) if node.tags else [],
|
|
129
|
+
"meta": json.loads(node.meta) if node.meta else {},
|
|
130
|
+
"columns": json.loads(node.columns) if node.columns else [],
|
|
131
|
+
"row_count": node.row_count,
|
|
132
|
+
"bytes_stored": node.bytes_stored,
|
|
133
|
+
"created_at": node.created_at.isoformat() if node.created_at else None,
|
|
134
|
+
"updated_at": node.updated_at.isoformat() if node.updated_at else None,
|
|
135
|
+
}
|
|
136
|
+
finally:
|
|
137
|
+
store.close()
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
@router.get("/search")
|
|
141
|
+
async def search_catalog(
|
|
142
|
+
q: str = Query(..., description="Search query"),
|
|
143
|
+
) -> List[Dict[str, Any]]:
|
|
144
|
+
"""
|
|
145
|
+
Search catalog nodes by name or description.
|
|
146
|
+
|
|
147
|
+
Returns matching nodes sorted by relevance.
|
|
148
|
+
"""
|
|
149
|
+
if not q or len(q) < 2:
|
|
150
|
+
raise HTTPException(status_code=400, detail="Query must be at least 2 characters")
|
|
151
|
+
|
|
152
|
+
store = _get_store()
|
|
153
|
+
|
|
154
|
+
try:
|
|
155
|
+
nodes = store.search_catalog_nodes(q)
|
|
156
|
+
return [
|
|
157
|
+
{
|
|
158
|
+
"unique_id": n.unique_id,
|
|
159
|
+
"resource_type": n.resource_type,
|
|
160
|
+
"name": n.name,
|
|
161
|
+
"schema": n.schema_name,
|
|
162
|
+
"connection": n.connection_name,
|
|
163
|
+
"description": n.description,
|
|
164
|
+
"icon": n.icon_type,
|
|
165
|
+
"color": n.color_hex,
|
|
166
|
+
}
|
|
167
|
+
for n in nodes
|
|
168
|
+
]
|
|
169
|
+
finally:
|
|
170
|
+
store.close()
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@router.get("/stats")
|
|
174
|
+
async def get_catalog_stats() -> Dict[str, Any]:
|
|
175
|
+
"""
|
|
176
|
+
Get catalog statistics.
|
|
177
|
+
|
|
178
|
+
Returns counts of nodes by type, connections, etc.
|
|
179
|
+
"""
|
|
180
|
+
store = _get_store()
|
|
181
|
+
|
|
182
|
+
try:
|
|
183
|
+
all_nodes = store.get_all_catalog_nodes()
|
|
184
|
+
|
|
185
|
+
# Count by type
|
|
186
|
+
type_counts: Dict[str, int] = {}
|
|
187
|
+
connection_counts: Dict[str, int] = {}
|
|
188
|
+
adapter_counts: Dict[str, int] = {}
|
|
189
|
+
|
|
190
|
+
for node in all_nodes:
|
|
191
|
+
type_counts[node.resource_type] = type_counts.get(node.resource_type, 0) + 1
|
|
192
|
+
if node.connection_name:
|
|
193
|
+
connection_counts[node.connection_name] = connection_counts.get(node.connection_name, 0) + 1
|
|
194
|
+
if node.adapter_type:
|
|
195
|
+
adapter_counts[node.adapter_type] = adapter_counts.get(node.adapter_type, 0) + 1
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
"total_nodes": len(all_nodes),
|
|
199
|
+
"by_type": type_counts,
|
|
200
|
+
"by_connection": connection_counts,
|
|
201
|
+
"by_adapter": adapter_counts,
|
|
202
|
+
}
|
|
203
|
+
finally:
|
|
204
|
+
store.close()
|