dagster-fivetran 0.27.13__tar.gz → 0.27.15__tar.gz

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 (36) hide show
  1. {dagster_fivetran-0.27.13/dagster_fivetran.egg-info → dagster_fivetran-0.27.15}/PKG-INFO +3 -3
  2. dagster_fivetran-0.27.15/dagster_fivetran/components/workspace_component/component.py +199 -0
  3. dagster_fivetran-0.27.15/dagster_fivetran/version.py +1 -0
  4. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15/dagster_fivetran.egg-info}/PKG-INFO +3 -3
  5. dagster_fivetran-0.27.15/dagster_fivetran.egg-info/requires.txt +7 -0
  6. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/setup.py +2 -2
  7. dagster_fivetran-0.27.13/dagster_fivetran/components/workspace_component/component.py +0 -134
  8. dagster_fivetran-0.27.13/dagster_fivetran/version.py +0 -1
  9. dagster_fivetran-0.27.13/dagster_fivetran.egg-info/requires.txt +0 -7
  10. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/LICENSE +0 -0
  11. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/MANIFEST.in +0 -0
  12. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/README.md +0 -0
  13. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran/__init__.py +0 -0
  14. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran/asset_decorator.py +0 -0
  15. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran/asset_defs.py +0 -0
  16. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran/cli.py +0 -0
  17. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran/components/__init__.py +0 -0
  18. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran/components/workspace_component/__init__.py +0 -0
  19. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran/components/workspace_component/scaffolder.py +0 -0
  20. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran/constants.py +0 -0
  21. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran/fivetran_event_iterator.py +0 -0
  22. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran/managed/__init__.py +0 -0
  23. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran/managed/reconciliation.py +0 -0
  24. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran/managed/types.py +0 -0
  25. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran/ops.py +0 -0
  26. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran/py.typed +0 -0
  27. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran/resources.py +0 -0
  28. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran/translator.py +0 -0
  29. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran/types.py +0 -0
  30. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran/utils.py +0 -0
  31. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran.egg-info/SOURCES.txt +0 -0
  32. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran.egg-info/dependency_links.txt +0 -0
  33. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran.egg-info/entry_points.txt +0 -0
  34. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran.egg-info/not-zip-safe +0 -0
  35. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/dagster_fivetran.egg-info/top_level.txt +0 -0
  36. {dagster_fivetran-0.27.13 → dagster_fivetran-0.27.15}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dagster-fivetran
3
- Version: 0.27.13
3
+ Version: 0.27.15
4
4
  Summary: Package for integrating Fivetran with Dagster.
5
5
  Home-page: https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-fivetran
6
6
  Author: Dagster Labs
@@ -15,9 +15,9 @@ Classifier: License :: OSI Approved :: Apache Software License
15
15
  Classifier: Operating System :: OS Independent
16
16
  Requires-Python: >=3.9,<3.14
17
17
  License-File: LICENSE
18
- Requires-Dist: dagster==1.11.13
18
+ Requires-Dist: dagster==1.11.15
19
19
  Provides-Extra: managed
20
- Requires-Dist: dagster-managed-elements==0.27.13; extra == "managed"
20
+ Requires-Dist: dagster-managed-elements==0.27.15; extra == "managed"
21
21
  Provides-Extra: test
22
22
  Requires-Dist: pytest-order; extra == "test"
23
23
  Dynamic: author
