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.
Files changed (58) hide show
  1. {tinyfan-0.2.4 → tinyfan-0.2.6}/PKG-INFO +1 -1
  2. {tinyfan-0.2.4 → tinyfan-0.2.6}/pyproject.toml +1 -1
  3. {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/argo_typing.py +17 -1
  4. {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/codegen.py +24 -13
  5. {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/test_codegen.py +18 -1
  6. {tinyfan-0.2.4 → tinyfan-0.2.6}/uv.lock +1 -1
  7. {tinyfan-0.2.4 → tinyfan-0.2.6}/.github/workflows/publish.yml +0 -0
  8. {tinyfan-0.2.4 → tinyfan-0.2.6}/.gitignore +0 -0
  9. {tinyfan-0.2.4 → tinyfan-0.2.6}/.python-version +0 -0
  10. {tinyfan-0.2.4 → tinyfan-0.2.6}/README.md +0 -0
  11. {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/README.md +0 -0
  12. {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/configmap.yaml +0 -0
  13. {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/configs.py +0 -0
  14. {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/getting-started.py +0 -0
  15. {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/packaged/.python-version +0 -0
  16. {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/packaged/Dockerfile +0 -0
  17. {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/packaged/README.md +0 -0
  18. {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/packaged/pyproject.toml +0 -0
  19. {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/packaged/src/tinyfan_examples_packaged/__init__.py +0 -0
  20. {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/packaged/src/tinyfan_examples_packaged/asset.py +0 -0
  21. {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/resource.py +0 -0
  22. {tinyfan-0.2.4 → tinyfan-0.2.6}/examples/secret.yaml +0 -0
  23. {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/__init__.py +0 -0
  24. {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/cli.py +0 -0
  25. {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/config.py +0 -0
  26. {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/dagviz.py +0 -0
  27. {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/flow.py +0 -0
  28. {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/flowrundata.py +0 -0
  29. {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/py.typed +0 -0
  30. {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/resources/__init__.py +0 -0
  31. {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/resources/base.py +0 -0
  32. {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/stores/__init__.py +0 -0
  33. {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/stores/base.py +0 -0
  34. {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/stores/bigquery.py +0 -0
  35. {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/stores/gcs_pickle.py +0 -0
  36. {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/stores/naive.py +0 -0
  37. {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/utils/__init__.py +0 -0
  38. {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/utils/embed.py +0 -0
  39. {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/utils/exjson.py +0 -0
  40. {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/utils/merge.py +0 -0
  41. {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/utils/typing.py +0 -0
  42. {tinyfan-0.2.4 → tinyfan-0.2.6}/src/tinyfan/utils/yaml.py +0 -0
  43. {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/__init__.py +0 -0
  44. {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/codegen_samples/directory/__init__.py +0 -0
  45. {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/codegen_samples/directory/asset.py +0 -0
  46. {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/codegen_samples/directory/asset2.py +0 -0
  47. {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/codegen_samples/singlefile.py +0 -0
  48. {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/conftest.py +0 -0
  49. {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/helpers.py +0 -0
  50. {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/openapi2jsonschema.py +0 -0
  51. {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/test_config.py +0 -0
  52. {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/test_decorators.py +0 -0
  53. {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/utils/__init__.py +0 -0
  54. {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/utils/embed_samples/directory/__init__.py +0 -0
  55. {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/utils/embed_samples/directory/dep.py +0 -0
  56. {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/utils/embed_samples/singlefile.py +0 -0
  57. {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/utils/test_embed.py +0 -0
  58. {tinyfan-0.2.4 → tinyfan-0.2.6}/tests/utils/test_exjson.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tinyfan
3
- Version: 0.2.4
3
+ Version: 0.2.6
4
4
  Summary: Tiny Argo Workflows python devkit
5
5
  Project-URL: Documentation, https://github.com/eunchuldev/tinyfan#readme
6
6
  Project-URL: Issues, https://github.com/eunchuldev/tinyfan/issues
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tinyfan"
3
- version = "0.2.4"
3
+ version = "0.2.6"
4
4
  description = 'Tiny Argo Workflows python devkit'
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -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[EnvVar]
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 for p in self.parents
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 = set[Self]([self])
121
- for o in self.parents + self.children:
122
- if o not in result:
123
- result.add(o)
124
- o.relatives(result)
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 len(unknown_names) > 0:
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
- node.asset.depends = f"({node.asset.depends}) && {' && '.join(params_ids - depends_ids)}".replace(
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": {"mutexes": [{"name": f"{self.flow.name}-{node.asset.name}"}]},
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
+ ]
@@ -784,7 +784,7 @@ wheels = [
784
784
 
785
785
  [[package]]
786
786
  name = "tinyfan"
787
- version = "0.2.4"
787
+ version = "0.2.6"
788
788
  source = { editable = "." }
789
789
  dependencies = [
790
790
  { name = "croniter" },
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