pyflowstep 0.6.0__tar.gz → 0.7.1__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.
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyflowstep
3
- Version: 0.6.0
4
- Summary: A lightweight, typed Python library for composing functions into readable, reusable flows that can be defined as JSON.
5
- Keywords: flow,pipeline,composition,functional,fluent-interface,json,json-schema,workflow,dsl
3
+ Version: 0.7.1
4
+ Summary: A lightweight, typed Python library for composing functions into readable, reusable flows that can be defined as JSON or TOML.
5
+ Keywords: flow,pipeline,composition,functional,fluent-interface,json,json-schema,toml,workflow,dsl
6
6
  Author: aaltatan
7
7
  Author-email: aaltatan <a.altatan@gmail.com>
8
8
  License-Expression: GPL-3.0-only
@@ -16,6 +16,7 @@ Classifier: Programming Language :: Python :: 3.13
16
16
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
17
  Classifier: Typing :: Typed
18
18
  Requires-Dist: pyargprocessors>=0.1.0
19
+ Requires-Dist: pyvocabulary>=0.1.0
19
20
  Requires-Python: >=3.12
20
21
  Project-URL: Homepage, https://github.com/aaltatan/pyflowstep
21
22
  Project-URL: Repository, https://github.com/aaltatan/pyflowstep