@@ -0,0 +1,199 @@
1
+ from collections import defaultdict
2
+ from collections.abc import Iterable, Sequence
3
+ from functools import cached_property
4
+ from pathlib import Path
5
+ from typing import Annotated, Callable, Optional, Union
6
+
7
+ import dagster as dg
8
+ import pydantic
9
+ from dagster._annotations import public
10
+ from dagster._utils.names import clean_name
11
+ from dagster.components.component.state_backed_component import StateBackedComponent
12
+ from dagster.components.resolved.base import resolve_fields
13
+ from dagster.components.utils.defs_state import (
14
+ DefsStateConfig,
15
+ DefsStateConfigArgs,
16
+ ResolvedDefsStateConfig,
17
+ )
18
+ from dagster.components.utils.translation import (
19
+ ComponentTranslator,
20
+ TranslationFn,
21
+ TranslationFnResolver,
22
+ create_component_translator_cls,
23
+ )
24
+ from dagster_shared import check
25
+ from dagster_shared.serdes.serdes import deserialize_value
26
+
27
+ from dagster_fivetran.components.workspace_component.scaffolder import (
28
+ FivetranAccountComponentScaffolder,
29
+ )
30
+ from dagster_fivetran.resources import FivetranWorkspace
31
+ from dagster_fivetran.translator import (
32
+ DagsterFivetranTranslator,
33
+ FivetranConnector,
34
+ FivetranConnectorTableProps,
35
+ FivetranMetadataSet,
36
+ FivetranWorkspaceData,
37
+ )
38
+ from dagster_fivetran.utils import DAGSTER_FIVETRAN_TRANSLATOR_METADATA_KEY
39
+
40
+
41
+ class FivetranWorkspaceModel(pydantic.BaseModel):
42
+ account_id: str = pydantic.Field(..., description="The Fivetran account ID.")
43
+ api_key: str = pydantic.Field(
44
+ ..., description="API key used to authenticate to a Fivetran instance."
45
+ )
46
+ api_secret: str = pydantic.Field(
47
+ ..., description="API secret used to authenticate to a Fivetran instance."
48
+ )
49
+
50
+
51
+ class FivetranConnectorSelectorByName(pydantic.BaseModel):
52
+ by_name: Sequence[str] = pydantic.Field(
53
+ ...,
54
+ description="A list of connector names to include in the collection.",
55
+ )
56
+
57
+
58
+ class FivetranConnectorSelectorById(pydantic.BaseModel):
59
+ by_id: Sequence[str] = pydantic.Field(
60
+ ...,
61
+ description="A list of connector IDs to include in the collection.",
62
+ )
63
+
64
+
65
+ def resolve_connector_selector(
66
+ context: dg.ResolutionContext, model
67
+ ) -> Optional[Callable[[FivetranConnector], bool]]:
68
+ if isinstance(model, str):
69
+ model = context.resolve_value(model)
70
+
71
+ if isinstance(model, FivetranConnectorSelectorByName):
72
+ return lambda connector: connector.name in model.by_name
73
+ elif isinstance(model, FivetranConnectorSelectorById):
74
+ return lambda connector: connector.id in model.by_id
75
+ else:
76
+ check.failed(f"Unknown connector target type: {type(model)}")
77
+
78
+
79
+ @public
80
+ @dg.scaffold_with(FivetranAccountComponentScaffolder)
81
+ class FivetranAccountComponent(StateBackedComponent, dg.Model, dg.Resolvable):
82
+ """Loads Fivetran connectors from a given Fivetran instance as Dagster assets.
83
+ Materializing these assets will trigger a sync of the Fivetran connector, enabling
84
+ you to schedule Fivetran syncs using Dagster.
85
+ """
86
+
87
+ workspace: Annotated[
88
+ FivetranWorkspace,
89
+ dg.Resolver(
90
+ lambda context, model: FivetranWorkspace(
91
+ **resolve_fields(model, FivetranWorkspace, context)
92
+ )
93
+ ),
94
+ ]
95
+ connector_selector: Annotated[
96
+ Optional[Callable[[FivetranConnector], bool]],
97
+ dg.Resolver(
98
+ resolve_connector_selector,
99
+ model_field_type=Union[
100
+ str, FivetranConnectorSelectorByName, FivetranConnectorSelectorById
101
+ ],
102
+ ),
103
+ ] = None
104
+ translation: Optional[
105
+ Annotated[
106
+ TranslationFn[FivetranConnectorTableProps],
107
+ TranslationFnResolver(template_vars_for_translation_fn=lambda data: {"props": data}),
108
+ ]
109
+ ] = pydantic.Field(
110
+ default=None,
111
+ description="Function used to translate Fivetran connector table properties into Dagster asset specs.",
112
+ )
113
+ defs_state: ResolvedDefsStateConfig = DefsStateConfigArgs.legacy_code_server_snapshots()
114
+
115
+ @cached_property
116
+ def workspace_resource(self) -> FivetranWorkspace:
117
+ return self.workspace
118
+
119
+ @cached_property
120
+ def translator(self) -> DagsterFivetranTranslator:
121
+ return FivetranComponentTranslator(self)
122
+
123
+ @cached_property
124
+ def _base_translator(self) -> DagsterFivetranTranslator:
125
+ return DagsterFivetranTranslator()
126
+
127
+ @property
128
+ def defs_state_config(self) -> DefsStateConfig:
129
+ default_key = f"{self.__class__.__name__}[{self.workspace_resource.account_id}]"
130
+ return DefsStateConfig.from_args(self.defs_state, default_key=default_key)
131
+
132
+ def get_asset_spec(self, props: FivetranConnectorTableProps) -> dg.AssetSpec:
133
+ return self._base_translator.get_asset_spec(props)
134
+
135
+ def execute(
136
+ self, context: dg.AssetExecutionContext, fivetran: FivetranWorkspace
137
+ ) -> Iterable[Union[dg.AssetMaterialization, dg.MaterializeResult]]:
138
+ yield from fivetran.sync_and_poll(context=context)
139
+
140
+ def _load_asset_specs(self, state: FivetranWorkspaceData) -> Sequence[dg.AssetSpec]:
141
+ connector_selector_fn = self.connector_selector or (lambda connector: bool(connector))
142
+ return [
143
+ self.translator.get_asset_spec(props).merge_attributes(
144
+ metadata={DAGSTER_FIVETRAN_TRANSLATOR_METADATA_KEY: self.translator}
145
+ )
146
+ for props in state.to_workspace_data_selection(
147
+ connector_selector_fn=connector_selector_fn
148
+ ).to_fivetran_connector_table_props_data()
149
+ ]
150
+
151
+ def _get_fivetran_assets_def(
152
+ self, connector_name: str, specs: Sequence[dg.AssetSpec]
153
+ ) -> dg.AssetsDefinition:
154
+ @dg.multi_asset(name=f"fivetran_{clean_name(connector_name)}", can_subset=True, specs=specs)
155
+ def _asset(context: dg.AssetExecutionContext):
156
+ yield from self.execute(context=context, fivetran=self.workspace)
157
+
158
+ return _asset
159
+
160
+ async def write_state_to_path(self, state_path: Path) -> None:
161
+ state = self.workspace_resource.fetch_fivetran_workspace_data()
162
+ state_path.write_text(dg.serialize_value(state))
163
+
164
+ def build_defs_from_state(
165
+ self, context: dg.ComponentLoadContext, state_path: Optional[Path]
166
+ ) -> dg.Definitions:
167
+ if state_path is None:
168
+ return dg.Definitions()
169
+ state = deserialize_value(state_path.read_text(), FivetranWorkspaceData)
170
+
171
+ # group specs by their connector names
172
+ specs_by_connector_name = defaultdict(list)
173
+ for spec in self._load_asset_specs(state):
174
+ connector_name = check.not_none(
175
+ FivetranMetadataSet.extract(spec.metadata).connector_name
176
+ )
177
+ specs_by_connector_name[connector_name].append(spec)
178
+
179
+ # create one assets definition per connector
180
+ assets = [
181
+ self._get_fivetran_assets_def(connector_name, specs)
182
+ for connector_name, specs in specs_by_connector_name.items()
183
+ ]
184
+ return dg.Definitions(assets=assets)
185
+
186
+
187
+ class FivetranComponentTranslator(
188
+ create_component_translator_cls(FivetranAccountComponent, DagsterFivetranTranslator),
189
+ ComponentTranslator[FivetranAccountComponent],
190
+ ):
191
+ def __init__(self, component: "FivetranAccountComponent"):
192
+ self._component = component
193
+
194
+ def get_asset_spec(self, props: FivetranConnectorTableProps) -> dg.AssetSpec:
195
+ base_asset_spec = super().get_asset_spec(props)
196
+ if self.component.translation is None:
197
+ return base_asset_spec
198
+ else:
199
+ return self.component.translation(base_asset_spec, props)
@@ -0,0 +1 @@
1
+ __version__ = "0.27.15"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dagster-fivetran
3
- Version: 0.27.13
3
+ Version: 0.27.15
4
4
  Summary: Package for integrating Fivetran with Dagster.
