dagster-fivetran 0.28.1__tar.gz → 0.28.3__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 (35) hide show
  1. {dagster_fivetran-0.28.1/dagster_fivetran.egg-info → dagster_fivetran-0.28.3}/PKG-INFO +4 -5
  2. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran/__init__.py +1 -0
  3. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran/asset_decorator.py +2 -1
  4. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran/asset_defs.py +2 -2
  5. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran/components/workspace_component/component.py +2 -2
  6. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran/fivetran_event_iterator.py +2 -2
  7. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran/resources.py +140 -6
  8. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran/translator.py +2 -3
  9. dagster_fivetran-0.28.3/dagster_fivetran/version.py +1 -0
  10. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3/dagster_fivetran.egg-info}/PKG-INFO +4 -5
  11. dagster_fivetran-0.28.3/dagster_fivetran.egg-info/requires.txt +7 -0
  12. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/setup.py +3 -4
  13. dagster_fivetran-0.28.1/dagster_fivetran/version.py +0 -1
  14. dagster_fivetran-0.28.1/dagster_fivetran.egg-info/requires.txt +0 -7
  15. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/LICENSE +0 -0
  16. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/MANIFEST.in +0 -0
  17. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/README.md +0 -0
  18. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran/cli.py +0 -0
  19. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran/components/__init__.py +0 -0
  20. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran/components/workspace_component/__init__.py +0 -0
  21. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran/components/workspace_component/scaffolder.py +0 -0
  22. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran/constants.py +0 -0
  23. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran/managed/__init__.py +0 -0
  24. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran/managed/reconciliation.py +0 -0
  25. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran/managed/types.py +0 -0
  26. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran/ops.py +0 -0
  27. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran/py.typed +0 -0
  28. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran/types.py +0 -0
  29. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran/utils.py +0 -0
  30. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran.egg-info/SOURCES.txt +0 -0
  31. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran.egg-info/dependency_links.txt +0 -0
  32. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran.egg-info/entry_points.txt +0 -0
  33. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran.egg-info/not-zip-safe +0 -0
  34. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/dagster_fivetran.egg-info/top_level.txt +0 -0
  35. {dagster_fivetran-0.28.1 → dagster_fivetran-0.28.3}/setup.cfg +0 -0
@@ -1,23 +1,22 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dagster-fivetran
3
- Version: 0.28.1
3
+ Version: 0.28.3
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
7
7
  Author-email: hello@dagsterlabs.com
8
8
  License: Apache-2.0
9
- Classifier: Programming Language :: Python :: 3.9
10
9
  Classifier: Programming Language :: Python :: 3.10
11
10
  Classifier: Programming Language :: Python :: 3.11
12
11
  Classifier: Programming Language :: Python :: 3.12
13
12
  Classifier: Programming Language :: Python :: 3.13
14
13
  Classifier: License :: OSI Approved :: Apache Software License
15
14
  Classifier: Operating System :: OS Independent
16
- Requires-Python: >=3.9,<3.14
15
+ Requires-Python: >=3.10,<3.14
17
16
  License-File: LICENSE
18
- Requires-Dist: dagster==1.12.1
17
+ Requires-Dist: dagster==1.12.3
19
18
  Provides-Extra: managed
20
- Requires-Dist: dagster-managed-elements==0.28.1; extra == "managed"
19
+ Requires-Dist: dagster-managed-elements==0.28.3; extra == "managed"
21
20
  Provides-Extra: test
22
21
  Requires-Dist: pytest-order; extra == "test"
23
22
  Dynamic: author
@@ -15,6 +15,7 @@ from dagster_fivetran.ops import (
15
15
  )
