gpframe 0.0.2__tar.gz → 0.0.4__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 (49) hide show
  1. {gpframe-0.0.2/src/gpframe.egg-info → gpframe-0.0.4}/PKG-INFO +1 -1
  2. {gpframe-0.0.2 → gpframe-0.0.4}/pyproject.toml +1 -1
  3. gpframe-0.0.4/src/gpframe/__init__.py +142 -0
  4. gpframe-0.0.4/src/gpframe/api/builder.py +87 -0
  5. gpframe-0.0.4/src/gpframe/api/contexts.py +79 -0
  6. gpframe-0.0.4/src/gpframe/api/frame.py +50 -0
  7. gpframe-0.0.4/src/gpframe/api/outcome.py +23 -0
  8. gpframe-0.0.4/src/gpframe/impl/builder.py +364 -0
  9. gpframe-0.0.4/src/gpframe/impl/context/event.py +51 -0
  10. {gpframe-0.0.2 → gpframe-0.0.4}/src/gpframe/impl/context/routine.py +8 -3
  11. gpframe-0.0.4/src/gpframe/impl/frame.py +56 -0
  12. {gpframe-0.0.2 → gpframe-0.0.4}/src/gpframe/impl/handler/event.py +3 -2
  13. {gpframe-0.0.2 → gpframe-0.0.4}/src/gpframe/impl/handler/exception.py +9 -7
  14. {gpframe-0.0.2 → gpframe-0.0.4}/src/gpframe/impl/handler/redo.py +7 -5
  15. {gpframe-0.0.2 → gpframe-0.0.4}/src/gpframe/impl/handler/terminated.py +7 -8
  16. gpframe-0.0.4/src/gpframe/impl/lifecycle/__init__.py +8 -0
  17. gpframe-0.0.4/src/gpframe/impl/lifecycle/mod.py +133 -0
  18. gpframe-0.0.4/src/gpframe/impl/lifecycle/phase.py +133 -0
  19. {gpframe-0.0.2 → gpframe-0.0.4}/src/gpframe/impl/outcome.py +0 -25
  20. gpframe-0.0.2/src/gpframe/impl/execute/ansynchronize.py → gpframe-0.0.4/src/gpframe/impl/routine/asynchronous.py +2 -2
  21. {gpframe-0.0.2/src/gpframe/impl/execute → gpframe-0.0.4/src/gpframe/impl/routine}/base.py +4 -3
  22. {gpframe-0.0.2/src/gpframe/impl → gpframe-0.0.4/src/gpframe/impl/routine}/result.py +10 -8
  23. {gpframe-0.0.2/src/gpframe/impl/execute → gpframe-0.0.4/src/gpframe/impl/routine}/subprocess.py +2 -2
  24. gpframe-0.0.2/src/gpframe/impl/execute/synchronize.py → gpframe-0.0.4/src/gpframe/impl/routine/synchronous.py +2 -2
  25. {gpframe-0.0.2 → gpframe-0.0.4/src/gpframe.egg-info}/PKG-INFO +1 -1
  26. {gpframe-0.0.2 → gpframe-0.0.4}/src/gpframe.egg-info/SOURCES.txt +14 -12
  27. gpframe-0.0.2/src/gpframe/__init__.py +0 -65
  28. gpframe-0.0.2/src/gpframe/api/contexts.py +0 -220
  29. gpframe-0.0.2/src/gpframe/api/gpframe.py +0 -284
  30. gpframe-0.0.2/src/gpframe/api/outcome.py +0 -59
  31. gpframe-0.0.2/src/gpframe/api/result.py +0 -41
  32. gpframe-0.0.2/src/gpframe/impl/context/controller.py +0 -56
  33. gpframe-0.0.2/src/gpframe/impl/context/event.py +0 -50
  34. gpframe-0.0.2/src/gpframe/impl/frame.py +0 -492
  35. gpframe-0.0.2/src/gpframe/impl/state.py +0 -173
  36. {gpframe-0.0.2 → gpframe-0.0.4}/LICENSE +0 -0
  37. {gpframe-0.0.2 → gpframe-0.0.4}/README.md +0 -0
  38. {gpframe-0.0.2 → gpframe-0.0.4}/setup.cfg +0 -0
  39. {gpframe-0.0.2 → gpframe-0.0.4}/src/gpframe/api/__init__.py +0 -0
  40. {gpframe-0.0.2 → gpframe-0.0.4}/src/gpframe/impl/__init__.py +0 -0
  41. {gpframe-0.0.2 → gpframe-0.0.4}/src/gpframe/impl/context/__init__.py +0 -0
  42. {gpframe-0.0.2 → gpframe-0.0.4}/src/gpframe/impl/errors.py +0 -0
  43. {gpframe-0.0.2/src/gpframe/impl/execute → gpframe-0.0.4/src/gpframe/impl/handler}/__init__.py +0 -0
  44. {gpframe-0.0.2 → gpframe-0.0.4}/src/gpframe/impl/handler/errors.py +0 -0
  45. {gpframe-0.0.2/src/gpframe/impl/handler → gpframe-0.0.4/src/gpframe/impl/routine}/__init__.py +0 -0
  46. {gpframe-0.0.2/src/gpframe/impl/execute → gpframe-0.0.4/src/gpframe/impl/routine}/errors.py +0 -0
  47. {gpframe-0.0.2 → gpframe-0.0.4}/src/gpframe/impl/syncm.py +0 -0
  48. {gpframe-0.0.2 → gpframe-0.0.4}/src/gpframe.egg-info/dependency_links.txt +0 -0
  49. {gpframe-0.0.2 → gpframe-0.0.4}/src/gpframe.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gpframe