5
5
  Home-page: https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-fivetran
6
6
  Author: Dagster Labs
@@ -15,9 +15,9 @@ Classifier: License :: OSI Approved :: Apache Software License
15
15
  Classifier: Operating System :: OS Independent
16
16
  Requires-Python: >=3.9,<3.14
17
17
  License-File: LICENSE
18
- Requires-Dist: dagster==1.11.13
18
+ Requires-Dist: dagster==1.11.15
19
19
  Provides-Extra: managed
20
- Requires-Dist: dagster-managed-elements==0.27.13; extra == "managed"
20
+ Requires-Dist: dagster-managed-elements==0.27.15; extra == "managed"
21
21
  Provides-Extra: test
22
22
  Requires-Dist: pytest-order; extra == "test"
23
23
  Dynamic: author
@@ -0,0 +1,7 @@
1
+ dagster==1.11.15
2
+
3
+ [managed]
4
+ dagster-managed-elements==0.27.15
5
+
6
+ [test]
7
+ pytest-order
@@ -34,7 +34,7 @@ setup(
34
34
  packages=find_packages(exclude=["dagster_fivetran_tests*"]),
35
35
  include_package_data=True,
36
36
  python_requires=">=3.9,<3.14",
37
- install_requires=["dagster==1.11.13"],
37
+ install_requires=["dagster==1.11.15"],
38
38
  zip_safe=False,
39
39
  entry_points={
40
40
  "console_scripts": [
@@ -46,7 +46,7 @@ setup(
46
46
  },
47
47
  extras_require={
48
48
  "managed": [
49
- "dagster-managed-elements==0.27.13",
49
+ "dagster-managed-elements==0.27.15",
50
50
  ],
51
51
  "test": [
52
52
  "pytest-order",
@@ -1,134 +0,0 @@
1
- from collections.abc import Sequence
2
- from functools import cached_property
3
- from typing import Annotated, Callable, Optional, Union
4
-
5
- import dagster as dg
6
- import pydantic
7
- from dagster._annotations import public
8
- from dagster._core.definitions.job_definition import default_job_io_manager
9
- from dagster.components.resolved.base import resolve_fields
10
- from dagster.components.utils.translation import TranslationFn, TranslationFnResolver
11
- from dagster_shared import check
12
-
13
- from dagster_fivetran.asset_defs import build_fivetran_assets_definitions
14
- from dagster_fivetran.components.workspace_component.scaffolder import (
15
- FivetranAccountComponentScaffolder,
16
- )
17
- from dagster_fivetran.resources import FivetranWorkspace
18
- from dagster_fivetran.translator import (
19
- DagsterFivetranTranslator,
20
- FivetranConnector,
21
- FivetranConnectorTableProps,
22
- )
23
-
24
-
25
- class ProxyDagsterFivetranTranslator(DagsterFivetranTranslator):
26
- def __init__(self, fn: TranslationFn[FivetranConnectorTableProps]):
27
- self.fn = fn
28
-
29
- def get_asset_spec(self, props: FivetranConnectorTableProps) -> dg.AssetSpec:
30
- base_asset_spec = super().get_asset_spec(props)
31
- spec = self.fn(base_asset_spec, props)
32
-
33
- return spec
34
-
35
-
36
- class FivetranWorkspaceModel(pydantic.BaseModel):
37
- account_id: str = pydantic.Field(..., description="The Fivetran account ID.")
38
- api_key: str = pydantic.Field(
39
- ..., description="API key used to authenticate to a Fivetran instance."
40
- )
41
- api_secret: str = pydantic.Field(
42
- ..., description="API secret used to authenticate to a Fivetran instance."
43
- )
44
-
45
-
46
- class FivetranConnectorSelectorByName(pydantic.BaseModel):
47
- by_name: Sequence[str] = pydantic.Field(
48
- ...,
49
- description="A list of connector names to include in the collection.",
50
- )
51
-
52
-
53
- class FivetranConnectorSelectorById(pydantic.BaseModel):
54
- by_id: Sequence[str] = pydantic.Field(
55
- ...,
56
- description="A list of connector IDs to include in the collection.",
57
- )
58
-
59
-
60
- def resolve_connector_selector(
61
- context: dg.ResolutionContext, model
62
- ) -> Optional[Callable[[FivetranConnector], bool]]:
63
- if isinstance(model, str):
64
- model = context.resolve_value(model)
65
-
66
- if isinstance(model, FivetranConnectorSelectorByName):
67
- return lambda connector: connector.name in model.by_name
68
- elif isinstance(model, FivetranConnectorSelectorById):
69
- return lambda connector: connector.id in model.by_id
70
- else:
71
- check.failed(f"Unknown connector target type: {type(model)}")
72
-
73
-
74
- @public
75
- @dg.scaffold_with(FivetranAccountComponentScaffolder)
76
- class FivetranAccountComponent(dg.Component, dg.Model, dg.Resolvable):
77
- """Loads Fivetran connectors from a given Fivetran instance as Dagster assets.
78
- Materializing these assets will trigger a sync of the Fivetran connector, enabling
79
- you to schedule Fivetran syncs using Dagster.
80
- """
81
-
82
- workspace: Annotated[
83
- FivetranWorkspace,
84
- dg.Resolver(
85
- lambda context, model: FivetranWorkspace(
86
- **resolve_fields(model, FivetranWorkspace, context)
87
- )
88
- ),
89
- ]
90
- connector_selector: Annotated[
91
- Optional[Callable[[FivetranConnector], bool]],
92
- dg.Resolver(
93
- resolve_connector_selector,
94
- model_field_type=Union[
95
- str, FivetranConnectorSelectorByName, FivetranConnectorSelectorById
96
- ],
97
- ),
98
- ] = None
99
- translation: Optional[
100
- Annotated[
101
- TranslationFn[FivetranConnectorTableProps],
102
- TranslationFnResolver(template_vars_for_translation_fn=lambda data: {"props": data}),
103
- ]
104
- ] = pydantic.Field(
105
- None,
106
- description="Function used to translate Fivetran connector table properties into Dagster asset specs.",
107
- )
108
-
109
- @cached_property
110
- def workspace_resource(self) -> FivetranWorkspace:
111
- return self.workspace
112
-
113
- @cached_property
114
- def translator(self) -> DagsterFivetranTranslator:
115
- if self.translation:
116
- return ProxyDagsterFivetranTranslator(self.translation)
117
- return DagsterFivetranTranslator()
118
-
119
- def build_defs(self, context: dg.ComponentLoadContext) -> dg.Definitions:
120
- fivetran_assets = build_fivetran_assets_definitions(
121
- workspace=self.workspace_resource,
122
- dagster_fivetran_translator=self.translator,
123
- connector_selector_fn=self.connector_selector,
124
- )
125
- assets_with_resource = [
126
- fivetran_asset.with_resources(
127
- {
128
- "fivetran": self.workspace_resource.get_resource_definition(),
129
- "io_manager": default_job_io_manager,
130
- }
131
- )
132
- for fivetran_asset in fivetran_assets
133
- ]
134
- return dg.Definitions(assets=assets_with_resource)
@@ -1 +0,0 @@
1
- __version__ = "0.27.13"
@@ -1,7 +0,0 @@
1
- dagster==1.11.13
2
-
3
- [managed]
4
- dagster-managed-elements==0.27.13
5
-
6
- [test]
7
- pytest-order