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.
Files changed (299) hide show
  1. dbt/__init__.py +7 -0
  2. dbt/_pydantic_shim.py +26 -0
  3. dbt/artifacts/__init__.py +0 -0
  4. dbt/artifacts/exceptions/__init__.py +1 -0
  5. dbt/artifacts/exceptions/schemas.py +31 -0
  6. dbt/artifacts/resources/__init__.py +116 -0
  7. dbt/artifacts/resources/base.py +67 -0
  8. dbt/artifacts/resources/types.py +93 -0
  9. dbt/artifacts/resources/v1/analysis.py +10 -0
  10. dbt/artifacts/resources/v1/catalog.py +23 -0
  11. dbt/artifacts/resources/v1/components.py +274 -0
  12. dbt/artifacts/resources/v1/config.py +277 -0
  13. dbt/artifacts/resources/v1/documentation.py +11 -0
  14. dbt/artifacts/resources/v1/exposure.py +51 -0
  15. dbt/artifacts/resources/v1/function.py +52 -0
  16. dbt/artifacts/resources/v1/generic_test.py +31 -0
  17. dbt/artifacts/resources/v1/group.py +21 -0
  18. dbt/artifacts/resources/v1/hook.py +11 -0
  19. dbt/artifacts/resources/v1/macro.py +29 -0
  20. dbt/artifacts/resources/v1/metric.py +172 -0
  21. dbt/artifacts/resources/v1/model.py +145 -0
  22. dbt/artifacts/resources/v1/owner.py +10 -0
  23. dbt/artifacts/resources/v1/saved_query.py +111 -0
  24. dbt/artifacts/resources/v1/seed.py +41 -0
  25. dbt/artifacts/resources/v1/semantic_layer_components.py +72 -0
  26. dbt/artifacts/resources/v1/semantic_model.py +314 -0
  27. dbt/artifacts/resources/v1/singular_test.py +14 -0
  28. dbt/artifacts/resources/v1/snapshot.py +91 -0
  29. dbt/artifacts/resources/v1/source_definition.py +84 -0
  30. dbt/artifacts/resources/v1/sql_operation.py +10 -0
  31. dbt/artifacts/resources/v1/unit_test_definition.py +77 -0
  32. dbt/artifacts/schemas/__init__.py +0 -0
  33. dbt/artifacts/schemas/base.py +191 -0
  34. dbt/artifacts/schemas/batch_results.py +24 -0
  35. dbt/artifacts/schemas/catalog/__init__.py +11 -0
  36. dbt/artifacts/schemas/catalog/v1/__init__.py +0 -0
  37. dbt/artifacts/schemas/catalog/v1/catalog.py +59 -0
  38. dbt/artifacts/schemas/freshness/__init__.py +1 -0
  39. dbt/artifacts/schemas/freshness/v3/__init__.py +0 -0
  40. dbt/artifacts/schemas/freshness/v3/freshness.py +158 -0
  41. dbt/artifacts/schemas/manifest/__init__.py +2 -0
  42. dbt/artifacts/schemas/manifest/v12/__init__.py +0 -0
  43. dbt/artifacts/schemas/manifest/v12/manifest.py +211 -0
  44. dbt/artifacts/schemas/results.py +147 -0
  45. dbt/artifacts/schemas/run/__init__.py +2 -0
  46. dbt/artifacts/schemas/run/v5/__init__.py +0 -0
  47. dbt/artifacts/schemas/run/v5/run.py +184 -0
  48. dbt/artifacts/schemas/upgrades/__init__.py +4 -0
  49. dbt/artifacts/schemas/upgrades/upgrade_manifest.py +174 -0
  50. dbt/artifacts/schemas/upgrades/upgrade_manifest_dbt_version.py +2 -0
  51. dbt/artifacts/utils/validation.py +153 -0
  52. dbt/cli/__init__.py +1 -0
  53. dbt/cli/context.py +17 -0
  54. dbt/cli/exceptions.py +57 -0
  55. dbt/cli/flags.py +560 -0
  56. dbt/cli/main.py +2660 -0
  57. dbt/cli/option_types.py +121 -0
  58. dbt/cli/options.py +80 -0
  59. dbt/cli/params.py +844 -0
  60. dbt/cli/requires.py +490 -0
  61. dbt/cli/resolvers.py +60 -0
  62. dbt/cli/types.py +40 -0
  63. dbt/clients/__init__.py +0 -0
  64. dbt/clients/checked_load.py +83 -0
  65. dbt/clients/git.py +164 -0
  66. dbt/clients/jinja.py +206 -0
  67. dbt/clients/jinja_static.py +245 -0
  68. dbt/clients/registry.py +192 -0
  69. dbt/clients/yaml_helper.py +68 -0
  70. dbt/compilation.py +876 -0
  71. dbt/compute/__init__.py +14 -0
  72. dbt/compute/engines/__init__.py +12 -0
  73. dbt/compute/engines/spark_engine.py +642 -0
  74. dbt/compute/federated_executor.py +1080 -0
  75. dbt/compute/filter_pushdown.py +273 -0
  76. dbt/compute/jar_provisioning.py +273 -0
  77. dbt/compute/java_compat.py +689 -0
  78. dbt/compute/jdbc_utils.py +1252 -0
  79. dbt/compute/metadata/__init__.py +63 -0
  80. dbt/compute/metadata/adapters_registry.py +370 -0
  81. dbt/compute/metadata/catalog_store.py +1036 -0
  82. dbt/compute/metadata/registry.py +674 -0
  83. dbt/compute/metadata/store.py +1020 -0
  84. dbt/compute/smart_selector.py +377 -0
  85. dbt/compute/spark_logger.py +272 -0
  86. dbt/compute/strategies/__init__.py +55 -0
  87. dbt/compute/strategies/base.py +165 -0
  88. dbt/compute/strategies/dataproc.py +207 -0
  89. dbt/compute/strategies/emr.py +203 -0
  90. dbt/compute/strategies/local.py +472 -0
  91. dbt/compute/strategies/standalone.py +262 -0
  92. dbt/config/__init__.py +4 -0
  93. dbt/config/catalogs.py +94 -0
  94. dbt/config/compute.py +513 -0
  95. dbt/config/dvt_profile.py +408 -0
  96. dbt/config/profile.py +422 -0
  97. dbt/config/project.py +888 -0
  98. dbt/config/project_utils.py +48 -0
  99. dbt/config/renderer.py +231 -0
  100. dbt/config/runtime.py +564 -0
  101. dbt/config/selectors.py +208 -0
  102. dbt/config/utils.py +77 -0
  103. dbt/constants.py +28 -0
  104. dbt/context/__init__.py +0 -0
  105. dbt/context/base.py +745 -0
  106. dbt/context/configured.py +135 -0
  107. dbt/context/context_config.py +382 -0
  108. dbt/context/docs.py +82 -0
  109. dbt/context/exceptions_jinja.py +178 -0
  110. dbt/context/macro_resolver.py +195 -0
  111. dbt/context/macros.py +171 -0
  112. dbt/context/manifest.py +72 -0
  113. dbt/context/providers.py +2249 -0
  114. dbt/context/query_header.py +13 -0
  115. dbt/context/secret.py +58 -0
  116. dbt/context/target.py +74 -0
  117. dbt/contracts/__init__.py +0 -0
  118. dbt/contracts/files.py +413 -0
  119. dbt/contracts/graph/__init__.py +0 -0
  120. dbt/contracts/graph/manifest.py +1904 -0
  121. dbt/contracts/graph/metrics.py +97 -0
  122. dbt/contracts/graph/model_config.py +70 -0
  123. dbt/contracts/graph/node_args.py +42 -0
  124. dbt/contracts/graph/nodes.py +1806 -0
  125. dbt/contracts/graph/semantic_manifest.py +232 -0
  126. dbt/contracts/graph/unparsed.py +811 -0
  127. dbt/contracts/project.py +419 -0
  128. dbt/contracts/results.py +53 -0
  129. dbt/contracts/selection.py +23 -0
  130. dbt/contracts/sql.py +85 -0
  131. dbt/contracts/state.py +68 -0
  132. dbt/contracts/util.py +46 -0
  133. dbt/deprecations.py +348 -0
  134. dbt/deps/__init__.py +0 -0
  135. dbt/deps/base.py +152 -0
  136. dbt/deps/git.py +195 -0
  137. dbt/deps/local.py +79 -0
  138. dbt/deps/registry.py +130 -0
  139. dbt/deps/resolver.py +149 -0
  140. dbt/deps/tarball.py +120 -0
  141. dbt/docs/source/_ext/dbt_click.py +119 -0
  142. dbt/docs/source/conf.py +32 -0
  143. dbt/env_vars.py +64 -0
  144. dbt/event_time/event_time.py +40 -0
  145. dbt/event_time/sample_window.py +60 -0
  146. dbt/events/__init__.py +15 -0
  147. dbt/events/base_types.py +36 -0
  148. dbt/events/core_types_pb2.py +2 -0
  149. dbt/events/logging.py +108 -0
  150. dbt/events/types.py +2516 -0
  151. dbt/exceptions.py +1486 -0
  152. dbt/flags.py +89 -0
  153. dbt/graph/__init__.py +11 -0
  154. dbt/graph/cli.py +249 -0
  155. dbt/graph/graph.py +172 -0
  156. dbt/graph/queue.py +214 -0
  157. dbt/graph/selector.py +374 -0
  158. dbt/graph/selector_methods.py +975 -0
  159. dbt/graph/selector_spec.py +222 -0
  160. dbt/graph/thread_pool.py +18 -0
  161. dbt/hooks.py +21 -0
  162. dbt/include/README.md +49 -0
  163. dbt/include/__init__.py +3 -0
  164. dbt/include/data/adapters_registry.duckdb +0 -0
  165. dbt/include/data/build_comprehensive_registry.py +1254 -0
  166. dbt/include/data/build_registry.py +242 -0
  167. dbt/include/data/csv/adapter_queries.csv +33 -0
  168. dbt/include/data/csv/syntax_rules.csv +9 -0
  169. dbt/include/data/csv/type_mappings_bigquery.csv +28 -0
  170. dbt/include/data/csv/type_mappings_databricks.csv +30 -0
  171. dbt/include/data/csv/type_mappings_mysql.csv +40 -0
  172. dbt/include/data/csv/type_mappings_oracle.csv +30 -0
  173. dbt/include/data/csv/type_mappings_postgres.csv +56 -0
  174. dbt/include/data/csv/type_mappings_redshift.csv +33 -0
  175. dbt/include/data/csv/type_mappings_snowflake.csv +38 -0
  176. dbt/include/data/csv/type_mappings_sqlserver.csv +35 -0
  177. dbt/include/dvt_starter_project/README.md +15 -0
  178. dbt/include/dvt_starter_project/__init__.py +3 -0
  179. dbt/include/dvt_starter_project/analyses/PLACEHOLDER +0 -0
  180. dbt/include/dvt_starter_project/dvt_project.yml +39 -0
  181. dbt/include/dvt_starter_project/logs/PLACEHOLDER +0 -0
  182. dbt/include/dvt_starter_project/macros/PLACEHOLDER +0 -0
  183. dbt/include/dvt_starter_project/models/example/my_first_dbt_model.sql +27 -0
  184. dbt/include/dvt_starter_project/models/example/my_second_dbt_model.sql +6 -0
  185. dbt/include/dvt_starter_project/models/example/schema.yml +21 -0
  186. dbt/include/dvt_starter_project/seeds/PLACEHOLDER +0 -0
  187. dbt/include/dvt_starter_project/snapshots/PLACEHOLDER +0 -0
  188. dbt/include/dvt_starter_project/tests/PLACEHOLDER +0 -0
  189. dbt/internal_deprecations.py +26 -0
  190. dbt/jsonschemas/__init__.py +3 -0
  191. dbt/jsonschemas/jsonschemas.py +309 -0
  192. dbt/jsonschemas/project/0.0.110.json +4717 -0
  193. dbt/jsonschemas/project/0.0.85.json +2015 -0
  194. dbt/jsonschemas/resources/0.0.110.json +2636 -0
  195. dbt/jsonschemas/resources/0.0.85.json +2536 -0
  196. dbt/jsonschemas/resources/latest.json +6773 -0
  197. dbt/links.py +4 -0
  198. dbt/materializations/__init__.py +0 -0
  199. dbt/materializations/incremental/__init__.py +0 -0
  200. dbt/materializations/incremental/microbatch.py +236 -0
  201. dbt/mp_context.py +8 -0
  202. dbt/node_types.py +37 -0
  203. dbt/parser/__init__.py +23 -0
  204. dbt/parser/analysis.py +21 -0
  205. dbt/parser/base.py +548 -0
  206. dbt/parser/common.py +266 -0
  207. dbt/parser/docs.py +52 -0
  208. dbt/parser/fixtures.py +51 -0
  209. dbt/parser/functions.py +30 -0
  210. dbt/parser/generic_test.py +100 -0
  211. dbt/parser/generic_test_builders.py +333 -0
  212. dbt/parser/hooks.py +122 -0
  213. dbt/parser/macros.py +137 -0
  214. dbt/parser/manifest.py +2208 -0
  215. dbt/parser/models.py +573 -0
  216. dbt/parser/partial.py +1178 -0
  217. dbt/parser/read_files.py +445 -0
  218. dbt/parser/schema_generic_tests.py +422 -0
  219. dbt/parser/schema_renderer.py +111 -0
  220. dbt/parser/schema_yaml_readers.py +935 -0
  221. dbt/parser/schemas.py +1466 -0
  222. dbt/parser/search.py +149 -0
  223. dbt/parser/seeds.py +28 -0
  224. dbt/parser/singular_test.py +20 -0
  225. dbt/parser/snapshots.py +44 -0
  226. dbt/parser/sources.py +558 -0
  227. dbt/parser/sql.py +62 -0
  228. dbt/parser/unit_tests.py +621 -0
  229. dbt/plugins/__init__.py +20 -0
  230. dbt/plugins/contracts.py +9 -0
  231. dbt/plugins/exceptions.py +2 -0
  232. dbt/plugins/manager.py +163 -0
  233. dbt/plugins/manifest.py +21 -0
  234. dbt/profiler.py +20 -0
  235. dbt/py.typed +1 -0
  236. dbt/query_analyzer.py +410 -0
  237. dbt/runners/__init__.py +2 -0
  238. dbt/runners/exposure_runner.py +7 -0
  239. dbt/runners/no_op_runner.py +45 -0
  240. dbt/runners/saved_query_runner.py +7 -0
  241. dbt/selected_resources.py +8 -0
  242. dbt/task/__init__.py +0 -0
  243. dbt/task/base.py +506 -0
  244. dbt/task/build.py +197 -0
  245. dbt/task/clean.py +56 -0
  246. dbt/task/clone.py +161 -0
  247. dbt/task/compile.py +150 -0
  248. dbt/task/compute.py +458 -0
  249. dbt/task/debug.py +513 -0
  250. dbt/task/deps.py +280 -0
  251. dbt/task/docs/__init__.py +3 -0
  252. dbt/task/docs/api/__init__.py +23 -0
  253. dbt/task/docs/api/catalog.py +204 -0
  254. dbt/task/docs/api/lineage.py +234 -0
  255. dbt/task/docs/api/profile.py +204 -0
  256. dbt/task/docs/api/spark.py +186 -0
  257. dbt/task/docs/generate.py +1002 -0
  258. dbt/task/docs/index.html +250 -0
  259. dbt/task/docs/serve.py +174 -0
  260. dbt/task/dvt_output.py +509 -0
  261. dbt/task/dvt_run.py +282 -0
  262. dbt/task/dvt_seed.py +806 -0
  263. dbt/task/freshness.py +322 -0
  264. dbt/task/function.py +121 -0
  265. dbt/task/group_lookup.py +46 -0
  266. dbt/task/init.py +1022 -0
  267. dbt/task/java.py +316 -0
  268. dbt/task/list.py +236 -0
  269. dbt/task/metadata.py +804 -0
  270. dbt/task/migrate.py +714 -0
  271. dbt/task/printer.py +175 -0
  272. dbt/task/profile.py +1489 -0
  273. dbt/task/profile_serve.py +662 -0
  274. dbt/task/retract.py +441 -0
  275. dbt/task/retry.py +175 -0
  276. dbt/task/run.py +1647 -0
  277. dbt/task/run_operation.py +141 -0
  278. dbt/task/runnable.py +758 -0
  279. dbt/task/seed.py +103 -0
  280. dbt/task/show.py +149 -0
  281. dbt/task/snapshot.py +56 -0
  282. dbt/task/spark.py +414 -0
  283. dbt/task/sql.py +110 -0
  284. dbt/task/target_sync.py +814 -0
  285. dbt/task/test.py +464 -0
  286. dbt/tests/fixtures/__init__.py +1 -0
  287. dbt/tests/fixtures/project.py +620 -0
  288. dbt/tests/util.py +651 -0
  289. dbt/tracking.py +529 -0
  290. dbt/utils/__init__.py +3 -0
  291. dbt/utils/artifact_upload.py +151 -0
  292. dbt/utils/utils.py +408 -0
  293. dbt/version.py +271 -0
  294. dvt_cli/__init__.py +158 -0
  295. dvt_core-0.59.0a51.dist-info/METADATA +288 -0
  296. dvt_core-0.59.0a51.dist-info/RECORD +299 -0
  297. dvt_core-0.59.0a51.dist-info/WHEEL +5 -0
  298. dvt_core-0.59.0a51.dist-info/entry_points.txt +2 -0
  299. dvt_core-0.59.0a51.dist-info/top_level.txt +2 -0
