dvt-core 0.52.2__cp310-cp310-macosx_10_9_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of dvt-core might be problematic. Click here for more details.

Files changed (275) 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 +2039 -0
  57. dbt/cli/option_types.py +121 -0
  58. dbt/cli/options.py +80 -0
  59. dbt/cli/params.py +804 -0
  60. dbt/cli/requires.py +490 -0
  61. dbt/cli/resolvers.py +50 -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 +624 -0
  74. dbt/compute/federated_executor.py +837 -0
  75. dbt/compute/filter_pushdown.cpython-310-darwin.so +0 -0
  76. dbt/compute/filter_pushdown.py +273 -0
  77. dbt/compute/jar_provisioning.cpython-310-darwin.so +0 -0
  78. dbt/compute/jar_provisioning.py +255 -0
  79. dbt/compute/java_compat.cpython-310-darwin.so +0 -0
  80. dbt/compute/java_compat.py +689 -0
  81. dbt/compute/jdbc_utils.cpython-310-darwin.so +0 -0
  82. dbt/compute/jdbc_utils.py +678 -0
  83. dbt/compute/smart_selector.cpython-310-darwin.so +0 -0
  84. dbt/compute/smart_selector.py +311 -0
  85. dbt/compute/strategies/__init__.py +54 -0
  86. dbt/compute/strategies/base.py +165 -0
  87. dbt/compute/strategies/dataproc.py +207 -0
  88. dbt/compute/strategies/emr.py +203 -0
  89. dbt/compute/strategies/local.py +364 -0
  90. dbt/compute/strategies/standalone.py +262 -0
  91. dbt/config/__init__.py +4 -0
  92. dbt/config/catalogs.py +94 -0
  93. dbt/config/compute.cpython-310-darwin.so +0 -0
  94. dbt/config/compute.py +547 -0
  95. dbt/config/dvt_profile.cpython-310-darwin.so +0 -0
  96. dbt/config/dvt_profile.py +342 -0
  97. dbt/config/profile.py +422 -0
  98. dbt/config/project.py +873 -0
  99. dbt/config/project_utils.py +28 -0
  100. dbt/config/renderer.py +231 -0
  101. dbt/config/runtime.py +553 -0
  102. dbt/config/selectors.py +208 -0
  103. dbt/config/utils.py +77 -0
  104. dbt/constants.py +28 -0
  105. dbt/context/__init__.py +0 -0
  106. dbt/context/base.py +745 -0
  107. dbt/context/configured.py +135 -0
  108. dbt/context/context_config.py +382 -0
  109. dbt/context/docs.py +82 -0
  110. dbt/context/exceptions_jinja.py +178 -0
  111. dbt/context/macro_resolver.py +195 -0
  112. dbt/context/macros.py +171 -0
  113. dbt/context/manifest.py +72 -0
  114. dbt/context/providers.py +2249 -0
  115. dbt/context/query_header.py +13 -0
  116. dbt/context/secret.py +58 -0
  117. dbt/context/target.py +74 -0
  118. dbt/contracts/__init__.py +0 -0
  119. dbt/contracts/files.py +413 -0
  120. dbt/contracts/graph/__init__.py +0 -0
  121. dbt/contracts/graph/manifest.py +1904 -0
  122. dbt/contracts/graph/metrics.py +97 -0
  123. dbt/contracts/graph/model_config.py +70 -0
  124. dbt/contracts/graph/node_args.py +42 -0
  125. dbt/contracts/graph/nodes.py +1806 -0
  126. dbt/contracts/graph/semantic_manifest.py +232 -0
  127. dbt/contracts/graph/unparsed.py +811 -0
  128. dbt/contracts/project.py +417 -0
  129. dbt/contracts/results.py +53 -0
  130. dbt/contracts/selection.py +23 -0
  131. dbt/contracts/sql.py +85 -0
  132. dbt/contracts/state.py +68 -0
  133. dbt/contracts/util.py +46 -0
  134. dbt/deprecations.py +346 -0
  135. dbt/deps/__init__.py +0 -0
  136. dbt/deps/base.py +152 -0
  137. dbt/deps/git.py +195 -0
  138. dbt/deps/local.py +79 -0
  139. dbt/deps/registry.py +130 -0
  140. dbt/deps/resolver.py +149 -0
  141. dbt/deps/tarball.py +120 -0
  142. dbt/docs/source/_ext/dbt_click.py +119 -0
  143. dbt/docs/source/conf.py +32 -0
  144. dbt/env_vars.py +64 -0
  145. dbt/event_time/event_time.py +40 -0
  146. dbt/event_time/sample_window.py +60 -0
  147. dbt/events/__init__.py +15 -0
  148. dbt/events/base_types.py +36 -0
  149. dbt/events/core_types_pb2.py +2 -0
  150. dbt/events/logging.py +108 -0
  151. dbt/events/types.py +2516 -0
  152. dbt/exceptions.py +1486 -0
  153. dbt/flags.py +89 -0
  154. dbt/graph/__init__.py +11 -0
  155. dbt/graph/cli.py +247 -0
  156. dbt/graph/graph.py +172 -0
  157. dbt/graph/queue.py +214 -0
  158. dbt/graph/selector.py +374 -0
  159. dbt/graph/selector_methods.py +975 -0
  160. dbt/graph/selector_spec.py +222 -0
  161. dbt/graph/thread_pool.py +18 -0
  162. dbt/hooks.py +21 -0
  163. dbt/include/README.md +49 -0
  164. dbt/include/__init__.py +3 -0
  165. dbt/include/starter_project/.gitignore +4 -0
  166. dbt/include/starter_project/README.md +15 -0
  167. dbt/include/starter_project/__init__.py +3 -0
  168. dbt/include/starter_project/analyses/.gitkeep +0 -0
  169. dbt/include/starter_project/dbt_project.yml +36 -0
  170. dbt/include/starter_project/macros/.gitkeep +0 -0
  171. dbt/include/starter_project/models/example/my_first_dbt_model.sql +27 -0
  172. dbt/include/starter_project/models/example/my_second_dbt_model.sql +6 -0
  173. dbt/include/starter_project/models/example/schema.yml +21 -0
  174. dbt/include/starter_project/seeds/.gitkeep +0 -0
  175. dbt/include/starter_project/snapshots/.gitkeep +0 -0
  176. dbt/include/starter_project/tests/.gitkeep +0 -0
  177. dbt/internal_deprecations.py +26 -0
  178. dbt/jsonschemas/__init__.py +3 -0
  179. dbt/jsonschemas/jsonschemas.py +309 -0
  180. dbt/jsonschemas/project/0.0.110.json +4717 -0
  181. dbt/jsonschemas/project/0.0.85.json +2015 -0
  182. dbt/jsonschemas/resources/0.0.110.json +2636 -0
  183. dbt/jsonschemas/resources/0.0.85.json +2536 -0
  184. dbt/jsonschemas/resources/latest.json +6773 -0
  185. dbt/links.py +4 -0
  186. dbt/materializations/__init__.py +0 -0
  187. dbt/materializations/incremental/__init__.py +0 -0
  188. dbt/materializations/incremental/microbatch.py +236 -0
  189. dbt/mp_context.py +8 -0
  190. dbt/node_types.py +37 -0
  191. dbt/parser/__init__.py +23 -0
  192. dbt/parser/analysis.py +21 -0
  193. dbt/parser/base.py +548 -0
  194. dbt/parser/common.py +266 -0
  195. dbt/parser/docs.py +52 -0
  196. dbt/parser/fixtures.py +51 -0
  197. dbt/parser/functions.py +30 -0
  198. dbt/parser/generic_test.py +100 -0
  199. dbt/parser/generic_test_builders.py +333 -0
  200. dbt/parser/hooks.py +118 -0
  201. dbt/parser/macros.py +137 -0
  202. dbt/parser/manifest.py +2204 -0
  203. dbt/parser/models.py +573 -0
  204. dbt/parser/partial.py +1178 -0
  205. dbt/parser/read_files.py +445 -0
  206. dbt/parser/schema_generic_tests.py +422 -0
  207. dbt/parser/schema_renderer.py +111 -0
  208. dbt/parser/schema_yaml_readers.py +935 -0
  209. dbt/parser/schemas.py +1466 -0
  210. dbt/parser/search.py +149 -0
  211. dbt/parser/seeds.py +28 -0
  212. dbt/parser/singular_test.py +20 -0
  213. dbt/parser/snapshots.py +44 -0
  214. dbt/parser/sources.py +558 -0
  215. dbt/parser/sql.py +62 -0
  216. dbt/parser/unit_tests.py +621 -0
  217. dbt/plugins/__init__.py +20 -0
  218. dbt/plugins/contracts.py +9 -0
  219. dbt/plugins/exceptions.py +2 -0
  220. dbt/plugins/manager.py +163 -0
  221. dbt/plugins/manifest.py +21 -0
  222. dbt/profiler.py +20 -0
  223. dbt/py.typed +1 -0
  224. dbt/query_analyzer.cpython-310-darwin.so +0 -0
  225. dbt/query_analyzer.py +410 -0
  226. dbt/runners/__init__.py +2 -0
  227. dbt/runners/exposure_runner.py +7 -0
  228. dbt/runners/no_op_runner.py +45 -0
  229. dbt/runners/saved_query_runner.py +7 -0
  230. dbt/selected_resources.py +8 -0
  231. dbt/task/__init__.py +0 -0
  232. dbt/task/base.py +503 -0
  233. dbt/task/build.py +197 -0
  234. dbt/task/clean.py +56 -0
  235. dbt/task/clone.py +161 -0
  236. dbt/task/compile.py +150 -0
  237. dbt/task/compute.py +454 -0
  238. dbt/task/debug.py +505 -0
  239. dbt/task/deps.py +280 -0
  240. dbt/task/docs/__init__.py +3 -0
  241. dbt/task/docs/generate.py +660 -0
  242. dbt/task/docs/index.html +250 -0
  243. dbt/task/docs/serve.py +29 -0
  244. dbt/task/freshness.py +322 -0
  245. dbt/task/function.py +121 -0
  246. dbt/task/group_lookup.py +46 -0
  247. dbt/task/init.py +553 -0
  248. dbt/task/java.py +316 -0
  249. dbt/task/list.py +236 -0
  250. dbt/task/printer.py +175 -0
  251. dbt/task/retry.py +175 -0
  252. dbt/task/run.py +1306 -0
  253. dbt/task/run_operation.py +141 -0
  254. dbt/task/runnable.py +758 -0
  255. dbt/task/seed.py +103 -0
  256. dbt/task/show.py +149 -0
  257. dbt/task/snapshot.py +56 -0
  258. dbt/task/spark.py +414 -0
  259. dbt/task/sql.py +110 -0
  260. dbt/task/target_sync.py +759 -0
  261. dbt/task/test.py +464 -0
  262. dbt/tests/fixtures/__init__.py +1 -0
  263. dbt/tests/fixtures/project.py +620 -0
  264. dbt/tests/util.py +651 -0
  265. dbt/tracking.py +529 -0
  266. dbt/utils/__init__.py +3 -0
  267. dbt/utils/artifact_upload.py +151 -0
  268. dbt/utils/utils.py +408 -0
  269. dbt/version.py +268 -0
  270. dvt_cli/__init__.py +72 -0
  271. dvt_core-0.52.2.dist-info/METADATA +286 -0
  272. dvt_core-0.52.2.dist-info/RECORD +275 -0
  273. dvt_core-0.52.2.dist-info/WHEEL +5 -0
  274. dvt_core-0.52.2.dist-info/entry_points.txt +2 -0
  275. dvt_core-0.52.2.dist-info/top_level.txt +2 -0
