tinyfan 0.2.2__tar.gz → 0.2.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 (58) hide show
  1. {tinyfan-0.2.2 → tinyfan-0.2.3}/PKG-INFO +1 -1
  2. {tinyfan-0.2.2 → tinyfan-0.2.3}/pyproject.toml +1 -1
  3. {tinyfan-0.2.2 → tinyfan-0.2.3}/src/tinyfan/codegen.py +7 -7
  4. {tinyfan-0.2.2 → tinyfan-0.2.3}/src/tinyfan/dagviz.py +3 -1
  5. {tinyfan-0.2.2 → tinyfan-0.2.3}/src/tinyfan/flow.py +9 -4
  6. tinyfan-0.2.3/tests/test_decorators.py +32 -0
  7. {tinyfan-0.2.2 → tinyfan-0.2.3}/uv.lock +1 -1
  8. tinyfan-0.2.2/tests/test_decorators.py +0 -9
  9. {tinyfan-0.2.2 → tinyfan-0.2.3}/.github/workflows/publish.yml +0 -0
  10. {tinyfan-0.2.2 → tinyfan-0.2.3}/.gitignore +0 -0
  11. {tinyfan-0.2.2 → tinyfan-0.2.3}/.python-version +0 -0
  12. {tinyfan-0.2.2 → tinyfan-0.2.3}/README.md +0 -0
  13. {tinyfan-0.2.2 → tinyfan-0.2.3}/examples/README.md +0 -0
  14. {tinyfan-0.2.2 → tinyfan-0.2.3}/examples/configmap.yaml +0 -0
  15. {tinyfan-0.2.2 → tinyfan-0.2.3}/examples/configs.py +0 -0
  16. {tinyfan-0.2.2 → tinyfan-0.2.3}/examples/getting-started.py +0 -0
  17. {tinyfan-0.2.2 → tinyfan-0.2.3}/examples/packaged/.python-version +0 -0
  18. {tinyfan-0.2.2 → tinyfan-0.2.3}/examples/packaged/Dockerfile +0 -0
  19. {tinyfan-0.2.2 → tinyfan-0.2.3}/examples/packaged/README.md +0 -0
  20. {tinyfan-0.2.2 → tinyfan-0.2.3}/examples/packaged/pyproject.toml +0 -0
  21. {tinyfan-0.2.2 → tinyfan-0.2.3}/examples/packaged/src/tinyfan_examples_packaged/__init__.py +0 -0
  22. {tinyfan-0.2.2 → tinyfan-0.2.3}/examples/packaged/src/tinyfan_examples_packaged/asset.py +0 -0
  23. {tinyfan-0.2.2 → tinyfan-0.2.3}/examples/resource.py +0 -0
  24. {tinyfan-0.2.2 → tinyfan-0.2.3}/examples/secret.yaml +0 -0
  25. {tinyfan-0.2.2 → tinyfan-0.2.3}/src/tinyfan/__init__.py +0 -0
  26. {tinyfan-0.2.2 → tinyfan-0.2.3}/src/tinyfan/argo_typing.py +0 -0
  27. {tinyfan-0.2.2 → tinyfan-0.2.3}/src/tinyfan/cli.py +0 -0
  28. {tinyfan-0.2.2 → tinyfan-0.2.3}/src/tinyfan/config.py +0 -0
  29. {tinyfan-0.2.2 → tinyfan-0.2.3}/src/tinyfan/flowrundata.py +0 -0
  30. {tinyfan-0.2.2 → tinyfan-0.2.3}/src/tinyfan/py.typed +0 -0
  31. {tinyfan-0.2.2 → tinyfan-0.2.3}/src/tinyfan/resources/__init__.py +0 -0
  32. {tinyfan-0.2.2 → tinyfan-0.2.3}/src/tinyfan/resources/base.py +0 -0
  33. {tinyfan-0.2.2 → tinyfan-0.2.3}/src/tinyfan/stores/__init__.py +0 -0
  34. {tinyfan-0.2.2 → tinyfan-0.2.3}/src/tinyfan/stores/base.py +0 -0
  35. {tinyfan-0.2.2 → tinyfan-0.2.3}/src/tinyfan/stores/bigquery.py +0 -0
  36. {tinyfan-0.2.2 → tinyfan-0.2.3}/src/tinyfan/stores/gcs_pickle.py +0 -0
  37. {tinyfan-0.2.2 → tinyfan-0.2.3}/src/tinyfan/stores/naive.py +0 -0
  38. {tinyfan-0.2.2 → tinyfan-0.2.3}/src/tinyfan/utils/__init__.py +0 -0
  39. {tinyfan-0.2.2 → tinyfan-0.2.3}/src/tinyfan/utils/embed.py +0 -0
  40. {tinyfan-0.2.2 → tinyfan-0.2.3}/src/tinyfan/utils/exjson.py +0 -0
  41. {tinyfan-0.2.2 → tinyfan-0.2.3}/src/tinyfan/utils/merge.py +0 -0
  42. {tinyfan-0.2.2 → tinyfan-0.2.3}/src/tinyfan/utils/typing.py +0 -0
  43. {tinyfan-0.2.2 → tinyfan-0.2.3}/src/tinyfan/utils/yaml.py +0 -0
  44. {tinyfan-0.2.2 → tinyfan-0.2.3}/tests/__init__.py +0 -0
  45. {tinyfan-0.2.2 → tinyfan-0.2.3}/tests/codegen_samples/directory/__init__.py +0 -0
  46. {tinyfan-0.2.2 → tinyfan-0.2.3}/tests/codegen_samples/directory/asset.py +0 -0
  47. {tinyfan-0.2.2 → tinyfan-0.2.3}/tests/codegen_samples/directory/asset2.py +0 -0
  48. {tinyfan-0.2.2 → tinyfan-0.2.3}/tests/codegen_samples/singlefile.py +0 -0
  49. {tinyfan-0.2.2 → tinyfan-0.2.3}/tests/conftest.py +0 -0
  50. {tinyfan-0.2.2 → tinyfan-0.2.3}/tests/helpers.py +0 -0
  51. {tinyfan-0.2.2 → tinyfan-0.2.3}/tests/openapi2jsonschema.py +0 -0
  52. {tinyfan-0.2.2 → tinyfan-0.2.3}/tests/test_codegen.py +0 -0
  53. {tinyfan-0.2.2 → tinyfan-0.2.3}/tests/utils/__init__.py +0 -0
  54. {tinyfan-0.2.2 → tinyfan-0.2.3}/tests/utils/embed_samples/directory/__init__.py +0 -0
  55. {tinyfan-0.2.2 → tinyfan-0.2.3}/tests/utils/embed_samples/directory/dep.py +0 -0
  56. {tinyfan-0.2.2 → tinyfan-0.2.3}/tests/utils/embed_samples/singlefile.py +0 -0
  57. {tinyfan-0.2.2 → tinyfan-0.2.3}/tests/utils/test_embed.py +0 -0
  58. {tinyfan-0.2.2 → tinyfan-0.2.3}/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.2
