Highly into type-safe Python code?
runtime_generics is a niche Python library that allows you to reuse type arguments explicitly passed at runtime to generic classes before instantiation.
The library does four things:
- exposes utilities that allow to inspect C3-linearized MROs of runtime generics
and type-check them with variance support:
get_mro()
,type_check()
; - makes it possible to retrieve the type arguments passed to the generic class at runtime
before the class was instantiated:
get_type_arguments()
,get_alias()
; - offers facilities to find how parent classes are parametrized (
e.g. if
Foo[T]
inherits fromDict[str, T]
, finds thatDict[str, int]
is a parent forFoo[int]
):get_parents()
; - given a parametrized generic class (generic alias),
makes every class method use generic alias
cls
instead of the origin class (unless decorated with@no_alias
).
3.12+ (PEP 695 syntax):
from __future__ import annotations
import io
from typing import TYPE_CHECKING
from runtime_generics import get_alias, get_type_arguments, runtime_generic, type_check
if TYPE_CHECKING:
from typing import IO, Literal, overload
@runtime_generic
class IOWrapper[T: str | bytes]:
data_type: type[T]
def __init__(self, stream: IO[T]) -> None:
(self.data_type,) = get_type_arguments(self)
self.stream = stream
if TYPE_CHECKING:
@overload
def is_binary(self: IOWrapper[bytes]) -> Literal[True]: ...
@overload
def is_binary(self: IOWrapper[str]) -> Literal[False]: ...
def is_binary(self) -> bool:
# alternatively here: `self.data_type == bytes`
return type_check(self, IOWrapper[bytes])
def __repr__(self) -> str:
return f"<{get_alias(self)} object at ...>"
my_binary_data = IOWrapper[bytes](io.BytesIO(b"foo"))
assert my_binary_data.data_type is bytes
assert my_binary_data.is_binary()
assert repr(IOWrapper[str](io.StringIO())) == "<__main__.IOWrapper[str] object at ...>"
3.8+:
from __future__ import annotations
import io
from typing import TYPE_CHECKING, Generic, TypeVar
from runtime_generics import get_alias, get_type_arguments, runtime_generic, type_check
if TYPE_CHECKING:
from typing import IO, Literal, overload
T = TypeVar("T", str, bytes)
@runtime_generic
class IOWrapper(Generic[T]):
data_type: type[T]
def __init__(self, stream: IO[T]) -> None:
(self.data_type,) = get_type_arguments(self)
self.stream = stream
if TYPE_CHECKING:
@overload
def is_binary(self: IOWrapper[bytes]) -> Literal[True]: ...
@overload
def is_binary(self: IOWrapper[str]) -> Literal[False]: ...
def is_binary(self) -> bool:
# alternatively here: `self.data_type == bytes`
return type_check(self, IOWrapper[bytes])
def __repr__(self) -> str:
return f"<{get_alias(self)} object at ...>"
my_binary_data = IOWrapper[bytes](io.BytesIO(b"foo"))
assert my_binary_data.data_type is bytes
assert my_binary_data.is_binary()
assert repr(IOWrapper[str](io.StringIO())) == "<__main__.IOWrapper[str] object at ...>"
Available as part of the Tidelift Subscription. This project and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use. Learn more here. |
---|
To report a security vulnerability, please use the
Tidelift security contact.
Tidelift will coordinate the fix and disclosure.
You might simply install it with pip:
pip install runtime-generics
If you use Poetry, then you might want to run:
poetry add runtime-generics
Note
If you use Windows, it is highly recommended to complete the installation in the way presented below through WSL2.
-
Fork the runtime_generics repository on GitHub.
-
Install Poetry.
Poetry is an amazing tool for managing dependencies & virtual environments, building packages and publishing them. You might use pipx to install it globally (recommended):pipx install poetry
If you encounter any problems, refer to the official documentation for the most up-to-date installation instructions.
Be sure to have Python 3.8 installed—if you use pyenv, simply run:
pyenv install 3.8
-
Clone your fork locally and install dependencies.
git clone https://github.com/your-username/runtime_generics path/to/runtime_generics cd path/to/runtime_generics poetry env use $(cat .python-version) poetry install
Next up, simply activate the virtual environment and install pre-commit hooks:
poetry shell pre-commit install
For more information on how to contribute, check out CONTRIBUTING.md.
Always happy to accept contributions! ❤️
© Copyright by Bartosz Sławecki (@bswck).
This software is licensed under the terms of MIT License.