16
16
  from dagster_fivetran.resources import (
17
17
  FivetranResource as FivetranResource,
18
+ FivetranSyncConfig as FivetranSyncConfig,
18
19
  FivetranWorkspace as FivetranWorkspace,
19
20
  fivetran_resource as fivetran_resource,
20
21
  load_fivetran_asset_specs as load_fivetran_asset_specs,
@@ -1,4 +1,5 @@
1
- from typing import Any, Callable, Optional
1
+ from collections.abc import Callable
2
+ from typing import Any, Optional
2
3
 
3
4
  from dagster import AssetsDefinition, multi_asset
4
5
  from dagster._core.errors import DagsterInvariantViolationError
@@ -1,9 +1,9 @@
1
1
  import hashlib
2
2
  import inspect
3
- from collections.abc import Mapping, Sequence
3
+ from collections.abc import Callable, Mapping, Sequence
4
4
  from concurrent.futures import ThreadPoolExecutor
5
5
  from functools import partial
6
- from typing import Any, Callable, NamedTuple, Optional, Union, cast
6
+ from typing import Any, NamedTuple, Optional, Union, cast
7
7
 
8
8
  from dagster import (
9
9
  AssetExecutionContext,
@@ -1,8 +1,8 @@
1
1
  from collections import defaultdict
2
- from collections.abc import Iterable, Sequence
2
+ from collections.abc import Callable, Iterable, Sequence
3
3
  from functools import cached_property
4
4
  from pathlib import Path
5
- from typing import Annotated, Callable, Optional, Union
5
+ from typing import Annotated, Optional, Union
6
6
 
7
7
  import dagster as dg
8
8
  import pydantic
@@ -1,7 +1,7 @@
1
1
  import os
2
- from collections.abc import Iterator
2
+ from collections.abc import Callable, Iterator
3
3
  from concurrent.futures import ThreadPoolExecutor
4
- from typing import TYPE_CHECKING, Any, Callable, Union
4
+ from typing import TYPE_CHECKING, Any, Union
5
5
 
6
6
  from dagster import (
7
7
  AssetExecutionContext,
@@ -2,17 +2,18 @@ import json
2
2
  import logging
3
3
  import os
4
4
  import time
5
- from collections.abc import Mapping, Sequence
5
+ from collections.abc import Callable, Mapping, Sequence
6
6
  from datetime import datetime, timedelta
7
7
  from functools import cached_property, partial
8
8
  from pathlib import Path
9
- from typing import Any, Callable, Optional, Union
9
+ from typing import Any, Optional, Union
10
10
  from urllib.parse import urljoin
11
11
 
12
12
  import requests
13
13
  from dagster import (
14
14
  AssetExecutionContext,
15
15
  AssetMaterialization,
16
+ Config,
16
17
  Definitions,
17
18
  Failure,
18
19
  InitResourceContext,
@@ -928,6 +929,29 @@ class FivetranClient:
928
929
  return FivetranOutput(connector_details=final_details, schema_config=schema_config_details)
929
930
 
930
931
 
932
+ class FivetranSyncConfig(Config):
933
+ """Configuration for controlling Fivetran sync behavior.
934
+
935
+ Attributes:
936
+ resync: If True, performs a historical resync. If False, performs a normal sync.
937
+ resync_parameters: Optional parameters to control which tables to resync.
938
+ If not provided with resync=True, all tables will be resynced.
939
+ Example: {"schema_name": ["table1", "table2"], "another_schema": ["table3"]}
940
+ """
941
+
942
+ resync: bool = Field(
943
+ default=False,
944
+ description="Whether to perform a historical resync instead of a normal sync",
945
+ )
946
+ resync_parameters: Optional[dict[str, Any]] = Field(
947
+ default=None,
948
+ description=(
949
+ "Optional parameters to control which tables to resync. "
950
+ "If not provided with resync=True, all tables will be resynced."
951
+ ),
952
+ )
953
+
954
+
931
955
  class FivetranWorkspace(ConfigurableResource):
932
956
  """This class represents a Fivetran workspace and provides utilities
933
957
  to interact with Fivetran APIs.
@@ -1185,7 +1209,9 @@ class FivetranWorkspace(ConfigurableResource):
1185
1209
 
1186
1210
  @public
1187
1211
  def sync_and_poll(
1188
- self, context: AssetExecutionContext
1212
+ self,
1213
+ context: AssetExecutionContext,
1214
+ config: Optional[FivetranSyncConfig] = None,
1189
1215
  ) -> FivetranEventIterator[Union[AssetMaterialization, MaterializeResult]]:
1190
1216
  """Executes a sync and poll process to materialize Fivetran assets.
1191
1217
  This method can only be used in the context of an asset execution.
@@ -1193,14 +1219,74 @@ class FivetranWorkspace(ConfigurableResource):
1193
1219
  Args:
1194
1220
  context (AssetExecutionContext): The execution context
1195
1221
  from within `@fivetran_assets`.
1222
+ config (Optional[FivetranSyncConfig]): Optional configuration to control sync behavior.
1223
+ If config.resync is True, performs a historical resync instead of a normal sync.
1224
+ If config.resync_parameters is provided, only the specified tables will be resynced.
1196
1225
 
1197
1226
  Returns:
1198
1227
  Iterator[Union[AssetMaterialization, MaterializeResult]]: An iterator of MaterializeResult
1199
1228
  or AssetMaterialization.
1229
+
1230
+ Examples:
1231
+ Normal sync (without config):
1232
+
1233
+ .. code-block:: python
1234
+
1235
+ from dagster import AssetExecutionContext
1236
+ from dagster_fivetran import FivetranWorkspace, fivetran_assets
1237
+
1238
+ @fivetran_assets(connector_id="my_connector", workspace=fivetran_workspace)
1239
+ def my_fivetran_assets(context: AssetExecutionContext, fivetran: FivetranWorkspace):
1240
+ yield from fivetran.sync_and_poll(context=context)
1241
+
1242
+ Historical resync of specific tables (config passed at runtime):
1243
+
1244
+ .. code-block:: python
1245
+
1246
+ from dagster import AssetExecutionContext
1247
+ from dagster_fivetran import FivetranWorkspace, FivetranSyncConfig, fivetran_assets
1248
+
1249
+ @fivetran_assets(connector_id="my_connector", workspace=fivetran_workspace)
1250
+ def my_fivetran_assets(
1251
+ context: AssetExecutionContext,
1252
+ fivetran: FivetranWorkspace,
1253
+ config: FivetranSyncConfig,
1254
+ ):
1255
+ # When materializing, pass config with:
1256
+ # resync=True
1257
+ # resync_parameters={"schema_name": ["table1", "table2"]}
1258
+ yield from fivetran.sync_and_poll(context=context, config=config)
1259
+
1260
+ Full historical resync (config passed at runtime):
1261
+
1262
+ .. code-block:: python
1263
+
1264
+ from dagster import AssetExecutionContext
1265
+ from dagster_fivetran import FivetranWorkspace, FivetranSyncConfig, fivetran_assets
1266
+
1267
+ @fivetran_assets(connector_id="my_connector", workspace=fivetran_workspace)
1268
+ def my_fivetran_assets(
1269
+ context: AssetExecutionContext,
1270
+ fivetran: FivetranWorkspace,
1271
+ config: FivetranSyncConfig,
1272
+ ):
1273
+ # When materializing, pass config with resync=True to resync all tables
1274
+ yield from fivetran.sync_and_poll(context=context, config=config)
1200
1275
  """
1201
- return FivetranEventIterator(
1202
- events=self._sync_and_poll(context=context), fivetran_workspace=self, context=context
1203
- )
1276
+ if config and config.resync:
1277
+ return FivetranEventIterator(
1278
+ events=self._resync_and_poll(
1279
+ context=context, resync_parameters=config.resync_parameters
1280
+ ),
1281
+ fivetran_workspace=self,
1282
+ context=context,
1283
+ )
1284
+ else:
1285
+ return FivetranEventIterator(
1286
+ events=self._sync_and_poll(context=context),
1287
+ fivetran_workspace=self,
1288
+ context=context,
1289
+ )
1204
1290
 
1205
1291
  def _sync_and_poll(self, context: AssetExecutionContext):
1206
1292
  assets_def = context.assets_def
@@ -1245,6 +1331,54 @@ class FivetranWorkspace(ConfigurableResource):
1245
1331
  if unmaterialized_asset_keys:
1246
1332
  context.log.warning(f"Assets were not materialized: {unmaterialized_asset_keys}")
1247
1333
 
1334
+ def _resync_and_poll(
1335
+ self,
1336
+ context: AssetExecutionContext,
1337
+ resync_parameters: Optional[Mapping[str, Sequence[str]]] = None,
1338
+ ):
1339
+ assets_def = context.assets_def
1340
+ dagster_fivetran_translator = get_translator_from_fivetran_assets(assets_def)
1341
+ connector_id = next(
1342
+ check.not_none(FivetranMetadataSet.extract(spec.metadata).connector_id)
1343
+ for spec in assets_def.specs
1344
+ )
1345
+
1346
+ client = self.get_client()
1347
+ fivetran_output = client.resync_and_poll(
1348
+ connector_id=connector_id,
1349
+ resync_parameters=resync_parameters,
1350
+ )
1351
+
1352
+ # The FivetranOutput is None if the connector hasn't been synced
1353
+ if not fivetran_output:
1354
+ context.log.warning(
1355
+ f"The connector with ID {connector_id} is currently paused and so it has not been resynced. "
1356
+ f"Make sure that your connector is enabled before resyncing it with Dagster."
1357
+ )
1358
+ return
1359
+
1360
+ materialized_asset_keys = set()
1361
+ for materialization in self._generate_materialization(
1362
+ fivetran_output=fivetran_output, dagster_fivetran_translator=dagster_fivetran_translator
1363
+ ):
1364
+ # Scan through all tables actually created, if it was expected then emit a MaterializeResult.
1365
+ # Otherwise, emit a runtime AssetMaterialization.
1366
+ if materialization.asset_key in context.selected_asset_keys:
1367
+ yield MaterializeResult(
1368
+ asset_key=materialization.asset_key, metadata=materialization.metadata
1369
+ )
1370
+ materialized_asset_keys.add(materialization.asset_key)
1371
+ else:
1372
+ context.log.warning(
1373
+ f"An unexpected asset was materialized: {materialization.asset_key}. "
1374
+ f"Yielding a materialization event."
1375
+ )
1376
+ yield materialization
1377
+
1378
+ unmaterialized_asset_keys = context.selected_asset_keys - materialized_asset_keys
1379
+ if unmaterialized_asset_keys:
1380
+ context.log.warning(f"Assets were not materialized: {unmaterialized_asset_keys}")
1381
+
1248
1382
 
1249
1383
  def load_fivetran_asset_specs(
1250
1384
  workspace: FivetranWorkspace,
@@ -1,7 +1,7 @@
1
- from collections.abc import Mapping, Sequence
1
+ from collections.abc import Callable, Mapping, Sequence
2
2
  from datetime import datetime
3
3
  from enum import Enum
4
- from typing import Any, Callable, NamedTuple, Optional
4
+ from typing import Any, NamedTuple, Optional, TypeAlias
5
5
 
6
6
  from dagster import Failure
7
7
  from dagster._core.definitions.asset_key import AssetKey
@@ -12,7 +12,6 @@ from dagster._utils.cached_method import cached_method
12
12
  from dagster._utils.names import clean_name_lower
13
13
  from dagster._vendored.dateutil import parser
14
14
  from dagster_shared.serdes import whitelist_for_serdes
15
- from typing_extensions import TypeAlias
16
15
 
17
16
  from dagster_fivetran.utils import get_fivetran_connector_table_name, metadata_for_table
18
17
 
@@ -0,0 +1 @@
1
+ __version__ = "0.28.3"
@@ -1,23 +1,22 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dagster-fivetran
3
- Version: 0.28.1
3
+ Version: 0.28.3
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
7
7
  Author-email: hello@dagsterlabs.com
8
8
  License: Apache-2.0
9
- Classifier: Programming Language :: Python :: 3.9
10
9
  Classifier: Programming Language :: Python :: 3.10
11
10
  Classifier: Programming Language :: Python :: 3.11
12
11
  Classifier: Programming Language :: Python :: 3.12
13
12
  Classifier: Programming Language :: Python :: 3.13
14
13
  Classifier: License :: OSI Approved :: Apache Software License
15
14
  Classifier: Operating System :: OS Independent
16
- Requires-Python: >=3.9,<3.14
15
+ Requires-Python: >=3.10,<3.14
17
16
  License-File: LICENSE
18
- Requires-Dist: dagster==1.12.1
17
+ Requires-Dist: dagster==1.12.3
19
18
  Provides-Extra: managed
20
- Requires-Dist: dagster-managed-elements==0.28.1; extra == "managed"
19
+ Requires-Dist: dagster-managed-elements==0.28.3; extra == "managed"
21
20
  Provides-Extra: test
22
21
  Requires-Dist: pytest-order; extra == "test"
23
22
  Dynamic: author
@@ -0,0 +1,7 @@
1
+ dagster==1.12.3
2
+
3
+ [managed]
4
+ dagster-managed-elements==0.28.3
5
+
6
+ [test]
7
+ pytest-order
@@ -23,7 +23,6 @@ setup(
23
23
  description="Package for integrating Fivetran with Dagster.",
24
24
  url="https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-fivetran",
25
25
  classifiers=[
26
- "Programming Language :: Python :: 3.9",
27
26
  "Programming Language :: Python :: 3.10",
28
27
  "Programming Language :: Python :: 3.11",
29
28
  "Programming Language :: Python :: 3.12",
@@ -33,8 +32,8 @@ setup(
33
32
  ],
34
33
  packages=find_packages(exclude=["dagster_fivetran_tests*"]),
35
34
  include_package_data=True,
36
- python_requires=">=3.9,<3.14",
37
- install_requires=["dagster==1.12.1"],
35
+ python_requires=">=3.10,<3.14",
36
+ install_requires=["dagster==1.12.3"],
38
37
  zip_safe=False,
39
38
  entry_points={
40
39
  "console_scripts": [
@@ -46,7 +45,7 @@ setup(
46
45
  },
47
46
  extras_require={
48
47
  "managed": [
49
- "dagster-managed-elements==0.28.1",
48
+ "dagster-managed-elements==0.28.3",
50
49
  ],
51
50
  "test": [
52
51
  "pytest-order",
@@ -1 +0,0 @@
1
- __version__ = "0.28.1"
@@ -1,7 +0,0 @@
1
- dagster==1.12.1
2
-
3
- [managed]
4
- dagster-managed-elements==0.28.1
5
-
6
- [test]
7
- pytest-order