tinyfan 0.2.4__tar.gz → 0.2.6__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.
- {tinyfan-0.2.4 → tinyfan-0.2.6}/PKG-INFO +1 -1
- {tinyfan-0.2.4 → tinyfan-0.2.6}/pyproject.toml +1 -1
- {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/argo_typing.py +17 -1
- {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/codegen.py +24 -13
- {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/test_codegen.py +18 -1
- {tinyfan-0.2.4 → tinyfan-0.2.6}/uv.lock +1 -1
- {tinyfan-0.2.4 → tinyfan-0.2.6}/.github/workflows/publish.yml +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/.gitignore +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/.python-version +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/README.md +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/README.md +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/configmap.yaml +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/configs.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/getting-started.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/packaged/.python-version +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/packaged/Dockerfile +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/packaged/README.md +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/packaged/pyproject.toml +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/packaged/src/tinyfan_examples_packaged/__init__.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/packaged/src/tinyfan_examples_packaged/asset.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/resource.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/secret.yaml +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/__init__.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/cli.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/config.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/dagviz.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/flow.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/flowrundata.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/py.typed +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/resources/__init__.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/resources/base.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/stores/__init__.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/stores/base.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/stores/bigquery.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/stores/gcs_pickle.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/stores/naive.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/utils/__init__.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/utils/embed.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/utils/exjson.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/utils/merge.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/utils/typing.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/utils/yaml.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/__init__.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/codegen_samples/directory/__init__.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/codegen_samples/directory/asset.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/codegen_samples/directory/asset2.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/codegen_samples/singlefile.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/conftest.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/helpers.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/openapi2jsonschema.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/test_config.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/test_decorators.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/utils/__init__.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/utils/embed_samples/directory/__init__.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/utils/embed_samples/directory/dep.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/utils/embed_samples/singlefile.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/utils/test_embed.py +0 -0
- {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/utils/test_exjson.py +0 -0
|
@@ -93,6 +93,22 @@ class EnvVar(TypedDict):
|
|
|
93
93
|
valueFrom: NotRequired[EnvVarSource]
|
|
94
94
|
|
|
95
95
|
|
|
96
|
+
class ConfigMapEnvSource(TypedDict, total=False):
|
|
97
|
+
name: str
|
|
98
|
+
optional: bool
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class SecretEnvSource(TypedDict, total=False):
|
|
102
|
+
name: str
|
|
103
|
+
optional: bool
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class EnvFromSource(TypedDict, total=False):
|
|
107
|
+
configMapRef: ConfigMapEnvSource
|
|
108
|
+
secretRef: SecretEnvSource
|
|
109
|
+
prefix: str
|
|
110
|
+
|
|
111
|
+
|
|
96
112
|
class Lifecycle(TypedDict, total=False):
|
|
97
113
|
postStart: LifecycleHandler
|
|
98
114
|
preStop: LifecycleHandler
|
|
@@ -183,7 +199,7 @@ class ScriptTemplate(TypedDict, total=False):
|
|
|
183
199
|
args: list[str]
|
|
184
200
|
command: list[str]
|
|
185
201
|
env: list[EnvVar]
|
|
186
|
-
envFrom: list[
|
|
202
|
+
envFrom: list[EnvFromSource]
|
|
187
203
|
image: str
|
|
188
204
|
imagePullPolicy: str
|
|
189
205
|
lifecycle: Lifecycle
|
|
@@ -66,6 +66,10 @@ def import_all_submodules(location: str):
|
|
|
66
66
|
importlib.import_module(name)
|
|
67
67
|
|
|
68
68
|
|
|
69
|
+
def assetname2template(name: str):
|
|
70
|
+
return name.replace("_", "-")
|
|
71
|
+
|
|
72
|
+
|
|
69
73
|
class AssetNode:
|
|
70
74
|
asset: Asset
|
|
71
75
|
refs: list[Config | ConfigValue | str | None]
|
|
@@ -106,7 +110,8 @@ class AssetNode:
|
|
|
106
110
|
DATETIME_ANNOTATION: "{{workflow.scheduledTime}}",
|
|
107
111
|
},
|
|
108
112
|
"parents": {
|
|
109
|
-
p.asset.name: "{{tasks.%s.outputs.parameters.rundata}}" % p.asset.name
|
|
113
|
+
p.asset.name: "{{tasks.%s.outputs.parameters.rundata}}" % p.asset.name.replace("_", "-")
|
|
114
|
+
for p in self.parents
|
|
110
115
|
},
|
|
111
116
|
"asset_name": self.asset.name,
|
|
112
117
|
"flow_name": self.asset.flow.name,
|
|
@@ -117,11 +122,11 @@ class AssetNode:
|
|
|
117
122
|
|
|
118
123
|
def relatives(self, result: set[Self] | None = None) -> set[Self]:
|
|
119
124
|
if result is None:
|
|
120
|
-
result =
|
|
121
|
-
for
|
|
122
|
-
if
|
|
123
|
-
result.add(
|
|
124
|
-
|
|
125
|
+
result = {self}
|
|
126
|
+
for node in self.parents + self.children:
|
|
127
|
+
if node not in result:
|
|
128
|
+
result.add(node)
|
|
129
|
+
node.relatives(result)
|
|
125
130
|
return result
|
|
126
131
|
|
|
127
132
|
|
|
@@ -142,18 +147,23 @@ class AssetTree:
|
|
|
142
147
|
| set(inspect.get_annotations(FlowRunData).keys())
|
|
143
148
|
)
|
|
144
149
|
unknown_names = [n for n in func_param_names if n not in known_names]
|
|
145
|
-
if
|
|
150
|
+
if unknown_names:
|
|
146
151
|
raise Exception(
|
|
147
152
|
f"unknown asset args: {', '.join('`' + n + '`' for n in unknown_names)} from asset `{node.asset.name}`"
|
|
148
153
|
)
|
|
149
154
|
|
|
150
155
|
params_ids = set(name for name in func_param_names if name in self.flow.assets)
|
|
151
156
|
if node.asset.depends is not None:
|
|
157
|
+
assert re.match(VALID_DEPENDS_REGEXP, node.asset.depends)
|
|
152
158
|
depends_ids = set(re.findall(EXTRACT_DEPENDS_REGEXP, node.asset.depends))
|
|
153
159
|
node.parents = [self.nodes[n] for n in depends_ids.union(params_ids)]
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
160
|
+
new_ids = params_ids - depends_ids
|
|
161
|
+
if new_ids:
|
|
162
|
+
if len(depends_ids) > 1:
|
|
163
|
+
node.asset.depends = f"({node.asset.depends}) && {' && '.join(new_ids)}".replace("_", "-")
|
|
164
|
+
else:
|
|
165
|
+
node.asset.depends = f"{node.asset.depends} && {' && '.join(new_ids)}".replace("_", "-")
|
|
166
|
+
assert re.match(VALID_DEPENDS_REGEXP, node.asset.depends)
|
|
157
167
|
for p in node.parents:
|
|
158
168
|
p.children.append(node)
|
|
159
169
|
else:
|
|
@@ -189,10 +199,9 @@ class AssetTree:
|
|
|
189
199
|
|
|
190
200
|
from .dagviz import dagviz
|
|
191
201
|
|
|
192
|
-
relatives_by_schedules = self.relatives_by_schedules()
|
|
193
202
|
g: nx.DiGraph = nx.DiGraph()
|
|
194
203
|
g.add_node(self.flow.name, bullet="■")
|
|
195
|
-
for (tz, schedule), relatives in relatives_by_schedules.items():
|
|
204
|
+
for (tz, schedule), relatives in self.relatives_by_schedules().items():
|
|
196
205
|
schedule_node_name = schedule + f" ({tz})"
|
|
197
206
|
g.add_node(schedule_node_name, bullet="○")
|
|
198
207
|
g.add_edge(self.flow.name, schedule_node_name)
|
|
@@ -343,7 +352,9 @@ class AssetTree:
|
|
|
343
352
|
]
|
|
344
353
|
}
|
|
345
354
|
),
|
|
346
|
-
"synchronization": {
|
|
355
|
+
"synchronization": {
|
|
356
|
+
"mutexes": [{"name": f"{self.flow.name}-{node.asset.name.replace('_', '-')}"}]
|
|
357
|
+
},
|
|
347
358
|
"inputs": {
|
|
348
359
|
"parameters": [
|
|
349
360
|
{
|
|
@@ -21,6 +21,14 @@ def sample_flow() -> Generator:
|
|
|
21
21
|
def asset2(asset1: str): # type: ignore
|
|
22
22
|
print("asset1 says: " + asset1)
|
|
23
23
|
|
|
24
|
+
@asset(flow=flow, depends="asset1 && asset2")
|
|
25
|
+
def asset3(asset1: str): # type: ignore
|
|
26
|
+
print("asset1 says: " + asset1)
|
|
27
|
+
|
|
28
|
+
@asset(flow=flow, depends="asset2")
|
|
29
|
+
def asset4(asset1: str): # type: ignore
|
|
30
|
+
print("asset1 says: " + asset1)
|
|
31
|
+
|
|
24
32
|
yield flow
|
|
25
33
|
FLOW_REGISTER.clear()
|
|
26
34
|
|
|
@@ -132,9 +140,18 @@ def test_codegen_directory(validate_crds):
|
|
|
132
140
|
def test_rundata_data_interval(sample_flow):
|
|
133
141
|
tree = AssetTree(sample_flow)
|
|
134
142
|
node = list(tree.nodes.values())[0]
|
|
135
|
-
# rundatatmpl = node.rundatatmpl("0 * * * * *")
|
|
136
143
|
daily = node.rundatatmpl("@daily")
|
|
137
144
|
assert (
|
|
138
145
|
daily
|
|
139
146
|
== """{"ds": "{{=sprig.date('2006-01-02', sprig.dateModify('-86400.0s', sprig.toDate('2006-01-02T15:04:05Z07:00', workflow.scheduledTime)))}}", "ts": "{{=sprig.dateModify('-86400.0s', sprig.toDate('2006-01-02T15:04:05Z07:00', workflow.scheduledTime))}}", "data_interval_start": {"__tinyfan_datetime__": "{{=sprig.dateModify('-86400.0s', sprig.toDate('2006-01-02T15:04:05Z07:00', workflow.scheduledTime))}}"}, "data_interval_end": {"__tinyfan_datetime__": "{{workflow.scheduledTime}}"}, "parents": {}, "asset_name": "asset1", "flow_name": "test", "module_name": "tests.test_codegen"}"""
|
|
140
147
|
)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def test_depends(sample_flow):
|
|
151
|
+
tree = AssetTree(sample_flow)
|
|
152
|
+
assert [node.asset.depends for node in tree.nodes.values()] == [
|
|
153
|
+
"",
|
|
154
|
+
"asset1",
|
|
155
|
+
"asset1 && asset2",
|
|
156
|
+
"asset2 && asset1",
|
|
157
|
+
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|