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.
Files changed (34) hide show
  1. {stepfunction-0.0.3/src/StepFunction.egg-info → stepfunction-0.0.5}/PKG-INFO +2 -2
  2. {stepfunction-0.0.3 → stepfunction-0.0.5}/README.md +1 -1
  3. {stepfunction-0.0.3 → stepfunction-0.0.5}/pyproject.toml +1 -1
  4. {stepfunction-0.0.3 → stepfunction-0.0.5/src/StepFunction.egg-info}/PKG-INFO +2 -2
  5. {stepfunction-0.0.3 → stepfunction-0.0.5}/src/StepFunction.egg-info/SOURCES.txt +8 -0
  6. {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/constants/enums.py +5 -0
  7. {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/core/step_function/step_function.py +8 -1
  8. stepfunction-0.0.5/src/stepfunction/steps/__init__.py +7 -0
  9. stepfunction-0.0.5/src/stepfunction/steps/base/__init__.py +3 -0
  10. stepfunction-0.0.5/src/stepfunction/steps/base/base_step.py +54 -0
  11. stepfunction-0.0.5/src/stepfunction/steps/exceptions/__init__.py +3 -0
  12. stepfunction-0.0.5/src/stepfunction/steps/exceptions/step_exceptions.py +11 -0
  13. stepfunction-0.0.5/src/stepfunction/steps/retry_step.py +68 -0
  14. stepfunction-0.0.5/src/stepfunction/steps/timeout_step.py +61 -0
  15. stepfunction-0.0.5/src/stepfunction/steps/wait_step.py +41 -0
  16. {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/types/step_types.py +3 -0
  17. {stepfunction-0.0.3 → stepfunction-0.0.5}/LICENSE +0 -0
  18. {stepfunction-0.0.3 → stepfunction-0.0.5}/setup.cfg +0 -0
  19. {stepfunction-0.0.3 → stepfunction-0.0.5}/src/StepFunction.egg-info/dependency_links.txt +0 -0
  20. {stepfunction-0.0.3 → stepfunction-0.0.5}/src/StepFunction.egg-info/requires.txt +0 -0
  21. {stepfunction-0.0.3 → stepfunction-0.0.5}/src/StepFunction.egg-info/top_level.txt +0 -0
  22. {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/constants/__init__.py +0 -0
  23. {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/constants/visualizer.py +0 -0
  24. {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/core/step_function/__init__.py +0 -0
  25. {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/core/visualizer/__init__.py +0 -0
  26. {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/core/visualizer/visualizer.py +0 -0
  27. {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/exceptions/__init__.py +0 -0
  28. {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/exceptions/step_errors.py +0 -0
  29. {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/types/__init__.py +0 -0
  30. {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/types/visualizer_types.py +0 -0
  31. {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/utils/__init__.py +0 -0
  32. {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/utils/constants.py +0 -0
  33. {stepfunction-0.0.3 → stepfunction-0.0.5}/src/stepfunction/utils/logger.py +0 -0
  34. {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
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
  ![License](https://img.shields.io/badge/License-MIT-blue.svg)
25
- ![Python](https://img.shields.io/badge/Python-3.12%2B-brightgreen.svg)
25
+ ![Python](https://img.shields.io/badge/Python-3.9%2B-brightgreen.svg)
26
26
  ![Status](https://img.shields.io/badge/Status-Alpha-red.svg)
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
  ![License](https://img.shields.io/badge/License-MIT-blue.svg)
4
- ![Python](https://img.shields.io/badge/Python-3.12%2B-brightgreen.svg)
4
+ ![Python](https://img.shields.io/badge/Python-3.9%2B-brightgreen.svg)
5
5
  ![Status](https://img.shields.io/badge/Status-Alpha-red.svg)
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
  [project]
2
2
  name = "stepfunction"
3
- version = "0.0.3"
3
+ version = "0.0.5"
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.3
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
  ![License](https://img.shields.io/badge/License-MIT-blue.svg)
25
- ![Python](https://img.shields.io/badge/Python-3.12%2B-brightgreen.svg)
25
+ ![Python](https://img.shields.io/badge/Python-3.9%2B-brightgreen.svg)
26
26
  ![Status](https://img.shields.io/badge/Status-Alpha-red.svg)
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
@@ -6,3 +6,8 @@ class StepFunctionStatus(Enum):
6
6
  RUNNING = "IN_PROGRESS"
7
7
  COMPLETED = "COMPLETED"
8
8
  FAILED = "FAILED"
9
+
10
+
11
+ class StepType(Enum):
12
+ INBUILT = "INBUILT"
13
+ EXTERNAL = "EXTERNAL"
@@ -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,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 .base_step import BaseStep
2
+
3
+ __all__ = ["BaseStep"]
@@ -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,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,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