stepfunction 0.0.4__tar.gz → 0.0.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.
- {stepfunction-0.0.4/src/StepFunction.egg-info → stepfunction-0.0.6}/PKG-INFO +1 -1
- {stepfunction-0.0.4 → stepfunction-0.0.6}/pyproject.toml +1 -1
- {stepfunction-0.0.4 → stepfunction-0.0.6/src/StepFunction.egg-info}/PKG-INFO +1 -1
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/StepFunction.egg-info/SOURCES.txt +4 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/core/step_function/step_function.py +1 -1
- stepfunction-0.0.6/src/stepfunction/steps/__init__.py +7 -0
- stepfunction-0.0.6/src/stepfunction/steps/exceptions/__init__.py +3 -0
- stepfunction-0.0.6/src/stepfunction/steps/exceptions/step_exceptions.py +11 -0
- stepfunction-0.0.6/src/stepfunction/steps/retry_step.py +78 -0
- stepfunction-0.0.6/src/stepfunction/steps/timeout_step.py +65 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/steps/wait_step.py +6 -2
- stepfunction-0.0.4/src/stepfunction/steps/__init__.py +0 -4
- {stepfunction-0.0.4 → stepfunction-0.0.6}/LICENSE +0 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/README.md +0 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/setup.cfg +0 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/StepFunction.egg-info/dependency_links.txt +0 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/StepFunction.egg-info/requires.txt +0 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/StepFunction.egg-info/top_level.txt +0 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/constants/__init__.py +0 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/constants/enums.py +0 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/constants/visualizer.py +0 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/core/step_function/__init__.py +0 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/core/visualizer/__init__.py +0 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/core/visualizer/visualizer.py +0 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/exceptions/__init__.py +0 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/exceptions/step_errors.py +0 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/steps/base/__init__.py +0 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/steps/base/base_step.py +0 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/types/__init__.py +0 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/types/step_types.py +0 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/types/visualizer_types.py +0 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/utils/__init__.py +0 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/utils/constants.py +0 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/utils/logger.py +0 -0
- {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/utils/utils.py +0 -0
|
@@ -21,9 +21,13 @@ src/stepfunction/core/visualizer/visualizer.py
|
|
|
21
21
|
src/stepfunction/exceptions/__init__.py
|
|
22
22
|
src/stepfunction/exceptions/step_errors.py
|
|
23
23
|
src/stepfunction/steps/__init__.py
|
|
24
|
+
src/stepfunction/steps/retry_step.py
|
|
25
|
+
src/stepfunction/steps/timeout_step.py
|
|
24
26
|
src/stepfunction/steps/wait_step.py
|
|
25
27
|
src/stepfunction/steps/base/__init__.py
|
|
26
28
|
src/stepfunction/steps/base/base_step.py
|
|
29
|
+
src/stepfunction/steps/exceptions/__init__.py
|
|
30
|
+
src/stepfunction/steps/exceptions/step_exceptions.py
|
|
27
31
|
src/stepfunction/types/__init__.py
|
|
28
32
|
src/stepfunction/types/step_types.py
|
|
29
33
|
src/stepfunction/types/visualizer_types.py
|
{stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/core/step_function/step_function.py
RENAMED
|
@@ -131,7 +131,7 @@ class StepFunction:
|
|
|
131
131
|
func: Union[Callable[[Any], Any], Dict[str, Callable[[Any], Any]], BaseStep],
|
|
132
132
|
next_step: Optional[str] = None,
|
|
133
133
|
on_failure: Optional[str] = None,
|
|
134
|
-
branch: Optional[Dict[Any, str]] = None,
|
|
134
|
+
branch: Optional[Union[Dict[Any, str], Callable[[Any], str]]] = None,
|
|
135
135
|
parallel: bool = False,
|
|
136
136
|
stop_on_failure: bool = False,
|
|
137
137
|
):
|
|
@@ -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,78 @@
|
|
|
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, Optional
|
|
9
|
+
|
|
10
|
+
from stepfunction.constants.enums import StepType
|
|
11
|
+
from stepfunction.steps.base import BaseStep
|
|
12
|
+
from stepfunction.utils.logger import setup_logger
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class RetryStep(BaseStep):
|
|
16
|
+
"""A step that retries a callable on failure with a fixed delay between attempts.
|
|
17
|
+
|
|
18
|
+
Executes the wrapped function and retries up to ``max_retries`` times if it
|
|
19
|
+
raises an exception. Raises the last exception if all attempts fail.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
func (Callable): The function to execute. May be sync or async.
|
|
23
|
+
max_retries (int): Maximum number of retry attempts after the first failure.
|
|
24
|
+
A value of 3 means the function is called at most 4 times. Defaults to 3.
|
|
25
|
+
delay (float): Seconds to wait between retry attempts. Defaults to 1.0.
|
|
26
|
+
|
|
27
|
+
Raises:
|
|
28
|
+
ValueError: If max_retries is negative or delay is negative.
|
|
29
|
+
|
|
30
|
+
Example:
|
|
31
|
+
sf.add_step("fetch", RetryStep(func=call_api, max_retries=3, delay=2.0), next_step="next")
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
step_type: StepType = StepType.INBUILT
|
|
35
|
+
|
|
36
|
+
def __init__(
|
|
37
|
+
self, func: Callable[[Any], Any], max_retries: int = 3, delay: float = 1.0
|
|
38
|
+
):
|
|
39
|
+
if max_retries < 0:
|
|
40
|
+
raise ValueError("max_retries must be a non-negative integer")
|
|
41
|
+
if delay < 0:
|
|
42
|
+
raise ValueError("delay must be a non-negative number")
|
|
43
|
+
|
|
44
|
+
self.func = func
|
|
45
|
+
self.max_retries = max_retries
|
|
46
|
+
self.delay = delay
|
|
47
|
+
self.__logger = setup_logger(__name__)
|
|
48
|
+
|
|
49
|
+
def build(self) -> Callable[[Any], Any]:
|
|
50
|
+
"""Return an async function that retries ``func`` on failure."""
|
|
51
|
+
func = self.func
|
|
52
|
+
max_retries = self.max_retries
|
|
53
|
+
delay = self.delay
|
|
54
|
+
|
|
55
|
+
async def run(input_value: Any) -> Any:
|
|
56
|
+
self.__logger.debug(
|
|
57
|
+
f"RetryStep - executing with max_retries={max_retries}, delay={delay}s"
|
|
58
|
+
)
|
|
59
|
+
last_exc: Optional[Exception] = None
|
|
60
|
+
|
|
61
|
+
for attempt in range(max_retries + 1):
|
|
62
|
+
try:
|
|
63
|
+
if iscoroutinefunction(func):
|
|
64
|
+
return await func(input_value)
|
|
65
|
+
return func(input_value)
|
|
66
|
+
except Exception as exc:
|
|
67
|
+
last_exc = exc
|
|
68
|
+
self.__logger.warning(
|
|
69
|
+
f"RetryStep - attempt {attempt + 1}/{max_retries + 1} failed: {exc}"
|
|
70
|
+
)
|
|
71
|
+
if attempt < max_retries:
|
|
72
|
+
self.__logger.debug(f"RetryStep - retrying in {delay}s")
|
|
73
|
+
await sleep(delay)
|
|
74
|
+
|
|
75
|
+
self.__logger.error(f"RetryStep - all {max_retries + 1} attempts exhausted")
|
|
76
|
+
raise last_exc
|
|
77
|
+
|
|
78
|
+
return run
|
|
@@ -0,0 +1,65 @@
|
|
|
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
|
+
from stepfunction.utils.logger import setup_logger
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class TimeoutStep(BaseStep):
|
|
18
|
+
"""A step that raises an error if the wrapped callable exceeds a time limit.
|
|
19
|
+
|
|
20
|
+
Works with both sync and async functions. Sync functions are executed in a
|
|
21
|
+
thread pool so the timeout can be enforced without blocking the event loop.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
func (Callable): The function to execute. May be sync or async.
|
|
25
|
+
timeout (float): Maximum allowed duration in seconds.
|
|
26
|
+
|
|
27
|
+
Raises:
|
|
28
|
+
ValueError: If timeout is not a positive number.
|
|
29
|
+
StepTimeoutError: If the function does not complete within ``timeout`` seconds.
|
|
30
|
+
|
|
31
|
+
Example:
|
|
32
|
+
sf.add_step("process", TimeoutStep(func=heavy_job, timeout=30.0), next_step="next")
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
step_type: StepType = StepType.INBUILT
|
|
36
|
+
|
|
37
|
+
def __init__(self, func: Callable[[Any], Any], timeout: float):
|
|
38
|
+
if timeout <= 0:
|
|
39
|
+
raise ValueError("timeout must be a positive number")
|
|
40
|
+
|
|
41
|
+
self.func = func
|
|
42
|
+
self.timeout = timeout
|
|
43
|
+
self.__logger = setup_logger(__name__)
|
|
44
|
+
|
|
45
|
+
def build(self) -> Callable[[Any], Any]:
|
|
46
|
+
"""Return an async function that enforces a timeout on ``func``."""
|
|
47
|
+
func = self.func
|
|
48
|
+
timeout = self.timeout
|
|
49
|
+
|
|
50
|
+
async def run(input_value: Any) -> Any:
|
|
51
|
+
self.__logger.debug(f"TimeoutStep - executing with timeout of {timeout}s")
|
|
52
|
+
try:
|
|
53
|
+
if iscoroutinefunction(func):
|
|
54
|
+
return await wait_for(func(input_value), timeout=timeout)
|
|
55
|
+
else:
|
|
56
|
+
loop = get_running_loop()
|
|
57
|
+
return await wait_for(
|
|
58
|
+
loop.run_in_executor(None, func, input_value),
|
|
59
|
+
timeout=timeout,
|
|
60
|
+
)
|
|
61
|
+
except AsyncTimeoutError:
|
|
62
|
+
self.__logger.error(f"TimeoutStep - exceeded timeout of {timeout}s")
|
|
63
|
+
raise StepTimeoutError(timeout)
|
|
64
|
+
|
|
65
|
+
return run
|
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
Author: Vineeth Penugonda
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
import
|
|
6
|
+
from asyncio import sleep
|
|
7
7
|
from typing import Any, Callable
|
|
8
8
|
|
|
9
9
|
from stepfunction.constants.enums import StepType
|
|
10
10
|
from stepfunction.steps.base import BaseStep
|
|
11
|
+
from stepfunction.utils.logger import setup_logger
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class WaitStep(BaseStep):
|
|
@@ -29,13 +30,16 @@ class WaitStep(BaseStep):
|
|
|
29
30
|
if duration < 0:
|
|
30
31
|
raise ValueError("duration must be a non-negative number")
|
|
31
32
|
self.duration = duration
|
|
33
|
+
self.__logger = setup_logger(__name__)
|
|
32
34
|
|
|
33
35
|
def build(self) -> Callable[[Any], Any]:
|
|
34
36
|
"""Return an async function that sleeps for ``duration`` seconds."""
|
|
35
37
|
duration = self.duration
|
|
36
38
|
|
|
37
39
|
async def wait(input_value: Any) -> Any:
|
|
38
|
-
|
|
40
|
+
self.__logger.debug(f"WaitStep - sleeping for {duration}s")
|
|
41
|
+
await sleep(duration)
|
|
42
|
+
self.__logger.debug(f"WaitStep - resumed after {duration}s")
|
|
39
43
|
return input_value
|
|
40
44
|
|
|
41
45
|
return wait
|
|
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
|