dvt-core 1.11.0b4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of dvt-core might be problematic. Click here for more details.
- dvt/__init__.py +7 -0
- dvt/_pydantic_shim.py +26 -0
- dvt/adapters/__init__.py +16 -0
- dvt/adapters/multi_adapter_manager.py +268 -0
- dvt/artifacts/__init__.py +0 -0
- dvt/artifacts/exceptions/__init__.py +1 -0
- dvt/artifacts/exceptions/schemas.py +31 -0
- dvt/artifacts/resources/__init__.py +116 -0
- dvt/artifacts/resources/base.py +68 -0
- dvt/artifacts/resources/types.py +93 -0
- dvt/artifacts/resources/v1/analysis.py +10 -0
- dvt/artifacts/resources/v1/catalog.py +23 -0
- dvt/artifacts/resources/v1/components.py +275 -0
- dvt/artifacts/resources/v1/config.py +282 -0
- dvt/artifacts/resources/v1/documentation.py +11 -0
- dvt/artifacts/resources/v1/exposure.py +52 -0
- dvt/artifacts/resources/v1/function.py +53 -0
- dvt/artifacts/resources/v1/generic_test.py +32 -0
- dvt/artifacts/resources/v1/group.py +22 -0
- dvt/artifacts/resources/v1/hook.py +11 -0
- dvt/artifacts/resources/v1/macro.py +30 -0
- dvt/artifacts/resources/v1/metric.py +173 -0
- dvt/artifacts/resources/v1/model.py +146 -0
- dvt/artifacts/resources/v1/owner.py +10 -0
- dvt/artifacts/resources/v1/saved_query.py +112 -0
- dvt/artifacts/resources/v1/seed.py +42 -0
- dvt/artifacts/resources/v1/semantic_layer_components.py +72 -0
- dvt/artifacts/resources/v1/semantic_model.py +315 -0
- dvt/artifacts/resources/v1/singular_test.py +14 -0
- dvt/artifacts/resources/v1/snapshot.py +92 -0
- dvt/artifacts/resources/v1/source_definition.py +85 -0
- dvt/artifacts/resources/v1/sql_operation.py +10 -0
- dvt/artifacts/resources/v1/unit_test_definition.py +78 -0
- dvt/artifacts/schemas/__init__.py +0 -0
- dvt/artifacts/schemas/base.py +191 -0
- dvt/artifacts/schemas/batch_results.py +24 -0
- dvt/artifacts/schemas/catalog/__init__.py +12 -0
- dvt/artifacts/schemas/catalog/v1/__init__.py +0 -0
- dvt/artifacts/schemas/catalog/v1/catalog.py +60 -0
- dvt/artifacts/schemas/freshness/__init__.py +1 -0
- dvt/artifacts/schemas/freshness/v3/__init__.py +0 -0
- dvt/artifacts/schemas/freshness/v3/freshness.py +159 -0
- dvt/artifacts/schemas/manifest/__init__.py +2 -0
- dvt/artifacts/schemas/manifest/v12/__init__.py +0 -0
- dvt/artifacts/schemas/manifest/v12/manifest.py +212 -0
- dvt/artifacts/schemas/results.py +148 -0
- dvt/artifacts/schemas/run/__init__.py +2 -0
- dvt/artifacts/schemas/run/v5/__init__.py +0 -0
- dvt/artifacts/schemas/run/v5/run.py +184 -0
- dvt/artifacts/schemas/upgrades/__init__.py +4 -0
- dvt/artifacts/schemas/upgrades/upgrade_manifest.py +174 -0
- dvt/artifacts/schemas/upgrades/upgrade_manifest_dbt_version.py +2 -0
- dvt/artifacts/utils/validation.py +153 -0
- dvt/cli/__init__.py +1 -0
- dvt/cli/context.py +16 -0
- dvt/cli/exceptions.py +56 -0
- dvt/cli/flags.py +558 -0
- dvt/cli/main.py +971 -0
- dvt/cli/option_types.py +121 -0
- dvt/cli/options.py +79 -0
- dvt/cli/params.py +803 -0
- dvt/cli/requires.py +478 -0
- dvt/cli/resolvers.py +32 -0
- dvt/cli/types.py +40 -0
- dvt/clients/__init__.py +0 -0
- dvt/clients/checked_load.py +82 -0
- dvt/clients/git.py +164 -0
- dvt/clients/jinja.py +206 -0
- dvt/clients/jinja_static.py +245 -0
- dvt/clients/registry.py +192 -0
- dvt/clients/yaml_helper.py +68 -0
- dvt/compilation.py +833 -0
- dvt/compute/__init__.py +26 -0
- dvt/compute/base.py +288 -0
- dvt/compute/engines/__init__.py +13 -0
- dvt/compute/engines/duckdb_engine.py +368 -0
- dvt/compute/engines/spark_engine.py +273 -0
- dvt/compute/query_analyzer.py +212 -0
- dvt/compute/router.py +483 -0
- dvt/config/__init__.py +4 -0
- dvt/config/catalogs.py +95 -0
- dvt/config/compute_config.py +406 -0
- dvt/config/profile.py +411 -0
- dvt/config/profiles_v2.py +464 -0
- dvt/config/project.py +893 -0
- dvt/config/renderer.py +232 -0
- dvt/config/runtime.py +491 -0
- dvt/config/selectors.py +209 -0
- dvt/config/utils.py +78 -0
- dvt/connectors/.gitignore +6 -0
- dvt/connectors/README.md +306 -0
- dvt/connectors/catalog.yml +217 -0
- dvt/connectors/download_connectors.py +300 -0
- dvt/constants.py +29 -0
- dvt/context/__init__.py +0 -0
- dvt/context/base.py +746 -0
- dvt/context/configured.py +136 -0
- dvt/context/context_config.py +350 -0
- dvt/context/docs.py +82 -0
- dvt/context/exceptions_jinja.py +179 -0
- dvt/context/macro_resolver.py +195 -0
- dvt/context/macros.py +171 -0
- dvt/context/manifest.py +73 -0
- dvt/context/providers.py +2198 -0
- dvt/context/query_header.py +14 -0
- dvt/context/secret.py +59 -0
- dvt/context/target.py +74 -0
- dvt/contracts/__init__.py +0 -0
- dvt/contracts/files.py +413 -0
- dvt/contracts/graph/__init__.py +0 -0
- dvt/contracts/graph/manifest.py +1904 -0
- dvt/contracts/graph/metrics.py +98 -0
- dvt/contracts/graph/model_config.py +71 -0
- dvt/contracts/graph/node_args.py +42 -0
- dvt/contracts/graph/nodes.py +1806 -0
- dvt/contracts/graph/semantic_manifest.py +233 -0
- dvt/contracts/graph/unparsed.py +812 -0
- dvt/contracts/project.py +417 -0
- dvt/contracts/results.py +53 -0
- dvt/contracts/selection.py +23 -0
- dvt/contracts/sql.py +86 -0
- dvt/contracts/state.py +69 -0
- dvt/contracts/util.py +46 -0
- dvt/deprecations.py +347 -0
- dvt/deps/__init__.py +0 -0
- dvt/deps/base.py +153 -0
- dvt/deps/git.py +196 -0
- dvt/deps/local.py +80 -0
- dvt/deps/registry.py +131 -0
- dvt/deps/resolver.py +149 -0
- dvt/deps/tarball.py +121 -0
- dvt/docs/source/_ext/dbt_click.py +118 -0
- dvt/docs/source/conf.py +32 -0
- dvt/env_vars.py +64 -0
- dvt/event_time/event_time.py +40 -0
- dvt/event_time/sample_window.py +60 -0
- dvt/events/__init__.py +16 -0
- dvt/events/base_types.py +37 -0
- dvt/events/core_types_pb2.py +2 -0
- dvt/events/logging.py +109 -0
- dvt/events/types.py +2534 -0
- dvt/exceptions.py +1487 -0
- dvt/flags.py +89 -0
- dvt/graph/__init__.py +11 -0
- dvt/graph/cli.py +248 -0
- dvt/graph/graph.py +172 -0
- dvt/graph/queue.py +213 -0
- dvt/graph/selector.py +375 -0
- dvt/graph/selector_methods.py +976 -0
- dvt/graph/selector_spec.py +223 -0
- dvt/graph/thread_pool.py +18 -0
- dvt/hooks.py +21 -0
- dvt/include/README.md +49 -0
- dvt/include/__init__.py +3 -0
- dvt/include/global_project.py +4 -0
- dvt/include/starter_project/.gitignore +4 -0
- dvt/include/starter_project/README.md +15 -0
- dvt/include/starter_project/__init__.py +3 -0
- dvt/include/starter_project/analyses/.gitkeep +0 -0
- dvt/include/starter_project/dvt_project.yml +36 -0
- dvt/include/starter_project/macros/.gitkeep +0 -0
- dvt/include/starter_project/models/example/my_first_dbt_model.sql +27 -0
- dvt/include/starter_project/models/example/my_second_dbt_model.sql +6 -0
- dvt/include/starter_project/models/example/schema.yml +21 -0
- dvt/include/starter_project/seeds/.gitkeep +0 -0
- dvt/include/starter_project/snapshots/.gitkeep +0 -0
- dvt/include/starter_project/tests/.gitkeep +0 -0
- dvt/internal_deprecations.py +27 -0
- dvt/jsonschemas/__init__.py +3 -0
- dvt/jsonschemas/jsonschemas.py +309 -0
- dvt/jsonschemas/project/0.0.110.json +4717 -0
- dvt/jsonschemas/project/0.0.85.json +2015 -0
- dvt/jsonschemas/resources/0.0.110.json +2636 -0
- dvt/jsonschemas/resources/0.0.85.json +2536 -0
- dvt/jsonschemas/resources/latest.json +6773 -0
- dvt/links.py +4 -0
- dvt/materializations/__init__.py +0 -0
- dvt/materializations/incremental/__init__.py +0 -0
- dvt/materializations/incremental/microbatch.py +235 -0
- dvt/mp_context.py +8 -0
- dvt/node_types.py +37 -0
- dvt/parser/__init__.py +23 -0
- dvt/parser/analysis.py +21 -0
- dvt/parser/base.py +549 -0
- dvt/parser/common.py +267 -0
- dvt/parser/docs.py +52 -0
- dvt/parser/fixtures.py +51 -0
- dvt/parser/functions.py +30 -0
- dvt/parser/generic_test.py +100 -0
- dvt/parser/generic_test_builders.py +334 -0
- dvt/parser/hooks.py +119 -0
- dvt/parser/macros.py +137 -0
- dvt/parser/manifest.py +2204 -0
- dvt/parser/models.py +574 -0
- dvt/parser/partial.py +1179 -0
- dvt/parser/read_files.py +445 -0
- dvt/parser/schema_generic_tests.py +423 -0
- dvt/parser/schema_renderer.py +111 -0
- dvt/parser/schema_yaml_readers.py +936 -0
- dvt/parser/schemas.py +1467 -0
- dvt/parser/search.py +149 -0
- dvt/parser/seeds.py +28 -0
- dvt/parser/singular_test.py +20 -0
- dvt/parser/snapshots.py +44 -0
- dvt/parser/sources.py +557 -0
- dvt/parser/sql.py +63 -0
- dvt/parser/unit_tests.py +622 -0
- dvt/plugins/__init__.py +20 -0
- dvt/plugins/contracts.py +10 -0
- dvt/plugins/exceptions.py +2 -0
- dvt/plugins/manager.py +164 -0
- dvt/plugins/manifest.py +21 -0
- dvt/profiler.py +20 -0
- dvt/py.typed +1 -0
- dvt/runners/__init__.py +2 -0
- dvt/runners/exposure_runner.py +7 -0
- dvt/runners/no_op_runner.py +46 -0
- dvt/runners/saved_query_runner.py +7 -0
- dvt/selected_resources.py +8 -0
- dvt/task/__init__.py +0 -0
- dvt/task/base.py +504 -0
- dvt/task/build.py +197 -0
- dvt/task/clean.py +57 -0
- dvt/task/clone.py +162 -0
- dvt/task/compile.py +151 -0
- dvt/task/compute.py +366 -0
- dvt/task/debug.py +650 -0
- dvt/task/deps.py +280 -0
- dvt/task/docs/__init__.py +3 -0
- dvt/task/docs/generate.py +408 -0
- dvt/task/docs/index.html +250 -0
- dvt/task/docs/serve.py +28 -0
- dvt/task/freshness.py +323 -0
- dvt/task/function.py +122 -0
- dvt/task/group_lookup.py +46 -0
- dvt/task/init.py +374 -0
- dvt/task/list.py +237 -0
- dvt/task/printer.py +176 -0
- dvt/task/profiles.py +256 -0
- dvt/task/retry.py +175 -0
- dvt/task/run.py +1146 -0
- dvt/task/run_operation.py +142 -0
- dvt/task/runnable.py +802 -0
- dvt/task/seed.py +104 -0
- dvt/task/show.py +150 -0
- dvt/task/snapshot.py +57 -0
- dvt/task/sql.py +111 -0
- dvt/task/test.py +464 -0
- dvt/tests/fixtures/__init__.py +1 -0
- dvt/tests/fixtures/project.py +620 -0
- dvt/tests/util.py +651 -0
- dvt/tracking.py +529 -0
- dvt/utils/__init__.py +3 -0
- dvt/utils/artifact_upload.py +151 -0
- dvt/utils/utils.py +408 -0
- dvt/version.py +249 -0
- dvt_core-1.11.0b4.dist-info/METADATA +252 -0
- dvt_core-1.11.0b4.dist-info/RECORD +261 -0
- dvt_core-1.11.0b4.dist-info/WHEEL +5 -0
- dvt_core-1.11.0b4.dist-info/entry_points.txt +2 -0
- dvt_core-1.11.0b4.dist-info/top_level.txt +1 -0
dvt/clients/registry.py
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import os
|
|
3
|
+
from typing import Any, Dict, List, Optional
|
|
4
|
+
|
|
5
|
+
import requests
|
|
6
|
+
from dvt import deprecations
|
|
7
|
+
from dvt.events.types import (
|
|
8
|
+
RegistryIndexProgressGETRequest,
|
|
9
|
+
RegistryIndexProgressGETResponse,
|
|
10
|
+
RegistryProgressGETRequest,
|
|
11
|
+
RegistryProgressGETResponse,
|
|
12
|
+
RegistryResponseExtraNestedKeys,
|
|
13
|
+
RegistryResponseMissingNestedKeys,
|
|
14
|
+
RegistryResponseMissingTopKeys,
|
|
15
|
+
RegistryResponseUnexpectedType,
|
|
16
|
+
)
|
|
17
|
+
from dvt.utils import memoized
|
|
18
|
+
|
|
19
|
+
from dbt_common import semver
|
|
20
|
+
from dbt_common.events.functions import fire_event
|
|
21
|
+
from dbt_common.utils.connection import connection_exception_retry
|
|
22
|
+
|
|
23
|
+
if os.getenv("DBT_PACKAGE_HUB_URL"):
|
|
24
|
+
DEFAULT_REGISTRY_BASE_URL = os.getenv("DBT_PACKAGE_HUB_URL")
|
|
25
|
+
else:
|
|
26
|
+
DEFAULT_REGISTRY_BASE_URL = "https://hub.getdbt.com/"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _get_url(name, registry_base_url=None):
|
|
30
|
+
if registry_base_url is None:
|
|
31
|
+
registry_base_url = DEFAULT_REGISTRY_BASE_URL
|
|
32
|
+
url = "api/v1/{}.json".format(name)
|
|
33
|
+
|
|
34
|
+
return "{}{}".format(registry_base_url, url)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _check_package_redirect(package_name: str, response: Dict[str, Any]) -> None:
|
|
38
|
+
# Either redirectnamespace or redirectname in the JSON response indicate a redirect
|
|
39
|
+
# redirectnamespace redirects based on package ownership
|
|
40
|
+
# redirectname redirects based on package name
|
|
41
|
+
# Both can be present at the same time, or neither. Fails gracefully to old name
|
|
42
|
+
if ("redirectnamespace" in response) or ("redirectname" in response):
|
|
43
|
+
use_namespace = response.get("redirectnamespace") or response["namespace"]
|
|
44
|
+
use_name = response.get("redirectname") or response["name"]
|
|
45
|
+
|
|
46
|
+
new_nwo = f"{use_namespace}/{use_name}"
|
|
47
|
+
deprecations.warn("package-redirect", old_name=package_name, new_name=new_nwo)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _get_package_with_retries(
|
|
51
|
+
package_name: str, registry_base_url: Optional[str] = None
|
|
52
|
+
) -> Dict[str, Any]:
|
|
53
|
+
get_fn = functools.partial(_get, package_name, registry_base_url)
|
|
54
|
+
response: Dict[str, Any] = connection_exception_retry(get_fn, 5)
|
|
55
|
+
_check_package_redirect(package_name, response)
|
|
56
|
+
return response
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _get(package_name, registry_base_url=None):
|
|
60
|
+
url = _get_url(package_name, registry_base_url)
|
|
61
|
+
fire_event(RegistryProgressGETRequest(url=url))
|
|
62
|
+
# all exceptions from requests get caught in the retry logic so no need to wrap this here
|
|
63
|
+
resp = requests.get(url, timeout=30)
|
|
64
|
+
fire_event(RegistryProgressGETResponse(url=url, resp_code=resp.status_code))
|
|
65
|
+
resp.raise_for_status()
|
|
66
|
+
|
|
67
|
+
# The response should always be a dictionary. Anything else is unexpected, raise error.
|
|
68
|
+
# Raising this error will cause this function to retry (if called within _get_package_with_retries)
|
|
69
|
+
# and hopefully get a valid response. This seems to happen when there's an issue with the Hub.
|
|
70
|
+
# Since we control what we expect the HUB to return, this is safe.
|
|
71
|
+
# See https://github.com/dbt-labs/dbt-core/issues/4577
|
|
72
|
+
# and https://github.com/dbt-labs/dbt-core/issues/4849
|
|
73
|
+
response = resp.json()
|
|
74
|
+
|
|
75
|
+
if not isinstance(response, dict): # This will also catch Nonetype
|
|
76
|
+
error_msg = (
|
|
77
|
+
f"Request error: Expected a response type of <dict> but got {type(response)} instead"
|
|
78
|
+
)
|
|
79
|
+
fire_event(RegistryResponseUnexpectedType(response=response))
|
|
80
|
+
raise requests.exceptions.ContentDecodingError(error_msg, response=resp)
|
|
81
|
+
|
|
82
|
+
# check for expected top level keys
|
|
83
|
+
expected_keys = {"name", "versions"}
|
|
84
|
+
if not expected_keys.issubset(response):
|
|
85
|
+
error_msg = (
|
|
86
|
+
f"Request error: Expected the response to contain keys {expected_keys} "
|
|
87
|
+
f"but is missing {expected_keys.difference(set(response))}"
|
|
88
|
+
)
|
|
89
|
+
fire_event(RegistryResponseMissingTopKeys(response=response))
|
|
90
|
+
raise requests.exceptions.ContentDecodingError(error_msg, response=resp)
|
|
91
|
+
|
|
92
|
+
# check for the keys we need nested under each version
|
|
93
|
+
expected_version_keys = {"name", "packages", "downloads"}
|
|
94
|
+
all_keys = set().union(*(response["versions"][d] for d in response["versions"]))
|
|
95
|
+
if not expected_version_keys.issubset(all_keys):
|
|
96
|
+
error_msg = (
|
|
97
|
+
"Request error: Expected the response for the version to contain keys "
|
|
98
|
+
f"{expected_version_keys} but is missing {expected_version_keys.difference(all_keys)}"
|
|
99
|
+
)
|
|
100
|
+
fire_event(RegistryResponseMissingNestedKeys(response=response))
|
|
101
|
+
raise requests.exceptions.ContentDecodingError(error_msg, response=resp)
|
|
102
|
+
|
|
103
|
+
# all version responses should contain identical keys.
|
|
104
|
+
has_extra_keys = set().difference(*(response["versions"][d] for d in response["versions"]))
|
|
105
|
+
if has_extra_keys:
|
|
106
|
+
error_msg = (
|
|
107
|
+
"Request error: Keys for all versions do not match. Found extra key(s) "
|
|
108
|
+
f"of {has_extra_keys}."
|
|
109
|
+
)
|
|
110
|
+
fire_event(RegistryResponseExtraNestedKeys(response=response))
|
|
111
|
+
raise requests.exceptions.ContentDecodingError(error_msg, response=resp)
|
|
112
|
+
|
|
113
|
+
return response
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
_get_cached = memoized(_get_package_with_retries)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def package(package_name, registry_base_url=None) -> Dict[str, Any]:
|
|
120
|
+
# returns a dictionary of metadata for all versions of a package
|
|
121
|
+
response = _get_cached(package_name, registry_base_url)
|
|
122
|
+
return response["versions"]
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def package_version(package_name, version, registry_base_url=None) -> Dict[str, Any]:
|
|
126
|
+
# returns the metadata of a specific version of a package
|
|
127
|
+
response = package(package_name, registry_base_url)
|
|
128
|
+
return response[version]
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def is_compatible_version(package_spec, dbt_version) -> bool:
|
|
132
|
+
require_dbt_version = package_spec.get("require_dbt_version")
|
|
133
|
+
if not require_dbt_version:
|
|
134
|
+
# if version requirements are missing or empty, assume any version is compatible
|
|
135
|
+
return True
|
|
136
|
+
else:
|
|
137
|
+
# determine whether dbt_version satisfies this package's require-dbt-version config
|
|
138
|
+
if not isinstance(require_dbt_version, list):
|
|
139
|
+
require_dbt_version = [require_dbt_version]
|
|
140
|
+
supported_versions = [
|
|
141
|
+
semver.VersionSpecifier.from_version_string(v) for v in require_dbt_version
|
|
142
|
+
]
|
|
143
|
+
return semver.versions_compatible(dbt_version, *supported_versions)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def get_compatible_versions(package_name, dbt_version, should_version_check) -> List["str"]:
|
|
147
|
+
# returns a list of all available versions of a package
|
|
148
|
+
response = package(package_name)
|
|
149
|
+
|
|
150
|
+
# if the user doesn't care about installing compatible versions, just return them all
|
|
151
|
+
if not should_version_check:
|
|
152
|
+
return list(response)
|
|
153
|
+
|
|
154
|
+
# otherwise, only return versions that are compatible with the installed version of dbt-core
|
|
155
|
+
else:
|
|
156
|
+
compatible_versions = [
|
|
157
|
+
pkg_version
|
|
158
|
+
for pkg_version, info in response.items()
|
|
159
|
+
if is_compatible_version(info, dbt_version)
|
|
160
|
+
]
|
|
161
|
+
return compatible_versions
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _get_index(registry_base_url=None):
|
|
165
|
+
url = _get_url("index", registry_base_url)
|
|
166
|
+
fire_event(RegistryIndexProgressGETRequest(url=url))
|
|
167
|
+
# all exceptions from requests get caught in the retry logic so no need to wrap this here
|
|
168
|
+
resp = requests.get(url, timeout=30)
|
|
169
|
+
fire_event(RegistryIndexProgressGETResponse(url=url, resp_code=resp.status_code))
|
|
170
|
+
resp.raise_for_status()
|
|
171
|
+
|
|
172
|
+
# The response should be a list. Anything else is unexpected, raise an error.
|
|
173
|
+
# Raising this error will cause this function to retry and hopefully get a valid response.
|
|
174
|
+
|
|
175
|
+
response = resp.json()
|
|
176
|
+
|
|
177
|
+
if not isinstance(response, list): # This will also catch Nonetype
|
|
178
|
+
error_msg = (
|
|
179
|
+
f"Request error: The response type of {type(response)} is not valid: {resp.text}"
|
|
180
|
+
)
|
|
181
|
+
raise requests.exceptions.ContentDecodingError(error_msg, response=resp)
|
|
182
|
+
|
|
183
|
+
return response
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def index(registry_base_url=None) -> List[str]:
|
|
187
|
+
# this returns a list of all packages on the Hub
|
|
188
|
+
get_index_fn = functools.partial(_get_index, registry_base_url)
|
|
189
|
+
return connection_exception_retry(get_index_fn, 5)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
index_cached = memoized(index)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from typing import Any, Dict, Optional
|
|
2
|
+
|
|
3
|
+
import yaml
|
|
4
|
+
|
|
5
|
+
import dbt_common.exceptions
|
|
6
|
+
import dbt_common.exceptions.base
|
|
7
|
+
|
|
8
|
+
# the C version is faster, but it doesn't always exist
|
|
9
|
+
try:
|
|
10
|
+
from yaml import CDumper as Dumper
|
|
11
|
+
from yaml import CLoader as Loader
|
|
12
|
+
from yaml import CSafeLoader as SafeLoader
|
|
13
|
+
except ImportError:
|
|
14
|
+
from yaml import Dumper, Loader, SafeLoader # type: ignore # noqa: F401
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
YAML_ERROR_MESSAGE = """
|
|
18
|
+
Syntax error near line {line_number}
|
|
19
|
+
------------------------------
|
|
20
|
+
{nice_error}
|
|
21
|
+
|
|
22
|
+
Raw Error:
|
|
23
|
+
------------------------------
|
|
24
|
+
{raw_error}
|
|
25
|
+
""".strip()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def line_no(i, line, width=3):
|
|
29
|
+
line_number = str(i).ljust(width)
|
|
30
|
+
return "{}| {}".format(line_number, line)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def prefix_with_line_numbers(string, no_start, no_end):
|
|
34
|
+
line_list = string.split("\n")
|
|
35
|
+
|
|
36
|
+
numbers = range(no_start, no_end)
|
|
37
|
+
relevant_lines = line_list[no_start:no_end]
|
|
38
|
+
|
|
39
|
+
return "\n".join([line_no(i + 1, line) for (i, line) in zip(numbers, relevant_lines)])
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def contextualized_yaml_error(raw_contents, error):
|
|
43
|
+
mark = error.problem_mark
|
|
44
|
+
|
|
45
|
+
min_line = max(mark.line - 3, 0)
|
|
46
|
+
max_line = mark.line + 4
|
|
47
|
+
|
|
48
|
+
nice_error = prefix_with_line_numbers(raw_contents, min_line, max_line)
|
|
49
|
+
|
|
50
|
+
return YAML_ERROR_MESSAGE.format(
|
|
51
|
+
line_number=mark.line + 1, nice_error=nice_error, raw_error=error
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def safe_load(contents) -> Optional[Dict[str, Any]]:
|
|
56
|
+
return yaml.load(contents, Loader=SafeLoader)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def load_yaml_text(contents, path=None, loader=SafeLoader) -> Optional[Dict[str, Any]]:
|
|
60
|
+
try:
|
|
61
|
+
return yaml.load(contents, loader)
|
|
62
|
+
except (yaml.scanner.ScannerError, yaml.YAMLError) as e:
|
|
63
|
+
if hasattr(e, "problem_mark"):
|
|
64
|
+
error = contextualized_yaml_error(contents, e)
|
|
65
|
+
else:
|
|
66
|
+
error = str(e)
|
|
67
|
+
|
|
68
|
+
raise dbt_common.exceptions.base.DbtValidationError(error)
|