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/config/profile.py ADDED
@@ -0,0 +1,422 @@
1
+ import os
2
+ from dataclasses import dataclass
3
+ from typing import Any, Dict, Optional, Tuple
4
+
5
+ from dbt.adapters.contracts.connection import Credentials, HasCredentials
6
+ from dbt.clients.yaml_helper import load_yaml_text
7
+ from dbt.contracts.project import ProfileConfig
8
+ from dbt.events.types import MissingProfileTarget
9
+ from dbt.exceptions import (
10
+ CompilationError,
11
+ DbtProfileError,
12
+ DbtProjectError,
13
+ DbtRuntimeError,
14
+ ProfileConfigError,
15
+ )
16
+ from dbt.flags import get_flags
17
+ from dbt_common.clients.system import load_file_contents
18
+ from dbt_common.dataclass_schema import ValidationError
19
+ from dbt_common.events.functions import fire_event
20
+ from dbt_common.exceptions import DbtValidationError
21
+
22
+ from .renderer import ProfileRenderer
23
+
24
+ DEFAULT_THREADS = 1
25
+
26
+ INVALID_PROFILE_MESSAGE = """
27
+ dbt encountered an error while trying to read your profiles.yml file.
28
+
29
+ {error_string}
30
+ """
31
+
32
+
33
+ def read_profile(profiles_dir: str) -> Dict[str, Any]:
34
+ path = os.path.join(profiles_dir, "profiles.yml")
35
+
36
+ contents = None
37
+ if os.path.isfile(path):
38
+ try:
39
+ contents = load_file_contents(path, strip=False)
40
+ yaml_content = load_yaml_text(contents)
41
+ if not yaml_content:
42
+ msg = f"The profiles.yml file at {path} is empty"
43
+ raise DbtProfileError(INVALID_PROFILE_MESSAGE.format(error_string=msg))
44
+
45
+ return yaml_content
46
+ except DbtValidationError as e:
47
+ msg = INVALID_PROFILE_MESSAGE.format(error_string=e)
48
+ raise DbtValidationError(msg) from e
49
+
50
+ return {}
51
+
52
+
53
+ # The Profile class is included in RuntimeConfig, so any attribute
54
+ # additions must also be set where the RuntimeConfig class is created
55
+ # `init=False` is a workaround for https://bugs.python.org/issue45081
56
+ @dataclass(init=False)
57
+ class Profile(HasCredentials):
58
+ profile_name: str
59
+ target_name: str
60
+ threads: int
61
+ credentials: Credentials
62
+ profile_env_vars: Dict[str, Any]
63
+ log_cache_events: bool
64
+
65
+ def __init__(
66
+ self,
67
+ profile_name: str,
68
+ target_name: str,
69
+ threads: int,
70
+ credentials: Credentials,
71
+ ) -> None:
72
+ """
73
+ TODO: Is this no longer needed now that 3.9 is no longer supported?
74
+ Explicitly defining `__init__` to work around bug in Python 3.9.7
75
+ https://bugs.python.org/issue45081
76
+ """
77
+ self.profile_name = profile_name
78
+ self.target_name = target_name
79
+ self.threads = threads
80
+ self.credentials = credentials
81
+ self.profile_env_vars = {} # never available on init
82
+ self.log_cache_events = (
83
+ get_flags().LOG_CACHE_EVENTS
84
+ ) # never available on init, set for adapter instantiation via AdapterRequiredConfig
85
+
86
+ def to_profile_info(self, serialize_credentials: bool = False) -> Dict[str, Any]:
87
+ """Unlike to_project_config, this dict is not a mirror of any existing
88
+ on-disk data structure. It's used when creating a new profile from an
89
+ existing one.
90
+
91
+ :param serialize_credentials bool: If True, serialize the credentials.
92
+ Otherwise, the Credentials object will be copied.
93
+ :returns dict: The serialized profile.
94
+ """
95
+ result = {
96
+ "profile_name": self.profile_name,
97
+ "target_name": self.target_name,
98
+ "threads": self.threads,
99
+ "credentials": self.credentials,
100
+ }
101
+ if serialize_credentials:
102
+ result["credentials"] = self.credentials.to_dict(omit_none=True)
103
+ return result
104
+
105
+ def to_target_dict(self) -> Dict[str, Any]:
106
+ target = dict(self.credentials.connection_info(with_aliases=True))
107
+ target.update(
108
+ {
109
+ "type": self.credentials.type,
110
+ "threads": self.threads,
111
+ "name": self.target_name,
112
+ "target_name": self.target_name,
113
+ "profile_name": self.profile_name,
114
+ }
115
+ )
116
+ return target
117
+
118
+ def __eq__(self, other: object) -> bool:
119
+ if not (isinstance(other, self.__class__) and isinstance(self, other.__class__)):
120
+ return NotImplemented
121
+ return self.to_profile_info() == other.to_profile_info()
122
+
123
+ def validate(self):
124
+ try:
125
+ if self.credentials:
126
+ dct = self.credentials.to_dict(omit_none=True)
127
+ self.credentials.validate(dct)
128
+ dct = self.to_profile_info(serialize_credentials=True)
129
+ ProfileConfig.validate(dct)
130
+ except ValidationError as exc:
131
+ raise ProfileConfigError(exc) from exc
132
+
133
+ @staticmethod
134
+ def _credentials_from_profile(
135
+ profile: Dict[str, Any], profile_name: str, target_name: str
136
+ ) -> Credentials:
137
+ # avoid an import cycle
138
+ from dbt.adapters.factory import load_plugin
139
+
140
+ # credentials carry their 'type' in their actual type, not their
141
+ # attributes. We do want this in order to pick our Credentials class.
142
+ if "type" not in profile:
143
+ raise DbtProfileError(
144
+ 'required field "type" not found in profile {} and target {}'.format(
145
+ profile_name, target_name
146
+ )
147
+ )
148
+
149
+ typename = profile.pop("type")
150
+ try:
151
+ cls = load_plugin(typename)
152
+ data = cls.translate_aliases(profile)
153
+ cls.validate(data)
154
+ credentials = cls.from_dict(data)
155
+ except (DbtRuntimeError, ValidationError) as e:
156
+ msg = str(e) if isinstance(e, DbtRuntimeError) else e.message
157
+ raise DbtProfileError(
158
+ 'Credentials in profile "{}", target "{}" invalid: {}'.format(
159
+ profile_name, target_name, msg
160
+ )
161
+ ) from e
162
+
163
+ return credentials
164
+
165
+ @staticmethod
166
+ def pick_profile_name(
167
+ args_profile_name: Optional[str],
168
+ project_profile_name: Optional[str] = None,
169
+ ) -> str:
170
+ # TODO: Duplicating this method as direct copy of the implementation in dbt.cli.resolvers
171
+ # dbt.cli.resolvers implementation can't be used because it causes a circular dependency.
172
+ # This should be removed and use a safe default access on the Flags module when
173
+ # https://github.com/dbt-labs/dbt-core/issues/6259 is closed.
174
+ def default_profiles_dir():
175
+ from pathlib import Path
176
+
177
+ # DVT uses .dvt/ directory - NO fallback to .dbt/
178
+ cwd = Path.cwd()
179
+ home = Path.home()
180
+
181
+ # Priority: 1. CWD with profiles.yml, 2. CWD/.dvt/, 3. ~/.dvt/
182
+ if (cwd / "profiles.yml").exists():
183
+ return cwd
184
+ elif (cwd / ".dvt" / "profiles.yml").exists():
185
+ return cwd / ".dvt"
186
+ else:
187
+ # DVT always uses ~/.dvt/ - use 'dvt migrate' to move from ~/.dbt/
188
+ return home / ".dvt"
189
+
190
+ profile_name = project_profile_name
191
+ if args_profile_name is not None:
192
+ profile_name = args_profile_name
193
+ if profile_name is None:
194
+ NO_SUPPLIED_PROFILE_ERROR = """\
195
+ dbt cannot run because no profile was specified for this dbt project.
196
+ To specify a profile for this project, add a line like the this to
197
+ your dbt_project.yml file:
198
+
199
+ profile: [profile name]
200
+
201
+ Here, [profile name] should be replaced with a profile name
202
+ defined in your profiles.yml file. You can find profiles.yml here:
203
+
204
+ {profiles_file}/profiles.yml
205
+ """.format(
206
+ profiles_file=default_profiles_dir()
207
+ )
208
+ raise DbtProjectError(NO_SUPPLIED_PROFILE_ERROR)
209
+ return profile_name
210
+
211
+ @staticmethod
212
+ def _get_profile_data(
213
+ profile: Dict[str, Any], profile_name: str, target_name: str
214
+ ) -> Dict[str, Any]:
215
+ if "outputs" not in profile:
216
+ raise DbtProfileError("outputs not specified in profile '{}'".format(profile_name))
217
+ outputs = profile["outputs"]
218
+
219
+ if target_name not in outputs:
220
+ outputs = "\n".join(" - {}".format(output) for output in outputs)
221
+ msg = (
222
+ "The profile '{}' does not have a target named '{}'. The "
223
+ "valid target names for this profile are:\n{}".format(
224
+ profile_name, target_name, outputs
225
+ )
226
+ )
227
+ raise DbtProfileError(msg, result_type="invalid_target")
228
+ profile_data = outputs[target_name]
229
+
230
+ if not isinstance(profile_data, dict):
231
+ msg = (
232
+ f"output '{target_name}' of profile '{profile_name}' is "
233
+ f"misconfigured in profiles.yml"
234
+ )
235
+ raise DbtProfileError(msg, result_type="invalid_target")
236
+
237
+ return profile_data
238
+
239
+ @classmethod
240
+ def from_credentials(
241
+ cls,
242
+ credentials: Credentials,
243
+ threads: int,
244
+ profile_name: str,
245
+ target_name: str,
246
+ ) -> "Profile":
247
+ """Create a profile from an existing set of Credentials and the
248
+ remaining information.
249
+
250
+ :param credentials: The credentials dict for this profile.
251
+ :param threads: The number of threads to use for connections.
252
+ :param profile_name: The profile name used for this profile.
253
+ :param target_name: The target name used for this profile.
254
+ :raises DbtProfileError: If the profile is invalid.
255
+ :returns: The new Profile object.
256
+ """
257
+
258
+ profile = cls(
259
+ profile_name=profile_name,
260
+ target_name=target_name,
261
+ threads=threads,
262
+ credentials=credentials,
263
+ )
264
+ profile.validate()
265
+ return profile
266
+
267
+ @classmethod
268
+ def render_profile(
269
+ cls,
270
+ raw_profile: Dict[str, Any],
271
+ profile_name: str,
272
+ target_override: Optional[str],
273
+ renderer: ProfileRenderer,
274
+ ) -> Tuple[str, Dict[str, Any]]:
275
+ """This is a containment zone for the hateful way we're rendering
276
+ profiles.
277
+ """
278
+ # rendering profiles is a bit complex. Two constraints cause trouble:
279
+ # 1) users should be able to use environment/cli variables to specify
280
+ # the target in their profile.
281
+ # 2) Missing environment/cli variables in profiles/targets that don't
282
+ # end up getting selected should not cause errors.
283
+ # so first we'll just render the target name, then we use that rendered
284
+ # name to extract a profile that we can render.
285
+ if target_override is not None:
286
+ target_name = target_override
287
+ elif "target" in raw_profile:
288
+ # render the target if it was parsed from yaml
289
+ target_name = renderer.render_value(raw_profile["target"])
290
+ else:
291
+ target_name = "default"
292
+ fire_event(MissingProfileTarget(profile_name=profile_name, target_name=target_name))
293
+
294
+ raw_profile_data = cls._get_profile_data(raw_profile, profile_name, target_name)
295
+
296
+ try:
297
+ profile_data = renderer.render_data(raw_profile_data)
298
+ except CompilationError as exc:
299
+ raise DbtProfileError(str(exc)) from exc
300
+ return target_name, profile_data
301
+
302
+ @classmethod
303
+ def from_raw_profile_info(
304
+ cls,
305
+ raw_profile: Dict[str, Any],
306
+ profile_name: str,
307
+ renderer: ProfileRenderer,
308
+ target_override: Optional[str] = None,
309
+ threads_override: Optional[int] = None,
310
+ ) -> "Profile":
311
+ """Create a profile from its raw profile information.
312
+
313
+ (this is an intermediate step, mostly useful for unit testing)
314
+
315
+ :param raw_profile: The profile data for a single profile, from
316
+ disk as yaml and its values rendered with jinja.
317
+ :param profile_name: The profile name used.
318
+ :param renderer: The config renderer.
319
+ :param target_override: The target to use, if provided on
320
+ the command line.
321
+ :param threads_override: The thread count to use, if
322
+ provided on the command line.
323
+ :raises DbtProfileError: If the profile is invalid or missing, or the
324
+ target could not be found
325
+ :returns: The new Profile object.
326
+ """
327
+ # TODO: should it be, and the values coerced to bool?
328
+ target_name, profile_data = cls.render_profile(
329
+ raw_profile, profile_name, target_override, renderer
330
+ )
331
+
332
+ # valid connections never include the number of threads, but it's
333
+ # stored on a per-connection level in the raw configs
334
+ threads = profile_data.pop("threads", DEFAULT_THREADS)
335
+ if threads_override is not None:
336
+ threads = threads_override
337
+
338
+ credentials: Credentials = cls._credentials_from_profile(
339
+ profile_data, profile_name, target_name
340
+ )
341
+
342
+ return cls.from_credentials(
343
+ credentials=credentials,
344
+ profile_name=profile_name,
345
+ target_name=target_name,
346
+ threads=threads,
347
+ )
348
+
349
+ @classmethod
350
+ def from_raw_profiles(
351
+ cls,
352
+ raw_profiles: Dict[str, Any],
353
+ profile_name: str,
354
+ renderer: ProfileRenderer,
355
+ target_override: Optional[str] = None,
356
+ threads_override: Optional[int] = None,
357
+ ) -> "Profile":
358
+ """
359
+ :param raw_profiles: The profile data, from disk as yaml.
360
+ :param profile_name: The profile name to use.
361
+ :param renderer: The config renderer.
362
+ :param target_override: The target to use, if provided on the command
363
+ line.
364
+ :param threads_override: The thread count to use, if provided on the
365
+ command line.
366
+ :raises DbtProjectError: If there is no profile name specified in the
367
+ project or the command line arguments
368
+ :raises DbtProfileError: If the profile is invalid or missing, or the
369
+ target could not be found
370
+ :returns: The new Profile object.
371
+ """
372
+ if profile_name not in raw_profiles:
373
+ raise DbtProjectError("Could not find profile named '{}'".format(profile_name))
374
+
375
+ # First, we've already got our final decision on profile name, and we
376
+ # don't render keys, so we can pluck that out
377
+ raw_profile = raw_profiles[profile_name]
378
+ if not raw_profile:
379
+ msg = f"Profile {profile_name} in profiles.yml is empty"
380
+ raise DbtProfileError(INVALID_PROFILE_MESSAGE.format(error_string=msg))
381
+
382
+ return cls.from_raw_profile_info(
383
+ raw_profile=raw_profile,
384
+ profile_name=profile_name,
385
+ renderer=renderer,
386
+ target_override=target_override,
387
+ threads_override=threads_override,
388
+ )
389
+
390
+ @classmethod
391
+ def render(
392
+ cls,
393
+ renderer: ProfileRenderer,
394
+ project_profile_name: Optional[str],
395
+ profile_name_override: Optional[str] = None,
396
+ target_override: Optional[str] = None,
397
+ threads_override: Optional[int] = None,
398
+ ) -> "Profile":
399
+ """Given the raw profiles as read from disk and the name of the desired
400
+ profile if specified, return the profile component of the runtime
401
+ config.
402
+
403
+ :param args argparse.Namespace: The arguments as parsed from the cli.
404
+ :param project_profile_name Optional[str]: The profile name, if
405
+ specified in a project.
406
+ :raises DbtProjectError: If there is no profile name specified in the
407
+ project or the command line arguments, or if the specified profile
408
+ is not found
409
+ :raises DbtProfileError: If the profile is invalid or missing, or the
410
+ target could not be found.
411
+ :returns Profile: The new Profile object.
412
+ """
413
+ flags = get_flags()
414
+ raw_profiles = read_profile(flags.PROFILES_DIR)
415
+ profile_name = cls.pick_profile_name(profile_name_override, project_profile_name)
416
+ return cls.from_raw_profiles(
417
+ raw_profiles=raw_profiles,
418
+ profile_name=profile_name,
419
+ renderer=renderer,
420
+ target_override=target_override,
421
+ threads_override=threads_override,
422
+ )