3
- Version: 0.0.2
3
+ Version: 0.0.4
4
4
  Summary: A general-purpose framework for routine execution with concurrency and event handling.
5
5
  Author: minoru_jp
6
6
  License: MIT License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "gpframe"
7
- version = "0.0.2"
7
+ version = "0.0.4"
8
8
  description = "A general-purpose framework for routine execution with concurrency and event handling."
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  requires-python = ">=3.10"
@@ -0,0 +1,142 @@
1
+ """
2
+ gpframe: A general-purpose framework for routine execution with concurrency and event handling.
3
+ ------------
4
+
5
+ Note
6
+ ---------------
7
+ This library is in an early stage of development.
8
+ It is generally unstable: documentation and tests are incomplete,
9
+ and the API may undergo breaking changes without notice.
10
+
11
+ Core Components
12
+ ---------------
13
+ - FrameBuilder (from .api.builder):
14
+ Factory function to obtain a FrameBuilderType.
15
+ Accepts a routine to be executed inside a Frame.
16
+ The routine can be synchronous or asynchronous.
17
+
18
+ - FrameBuilderType (from .api.builder):
19
+ API to configure the Frame name, logger, and handlers.
20
+ Calling FrameBuilderType.start() launches the Frame and returns a Frame object.
21
+
22
+ - Frame (from .api.frame):
23
+ Represents the entire lifecycle of a Frame.
24
+ Provides Frame.task for accessing the Frame's execution task.
25
+ Allows writing to the request message map via Frame.request.update().
26
+
27
+ - EventContext (from .api.contexts):
28
+ Allows writing to the event_message map through EventContext.event_message.update().
29
+
30
+ - RoutineContext (from .api.contexts):
31
+ Allows writing to the routine_message map through RoutineContext.routine_message.update().
32
+
33
+ - Outcome (from .api.outcome):
34
+ Passed to the terminated_callback after the Frame has finished (after on_close).
35
+ Provides read-only access to all message maps.
36
+ Each message map is a snapshot of its state at termination.
37
+
38
+
39
+ Message Maps
40
+ ------------
41
+ gpframe defines four synchronized message maps and one result container.
42
+ These maps are the core mechanism for communication between the Frame,
43
+ the routine, and event handlers.
44
+
45
+ 1. environment
46
+ - Purpose: Immutable configuration or contextual information.
47
+ - Access:
48
+ Read: Frame, EventContext, RoutineContext
49
+ Write: Frame (setup stage only)
50
+ - Example: constants, system configuration, resource identifiers.
51
+
52
+ 2. request
53
+ - Purpose: Incoming requests or instructions that affect routine behavior.
54
+ - Access:
55
+ Read: Frame, EventContext, RoutineContext
56
+ Write: Frame (via Frame.request.update())
57
+ - Example: runtime parameters, control flags.
58
+
59
+ 3. event_message
60
+ - Purpose: Event-driven updates produced by event handlers.
61
+ - Access:
62
+ Read: Frame, RoutineContext
63
+ Write: EventContext (via EventContext.event_message.update())
64
+ - Example: status events, log signals, external notifications.
65
+
66
+ 4. routine_message
67
+ - Purpose: Communication channel from the routine to other components.
68
+ - Access:
69
+ Read: Frame, EventContext
70
+ Write: RoutineContext (via RoutineContext.routine_message.update())
71
+ - Example: progress reports, intermediate results.
72
+
73
+ 5. routine_result
74
+ - Purpose: Result value of the routine execution.
75
+ - Access:
76
+ Read: EventContext.routine_result
77
+ Write: set internally by each routine execution
78
+ - Behavior:
79
+ Updated every time the routine finishes (success, error, or cancellation).
80
+ After the Frame terminates, the last value represents the final outcome.
81
+ - Special values:
82
+ NO_VALUE = not yet executed or failed
83
+
84
+ Lifecycle and Access Rules
85
+ --------------------------
86
+ - All maps are thread-safe (backed by SynchronizedMapReader/SynchronizedMapUpdater).
87
+ - During Frame execution, access is restricted according to context type.
88
+ - After Frame termination, direct access is invalid and raises TerminatedError.
89
+ To inspect final state, use Outcome which contains a snapshot of all maps.
90
+
91
+
92
+ Error Handling
93
+ --------------
94
+ - NO_VALUE (from .impl.routine.result):
95
+ Initial value of EventContext.routine_result.value.
96
+ Indicates that no routine result exists (not yet executed, exception raised, etc.).
97
+
98
+ - TerminatedError (from .impl.builder):
99
+ Raised when attempting to access message maps after a Frame has terminated.
100
+ In such cases, maps must be accessed via Outcome.
101
+
102
+ - FutureTimeoutError, ThreadCleanupTimeoutError (from .impl.routine.asynchronous):
103
+ Timeout-related errors for asynchronous routines and thread cleanup.
104
+
105
+ - SubprocessTimeoutError (from .impl.routine.subprocess):
106
+ Timeout error for subprocess routines.
107
+
108
+ - Throw (from .impl.handler.exception):
109
+ Exception wrapper for re-throwing errors without being wrapped as HandlerError.
110
+ Useful when propagating exceptions such as asyncio.CancelledError directly.
111
+
112
+ """
113
+
114
+ from .api.builder import FrameBuilder
115
+
116
+ from .api.builder import FrameBuilderType
117
+
118
+ from .api.frame import Frame
119
+
120
+ from .api.contexts import EventContext
121
+ from .api.contexts import RoutineContext
122
+
123
+ from .api.outcome import Outcome
124
+
125
+ from .impl.routine.result import NO_VALUE
126
+
127
+ from .impl.builder import TerminatedError
128
+
129
+ from .impl.routine.asynchronous import FutureTimeoutError, ThreadCleanupTimeoutError
130
+ from .impl.routine.subprocess import SubprocessTimeoutError
131
+
132
+ from .impl.handler.exception import Throw
133
+
134
+ __all__ = ("FrameBuilder", "FrameBuilderType",
135
+ "Frame",
136
+ "EventContext", "RoutineContext",
137
+ "Outcome",
138
+ "NO_VALUE",
139
+ "TerminatedError",
140
+ "FutureTimeoutError", "ThreadCleanupTimeoutError",
141
+ "SubprocessTimeoutError",
142
+ "Throw")
@@ -0,0 +1,87 @@
1
+
2
+ from __future__ import annotations
3
+
4
+ from abc import ABC, abstractmethod
5
+ from typing import TYPE_CHECKING, Generic, TypeVar
6
+
7
+ R = TypeVar("R")
8
+
9
+
10
+ if TYPE_CHECKING:
11
+ import logging
12
+
13
+ from ..impl.frame import Frame
14
+ from ..impl.builder import Routine
15
+ from ..impl.handler.event import EventHandler
16
+ from ..impl.handler.redo import RedoHandler
17
+ from ..impl.handler.exception import ExceptionHandler
18
+ from ..impl.handler.terminated import TerminatedHandler
19
+
20
+
21
+ def FrameBuilder(routine: Routine[R]) -> FrameBuilderType[R]:
22
+ from ..impl.builder import create_builder_role
23
+ role = create_builder_role(routine)
24
+ return role.interface
25
+
26
+
27
+ class FrameBuilderType(ABC, Generic[R]):
28
+ __slots__ = ()
29
+ @abstractmethod
30
+ def set_name(self, name: str) -> None:
31
+ ...
32
+
33
+ @abstractmethod
34
+ def set_logger(self, logger: logging.Logger):
35
+ ...
36
+
37
+ @abstractmethod
38
+ def set_environments(self, environments: dict):
39
+ ...
40
+
41
+ @abstractmethod
42
+ def set_requests(self, requests: dict):
43
+ ...
44
+
45
+ @abstractmethod
46
+ def set_routine_timeout(self, timeout: float | None) -> None:
47
+ ...
48
+
49
+ @abstractmethod
50
+ def set_cleanup_timeout(self, timeout: float | None) -> None:
51
+ ...
52
+
53
+ @abstractmethod
54
+ def start(self, *, as_subprocess: bool = False) -> Frame:
55
+ ...
56
+
57
+ @abstractmethod
58
+ def set_terminated_callback(self, handler: TerminatedHandler):
59
+ ...
60
+
61
+ @abstractmethod
62
+ def set_exception_handler(self, handler: ExceptionHandler):
63
+ ...
64
+
65
+ @abstractmethod
66
+ def set_redo_handler(self, handler: RedoHandler[R]) -> None:
67
+ ...
68
+
69
+ @abstractmethod
70
+ def set_on_open(self, handler: EventHandler[R]) -> None:
71
+ ...
72
+
73
+ @abstractmethod
74
+ def set_on_start(self, handler: EventHandler[R]) -> None:
75
+ ...
76
+
77
+ @abstractmethod
78
+ def set_on_end(self, handler: EventHandler[R]) -> None:
79
+ ...
80
+
81
+ @abstractmethod
82
+ def set_on_cancel(self, handler: EventHandler[R]) -> None:
83
+ ...
84
+
85
+ @abstractmethod
86
+ def set_on_close(self, handler: EventHandler[R]) -> None:
87
+ ...
@@ -0,0 +1,79 @@
1
+ from __future__ import annotations
2
+
3
+ from abc import ABC, abstractmethod
4
+ from typing import TYPE_CHECKING, Generic, TypeVar
5
+
6
+ R = TypeVar("R")
7
+
8
+ if TYPE_CHECKING:
9
+ from logging import Logger
10
+
11
+ from ..impl.routine.result import RoutineResult
12
+ from ..impl.syncm import SynchronizedMapReader, SynchronizedMapUpdater
13
+
14
+
15
+ class EventContext(ABC, Generic[R]):
16
+ __slots__ = ()
17
+ @property
18
+ @abstractmethod
19
+ def frame_name(self) -> str:
20
+ ...
21
+ @property
22
+ @abstractmethod
23
+ def logger(self) -> Logger:
24
+ ...
25
+ @property
26
+ @abstractmethod
27
+ def routine_in_subprocess(self) -> bool:
28
+ ...
29
+ @property
30
+ @abstractmethod
31
+ def environment(self) -> SynchronizedMapReader:
32
+ ...
33
+ @property
34
+ @abstractmethod
35
+ def request(self) -> SynchronizedMapReader:
36
+ ...
37
+ @property
38
+ @abstractmethod
39
+ def event_message(self) -> SynchronizedMapUpdater:
40
+ ...
41
+ @property
42
+ @abstractmethod
43
+ def routine_message(self) -> SynchronizedMapReader:
44
+ ...
45
+ @property
46
+ @abstractmethod
47
+ def routine_result(self) -> RoutineResult[R]:
48
+ ...
49
+
50
+ class RoutineContext(ABC):
51
+ __slots__ = ()
52
+ @property
53
+ @abstractmethod
54
+ def frame_name(self) -> str:
55
+ ...
56
+ @property
57
+ @abstractmethod
58
+ def logger_name(self) -> str:
59
+ ...
60
+ @property
61
+ @abstractmethod
62
+ def routine_in_subprocess(self) -> bool:
63
+ ...
64
+ @property
65
+ @abstractmethod
66
+ def environment(self) -> SynchronizedMapReader:
67
+ ...
68
+ @property
69
+ @abstractmethod
70
+ def request(self) -> SynchronizedMapReader:
71
+ ...
72
+ @property
73
+ @abstractmethod
74
+ def event_message(self) -> SynchronizedMapReader:
75
+ ...
76
+ @property
77
+ @abstractmethod
78
+ def routine_message(self) -> SynchronizedMapUpdater:
79
+ ...
@@ -0,0 +1,50 @@
1
+ from __future__ import annotations
2
+
3
+ from abc import ABC, abstractmethod
4
+ import asyncio
5
+ from logging import Logger
6
+ from typing import TYPE_CHECKING, Generic, TypeVar
7
+
8
+ if TYPE_CHECKING:
9
+ from ..impl.syncm import SynchronizedMapReader, SynchronizedMapUpdater
10
+
11
+ class Frame(ABC):
12
+ __slots__ = ()
13
+ @property
14
+ @abstractmethod
15
+ def frame_name(self) -> str:
16
+ ...
17
+ @property
18
+ @abstractmethod
19
+ def logger(self) -> Logger:
20
+ ...
21
+ @property
22
+ @abstractmethod
23
+ def routine_in_subprocess(self) -> bool:
24
+ ...
25
+ @property
26
+ @abstractmethod
27
+ def environment(self) -> SynchronizedMapReader:
28
+ ...
29
+ @property
30
+ @abstractmethod
31
+ def request(self) -> SynchronizedMapUpdater:
32
+ ...
33
+ @property
34
+ @abstractmethod
35
+ def event_message(self) -> SynchronizedMapReader:
36
+ ...
37
+ @property
38
+ @abstractmethod
39
+ def routine_message(self) -> SynchronizedMapReader:
40
+ ...
41
+
42
+ @abstractmethod
43
+ def request_stop_routine(self, *, kill: bool = False) -> None:
44
+ ...
45
+
46
+ @property
47
+ @abstractmethod
48
+ def task(self) -> asyncio.Task:
49
+ ...
50
+
@@ -0,0 +1,23 @@
1
+ from __future__ import annotations
2
+
3
+ from abc import ABC, abstractmethod
4
+ from typing import TYPE_CHECKING
5
+
6
+ if TYPE_CHECKING:
7
+ from types import MappingProxyType
8
+
9
+ class Outcome(ABC):
10
+ __slots__ = ()
11
+ @property
12
+ @abstractmethod
13
+ def requests(self) -> MappingProxyType:
14
+ ...
15
+ @property
16
+ @abstractmethod
17
+ def event_messages(self) -> MappingProxyType:
18
+ ...
19
+ @property
20
+ @abstractmethod
21
+ def routine_messages(self) -> MappingProxyType:
22
+ ...
23
+