<div align="center">
# runtypecheck
Fast, pragmatic runtime type checking for Python 3.10+: a configurable `@typecheck` decorator (and class wrapper) featuring structural `Protocol` validation, constrained & bound `TypeVar` handling, iterable sampling, lazy iterator inspection, async support, custom validators, and a weak-reference LRU cache.
</div>
---
## Why?
Static type checkers (mypy, pyright, pyre) are invaluable before runtime. This library adds inexpensive runtime assurance at the *boundaries* where static analysis may be weak: plugin entry points, notebook experiments, dynamically constructed data, tests, or external inputs. Design goals:
* Pragmatic: unknown / future typing forms are accepted by default (configurable fallback policy).
* Fast: caches resolved hints & origins, samples containers, and short‑circuits early.
* Focused: only one decorator + a small config surface; no metaclass trickery.
* Extensible: drop-in custom validators with a tiny decorator.
---
## Quick Start
```python
from typecheck import typecheck, TypeCheckError
@typecheck()
def greet(name: str, times: int = 1) -> str:
return ' '.join([f'Hello {name}!'] * times)
print(greet('Alice', 2)) # OK
try:
greet('Bob', 'x') # type: ignore
except TypeCheckError as e:
print('Caught:', e)
```
Apply to a class to wrap all public methods (plus `__init__` / `__call__`).
```python
@typecheck()
class Calc:
def add(self, a: int, b: int) -> int: return a + b
Calc().add(1, 2)
```
---
## Feature Matrix
| Category | Support Summary |
|----------|-----------------|
| Primitives / builtins | Standard `isinstance` semantics |
| Container generics | `list`, `tuple` (fixed & variadic), `set`, `frozenset`, `dict`, `deque` + ABCs (`Sequence`, `Mapping`, `Iterable`, `Iterator`) |
| Collections sampling | Validates up to N elements (configurable) unless deep mode |
| Unions & Optional | Full branch validation with aggregated mismatch context |
| `Literal[...]` | Membership check |
| `Callable` | Light structural check: positional arity & simple annotation compatibility |
| `Type[Cls]` | Class identity / subclass acceptance |
| `Final` / `ClassVar` | Inner type validated |
| Structural `Protocol` | Attributes & method signature compatibility (positional params & annotations + return) |
| `TypeVar` | Constraint / bound enforcement + per-call consistent binding |
| `Annotated[T, ...]` | Treated as `T` (metadata ignored) |
| `TypedDict` | Required keys + per-key value validation; extra keys allowed (PEP 589 semantics) |
| `NewType` | Validated against its underlying supertype |
| `Never` | Always error if a runtime value is supplied |
| `NoReturn` | Accepted for parameter context (enforced on returns elsewhere) |
| `LiteralString` (3.11+) | Treated as `str` (best effort) |
| `TypeGuard[T]` | Ensures runtime bool result |
| Forward refs | Permissive or strict (config) |
| Async functions | Wrapper preserves `async` and validates awaited result |
| Lazy iterables | Non-length iterables sampled via `itertools.tee` |
| Deep vs sample | `deep=True` overrides sampling; otherwise first *N* elements |
| Custom validators | `@register_validator(cls)` mapping exact type -> predicate |
| Runtime disable | `TYPECHECK_DISABLED=1` env var skips decoration logic |
Unsupported / unrecognized constructs (e.g., advanced future typing forms) fall back to acceptance unless `config.fallback_policy` is set to `warn` or `error`.
---
## Installation
```bash
pip install runtypecheck
```
Python 3.10–3.13 (tested). Zero runtime dependencies.
---
## Usage Examples
### Collections & Sampling
```python
from typecheck import typecheck, TypeCheckError
@typecheck(sample=3) # only first 3 elements of large list validated
def head_sum(values: list[int]) -> int:
return sum(values[:3])
@typecheck(deep=True) # validate every element
def full_sum(values: list[int]) -> int:
return sum(values)
head_sum([1,2,3,'x',5]) # OK (sampling hides later mismatch) # type: ignore
try:
full_sum([1,2,3,'x',5]) # type: ignore
except TypeCheckError: pass
```
### Protocols & TypeVars
```python
from typing import Protocol, TypeVar
from typecheck import typecheck, TypeCheckError
class SupportsClose(Protocol):
def close(self) -> None: ...
@typecheck()
def shutdown(r: SupportsClose) -> None: r.close()
T = TypeVar('T', int, str)
@typecheck()
def echo(x: T) -> T: return x
```
### Custom Validator
```python
from typecheck import register_validator, typecheck, TypeCheckError
class PositiveInt(int):
pass
@register_validator(PositiveInt)
def _validate_positive(v, t): return isinstance(v, int) and v >= 0
@typecheck()
def square(x: PositiveInt) -> int: return x * x
```
### Async
```python
import asyncio
from typecheck import typecheck
@typecheck()
async def fetch(n: int) -> int:
return n * 2
asyncio.run(fetch(5))
```
### Strict Modes & Method Selection
Wrap only selected methods or ignore specific ones:
```python
from typecheck import typecheck
@typecheck(include=["process", "finalize"], exclude=["finalize"]) # only "process" gets wrapped
class Job:
def process(self, x: int) -> int: return x
def finalize(self, x: int) -> int: return x # excluded
def helper(self, x: int) -> int: return x # not in include list
class Service:
@typecheck(ignore=True) # marker to skip when class decorated
def fast_path(self, x: int) -> int: return x
@typecheck()
def strict_path(self, x: int) -> int: return x
Service = typecheck()(Service)
```
Parameters:
* `include=[...]`: Only listed methods (plus `__init__` / `__call__`).
* `exclude=[...]`: Remove methods after inclusion filtering.
* Per-method `@typecheck(ignore=True)`: Skip even under class decorator.
```python
from typecheck import typecheck, config
config.strict_mode = True # missing parameter annotations raise
config.strict_return_mode = True # missing return annotations raise
```
---
## Configuration (`typecheck.config`)
| Attribute | Default | Effect |
|-----------|---------|--------|
| `sample_size` | 5 | Default element sample for collections / iterables |
| `strict_mode` | False | Enforce all parameters annotated |
| `strict_return_mode` | False | Enforce return annotation presence (independent of `strict_mode`) |
| `deep_checking` | False | If True, decorator defaults to deep validation when `deep` not passed |
| `lazy_iterable_validation` | True | Sample first N elements of single‑pass iterables via `itertools.tee` |
| `fallback_policy` | "silent" | Behavior for unsupported constructs: silent / warn / error |
| `forward_ref_policy` | "permissive" | Unresolved forward refs: permissive accept or strict error |
Per‑call overrides: `@typecheck(sample=10)`, `@typecheck(deep=True)`, `@typecheck(strict=True)`, etc.
Reset to defaults:
```python
from typecheck import config
config.reset()
```
---
## Fallback Policy
If a construct is unrecognized, `_check_type` accepts it by default (policy `silent`). Change behavior:
```python
from typecheck import config
config.set_fallback_policy("warn") # or "error"
```
`warn` emits a `RuntimeWarning`; `error` raises immediately.
---
## Error Messages
Errors raise `TypeCheckError` with a concise diagnostic:
```
Type mismatch for parameter 'age' in function 'greet': expected int, got str ('twenty-five')
```
Return mismatches use: `Return value type mismatch in function 'func': expected list[int], got dict (...)`.
---
## Performance Notes
* Cached: resolved `get_type_hints` + origin/args via weak LRU caches.
* Sampling: limits deep traversal cost for large structures & streams.
* Iterables: lazy path avoids exhausting one‑shot generators.
* Overhead on simple primitive calls is typically a handful of microseconds (implementation detail; measure in your environment).
Disable entirely with an environment variable:
```bash
TYPECHECK_DISABLED=1 python your_app.py
```
---
## Custom Validators API
```python
from typecheck import register_validator
@register_validator(MyType)
def validate(value, expected_type) -> bool:
# return True / False or raise TypeCheckError for custom message
...
```
Validators run before built‑in generic origin handlers.
---
## Weak LRU Cache Utility
`typecheck.weak_lru.lru_cache(maxsize=..., typed=False)` behaves like `functools.lru_cache` but stores per‑instance caches for methods in a `WeakKeyDictionary` so instances can be GC’d.
```python
from typecheck import weak_lru
@weak_lru.lru_cache(maxsize=256)
def fib(n: int) -> int:
return n if n < 2 else fib(n-1)+fib(n-2)
```
Use `.cache_info()` / `.cache_clear()` same as stdlib.
---
## Advanced Topics
* Deep vs Sampled: `@typecheck(deep=True)` enforces full traversal; otherwise first `sample_size` (config or decorator arg) elements validated.
* Lazy Iterables: When `lazy_iterable_validation` is True and object lacks `__len__`, the library samples via `itertools.tee` without consuming the original iterator.
* Protocol Enumeration: Methods, properties, classmethods, staticmethods, and annotated attributes all counted as required members.
* TypeVar Binding: A fresh context per function call enforces consistent multi-parameter binding (subtype-compatible reuse accepted).
* TypeGuard: Treated as `bool` sanity gate.
---
## Testing
The project ships with a comprehensive pytest suite (async, protocols, lazy iterables, custom validators, strict returns, weak LRU). Run:
```bash
pytest --cov=src/typecheck --cov-report=term-missing
```
---
## Roadmap (Abridged)
* Finer-grained Callable variance & keyword kind checking
* Optional stricter Protocol variance rules
* Configurable error formatter hook
* Extended TypedDict total / optional key strictness flags
* Richer metadata usage for `Annotated`
---
## Packaging & Type Information
The distribution includes a `py.typed` marker so static type checkers (mypy, pyright) can consume inline type hints.
Supported Python versions: 3.10, 3.11, 3.12, 3.13.
Partially handled (best-effort) constructs: `LiteralString` (treated as `str`), `Annotated` (metadata ignored). Unsupported advanced forms like `ParamSpec`, `Concatenate`, `Unpack`, `Required` / `NotRequired`, `Self` currently fall back per the fallback policy.
---
## License
AGPL-3.0-or-later. See `LICENSE`.
Rationale: AGPL ensures improvements to the runtime validation mechanics remain available to the community even when
used over a network (a common deployment style for frameworks and services). This license choice is intentional and
will not be changed or re-licensed under a more permissive variant.
---
## Cheat Sheet
| Want | Use |
|------|-----|
| Enforce parameter annotations globally | `config.strict_mode = True` |
| Enforce return annotations too | `config.strict_return_mode = True` |
| Disable sampling for a call | `@typecheck(deep=True)` |
| Increase sampling globally | `config.set_sample_size(10)` |
| Custom validator | `@register_validator(MyType)` |
| Skip runtime cost (env) | `TYPECHECK_DISABLED=1` |
| Validate generator lazily | leave `config.lazy_iterable_validation = True` |
| Strict on one function only | `@typecheck(strict=True)` |
---
Happy checking!
Raw data
{
"_id": null,
"home_page": null,
"name": "runtypecheck",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "typecheck, type-checking, runtime, decorator, validation, typing, annotations",
"author": null,
"author_email": "Oliver Kleinke <oliver.kleinke@c-01a.de>",
"download_url": "https://files.pythonhosted.org/packages/07/b2/8b2997c75def226a7858de9e5df09186fa623d4bed73ee7cb70bbaf861d3/runtypecheck-0.1.0.tar.gz",
"platform": null,
"description": "<div align=\"center\">\n\n# runtypecheck\n\nFast, pragmatic runtime type checking for Python 3.10+: a configurable `@typecheck` decorator (and class wrapper) featuring structural `Protocol` validation, constrained & bound `TypeVar` handling, iterable sampling, lazy iterator inspection, async support, custom validators, and a weak-reference LRU cache.\n\n</div>\n\n---\n\n## Why?\n\nStatic type checkers (mypy, pyright, pyre) are invaluable before runtime. This library adds inexpensive runtime assurance at the *boundaries* where static analysis may be weak: plugin entry points, notebook experiments, dynamically constructed data, tests, or external inputs. Design goals:\n\n* Pragmatic: unknown / future typing forms are accepted by default (configurable fallback policy).\n* Fast: caches resolved hints & origins, samples containers, and short\u2011circuits early.\n* Focused: only one decorator + a small config surface; no metaclass trickery.\n* Extensible: drop-in custom validators with a tiny decorator.\n\n---\n## Quick Start\n\n```python\nfrom typecheck import typecheck, TypeCheckError\n\n@typecheck()\ndef greet(name: str, times: int = 1) -> str:\n return ' '.join([f'Hello {name}!'] * times)\n\nprint(greet('Alice', 2)) # OK\ntry:\n greet('Bob', 'x') # type: ignore\nexcept TypeCheckError as e:\n print('Caught:', e)\n```\n\nApply to a class to wrap all public methods (plus `__init__` / `__call__`).\n\n```python\n@typecheck()\nclass Calc:\n def add(self, a: int, b: int) -> int: return a + b\n\nCalc().add(1, 2)\n```\n\n---\n## Feature Matrix\n\n| Category | Support Summary |\n|----------|-----------------|\n| Primitives / builtins | Standard `isinstance` semantics |\n| Container generics | `list`, `tuple` (fixed & variadic), `set`, `frozenset`, `dict`, `deque` + ABCs (`Sequence`, `Mapping`, `Iterable`, `Iterator`) |\n| Collections sampling | Validates up to N elements (configurable) unless deep mode |\n| Unions & Optional | Full branch validation with aggregated mismatch context |\n| `Literal[...]` | Membership check |\n| `Callable` | Light structural check: positional arity & simple annotation compatibility |\n| `Type[Cls]` | Class identity / subclass acceptance |\n| `Final` / `ClassVar` | Inner type validated |\n| Structural `Protocol` | Attributes & method signature compatibility (positional params & annotations + return) |\n| `TypeVar` | Constraint / bound enforcement + per-call consistent binding |\n| `Annotated[T, ...]` | Treated as `T` (metadata ignored) |\n| `TypedDict` | Required keys + per-key value validation; extra keys allowed (PEP 589 semantics) |\n| `NewType` | Validated against its underlying supertype |\n| `Never` | Always error if a runtime value is supplied |\n| `NoReturn` | Accepted for parameter context (enforced on returns elsewhere) |\n| `LiteralString` (3.11+) | Treated as `str` (best effort) |\n| `TypeGuard[T]` | Ensures runtime bool result |\n| Forward refs | Permissive or strict (config) |\n| Async functions | Wrapper preserves `async` and validates awaited result |\n| Lazy iterables | Non-length iterables sampled via `itertools.tee` |\n| Deep vs sample | `deep=True` overrides sampling; otherwise first *N* elements |\n| Custom validators | `@register_validator(cls)` mapping exact type -> predicate |\n| Runtime disable | `TYPECHECK_DISABLED=1` env var skips decoration logic |\n\nUnsupported / unrecognized constructs (e.g., advanced future typing forms) fall back to acceptance unless `config.fallback_policy` is set to `warn` or `error`.\n\n---\n## Installation\n\n```bash\npip install runtypecheck\n```\n\nPython 3.10\u20133.13 (tested). Zero runtime dependencies.\n\n---\n## Usage Examples\n\n### Collections & Sampling\n```python\nfrom typecheck import typecheck, TypeCheckError\n\n@typecheck(sample=3) # only first 3 elements of large list validated\ndef head_sum(values: list[int]) -> int:\n return sum(values[:3])\n\n@typecheck(deep=True) # validate every element\ndef full_sum(values: list[int]) -> int:\n return sum(values)\n\nhead_sum([1,2,3,'x',5]) # OK (sampling hides later mismatch) # type: ignore\ntry:\n full_sum([1,2,3,'x',5]) # type: ignore\nexcept TypeCheckError: pass\n```\n\n### Protocols & TypeVars\n```python\nfrom typing import Protocol, TypeVar\nfrom typecheck import typecheck, TypeCheckError\n\nclass SupportsClose(Protocol):\n def close(self) -> None: ...\n\n@typecheck()\ndef shutdown(r: SupportsClose) -> None: r.close()\n\nT = TypeVar('T', int, str)\n@typecheck()\ndef echo(x: T) -> T: return x\n```\n\n### Custom Validator\n```python\nfrom typecheck import register_validator, typecheck, TypeCheckError\n\nclass PositiveInt(int):\n pass\n\n@register_validator(PositiveInt)\ndef _validate_positive(v, t): return isinstance(v, int) and v >= 0\n\n@typecheck()\ndef square(x: PositiveInt) -> int: return x * x\n```\n\n### Async\n```python\nimport asyncio\nfrom typecheck import typecheck\n\n@typecheck()\nasync def fetch(n: int) -> int:\n return n * 2\n\nasyncio.run(fetch(5))\n```\n\n### Strict Modes & Method Selection\nWrap only selected methods or ignore specific ones:\n\n```python\nfrom typecheck import typecheck\n\n@typecheck(include=[\"process\", \"finalize\"], exclude=[\"finalize\"]) # only \"process\" gets wrapped\nclass Job:\n def process(self, x: int) -> int: return x\n def finalize(self, x: int) -> int: return x # excluded\n def helper(self, x: int) -> int: return x # not in include list\n\nclass Service:\n @typecheck(ignore=True) # marker to skip when class decorated\n def fast_path(self, x: int) -> int: return x\n @typecheck()\n def strict_path(self, x: int) -> int: return x\n\nService = typecheck()(Service)\n```\n\nParameters:\n* `include=[...]`: Only listed methods (plus `__init__` / `__call__`).\n* `exclude=[...]`: Remove methods after inclusion filtering.\n* Per-method `@typecheck(ignore=True)`: Skip even under class decorator.\n\n```python\nfrom typecheck import typecheck, config\n\nconfig.strict_mode = True # missing parameter annotations raise\nconfig.strict_return_mode = True # missing return annotations raise\n```\n\n---\n## Configuration (`typecheck.config`)\n\n| Attribute | Default | Effect |\n|-----------|---------|--------|\n| `sample_size` | 5 | Default element sample for collections / iterables |\n| `strict_mode` | False | Enforce all parameters annotated |\n| `strict_return_mode` | False | Enforce return annotation presence (independent of `strict_mode`) |\n| `deep_checking` | False | If True, decorator defaults to deep validation when `deep` not passed |\n| `lazy_iterable_validation` | True | Sample first N elements of single\u2011pass iterables via `itertools.tee` |\n| `fallback_policy` | \"silent\" | Behavior for unsupported constructs: silent / warn / error |\n| `forward_ref_policy` | \"permissive\" | Unresolved forward refs: permissive accept or strict error |\n\nPer\u2011call overrides: `@typecheck(sample=10)`, `@typecheck(deep=True)`, `@typecheck(strict=True)`, etc.\n\nReset to defaults:\n```python\nfrom typecheck import config\nconfig.reset()\n```\n\n---\n## Fallback Policy\n\nIf a construct is unrecognized, `_check_type` accepts it by default (policy `silent`). Change behavior:\n\n```python\nfrom typecheck import config\nconfig.set_fallback_policy(\"warn\") # or \"error\"\n```\n\n`warn` emits a `RuntimeWarning`; `error` raises immediately.\n\n---\n## Error Messages\n\nErrors raise `TypeCheckError` with a concise diagnostic:\n\n```\nType mismatch for parameter 'age' in function 'greet': expected int, got str ('twenty-five')\n```\n\nReturn mismatches use: `Return value type mismatch in function 'func': expected list[int], got dict (...)`.\n\n---\n## Performance Notes\n\n* Cached: resolved `get_type_hints` + origin/args via weak LRU caches.\n* Sampling: limits deep traversal cost for large structures & streams.\n* Iterables: lazy path avoids exhausting one\u2011shot generators.\n* Overhead on simple primitive calls is typically a handful of microseconds (implementation detail; measure in your environment).\n\nDisable entirely with an environment variable:\n\n```bash\nTYPECHECK_DISABLED=1 python your_app.py\n```\n\n---\n## Custom Validators API\n\n```python\nfrom typecheck import register_validator\n\n@register_validator(MyType)\ndef validate(value, expected_type) -> bool:\n # return True / False or raise TypeCheckError for custom message\n ...\n```\n\nValidators run before built\u2011in generic origin handlers.\n\n---\n## Weak LRU Cache Utility\n\n`typecheck.weak_lru.lru_cache(maxsize=..., typed=False)` behaves like `functools.lru_cache` but stores per\u2011instance caches for methods in a `WeakKeyDictionary` so instances can be GC\u2019d.\n\n```python\nfrom typecheck import weak_lru\n\n@weak_lru.lru_cache(maxsize=256)\ndef fib(n: int) -> int:\n return n if n < 2 else fib(n-1)+fib(n-2)\n```\n\nUse `.cache_info()` / `.cache_clear()` same as stdlib.\n\n---\n## Advanced Topics\n\n* Deep vs Sampled: `@typecheck(deep=True)` enforces full traversal; otherwise first `sample_size` (config or decorator arg) elements validated.\n* Lazy Iterables: When `lazy_iterable_validation` is True and object lacks `__len__`, the library samples via `itertools.tee` without consuming the original iterator.\n* Protocol Enumeration: Methods, properties, classmethods, staticmethods, and annotated attributes all counted as required members.\n* TypeVar Binding: A fresh context per function call enforces consistent multi-parameter binding (subtype-compatible reuse accepted).\n* TypeGuard: Treated as `bool` sanity gate.\n\n---\n## Testing\n\nThe project ships with a comprehensive pytest suite (async, protocols, lazy iterables, custom validators, strict returns, weak LRU). Run:\n\n```bash\npytest --cov=src/typecheck --cov-report=term-missing\n```\n\n---\n## Roadmap (Abridged)\n\n* Finer-grained Callable variance & keyword kind checking\n* Optional stricter Protocol variance rules\n* Configurable error formatter hook\n* Extended TypedDict total / optional key strictness flags\n* Richer metadata usage for `Annotated`\n\n---\n## Packaging & Type Information\n\nThe distribution includes a `py.typed` marker so static type checkers (mypy, pyright) can consume inline type hints.\n\nSupported Python versions: 3.10, 3.11, 3.12, 3.13.\n\nPartially handled (best-effort) constructs: `LiteralString` (treated as `str`), `Annotated` (metadata ignored). Unsupported advanced forms like `ParamSpec`, `Concatenate`, `Unpack`, `Required` / `NotRequired`, `Self` currently fall back per the fallback policy.\n\n---\n## License\n\nAGPL-3.0-or-later. See `LICENSE`.\n\nRationale: AGPL ensures improvements to the runtime validation mechanics remain available to the community even when\nused over a network (a common deployment style for frameworks and services). This license choice is intentional and\nwill not be changed or re-licensed under a more permissive variant.\n\n---\n## Cheat Sheet\n\n| Want | Use |\n|------|-----|\n| Enforce parameter annotations globally | `config.strict_mode = True` |\n| Enforce return annotations too | `config.strict_return_mode = True` |\n| Disable sampling for a call | `@typecheck(deep=True)` |\n| Increase sampling globally | `config.set_sample_size(10)` |\n| Custom validator | `@register_validator(MyType)` |\n| Skip runtime cost (env) | `TYPECHECK_DISABLED=1` |\n| Validate generator lazily | leave `config.lazy_iterable_validation = True` |\n| Strict on one function only | `@typecheck(strict=True)` |\n\n---\nHappy checking!\n",
"bugtrack_url": null,
"license": null,
"summary": "Runtime type checking decorator for Python functions and classes",
"version": "0.1.0",
"project_urls": {
"Source": "https://github.com/okleinke/runtypecheck/"
},
"split_keywords": [
"typecheck",
" type-checking",
" runtime",
" decorator",
" validation",
" typing",
" annotations"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "8426924fa401483b508af61585f77fb748b0c0aaa69d2371e4d16bd0322a96ee",
"md5": "704500a28374c65db9accf9f5aab8aa6",
"sha256": "113820fb7c2f1777b08fda8c04af5b53d57b524e0014b6f9cf075704f1d75cff"
},
"downloads": -1,
"filename": "runtypecheck-0.1.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "704500a28374c65db9accf9f5aab8aa6",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 36570,
"upload_time": "2025-08-17T15:39:32",
"upload_time_iso_8601": "2025-08-17T15:39:32.436584Z",
"url": "https://files.pythonhosted.org/packages/84/26/924fa401483b508af61585f77fb748b0c0aaa69d2371e4d16bd0322a96ee/runtypecheck-0.1.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "07b28b2997c75def226a7858de9e5df09186fa623d4bed73ee7cb70bbaf861d3",
"md5": "eb05d67749b41c9fd1b048707c8004b6",
"sha256": "a6ccfc931e9aa127ce7e68728d17a3cbb518d06cf8ef89b51c619bda74d9ff00"
},
"downloads": -1,
"filename": "runtypecheck-0.1.0.tar.gz",
"has_sig": false,
"md5_digest": "eb05d67749b41c9fd1b048707c8004b6",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 48004,
"upload_time": "2025-08-17T15:39:34",
"upload_time_iso_8601": "2025-08-17T15:39:34.005763Z",
"url": "https://files.pythonhosted.org/packages/07/b2/8b2997c75def226a7858de9e5df09186fa623d4bed73ee7cb70bbaf861d3/runtypecheck-0.1.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-17 15:39:34",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "okleinke",
"github_project": "runtypecheck",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "runtypecheck"
}