junban 1.0.0__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.
junban-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 biocentral
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
junban-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,7 @@
1
+ Metadata-Version: 2.4
2
+ Name: junban
3
+ Version: 1.0.0
4
+ Summary: Junban – Simple Sequential Python Workflows
5
+ Requires-Python: >=3.11
6
+ License-File: LICENSE
7
+ Dynamic: license-file
junban-1.0.0/README.md ADDED
@@ -0,0 +1,81 @@
1
+ # Junban (順番) – Simple Sequential Python Workflows
2
+
3
+ Junban (english: order) is a lightweight library for defining and executing sequential (scientific) workflows in Python.
4
+
5
+ ## Installation
6
+
7
+ Junban is available via pypi:
8
+ ```python
9
+
10
+ ```
11
+
12
+ ## Quick Example
13
+
14
+ Here is a simple example showing how to define a context and two steps. It showcases how context is passed between steps
15
+ and how entry/exit assumptions (verification) are handled.
16
+
17
+ ```python
18
+ from dataclasses import dataclass
19
+ from junban.pipeline import Pipeline
20
+ from junban.pipeline_step import PipelineStep
21
+ from junban.pipeline_context import PipelineContext
22
+
23
+
24
+ # 1. Define your context by inheriting from PipelineContext
25
+ @dataclass
26
+ class MyContext(PipelineContext):
27
+ value: int = 0
28
+ is_processed: bool = False
29
+
30
+
31
+ # 2. Create pipeline steps by inheriting from PipelineStep
32
+ class IncrementStep(PipelineStep[MyContext]):
33
+ def _check_entry_assumptions(self, context: MyContext) -> bool:
34
+ # Verification before step execution
35
+ return context.value == 0
36
+
37
+ def _execute(self, context: MyContext) -> MyContext:
38
+ # Core logic of the step
39
+ context.value += 1
40
+ return context
41
+
42
+ def _check_exit_assumptions(self, context: MyContext) -> bool:
43
+ # Verification after step execution
44
+ return context.value == 1
45
+
46
+ def get_start_message(self) -> str:
47
+ return "Incrementing value..."
48
+
49
+ def get_end_message(self) -> str:
50
+ return "Value incremented."
51
+
52
+
53
+ class ProcessStep(PipelineStep[MyContext]):
54
+ def _check_entry_assumptions(self, context: MyContext) -> bool:
55
+ return context.value > 0
56
+
57
+ def _execute(self, context: MyContext) -> MyContext:
58
+ context.is_processed = True
59
+ return context
60
+
61
+ def _check_exit_assumptions(self, context: MyContext) -> bool:
62
+ return context.is_processed is True
63
+
64
+ def get_start_message(self) -> str:
65
+ return "Processing..."
66
+
67
+ def get_end_message(self) -> str:
68
+ return "Processed."
69
+
70
+
71
+ # 3. Initialize and execute the pipeline
72
+ if __name__ == "__main__":
73
+ context = MyContext()
74
+ pipeline = Pipeline(
75
+ steps=[IncrementStep(), ProcessStep()],
76
+ name="ExamplePipeline"
77
+ )
78
+
79
+ final_context = pipeline.execute(context)
80
+ print(f"Final value: {final_context.value}, Processed: {final_context.is_processed}")
81
+ ```
@@ -0,0 +1,5 @@
1
+ from .pipeline import Pipeline
2
+ from .pipeline_step import PipelineStep
3
+ from .pipeline_context import PipelineContext
4
+
5
+ __all__ = ["PipelineStep", "PipelineContext", "Pipeline"]
@@ -0,0 +1,53 @@
1
+ import logging
2
+
3
+ from typing import List, Generic, Optional
4
+
5
+ from .pipeline_context import C
6
+ from .pipeline_step import PipelineStep
7
+
8
+
9
+ class Pipeline(Generic[C]):
10
+ def __init__(self, steps: List[PipelineStep[C]], name: Optional[str] = "PIPELINE",
11
+ logger: Optional[logging.Logger] = None):
12
+ """
13
+ Main junban pipeline class.
14
+
15
+ :param steps: Pipeline steps to be executed.
16
+ :param name: Name of the pipeline, defaults to "PIPELINE".
17
+ :param logger: Optional logger to log pipeline steps, defaults to None.
18
+ If no logger is provided, logs will be printed to stdout.
19
+ """
20
+ self.steps: List[PipelineStep[C]] = steps
21
+ self.name = name
22
+ self._log_info = lambda msg: self._log_info_func(msg, logger)
23
+ self._log_error = lambda msg: self._log_error_func(msg, logger)
24
+
25
+ @staticmethod
26
+ def _log_info_func(message: str, logger: logging.Logger = None):
27
+ if logger is None:
28
+ print(message)
29
+ else:
30
+ logger.info(message)
31
+
32
+ @staticmethod
33
+ def _log_error_func(message: str, logger: logging.Logger = None):
34
+ if logger is None:
35
+ print(message)
36
+ else:
37
+ logger.error(message)
38
+
39
+ def execute(self, context: C) -> C:
40
+ """ Run the pipeline steps with the given initial context."""
41
+ current_context = context
42
+ for step in self.steps:
43
+ try:
44
+ self._log_info(f"[{self.name}] {step.get_start_message()}")
45
+ current_context = step.run(current_context)
46
+ self._log_info(f"[{self.name}] {step.get_end_message()}")
47
+ except AssertionError as e:
48
+ self._log_error(f"[{self.name}] Assertion error in step {step.__class__.__name__}: {str(e)}")
49
+ raise
50
+ except Exception as e:
51
+ self._log_error(f"[{self.name}] Error in step {step.__class__.__name__}: {str(e)}")
52
+ raise
53
+ return current_context
@@ -0,0 +1,7 @@
1
+ from typing import TypeVar
2
+
3
+ class PipelineContext:
4
+ """ Large struct to hold pipeline context during execution """
5
+ pass
6
+
7
+ C = TypeVar("C", bound=PipelineContext)
@@ -0,0 +1,44 @@
1
+ from typing import Generic
2
+ from abc import ABC, abstractmethod
3
+
4
+ from .pipeline_context import C
5
+
6
+
7
+ class PipelineStep(ABC, Generic[C]):
8
+
9
+ @abstractmethod
10
+ def _check_entry_assumptions(self, context: C) -> bool:
11
+ """ You can use this method to check if the pipeline step can be executed.
12
+ Depending on your use case, you can use assert statements, raise exceptions, or return a boolean.
13
+ """
14
+ return True
15
+
16
+ @abstractmethod
17
+ def _check_exit_assumptions(self, context: C) -> bool:
18
+ """ You can use this method to check if the pipeline step executed successfully.
19
+ Depending on your use case, you can use assert statements, raise exceptions, or return a boolean.
20
+ """
21
+ return True
22
+
23
+ @abstractmethod
24
+ def get_start_message(self) -> str:
25
+ raise NotImplementedError
26
+
27
+ @abstractmethod
28
+ def get_end_message(self) -> str:
29
+ raise NotImplementedError
30
+
31
+ @abstractmethod
32
+ def _execute(self, context: C) -> C:
33
+ raise NotImplementedError
34
+
35
+ def run(self, context: C) -> C:
36
+ if not self._check_entry_assumptions(context):
37
+ assert False, "Entry assumptions not met"
38
+
39
+ context = self._execute(context)
40
+
41
+ if not self._check_exit_assumptions(context):
42
+ assert False, "Exit assumptions not met"
43
+
44
+ return context
@@ -0,0 +1,7 @@
1
+ Metadata-Version: 2.4
2
+ Name: junban
3
+ Version: 1.0.0
4
+ Summary: Junban – Simple Sequential Python Workflows
5
+ Requires-Python: >=3.11
6
+ License-File: LICENSE
7
+ Dynamic: license-file
@@ -0,0 +1,11 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ junban/__init__.py
5
+ junban/pipeline.py
6
+ junban/pipeline_context.py
7
+ junban/pipeline_step.py
8
+ junban.egg-info/PKG-INFO
9
+ junban.egg-info/SOURCES.txt
10
+ junban.egg-info/dependency_links.txt
11
+ junban.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ junban
@@ -0,0 +1,6 @@
1
+ [project]
2
+ name = "junban"
3
+ version = "1.0.0"
4
+ description = "Junban – Simple Sequential Python Workflows"
5
+ requires-python = ">=3.11"
6
+ dependencies = []
junban-1.0.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+