3
+ Version: 0.2.3
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.2"
3
+ version = "0.2.3"
4
4
  description = 'Tiny Argo Workflows python devkit'
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -191,13 +191,13 @@ class AssetTree:
191
191
 
192
192
  relatives_by_schedules = self.relatives_by_schedules()
193
193
  g: nx.DiGraph = nx.DiGraph()
194
- # g.add_node(self.flow.name)
195
- # g.add_nodes_from([k for k in relatives_by_schedules.keys()])
196
- # g.add_nodes_from(self.nodes.keys())
197
- for (_, schedule), relatives in relatives_by_schedules.items():
198
- g.add_edge(self.flow.name, schedule)
199
- g.add_edges_from([(schedule, r.asset.name) for r in relatives])
200
- g.add_edges_from([(r.asset.name, d.asset.name) for r in relatives for d in r.parents])
194
+ g.add_node(self.flow.name, bullet="■")
195
+ for (tz, schedule), relatives in relatives_by_schedules.items():
196
+ schedule_node_name = schedule + f" ({tz})"
197
+ g.add_node(schedule_node_name, bullet="○")
198
+ g.add_edge(self.flow.name, schedule_node_name)
199
+ g.add_edges_from([(schedule_node_name, r.asset.name) for r in relatives])
200
+ g.add_edges_from([(d.asset.name, r.asset.name) for r in relatives for d in r.parents])
201
201
  return dagviz(g, round_angle=True)
202
202
 
