tools to make typing more consistent in older versions of python3, and access generic variables at runtime
Project description
RT-Generic
RT-Generic is a typed python module to make accessing the actual runtime types from a generic module more straight forward. It defines a base class RTGeneric which initializes each subclass (at subclass definition) with a mapping from (Class, TypeVar) to the actual type eventually assigned to that TypeVar. This permits me, for example, when creating class GenClass[T,U,V](RTGeneric): to write code which will behave appropriately for when I eventually create class SubClass1(GenClass[int, float, dict[int, float]]): and class SubClass2(GenClass[tuple[str], list[float], dict[tuple[str], list[float]]]):. Repository, PyPI.
The process has 4 steps minimum (with a few optional steps along the way):
- Import RTGeneric from rt_generic. Importing * also brings three Literal types which can be useful.
- all brings in
- class RTGeneric with class methods tv2type (converts TypeVar to actual type), generic_true (tests if Literal type means "True" or "Yes"), generic_false (tests if Literal type means "No" or "False"), and generic_lit_values (which gives a tuple of all literal values a Literal type represents).
- TrueT, a Literal type for True.
- FalseT, a Literal type for False.
- TypeErrorT, a Literal type RTGeneric functions return when an error occured
- function has_anyTypeVar(cls) -> bool, which can be used to check if all types in a class have been defined
- all brings in
- (Optionally) from rt_generic.type_setup import * for consistent types across python versions
- For all python versions supported by rt_generic, ensures that these are defined:
- TypeAlias, GenericAlias, LiteralGenericAlias
- TypeVar, ClassVar, Generic, Any, Literal, NoneType
- Self
- Union, Tuple, Dict, List, TYPE_CHECKING
- get_args, get_origin, get_original_bases
- For all python versions supported by rt_generic, ensures that these are defined:
- Declare your generic base class, based on Generic and RTGeneric
- Either
class MyClass[T,U,V](RTGeneric):, (python 3.11 or higher) or
T = TypeVar('T') U = TypeVar('U') V = TypeVar('V') class MyClass(RTGeneric, Generic[T,U,V]) :
- Either
- Add self.tv2type (or cls.tv2type) calls in your base class where you need behavior to depend on actual types.
- Just to be clear, self.tv2type(MyClass,T) from an instance method, and cls.tv2type(MyClass,T) from a class method.
- You must specify your base class name for the
cls2argument to tv2type, since you want to resolve TypeVars specified here. For example, using self.class will attempt to resolve them according to the subclass, where there are no remaining TypeVars. - This returns a type, so for example you might have
self.tv2type(MyClass, U) == List[int], but notself.tv2type(MyClass, U) == [1,2]. - You can use Literal types to pass in values when you speciallize your class
- To turn behavior on and off, use actual types
TrueTorFalseT, and check in your code withself.generic_true(MyClass, U) - To set values to be used when you speciallize, for example, try using the actual type
Literal["Hello World"], and in your codeprint(f"Custom Message: {self.generic_lit_values(self.tv2type(MyClass,V))[0]}")(note index to select an element from the tuple returned bygeneric_lit_values).
- To turn behavior on and off, use actual types
- (Optionally) add a
def __init_subclass__(cls, **kwargs) : super().__init_subclass(kwargs) if not has_anyTypeVars(cls) : ... # do your own setup, for example instantiate class ... # variables of types represented by typevars, ... # now that you know what those types are
- (Optionally) declare subclasses which partially assign types to generics
- For example,
class MyClass2[T](MyClass[list[T], dict[str,T], Literal["mode2"]]):. Note that in this casetv2type(MyClass2,T) != tv2type(MyClass,T).
- For example,
- Declare subclasses which fully assign types (possibly subclasses of other subclasses).
- This is required because RTGeneric works by initializing subclasses, and an anonymous subclass (as in
a = MyClass[int,int,dict[str, float]]()) does not get initalized. - instead do
class MyFinalClass(MyClass[int,int,dict[str, float]]) : pass # or class MyFinalClass(MyClass2[str]]) : pass a = MyFinalClass()
- This is required because RTGeneric works by initializing subclasses, and an anonymous subclass (as in
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rt_generic-0.2.3.tar.gz.
File metadata
- Download URL: rt_generic-0.2.3.tar.gz
- Upload date:
- Size: 4.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bc3561034eb8a79b518d31d485e7cf32c0066cc308eab3581bf468db5f4b5490
|
|
| MD5 |
cb1370c8131681992e1c4372f0702053
|
|
| BLAKE2b-256 |
32453e854a1560d06a2d95113d9804ff8e5fbf874bb50e138096d8e6c8468a97
|
File details
Details for the file rt_generic-0.2.3-py3-none-any.whl.
File metadata
- Download URL: rt_generic-0.2.3-py3-none-any.whl
- Upload date:
- Size: 9.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
111cd699dcf5004a7b7e478c9963c1164ba903993b17d845b548cc41ee58d19d
|
|
| MD5 |
06b259222b7f4f6e9a35b0c6e650bc68
|
|
| BLAKE2b-256 |
cb83020fc3b0d7256a448c08bd35a2707859cf4f9510f43c0cf5d150b4011f92
|