dbt/config/project.py ADDED
@@ -0,0 +1,888 @@
1
+ import os
2
+ from copy import deepcopy
3
+ from dataclasses import dataclass, field
4
+ from itertools import chain
5
+ from typing import Any, Dict, List, Mapping, Optional, TypeVar, Union
6
+
7
+ from typing_extensions import Protocol, runtime_checkable
8
+
9
+ from dbt import deprecations
10
+ from dbt.adapters.contracts.connection import QueryComment
11
+ from dbt.clients.checked_load import (
12
+ checked_load,
13
+ issue_deprecation_warnings_for_failures,
14
+ )
15
+ from dbt.clients.yaml_helper import load_yaml_text
16
+ from dbt.config.selectors import SelectorDict
17
+ from dbt.config.utils import normalize_warn_error_options
18
+ from dbt.constants import (
19
+ DVT_PROJECT_FILE_NAME,
20
+ DEPENDENCIES_FILE_NAME,
21
+ PACKAGE_LOCK_HASH_KEY,
22
+ PACKAGES_FILE_NAME,
23
+ )
24
+ from dbt.contracts.project import PackageConfig
25
+ from dbt.contracts.project import Project as ProjectContract
26
+ from dbt.contracts.project import ProjectFlags, ProjectPackageMetadata, SemverString
27
+ from dbt.exceptions import (
28
+ DbtExclusivePropertyUseError,
29
+ DbtProjectError,
30
+ DbtRuntimeError,
31
+ ProjectContractBrokenError,
32
+ ProjectContractError,
33
+ )
34
+ from dbt.flags import get_flags
35
+ from dbt.graph import SelectionSpec
36
+ from dbt.node_types import NodeType
37
+ from dbt.utils import MultiDict, coerce_dict_str, md5
38
+ from dbt.version import get_installed_version
39
+ from dbt_common.clients.system import load_file_contents, path_exists
40
+ from dbt_common.dataclass_schema import ValidationError
41
+ from dbt_common.exceptions import SemverError
42
+ from dbt_common.helper_types import NoValue
43
+ from dbt_common.semver import VersionSpecifier, versions_compatible
44
+
45
+ from .renderer import DbtProjectYamlRenderer, PackageRenderer
46
+ from .selectors import (
47
+ SelectorConfig,
48
+ selector_config_from_data,
49
+ selector_data_from_root,
50
+ )
51
+
52
+ INVALID_VERSION_ERROR = """\
53
+ This version of dbt is not supported with the '{package}' package.
54
+ Installed version of dbt: {installed}
55
+ Required version of dbt for '{package}': {version_spec}
56
+ Check for a different version of the '{package}' package, or run dbt again with \
57
+ --no-version-check
58
+ """
59
+
60
+
61
+ IMPOSSIBLE_VERSION_ERROR = """\
62
+ The package version requirement can never be satisfied for the '{package}
63
+ package.
64
+ Required versions of dbt for '{package}': {version_spec}
65
+ Check for a different version of the '{package}' package, or run dbt again with \
66
+ --no-version-check
67
+ """
68
+
69
+ MALFORMED_PACKAGE_ERROR = """\
70
+ The packages.yml file in this project is malformed. Please double check
71
+ the contents of this file and fix any errors before retrying.
72
+
73
+ You can find more information on the syntax for this file here:
74
+ https://docs.getdbt.com/docs/package-management
75
+
76
+ Validator Error:
77
+ {error}
78
+ """
79
+
80
+ MISSING_DBT_PROJECT_ERROR = """\
81
+ No dvt_project.yml or dbt_project.yml found at expected path {path}
82
+ Verify that each entry within packages.yml (and their transitive dependencies) contains a project file
83
+ """
84
+
85
+
86
+ @runtime_checkable
87
+ class IsFQNResource(Protocol):
88
+ fqn: List[str]
89
+ resource_type: NodeType
90
+ package_name: str
91
+
92
+
93
+ def _load_yaml(path, validate: bool = False):
94
+ contents = load_file_contents(path)
95
+ if validate:
96
+ result, failures = checked_load(contents)
97
+ issue_deprecation_warnings_for_failures(failures=failures, file=path)
98
+ return result
99
+ else:
100
+ return load_yaml_text(contents)
101
+
102
+
103
+ def load_yml_dict(file_path):
104
+ ret = {}
105
+ if path_exists(file_path):
106
+ ret = _load_yaml(file_path) or {}
107
+ return ret
108
+
109
+
110
+ def package_and_project_data_from_root(project_root):
111
+ packages_yml_dict = load_yml_dict(f"{project_root}/{PACKAGES_FILE_NAME}")
112
+ dependencies_yml_dict = load_yml_dict(f"{project_root}/{DEPENDENCIES_FILE_NAME}")
113
+
114
+ if "packages" in packages_yml_dict and "packages" in dependencies_yml_dict:
115
+ msg = "The 'packages' key cannot be specified in both packages.yml and dependencies.yml"
116
+ raise DbtProjectError(msg)
117
+ if "projects" in packages_yml_dict:
118
+ msg = "The 'projects' key cannot be specified in packages.yml"
119
+ raise DbtProjectError(msg)
120
+
121
+ packages_specified_path = PACKAGES_FILE_NAME
122
+ packages_dict = {}
123
+ if "packages" in dependencies_yml_dict:
124
+ packages_dict["packages"] = dependencies_yml_dict["packages"]
125
+ packages_specified_path = DEPENDENCIES_FILE_NAME
126
+ else: # don't check for "packages" here so we capture invalid keys in packages.yml
127
+ packages_dict = packages_yml_dict
128
+
129
+ return packages_dict, packages_specified_path
130
+
131
+
132
+ def package_config_from_data(
133
+ packages_data: Dict[str, Any],
134
+ unrendered_packages_data: Optional[Dict[str, Any]] = None,
135
+ ) -> PackageConfig:
136
+ if not packages_data:
137
+ packages_data = {"packages": []}
138
+
139
+ # this depends on the two lists being in the same order
140
+ if unrendered_packages_data:
141
+ unrendered_packages_data = deepcopy(unrendered_packages_data)
142
+ for i in range(0, len(packages_data.get("packages", []))):
143
+ packages_data["packages"][i]["unrendered"] = unrendered_packages_data["packages"][i]
144
+
145
+ if PACKAGE_LOCK_HASH_KEY in packages_data:
146
+ packages_data.pop(PACKAGE_LOCK_HASH_KEY)
147
+ try:
148
+ PackageConfig.validate(packages_data)
149
+ packages = PackageConfig.from_dict(packages_data)
150
+ except ValidationError as e:
151
+ raise DbtProjectError(MALFORMED_PACKAGE_ERROR.format(error=str(e.message))) from e
152
+ return packages
153
+
154
+
155
+ def _parse_versions(versions: Union[List[str], str]) -> List[VersionSpecifier]:
156
+ """Parse multiple versions as read from disk. The versions value may be any
157
+ one of:
158
+ - a single version string ('>0.12.1')
159
+ - a single string specifying multiple comma-separated versions
160
+ ('>0.11.1,<=0.12.2')
161
+ - an array of single-version strings (['>0.11.1', '<=0.12.2'])
162
+
163
+ Regardless, this will return a list of VersionSpecifiers
164
+ """
165
+ if isinstance(versions, str):
166
+ versions = versions.split(",")
167
+ return [VersionSpecifier.from_version_string(v) for v in versions]
168
+
169
+
170
+ def _all_source_paths(*args: List[str]) -> List[str]:
171
+ paths = chain(*args)
172
+ # Strip trailing slashes since the path is the same even though the name is not
173
+ stripped_paths = map(lambda s: s.rstrip("/"), paths)
174
+ return list(set(stripped_paths))
175
+
176
+
177
+ T = TypeVar("T")
178
+
179
+
180
+ def flag_or(flag: Optional[T], value: Optional[T], default: T) -> T:
181
+ if flag is None:
182
+ return value_or(value, default)
183
+ else:
184
+ return flag
185
+
186
+
187
+ def value_or(value: Optional[T], default: T) -> T:
188
+ if value is None:
189
+ return default
190
+ else:
191
+ return value
192
+
193
+
194
+ def load_raw_project(project_root: str, validate: bool = False) -> Dict[str, Any]:
195
+ project_root = os.path.normpath(project_root)
196
+
197
+ # DVT: Support both dvt_project.yml (DVT projects) and dbt_project.yml (adapter packages)
198
+ # Priority: dvt_project.yml > dbt_project.yml
199
+ dvt_project_path = os.path.join(project_root, DVT_PROJECT_FILE_NAME)
200
+ dbt_project_path = os.path.join(project_root, "dbt_project.yml")
201
+
202
+ if path_exists(dvt_project_path):
203
+ project_yaml_filepath = dvt_project_path
204
+ elif path_exists(dbt_project_path):
205
+ project_yaml_filepath = dbt_project_path
206
+ else:
207
+ raise DbtProjectError(
208
+ MISSING_DBT_PROJECT_ERROR.format(path=project_root)
209
+ )
210
+
211
+ project_dict = _load_yaml(project_yaml_filepath, validate=validate)
212
+
213
+ if validate:
214
+ from dbt.jsonschemas.jsonschemas import jsonschema_validate, project_schema
215
+
216
+ jsonschema_validate(
217
+ schema=project_schema(), json=project_dict, file_path=project_yaml_filepath
218
+ )
219
+
220
+ if not isinstance(project_dict, dict):
221
+ raise DbtProjectError(f"{DVT_PROJECT_FILE_NAME} does not parse to a dictionary")
222
+
223
+ if "tests" in project_dict and "data_tests" not in project_dict:
224
+ project_dict["data_tests"] = project_dict.pop("tests")
225
+
226
+ return project_dict
227
+
228
+
229
+ def _query_comment_from_cfg(
230
+ cfg_query_comment: Union[QueryComment, NoValue, str, None]
231
+ ) -> QueryComment:
232
+ if not cfg_query_comment:
233
+ return QueryComment(comment="")
234
+
235
+ if isinstance(cfg_query_comment, str):
236
+ return QueryComment(comment=cfg_query_comment)
237
+
238
+ if isinstance(cfg_query_comment, NoValue):
239
+ return QueryComment()
240
+
241
+ return cfg_query_comment
242
+
243
+
244
+ def validate_version(dbt_version: List[VersionSpecifier], project_name: str):
245
+ """Ensure this package works with the installed version of dbt."""
246
+ installed = get_installed_version()
247
+ if not versions_compatible(*dbt_version):
248
+ msg = IMPOSSIBLE_VERSION_ERROR.format(
249
+ package=project_name, version_spec=[x.to_version_string() for x in dbt_version]
250
+ )
251
+ raise DbtProjectError(msg)
252
+
253
+ if not versions_compatible(installed, *dbt_version):
254
+ msg = INVALID_VERSION_ERROR.format(
255
+ package=project_name,
256
+ installed=installed.to_version_string(),
257
+ version_spec=[x.to_version_string() for x in dbt_version],
258
+ )
259
+ raise DbtProjectError(msg)
260
+
261
+
262
+ def _get_required_version(
263
+ project_dict: Dict[str, Any],
264
+ verify_version: bool,
265
+ ) -> List[VersionSpecifier]:
266
+ dbt_raw_version: Union[List[str], str] = ">=0.0.0"
267
+ required = project_dict.get("require-dbt-version")
268
+ if required is not None:
269
+ dbt_raw_version = required
270
+
271
+ try:
272
+ dbt_version = _parse_versions(dbt_raw_version)
273
+ except SemverError as e:
274
+ raise DbtProjectError(str(e)) from e
275
+
276
+ if verify_version:
277
+ # no name is also an error that we want to raise
278
+ if "name" not in project_dict:
279
+ raise DbtProjectError(
280
+ 'Required "name" field not present in project',
281
+ )
282
+ validate_version(dbt_version, project_dict["name"])
283
+
284
+ return dbt_version
285
+
286
+
287
+ @dataclass
288
+ class RenderComponents:
289
+ project_dict: Dict[str, Any] = field(metadata=dict(description="The project dictionary"))
290
+ packages_dict: Dict[str, Any] = field(metadata=dict(description="The packages dictionary"))
291
+ selectors_dict: Dict[str, Any] = field(metadata=dict(description="The selectors dictionary"))
292
+
293
+
294
+ @dataclass
295
+ class PartialProject(RenderComponents):
296
+ # This class includes the project_dict, packages_dict, selectors_dict, etc from RenderComponents
297
+ profile_name: Optional[str] = field(
298
+ metadata=dict(description="The unrendered profile name in the project, if set")
299
+ )
300
+ project_name: Optional[str] = field(
301
+ metadata=dict(
302
+ description=(
303
+ "The name of the project. This should always be set and will not be rendered"
304
+ )
305
+ )
306
+ )
307
+ project_root: str = field(
308
+ metadata=dict(description="The root directory of the project"),
309
+ )
310
+ verify_version: bool = field(
311
+ metadata=dict(description=("If True, verify the dbt version matches the required version"))
312
+ )
313
+ packages_specified_path: str = field(
314
+ metadata=dict(description="The filename where packages were specified")
315
+ )
316
+
317
+ def render_profile_name(self, renderer) -> Optional[str]:
318
+ if self.profile_name is None:
319
+ return None
320
+ return renderer.render_value(self.profile_name)
321
+
322
+ def get_rendered(
323
+ self,
324
+ renderer: DbtProjectYamlRenderer,
325
+ ) -> RenderComponents:
326
+ rendered_project = renderer.render_project(self.project_dict, self.project_root)
327
+ rendered_packages = renderer.render_packages(
328
+ self.packages_dict, self.packages_specified_path
329
+ )
330
+ rendered_selectors = renderer.render_selectors(self.selectors_dict)
331
+
332
+ return RenderComponents(
333
+ project_dict=rendered_project,
334
+ packages_dict=rendered_packages,
335
+ selectors_dict=rendered_selectors,
336
+ )
337
+
338
+ # Called by Project.from_project_root which first calls PartialProject.from_project_root
339
+ def render(self, renderer: DbtProjectYamlRenderer) -> "Project":
340
+ try:
341
+ rendered = self.get_rendered(renderer)
342
+ return self.create_project(rendered)
343
+ except DbtProjectError as exc:
344
+ if exc.path is None:
345
+ exc.path = os.path.join(self.project_root, DVT_PROJECT_FILE_NAME)
346
+ raise
347
+
348
+ def render_package_metadata(self, renderer: PackageRenderer) -> ProjectPackageMetadata:
349
+ packages_data = renderer.render_data(self.packages_dict)
350
+ packages_config = package_config_from_data(packages_data, self.packages_dict)
351
+ if not self.project_name:
352
+ raise DbtProjectError(f"Package defined in {DVT_PROJECT_FILE_NAME} must have a name!")
353
+ return ProjectPackageMetadata(self.project_name, packages_config.packages)
354
+
355
+ def check_config_path(
356
+ self, project_dict, deprecated_path, expected_path=None, default_value=None
357
+ ):
358
+ if deprecated_path in project_dict:
359
+ if expected_path in project_dict:
360
+ msg = (
361
+ "{deprecated_path} and {expected_path} cannot both be defined. The "
362
+ "`{deprecated_path}` config has been deprecated in favor of `{expected_path}`. "
363
+ f"Please update your `{DVT_PROJECT_FILE_NAME}` configuration to reflect this "
364
+ "change."
365
+ )
366
+ raise DbtProjectError(
367
+ msg.format(deprecated_path=deprecated_path, expected_path=expected_path)
368
+ )
369
+ # this field is no longer supported, but many projects may specify it with the default value
370
+ # if so, let's only raise this deprecation warning if they set a custom value
371
+ if not default_value or project_dict[deprecated_path] != default_value:
372
+ kwargs = {"deprecated_path": deprecated_path}
373
+ if expected_path:
374
+ kwargs.update({"exp_path": expected_path})
375
+ deprecations.warn(f"project-config-{deprecated_path}", **kwargs)
376
+
377
+ def create_project(self, rendered: RenderComponents) -> "Project":
378
+ unrendered = RenderComponents(
379
+ project_dict=self.project_dict,
380
+ packages_dict=self.packages_dict,
381
+ selectors_dict=self.selectors_dict,
382
+ )
383
+ dbt_version = _get_required_version(
384
+ rendered.project_dict,
385
+ verify_version=self.verify_version,
386
+ )
387
+
388
+ self.check_config_path(rendered.project_dict, "source-paths", "model-paths")
389
+ self.check_config_path(rendered.project_dict, "data-paths", "seed-paths")
390
+ self.check_config_path(rendered.project_dict, "log-path", default_value="logs")
391
+ self.check_config_path(rendered.project_dict, "target-path", default_value="target")
392
+
393
+ try:
394
+ ProjectContract.validate(rendered.project_dict)
395
+ cfg = ProjectContract.from_dict(rendered.project_dict)
396
+ except ValidationError as e:
397
+ raise ProjectContractError(e) from e
398
+ # name/version are required in the Project definition, so we can assume
399
+ # they are present
400
+ name = cfg.name
401
+ version = cfg.version
402
+ # this is added at project_dict parse time and should always be here
403
+ # once we see it.
404
+ if cfg.project_root is None:
405
+ raise DbtProjectError("cfg must have a project root!")
406
+ else:
407
+ project_root = cfg.project_root
408
+ # this is only optional in the sense that if it's not present, it needs
409
+ # to have been a cli argument.
410
+ profile_name = cfg.profile
411
+ # these are all the defaults
412
+
413
+ # `source_paths` is deprecated but still allowed. Copy it into
414
+ # `model_paths` to simlify logic throughout the rest of the system.
415
+ model_paths: List[str] = value_or(
416
+ cfg.model_paths if "model-paths" in rendered.project_dict else cfg.source_paths,
417
+ ["models"],
418
+ )
419
+ macro_paths: List[str] = value_or(cfg.macro_paths, ["macros"])
420
+ # `data_paths` is deprecated but still allowed. Copy it into
421
+ # `seed_paths` to simlify logic throughout the rest of the system.
422
+ seed_paths: List[str] = value_or(
423
+ cfg.seed_paths if "seed-paths" in rendered.project_dict else cfg.data_paths, ["seeds"]
424
+ )
425
+ test_paths: List[str] = value_or(cfg.test_paths, ["tests"])
426
+ analysis_paths: List[str] = value_or(cfg.analysis_paths, ["analyses"])
427
+ snapshot_paths: List[str] = value_or(cfg.snapshot_paths, ["snapshots"])
428
+ function_paths: List[str] = value_or(cfg.function_paths, ["functions"])
429
+
430
+ all_source_paths: List[str] = _all_source_paths(
431
+ model_paths,
432
+ seed_paths,
433
+ snapshot_paths,
434
+ analysis_paths,
435
+ macro_paths,
436
+ test_paths,
437
+ function_paths,
438
+ )
439
+
440
+ docs_paths: List[str] = value_or(cfg.docs_paths, all_source_paths)
441
+ asset_paths: List[str] = value_or(cfg.asset_paths, [])
442
+ global_flags = get_flags()
443
+
444
+ flag_target_path = str(global_flags.TARGET_PATH) if global_flags.TARGET_PATH else None
445
+ target_path: str = flag_or(flag_target_path, cfg.target_path, "target")
446
+ log_path: str = str(global_flags.LOG_PATH)
447
+
448
+ clean_targets: List[str] = value_or(cfg.clean_targets, [target_path])
449
+ packages_install_path: str = value_or(cfg.packages_install_path, "dbt_packages")
450
+ # in the default case we'll populate this once we know the adapter type
451
+ # It would be nice to just pass along a Quoting here, but that would
452
+ # break many things
453
+ quoting: Dict[str, Any] = {}
454
+ if cfg.quoting is not None:
455
+ quoting = cfg.quoting.to_dict(omit_none=True)
456
+
457
+ dispatch: List[Dict[str, Any]]
458
+ models: Dict[str, Any]
459
+ seeds: Dict[str, Any]
460
+ snapshots: Dict[str, Any]
461
+ sources: Dict[str, Any]
462
+ data_tests: Dict[str, Any]
463
+ unit_tests: Dict[str, Any]
464
+ metrics: Dict[str, Any]
465
+ semantic_models: Dict[str, Any]
466
+ saved_queries: Dict[str, Any]
467
+ exposures: Dict[str, Any]
468
+ functions: Dict[str, Any]
469
+ vars_value: VarProvider
470
+ dbt_cloud: Dict[str, Any]
471
+
472
+ dispatch = cfg.dispatch
473
+ models = cfg.models
474
+ seeds = cfg.seeds
475
+ snapshots = cfg.snapshots
476
+ sources = cfg.sources
477
+ # the `tests` config is deprecated but still allowed. Copy it into
478
+ # `data_tests` to simplify logic throughout the rest of the system.
479
+ data_tests = cfg.data_tests if "data_tests" in rendered.project_dict else cfg.tests
480
+ unit_tests = cfg.unit_tests
481
+ metrics = cfg.metrics
482
+ semantic_models = cfg.semantic_models
483
+ saved_queries = cfg.saved_queries
484
+ exposures = cfg.exposures
485
+ functions = cfg.functions
486
+ if cfg.vars is None:
487
+ vars_dict: Dict[str, Any] = {}
488
+ else:
489
+ vars_dict = cfg.vars
490
+
491
+ vars_value = VarProvider(vars_dict)
492
+ # There will never be any project_env_vars when it's first created
493
+ project_env_vars: Dict[str, Any] = {}
494
+ on_run_start: List[str] = value_or(cfg.on_run_start, [])
495
+ on_run_end: List[str] = value_or(cfg.on_run_end, [])
496
+
497
+ query_comment = _query_comment_from_cfg(cfg.query_comment)
498
+ packages: PackageConfig = package_config_from_data(
499
+ rendered.packages_dict, unrendered.packages_dict
500
+ )
501
+ selectors = selector_config_from_data(rendered.selectors_dict)
502
+ manifest_selectors: Dict[str, Any] = {}
503
+ if rendered.selectors_dict and rendered.selectors_dict["selectors"]:
504
+ # this is a dict with a single key 'selectors' pointing to a list
505
+ # of dicts.
506
+ manifest_selectors = SelectorDict.parse_from_selectors_list(
507
+ rendered.selectors_dict["selectors"]
508
+ )
509
+ dbt_cloud = cfg.dbt_cloud
510
+ flags: Dict[str, Any] = cfg.flags
511
+
512
+ project = Project(
513
+ project_name=name,
514
+ version=version,
515
+ project_root=project_root,
516
+ profile_name=profile_name,
517
+ model_paths=model_paths,
518
+ macro_paths=macro_paths,
519
+ seed_paths=seed_paths,
520
+ test_paths=test_paths,
521
+ analysis_paths=analysis_paths,
522
+ docs_paths=docs_paths,
523
+ asset_paths=asset_paths,
524
+ target_path=target_path,
525
+ snapshot_paths=snapshot_paths,
526
+ function_paths=function_paths,
527
+ clean_targets=clean_targets,
528
+ log_path=log_path,
529
+ packages_install_path=packages_install_path,
530
+ packages_specified_path=self.packages_specified_path,
531
+ quoting=quoting,
532
+ models=models,
533
+ on_run_start=on_run_start,
534
+ on_run_end=on_run_end,
535
+ dispatch=dispatch,
536
+ seeds=seeds,
537
+ snapshots=snapshots,
538
+ dbt_version=dbt_version,
539
+ packages=packages,
540
+ manifest_selectors=manifest_selectors,
541
+ selectors=selectors,
542
+ query_comment=query_comment,
543
+ sources=sources,
544
+ data_tests=data_tests,
545
+ unit_tests=unit_tests,
546
+ metrics=metrics,
547
+ semantic_models=semantic_models,
548
+ saved_queries=saved_queries,
549
+ exposures=exposures,
550
+ functions=functions,
551
+ vars=vars_value,
552
+ config_version=cfg.config_version,
553
+ unrendered=unrendered,
554
+ project_env_vars=project_env_vars,
555
+ restrict_access=cfg.restrict_access,
556
+ dbt_cloud=dbt_cloud,
557
+ flags=flags,
558
+ )
559
+ # sanity check - this means an internal issue
560
+ project.validate()
561
+ return project
562
+
563
+ @classmethod
564
+ def from_dicts(
565
+ cls,
566
+ project_root: str,
567
+ project_dict: Dict[str, Any],
568
+ packages_dict: Dict[str, Any],
569
+ selectors_dict: Optional[Dict[str, Any]],
570
+ *,
571
+ verify_version: bool = False,
572
+ packages_specified_path: str = PACKAGES_FILE_NAME,
573
+ ):
574
+ """Construct a partial project from its constituent dicts."""
575
+ project_name = project_dict.get("name")
576
+ profile_name = project_dict.get("profile")
577
+
578
+ # Create a PartialProject
579
+ return cls(
580
+ profile_name=profile_name,
581
+ project_name=project_name,
582
+ project_root=project_root,
583
+ project_dict=project_dict,
584
+ packages_dict=packages_dict,
585
+ selectors_dict=selectors_dict, # type: ignore
586
+ verify_version=verify_version,
587
+ packages_specified_path=packages_specified_path,
588
+ )
589
+
590
+ @classmethod
591
+ def from_project_root(
592
+ cls, project_root: str, *, verify_version: bool = False, validate: bool = False
593
+ ) -> "PartialProject":
594
+ project_root = os.path.normpath(project_root)
595
+ project_dict = load_raw_project(project_root, validate=validate)
596
+ (
597
+ packages_dict,
598
+ packages_specified_path,
599
+ ) = package_and_project_data_from_root(project_root)
600
+ selectors_dict = selector_data_from_root(project_root)
601
+
602
+ return cls.from_dicts(
603
+ project_root=project_root,
604
+ project_dict=project_dict,
605
+ selectors_dict=selectors_dict,
606
+ packages_dict=packages_dict,
607
+ verify_version=verify_version,
608
+ packages_specified_path=packages_specified_path,
609
+ )
610
+
611
+
612
+ class VarProvider:
613
+ """Var providers are tied to a particular Project."""
614
+
615
+ def __init__(self, vars: Dict[str, Dict[str, Any]]) -> None:
616
+ self.vars = vars
617
+
618
+ def vars_for(self, node: IsFQNResource, adapter_type: str) -> Mapping[str, Any]:
619
+ # in v2, vars are only either project or globally scoped
620
+ merged = MultiDict([self.vars])
621
+ merged.add(self.vars.get(node.package_name, {}))
622
+ return merged
623
+
624
+ def to_dict(self):
625
+ return self.vars
626
+
627
+
628
+ # The Project class is included in RuntimeConfig, so any attribute
629
+ # additions must also be set where the RuntimeConfig class is created
630
+ @dataclass
631
+ class Project:
632
+ project_name: str
633
+ version: Optional[Union[SemverString, float]]
634
+ project_root: str
635
+ profile_name: Optional[str]
636
+ model_paths: List[str]
637
+ macro_paths: List[str]
638
+ seed_paths: List[str]
639
+ test_paths: List[str]
640
+ analysis_paths: List[str]
641
+ docs_paths: List[str]
642
+ asset_paths: List[str]
643
+ target_path: str
644
+ snapshot_paths: List[str]
645
+ function_paths: List[str]
646
+ clean_targets: List[str]
647
+ log_path: str
648
+ packages_install_path: str
649
+ packages_specified_path: str
650
+ quoting: Dict[str, Any]
651
+ models: Dict[str, Any]
652
+ on_run_start: List[str]
653
+ on_run_end: List[str]
654
+ dispatch: List[Dict[str, Any]]
655
+ seeds: Dict[str, Any]
656
+ snapshots: Dict[str, Any]
657
+ sources: Dict[str, Any]
658
+ data_tests: Dict[str, Any]
659
+ unit_tests: Dict[str, Any]
660
+ metrics: Dict[str, Any]
661
+ semantic_models: Dict[str, Any]
662
+ saved_queries: Dict[str, Any]
663
+ exposures: Dict[str, Any]
664
+ functions: Dict[str, Any]
665
+ vars: VarProvider
666
+ dbt_version: List[VersionSpecifier]
667
+ packages: PackageConfig
668
+ manifest_selectors: Dict[str, Any]
669
+ selectors: SelectorConfig
670
+ query_comment: QueryComment
671
+ config_version: int
672
+ unrendered: RenderComponents
673
+ project_env_vars: Dict[str, Any]
674
+ restrict_access: bool
675
+ dbt_cloud: Dict[str, Any]
676
+ flags: Dict[str, Any]
677
+
678
+ @property
679
+ def all_source_paths(self) -> List[str]:
680
+ return _all_source_paths(
681
+ self.model_paths,
682
+ self.seed_paths,
683
+ self.snapshot_paths,
684
+ self.analysis_paths,
685
+ self.macro_paths,
686
+ self.test_paths,
687
+ self.function_paths,
688
+ )
689
+
690
+ @property
691
+ def generic_test_paths(self):
692
+ generic_test_paths = []
693
+ for test_path in self.test_paths:
694
+ generic_test_paths.append(os.path.join(test_path, "generic"))
695
+ return generic_test_paths
696
+
697
+ @property
698
+ def fixture_paths(self):
699
+ fixture_paths = []
700
+ for test_path in self.test_paths:
701
+ fixture_paths.append(os.path.join(test_path, "fixtures"))
702
+ return fixture_paths
703
+
704
+ def __str__(self):
705
+ cfg = self.to_project_config(with_packages=True)
706
+ return str(cfg)
707
+
708
+ def __eq__(self, other):
709
+ if not (isinstance(other, self.__class__) and isinstance(self, other.__class__)):
710
+ return False
711
+ return self.to_project_config(with_packages=True) == other.to_project_config(
712
+ with_packages=True
713
+ )
714
+
715
+ def to_project_config(self, with_packages=False):
716
+ """Return a dict representation of the config that could be written to
717
+ disk with `yaml.safe_dump` to get this configuration.
718
+
719
+ :param with_packages bool: If True, include the serialized packages
720
+ file in the root.
721
+ :returns dict: The serialized profile.
722
+ """
723
+ result = deepcopy(
724
+ {
725
+ "name": self.project_name,
726
+ "version": self.version,
727
+ "project-root": self.project_root,
728
+ "profile": self.profile_name,
729
+ "model-paths": self.model_paths,
730
+ "macro-paths": self.macro_paths,
731
+ "seed-paths": self.seed_paths,
732
+ "test-paths": self.test_paths,
733
+ "analysis-paths": self.analysis_paths,
734
+ "docs-paths": self.docs_paths,
735
+ "asset-paths": self.asset_paths,
736
+ "target-path": self.target_path,
737
+ "snapshot-paths": self.snapshot_paths,
738
+ "clean-targets": self.clean_targets,
739
+ "log-path": self.log_path,
740
+ "quoting": self.quoting,
741
+ "models": self.models,
742
+ "on-run-start": self.on_run_start,
743
+ "on-run-end": self.on_run_end,
744
+ "dispatch": self.dispatch,
745
+ "seeds": self.seeds,
746
+ "snapshots": self.snapshots,
747
+ "sources": self.sources,
748
+ "data_tests": self.data_tests,
749
+ "unit_tests": self.unit_tests,
750
+ "metrics": self.metrics,
751
+ "semantic-models": self.semantic_models,
752
+ "saved-queries": self.saved_queries,
753
+ "exposures": self.exposures,
754
+ "functions": self.functions,
755
+ "vars": self.vars.to_dict(),
756
+ "require-dbt-version": [v.to_version_string() for v in self.dbt_version],
757
+ "restrict-access": self.restrict_access,
758
+ "dbt-cloud": self.dbt_cloud,
759
+ "flags": self.flags,
760
+ }
761
+ )
762
+ if self.query_comment:
763
+ result["query-comment"] = self.query_comment.to_dict(omit_none=True)
764
+
765
+ if with_packages:
766
+ result.update(self.packages.to_dict(omit_none=True))
767
+
768
+ return result
769
+
770
+ def validate(self):
771
+ try:
772
+ ProjectContract.validate(self.to_project_config())
773
+ except ValidationError as e:
774
+ raise ProjectContractBrokenError(e) from e
775
+
776
+ # Called by:
777
+ # RtConfig.load_dependencies => RtConfig.load_projects => RtConfig.new_project => Project.from_project_root
778
+ # RtConfig.from_args => RtConfig.collect_parts => load_project => Project.from_project_root
779
+ @classmethod
780
+ def from_project_root(
781
+ cls,
782
+ project_root: str,
783
+ renderer: DbtProjectYamlRenderer,
784
+ *,
785
+ verify_version: bool = False,
786
+ validate: bool = False,
787
+ ) -> "Project":
788
+ partial = PartialProject.from_project_root(
789
+ project_root, verify_version=verify_version, validate=validate
790
+ )
791
+ return partial.render(renderer)
792
+
793
+ def hashed_name(self):
794
+ return md5(self.project_name)
795
+
796
+ def get_selector(self, name: str) -> Union[SelectionSpec, bool]:
797
+ if name not in self.selectors:
798
+ raise DbtRuntimeError(
799
+ f"Could not find selector named {name}, expected one of {list(self.selectors)}"
800
+ )
801
+ return self.selectors[name]["definition"]
802
+
803
+ def get_default_selector_name(self) -> Union[str, None]:
804
+ """This function fetch the default selector to use on `dbt run` (if any)
805
+ :return: either a selector if default is set or None
806
+ :rtype: Union[SelectionSpec, None]
807
+ """
808
+ for selector_name, selector in self.selectors.items():
809
+ if selector["default"] is True:
810
+ return selector_name
811
+
812
+ return None
813
+
814
+ def get_macro_search_order(self, macro_namespace: str):
815
+ for dispatch_entry in self.dispatch:
816
+ if dispatch_entry["macro_namespace"] == macro_namespace:
817
+ return dispatch_entry["search_order"]
818
+ return None
819
+
820
+ @property
821
+ def project_target_path(self):
822
+ # If target_path is absolute, project_root will not be included
823
+ return os.path.join(self.project_root, self.target_path)
824
+
825
+
826
+ def read_project_flags(project_dir: str, profiles_dir: str) -> ProjectFlags:
827
+ try:
828
+ project_flags: Dict[str, Any] = {}
829
+ # Read project_flags from project file first
830
+ # Flags are instantiated before the project, so we don't
831
+ # want to throw an error for non-existence of project file here
832
+ # because it breaks things.
833
+ # DVT: Support both dvt_project.yml and dbt_project.yml
834
+ project_root = os.path.normpath(project_dir)
835
+ dvt_project_path = os.path.join(project_root, DVT_PROJECT_FILE_NAME)
836
+ dbt_project_path = os.path.join(project_root, "dbt_project.yml")
837
+
838
+ if path_exists(dvt_project_path):
839
+ project_yaml_filepath = dvt_project_path
840
+ elif path_exists(dbt_project_path):
841
+ project_yaml_filepath = dbt_project_path
842
+ else:
843
+ project_yaml_filepath = None
844
+
845
+ if project_yaml_filepath:
846
+ try:
847
+ project_dict = load_raw_project(project_root)
848
+ if "flags" in project_dict:
849
+ project_flags = project_dict.pop("flags")
850
+ except Exception:
851
+ # This is probably a yaml load error.The error will be reported
852
+ # later, when the project loads.
853
+ pass
854
+
855
+ from dbt.config.profile import read_profile
856
+
857
+ profile = read_profile(profiles_dir)
858
+ profile_project_flags: Optional[Dict[str, Any]] = {}
859
+ if profile:
860
+ profile_project_flags = coerce_dict_str(profile.get("config", {}))
861
+
862
+ if project_flags and profile_project_flags:
863
+ raise DbtProjectError(
864
+ f"Do not specify both 'config' in profiles.yml and 'flags' in {DVT_PROJECT_FILE_NAME}. "
865
+ "Using 'config' in profiles.yml is deprecated."
866
+ )
867
+
868
+ if profile_project_flags:
869
+ # This can't use WARN_ERROR or WARN_ERROR_OPTIONS because they're in
870
+ # the config that we're loading. Uses special "buffer" method and fired after flags are initialized in preflight.
871
+ deprecations.buffer("project-flags-moved")
872
+ project_flags = profile_project_flags
873
+
874
+ if project_flags is not None:
875
+ # handle collapsing `include` and `error` as well as collapsing `exclude` and `warn`
876
+ # for warn_error_options
877
+ warn_error_options = project_flags.get("warn_error_options", {})
878
+ normalize_warn_error_options(warn_error_options)
879
+
880
+ ProjectFlags.validate(project_flags)
881
+ return ProjectFlags.from_dict(project_flags)
882
+ except (DbtProjectError, DbtExclusivePropertyUseError) as exc:
883
+ # We don't want to eat the DbtProjectError for UserConfig to ProjectFlags or
884
+ # DbtConfigError for warn_error_options munging
885
+ raise exc
886
+ except (DbtRuntimeError, ValidationError):
887
+ pass
888
+ return ProjectFlags()