203
203
  def compile(
@@ -15,6 +15,7 @@ def dagviz(g: nx.DiGraph, round_angle: bool = False) -> str:
15
15
  assert nx.is_directed_acyclic_graph(g), "Graph contains cycles"
16
16
 
17
17
  rows: List[Hashable] = []
18
+ bullets: List[str] = []
18
19
  node_to_row: Dict[Hashable, int] = {}
19
20
  indents: List[int] = []
20
21
 
@@ -27,6 +28,7 @@ def dagviz(g: nx.DiGraph, round_angle: bool = False) -> str:
27
28
  for i in range(len(sources)):
28
29
  node_to_row[sources[i]] = len(rows)
29
30
  rows.append(sources[i])
31
+ bullets.append(g.nodes[sources[i]].get("bullet", "•"))
30
32
  indents.append(indent + i)
31
33
  _process_dag(nx.DiGraph(g.subgraph(set(g.nodes).difference(sources))), indent=indent + len(sources))
32
34
 
@@ -50,5 +52,5 @@ def dagviz(g: nx.DiGraph, round_angle: bool = False) -> str:
50
52
  for k in range(indents[i] * 2 + 1, indents[n] * 2):
51
53
  a[n][k] = "─"
52
54
 
53
- lines: List[str] = [x.tounicode() + "• " + str(i).replace("\n", " ") for x, i in zip(a, rows)]
55
+ lines: List[str] = [x.tounicode() + f"{b} " + str(i).replace("\n", " ") for x, b, i in zip(a, bullets, rows)]
54
56
  return "\n".join(lines)
@@ -1,9 +1,10 @@
1
1
  import inspect
2
+ import asyncio
2
3
  from .stores.base import StoreBase
3
4
  from .stores.naive import NaiveStore
4
5
  from .flowrundata import FlowRunData, StoreIdx, UMeta
5
6
  from dataclasses import dataclass, field
6
- from typing import Callable, Any, Generic, TypeVar
7
+ from typing import Callable, Any, Generic, TypeVar, Awaitable, Coroutine, cast
7
8
  from .resources.base import ResourceBase
8
9
  from .argo_typing import ScriptTemplate
9
10
  from .config import Config, ConfigValue
@@ -41,7 +42,7 @@ DEFAULT_FLOW: Flow = Flow(
41
42
  @dataclass
42
43
  class Asset(Generic[Ret, UMeta, StoreIdx]):
43
44
  flow: Flow
44
- func: Callable[..., Ret]
45
+ func: Callable[..., Ret | Awaitable[Ret]]
45
46
  store: StoreBase[Ret, UMeta, StoreIdx]
46
47
  schedule: str | None = None
47
48
  tz: str | None = None
@@ -84,11 +85,15 @@ class Asset(Generic[Ret, UMeta, StoreIdx]):
84
85
  if name in func_param_names:
85
86
  params[name] = data
86
87
  ret = self.func(**params)
87
- store_entry_idx = self.store.store(ret, rundata)
88
+ if inspect.isawaitable(ret):
89
+ res: Ret = asyncio.run(cast(Coroutine[Any, Any, Ret], ret))
90
+ else:
91
+ res = cast(Ret, ret)
92
+ store_entry_idx = self.store.store(res, rundata)
88
93
  rundata["store_entry_idx"] = store_entry_idx
89
94
  if "parents" in rundata:
90
95
  del rundata["parents"]
91
- return (ret, rundata)
96
+ return (res, rundata)
92
97
 
93
98
 
94
99
  class AssetFunc(Generic[Ret, UMeta, StoreIdx]):
@@ -0,0 +1,32 @@
1
+ from tinyfan import asset
2
+
3
+
4
+ def test_preserve_original_functionality():
5
+ @asset()
6
+ def test(arg: str):
7
+ return arg
8
+
9
+ assert test(arg="test") == "test"
10
+
11
+
12
+ def test_asset_run():
13
+ @asset()
14
+ def test(ds: str):
15
+ return ds
16
+
17
+ actual, _ = test.asset.run({"ds": "2020-01-01"})
18
+ expected = "2020-01-01"
19
+ assert actual == expected
20
+
21
+
22
+ def test_async_asset_run():
23
+ async def awaitable() -> str:
24
+ return " awaited"
25
+
26
+ @asset()
27
+ async def test(ds: str):
28
+ return ds + await awaitable()
29
+
30
+ actual, _ = test.asset.run({"ds": "2020-01-01"})
31
+ expected = "2020-01-01 awaited"
32
+ assert actual == expected
@@ -784,7 +784,7 @@ wheels = [
784
784
 
785
785
  [[package]]
786
786
  name = "tinyfan"
787
- version = "0.2.2"
787
+ version = "0.2.3"
788
788
  source = { editable = "." }
789
789
  dependencies = [
790
790
  { name = "croniter" },
@@ -1,9 +0,0 @@
1
- from tinyfan import asset
2
-
3
-
4
- def test_preserve_original_functionality():
5
- @asset()
6
- def test(arg: str):
7
- return arg
8
-
9
- assert test(arg="test") == "test"
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