dagster-dbt 0.23.3__py3-none-any.whl → 0.28.4__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 (64) hide show
  1. dagster_dbt/__init__.py +41 -140
  2. dagster_dbt/asset_decorator.py +49 -230
  3. dagster_dbt/asset_specs.py +65 -0
  4. dagster_dbt/asset_utils.py +655 -338
  5. dagster_dbt/cli/app.py +44 -43
  6. dagster_dbt/cloud/__init__.py +6 -4
  7. dagster_dbt/cloud/asset_defs.py +119 -177
  8. dagster_dbt/cloud/cli.py +3 -4
  9. dagster_dbt/cloud/ops.py +9 -6
  10. dagster_dbt/cloud/resources.py +9 -4
  11. dagster_dbt/cloud/types.py +12 -7
  12. dagster_dbt/cloud/utils.py +186 -0
  13. dagster_dbt/cloud_v2/__init__.py +10 -0
  14. dagster_dbt/cloud_v2/asset_decorator.py +81 -0
  15. dagster_dbt/cloud_v2/cli_invocation.py +67 -0
  16. dagster_dbt/cloud_v2/client.py +438 -0
  17. dagster_dbt/cloud_v2/resources.py +462 -0
  18. dagster_dbt/cloud_v2/run_handler.py +229 -0
  19. dagster_dbt/cloud_v2/sensor_builder.py +254 -0
  20. dagster_dbt/cloud_v2/types.py +143 -0
  21. dagster_dbt/compat.py +107 -0
  22. dagster_dbt/components/__init__.py +0 -0
  23. dagster_dbt/components/dbt_project/__init__.py +0 -0
  24. dagster_dbt/components/dbt_project/component.py +545 -0
  25. dagster_dbt/components/dbt_project/scaffolder.py +65 -0
  26. dagster_dbt/core/__init__.py +0 -10
  27. dagster_dbt/core/dbt_cli_event.py +612 -0
  28. dagster_dbt/core/dbt_cli_invocation.py +474 -0
  29. dagster_dbt/core/dbt_event_iterator.py +399 -0
  30. dagster_dbt/core/resource.py +733 -0
  31. dagster_dbt/core/utils.py +14 -279
  32. dagster_dbt/dagster_dbt_translator.py +317 -74
  33. dagster_dbt/dbt_core_version.py +1 -0
  34. dagster_dbt/dbt_manifest.py +6 -5
  35. dagster_dbt/dbt_manifest_asset_selection.py +62 -22
  36. dagster_dbt/dbt_project.py +179 -40
  37. dagster_dbt/dbt_project_manager.py +173 -0
  38. dagster_dbt/dbt_version.py +0 -0
  39. dagster_dbt/errors.py +9 -84
  40. dagster_dbt/freshness_builder.py +147 -0
  41. dagster_dbt/include/pyproject.toml.jinja +21 -0
  42. dagster_dbt/include/scaffold/assets.py.jinja +1 -8
  43. dagster_dbt/include/scaffold/definitions.py.jinja +0 -15
  44. dagster_dbt/include/scaffold/project.py.jinja +1 -0
  45. dagster_dbt/include/setup.py.jinja +2 -3
  46. dagster_dbt/metadata_set.py +18 -0
  47. dagster_dbt/utils.py +136 -234
  48. dagster_dbt/version.py +1 -1
  49. dagster_dbt-0.28.4.dist-info/METADATA +47 -0
  50. dagster_dbt-0.28.4.dist-info/RECORD +59 -0
  51. {dagster_dbt-0.23.3.dist-info → dagster_dbt-0.28.4.dist-info}/WHEEL +1 -1
  52. {dagster_dbt-0.23.3.dist-info → dagster_dbt-0.28.4.dist-info}/entry_points.txt +3 -0
  53. {dagster_dbt-0.23.3.dist-info → dagster_dbt-0.28.4.dist-info/licenses}/LICENSE +1 -1
  54. dagster_dbt/asset_defs.py +0 -1049
  55. dagster_dbt/core/resources.py +0 -527
  56. dagster_dbt/core/resources_v2.py +0 -1542
  57. dagster_dbt/core/types.py +0 -63
  58. dagster_dbt/dbt_resource.py +0 -220
  59. dagster_dbt/include/scaffold/constants.py.jinja +0 -21
  60. dagster_dbt/ops.py +0 -134
  61. dagster_dbt/types.py +0 -22
  62. dagster_dbt-0.23.3.dist-info/METADATA +0 -31
  63. dagster_dbt-0.23.3.dist-info/RECORD +0 -43
  64. {dagster_dbt-0.23.3.dist-info → dagster_dbt-0.28.4.dist-info}/top_level.txt +0 -0