dbt/parser/base.py ADDED
@@ -0,0 +1,548 @@
1
+ import abc
2
+ import itertools
3
+ import os
4
+ from typing import Any, Dict, Generic, List, Optional, TypeVar
5
+
6
+ from dbt import deprecations, hooks, utils
7
+ from dbt.adapters.factory import get_adapter # noqa: F401
8
+ from dbt.artifacts.resources import Contract
9
+ from dbt.clients.jinja import MacroGenerator, get_rendered
10
+ from dbt.config import RuntimeConfig
11
+ from dbt.context.context_config import ContextConfig
12
+ from dbt.context.providers import (
13
+ generate_generate_name_macro_context,
14
+ generate_parser_model_context,
15
+ )
16
+ from dbt.contracts.files import SchemaSourceFile
17
+ from dbt.contracts.graph.manifest import Manifest
18
+ from dbt.contracts.graph.nodes import BaseNode, ManifestNode
19
+ from dbt.contracts.graph.unparsed import Docs, UnparsedNode
20
+ from dbt.exceptions import (
21
+ ConfigUpdateError,
22
+ DbtInternalError,
23
+ DictParseError,
24
+ InvalidAccessTypeError,
25
+ )
26
+ from dbt.flags import get_flags
27
+ from dbt.jsonschemas.jsonschemas import validate_model_config
28
+ from dbt.node_types import AccessType, ModelLanguage, NodeType
29
+ from dbt.parser.common import resource_types_to_schema_file_keys
30
+ from dbt.parser.search import FileBlock
31
+ from dbt_common.clients._jinja_blocks import ExtractWarning
32
+ from dbt_common.dataclass_schema import ValidationError
33
+ from dbt_common.events.base_types import EventLevel
34
+ from dbt_common.events.functions import fire_event
35
+ from dbt_common.events.types import Note
36
+ from dbt_common.utils import deep_merge
37
+
38
+ # internally, the parser may store a less-restrictive type that will be
39
+ # transformed into the final type. But it will have to be derived from
40
+ # ParsedNode to be operable.
41
+ FinalValue = TypeVar("FinalValue", bound=BaseNode)
42
+ IntermediateValue = TypeVar("IntermediateValue", bound=BaseNode)
43
+
44
+ FinalNode = TypeVar("FinalNode", bound=ManifestNode)
45
+
46
+
47
+ ConfiguredBlockType = TypeVar("ConfiguredBlockType", bound=FileBlock)
48
+
49
+
50
+ class BaseParser(Generic[FinalValue]):
51
+ def __init__(self, project: RuntimeConfig, manifest: Manifest) -> None:
52
+ self.project: RuntimeConfig = project
53
+ self.manifest: Manifest = manifest
54
+
55
+ @abc.abstractmethod
56
+ def parse_file(self, block: FileBlock) -> None:
57
+ pass
58
+
59
+ @abc.abstractproperty
60
+ def resource_type(self) -> NodeType:
61
+ pass
62
+
63
+ def generate_unique_id(self, resource_name: str, hash: Optional[str] = None) -> str:
64
+ """Returns a unique identifier for a resource
65
+ An optional hash may be passed in to ensure uniqueness for edge cases"""
66
+
67
+ return ".".join(
68
+ filter(None, [self.resource_type, self.project.project_name, resource_name, hash])
69
+ )
70
+
71
+ def _handle_extract_warning(self, warning: ExtractWarning, file: str) -> None:
72
+ deprecations.warn("unexpected-jinja-block-deprecation", msg=warning.msg, file=file)
73
+
74
+
75
+ class Parser(BaseParser[FinalValue], Generic[FinalValue]):
76
+ def __init__(
77
+ self,
78
+ project: RuntimeConfig,
79
+ manifest: Manifest,
80
+ root_project: RuntimeConfig,
81
+ ) -> None:
82
+ super().__init__(project, manifest)
83
+ self.root_project = root_project
84
+
85
+
86
+ class RelationUpdate:
87
+ # "component" is database, schema or alias
88
+ def __init__(self, config: RuntimeConfig, manifest: Manifest, component: str) -> None:
89
+ default_macro = manifest.find_generate_macro_by_name(
90
+ component=component,
91
+ root_project_name=config.project_name,
92
+ )
93
+ if default_macro is None:
94
+ raise DbtInternalError(f"No macro with name generate_{component}_name found")
95
+
96
+ default_macro_context = generate_generate_name_macro_context(
97
+ default_macro, config, manifest
98
+ )
99
+ self.default_updater = MacroGenerator(default_macro, default_macro_context)
100
+
101
+ package_names = config.dependencies.keys() if config.dependencies else {}
102
+ package_updaters = {}
103
+ for package_name in package_names:
104
+ package_macro = manifest.find_generate_macro_by_name(
105
+ component=component,
106
+ root_project_name=config.project_name,
107
+ imported_package=package_name,
108
+ )
109
+ if package_macro:
110
+ imported_macro_context = generate_generate_name_macro_context(
111
+ package_macro, config, manifest
112
+ )
113
+ package_updaters[package_macro.package_name] = MacroGenerator(
114
+ package_macro, imported_macro_context
115
+ )
116
+
117
+ self.package_updaters = package_updaters
118
+ self.component = component
119
+
120
+ def __call__(self, parsed_node: Any, override: Optional[str]) -> None:
121
+ if getattr(parsed_node, "package_name", None) in self.package_updaters:
122
+ new_value = self.package_updaters[parsed_node.package_name](override, parsed_node)
123
+ else:
124
+ new_value = self.default_updater(override, parsed_node)
125
+
126
+ if isinstance(new_value, str):
127
+ new_value = new_value.strip()
128
+ setattr(parsed_node, self.component, new_value)
129
+
130
+
131
+ class ConfiguredParser(
132
+ Parser[FinalNode],
133
+ Generic[ConfiguredBlockType, FinalNode],
134
+ ):
135
+ def __init__(
136
+ self,
137
+ project: RuntimeConfig,
138
+ manifest: Manifest,
139
+ root_project: RuntimeConfig,
140
+ ) -> None:
141
+ super().__init__(project, manifest, root_project)
142
+
143
+ # this sets callables from RelationUpdate
144
+ self._update_node_database = RelationUpdate(
145
+ manifest=manifest, config=root_project, component="database"
146
+ )
147
+ self._update_node_schema = RelationUpdate(
148
+ manifest=manifest, config=root_project, component="schema"
149
+ )
150
+ self._update_node_alias = RelationUpdate(
151
+ manifest=manifest, config=root_project, component="alias"
152
+ )
153
+
154
+ @classmethod
155
+ @abc.abstractmethod
156
+ def get_compiled_path(cls, block: ConfiguredBlockType) -> str:
157
+ pass
158
+
159
+ @abc.abstractmethod
160
+ def parse_from_dict(self, dict, validate=True) -> FinalNode:
161
+ pass
162
+
163
+ @abc.abstractproperty
164
+ def resource_type(self) -> NodeType:
165
+ pass
166
+
167
+ @property
168
+ def default_schema(self):
169
+ return self.root_project.credentials.schema
170
+
171
+ @property
172
+ def default_database(self):
173
+ return self.root_project.credentials.database
174
+
175
+ def get_fqn_prefix(self, path: str) -> List[str]:
176
+ no_ext = os.path.splitext(path)[0]
177
+ fqn = [self.project.project_name]
178
+ fqn.extend(utils.split_path(no_ext)[:-1])
179
+ return fqn
180
+
181
+ def get_fqn(self, path: str, name: str) -> List[str]:
182
+ """Get the FQN for the node. This impacts node selection and config
183
+ application.
184
+ """
185
+ fqn = self.get_fqn_prefix(path)
186
+ fqn.append(name)
187
+ return fqn
188
+
189
+ def _mangle_hooks(self, config):
190
+ """Given a config dict that may have `pre-hook`/`post-hook` keys,
191
+ convert it from the yucky maybe-a-string, maybe-a-dict to a dict.
192
+ """
193
+ # Like most of parsing, this is a horrible hack :(
194
+ for key in hooks.ModelHookType:
195
+ if key in config:
196
+ config[key] = [hooks.get_hook_dict(h) for h in config[key]]
197
+
198
+ def _create_error_node(
199
+ self, name: str, path: str, original_file_path: str, raw_code: str, language: str = "sql"
200
+ ) -> UnparsedNode:
201
+ """If we hit an error before we've actually parsed a node, provide some
202
+ level of useful information by attaching this to the exception.
203
+ """
204
+ # this is a bit silly, but build an UnparsedNode just for error
205
+ # message reasons
206
+ return UnparsedNode(
207
+ name=name,
208
+ resource_type=self.resource_type,
209
+ path=path,
210
+ original_file_path=original_file_path,
211
+ package_name=self.project.project_name,
212
+ raw_code=raw_code,
213
+ language=language,
214
+ )
215
+
216
+ def _create_parsetime_node(
217
+ self,
218
+ block: ConfiguredBlockType,
219
+ path: str,
220
+ config: ContextConfig,
221
+ fqn: List[str],
222
+ name=None,
223
+ **kwargs,
224
+ ) -> FinalNode:
225
+ """Create the node that will be passed in to the parser context for
226
+ "rendering". Some information may be partial, as it'll be updated by
227
+ config() and any ref()/source() calls discovered during rendering.
228
+ """
229
+ if name is None:
230
+ name = block.name
231
+ if block.path.relative_path.endswith(".py"):
232
+ language = ModelLanguage.python
233
+ else:
234
+ # this is not ideal but we have a lot of tests to adjust if don't do it
235
+ language = ModelLanguage.sql
236
+
237
+ dct = {
238
+ "alias": name,
239
+ "schema": self.default_schema,
240
+ "database": self.default_database,
241
+ "fqn": fqn,
242
+ "name": name,
243
+ "resource_type": self.resource_type,
244
+ "path": path,
245
+ "original_file_path": block.path.original_file_path,
246
+ "package_name": self.project.project_name,
247
+ "raw_code": block.contents or "",
248
+ "language": language,
249
+ "unique_id": self.generate_unique_id(name),
250
+ "config": self.config_dict(config),
251
+ "checksum": block.file.checksum.to_dict(omit_none=True),
252
+ }
253
+ dct.update(kwargs)
254
+
255
+ # TODO: we're doing this becaus return type is _required_ for the FunctionNode
256
+ # but we don't get the return type until we patch the node with the yml definition
257
+ # so we need to set it to a default value here.
258
+ if self.resource_type == NodeType.Function:
259
+ dct["returns"] = {"data_type": "INVALID_TYPE"}
260
+
261
+ try:
262
+ return self.parse_from_dict(dct, validate=True)
263
+ except ValidationError as exc:
264
+ # this is a bit silly, but build an UnparsedNode just for error
265
+ # message reasons
266
+ node = self._create_error_node(
267
+ name=block.name,
268
+ path=path,
269
+ original_file_path=block.path.original_file_path,
270
+ raw_code=block.contents,
271
+ )
272
+ raise DictParseError(exc, node=node)
273
+
274
+ def _context_for(self, parsed_node: FinalNode, config: ContextConfig) -> Dict[str, Any]:
275
+ return generate_parser_model_context(parsed_node, self.root_project, self.manifest, config)
276
+
277
+ def render_with_context(self, parsed_node: FinalNode, config: ContextConfig):
278
+ # Given the parsed node and a ContextConfig to use during parsing,
279
+ # render the node's sql with macro capture enabled.
280
+ # Note: this mutates the config object when config calls are rendered.
281
+ context = self._context_for(parsed_node, config)
282
+
283
+ # this goes through the process of rendering, but just throws away
284
+ # the rendered result. The "macro capture" is the point?
285
+ get_rendered(parsed_node.raw_code, context, parsed_node, capture_macros=True)
286
+ return context
287
+
288
+ # This is taking the original config for the node, converting it to a dict,
289
+ # updating the config with new config passed in, then re-creating the
290
+ # config from the dict in the node.
291
+ def update_parsed_node_config_dict(
292
+ self, parsed_node: FinalNode, config_dict: Dict[str, Any]
293
+ ) -> None:
294
+ # Overwrite node config
295
+ final_config_dict = parsed_node.config.to_dict(omit_none=True)
296
+ final_config_dict.update({k.strip(): v for (k, v) in config_dict.items()})
297
+ # re-mangle hooks, in case we got new ones
298
+ self._mangle_hooks(final_config_dict)
299
+ parsed_node.config = parsed_node.config.from_dict(final_config_dict)
300
+
301
+ def update_parsed_node_relation_names(
302
+ self, parsed_node: FinalNode, config_dict: Dict[str, Any]
303
+ ) -> None:
304
+
305
+ # These call the RelationUpdate callable to go through generate_name macros
306
+ self._update_node_database(parsed_node, config_dict.get("database"))
307
+ self._update_node_schema(parsed_node, config_dict.get("schema"))
308
+ if parsed_node.schema is None:
309
+ fire_event(
310
+ Note(
311
+ msg=f"Node schema set to None from generate_schema_name call for node '{parsed_node.unique_id}'."
312
+ ),
313
+ level=EventLevel.DEBUG,
314
+ )
315
+
316
+ self._update_node_alias(parsed_node, config_dict.get("alias"))
317
+
318
+ # Snapshot nodes use special "target_database" and "target_schema" fields
319
+ # for backward compatibility
320
+ # We have to do getattr here because saved_query parser calls this method with
321
+ # Export object instead of a node.
322
+ if getattr(parsed_node, "resource_type", None) == NodeType.Snapshot:
323
+ if "target_database" in config_dict and config_dict["target_database"]:
324
+ parsed_node.database = config_dict["target_database"]
325
+ if "target_schema" in config_dict and config_dict["target_schema"]:
326
+ parsed_node.schema = config_dict["target_schema"]
327
+
328
+ self._update_node_relation_name(parsed_node)
329
+
330
+ def update_parsed_node_config(
331
+ self,
332
+ parsed_node: FinalNode,
333
+ config: ContextConfig,
334
+ context=None,
335
+ patch_config_dict=None,
336
+ patch_file_id=None,
337
+ validate_config_call_dict: bool = False,
338
+ ) -> None:
339
+ """Given the ContextConfig used for parsing and the parsed node,
340
+ generate and set the true values to use, overriding the temporary parse
341
+ values set in _build_intermediate_parsed_node.
342
+ """
343
+
344
+ # build_config_dict takes the config_call_dict in the ContextConfig object
345
+ # and calls calculate_node_config to combine dbt_project configs and
346
+ # config calls from SQL files, plus patch configs (from schema files)
347
+ # This normalize the config for a model node due #8520; should be improved latter
348
+ if not patch_config_dict:
349
+ patch_config_dict = {}
350
+ if (
351
+ parsed_node.resource_type == NodeType.Model
352
+ and parsed_node.language == ModelLanguage.python
353
+ ):
354
+ if "materialized" not in patch_config_dict:
355
+ patch_config_dict["materialized"] = "table"
356
+ config_dict = config.build_config_dict(patch_config_dict=patch_config_dict)
357
+
358
+ # Set tags on node provided in config blocks. Tags are additive, so even if
359
+ # config has been built before, we don't have to reset tags in the parsed_node.
360
+ model_tags = config_dict.get("tags", [])
361
+ for tag in model_tags:
362
+ if tag not in parsed_node.tags:
363
+ parsed_node.tags.append(tag)
364
+
365
+ # If we have meta in the config, copy to node level, for backwards
366
+ # compatibility with earlier node-only config.
367
+ if "meta" in config_dict and config_dict["meta"]:
368
+ parsed_node.meta = config_dict["meta"]
369
+
370
+ # If we have group in the config, copy to node level
371
+ if "group" in config_dict and config_dict["group"]:
372
+ parsed_node.group = config_dict["group"]
373
+
374
+ # If we have access in the config, copy to node level
375
+ if parsed_node.resource_type == NodeType.Model and config_dict.get("access", None):
376
+ if AccessType.is_valid(config_dict["access"]):
377
+ assert hasattr(parsed_node, "access")
378
+ parsed_node.access = AccessType(config_dict["access"])
379
+ else:
380
+ raise InvalidAccessTypeError(
381
+ unique_id=parsed_node.unique_id, field_value=config_dict["access"]
382
+ )
383
+
384
+ # If we have docs in the config, merge with the node level, for backwards
385
+ # compatibility with earlier node-only config.
386
+ if "docs" in config_dict and config_dict["docs"]:
387
+ # we set show at the value of the config if it is set, otherwise, inherit the value
388
+ docs_show = (
389
+ config_dict["docs"]["show"]
390
+ if "show" in config_dict["docs"]
391
+ else parsed_node.docs.show
392
+ )
393
+ if "node_color" in config_dict["docs"]:
394
+ parsed_node.docs = Docs(
395
+ show=docs_show, node_color=config_dict["docs"]["node_color"]
396
+ )
397
+ else:
398
+ parsed_node.docs = Docs(show=docs_show)
399
+
400
+ # If we have contract in the config, copy to node level
401
+ if "contract" in config_dict and config_dict["contract"]:
402
+ contract_dct = config_dict["contract"]
403
+ Contract.validate(contract_dct)
404
+ # Seed node has contract config (from NodeConfig) but no contract in SeedNode
405
+ if hasattr(parsed_node, "contract"):
406
+ parsed_node.contract = Contract.from_dict(contract_dct)
407
+
408
+ if get_flags().state_modified_compare_more_unrendered_values:
409
+ # Use the patch_file.unrendered_configs if available to update patch_dict_config,
410
+ # as provided patch_config_dict may actually already be rendered and thus sensitive to jinja evaluations
411
+ if patch_file_id:
412
+ patch_file = self.manifest.files.get(patch_file_id, None)
413
+ if patch_file and isinstance(patch_file, SchemaSourceFile):
414
+ schema_key = resource_types_to_schema_file_keys.get(parsed_node.resource_type)
415
+ if schema_key:
416
+ if unrendered_patch_config := patch_file.get_unrendered_config(
417
+ schema_key, parsed_node.name, getattr(parsed_node, "version", None)
418
+ ):
419
+ patch_config_dict = deep_merge(
420
+ patch_config_dict, unrendered_patch_config
421
+ )
422
+
423
+ # unrendered_config is used to compare the original database/schema/alias
424
+ # values and to handle 'same_config' and 'same_contents' calls
425
+ parsed_node.unrendered_config = config.build_config_dict(
426
+ rendered=False, patch_config_dict=patch_config_dict
427
+ )
428
+
429
+ # We validate the _config_call_dict here because there is more than
430
+ # one way that the _config_call_dict can be set and also, later it gets
431
+ # read multiple times. Doing the validation here ensures that the config
432
+ # is only validated once.
433
+ if parsed_node.resource_type == NodeType.Model and validate_config_call_dict:
434
+ validate_model_config(config._config_call_dict, parsed_node.original_file_path)
435
+
436
+ parsed_node.config_call_dict = config._config_call_dict
437
+ parsed_node.unrendered_config_call_dict = config._unrendered_config_call_dict
438
+
439
+ # do this once before we parse the node database/schema/alias, so
440
+ # parsed_node.config is what it would be if they did nothing
441
+ self.update_parsed_node_config_dict(parsed_node, config_dict)
442
+ # This updates the node database/schema/alias/relation_name
443
+ self.update_parsed_node_relation_names(parsed_node, config_dict)
444
+
445
+ # tests don't have hooks
446
+ if parsed_node.resource_type == NodeType.Test:
447
+ return
448
+
449
+ # at this point, we've collected our hooks. Use the node context to
450
+ # render each hook and collect refs/sources
451
+ assert hasattr(parsed_node.config, "pre_hook") and hasattr(parsed_node.config, "post_hook")
452
+ hooks = list(itertools.chain(parsed_node.config.pre_hook, parsed_node.config.post_hook))
453
+ # skip context rebuilding if there aren't any hooks
454
+ if not hooks:
455
+ return
456
+ if not context:
457
+ context = self._context_for(parsed_node, config)
458
+ for hook in hooks:
459
+ get_rendered(hook.sql, context, parsed_node, capture_macros=True)
460
+
461
+ def initial_config(self, fqn: List[str]) -> ContextConfig:
462
+ config_version = min([self.project.config_version, self.root_project.config_version])
463
+ if config_version == 2:
464
+ return ContextConfig(
465
+ self.root_project,
466
+ fqn,
467
+ self.resource_type,
468
+ self.project.project_name,
469
+ )
470
+ else:
471
+ raise DbtInternalError(
472
+ f"Got an unexpected project version={config_version}, expected 2"
473
+ )
474
+
475
+ def config_dict(
476
+ self,
477
+ config: ContextConfig,
478
+ ) -> Dict[str, Any]:
479
+ config_dict = config.build_config_dict(base=True)
480
+ self._mangle_hooks(config_dict)
481
+ return config_dict
482
+
483
+ def render_update(
484
+ self, node: FinalNode, config: ContextConfig, validate_config_call_dict: bool = False
485
+ ) -> None:
486
+ try:
487
+ context = self.render_with_context(node, config)
488
+ self.update_parsed_node_config(
489
+ node, config, context=context, validate_config_call_dict=validate_config_call_dict
490
+ )
491
+ except ValidationError as exc:
492
+ # we got a ValidationError - probably bad types in config()
493
+ raise ConfigUpdateError(exc, node=node) from exc
494
+
495
+ def add_result_node(self, block: FileBlock, node: ManifestNode):
496
+ if node.config.enabled:
497
+ self.manifest.add_node(block.file, node)
498
+ else:
499
+ self.manifest.add_disabled(block.file, node)
500
+
501
+ def parse_node(self, block: ConfiguredBlockType) -> FinalNode:
502
+ compiled_path: str = self.get_compiled_path(block)
503
+ fqn = self.get_fqn(compiled_path, block.name)
504
+
505
+ config: ContextConfig = self.initial_config(fqn)
506
+
507
+ node = self._create_parsetime_node(
508
+ block=block,
509
+ path=compiled_path,
510
+ config=config,
511
+ fqn=fqn,
512
+ )
513
+ self.render_update(node, config)
514
+ self.add_result_node(block, node)
515
+ return node
516
+
517
+ def _update_node_relation_name(self, node: ManifestNode):
518
+ # Seed and Snapshot nodes and Models that are not ephemeral,
519
+ # and TestNodes that store_failures.
520
+ # TestNodes do not get a relation_name without store failures
521
+ # because no schema is created.
522
+ if getattr(node, "is_relational", None) and not getattr(node, "is_ephemeral_model", None):
523
+ adapter = get_adapter(self.root_project)
524
+ relation_cls = adapter.Relation
525
+ node.relation_name = str(relation_cls.create_from(self.root_project, node))
526
+ else:
527
+ # Set it to None in case it changed with a config update
528
+ node.relation_name = None
529
+
530
+ @abc.abstractmethod
531
+ def parse_file(self, file_block: FileBlock) -> None:
532
+ pass
533
+
534
+
535
+ class SimpleParser(
536
+ ConfiguredParser[ConfiguredBlockType, FinalNode],
537
+ Generic[ConfiguredBlockType, FinalNode],
538
+ ):
539
+ pass
540
+
541
+
542
+ class SQLParser(ConfiguredParser[FileBlock, FinalNode], Generic[FinalNode]):
543
+ def parse_file(self, file_block: FileBlock) -> None:
544
+ self.parse_node(file_block)
545
+
546
+
547
+ class SimpleSQLParser(SQLParser[FinalNode]):
548
+ pass