dagster-sling 0.26.20__tar.gz → 0.27.0__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.

Potentially problematic release.


This version of dagster-sling might be problematic. Click here for more details.

Files changed (28) hide show
  1. {dagster_sling-0.26.20/dagster_sling.egg-info → dagster_sling-0.27.0}/PKG-INFO +2 -2
  2. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/dagster_sling/asset_decorator.py +32 -18
  3. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/dagster_sling/components/sling_replication_collection/component.py +88 -15
  4. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/dagster_sling/dagster_sling_translator.py +5 -5
  5. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/dagster_sling/resources.py +2 -0
  6. dagster_sling-0.27.0/dagster_sling/version.py +1 -0
  7. {dagster_sling-0.26.20 → dagster_sling-0.27.0/dagster_sling.egg-info}/PKG-INFO +2 -2
  8. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/dagster_sling.egg-info/requires.txt +1 -1
  9. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/setup.py +1 -1
  10. dagster_sling-0.26.20/dagster_sling/version.py +0 -1
  11. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/LICENSE +0 -0
  12. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/MANIFEST.in +0 -0
  13. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/README.md +0 -0
  14. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/dagster_sling/__init__.py +0 -0
  15. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/dagster_sling/asset_defs.py +0 -0
  16. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/dagster_sling/components/__init__.py +0 -0
  17. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/dagster_sling/components/sling_replication_collection/__init__.py +0 -0
  18. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/dagster_sling/components/sling_replication_collection/scaffolder.py +0 -0
  19. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/dagster_sling/py.typed +0 -0
  20. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/dagster_sling/sling_event_iterator.py +0 -0
  21. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/dagster_sling/sling_replication.py +0 -0
  22. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/dagster_sling.egg-info/SOURCES.txt +0 -0
  23. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/dagster_sling.egg-info/dependency_links.txt +0 -0
  24. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/dagster_sling.egg-info/entry_points.txt +0 -0
  25. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/dagster_sling.egg-info/not-zip-safe +0 -0
  26. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/dagster_sling.egg-info/top_level.txt +0 -0
  27. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/integration.yaml +0 -0
  28. {dagster_sling-0.26.20 → dagster_sling-0.27.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dagster-sling
3
- Version: 0.26.20
3
+ Version: 0.27.0
4
4
  Summary: Package for performing ETL/ELT tasks with Sling in Dagster.
5
5
  Home-page: https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-sling
6
6
  Author: Dagster Labs
@@ -14,7 +14,7 @@ Classifier: License :: OSI Approved :: Apache Software License
14
14
  Classifier: Operating System :: OS Independent
15
15
  Requires-Python: >=3.9,<3.13
16
16
  License-File: LICENSE
17
- Requires-Dist: dagster==1.10.20
17
+ Requires-Dist: dagster==1.11.0
18
18
  Requires-Dist: sling>=1.1.5
19
19
  Requires-Dist: sling-mac-arm64; platform_system == "Darwin" and platform_machine == "arm64"
20
20
  Provides-Extra: test
@@ -104,6 +104,22 @@ def sling_assets(
104
104
  def my_assets(context, sling: SlingResource):
105
105
  yield from sling.replicate(context=context)
106
106
  """
107
+ return multi_asset(
108
+ name=name,
109
+ partitions_def=partitions_def,
110
+ can_subset=True,
111
+ op_tags=op_tags,
112
+ backfill_policy=backfill_policy,
113
+ specs=get_sling_asset_specs(replication_config, dagster_sling_translator, partitions_def),
114
+ pool=pool,
115
+ )
116
+
117
+
118
+ def get_sling_asset_specs(
119
+ replication_config: SlingReplicationParam,
120
+ dagster_sling_translator: Optional[DagsterSlingTranslator] = None,
121
+ partitions_def: Optional[PartitionsDefinition] = None,
122
+ ) -> list[AssetSpec]:
107
123
  replication_config = validate_replication(replication_config)
108
124
 
109
125
  raw_streams = get_streams_from_replication(replication_config)
@@ -124,22 +140,20 @@ def sling_assets(
124
140
  return asset_spec.replace_attributes(code_version=code_version)
125
141
  return asset_spec
126
142
 
127
- return multi_asset(
128
- name=name,
129
- partitions_def=partitions_def,
130
- can_subset=True,
131
- op_tags=op_tags,
132
- backfill_policy=backfill_policy,
133
- specs=[
134
- update_code_version_if_unset_by_translator(
135
- dagster_sling_translator.get_asset_spec(stream).merge_attributes(
136
- metadata={
137
- METADATA_KEY_TRANSLATOR: dagster_sling_translator,
138
- METADATA_KEY_REPLICATION_CONFIG: replication_config,
139
- }
140
- )
143
+ base_specs = [
144
+ update_code_version_if_unset_by_translator(
145
+ dagster_sling_translator.get_asset_spec(stream).merge_attributes(
146
+ metadata={
147
+ METADATA_KEY_TRANSLATOR: dagster_sling_translator,
148
+ METADATA_KEY_REPLICATION_CONFIG: replication_config,
149
+ }
141
150
  )
142
- for stream in streams
143
- ],
144
- pool=pool,
145
- )
151
+ )
152
+ for stream in streams
153
+ ]
154
+ return [
155
+ spec.replace_attributes(
156
+ partitions_def=partitions_def or spec.partitions_def, skippable=True
157
+ )
158
+ for spec in base_specs
159
+ ]
@@ -1,3 +1,4 @@
1
+ import textwrap
1
2
  from collections.abc import Iterator, Mapping, Sequence
2
3
  from dataclasses import dataclass, field
3
4
  from functools import cached_property
@@ -20,6 +21,8 @@ from dagster.components.resolved.context import ResolutionContext
20
21
  from dagster.components.resolved.core_models import AssetAttributesModel, AssetPostProcessor, OpSpec
21
22
  from dagster.components.scaffold.scaffold import scaffold_with
22
23
  from dagster.components.utils import TranslatorResolvingInfo
24
+ from dagster_shared.utils.warnings import deprecation_warning
25
+ from pydantic import BaseModel, ConfigDict, Field
23
26
  from typing_extensions import TypeAlias
24
27
 
25
28
  from dagster_sling.asset_decorator import sling_assets
@@ -27,7 +30,7 @@ from dagster_sling.components.sling_replication_collection.scaffolder import (
27
30
  SlingReplicationComponentScaffolder,
28
31
  )
29
32
  from dagster_sling.dagster_sling_translator import DagsterSlingTranslator
30
- from dagster_sling.resources import AssetExecutionContext, SlingResource
33
+ from dagster_sling.resources import AssetExecutionContext, SlingConnectionResource, SlingResource
31
34
 
32
35
  SlingMetadataAddons: TypeAlias = Literal["column_metadata", "row_count"]
33
36
 
@@ -86,8 +89,57 @@ class SlingReplicationSpecModel(Resolvable):
86
89
  def resolve_resource(
87
90
  context: ResolutionContext,
88
91
  sling,
89
- ) -> SlingResource:
90
- return SlingResource(**context.resolve_value(sling.model_dump())) if sling else SlingResource()
92
+ ) -> Optional[SlingResource]:
93
+ if sling:
94
+ deprecation_warning(
95
+ "The `sling` field is deprecated, use `connections` instead. This field will be removed in a future release.",
96
+ "1.11.1",
97
+ )
98
+ return SlingResource(**context.resolve_value(sling.model_dump())) if sling else None
99
+
100
+
101
+ def replicate(
102
+ context: AssetExecutionContext,
103
+ connections: list[SlingConnectionResource],
104
+ ) -> Iterator[Union[AssetMaterialization, MaterializeResult]]:
105
+ sling = SlingResource(connections=connections)
106
+ yield from sling.replicate(context=context)
107
+
108
+
109
+ class SlingConnectionResourcePropertiesModel(Resolvable, BaseModel):
110
+ """Properties of a Sling connection resource."""
111
+
112
+ # each connection type supports a variety of different properties
113
+ model_config = ConfigDict(extra="allow")
114
+
115
+ type: str = Field(
116
+ description="Type of the source connection, must match the Sling connection types. Use 'file' for local storage."
117
+ )
118
+ connection_string: Optional[str] = Field(
119
+ description="The optional connection string for the source database, if not using keyword arguments.",
120
+ default=None,
121
+ )
122
+
123
+
124
+ def resolve_connections(
125
+ context: ResolutionContext,
126
+ connections: Mapping[str, SlingConnectionResourcePropertiesModel],
127
+ ) -> list[SlingConnectionResource]:
128
+ return [
129
+ SlingConnectionResource(
130
+ name=name,
131
+ **context.resolve_value(connection.model_dump()),
132
+ )
133
+ for name, connection in connections.items()
134
+ ]
135
+
136
+
137
+ ResolvedSlingConnections: TypeAlias = Annotated[
138
+ list[SlingConnectionResource],
139
+ Resolver(
140
+ resolve_connections, model_field_type=Mapping[str, SlingConnectionResourcePropertiesModel]
141
+ ),
142
+ ]
91
143
 
92
144
 
93
145
  @scaffold_with(SlingReplicationComponentScaffolder)
@@ -104,15 +156,18 @@ class SlingReplicationCollectionComponent(Component, Resolvable):
104
156
  file. See Sling's [documentation](https://docs.slingdata.io/concepts/replication#overview) on `replication.yaml`.
105
157
  """
106
158
 
107
- resource: Annotated[
108
- SlingResource,
109
- Resolver(
110
- resolve_resource,
111
- model_field_name="sling",
112
- ),
113
- ] = field(default_factory=SlingResource)
159
+ connections: ResolvedSlingConnections = field(default_factory=list)
114
160
  replications: Sequence[SlingReplicationSpecModel] = field(default_factory=list)
161
+ # TODO: deprecate and then delete -- schrockn 2025-06-10
115
162
  asset_post_processors: Optional[Sequence[AssetPostProcessor]] = None
163
+ resource: Annotated[
164
+ Optional[SlingResource],
165
+ Resolver(resolve_resource, model_field_name="sling"),
166
+ ] = None
167
+
168
+ @cached_property
169
+ def sling_resource(self) -> SlingResource:
170
+ return self.resource or SlingResource(connections=self.connections)
116
171
 
117
172
  def build_asset(
118
173
  self, context: ComponentLoadContext, replication_spec_model: SlingReplicationSpecModel
@@ -140,7 +195,9 @@ class SlingReplicationCollectionComponent(Component, Resolvable):
140
195
  )
141
196
  def _asset(context: AssetExecutionContext):
142
197
  yield from self.execute(
143
- context=context, sling=self.resource, replication_spec_model=replication_spec_model
198
+ context=context,
199
+ sling=self.sling_resource,
200
+ replication_spec_model=replication_spec_model,
144
201
  )
145
202
 
146
203
  return _asset
@@ -159,9 +216,25 @@ class SlingReplicationCollectionComponent(Component, Resolvable):
159
216
  yield from iterator
160
217
 
161
218
  def build_defs(self, context: ComponentLoadContext) -> Definitions:
162
- defs = Definitions(
219
+ if self.asset_post_processors:
220
+ raise Exception(
221
+ "The asset_post_processors field is deprecated, place your post-processors in the assets"
222
+ " field in the top-level post_processing field instead, as in this example:\n"
223
+ + textwrap.dedent(
224
+ """
225
+ type: dagster_sling.SlingReplicationCollectionComponent
226
+
227
+ attributes: ~
228
+
229
+ post_processing:
230
+ assets:
231
+ - target: "*"
232
+ attributes:
233
+ group_name: "my_group"
234
+ """
235
+ )
236
+ )
237
+
238
+ return Definitions(
163
239
  assets=[self.build_asset(context, replication) for replication in self.replications],
164
240
  )
165
- for post_processor in self.asset_post_processors or []:
166
- defs = post_processor(defs)
167
- return defs
@@ -2,7 +2,7 @@ from collections.abc import Iterable, Mapping
2
2
  from dataclasses import dataclass
3
3
  from typing import Any, Callable, Optional
4
4
 
5
- from dagster import AssetKey, AssetSpec, AutoMaterializePolicy, FreshnessPolicy, MetadataValue
5
+ from dagster import AssetKey, AssetSpec, AutoMaterializePolicy, LegacyFreshnessPolicy, MetadataValue
6
6
  from dagster._annotations import public, superseded
7
7
  from dagster._utils.names import clean_name_lower_with_dots
8
8
  from dagster._utils.warnings import supersession_warning
@@ -42,7 +42,7 @@ class DagsterSlingTranslator:
42
42
  group_name=self._resolve_back_compat_method(
43
43
  "get_group_name", self._default_group_name_fn, stream_definition
44
44
  ),
45
- freshness_policy=self._resolve_back_compat_method(
45
+ legacy_freshness_policy=self._resolve_back_compat_method(
46
46
  "get_freshness_policy", self._default_freshness_policy_fn, stream_definition
47
47
  ),
48
48
  auto_materialize_policy=self._resolve_back_compat_method(
@@ -471,7 +471,7 @@ class DagsterSlingTranslator:
471
471
  @public
472
472
  def get_freshness_policy(
473
473
  self, stream_definition: Mapping[str, Any]
474
- ) -> Optional[FreshnessPolicy]:
474
+ ) -> Optional[LegacyFreshnessPolicy]:
475
475
  """Retrieves the freshness policy for a given stream definition.
476
476
 
477
477
  This method checks the provided stream definition for a specific configuration
@@ -491,7 +491,7 @@ class DagsterSlingTranslator:
491
491
 
492
492
  def _default_freshness_policy_fn(
493
493
  self, stream_definition: Mapping[str, Any]
494
- ) -> Optional[FreshnessPolicy]:
494
+ ) -> Optional[LegacyFreshnessPolicy]:
495
495
  """Retrieves the freshness policy for a given stream definition.
496
496
 
497
497
  This method checks the provided stream definition for a specific configuration
@@ -511,7 +511,7 @@ class DagsterSlingTranslator:
511
511
  meta = config.get("meta", {})
512
512
  freshness_policy_config = meta.get("dagster", {}).get("freshness_policy")
513
513
  if freshness_policy_config:
514
- return FreshnessPolicy(
514
+ return LegacyFreshnessPolicy(
515
515
  maximum_lag_minutes=float(freshness_policy_config["maximum_lag_minutes"]),
516
516
  cron_schedule=freshness_policy_config.get("cron_schedule"),
517
517
  cron_schedule_timezone=freshness_policy_config.get("cron_schedule_timezone"),
@@ -635,6 +635,8 @@ def _process_env_vars(config: dict[str, Any]) -> dict[str, Any]:
635
635
  for key, value in config.items():
636
636
  if isinstance(value, dict) and len(value) == 1 and next(iter(value.keys())) == "env":
637
637
  out[key] = EnvVar(next(iter(value.values()))).get_value()
638
+ elif isinstance(value, EnvVar):
639
+ out[key] = value.get_value()
638
640
  else:
639
641
  out[key] = value
640
642
  return out
@@ -0,0 +1 @@
1
+ __version__ = "0.27.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dagster-sling
3
- Version: 0.26.20
3
+ Version: 0.27.0
4
4
  Summary: Package for performing ETL/ELT tasks with Sling in Dagster.
5
5
  Home-page: https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-sling
6
6
  Author: Dagster Labs
@@ -14,7 +14,7 @@ Classifier: License :: OSI Approved :: Apache Software License
14
14
  Classifier: Operating System :: OS Independent
15
15
  Requires-Python: >=3.9,<3.13
16
16
  License-File: LICENSE
17
- Requires-Dist: dagster==1.10.20
17
+ Requires-Dist: dagster==1.11.0
18
18
  Requires-Dist: sling>=1.1.5
19
19
  Requires-Dist: sling-mac-arm64; platform_system == "Darwin" and platform_machine == "arm64"
20
20
  Provides-Extra: test
@@ -1,4 +1,4 @@
1
- dagster==1.10.20
1
+ dagster==1.11.0
2
2
  sling>=1.1.5
3
3
 
4
4
  [:platform_system == "Darwin" and platform_machine == "arm64"]
@@ -34,7 +34,7 @@ setup(
34
34
  include_package_data=True,
35
35
  python_requires=">=3.9,<3.13",
36
36
  install_requires=[
37
- "dagster==1.10.20",
37
+ "dagster==1.11.0",
38
38
  "sling>=1.1.5",
39
39
  # Required due to a bug in uv that can cause sling-linux-amd64 to be installed instead.
40
40
  # See: https://github.com/astral-sh/uv/issues/10945
@@ -1 +0,0 @@
1
- __version__ = "0.26.20"
File without changes