Name | python-generics JSON |
Version |
0.2.3
JSON |
| download |
home_page | None |
Summary | A package to determine the values of generic classes through instances or subclasses |
upload_time | 2024-10-14 06:43:06 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.9 |
license | MIT |
keywords |
generics
python
|
VCS |
|
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# Python-Generics
![Unittests status badge](https://github.com/Hochfrequenz/python-generics/workflows/Unittests/badge.svg)
![Coverage status badge](https://github.com/Hochfrequenz/python-generics/workflows/Coverage/badge.svg)
![Linting status badge](https://github.com/Hochfrequenz/python-generics/workflows/Linting/badge.svg)
![Black status badge](https://github.com/Hochfrequenz/python-generics/workflows/Formatting/badge.svg)
Ever wondered how to do something like this?
```python
from typing import Generic, TypeVar
T = TypeVar("T")
class MySuperClass(Generic[T]):
def get_my_type(self) -> type[T]:
return T # This does not work
class MySubType(MySuperClass[str]):
def use_my_type(self):
my_type = self.get_my_type() # This should return str
assert isinstance("Hello", my_type)
```
This package provides functionalities to resolve this issue i.e. to
determine the values of generic type variables in Python.
As of now, it only supports two functions: `get_type_vars` and `get_filled_type`.
These functions work also with pydantic generic models (only tested with pydantic > v2.3.0).
They also work with [PEP 695](https://peps.python.org/pep-0695/) generic types.
The package has no dependencies itself.
## Installation
The package is [available on PyPI](https://pypi.org/project/python-generics/):
```bash
pip install python-generics
```
## How to use (in your own application)
The `get_type_vars` function returns a tuple of all type variables for a given generic type. The `TypeVar`s are
determined by `Generic` if the type is a subclass of `Generic`. Otherwise, they are determined by the indexed
supertypes (the order of the returned tuple is the lexicographical in the list of the supertypes).
```python
from typing import Generic, TypeVar
from generics import get_type_vars
T = TypeVar("T")
U = TypeVar("U")
V = TypeVar("V")
class A(Generic[T, U]):
pass
class B(A[T, U], Generic[U, T]):
pass
class C(B[T, U], A[T, V]):
pass
assert get_type_vars(A) == (T, U)
assert get_type_vars(B) == (U, T)
assert get_type_vars(C) == (T, U, V)
```
The `get_filled_type` function determines for a single `TypeVar` the value if defined somewhere.
To determine the value, you have to pass a type or an instance of a type that is a subclass of a generic type
of which you want to determine the value of the `TypeVar`.
Instead of supplying the `TypeVar` itself, you can define the integer position of the `TypeVar` in the tuple of
`TypeVar`s of the generic type.
```python
from typing import Generic, TypeVar
from generics import get_filled_type
T = TypeVar("T")
U = TypeVar("U")
V = TypeVar("V")
class A(Generic[T, U]):
pass
class B(A[str, U]):
pass
assert get_filled_type(A[str, U], A, T) == str
assert get_filled_type(B[int](), A, 0) == str
```
The `get_filled_type` function is especially useful if you have generic super types in which you want to determine
the value of a `TypeVar` inside methods.
```python
from typing import Generic, TypeVar, Any
from generics import get_filled_type
T = TypeVar("T")
class MySuperType(Generic[T]):
def get_type(self) -> Any:
return get_filled_type(self, MySuperType, 0)
class MySubType(MySuperType[str]):
pass
assert MySubType().get_type() == str
```
## Limitations
Due to how generics are implemented in Python, it is not possible to
determine the value of a `TypeVar` inside the constructor. This would require
some stack trace analysis and is currently not implemented in this project.
However, for most scenarios there is an easy workaround for this.
What does not work:
```python
from generics import get_filled_type
class MySuperType[T]:
def __init__(self):
self.my_type = get_filled_type(self, MySuperType, 0)
# This will raise a TypeError with something like
# "The value of the TypeVar is undefined"
_ = MySuperType[str]()
```
But instead, you can do this:
```python
from generics import get_filled_type
class MySuperType[T]:
def __init__(self):
self._my_type: type[T] | None = None
@property
def my_type(self) -> type[T]:
if self._my_type is None:
self._my_type = get_filled_type(self, MySuperType, 0)
return self._my_type
instance = MySuperType[str]()
assert instance.my_type is str
```
Note that the property will only resolve _after_ the constructor has been called i.e. the
object has been created. You cannot use it inside the constructor.
## How to use this Repository on Your Machine (as a developer)
Follow the instructions in our [Python template repository](https://github.com/Hochfrequenz/python_template_repository#how-to-use-this-repository-on-your-machine).
## Contribute
You are very welcome to contribute to this template repository by opening a pull request against the main branch.
Raw data
{
"_id": null,
"home_page": null,
"name": "python-generics",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "generics, python",
"author": null,
"author_email": "Hochfrequenz Unternehmensberatung GmbH <info@hochfrequenz.de>",
"download_url": "https://files.pythonhosted.org/packages/a9/fd/63a19568c103cfb8fa8c193f162ba5d5e50fc0ac98d8ca8925fe02536a0c/python_generics-0.2.3.tar.gz",
"platform": null,
"description": "# Python-Generics\n\n![Unittests status badge](https://github.com/Hochfrequenz/python-generics/workflows/Unittests/badge.svg)\n![Coverage status badge](https://github.com/Hochfrequenz/python-generics/workflows/Coverage/badge.svg)\n![Linting status badge](https://github.com/Hochfrequenz/python-generics/workflows/Linting/badge.svg)\n![Black status badge](https://github.com/Hochfrequenz/python-generics/workflows/Formatting/badge.svg)\n\nEver wondered how to do something like this?\n \n```python\nfrom typing import Generic, TypeVar\n\nT = TypeVar(\"T\")\n\nclass MySuperClass(Generic[T]):\n def get_my_type(self) -> type[T]:\n return T # This does not work\n\nclass MySubType(MySuperClass[str]):\n def use_my_type(self):\n my_type = self.get_my_type() # This should return str\n assert isinstance(\"Hello\", my_type)\n```\n\nThis package provides functionalities to resolve this issue i.e. to\ndetermine the values of generic type variables in Python.\nAs of now, it only supports two functions: `get_type_vars` and `get_filled_type`.\nThese functions work also with pydantic generic models (only tested with pydantic > v2.3.0).\nThey also work with [PEP 695](https://peps.python.org/pep-0695/) generic types.\n\nThe package has no dependencies itself.\n\n## Installation\nThe package is [available on PyPI](https://pypi.org/project/python-generics/):\n```bash\npip install python-generics\n```\n\n## How to use (in your own application)\n\nThe `get_type_vars` function returns a tuple of all type variables for a given generic type. The `TypeVar`s are\ndetermined by `Generic` if the type is a subclass of `Generic`. Otherwise, they are determined by the indexed\nsupertypes (the order of the returned tuple is the lexicographical in the list of the supertypes).\n\n```python\nfrom typing import Generic, TypeVar\nfrom generics import get_type_vars\n\nT = TypeVar(\"T\")\nU = TypeVar(\"U\")\nV = TypeVar(\"V\")\n\nclass A(Generic[T, U]):\n pass\n\nclass B(A[T, U], Generic[U, T]):\n pass\n\nclass C(B[T, U], A[T, V]):\n pass\n\nassert get_type_vars(A) == (T, U)\nassert get_type_vars(B) == (U, T)\nassert get_type_vars(C) == (T, U, V)\n```\n\nThe `get_filled_type` function determines for a single `TypeVar` the value if defined somewhere.\nTo determine the value, you have to pass a type or an instance of a type that is a subclass of a generic type\nof which you want to determine the value of the `TypeVar`.\n\nInstead of supplying the `TypeVar` itself, you can define the integer position of the `TypeVar` in the tuple of\n`TypeVar`s of the generic type.\n\n```python\nfrom typing import Generic, TypeVar\nfrom generics import get_filled_type\n\nT = TypeVar(\"T\")\nU = TypeVar(\"U\")\nV = TypeVar(\"V\")\n\nclass A(Generic[T, U]):\n pass\n\nclass B(A[str, U]):\n pass\n\nassert get_filled_type(A[str, U], A, T) == str\nassert get_filled_type(B[int](), A, 0) == str\n```\n\nThe `get_filled_type` function is especially useful if you have generic super types in which you want to determine\nthe value of a `TypeVar` inside methods.\n\n```python\nfrom typing import Generic, TypeVar, Any\nfrom generics import get_filled_type\n\nT = TypeVar(\"T\")\n\nclass MySuperType(Generic[T]):\n def get_type(self) -> Any:\n return get_filled_type(self, MySuperType, 0)\n\nclass MySubType(MySuperType[str]):\n pass\n\nassert MySubType().get_type() == str\n```\n\n## Limitations\nDue to how generics are implemented in Python, it is not possible to \ndetermine the value of a `TypeVar` inside the constructor. This would require\nsome stack trace analysis and is currently not implemented in this project.\nHowever, for most scenarios there is an easy workaround for this.\n\nWhat does not work:\n```python\nfrom generics import get_filled_type\n\nclass MySuperType[T]:\n def __init__(self):\n self.my_type = get_filled_type(self, MySuperType, 0)\n # This will raise a TypeError with something like\n # \"The value of the TypeVar is undefined\"\n_ = MySuperType[str]()\n```\n\nBut instead, you can do this:\n```python\nfrom generics import get_filled_type\n\nclass MySuperType[T]:\n def __init__(self):\n self._my_type: type[T] | None = None\n \n @property\n def my_type(self) -> type[T]:\n if self._my_type is None:\n self._my_type = get_filled_type(self, MySuperType, 0)\n return self._my_type\n\ninstance = MySuperType[str]()\nassert instance.my_type is str\n```\nNote that the property will only resolve _after_ the constructor has been called i.e. the\nobject has been created. You cannot use it inside the constructor.\n\n## How to use this Repository on Your Machine (as a developer)\n\nFollow the instructions in our [Python template repository](https://github.com/Hochfrequenz/python_template_repository#how-to-use-this-repository-on-your-machine).\n\n## Contribute\n\nYou are very welcome to contribute to this template repository by opening a pull request against the main branch.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "A package to determine the values of generic classes through instances or subclasses",
"version": "0.2.3",
"project_urls": {
"Changelog": "https://github.com/Hochfrequenz/python-generics/releases",
"Homepage": "https://github.com/Hochfrequenz/python-generics"
},
"split_keywords": [
"generics",
" python"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "8b381e31c8d849820de23d2ed7aa5e65902264fff5fe6547d8589194ad94b55f",
"md5": "02108c8bb0b954298d58aa0aa90179c0",
"sha256": "7dd0bdcd33eb874954eb580562bd6f2adb7f4c1d79d644a010efe59bb3fe186f"
},
"downloads": -1,
"filename": "python_generics-0.2.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "02108c8bb0b954298d58aa0aa90179c0",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 7321,
"upload_time": "2024-10-14T06:43:04",
"upload_time_iso_8601": "2024-10-14T06:43:04.758071Z",
"url": "https://files.pythonhosted.org/packages/8b/38/1e31c8d849820de23d2ed7aa5e65902264fff5fe6547d8589194ad94b55f/python_generics-0.2.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "a9fd63a19568c103cfb8fa8c193f162ba5d5e50fc0ac98d8ca8925fe02536a0c",
"md5": "109493a0e84ff96c5ab8524d5016ca28",
"sha256": "33c9c48c5d86df3bfc4a319e27cb7bcf3fdce1d28d89bdd3f7a15fe02d31a01e"
},
"downloads": -1,
"filename": "python_generics-0.2.3.tar.gz",
"has_sig": false,
"md5_digest": "109493a0e84ff96c5ab8524d5016ca28",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 12828,
"upload_time": "2024-10-14T06:43:06",
"upload_time_iso_8601": "2024-10-14T06:43:06.335725Z",
"url": "https://files.pythonhosted.org/packages/a9/fd/63a19568c103cfb8fa8c193f162ba5d5e50fc0ac98d8ca8925fe02536a0c/python_generics-0.2.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-10-14 06:43:06",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "Hochfrequenz",
"github_project": "python-generics",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [],
"tox": true,
"lcname": "python-generics"
}