dagster-sling 0.25.9__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.
Potentially problematic release.
This version of dagster-sling might be problematic. Click here for more details.
- dagster_sling/__init__.py +18 -0
- dagster_sling/asset_decorator.py +147 -0
- dagster_sling/asset_defs.py +0 -0
- dagster_sling/dagster_sling_translator.py +297 -0
- dagster_sling/py.typed +1 -0
- dagster_sling/resources.py +437 -0
- dagster_sling/sling_event_iterator.py +238 -0
- dagster_sling/sling_replication.py +33 -0
- dagster_sling/version.py +1 -0
- dagster_sling-0.25.9.dist-info/LICENSE +201 -0
- dagster_sling-0.25.9.dist-info/METADATA +21 -0
- dagster_sling-0.25.9.dist-info/RECORD +14 -0
- dagster_sling-0.25.9.dist-info/WHEEL +5 -0
- dagster_sling-0.25.9.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from dagster._core.libraries import DagsterLibraryRegistry
|
|
2
|
+
|
|
3
|
+
from dagster_sling.asset_decorator import sling_assets
|
|
4
|
+
from dagster_sling.dagster_sling_translator import DagsterSlingTranslator
|
|
5
|
+
from dagster_sling.resources import SlingConnectionResource, SlingMode, SlingResource
|
|
6
|
+
from dagster_sling.sling_replication import SlingReplicationParam
|
|
7
|
+
from dagster_sling.version import __version__
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"DagsterSlingTranslator",
|
|
11
|
+
"SlingConnectionResource",
|
|
12
|
+
"SlingMode",
|
|
13
|
+
"SlingReplicationParam",
|
|
14
|
+
"SlingResource",
|
|
15
|
+
"sling_assets",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
DagsterLibraryRegistry.register("dagster-sling", __version__)
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
from collections.abc import Iterable, Mapping
|
|
2
|
+
from copy import deepcopy
|
|
3
|
+
from typing import Any, Callable, Optional
|
|
4
|
+
|
|
5
|
+
from dagster import (
|
|
6
|
+
AssetsDefinition,
|
|
7
|
+
AssetSpec,
|
|
8
|
+
BackfillPolicy,
|
|
9
|
+
PartitionsDefinition,
|
|
10
|
+
_check as check,
|
|
11
|
+
multi_asset,
|
|
12
|
+
)
|
|
13
|
+
from dagster._utils.merger import deep_merge_dicts
|
|
14
|
+
from dagster._utils.security import non_secure_md5_hash_str
|
|
15
|
+
|
|
16
|
+
from dagster_sling.dagster_sling_translator import DagsterSlingTranslator
|
|
17
|
+
from dagster_sling.sling_replication import SlingReplicationParam, validate_replication
|
|
18
|
+
|
|
19
|
+
METADATA_KEY_TRANSLATOR = "dagster_sling/dagster_sling_translator"
|
|
20
|
+
METADATA_KEY_REPLICATION_CONFIG = "dagster_sling/sling_replication_config"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_streams_from_replication(
|
|
24
|
+
replication_config: Mapping[str, Any],
|
|
25
|
+
) -> Iterable[Mapping[str, Any]]:
|
|
26
|
+
"""Returns a list of streams and their configs from a Sling replication config."""
|
|
27
|
+
for stream, config in replication_config.get("streams", {}).items():
|
|
28
|
+
if config and config.get("disabled", False):
|
|
29
|
+
continue
|
|
30
|
+
yield {"name": stream, "config": config}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def streams_with_default_dagster_meta(
|
|
34
|
+
streams: Iterable[Mapping[str, Any]], replication_config: Mapping[str, Any]
|
|
35
|
+
) -> Iterable[Mapping[str, Any]]:
|
|
36
|
+
"""Ensures dagster meta configs in the `defaults` block of the replication_config are passed to
|
|
37
|
+
the assets definition object.
|
|
38
|
+
"""
|
|
39
|
+
default_dagster_meta = replication_config.get("defaults", {}).get("meta", {}).get("dagster", {})
|
|
40
|
+
if not default_dagster_meta:
|
|
41
|
+
yield from streams
|
|
42
|
+
else:
|
|
43
|
+
for stream in streams:
|
|
44
|
+
name = stream["name"]
|
|
45
|
+
config = deepcopy(stream["config"])
|
|
46
|
+
if not config:
|
|
47
|
+
config = {"meta": {"dagster": default_dagster_meta}}
|
|
48
|
+
else:
|
|
49
|
+
config["meta"] = deep_merge_dicts(
|
|
50
|
+
{"dagster": default_dagster_meta}, config.get("meta", {})
|
|
51
|
+
)
|
|
52
|
+
yield {"name": name, "config": config}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def sling_assets(
|
|
56
|
+
*,
|
|
57
|
+
replication_config: SlingReplicationParam,
|
|
58
|
+
dagster_sling_translator: Optional[DagsterSlingTranslator] = None,
|
|
59
|
+
name: Optional[str] = None,
|
|
60
|
+
partitions_def: Optional[PartitionsDefinition] = None,
|
|
61
|
+
backfill_policy: Optional[BackfillPolicy] = None,
|
|
62
|
+
op_tags: Optional[Mapping[str, Any]] = None,
|
|
63
|
+
) -> Callable[[Callable[..., Any]], AssetsDefinition]:
|
|
64
|
+
"""Create a definition for how to materialize a set of Sling replication streams as Dagster assets, as
|
|
65
|
+
described by a Sling replication config. This will create on Asset for every Sling target stream.
|
|
66
|
+
|
|
67
|
+
A Sling Replication config is a configuration that maps sources to destinations. For the full
|
|
68
|
+
spec and descriptions, see `Sling's Documentation <https://docs.slingdata.io/sling-cli/run/configuration>`_.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
replication_config (Union[Mapping[str, Any], str, Path]): A path to a Sling replication config, or a dictionary
|
|
72
|
+
of a replication config.
|
|
73
|
+
dagster_sling_translator: (DagsterSlingTranslator): Allows customization of how to map a Sling stream to a Dagster
|
|
74
|
+
AssetKey.
|
|
75
|
+
name (Optional[str]: The name of the op.
|
|
76
|
+
partitions_def (Optional[PartitionsDefinition]): The partitions definition for this asset.
|
|
77
|
+
backfill_policy (Optional[BackfillPolicy]): The backfill policy for this asset.
|
|
78
|
+
op_tags (Optional[Mapping[str, Any]]): The tags for the underlying op.
|
|
79
|
+
|
|
80
|
+
Examples:
|
|
81
|
+
Running a sync by providing a path to a Sling Replication config:
|
|
82
|
+
|
|
83
|
+
.. code-block:: python
|
|
84
|
+
|
|
85
|
+
from dagster_sling import sling_assets, SlingResource, SlingConnectionResource
|
|
86
|
+
|
|
87
|
+
sling_resource = SlingResource(
|
|
88
|
+
connections=[
|
|
89
|
+
SlingConnectionResource(
|
|
90
|
+
name="MY_POSTGRES", type="postgres", connection_string=EnvVar("POSTGRES_URL")
|
|
91
|
+
),
|
|
92
|
+
SlingConnectionResource(
|
|
93
|
+
name="MY_DUCKDB",
|
|
94
|
+
type="duckdb",
|
|
95
|
+
connection_string="duckdb:///var/tmp/duckdb.db",
|
|
96
|
+
),
|
|
97
|
+
]
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
config_path = "/path/to/replication.yaml"
|
|
101
|
+
@sling_assets(replication_config=config_path)
|
|
102
|
+
def my_assets(context, sling: SlingResource):
|
|
103
|
+
yield from sling.replicate(context=context)
|
|
104
|
+
"""
|
|
105
|
+
replication_config = validate_replication(replication_config)
|
|
106
|
+
|
|
107
|
+
raw_streams = get_streams_from_replication(replication_config)
|
|
108
|
+
|
|
109
|
+
streams = streams_with_default_dagster_meta(raw_streams, replication_config)
|
|
110
|
+
|
|
111
|
+
code_version = non_secure_md5_hash_str(str(replication_config).encode())
|
|
112
|
+
|
|
113
|
+
dagster_sling_translator = (
|
|
114
|
+
check.opt_inst_param(
|
|
115
|
+
dagster_sling_translator, "dagster_sling_translator", DagsterSlingTranslator
|
|
116
|
+
)
|
|
117
|
+
or DagsterSlingTranslator()
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
return multi_asset(
|
|
121
|
+
name=name,
|
|
122
|
+
partitions_def=partitions_def,
|
|
123
|
+
can_subset=True,
|
|
124
|
+
op_tags=op_tags,
|
|
125
|
+
backfill_policy=backfill_policy,
|
|
126
|
+
specs=[
|
|
127
|
+
AssetSpec(
|
|
128
|
+
key=dagster_sling_translator.get_asset_key(stream),
|
|
129
|
+
deps=dagster_sling_translator.get_deps_asset_key(stream),
|
|
130
|
+
description=dagster_sling_translator.get_description(stream),
|
|
131
|
+
metadata={
|
|
132
|
+
**dagster_sling_translator.get_metadata(stream),
|
|
133
|
+
METADATA_KEY_TRANSLATOR: dagster_sling_translator,
|
|
134
|
+
METADATA_KEY_REPLICATION_CONFIG: replication_config,
|
|
135
|
+
},
|
|
136
|
+
tags=dagster_sling_translator.get_tags(stream),
|
|
137
|
+
kinds=dagster_sling_translator.get_kinds(stream),
|
|
138
|
+
group_name=dagster_sling_translator.get_group_name(stream),
|
|
139
|
+
freshness_policy=dagster_sling_translator.get_freshness_policy(stream),
|
|
140
|
+
auto_materialize_policy=dagster_sling_translator.get_auto_materialize_policy(
|
|
141
|
+
stream
|
|
142
|
+
),
|
|
143
|
+
code_version=code_version,
|
|
144
|
+
)
|
|
145
|
+
for stream in streams
|
|
146
|
+
],
|
|
147
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from collections.abc import Iterable, Mapping
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any, Optional
|
|
5
|
+
|
|
6
|
+
from dagster import AssetKey, AutoMaterializePolicy, FreshnessPolicy, MetadataValue
|
|
7
|
+
from dagster._annotations import public
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class DagsterSlingTranslator:
|
|
12
|
+
target_prefix: str = "target"
|
|
13
|
+
|
|
14
|
+
@public
|
|
15
|
+
def sanitize_stream_name(self, stream_name: str) -> str:
|
|
16
|
+
"""A function that takes a stream name from a Sling replication config and returns a
|
|
17
|
+
sanitized name for the stream.
|
|
18
|
+
|
|
19
|
+
By default, this removes any non-alphanumeric characters from the stream name and replaces
|
|
20
|
+
them with underscores, while removing any double quotes.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
stream_name (str): The name of the stream.
|
|
24
|
+
|
|
25
|
+
Examples:
|
|
26
|
+
Using a custom stream name sanitizer:
|
|
27
|
+
|
|
28
|
+
.. code-block:: python
|
|
29
|
+
|
|
30
|
+
class CustomSlingTranslator(DagsterSlingTranslator):
|
|
31
|
+
def sanitize_stream_name(self, stream_name: str) -> str:
|
|
32
|
+
return stream_name.replace(".", "")
|
|
33
|
+
"""
|
|
34
|
+
return re.sub(r"[^a-zA-Z0-9_.]", "_", stream_name.replace('"', "").lower())
|
|
35
|
+
|
|
36
|
+
@public
|
|
37
|
+
def get_asset_key(self, stream_definition: Mapping[str, Any]) -> AssetKey:
|
|
38
|
+
"""A function that takes a stream definition from a Sling replication config and returns a
|
|
39
|
+
Dagster AssetKey.
|
|
40
|
+
|
|
41
|
+
The stream definition is a dictionary key/value pair where the key is the stream name and
|
|
42
|
+
the value is a dictionary representing the Sling Replication Stream Config.
|
|
43
|
+
|
|
44
|
+
For example:
|
|
45
|
+
|
|
46
|
+
.. code-block:: python
|
|
47
|
+
|
|
48
|
+
stream_definition = {"public.users":
|
|
49
|
+
{'sql': 'select all_user_id, name from public."all_Users"',
|
|
50
|
+
'object': 'public.all_users'}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
By default, this returns the class's target_prefix paramater concatenated with the stream name.
|
|
54
|
+
A stream named "public.accounts" will create an AssetKey named "target_public_accounts".
|
|
55
|
+
|
|
56
|
+
Override this function to customize how to map a Sling stream to a Dagster AssetKey.
|
|
57
|
+
|
|
58
|
+
Alternatively, you can provide metadata in your Sling replication config to specify the
|
|
59
|
+
Dagster AssetKey for a stream as follows:
|
|
60
|
+
|
|
61
|
+
.. code-block:: yaml
|
|
62
|
+
|
|
63
|
+
public.users:
|
|
64
|
+
meta:
|
|
65
|
+
dagster:
|
|
66
|
+
asset_key: "mydb_users"
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
stream_definition (Mapping[str, Any]): A dictionary representing the stream definition
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
AssetKey: The Dagster AssetKey for the replication stream.
|
|
73
|
+
|
|
74
|
+
Examples:
|
|
75
|
+
Using a custom mapping for streams:
|
|
76
|
+
|
|
77
|
+
.. code-block:: python
|
|
78
|
+
|
|
79
|
+
class CustomSlingTranslator(DagsterSlingTranslator):
|
|
80
|
+
def get_asset_key_for_target(self, stream_definition) -> AssetKey:
|
|
81
|
+
map = {"stream1": "asset1", "stream2": "asset2"}
|
|
82
|
+
return AssetKey(map[stream_name])
|
|
83
|
+
"""
|
|
84
|
+
config = stream_definition.get("config", {}) or {}
|
|
85
|
+
object_key = config.get("object")
|
|
86
|
+
meta = config.get("meta", {})
|
|
87
|
+
asset_key = meta.get("dagster", {}).get("asset_key")
|
|
88
|
+
|
|
89
|
+
if asset_key:
|
|
90
|
+
if self.sanitize_stream_name(asset_key) != asset_key:
|
|
91
|
+
raise ValueError(
|
|
92
|
+
f"Asset key {asset_key} for stream {stream_definition['name']} is not "
|
|
93
|
+
"sanitized. Please use only alphanumeric characters and underscores."
|
|
94
|
+
)
|
|
95
|
+
return AssetKey(asset_key.split("."))
|
|
96
|
+
|
|
97
|
+
# You can override the Sling Replication default object with an object key
|
|
98
|
+
stream_name = object_key or stream_definition["name"]
|
|
99
|
+
sanitized_components = self.sanitize_stream_name(stream_name).split(".")
|
|
100
|
+
return AssetKey([self.target_prefix] + sanitized_components)
|
|
101
|
+
|
|
102
|
+
@public
|
|
103
|
+
def get_deps_asset_key(self, stream_definition: Mapping[str, Any]) -> Iterable[AssetKey]:
|
|
104
|
+
"""A function that takes a stream name from a Sling replication config and returns a
|
|
105
|
+
Dagster AssetKey for the dependencies of the replication stream.
|
|
106
|
+
|
|
107
|
+
By default, this returns the stream name. For example, a stream named "public.accounts"
|
|
108
|
+
will create an AssetKey named "target_public_accounts" and a dependency named "public_accounts".
|
|
109
|
+
|
|
110
|
+
Override this function to customize how to map a Sling stream to a Dagster depenency.
|
|
111
|
+
Alternatively, you can provide metadata in your Sling replication config to specify the
|
|
112
|
+
Dagster AssetKey for a stream as follows:
|
|
113
|
+
|
|
114
|
+
.. code-block:: yaml
|
|
115
|
+
|
|
116
|
+
public.users:
|
|
117
|
+
meta:
|
|
118
|
+
dagster:
|
|
119
|
+
deps: "sourcedb_users"
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
stream_name (str): The name of the stream.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
AssetKey: The Dagster AssetKey dependency for the replication stream.
|
|
126
|
+
|
|
127
|
+
Examples:
|
|
128
|
+
Using a custom mapping for streams:
|
|
129
|
+
|
|
130
|
+
.. code-block:: python
|
|
131
|
+
|
|
132
|
+
class CustomSlingTranslator(DagsterSlingTranslator):
|
|
133
|
+
def get_deps_asset_key(self, stream_name: str) -> AssetKey:
|
|
134
|
+
map = {"stream1": "asset1", "stream2": "asset2"}
|
|
135
|
+
return AssetKey(map[stream_name])
|
|
136
|
+
|
|
137
|
+
"""
|
|
138
|
+
config = stream_definition.get("config", {}) or {}
|
|
139
|
+
meta = config.get("meta", {})
|
|
140
|
+
deps = meta.get("dagster", {}).get("deps")
|
|
141
|
+
deps_out = []
|
|
142
|
+
if deps and isinstance(deps, str):
|
|
143
|
+
deps = [deps]
|
|
144
|
+
if deps:
|
|
145
|
+
assert isinstance(deps, list)
|
|
146
|
+
for asset_key in deps:
|
|
147
|
+
if self.sanitize_stream_name(asset_key) != asset_key:
|
|
148
|
+
raise ValueError(
|
|
149
|
+
f"Deps Asset key {asset_key} for stream {stream_definition['name']} is not "
|
|
150
|
+
"sanitized. Please use only alphanumeric characters and underscores."
|
|
151
|
+
)
|
|
152
|
+
deps_out.append(AssetKey(asset_key.split(".")))
|
|
153
|
+
return deps_out
|
|
154
|
+
|
|
155
|
+
stream_name = stream_definition["name"]
|
|
156
|
+
components = self.sanitize_stream_name(stream_name).split(".")
|
|
157
|
+
return [AssetKey(components)]
|
|
158
|
+
|
|
159
|
+
@public
|
|
160
|
+
def get_description(self, stream_definition: Mapping[str, Any]) -> Optional[str]:
|
|
161
|
+
"""Retrieves the description for a given stream definition.
|
|
162
|
+
|
|
163
|
+
This method checks the provided stream definition for a description. It first looks
|
|
164
|
+
for an "sql" key in the configuration and returns its value if found. If not, it looks
|
|
165
|
+
for a description in the metadata under the "dagster" key.
|
|
166
|
+
|
|
167
|
+
Parameters:
|
|
168
|
+
stream_definition (Mapping[str, Any]): A dictionary representing the stream definition,
|
|
169
|
+
which includes configuration details.
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
Optional[str]: The description of the stream if found, otherwise None.
|
|
173
|
+
"""
|
|
174
|
+
config = stream_definition.get("config", {}) or {}
|
|
175
|
+
if "sql" in config:
|
|
176
|
+
return config["sql"]
|
|
177
|
+
meta = config.get("meta", {})
|
|
178
|
+
description = meta.get("dagster", {}).get("description")
|
|
179
|
+
return description
|
|
180
|
+
|
|
181
|
+
@public
|
|
182
|
+
def get_metadata(self, stream_definition: Mapping[str, Any]) -> Mapping[str, Any]:
|
|
183
|
+
"""Retrieves the metadata for a given stream definition.
|
|
184
|
+
|
|
185
|
+
This method extracts the configuration from the provided stream definition and returns
|
|
186
|
+
it as a JSON metadata value.
|
|
187
|
+
|
|
188
|
+
Parameters:
|
|
189
|
+
stream_definition (Mapping[str, Any]): A dictionary representing the stream definition,
|
|
190
|
+
which includes configuration details.
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
Mapping[str, Any]: A dictionary containing the stream configuration as JSON metadata.
|
|
194
|
+
"""
|
|
195
|
+
return {"stream_config": MetadataValue.json(stream_definition.get("config", {}))}
|
|
196
|
+
|
|
197
|
+
@public
|
|
198
|
+
def get_tags(self, stream_definition: Mapping[str, Any]) -> Mapping[str, Any]:
|
|
199
|
+
"""Retrieves the tags for a given stream definition.
|
|
200
|
+
|
|
201
|
+
This method returns an empty dictionary, indicating that no tags are associated with
|
|
202
|
+
the stream definition by default. This method can be overridden to provide custom tags.
|
|
203
|
+
|
|
204
|
+
Parameters:
|
|
205
|
+
stream_definition (Mapping[str, Any]): A dictionary representing the stream definition,
|
|
206
|
+
which includes configuration details.
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
Mapping[str, Any]: An empty dictionary.
|
|
210
|
+
"""
|
|
211
|
+
return {}
|
|
212
|
+
|
|
213
|
+
@public
|
|
214
|
+
def get_kinds(self, stream_definition: Mapping[str, Any]) -> set[str]:
|
|
215
|
+
"""Retrieves the kinds for a given stream definition.
|
|
216
|
+
|
|
217
|
+
This method returns "sling" by default. This method can be overridden to provide custom kinds.
|
|
218
|
+
|
|
219
|
+
Parameters:
|
|
220
|
+
stream_definition (Mapping[str, Any]): A dictionary representing the stream definition,
|
|
221
|
+
which includes configuration details.
|
|
222
|
+
|
|
223
|
+
Returns:
|
|
224
|
+
Set[str]: A set containing kinds for the stream's assets.
|
|
225
|
+
"""
|
|
226
|
+
return {"sling"}
|
|
227
|
+
|
|
228
|
+
@public
|
|
229
|
+
def get_group_name(self, stream_definition: Mapping[str, Any]) -> Optional[str]:
|
|
230
|
+
"""Retrieves the group name for a given stream definition.
|
|
231
|
+
|
|
232
|
+
This method checks the provided stream definition for a group name in the metadata
|
|
233
|
+
under the "dagster" key.
|
|
234
|
+
|
|
235
|
+
Parameters:
|
|
236
|
+
stream_definition (Mapping[str, Any]): A dictionary representing the stream definition,
|
|
237
|
+
which includes configuration details.
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
Optional[str]: The group name if found, otherwise None.
|
|
241
|
+
"""
|
|
242
|
+
config = stream_definition.get("config", {}) or {}
|
|
243
|
+
meta = config.get("meta", {})
|
|
244
|
+
return meta.get("dagster", {}).get("group")
|
|
245
|
+
|
|
246
|
+
@public
|
|
247
|
+
def get_freshness_policy(
|
|
248
|
+
self, stream_definition: Mapping[str, Any]
|
|
249
|
+
) -> Optional[FreshnessPolicy]:
|
|
250
|
+
"""Retrieves the freshness policy for a given stream definition.
|
|
251
|
+
|
|
252
|
+
This method checks the provided stream definition for a specific configuration
|
|
253
|
+
indicating a freshness policy. If the configuration is found, it constructs and
|
|
254
|
+
returns a FreshnessPolicy object based on the provided parameters. Otherwise,
|
|
255
|
+
it returns None.
|
|
256
|
+
|
|
257
|
+
Parameters:
|
|
258
|
+
stream_definition (Mapping[str, Any]): A dictionary representing the stream definition,
|
|
259
|
+
which includes configuration details.
|
|
260
|
+
|
|
261
|
+
Returns:
|
|
262
|
+
Optional[FreshnessPolicy]: A FreshnessPolicy object if the configuration is found,
|
|
263
|
+
otherwise None.
|
|
264
|
+
"""
|
|
265
|
+
config = stream_definition.get("config", {}) or {}
|
|
266
|
+
meta = config.get("meta", {})
|
|
267
|
+
freshness_policy_config = meta.get("dagster", {}).get("freshness_policy")
|
|
268
|
+
if freshness_policy_config:
|
|
269
|
+
return FreshnessPolicy(
|
|
270
|
+
maximum_lag_minutes=float(freshness_policy_config["maximum_lag_minutes"]),
|
|
271
|
+
cron_schedule=freshness_policy_config.get("cron_schedule"),
|
|
272
|
+
cron_schedule_timezone=freshness_policy_config.get("cron_schedule_timezone"),
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
@public
|
|
276
|
+
def get_auto_materialize_policy(
|
|
277
|
+
self, stream_definition: Mapping[str, Any]
|
|
278
|
+
) -> Optional[AutoMaterializePolicy]:
|
|
279
|
+
"""Defines the auto-materialize policy for a given stream definition.
|
|
280
|
+
|
|
281
|
+
This method checks the provided stream definition for a specific configuration
|
|
282
|
+
indicating an auto-materialize policy. If the configuration is found, it returns
|
|
283
|
+
an eager auto-materialize policy. Otherwise, it returns None.
|
|
284
|
+
|
|
285
|
+
Parameters:
|
|
286
|
+
stream_definition (Mapping[str, Any]): A dictionary representing the stream definition,
|
|
287
|
+
which includes configuration details.
|
|
288
|
+
|
|
289
|
+
Returns:
|
|
290
|
+
Optional[AutoMaterializePolicy]: An eager auto-materialize policy if the configuration
|
|
291
|
+
is found, otherwise None.
|
|
292
|
+
"""
|
|
293
|
+
config = stream_definition.get("config", {}) or {}
|
|
294
|
+
meta = config.get("meta", {})
|
|
295
|
+
auto_materialize_policy_config = "auto_materialize_policy" in meta.get("dagster", {})
|
|
296
|
+
if auto_materialize_policy_config:
|
|
297
|
+
return AutoMaterializePolicy.eager()
|
dagster_sling/py.typed
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
partial
|