@@ -695,15 +696,42 @@ login = compiler.compile(
695
696
  login(Page())
696
697
  ```
697
698
 
698
- The compiler takes already-parsed data. Reading JSON, YAML, a database row or an API payload is up to you:
699
+ `compile` takes already-parsed data, so a database row or an API payload works too.
700
+
701
+ ### Flow files
702
+
703
+ `compile_file` picks a parser by the file suffix. JSON and TOML are built in:
699
704
 
700
705
  ```python
701
- import json
702
- from pathlib import Path
706
+ login = compiler.compile_file("login.json") # a list of steps, as above
707
+ login = compiler.compile_file("login.toml")
708
+ ```
709
+
710
+ A TOML flow lists its steps as `[[steps]]` tables:
711
+
712
+ ```toml
713
+ [[steps]]
714
+ name = "navigate"
715
+ args = ["https://example.com/login"]
703
716
 
704
- login = compiler.compile(json.loads(Path("login.json").read_text()))
717
+ [[steps]]
718
+ name = "click"
719
+ kwargs = { selector = "button[type=submit]" }
705
720
  ```
706
721
 
722
+ Add any other format by registering a parser that turns the file text into a list of steps:
723
+
724
+ ```python
725
+ import yaml
726
+
727
+ from pyflowstep import register_flow_format
728
+
729
+ register_flow_format(".yaml", yaml.safe_load)
730
+ register_flow_format(".yml", yaml.safe_load)
731
+ ```
732
+
733
+ An unregistered suffix raises `UnsupportedFlowFormatError`; a file that does not parse raises `InvalidFlowDefinitionError`. Errors from a file carry an extra `in <path>` note. `load_flow_definition(path)` returns the parsed data without compiling it.
734
+
707
735
  Each step dictionary has this shape — only `name` is required:
708
736
 
709
737
  ```json
@@ -719,7 +747,7 @@ at $[1]
719
747
 
720
748
  | Problem | Exception |
721
749
  | ------------------------------------------------ | ------------------------------------------------------ |
722
- | Not a list / malformed step dict | `InvalidFlowDefinitionError` |
750
+ | Not a list / malformed step dict / bad file | `InvalidFlowDefinitionError` |
723
751
  | Unknown or hidden step name | `StepDoesNotExistError` (lists the available steps) |
724
752
  | Missing / extra / duplicated arguments | `MissingArgumentError`, `TooManyArgumentsError`, ... |
725
753
  | A processor rejects a value | `ProcessArgumentError` (from `pyargprocessors`) |
@@ -671,15 +671,42 @@ login = compiler.compile(
671
671
  login(Page())
672
672
  ```
673
673
 
674
- The compiler takes already-parsed data. Reading JSON, YAML, a database row or an API payload is up to you:
674
+ `compile` takes already-parsed data, so a database row or an API payload works too.
675
+
676
+ ### Flow files
677
+
678
+ `compile_file` picks a parser by the file suffix. JSON and TOML are built in:
675
679
 
676
680
  ```python
677
- import json
678
- from pathlib import Path
681
+ login = compiler.compile_file("login.json") # a list of steps, as above
682
+ login = compiler.compile_file("login.toml")
683
+ ```
684
+
685
+ A TOML flow lists its steps as `[[steps]]` tables:
686
+
687
+ ```toml
688
+ [[steps]]
689
+ name = "navigate"
690
+ args = ["https://example.com/login"]
679
691
 
680
- login = compiler.compile(json.loads(Path("login.json").read_text()))
692
+ [[steps]]
693
+ name = "click"
694
+ kwargs = { selector = "button[type=submit]" }
681
695
  ```
682
696
 
697
+ Add any other format by registering a parser that turns the file text into a list of steps:
698
+
699
+ ```python
700
+ import yaml
701
+
702
+ from pyflowstep import register_flow_format
703
+
704
+ register_flow_format(".yaml", yaml.safe_load)
705
+ register_flow_format(".yml", yaml.safe_load)
706
+ ```
707
+
708
+ An unregistered suffix raises `UnsupportedFlowFormatError`; a file that does not parse raises `InvalidFlowDefinitionError`. Errors from a file carry an extra `in <path>` note. `load_flow_definition(path)` returns the parsed data without compiling it.
709
+
683
710
  Each step dictionary has this shape — only `name` is required:
684
711
 
685
712
  ```json
@@ -695,7 +722,7 @@ at $[1]
695
722
 
696
723
  | Problem | Exception |
697
724
  | ------------------------------------------------ | ------------------------------------------------------ |
698
- | Not a list / malformed step dict | `InvalidFlowDefinitionError` |
725
+ | Not a list / malformed step dict / bad file | `InvalidFlowDefinitionError` |
699
726
  | Unknown or hidden step name | `StepDoesNotExistError` (lists the available steps) |
700
727
  | Missing / extra / duplicated arguments | `MissingArgumentError`, `TooManyArgumentsError`, ... |
701
728
  | A processor rejects a value | `ProcessArgumentError` (from `pyargprocessors`) |
@@ -1,11 +1,14 @@
1
1
  [project]
2
2
  name = "pyflowstep"
3
- version = "0.6.0"
4
- description = "A lightweight, typed Python library for composing functions into readable, reusable flows that can be defined as JSON."
3
+ version = "0.7.1"
4
+ description = "A lightweight, typed Python library for composing functions into readable, reusable flows that can be defined as JSON or TOML."
5
5
  readme = "README.md"
6
6
  license = "GPL-3.0-only"
7
7
  requires-python = ">=3.12"
8
- dependencies = ["pyargprocessors>=0.1.0"]
8
+ dependencies = [
9
+ "pyargprocessors>=0.1.0",
10
+ "pyvocabulary>=0.1.0",
11
+ ]
9
12
  keywords = [
10
13
  "flow",
11
14
  "pipeline",
@@ -14,6 +17,7 @@ keywords = [
14
17
  "fluent-interface",
15
18
  "json",
16
19
  "json-schema",
20
+ "toml",
17
21
  "workflow",
18
22
  "dsl",
19
23
  ]
@@ -118,3 +122,7 @@ extend-immutable-calls = [
118
122
  "T201",
119
123
  "INP001",
120
124
  ]
125
+
126
+ [tool.pyright]
127
+ venvPath = "."
128
+ venv = ".venv"
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "pyflowstep"
3
- version = "0.6.0"
4
- description = "A lightweight, typed Python library for composing functions into readable, reusable flows that can be defined as JSON."
3
+ version = "0.7.1"
4
+ description = "A lightweight, typed Python library for composing functions into readable, reusable flows that can be defined as JSON or TOML."
5
5
  readme = "README.md"
6
6
  authors = [
7
7
  { name = "aaltatan", email = "a.altatan@gmail.com" }
@@ -10,6 +10,7 @@ license = "GPL-3.0-only"
10
10
  requires-python = ">=3.12"
11
11
  dependencies = [
12
12
  "pyargprocessors>=0.1.0",
13
+ "pyvocabulary>=0.1.0",
13
14
  ]
14
15
  keywords = [
15
16
  "flow",
@@ -19,6 +20,7 @@ keywords = [
19
20
  "fluent-interface",
20
21
  "json",
21
22
  "json-schema",
23
+ "toml",
22
24
  "workflow",
23
25
  "dsl",
24
26
  ]
@@ -93,3 +95,8 @@ extend-immutable-calls = [
93
95
  [tool.ruff.lint.per-file-ignores]
94
96
  "tests/**" = ["S101", "PLR2004", "ANN", "ARG", "INP001", "E501"]
95
97
  "examples/**" = ["T201", "INP001"]
98
+
99
+
100
+ [tool.pyright]
101
+ venvPath = "."
102
+ venv = ".venv"
@@ -1,98 +1,105 @@
1
- """Compose functions into readable, reusable, JSON-definable flows.
2
-
3
- `pyflowstep` is a functional replacement for the fluent-interface (method chaining)
4
- pattern. Instead of adding chainable methods to a class, you write small step
5
- functions and compose them with `>>`:
6
-
7
- ```python
8
- >>> from pyflowstep import step
9
- >>> @step
10
- ... def add(total: int, amount: int) -> int:
11
- ... return total + amount
12
- >>> @step
13
- ... def double(total: int) -> int:
14
- ... return total * 2
15
- >>> (add(3) >> double() >> add(1))(0)
16
- 7
17
-
18
- ```
19
-
20
- Steps collected in a `StepsRegistry` can also be described as JSON
21
- (`get_flow_json_schema`) and compiled from JSON (`FlowCompiler`).
22
-
23
- Raw JSON values become typed arguments with the `Process` marker of
24
- `pyargprocessors`, written next to the parameter:
25
-
26
- ```python
27
- >>> from typing import Annotated
28
- >>> from pyargprocessors import Process
29
- >>> @step
30
- ... def scale(total: int, factor: Annotated[int, Process(int)]) -> int:
31
- ... return total * factor
32
- >>> scale("3")(2)
33
- 6
34
-
35
- ```
36
- """
37
-
38
- from .compilers import FlowCompiler, FlowDefinition, StepDict, validate_step_dict
39
- from .dependencies import Depends, override_dependencies
40
- from .exceptions import (
41
- ArgumentError,
42
- InvalidDependencyError,
43
- InvalidFlowDefinitionError,
44
- InvalidInputError,
45
- InvalidStepError,
46
- InvalidStepNameError,
47
- MissingArgumentError,
48
- MissingInputError,
49
- MultipleValuesArgumentError,
50
- PositionalOnlyArgumentError,
51
- PyflowstepError,
52
- StepAlreadyRegisteredError,
53
- StepDoesNotExistError,
54
- TooManyArgumentsError,
55
- UnexpectedKeywordArgumentError,
56
- )
57
- from .flow import Action, Flow, compose
58
- from .inputs import Input
59
- from .json_schema import get_flow_json_schema, get_json_schema, get_step_json_schema
60
- from .registry import StepsRegistry
61
- from .steps import StepFactory, StepFn, TapFn, step, tap
62
-
63
- __all__ = [
64
- "Action",
65
- "ArgumentError",
66
- "Depends",
67
- "Flow",
68
- "FlowCompiler",
69
- "FlowDefinition",
70
- "Input",
71
- "InvalidDependencyError",
72
- "InvalidFlowDefinitionError",
73
- "InvalidInputError",
74
- "InvalidStepError",
75
- "InvalidStepNameError",
76
- "MissingArgumentError",
77
- "MissingInputError",
78
- "MultipleValuesArgumentError",
79
- "PositionalOnlyArgumentError",
80
- "PyflowstepError",
81
- "StepAlreadyRegisteredError",
82
- "StepDict",
83
- "StepDoesNotExistError",
84
- "StepFactory",
85
- "StepFn",
86
- "StepsRegistry",
87
- "TapFn",
88
- "TooManyArgumentsError",
89
- "UnexpectedKeywordArgumentError",
90
- "compose",
91
- "get_flow_json_schema",
92
- "get_json_schema",
93
- "get_step_json_schema",
94
- "override_dependencies",
95
- "step",
96
- "tap",
97
- "validate_step_dict",
98
- ]
1
+ """Compose functions into readable, reusable, JSON-definable flows.
2
+
3
+ `pyflowstep` is a functional replacement for the fluent-interface (method chaining)
4
+ pattern. Instead of adding chainable methods to a class, you write small step
5
+ functions and compose them with `>>`:
6
+
7
+ ```python
8
+ >>> from pyflowstep import step
9
+ >>> @step
10
+ ... def add(total: int, amount: int) -> int:
11
+ ... return total + amount
12
+ >>> @step
13
+ ... def double(total: int) -> int:
14
+ ... return total * 2
15
+ >>> (add(3) >> double() >> add(1))(0)
16
+ 7
17
+
18
+ ```
19
+
20
+ Steps collected in a `StepsRegistry` can also be described as JSON
21
+ (`get_flow_json_schema`) and compiled from JSON or TOML files (`FlowCompiler`);
22
+ `register_flow_format` adds other file formats.
23
+
24
+ Raw JSON values become typed arguments with the `Process` marker of
25
+ `pyargprocessors`, written next to the parameter:
26
+
27
+ ```python
28
+ >>> from typing import Annotated
29
+ >>> from pyargprocessors import Process
30
+ >>> @step
31
+ ... def scale(total: int, factor: Annotated[int, Process(int)]) -> int:
32
+ ... return total * factor
33
+ >>> scale("3")(2)
34
+ 6
35
+
36
+ ```
37
+ """
38
+
39
+ from .compilers import FlowCompiler, FlowDefinition, StepDict, validate_step_dict
40
+ from .dependencies import Depends, override_dependencies
41
+ from .exceptions import (
42
+ ArgumentError,
43
+ InvalidDependencyError,
44
+ InvalidFlowDefinitionError,
45
+ InvalidInputError,
46
+ InvalidStepError,
47
+ InvalidStepNameError,
48
+ MissingArgumentError,
49
+ MissingInputError,
50
+ MultipleValuesArgumentError,
51
+ PositionalOnlyArgumentError,
52
+ PyflowstepError,
53
+ StepAlreadyRegisteredError,
54
+ StepDoesNotExistError,
55
+ TooManyArgumentsError,
56
+ UnexpectedKeywordArgumentError,
57
+ UnsupportedFlowFormatError,
58
+ )
59
+ from .flow import Action, Flow, compose
60
+ from .inputs import Input
61
+ from .json_schema import get_flow_json_schema, get_json_schema, get_step_json_schema
62
+ from .loaders import FlowParser, load_flow_definition, register_flow_format
63
+ from .registry import StepsRegistry
64
+ from .steps import StepFactory, StepFn, TapFn, step, tap
65
+
66
+ __all__ = [
67
+ "Action",
68
+ "ArgumentError",
69
+ "Depends",
70
+ "Flow",
71
+ "FlowCompiler",
72
+ "FlowDefinition",
73
+ "FlowParser",
74
+ "Input",
75
+ "InvalidDependencyError",
76
+ "InvalidFlowDefinitionError",
77
+ "InvalidInputError",
78
+ "InvalidStepError",
79
+ "InvalidStepNameError",
80
+ "MissingArgumentError",
81
+ "MissingInputError",
82
+ "MultipleValuesArgumentError",
83
+ "PositionalOnlyArgumentError",
84
+ "PyflowstepError",
85
+ "StepAlreadyRegisteredError",
86
+ "StepDict",
87
+ "StepDoesNotExistError",
88
+ "StepFactory",
89
+ "StepFn",
90
+ "StepsRegistry",
91
+ "TapFn",
92
+ "TooManyArgumentsError",
93
+ "UnexpectedKeywordArgumentError",
94
+ "UnsupportedFlowFormatError",
95
+ "compose",
96
+ "get_flow_json_schema",
97
+ "get_json_schema",
98
+ "get_step_json_schema",
99
+ "load_flow_definition",
100
+ "override_dependencies",
101
+ "register_flow_format",
102
+ "step",
103
+ "tap",
104
+ "validate_step_dict",
105
+ ]