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.
Files changed (35) hide show
  1. {stepfunction-0.0.4/src/StepFunction.egg-info → stepfunction-0.0.6}/PKG-INFO +1 -1
  2. {stepfunction-0.0.4 → stepfunction-0.0.6}/pyproject.toml +1 -1
  3. {stepfunction-0.0.4 → stepfunction-0.0.6/src/StepFunction.egg-info}/PKG-INFO +1 -1
  4. {stepfunction-0.0.4 → stepfunction-0.0.6}/src/StepFunction.egg-info/SOURCES.txt +4 -0
  5. {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/core/step_function/step_function.py +1 -1
  6. stepfunction-0.0.6/src/stepfunction/steps/__init__.py +7 -0
  7. stepfunction-0.0.6/src/stepfunction/steps/exceptions/__init__.py +3 -0
  8. stepfunction-0.0.6/src/stepfunction/steps/exceptions/step_exceptions.py +11 -0
  9. stepfunction-0.0.6/src/stepfunction/steps/retry_step.py +78 -0
  10. stepfunction-0.0.6/src/stepfunction/steps/timeout_step.py +65 -0
  11. {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/steps/wait_step.py +6 -2
  12. stepfunction-0.0.4/src/stepfunction/steps/__init__.py +0 -4
  13. {stepfunction-0.0.4 → stepfunction-0.0.6}/LICENSE +0 -0
  14. {stepfunction-0.0.4 → stepfunction-0.0.6}/README.md +0 -0
  15. {stepfunction-0.0.4 → stepfunction-0.0.6}/setup.cfg +0 -0
  16. {stepfunction-0.0.4 → stepfunction-0.0.6}/src/StepFunction.egg-info/dependency_links.txt +0 -0
  17. {stepfunction-0.0.4 → stepfunction-0.0.6}/src/StepFunction.egg-info/requires.txt +0 -0
  18. {stepfunction-0.0.4 → stepfunction-0.0.6}/src/StepFunction.egg-info/top_level.txt +0 -0
  19. {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/constants/__init__.py +0 -0
  20. {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/constants/enums.py +0 -0
  21. {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/constants/visualizer.py +0 -0
  22. {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/core/step_function/__init__.py +0 -0
  23. {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/core/visualizer/__init__.py +0 -0
  24. {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/core/visualizer/visualizer.py +0 -0
  25. {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/exceptions/__init__.py +0 -0
  26. {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/exceptions/step_errors.py +0 -0
  27. {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/steps/base/__init__.py +0 -0
  28. {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/steps/base/base_step.py +0 -0
  29. {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/types/__init__.py +0 -0
  30. {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/types/step_types.py +0 -0
  31. {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/types/visualizer_types.py +0 -0
  32. {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/utils/__init__.py +0 -0
  33. {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/utils/constants.py +0 -0
  34. {stepfunction-0.0.4 → stepfunction-0.0.6}/src/stepfunction/utils/logger.py +0 -0
  35. {stepfunction-0.0.4 → stepfunction-0.0.6}/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.4
3
+ Version: 0.0.6
4
4
  Summary: Step Function Workflow Orchestration Library
5
5
  Author: Vineeth Penugonda
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "stepfunction"
3
- version = "0.0.4"
3
+ version = "0.0.6"
4
4
  authors = [{ name = "Vineeth Penugonda" }]
5
5
  description = "Step Function Workflow Orchestration Library"
6
6
  readme = "README.md"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stepfunction
3
- Version: 0.0.4
3
+ Version: 0.0.6
4
4
  Summary: Step Function Workflow Orchestration Library
5
5
  Author: Vineeth Penugonda
6
6
  License-Expression: MIT
@@ -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
@@ -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,7 @@
1
+ from .base import BaseStep
2
+ from .exceptions import StepTimeoutError
3
+ from .retry_step import RetryStep
4
+ from .timeout_step import TimeoutStep
5
+ from .wait_step import WaitStep
6
+
7
+ __all__ = ["BaseStep", "RetryStep", "StepTimeoutError", "TimeoutStep", "WaitStep"]
@@ -0,0 +1,3 @@
1
+ from .step_exceptions import StepTimeoutError
2
+
3
+ __all__ = ["StepTimeoutError"]
@@ -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 asyncio
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
- await asyncio.sleep(duration)
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
@@ -1,4 +0,0 @@
1
- from .base import BaseStep
2
- from .wait_step import WaitStep
3
-
4
- __all__ = ["BaseStep", "WaitStep"]
File without changes
File without changes
File without changes