@@ -1,33 +1,54 @@
1
+ import os
2
+ from collections.abc import Mapping, Sequence
1
3
  from dataclasses import dataclass
2
- from typing import Any, Mapping, Optional, Sequence
4
+ from pathlib import Path
5
+ from typing import TYPE_CHECKING, Any, Optional
3
6
 
4
7
  from dagster import (
8
+ AssetCheckSpec,
9
+ AssetDep,
5
10
  AssetKey,
11
+ AssetSpec,
6
12
  AutoMaterializePolicy,
7
- FreshnessPolicy,
13
+ AutomationCondition,
14
+ DagsterInvalidDefinitionError,
8
15
  PartitionMapping,
9
- _check as check,
10
16
  )
11
- from dagster._annotations import public
12
- from dagster._core.definitions.asset_key import (
13
- CoercibleToAssetKeyPrefix,
14
- check_opt_coercible_to_asset_key_prefix_param,
17
+ from dagster._annotations import beta, public
18
+ from dagster._core.definitions.metadata.source_code import (
19
+ CodeReferencesMetadataSet,
20
+ CodeReferencesMetadataValue,
21
+ LocalFileCodeReference,
15
22
  )
16
- from dagster._core.definitions.utils import is_valid_definition_tag_key
17
-
18
- from .asset_utils import (
23
+ from dagster._core.definitions.partitions.definition import PartitionsDefinition
24
+ from dagster._utils.tags import is_valid_tag_key
25
+ from dagster.components.resolved.base import Resolvable
26
+ from dagster_shared import check
27
+
28
+ from dagster_dbt.asset_utils import (
29
+ DAGSTER_DBT_MANIFEST_METADATA_KEY,
30
+ DAGSTER_DBT_PROJECT_METADATA_KEY,
31
+ DAGSTER_DBT_TRANSLATOR_METADATA_KEY,
32
+ DAGSTER_DBT_UNIQUE_ID_METADATA_KEY,
33
+ default_asset_check_fn,
19
34
  default_asset_key_fn,
20
35
  default_auto_materialize_policy_fn,
36
+ default_code_version_fn,
21
37
  default_description_fn,
22
- default_freshness_policy_fn,
23
38
  default_group_from_dbt_resource_props,
24
39
  default_metadata_from_dbt_resource_props,
25
40
  default_owners_from_dbt_resource_props,
41
+ get_node,
42
+ get_upstream_unique_ids,
43
+ has_self_dependency,
26
44
  )
27
45
 
46
+ if TYPE_CHECKING:
47
+ from dagster_dbt.dbt_project import DbtProject
48
+
28
49
 
29
50
  @dataclass(frozen=True)
30
- class DagsterDbtTranslatorSettings:
51
+ class DagsterDbtTranslatorSettings(Resolvable):
31
52
  """Settings to enable Dagster features for your dbt project.
32
53
 
33
54
  Args:
@@ -35,10 +56,19 @@ class DagsterDbtTranslatorSettings:
35
56
  Defaults to True.
36
57
  enable_duplicate_source_asset_keys (bool): Whether to allow dbt sources with duplicate
37
58
  Dagster asset keys. Defaults to False.
59
+ enable_code_references (bool): Whether to enable Dagster code references for dbt resources.
60
+ Defaults to False.
61
+ enable_dbt_selection_by_name (bool): Whether to enable selecting dbt resources by name,
62
+ rather than fully qualified name. Defaults to False.
63
+ enable_source_tests_as_checks (bool): Whether to load dbt source tests as Dagster asset checks.
64
+ Defaults to False. If False, asset observations will be emitted for source tests.
38
65
  """
39
66
 
40
67
  enable_asset_checks: bool = True
41
68
  enable_duplicate_source_asset_keys: bool = False
69
+ enable_code_references: bool = False
70
+ enable_dbt_selection_by_name: bool = False
71
+ enable_source_tests_as_checks: bool = False
42
72
 
43
73
 
44
74
  class DagsterDbtTranslator:
@@ -64,6 +94,145 @@ class DagsterDbtTranslator:
64
94
 
65
95
  return self._settings
66
96
 
97
+ def get_resource_props(self, manifest: Mapping[str, Any], unique_id: str) -> Mapping[str, Any]:
98
+ """Given a parsed manifest and a dbt unique_id, returns the dictionary of properties
99
+ for the corresponding dbt resource (e.g. model, seed, snapshot, source) as defined
100
+ in your dbt project. This can be used as a convenience method when overriding the
101
+ `get_asset_spec` method.
102
+
103
+ Args:
104
+ manifest (Mapping[str, Any]): The parsed manifest of the dbt project.
105
+ unique_id (str): The unique_id of the dbt resource.
106
+
107
+ Returns:
108
+ Mapping[str, Any]: The dictionary of properties for the corresponding dbt resource.
109
+
110
+ Examples:
111
+ .. code-block:: python
112
+
113
+ class CustomDagsterDbtTranslator(DagsterDbtTranslator):
114
+
115
+ def get_asset_spec(self, manifest: Mapping[str, Any], unique_id: str, project: Optional[DbtProject]) -> dg.AssetSpec:
116
+ base_spec = super().get_asset_spec(manifest, unique_id, project)
117
+ resource_props = self.get_resource_props(manifest, unique_id)
118
+ if resource_props["meta"].get("use_custom_group"):
119
+ return base_spec.replace_attributes(group_name="custom_group")
120
+ else:
121
+ return base_spec
122
+ """
123
+ return get_node(manifest, unique_id)
124
+
125
+ def get_asset_spec(
126
+ self,
127
+ manifest: Mapping[str, Any],
128
+ unique_id: str,
129
+ project: Optional["DbtProject"],
130
+ ) -> AssetSpec:
131
+ """Returns an AssetSpec representing a specific dbt resource."""
132
+ # memoize resolution for a given manifest & unique_id
133
+ # since we recursively call get_asset_spec for dependencies
134
+ memo_id = (id(manifest), unique_id, id(project))
135
+
136
+ # Don't initialize this in the constructor in case a subclass does not call __init__
137
+ if not hasattr(self, "_resolved_specs"):
138
+ self._resolved_specs = {}
139
+
140
+ if memo_id in self._resolved_specs:
141
+ return self._resolved_specs[memo_id]
142
+
143
+ group_props = {group["name"]: group for group in manifest.get("groups", {}).values()}
144
+ resource_props = self.get_resource_props(manifest, unique_id)
145
+
146
+ # calculate the dependencies for the asset
147
+ upstream_ids = get_upstream_unique_ids(manifest, resource_props)
148
+ deps = [
149
+ AssetDep(
150
+ asset=self.get_asset_spec(manifest, upstream_id, project).key,
151
+ partition_mapping=self.get_partition_mapping(
152
+ resource_props, self.get_resource_props(manifest, upstream_id)
153
+ ),
154
+ )
155
+ for upstream_id in upstream_ids
156
+ ]
157
+ self_partition_mapping = self.get_partition_mapping(resource_props, resource_props)
158
+ if self_partition_mapping and has_self_dependency(resource_props):
159
+ deps.append(
160
+ AssetDep(
161
+ asset=self.get_asset_key(resource_props),
162
+ partition_mapping=self_partition_mapping,
163
+ )
164
+ )
165
+
166
+ resource_group_props = group_props.get(resource_props.get("group") or "")
167
+ if resource_group_props:
168
+ owners_resource_props = {
169
+ **resource_props,
170
+ # this overrides the group key in resource_props, which is bad as
171
+ # this key is not always empty and this dictionary generally differs
172
+ # in structure from other inputs, but this is necessary for backcompat
173
+ **({"group": resource_group_props} if resource_group_props else {}),
174
+ }
175
+ else:
176
+ owners_resource_props = resource_props
177
+
178
+ spec = AssetSpec(
179
+ key=self.get_asset_key(resource_props),
180
+ deps=deps,
181
+ description=self.get_description(resource_props),
182
+ metadata=self.get_metadata(resource_props),
183
+ skippable=True,
184
+ group_name=self.get_group_name(resource_props),
185
+ code_version=self.get_code_version(resource_props),
186
+ automation_condition=self.get_automation_condition(resource_props),
187
+ owners=self.get_owners(owners_resource_props),
188
+ tags=self.get_tags(resource_props),
189
+ kinds={"dbt", manifest.get("metadata", {}).get("adapter_type", "dbt")},
190
+ partitions_def=self.get_partitions_def(resource_props),
191
+ )
192
+
193
+ # add integration-specific metadata to the spec
194
+ spec = spec.merge_attributes(
195
+ metadata={
196
+ DAGSTER_DBT_MANIFEST_METADATA_KEY: DbtManifestWrapper(manifest=manifest),
197
+ DAGSTER_DBT_TRANSLATOR_METADATA_KEY: self,
198
+ DAGSTER_DBT_UNIQUE_ID_METADATA_KEY: resource_props["unique_id"],
199
+ **({DAGSTER_DBT_PROJECT_METADATA_KEY: project} if project else {}),
200
+ }
201
+ )
202
+ if self.settings.enable_code_references:
203
+ if not project:
204
+ raise DagsterInvalidDefinitionError(
205
+ "enable_code_references requires a DbtProject to be supplied"
206
+ " to the @dbt_assets decorator."
207
+ )
208
+
209
+ spec = spec.replace_attributes(
210
+ metadata=_attach_sql_model_code_reference(
211
+ existing_metadata=spec.metadata,
212
+ dbt_resource_props=resource_props,
213
+ project=project,
214
+ )
215
+ )
216
+
217
+ self._resolved_specs[memo_id] = spec
218
+
219
+ return self._resolved_specs[memo_id]
220
+
221
+ def get_asset_check_spec(
222
+ self,
223
+ asset_spec: AssetSpec,
224
+ manifest: Mapping[str, Any],
225
+ unique_id: str,
226
+ project: Optional["DbtProject"],
227
+ ) -> Optional[AssetCheckSpec]:
228
+ return default_asset_check_fn(
229
+ manifest=manifest,
230
+ dagster_dbt_translator=self,
231
+ asset_key=asset_spec.key,
232
+ test_unique_id=unique_id,
233
+ project=project,
234
+ )
235
+
67
236
  @public
68
237
  def get_asset_key(self, dbt_resource_props: Mapping[str, Any]) -> AssetKey:
69
238
  """A function that takes a dictionary representing properties of a dbt resource, and
@@ -119,6 +288,7 @@ class DagsterDbtTranslator:
119
288
  return default_asset_key_fn(dbt_resource_props)
120
289
 
121
290
  @public
291
+ @beta(emit_runtime_warning=False)
122
292
  def get_partition_mapping(
123
293
  self,
124
294
  dbt_resource_props: Mapping[str, Any],
@@ -223,8 +393,8 @@ class DagsterDbtTranslator:
223
393
  https://docs.getdbt.com/reference/artifacts/manifest-json#resource-details
224
394
 
225
395
  dbt tags are strings, but Dagster tags are key-value pairs. To bridge this divide, the dbt
226
- tag string is used as the Dagster tag key, and the Dagster tag value is set to special
227
- sentinel value `"__dagster_no_value"`.
396
+ tag string is used as the Dagster tag key, and the Dagster tag value is set to the empty
397
+ string, "".
228
398
 
229
399
  Any dbt tags that don't match Dagster's supported tag key format (e.g. they contain
230
400
  unsupported characters) will be ignored.
@@ -250,7 +420,7 @@ class DagsterDbtTranslator:
250
420
  return {"custom": "tag"}
251
421
  """
252
422
  tags = dbt_resource_props.get("tags", [])
253
- return {tag: "" for tag in tags if is_valid_definition_tag_key(tag)}
423
+ return {tag: "" for tag in tags if is_valid_tag_key(tag)}
254
424
 
255
425
  @public
256
426
  def get_group_name(self, dbt_resource_props: Mapping[str, Any]) -> Optional[str]:
@@ -284,6 +454,38 @@ class DagsterDbtTranslator:
284
454
  """
285
455
  return default_group_from_dbt_resource_props(dbt_resource_props)
286
456
 
457
+ @public
458
+ def get_code_version(self, dbt_resource_props: Mapping[str, Any]) -> Optional[str]:
459
+ """A function that takes a dictionary representing properties of a dbt resource, and
460
+ returns the Dagster code version for that resource.
461
+
462
+ Note that a dbt resource is unrelated to Dagster's resource concept, and simply represents
463
+ a model, seed, snapshot or source in a given dbt project. You can learn more about dbt
464
+ resources and the properties available in this dictionary here:
465
+ https://docs.getdbt.com/reference/artifacts/manifest-json#resource-details
466
+
467
+ This method can be overridden to provide a custom code version for a dbt resource.
468
+
469
+ Args:
470
+ dbt_resource_props (Mapping[str, Any]): A dictionary representing the dbt resource.
471
+
472
+ Returns:
473
+ Optional[str]: A Dagster code version.
474
+
475
+ Examples:
476
+ .. code-block:: python
477
+
478
+ from typing import Any, Mapping
479
+
480
+ from dagster_dbt import DagsterDbtTranslator
481
+
482
+
483
+ class CustomDagsterDbtTranslator(DagsterDbtTranslator):
484
+ def get_code_version(self, dbt_resource_props: Mapping[str, Any]) -> Optional[str]:
485
+ return dbt_resource_props["checksum"]["checksum"]
486
+ """
487
+ return default_code_version_fn(dbt_resource_props)
488
+
287
489
  @public
288
490
  def get_owners(self, dbt_resource_props: Mapping[str, Any]) -> Optional[Sequence[str]]:
289
491
  """A function that takes a dictionary representing properties of a dbt resource, and
@@ -317,27 +519,28 @@ class DagsterDbtTranslator:
317
519
  return default_owners_from_dbt_resource_props(dbt_resource_props)
318
520
 
319
521
  @public
320
- def get_freshness_policy(
522
+ @beta(emit_runtime_warning=False)
523
+ def get_auto_materialize_policy(
321
524
  self, dbt_resource_props: Mapping[str, Any]
322
- ) -> Optional[FreshnessPolicy]:
525
+ ) -> Optional[AutoMaterializePolicy]:
323
526
  """A function that takes a dictionary representing properties of a dbt resource, and
324
- returns the Dagster :py:class:`dagster.FreshnessPolicy` for that resource.
527
+ returns the Dagster :py:class:`dagster.AutoMaterializePolicy` for that resource.
325
528
 
326
529
  Note that a dbt resource is unrelated to Dagster's resource concept, and simply represents
327
530
  a model, seed, snapshot or source in a given dbt project. You can learn more about dbt
328
531
  resources and the properties available in this dictionary here:
329
532
  https://docs.getdbt.com/reference/artifacts/manifest-json#resource-details
330
533
 
331
- This method can be overridden to provide a custom freshness policy for a dbt resource.
534
+ This method can be overridden to provide a custom auto-materialize policy for a dbt resource.
332
535
 
333
536
  Args:
334
537
  dbt_resource_props (Mapping[str, Any]): A dictionary representing the dbt resource.
335
538
 
336
539
  Returns:
337
- Optional[FreshnessPolicy]: A Dagster freshness policy.
540
+ Optional[AutoMaterializePolicy]: A Dagster auto-materialize policy.
338
541
 
339
542
  Examples:
340
- Set a custom freshness policy for all dbt resources:
543
+ Set a custom auto-materialize policy for all dbt resources:
341
544
 
342
545
  .. code-block:: python
343
546
 
@@ -347,10 +550,10 @@ class DagsterDbtTranslator:
347
550
 
348
551
 
349
552
  class CustomDagsterDbtTranslator(DagsterDbtTranslator):
350
- def get_freshness_policy(self, dbt_resource_props: Mapping[str, Any]) -> Optional[FreshnessPolicy]:
351
- return FreshnessPolicy(maximum_lag_minutes=60)
553
+ def get_auto_materialize_policy(self, dbt_resource_props: Mapping[str, Any]) -> Optional[AutoMaterializePolicy]:
554
+ return AutoMaterializePolicy.eager()
352
555
 
353
- Set a custom freshness policy for dbt resources with a specific tag:
556
+ Set a custom auto-materialize policy for dbt resources with a specific tag:
354
557
 
355
558
  .. code-block:: python
356
559
 
@@ -360,19 +563,21 @@ class DagsterDbtTranslator:
360
563
 
361
564
 
362
565
  class CustomDagsterDbtTranslator(DagsterDbtTranslator):
363
- def get_freshness_policy(self, dbt_resource_props: Mapping[str, Any]) -> Optional[FreshnessPolicy]:
364
- freshness_policy = None
566
+ def get_auto_materialize_policy(self, dbt_resource_props: Mapping[str, Any]) -> Optional[AutoMaterializePolicy]:
567
+ auto_materialize_policy = None
365
568
  if "my_custom_tag" in dbt_resource_props.get("tags", []):
366
- freshness_policy = FreshnessPolicy(maximum_lag_minutes=60)
569
+ auto_materialize_policy = AutoMaterializePolicy.eager()
570
+
571
+ return auto_materialize_policy
367
572
 
368
- return freshness_policy
369
573
  """
370
- return default_freshness_policy_fn(dbt_resource_props)
574
+ return default_auto_materialize_policy_fn(dbt_resource_props)
371
575
 
372
576
  @public
373
- def get_auto_materialize_policy(
577
+ @beta(emit_runtime_warning=False)
578
+ def get_automation_condition(
374
579
  self, dbt_resource_props: Mapping[str, Any]
375
- ) -> Optional[AutoMaterializePolicy]:
580
+ ) -> Optional[AutomationCondition]:
376
581
  """A function that takes a dictionary representing properties of a dbt resource, and
377
582
  returns the Dagster :py:class:`dagster.AutoMaterializePolicy` for that resource.
378
583
 
@@ -381,7 +586,7 @@ class DagsterDbtTranslator:
381
586
  resources and the properties available in this dictionary here:
382
587
  https://docs.getdbt.com/reference/artifacts/manifest-json#resource-details
383
588
 
384
- This method can be overridden to provide a custom auto-materialize policy for a dbt resource.
589
+ This method can be overridden to provide a custom AutomationCondition for a dbt resource.
385
590
 
386
591
  Args:
387
592
  dbt_resource_props (Mapping[str, Any]): A dictionary representing the dbt resource.
@@ -390,7 +595,7 @@ class DagsterDbtTranslator:
390
595
  Optional[AutoMaterializePolicy]: A Dagster auto-materialize policy.
391
596
 
392
597
  Examples:
393
- Set a custom auto-materialize policy for all dbt resources:
598
+ Set a custom AutomationCondition for all dbt resources:
394
599
 
395
600
  .. code-block:: python
396
601
 
@@ -400,10 +605,10 @@ class DagsterDbtTranslator:
400
605
 
401
606
 
402
607
  class CustomDagsterDbtTranslator(DagsterDbtTranslator):
403
- def get_auto_materialize_policy(self, dbt_resource_props: Mapping[str, Any]) -> Optional[AutoMaterializePolicy]:
404
- return AutoMaterializePolicy.eager()
608
+ def get_automation_condition(self, dbt_resource_props: Mapping[str, Any]) -> Optional[AutomationCondition]:
609
+ return AutomationCondition.eager()
405
610
 
406
- Set a custom auto-materialize policy for dbt resources with a specific tag:
611
+ Set a custom AutomationCondition for dbt resources with a specific tag:
407
612
 
408
613
  .. code-block:: python
409
614
 
@@ -413,58 +618,58 @@ class DagsterDbtTranslator:
413
618
 
414
619
 
415
620
  class CustomDagsterDbtTranslator(DagsterDbtTranslator):
416
- def get_auto_materialize_policy(self, dbt_resource_props: Mapping[str, Any]) -> Optional[AutoMaterializePolicy]:
417
- auto_materialize_policy = None
621
+ def get_automation_condition(self, dbt_resource_props: Mapping[str, Any]) -> Optional[AutomationCondition]:
622
+ automation_condition = None
418
623
  if "my_custom_tag" in dbt_resource_props.get("tags", []):
419
- auto_materialize_policy = AutoMaterializePolicy.eager()
624
+ automation_condition = AutomationCondition.eager()
420
625
 
421
- return auto_materialize_policy
626
+ return automation_condition
422
627
 
423
628
  """
424
- return default_auto_materialize_policy_fn(dbt_resource_props)
629
+ auto_materialize_policy = self.get_auto_materialize_policy(dbt_resource_props)
630
+ return (
631
+ auto_materialize_policy.to_automation_condition() if auto_materialize_policy else None
632
+ )
425
633
 
634
+ def get_partitions_def(
635
+ self, dbt_resource_props: Mapping[str, Any]
636
+ ) -> Optional[PartitionsDefinition]:
637
+ """[INTERNAL] A function that takes a dictionary representing properties of a dbt resource, and
638
+ returns the Dagster :py:class:`dagster.PartitionsDefinition` for that resource.
426
639
 
427
- class KeyPrefixDagsterDbtTranslator(DagsterDbtTranslator):
428
- """A DagsterDbtTranslator that applies prefixes to the asset keys generated from dbt resources.
640
+ This method can be overridden to provide a custom PartitionsDefinition for a dbt resource.
429
641
 
430
- Attributes:
431
- asset_key_prefix (Optional[Union[str, Sequence[str]]]): A prefix to apply to all dbt models,
432
- seeds, snapshots, etc. This will *not* apply to dbt sources.
433
- source_asset_key_prefix (Optional[Union[str, Sequence[str]]]): A prefix to apply to all dbt
434
- sources.
435
- """
642
+ Args:
643
+ dbt_resource_props (Mapping[str, Any]): A dictionary representing the dbt resource.
436
644
 
437
- def __init__(
438
- self,
439
- asset_key_prefix: Optional[CoercibleToAssetKeyPrefix] = None,
440
- source_asset_key_prefix: Optional[CoercibleToAssetKeyPrefix] = None,
441
- *args,
442
- **kwargs,
443
- ):
444
- self._asset_key_prefix = (
445
- check_opt_coercible_to_asset_key_prefix_param(asset_key_prefix, "asset_key_prefix")
446
- or []
447
- )
448
- self._source_asset_key_prefix = (
449
- check_opt_coercible_to_asset_key_prefix_param(
450
- source_asset_key_prefix, "source_asset_key_prefix"
451
- )
452
- or []
453
- )
645
+ Returns:
646
+ Optional[PartitionsDefinition]: A Dagster partitions definition.
454
647
 
455
- super().__init__(*args, **kwargs)
648
+ Examples:
649
+ Set a custom AutomationCondition for dbt resources with a specific tag:
456
650
 
457
- @public
458
- def get_asset_key(self, dbt_resource_props: Mapping[str, Any]) -> AssetKey:
459
- base_key = default_asset_key_fn(dbt_resource_props)
460
- if dbt_resource_props["resource_type"] == "source":
461
- return base_key.with_prefix(self._source_asset_key_prefix)
462
- else:
463
- return base_key.with_prefix(self._asset_key_prefix)
651
+ .. code-block:: python
652
+
653
+ from typing import Any, Mapping
654
+
655
+ from dagster import DailyPartitionsDefinition
656
+ from dagster_dbt import DagsterDbtTranslator
657
+
658
+
659
+ class CustomDagsterDbtTranslator(DagsterDbtTranslator):
660
+ def get_partitions_def(self, dbt_resource_props: Mapping[str, Any]) -> Optional[PartitionsDefinition]:
661
+ if "my_custom_tag" in dbt_resource_props.get("tags", []):
662
+ return DailyPartitionsDefinition(start_date="2022-01-01")
663
+ else:
664
+ return None
665
+ """
666
+ return None
464
667
 
465
668
 
466
669
  @dataclass
467
670
  class DbtManifestWrapper:
671
+ """Wrapper around parsed DBT manifest json to provide convenient and efficient access."""
672
+
468
673
  manifest: Mapping[str, Any]
469
674
 
470
675
 
@@ -492,3 +697,41 @@ def validate_opt_translator(
492
697
  " DagsterDbtTranslator."
493
698
  ),
494
699
  )
700
+
701
+
702
+ def _attach_sql_model_code_reference(
703
+ existing_metadata: Mapping[str, Any],
704
+ dbt_resource_props: Mapping[str, Any],
705
+ project: "DbtProject",
706
+ ) -> Mapping[str, Any]:
707
+ """Pulls the SQL model location for a dbt resource and attaches it as a code reference to the
708
+ existing metadata.
709
+ """
710
+ existing_references_meta = CodeReferencesMetadataSet.extract(existing_metadata)
711
+ references = (
712
+ existing_references_meta.code_references.code_references
713
+ if existing_references_meta.code_references
714
+ else []
715
+ )
716
+
717
+ if "original_file_path" not in dbt_resource_props:
718
+ raise DagsterInvalidDefinitionError(
719
+ "Cannot attach SQL model code reference because 'original_file_path' is not present"
720
+ " in the dbt resource properties."
721
+ )
722
+
723
+ # attempt to get root_path, which is removed from manifests in newer dbt versions
724
+ relative_path = Path(dbt_resource_props["original_file_path"])
725
+ abs_path = project.project_dir.joinpath(relative_path).resolve()
726
+
727
+ return {
728
+ **existing_metadata,
729
+ **CodeReferencesMetadataSet(
730
+ code_references=CodeReferencesMetadataValue(
731
+ code_references=[
732
+ *references,
733
+ LocalFileCodeReference(file_path=os.fspath(abs_path)),
734
+ ],
735
+ )
736
+ ),
737
+ }
@@ -0,0 +1 @@
1
+ DBT_CORE_VERSION_UPPER_BOUND = "1.11"
@@ -1,16 +1,17 @@
1
- from functools import lru_cache
1
+ from collections.abc import Mapping
2
+ from functools import cache
2
3
  from pathlib import Path
3
- from typing import Any, Mapping, Union, cast
4
+ from typing import Any, Union, cast
4
5
 
5
6
  import dagster._check as check
6
7
  import orjson
7
8
 
8
- from .errors import DagsterDbtManifestNotFoundError
9
+ from dagster_dbt.errors import DagsterDbtManifestNotFoundError
9
10
 
10
11
  DbtManifestParam = Union[Mapping[str, Any], str, Path]
11
12
 
12
13
 
13
- @lru_cache(maxsize=None)
14
+ @cache
14
15
  def read_manifest_path(manifest_path: Path) -> Mapping[str, Any]:
15
16
  """Reads a dbt manifest path and returns the parsed JSON as a dict.
16
17
 
@@ -23,7 +24,7 @@ def read_manifest_path(manifest_path: Path) -> Mapping[str, Any]:
23
24
  if not manifest_path.exists():
24
25
  raise DagsterDbtManifestNotFoundError(f"{manifest_path} does not exist.")
25
26
 
26
- return cast(Mapping[str, Any], orjson.loads(manifest_path.read_bytes()))
27
+ return cast("Mapping[str, Any]", orjson.loads(manifest_path.read_bytes()))
27
28
 
28
29
 
29
30
  def validate_manifest(manifest: DbtManifestParam) -> Mapping[str, Any]: