gpframe


Namegpframe JSON
Version 0.0.30 PyPI version JSON
download
home_pageNone
SummaryA general-purpose framework for routine execution with concurrency and event handling.
upload_time2025-09-12 22:27:56
maintainerNone
docs_urlNone
authorminoru_jp
requires_python>=3.10
licenseMIT License Copyright (c) 2025 minoru Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords general-purpose framework concurrency async subprocess event lifecycle context outcome exception-handling wrapper skeleton task workflow execution state-management
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # gpframe

A general-purpose framework for managing routine execution with concurrency, event handling, and lifecycle control.

Note: This project is in an early stage. It currently provides implementation only, with no tests yet.

[![PyPI version](https://img.shields.io/pypi/v/gpframe.svg)](https://pypi.org/project/gpframe/)

install
```
pip install gpframe
```

---
Here is a transcription of the documentation from `__init__.py`.


gpframe: A general-purpose framework for routine execution with concurrency and event handling.
------------

Note
---------------
This library is in an early stage of development.
It is generally unstable: documentation and tests are incomplete,
and the API may undergo breaking changes without notice.


Core Components
---------------
- FrameBuilder (from .api.builder):
  Factory function to obtain a FrameBuilderType.  
  Accepts a routine to be executed inside a Frame.  
  The routine can be synchronous or asynchronous.

- FrameBuilderType (from .api.builder):
  API to configure the Frame name, logger, and handlers.  
  Calling FrameBuilderType.start() launches the Frame and returns a Frame object.

- Frame (from .api.frame):
  Represents the entire lifecycle of a Frame.  
  Provides Frame.task for accessing the Frame's execution task.  
  Allows writing to the request message map via Frame.request.update().

- EventContext (from .api.contexts):
  Allows writing to the event_message map through EventContext.event_message.update().

- RoutineContext (from .api.contexts):
  Allows writing to the routine_message map through RoutineContext.routine_message.update().

- Outcome (from .api.outcome):
  Passed to the on_terminated handler after the Frame has finished (after on_close).  
  Provides read-only access to all message maps.  
  Each message map is a snapshot of its state at termination.


Message Updaters / Readers
--------------------------
gpframe defines four synchronized message registries and one result container.  
These registries are the core mechanism for communication between the Frame, the routine, and event handlers.  
Each registry is exposed as a MessageReader (read-only) or MessageUpdater (read-write), depending on context.

1. environment
   - Purpose: Immutable configuration or contextual information.
   - Access:
       Read: Frame, EventContext, RoutineContext
       Write: Frame (setup stage only)
   - Example: constants, system configuration, resource identifiers.

2. request
   - Purpose: Incoming requests or instructions that affect routine behavior.
   - Access:
       Read: Frame, EventContext, RoutineContext
       Write: Frame (via Frame.request.update())
   - Example: runtime parameters, control flags.

3. event_message
   - Purpose: Event-driven updates produced by event handlers.
   - Access:
       Read: Frame, RoutineContext
       Write: EventContext (via EventContext.event_message.update())
   - Example: status events, log signals, external notifications.

4. routine_message
   - Purpose: Communication channel from the routine to other components.
   - Access:
       Read: Frame, EventContext
       Write: RoutineContext (via RoutineContext.routine_message.update())
   - Example: progress reports, intermediate results.

5. routine_result
   - Purpose: Result value of the routine execution.
   - Access:
       Read: EventContext.routine_result
       Write: set internally by each routine execution
   - Behavior:
       Updated every time the routine finishes (success, error, or cancellation).
       After the Frame terminates, the last value represents the final outcome.
   - Special values:
       NO_VALUE = not yet executed, canceled, interrupted, or failed.

MessageReader API
-----------------
A read-only view of a registry.

- geta(key, default=...) -> Any  
  Retrieve a value by key without type checking.  
  If missing and no default given, raises KeyError.

- getd(key, typ: type[T], default: D) -> T | D  
  Retrieve a value by key and validate its type.  
  If missing, return the given default (which may have a different type).

- get(key, typ: type[T]) -> T  
  Retrieve a value by key and validate its type.  
  Raises KeyError if missing, TypeError if mismatched.


MessageUpdater API
------------------
A read-write view of a registry.

- geta(key, default=...) -> Any  
  Retrieve a value by key without type checking.  
  If missing and no default given, raises KeyError.

- getd(key, typ: type[T], default: D) -> T | D  
  Retrieve a value by key and validate its type.  
  If missing, return the given default (which may have a different type).

- get(key, typ: type[T]) -> T  
  Retrieve a value by key and validate its type.  
  Raises KeyError if missing, TypeError if mismatched.

- update(key, value) -> T  
  Store a value under the given key, returning it.

- apply(key, typ: type[T], fn: Callable[[T], T], default=...) -> T  
  Atomically update a value using a function.  
  If missing, the default value is used (must be compatible with `typ`):

      ctx.event_message.apply("count", int, lambda c: c + 1, default=0)

- remove(key, default=None) -> Any  
  Remove a key and return its value.  
  If absent, return the given default.


String Conversion Utilities
---------------------------
Both `MessageReader` and `MessageUpdater` provide the following helpers to
convert string values stored in the registry.

Common Behavior

- If the key does not exist and no default is provided, a `KeyError` is raised.  
- If a default value is provided and its type already matches the *converted* type of the method
  (e.g., `int` for `string_to_int`, `float` for `string_to_float`, `bool` for `string_to_bool`, `str` for `string`),  
  then the default is returned directly without going through `prep` or `valid`.  
- Otherwise, the stored value (or the default) is first converted to `str` and processed.

- `prep` may be given as either a single callable `(str -> str)` or a tuple of such callables.  
  If a tuple is provided, each function is applied in order to the string before conversion.  
- After conversion, the resulting value is passed to `valid` (if applicable).  
  If `valid` returns `False`, a `ValueError` is raised.

Methods

- string(key, default=..., *, prep=..., valid=...) -> str  
  Retrieve the value by key, convert it with `str(...)`, and return it.  
  This acts as a string-typed getter regardless of the stored type.  
  The string may be preprocessed by `prep` and must satisfy `valid`.

- string_to_int(key, default=..., *, prep=..., valid=...) -> int  
  Retrieve a string by key and convert it to an integer.  
  Supports standard prefixes (0x, 0o, 0b) via `int(string, 0)`.  
  Preprocessing and validation are applied as described above.

- string_to_float(key, default=..., *, prep=..., valid=...) -> float  
  Retrieve a string by key and convert it to a float.  
  Preprocessing and validation are applied as described above.

- string_to_bool(key, default=..., *, prep=..., true=(), false=()) -> bool  
  Retrieve a string by key and convert it to a boolean.  
  Preprocessing is applied as described above.  
  If neither `true` nor `false` sets are provided, non-empty strings evaluate to `True`.  
  If only `true` is given, returns `True` if the string matches, `False` otherwise.  
  If only `false` is given, returns `False` if the string matches, `True` otherwise.  
  If both are given, raises `ValueError` if the string does not match either.


       
Lifecycle and Access Rules
--------------------------
- All maps are thread-safe (backed by SynchronizedMapReader/SynchronizedMapUpdater).
- During Frame execution, access is restricted according to context type.
- After Frame termination, direct access is invalid and raises TerminatedError.
  To inspect final state, use Outcome which contains a snapshot of all maps.

  
Lifecycle Overview
------------------

1. on_open
   - Called first at the very beginning.

2. on_start
   - Called before routine execution.

3. routine
   - The main processing logic.

4. on_end
   - Called immediately after routine finishes.

5. on_redo
   - Called right after on_end.
   - If it returns True, the loop continues with on_start → routine → on_end → on_redo.
   - If it returns False, the loop breaks and termination begins.

6. on_cancel  (shielded)
   - Called when asyncio.CancelledError is raised.

7. on_close  (shielded)
   - Always called at the end, regardless of success, failure, or cancellation.

8. on_terminated  (shielded)
   - Always called after on_close.


Control Flow (Summary)
----------------------
on_open
→ (loop) [ on_start → routine → on_end → on_redo ]
    ├─ on_redo == True → loop continues
    └─ on_redo == False → loop ends
→ finally: on_close → on_terminated

※ If asyncio.CancelledError is raised during execution,
   on_cancel will be called first, then finally on_close → on_terminated.

   
Error Handling
--------------
- If an exception occurs in any handler (on_* / routine / on_redo),
  it is passed to exception_handler.

  - exception_handler is shielded.

- If exception_handler returns False, the exception is re-raised (propagates upward).

- Regardless of exceptions, on_close and on_terminated are always executed.

- NO_VALUE (from .impl.routine.result):
  Initial value of EventContext.routine_result.value.  
  Indicates that no routine result exists (not yet executed, exception raised, etc.).

- TerminatedError (from .impl.builder):
  Raised when attempting to access message maps after a Frame has terminated.  
  In such cases, maps must be accessed via Outcome.

- FutureTimeoutError, ThreadCleanupTimeoutError (from .impl.routine.asynchronous):
  Timeout-related errors for asynchronous routines and thread cleanup.

- SubprocessTimeoutError (from .impl.routine.subprocess):
  Timeout error for subprocess routines.

- Throw (from .impl.handler.exception):
  Exception wrapper for re-throwing errors without being wrapped as HandlerError.  
  Useful when propagating exceptions such as asyncio.CancelledError directly.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "gpframe",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "general-purpose, framework, concurrency, async, subprocess, event, lifecycle, context, outcome, exception-handling, wrapper, skeleton, task, workflow, execution, state-management",
    "author": "minoru_jp",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/7f/8b/aacb6d74d7e9601d8765e2cae236f1056d7148716a51635dc352ec6b0763/gpframe-0.0.30.tar.gz",
    "platform": null,
    "description": "# gpframe\r\n\r\nA general-purpose framework for managing routine execution with concurrency, event handling, and lifecycle control.\r\n\r\nNote: This project is in an early stage. It currently provides implementation only, with no tests yet.\r\n\r\n[![PyPI version](https://img.shields.io/pypi/v/gpframe.svg)](https://pypi.org/project/gpframe/)\r\n\r\ninstall\r\n```\r\npip install gpframe\r\n```\r\n\r\n---\r\nHere is a transcription of the documentation from `__init__.py`.\r\n\r\n\r\ngpframe: A general-purpose framework for routine execution with concurrency and event handling.\r\n------------\r\n\r\nNote\r\n---------------\r\nThis library is in an early stage of development.\r\nIt is generally unstable: documentation and tests are incomplete,\r\nand the API may undergo breaking changes without notice.\r\n\r\n\r\nCore Components\r\n---------------\r\n- FrameBuilder (from .api.builder):\r\n  Factory function to obtain a FrameBuilderType.  \r\n  Accepts a routine to be executed inside a Frame.  \r\n  The routine can be synchronous or asynchronous.\r\n\r\n- FrameBuilderType (from .api.builder):\r\n  API to configure the Frame name, logger, and handlers.  \r\n  Calling FrameBuilderType.start() launches the Frame and returns a Frame object.\r\n\r\n- Frame (from .api.frame):\r\n  Represents the entire lifecycle of a Frame.  \r\n  Provides Frame.task for accessing the Frame's execution task.  \r\n  Allows writing to the request message map via Frame.request.update().\r\n\r\n- EventContext (from .api.contexts):\r\n  Allows writing to the event_message map through EventContext.event_message.update().\r\n\r\n- RoutineContext (from .api.contexts):\r\n  Allows writing to the routine_message map through RoutineContext.routine_message.update().\r\n\r\n- Outcome (from .api.outcome):\r\n  Passed to the on_terminated handler after the Frame has finished (after on_close).  \r\n  Provides read-only access to all message maps.  \r\n  Each message map is a snapshot of its state at termination.\r\n\r\n\r\nMessage Updaters / Readers\r\n--------------------------\r\ngpframe defines four synchronized message registries and one result container.  \r\nThese registries are the core mechanism for communication between the Frame, the routine, and event handlers.  \r\nEach registry is exposed as a MessageReader (read-only) or MessageUpdater (read-write), depending on context.\r\n\r\n1. environment\r\n   - Purpose: Immutable configuration or contextual information.\r\n   - Access:\r\n       Read: Frame, EventContext, RoutineContext\r\n       Write: Frame (setup stage only)\r\n   - Example: constants, system configuration, resource identifiers.\r\n\r\n2. request\r\n   - Purpose: Incoming requests or instructions that affect routine behavior.\r\n   - Access:\r\n       Read: Frame, EventContext, RoutineContext\r\n       Write: Frame (via Frame.request.update())\r\n   - Example: runtime parameters, control flags.\r\n\r\n3. event_message\r\n   - Purpose: Event-driven updates produced by event handlers.\r\n   - Access:\r\n       Read: Frame, RoutineContext\r\n       Write: EventContext (via EventContext.event_message.update())\r\n   - Example: status events, log signals, external notifications.\r\n\r\n4. routine_message\r\n   - Purpose: Communication channel from the routine to other components.\r\n   - Access:\r\n       Read: Frame, EventContext\r\n       Write: RoutineContext (via RoutineContext.routine_message.update())\r\n   - Example: progress reports, intermediate results.\r\n\r\n5. routine_result\r\n   - Purpose: Result value of the routine execution.\r\n   - Access:\r\n       Read: EventContext.routine_result\r\n       Write: set internally by each routine execution\r\n   - Behavior:\r\n       Updated every time the routine finishes (success, error, or cancellation).\r\n       After the Frame terminates, the last value represents the final outcome.\r\n   - Special values:\r\n       NO_VALUE = not yet executed, canceled, interrupted, or failed.\r\n\r\nMessageReader API\r\n-----------------\r\nA read-only view of a registry.\r\n\r\n- geta(key, default=...) -> Any  \r\n  Retrieve a value by key without type checking.  \r\n  If missing and no default given, raises KeyError.\r\n\r\n- getd(key, typ: type[T], default: D) -> T | D  \r\n  Retrieve a value by key and validate its type.  \r\n  If missing, return the given default (which may have a different type).\r\n\r\n- get(key, typ: type[T]) -> T  \r\n  Retrieve a value by key and validate its type.  \r\n  Raises KeyError if missing, TypeError if mismatched.\r\n\r\n\r\nMessageUpdater API\r\n------------------\r\nA read-write view of a registry.\r\n\r\n- geta(key, default=...) -> Any  \r\n  Retrieve a value by key without type checking.  \r\n  If missing and no default given, raises KeyError.\r\n\r\n- getd(key, typ: type[T], default: D) -> T | D  \r\n  Retrieve a value by key and validate its type.  \r\n  If missing, return the given default (which may have a different type).\r\n\r\n- get(key, typ: type[T]) -> T  \r\n  Retrieve a value by key and validate its type.  \r\n  Raises KeyError if missing, TypeError if mismatched.\r\n\r\n- update(key, value) -> T  \r\n  Store a value under the given key, returning it.\r\n\r\n- apply(key, typ: type[T], fn: Callable[[T], T], default=...) -> T  \r\n  Atomically update a value using a function.  \r\n  If missing, the default value is used (must be compatible with `typ`):\r\n\r\n      ctx.event_message.apply(\"count\", int, lambda c: c + 1, default=0)\r\n\r\n- remove(key, default=None) -> Any  \r\n  Remove a key and return its value.  \r\n  If absent, return the given default.\r\n\r\n\r\nString Conversion Utilities\r\n---------------------------\r\nBoth `MessageReader` and `MessageUpdater` provide the following helpers to\r\nconvert string values stored in the registry.\r\n\r\nCommon Behavior\r\n\r\n- If the key does not exist and no default is provided, a `KeyError` is raised.  \r\n- If a default value is provided and its type already matches the *converted* type of the method\r\n  (e.g., `int` for `string_to_int`, `float` for `string_to_float`, `bool` for `string_to_bool`, `str` for `string`),  \r\n  then the default is returned directly without going through `prep` or `valid`.  \r\n- Otherwise, the stored value (or the default) is first converted to `str` and processed.\r\n\r\n- `prep` may be given as either a single callable `(str -> str)` or a tuple of such callables.  \r\n  If a tuple is provided, each function is applied in order to the string before conversion.  \r\n- After conversion, the resulting value is passed to `valid` (if applicable).  \r\n  If `valid` returns `False`, a `ValueError` is raised.\r\n\r\nMethods\r\n\r\n- string(key, default=..., *, prep=..., valid=...) -> str  \r\n  Retrieve the value by key, convert it with `str(...)`, and return it.  \r\n  This acts as a string-typed getter regardless of the stored type.  \r\n  The string may be preprocessed by `prep` and must satisfy `valid`.\r\n\r\n- string_to_int(key, default=..., *, prep=..., valid=...) -> int  \r\n  Retrieve a string by key and convert it to an integer.  \r\n  Supports standard prefixes (0x, 0o, 0b) via `int(string, 0)`.  \r\n  Preprocessing and validation are applied as described above.\r\n\r\n- string_to_float(key, default=..., *, prep=..., valid=...) -> float  \r\n  Retrieve a string by key and convert it to a float.  \r\n  Preprocessing and validation are applied as described above.\r\n\r\n- string_to_bool(key, default=..., *, prep=..., true=(), false=()) -> bool  \r\n  Retrieve a string by key and convert it to a boolean.  \r\n  Preprocessing is applied as described above.  \r\n  If neither `true` nor `false` sets are provided, non-empty strings evaluate to `True`.  \r\n  If only `true` is given, returns `True` if the string matches, `False` otherwise.  \r\n  If only `false` is given, returns `False` if the string matches, `True` otherwise.  \r\n  If both are given, raises `ValueError` if the string does not match either.\r\n\r\n\r\n       \r\nLifecycle and Access Rules\r\n--------------------------\r\n- All maps are thread-safe (backed by SynchronizedMapReader/SynchronizedMapUpdater).\r\n- During Frame execution, access is restricted according to context type.\r\n- After Frame termination, direct access is invalid and raises TerminatedError.\r\n  To inspect final state, use Outcome which contains a snapshot of all maps.\r\n\r\n  \r\nLifecycle Overview\r\n------------------\r\n\r\n1. on_open\r\n   - Called first at the very beginning.\r\n\r\n2. on_start\r\n   - Called before routine execution.\r\n\r\n3. routine\r\n   - The main processing logic.\r\n\r\n4. on_end\r\n   - Called immediately after routine finishes.\r\n\r\n5. on_redo\r\n   - Called right after on_end.\r\n   - If it returns True, the loop continues with on_start \u2192 routine \u2192 on_end \u2192 on_redo.\r\n   - If it returns False, the loop breaks and termination begins.\r\n\r\n6. on_cancel  (shielded)\r\n   - Called when asyncio.CancelledError is raised.\r\n\r\n7. on_close  (shielded)\r\n   - Always called at the end, regardless of success, failure, or cancellation.\r\n\r\n8. on_terminated  (shielded)\r\n   - Always called after on_close.\r\n\r\n\r\nControl Flow (Summary)\r\n----------------------\r\non_open\r\n\u2192 (loop) [ on_start \u2192 routine \u2192 on_end \u2192 on_redo ]\r\n    \u251c\u2500 on_redo == True \u2192 loop continues\r\n    \u2514\u2500 on_redo == False \u2192 loop ends\r\n\u2192 finally: on_close \u2192 on_terminated\r\n\r\n\u203b If asyncio.CancelledError is raised during execution,\r\n   on_cancel will be called first, then finally on_close \u2192 on_terminated.\r\n\r\n   \r\nError Handling\r\n--------------\r\n- If an exception occurs in any handler (on_* / routine / on_redo),\r\n  it is passed to exception_handler.\r\n\r\n  - exception_handler is shielded.\r\n\r\n- If exception_handler returns False, the exception is re-raised (propagates upward).\r\n\r\n- Regardless of exceptions, on_close and on_terminated are always executed.\r\n\r\n- NO_VALUE (from .impl.routine.result):\r\n  Initial value of EventContext.routine_result.value.  \r\n  Indicates that no routine result exists (not yet executed, exception raised, etc.).\r\n\r\n- TerminatedError (from .impl.builder):\r\n  Raised when attempting to access message maps after a Frame has terminated.  \r\n  In such cases, maps must be accessed via Outcome.\r\n\r\n- FutureTimeoutError, ThreadCleanupTimeoutError (from .impl.routine.asynchronous):\r\n  Timeout-related errors for asynchronous routines and thread cleanup.\r\n\r\n- SubprocessTimeoutError (from .impl.routine.subprocess):\r\n  Timeout error for subprocess routines.\r\n\r\n- Throw (from .impl.handler.exception):\r\n  Exception wrapper for re-throwing errors without being wrapped as HandlerError.  \r\n  Useful when propagating exceptions such as asyncio.CancelledError directly.\r\n",
    "bugtrack_url": null,
    "license": "MIT License\r\n        \r\n        Copyright (c) 2025 minoru\r\n        \r\n        Permission is hereby granted, free of charge, to any person obtaining a copy\r\n        of this software and associated documentation files (the \"Software\"), to deal\r\n        in the Software without restriction, including without limitation the rights\r\n        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n        copies of the Software, and to permit persons to whom the Software is\r\n        furnished to do so, subject to the following conditions:\r\n        \r\n        The above copyright notice and this permission notice shall be included in all\r\n        copies or substantial portions of the Software.\r\n        \r\n        THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n        SOFTWARE.",
    "summary": "A general-purpose framework for routine execution with concurrency and event handling.",
    "version": "0.0.30",
    "project_urls": {
        "Homepage": "https://github.com/minoru-jp/gpframe",
        "Issues": "https://github.com/minoru-jp/gpframe/issues",
        "Source": "https://github.com/minoru-jp/gpframe"
    },
    "split_keywords": [
        "general-purpose",
        " framework",
        " concurrency",
        " async",
        " subprocess",
        " event",
        " lifecycle",
        " context",
        " outcome",
        " exception-handling",
        " wrapper",
        " skeleton",
        " task",
        " workflow",
        " execution",
        " state-management"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "fadd8fb95bf8fd0cb314bb5ca6e8c996d40b60e286f03453243fe23c9d23ecb8",
                "md5": "740cdc694a9a02deb0c040d9e8db1aef",
                "sha256": "233ae37f93d8dd049697e6bf9cd049926eedc541f94979483fd80dac5a772de2"
            },
            "downloads": -1,
            "filename": "gpframe-0.0.30-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "740cdc694a9a02deb0c040d9e8db1aef",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 33969,
            "upload_time": "2025-09-12T22:27:55",
            "upload_time_iso_8601": "2025-09-12T22:27:55.666901Z",
            "url": "https://files.pythonhosted.org/packages/fa/dd/8fb95bf8fd0cb314bb5ca6e8c996d40b60e286f03453243fe23c9d23ecb8/gpframe-0.0.30-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "7f8baacb6d74d7e9601d8765e2cae236f1056d7148716a51635dc352ec6b0763",
                "md5": "f391a09be1f9d3e97b6b7b3bfae9c3ec",
                "sha256": "997e2ba1a12c24d5b2f95f6a0c0786831b36291c7d3000dedd9d5c9d83c2e64d"
            },
            "downloads": -1,
            "filename": "gpframe-0.0.30.tar.gz",
            "has_sig": false,
            "md5_digest": "f391a09be1f9d3e97b6b7b3bfae9c3ec",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 24977,
            "upload_time": "2025-09-12T22:27:56",
            "upload_time_iso_8601": "2025-09-12T22:27:56.875040Z",
            "url": "https://files.pythonhosted.org/packages/7f/8b/aacb6d74d7e9601d8765e2cae236f1056d7148716a51635dc352ec6b0763/gpframe-0.0.30.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-09-12 22:27:56",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "minoru-jp",
    "github_project": "gpframe",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "gpframe"
}
        
Elapsed time: 2.22715s