stepfunction 0.0.3__tar.gz → 0.0.5__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.
- {stepfunction-0.0.3/src/StepFunction.egg-info → stepfunction-0.0.5}/PKG-INFO +2 -2
- {stepfunction-0.0.3 → stepfunction-0.0.5}/README.md +1 -1
- {stepfunction-0.0.3 → stepfunction-0.0.5}/pyproject.toml +1 -1
- {stepfunction-0.0.3 → stepfunction-0.0.5/src/StepFunction.egg-info}/PKG-INFO +2 -2
- {stepfunction-0.0.3 → stepfunction-0.0.5}/src/StepFunction.egg-info/SOURCES.txt +8 -0
- {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/constants/enums.py +5 -0
- {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/core/step_function/step_function.py +8 -1
- stepfunction-0.0.5/src/stepfunction/steps/__init__.py +7 -0
- stepfunction-0.0.5/src/stepfunction/steps/base/__init__.py +3 -0
- stepfunction-0.0.5/src/stepfunction/steps/base/base_step.py +54 -0
- stepfunction-0.0.5/src/stepfunction/steps/exceptions/__init__.py +3 -0
- stepfunction-0.0.5/src/stepfunction/steps/exceptions/step_exceptions.py +11 -0
- stepfunction-0.0.5/src/stepfunction/steps/retry_step.py +68 -0
- stepfunction-0.0.5/src/stepfunction/steps/timeout_step.py +61 -0
- stepfunction-0.0.5/src/stepfunction/steps/wait_step.py +41 -0
- {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/types/step_types.py +3 -0
- {stepfunction-0.0.3 → stepfunction-0.0.5}/LICENSE +0 -0
- {stepfunction-0.0.3 → stepfunction-0.0.5}/setup.cfg +0 -0
- {stepfunction-0.0.3 → stepfunction-0.0.5}/src/StepFunction.egg-info/dependency_links.txt +0 -0
- {stepfunction-0.0.3 → stepfunction-0.0.5}/src/StepFunction.egg-info/requires.txt +0 -0
- {stepfunction-0.0.3 → stepfunction-0.0.5}/src/StepFunction.egg-info/top_level.txt +0 -0
- {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/constants/__init__.py +0 -0
- {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/constants/visualizer.py +0 -0
- {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/core/step_function/__init__.py +0 -0
- {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/core/visualizer/__init__.py +0 -0
- {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/core/visualizer/visualizer.py +0 -0
- {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/exceptions/__init__.py +0 -0
- {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/exceptions/step_errors.py +0 -0
- {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/types/__init__.py +0 -0
- {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/types/visualizer_types.py +0 -0
- {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/utils/__init__.py +0 -0
- {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/utils/constants.py +0 -0
- {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/utils/logger.py +0 -0
- {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/utils/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stepfunction
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.5
|
|
4
4
|
Summary: Step Function Workflow Orchestration Library
|
|
5
5
|
Author: Vineeth Penugonda
|
|
6
6
|
License-Expression: MIT
|
|
@@ -22,7 +22,7 @@ Dynamic: license-file
|
|
|
22
22
|
# StepFunction
|
|
23
23
|
|
|
24
24
|

|
|
25
|
-

|
|
26
26
|

|
|
27
27
|
|
|
28
28
|
`StepFunction` is a Python library for orchestrating complex workflows through a step-by-step process. It allows for easy management of sequential and parallel tasks with robust error handling and branching. The library is inspired by AWS Step Functions but implemented as a Python-native solution to orchestrate workflows across any environment.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# StepFunction
|
|
2
2
|
|
|
3
3
|

|
|
4
|
-

|
|
5
5
|

|
|
6
6
|
|
|
7
7
|
`StepFunction` is a Python library for orchestrating complex workflows through a step-by-step process. It allows for easy management of sequential and parallel tasks with robust error handling and branching. The library is inspired by AWS Step Functions but implemented as a Python-native solution to orchestrate workflows across any environment.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stepfunction
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.5
|
|
4
4
|
Summary: Step Function Workflow Orchestration Library
|
|
5
5
|
Author: Vineeth Penugonda
|
|
6
6
|
License-Expression: MIT
|
|
@@ -22,7 +22,7 @@ Dynamic: license-file
|
|
|
22
22
|
# StepFunction
|
|
23
23
|
|
|
24
24
|

|
|
25
|
-

|
|
26
26
|

|
|
27
27
|
|
|
28
28
|
`StepFunction` is a Python library for orchestrating complex workflows through a step-by-step process. It allows for easy management of sequential and parallel tasks with robust error handling and branching. The library is inspired by AWS Step Functions but implemented as a Python-native solution to orchestrate workflows across any environment.
|
|
@@ -20,6 +20,14 @@ src/stepfunction/core/visualizer/__init__.py
|
|
|
20
20
|
src/stepfunction/core/visualizer/visualizer.py
|
|
21
21
|
src/stepfunction/exceptions/__init__.py
|
|
22
22
|
src/stepfunction/exceptions/step_errors.py
|
|
23
|
+
src/stepfunction/steps/__init__.py
|
|
24
|
+
src/stepfunction/steps/retry_step.py
|
|
25
|
+
src/stepfunction/steps/timeout_step.py
|
|
26
|
+
src/stepfunction/steps/wait_step.py
|
|
27
|
+
src/stepfunction/steps/base/__init__.py
|
|
28
|
+
src/stepfunction/steps/base/base_step.py
|
|
29
|
+
src/stepfunction/steps/exceptions/__init__.py
|
|
30
|
+
src/stepfunction/steps/exceptions/step_exceptions.py
|
|
23
31
|
src/stepfunction/types/__init__.py
|
|
24
32
|
src/stepfunction/types/step_types.py
|
|
25
33
|
src/stepfunction/types/visualizer_types.py
|
{stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/core/step_function/step_function.py
RENAMED
|
@@ -13,6 +13,7 @@ from stepfunction.exceptions.step_errors import (
|
|
|
13
13
|
ParallelStepExecutionError,
|
|
14
14
|
StepExecutionError,
|
|
15
15
|
)
|
|
16
|
+
from stepfunction.steps.base import BaseStep
|
|
16
17
|
from stepfunction.types.step_types import StepParams
|
|
17
18
|
from stepfunction.utils.logger import setup_logger
|
|
18
19
|
|
|
@@ -127,7 +128,7 @@ class StepFunction:
|
|
|
127
128
|
def add_step(
|
|
128
129
|
self,
|
|
129
130
|
name: str,
|
|
130
|
-
func: Union[Callable[[Any], Any], Dict[str, Callable[[Any], Any]]],
|
|
131
|
+
func: Union[Callable[[Any], Any], Dict[str, Callable[[Any], Any]], BaseStep],
|
|
131
132
|
next_step: Optional[str] = None,
|
|
132
133
|
on_failure: Optional[str] = None,
|
|
133
134
|
branch: Optional[Dict[Any, str]] = None,
|
|
@@ -139,6 +140,11 @@ class StepFunction:
|
|
|
139
140
|
if name in self.__steps:
|
|
140
141
|
raise ValueError(f"Step '{name}' already exists in steps")
|
|
141
142
|
|
|
143
|
+
step_type = None
|
|
144
|
+
if isinstance(func, BaseStep):
|
|
145
|
+
step_type = func.step_type
|
|
146
|
+
func = func.build()
|
|
147
|
+
|
|
142
148
|
self.__steps[name] = {
|
|
143
149
|
"func": func,
|
|
144
150
|
"next_step": next_step,
|
|
@@ -146,6 +152,7 @@ class StepFunction:
|
|
|
146
152
|
"branch": branch,
|
|
147
153
|
"parallel": parallel,
|
|
148
154
|
"stop_on_failure": stop_on_failure,
|
|
155
|
+
"step_type": step_type,
|
|
149
156
|
}
|
|
150
157
|
|
|
151
158
|
def add_sub_step_function(
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Base class for building custom step types.
|
|
2
|
+
|
|
3
|
+
Author: Vineeth Penugonda
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from abc import ABC, abstractmethod
|
|
7
|
+
from typing import Any, Callable
|
|
8
|
+
|
|
9
|
+
from stepfunction.constants.enums import StepType
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class BaseStep(ABC):
|
|
13
|
+
"""Abstract base class for building reusable, configurable step types.
|
|
14
|
+
|
|
15
|
+
Extend this class to create custom step types that encapsulate their own
|
|
16
|
+
logic and configuration. Pass an instance directly to ``StepFunction.add_step()``
|
|
17
|
+
— the framework will call ``build()`` automatically.
|
|
18
|
+
|
|
19
|
+
Class Attributes:
|
|
20
|
+
step_type (StepType): Marks the origin of the step.
|
|
21
|
+
- ``StepType.EXTERNAL`` (default) — user-defined step.
|
|
22
|
+
- ``StepType.INBUILT`` — provided by the stepfunction library.
|
|
23
|
+
Override this in your subclass only if you are building library steps.
|
|
24
|
+
|
|
25
|
+
Methods:
|
|
26
|
+
build(): Return the callable that the StepFunction will execute.
|
|
27
|
+
|
|
28
|
+
Example:
|
|
29
|
+
class MultiplyStep(BaseStep):
|
|
30
|
+
def __init__(self, factor: float):
|
|
31
|
+
self.factor = factor
|
|
32
|
+
|
|
33
|
+
def build(self) -> Callable:
|
|
34
|
+
async def run(input_value: Any) -> Any:
|
|
35
|
+
return input_value * self.factor
|
|
36
|
+
return run
|
|
37
|
+
|
|
38
|
+
sf.add_step("double", MultiplyStep(factor=2), next_step="next")
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
step_type: StepType = StepType.EXTERNAL
|
|
42
|
+
|
|
43
|
+
@abstractmethod
|
|
44
|
+
def build(self) -> Callable[[Any], Any]:
|
|
45
|
+
"""Return the callable that this step will execute.
|
|
46
|
+
|
|
47
|
+
The returned callable must accept a single positional argument
|
|
48
|
+
(the input value passed from the previous step) and return a value
|
|
49
|
+
that will be forwarded to the next step. It may be either a regular
|
|
50
|
+
function or a coroutine function.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Callable[[Any], Any]: The step function to execute.
|
|
54
|
+
"""
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""Exceptions for built-in step types.
|
|
2
|
+
|
|
3
|
+
Author: Vineeth Penugonda
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class StepTimeoutError(Exception):
|
|
8
|
+
"""Raised when a step exceeds its allowed execution time."""
|
|
9
|
+
|
|
10
|
+
def __init__(self, timeout: float):
|
|
11
|
+
super().__init__(f"Step exceeded the timeout of {timeout}s")
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""RetryStep — a built-in step that retries a callable on failure.
|
|
2
|
+
|
|
3
|
+
Author: Vineeth Penugonda
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from asyncio import sleep
|
|
7
|
+
from inspect import iscoroutinefunction
|
|
8
|
+
from typing import Any, Callable
|
|
9
|
+
|
|
10
|
+
from stepfunction.constants.enums import StepType
|
|
11
|
+
from stepfunction.steps.base import BaseStep
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class RetryStep(BaseStep):
|
|
15
|
+
"""A step that retries a callable on failure with a fixed delay between attempts.
|
|
16
|
+
|
|
17
|
+
Executes the wrapped function and retries up to ``max_retries`` times if it
|
|
18
|
+
raises an exception. Raises the last exception if all attempts fail.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
func (Callable): The function to execute. May be sync or async.
|
|
22
|
+
max_retries (int): Maximum number of retry attempts after the first failure.
|
|
23
|
+
A value of 3 means the function is called at most 4 times. Defaults to 3.
|
|
24
|
+
delay (float): Seconds to wait between retry attempts. Defaults to 1.0.
|
|
25
|
+
|
|
26
|
+
Raises:
|
|
27
|
+
ValueError: If max_retries is negative or delay is negative.
|
|
28
|
+
|
|
29
|
+
Example:
|
|
30
|
+
sf.add_step("fetch", RetryStep(func=call_api, max_retries=3, delay=2.0), next_step="next")
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
step_type: StepType = StepType.INBUILT
|
|
34
|
+
|
|
35
|
+
def __init__(
|
|
36
|
+
self, func: Callable[[Any], Any], max_retries: int = 3, delay: float = 1.0
|
|
37
|
+
):
|
|
38
|
+
if max_retries < 0:
|
|
39
|
+
raise ValueError("max_retries must be a non-negative integer")
|
|
40
|
+
if delay < 0:
|
|
41
|
+
raise ValueError("delay must be a non-negative number")
|
|
42
|
+
|
|
43
|
+
self.func = func
|
|
44
|
+
self.max_retries = max_retries
|
|
45
|
+
self.delay = delay
|
|
46
|
+
|
|
47
|
+
def build(self) -> Callable[[Any], Any]:
|
|
48
|
+
"""Return an async function that retries ``func`` on failure."""
|
|
49
|
+
func = self.func
|
|
50
|
+
max_retries = self.max_retries
|
|
51
|
+
delay = self.delay
|
|
52
|
+
|
|
53
|
+
async def run(input_value: Any) -> Any:
|
|
54
|
+
last_exc: Exception = None
|
|
55
|
+
|
|
56
|
+
for attempt in range(max_retries + 1):
|
|
57
|
+
try:
|
|
58
|
+
if iscoroutinefunction(func):
|
|
59
|
+
return await func(input_value)
|
|
60
|
+
return func(input_value)
|
|
61
|
+
except Exception as exc:
|
|
62
|
+
last_exc = exc
|
|
63
|
+
if attempt < max_retries:
|
|
64
|
+
await sleep(delay)
|
|
65
|
+
|
|
66
|
+
raise last_exc
|
|
67
|
+
|
|
68
|
+
return run
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""TimeoutStep — a built-in step that enforces a maximum execution duration.
|
|
2
|
+
|
|
3
|
+
Author: Vineeth Penugonda
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from asyncio import TimeoutError as AsyncTimeoutError
|
|
7
|
+
from asyncio import get_running_loop, wait_for
|
|
8
|
+
from inspect import iscoroutinefunction
|
|
9
|
+
from typing import Any, Callable
|
|
10
|
+
|
|
11
|
+
from stepfunction.constants.enums import StepType
|
|
12
|
+
from stepfunction.steps.base import BaseStep
|
|
13
|
+
from stepfunction.steps.exceptions import StepTimeoutError
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TimeoutStep(BaseStep):
|
|
17
|
+
"""A step that raises an error if the wrapped callable exceeds a time limit.
|
|
18
|
+
|
|
19
|
+
Works with both sync and async functions. Sync functions are executed in a
|
|
20
|
+
thread pool so the timeout can be enforced without blocking the event loop.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
func (Callable): The function to execute. May be sync or async.
|
|
24
|
+
timeout (float): Maximum allowed duration in seconds.
|
|
25
|
+
|
|
26
|
+
Raises:
|
|
27
|
+
ValueError: If timeout is not a positive number.
|
|
28
|
+
StepTimeoutError: If the function does not complete within ``timeout`` seconds.
|
|
29
|
+
|
|
30
|
+
Example:
|
|
31
|
+
sf.add_step("process", TimeoutStep(func=heavy_job, timeout=30.0), next_step="next")
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
step_type: StepType = StepType.INBUILT
|
|
35
|
+
|
|
36
|
+
def __init__(self, func: Callable[[Any], Any], timeout: float):
|
|
37
|
+
if timeout <= 0:
|
|
38
|
+
raise ValueError("timeout must be a positive number")
|
|
39
|
+
|
|
40
|
+
self.func = func
|
|
41
|
+
self.timeout = timeout
|
|
42
|
+
|
|
43
|
+
def build(self) -> Callable[[Any], Any]:
|
|
44
|
+
"""Return an async function that enforces a timeout on ``func``."""
|
|
45
|
+
func = self.func
|
|
46
|
+
timeout = self.timeout
|
|
47
|
+
|
|
48
|
+
async def run(input_value: Any) -> Any:
|
|
49
|
+
try:
|
|
50
|
+
if iscoroutinefunction(func):
|
|
51
|
+
return await wait_for(func(input_value), timeout=timeout)
|
|
52
|
+
else:
|
|
53
|
+
loop = get_running_loop()
|
|
54
|
+
return await wait_for(
|
|
55
|
+
loop.run_in_executor(None, func, input_value),
|
|
56
|
+
timeout=timeout,
|
|
57
|
+
)
|
|
58
|
+
except AsyncTimeoutError:
|
|
59
|
+
raise StepTimeoutError(timeout)
|
|
60
|
+
|
|
61
|
+
return run
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""WaitStep — a built-in step that pauses execution for a fixed interval.
|
|
2
|
+
|
|
3
|
+
Author: Vineeth Penugonda
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from asyncio import sleep
|
|
7
|
+
from typing import Any, Callable
|
|
8
|
+
|
|
9
|
+
from stepfunction.constants.enums import StepType
|
|
10
|
+
from stepfunction.steps.base import BaseStep
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class WaitStep(BaseStep):
|
|
14
|
+
"""A step that pauses workflow execution for a fixed duration.
|
|
15
|
+
|
|
16
|
+
The input value is passed through unchanged so the next step receives
|
|
17
|
+
exactly what the previous step produced.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
duration (float): Number of seconds to wait before proceeding.
|
|
21
|
+
|
|
22
|
+
Example:
|
|
23
|
+
sf.add_step("pause", WaitStep(duration=5), next_step="next_step")
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
step_type: StepType = StepType.INBUILT
|
|
27
|
+
|
|
28
|
+
def __init__(self, duration: float):
|
|
29
|
+
if duration < 0:
|
|
30
|
+
raise ValueError("duration must be a non-negative number")
|
|
31
|
+
self.duration = duration
|
|
32
|
+
|
|
33
|
+
def build(self) -> Callable[[Any], Any]:
|
|
34
|
+
"""Return an async function that sleeps for ``duration`` seconds."""
|
|
35
|
+
duration = self.duration
|
|
36
|
+
|
|
37
|
+
async def wait(input_value: Any) -> Any:
|
|
38
|
+
await sleep(duration)
|
|
39
|
+
return input_value
|
|
40
|
+
|
|
41
|
+
return wait
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from typing import Any, Callable, Dict, Optional, TypedDict, Union
|
|
2
2
|
|
|
3
|
+
from stepfunction.constants.enums import StepType
|
|
4
|
+
|
|
3
5
|
|
|
4
6
|
class StepParams(TypedDict, total=False):
|
|
5
7
|
func: Callable[[Any], Any]
|
|
@@ -9,3 +11,4 @@ class StepParams(TypedDict, total=False):
|
|
|
9
11
|
parallel: bool
|
|
10
12
|
stop_on_failure: bool
|
|
11
13
|
is_sub_step_function: bool
|
|
14
|
+
step_type: Optional[StepType]
|
|
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
|