# modern_types [](https://github.com/bswck/skeleton/tree/837babb)
[](https://pypi.org/project/modern-types/)
[](https://pypi.org/project/modern-types/)
[](https://github.com/bswck/modern_types/actions/workflows/test.yml)
[](https://coverage-badge.samuelcolvin.workers.dev/redirect/bswck/modern_types)
[](https://python-poetry.org/)
[](https://github.com/astral-sh/ruff)
[](https://github.com/bswck/modern_types/blob/HEAD/LICENSE)
[](https://github.com/pre-commit/pre-commit)
`__modern_types__` aims to provide [PEP 585](https://peps.python.org/pep-0585/) + [PEP 604](https://peps.python.org/pep-0604/) backward compatibility for Python <=3.10 deferred type evaluation.
Hence, the targeted Python versions are 3.8 and 3.9.
# What does it do?
Technically speaking, `__modern_types__` traverses ASTs of type hint expressions to transform copies
of the namespaces passed to the evaluation routine `ForwardRef._evaluate`.
The transformation prevents type errors in Python 3.8 and 3.9 when evaluating these type hints using future-version PEP 585 and PEP 604 syntaxes.
This might be very useful for [writing pydantic models](https://docs.pydantic.dev/2.5/concepts/models/) in Python <3.10 in a modern fashion, without having to import `typing`.
As a result, in Python 3.8 and Python 3.9, the following code
```py
from __future__ import annotations
import collections.abc
from collections import defaultdict
from pprint import pprint
from typing import get_type_hints
import __modern_types__ # without this line it won't work!
class Foo:
a: dict[str, int]
b: list[int]
c: set[int]
d: tuple[int, ...] | None
e: frozenset[int]
f: defaultdict[str, int]
g: str | None
h: str | int
i: str | int | None
j: str
k: collections.abc.Mapping[str, int]
l: collections.abc.Mapping[str, int] | None
m: collections.abc.Mapping[str, int | None] | float | None
pprint(get_type_hints(Foo, globals(), locals()))
```
gives:
```py
{'a': typing.Dict[str, int],
'b': typing.List[int],
'c': typing.Set[int],
'd': typing.Union[typing.Tuple[int, ...], NoneType],
'e': typing.FrozenSet[int],
'f': typing.DefaultDict[str, int],
'g': typing.Union[str, NoneType],
'h': typing.Union[str, int],
'i': typing.Union[str, int, NoneType],
'j': <class 'str'>,
'k': typing.Mapping[str, int],
'l': typing.Union[typing.Mapping[str, int], NoneType],
'm': typing.Union[typing.Mapping[str, typing.Union[int, NoneType]], float, NoneType]}
```
instead of raising an error that `type` object isn't subscriptable (Python 3.8)
or that `GenericAlias` doesn't support the `|` operator (Python 3.9).
# Use case
Keep your codebase up-to-date by speeding up migration to modern types, even if you support Python versions >=3.8.
Stop using deprecated `typing.Dict`, `typing.List`, `typing.Set`, `typing.Tuple`, `typing.FrozenSet`, `typing.DefaultDict` and other `typing` type proxies explicitly!
Importing `__modern_types__` will make all `typing.ForwardRef`-dependent parts of your application, including pydantic models, work flawlessly with PEP 585 and PEP 604.
# Is `__modern_types__` safe to use in production?
Yes. It doesn't break any existing codebase. It only uses AST and overwrites `typing.ForwardRef._evaluate`.
`__modern_types__` does not interact with the caller's namespaces, does not mutate built-in classes and does not do any other dubious things
that could potentially produce weird, unexpected side effects.
# How to use?
> [!Warning]
> Remember that the library does not change the built-in scope at runtime!
>
> So `dict[str, int]` won't render at runtime, but `typing.Dict[str, int]` will.
>
> `__modern_types__` makes it possible to evaluate `dict[str, int]` only through the `typing.get_type_hints` function.
>
> You should remember putting `from __future__ import annotations` at the top of your modules everywhere you
> want to leverage `__modern_types__`.
Simply import `__modern_types__` in your code, and it will make `typing.ForwardRef` instances go through the
type hint expression AST to try to tweak the copy of the passed global/local namespace
to use `typing._GenericAlias` instances that support `[]` and `|` operators at runtime.
Example replacements taking place in the built-in scope:
| Old type | New type | Without `__modern_types__`, works on Python version... | With `__modern_types__`, works on Python version... | Backports PEP |
| :-------------------------------: | :--------------------------: | :----------------------------------------------------: | :-------------------------------------------------: | :------------------------------------------: |
| `dict[KT, VT]` | `typing.Dict[KT, VT]` | >=3.9 | >=3.8 | [PEP 585](https://peps.python.org/pep-0585/) |
| `list[T]` | `typing.List[T]` | >=3.9 | >=3.8 | [PEP 585](https://peps.python.org/pep-0585/) |
| `set[T]` | `typing.Set[T]` | >=3.9 | >=3.8 | [PEP 585](https://peps.python.org/pep-0585/) |
| `tuple[T, ...]` | `typing.Tuple[T, ...]` | >=3.9 | >=3.8 | [PEP 585](https://peps.python.org/pep-0585/) |
| `frozenset[T]` | `typing.FrozenSet[T]` | >=3.9 | >=3.8 | [PEP 585](https://peps.python.org/pep-0585/) |
| `X \| Y` | `typing.Union[X, Y]` | **>=3.10** | >=3.8 | [PEP 604](https://peps.python.org/pep-0604/) |
Additionally, `__modern_types__` also allows you to use `collections.abc` and `contextlib` generic classes.
> [!Note]
> Some optional replacements will automatically also be registered if possible,
> according to those listed in the [`__modern_types__._typeshed`](https://github.com/bswck/modern_types/tree/HEAD/__modern_types__/_typeshed.py) source code.
# Installation
You might simply install it with pip:
```shell
pip install modern-types
```
If you use [Poetry](https://python-poetry.org/), then run:
```shell
poetry add modern-types
```
## For contributors
<!--
This section was generated from bswck/skeleton@837babb.
Instead of changing this particular file, you might want to alter the template:
https://github.com/bswck/skeleton/tree/837babb/fragments/readme.md
-->
> [!Note]
> If you use Windows, it is highly recommended to complete the installation in the way presented below through [WSL2](https://learn.microsoft.com/en-us/windows/wsl/install).
1. Fork the [modern_types repository](https://github.com/bswck/modern_types) on GitHub.
1. [Install Poetry](https://python-poetry.org/docs/#installation).<br/>
Poetry is an amazing tool for managing dependencies & virtual environments, building packages and publishing them.
You might use [pipx](https://github.com/pypa/pipx#readme) to install it globally (recommended):
```shell
pipx install poetry
```
<sub>If you encounter any problems, refer to [the official documentation](https://python-poetry.org/docs/#installation) for the most up-to-date installation instructions.</sub>
Be sure to have Python 3.8 installed—if you use [pyenv](https://github.com/pyenv/pyenv#readme), simply run:
```shell
pyenv install 3.8
```
1. Clone your fork locally and install dependencies.
```shell
git clone https://github.com/your-username/modern_types path/to/modern_types
cd path/to/modern_types
poetry env use $(cat .python-version)
poetry install
```
Next up, simply activate the virtual environment and install pre-commit hooks:
```shell
poetry shell
pre-commit install --hook-type pre-commit --hook-type pre-push
```
For more information on how to contribute, check out [CONTRIBUTING.md](https://github.com/bswck/modern_types/blob/HEAD/CONTRIBUTING.md).<br/>
Always happy to accept contributions! ❤️
# Legal info
© Copyright by Bartosz Sławecki ([@bswck](https://github.com/bswck)).
<br />This software is licensed under the terms of [MIT License](https://github.com/bswck/modern_types/blob/HEAD/LICENSE).
Raw data
{
"_id": null,
"home_page": "https://github.com/bswck/modern_types",
"name": "modern-types",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.8,<=3.12",
"maintainer_email": "",
"keywords": "",
"author": "bswck",
"author_email": "bswck.dev@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/44/e4/f487b3de0d1d1bb90e7541be9db6ad7acd952d7d877c8defc34c40272f61/modern_types-2.0.8.tar.gz",
"platform": null,
"description": "\n# modern_types [](https://github.com/bswck/skeleton/tree/837babb)\n[](https://pypi.org/project/modern-types/)\n[](https://pypi.org/project/modern-types/)\n\n[](https://github.com/bswck/modern_types/actions/workflows/test.yml)\n[](https://coverage-badge.samuelcolvin.workers.dev/redirect/bswck/modern_types)\n[](https://python-poetry.org/)\n[](https://github.com/astral-sh/ruff)\n[](https://github.com/bswck/modern_types/blob/HEAD/LICENSE)\n[](https://github.com/pre-commit/pre-commit)\n\n`__modern_types__` aims to provide [PEP 585](https://peps.python.org/pep-0585/) + [PEP 604](https://peps.python.org/pep-0604/) backward compatibility for Python <=3.10 deferred type evaluation.\nHence, the targeted Python versions are 3.8 and 3.9.\n\n# What does it do?\nTechnically speaking, `__modern_types__` traverses ASTs of type hint expressions to transform copies\nof the namespaces passed to the evaluation routine `ForwardRef._evaluate`.\nThe transformation prevents type errors in Python 3.8 and 3.9 when evaluating these type hints using future-version PEP 585 and PEP 604 syntaxes.\nThis might be very useful for [writing pydantic models](https://docs.pydantic.dev/2.5/concepts/models/) in Python <3.10 in a modern fashion, without having to import `typing`.\n\nAs a result, in Python 3.8 and Python 3.9, the following code\n\n```py\nfrom __future__ import annotations\n\nimport collections.abc\nfrom collections import defaultdict\nfrom pprint import pprint\nfrom typing import get_type_hints\n\nimport __modern_types__ # without this line it won't work!\n\nclass Foo:\n a: dict[str, int]\n b: list[int]\n c: set[int]\n d: tuple[int, ...] | None\n e: frozenset[int]\n f: defaultdict[str, int]\n g: str | None\n h: str | int\n i: str | int | None\n j: str\n k: collections.abc.Mapping[str, int]\n l: collections.abc.Mapping[str, int] | None\n m: collections.abc.Mapping[str, int | None] | float | None\n\n\npprint(get_type_hints(Foo, globals(), locals()))\n```\ngives:\n```py\n{'a': typing.Dict[str, int],\n 'b': typing.List[int],\n 'c': typing.Set[int],\n 'd': typing.Union[typing.Tuple[int, ...], NoneType],\n 'e': typing.FrozenSet[int],\n 'f': typing.DefaultDict[str, int],\n 'g': typing.Union[str, NoneType],\n 'h': typing.Union[str, int],\n 'i': typing.Union[str, int, NoneType],\n 'j': <class 'str'>,\n 'k': typing.Mapping[str, int],\n 'l': typing.Union[typing.Mapping[str, int], NoneType],\n 'm': typing.Union[typing.Mapping[str, typing.Union[int, NoneType]], float, NoneType]}\n```\ninstead of raising an error that `type` object isn't subscriptable (Python 3.8)\nor that `GenericAlias` doesn't support the `|` operator (Python 3.9).\n\n# Use case\nKeep your codebase up-to-date by speeding up migration to modern types, even if you support Python versions >=3.8.\n\nStop using deprecated `typing.Dict`, `typing.List`, `typing.Set`, `typing.Tuple`, `typing.FrozenSet`, `typing.DefaultDict` and other `typing` type proxies explicitly!\n\nImporting `__modern_types__` will make all `typing.ForwardRef`-dependent parts of your application, including pydantic models, work flawlessly with PEP 585 and PEP 604.\n\n# Is `__modern_types__` safe to use in production?\nYes. It doesn't break any existing codebase. It only uses AST and overwrites `typing.ForwardRef._evaluate`.\n`__modern_types__` does not interact with the caller's namespaces, does not mutate built-in classes and does not do any other dubious things\nthat could potentially produce weird, unexpected side effects.\n\n# How to use?\n> [!Warning]\n> Remember that the library does not change the built-in scope at runtime!\n>\n> So `dict[str, int]` won't render at runtime, but `typing.Dict[str, int]` will.\n>\n> `__modern_types__` makes it possible to evaluate `dict[str, int]` only through the `typing.get_type_hints` function.\n>\n> You should remember putting `from __future__ import annotations` at the top of your modules everywhere you\n> want to leverage `__modern_types__`.\n\nSimply import `__modern_types__` in your code, and it will make `typing.ForwardRef` instances go through the\ntype hint expression AST to try to tweak the copy of the passed global/local namespace\nto use `typing._GenericAlias` instances that support `[]` and `|` operators at runtime.\n\nExample replacements taking place in the built-in scope:\n\n| Old type | New type | Without `__modern_types__`, works on Python version... | With `__modern_types__`, works on Python version... | Backports PEP |\n| :-------------------------------: | :--------------------------: | :----------------------------------------------------: | :-------------------------------------------------: | :------------------------------------------: |\n| `dict[KT, VT]` | `typing.Dict[KT, VT]` | >=3.9 | >=3.8 | [PEP 585](https://peps.python.org/pep-0585/) |\n| `list[T]` | `typing.List[T]` | >=3.9 | >=3.8 | [PEP 585](https://peps.python.org/pep-0585/) |\n| `set[T]` | `typing.Set[T]` | >=3.9 | >=3.8 | [PEP 585](https://peps.python.org/pep-0585/) |\n| `tuple[T, ...]` | `typing.Tuple[T, ...]` | >=3.9 | >=3.8 | [PEP 585](https://peps.python.org/pep-0585/) |\n| `frozenset[T]` | `typing.FrozenSet[T]` | >=3.9 | >=3.8 | [PEP 585](https://peps.python.org/pep-0585/) |\n| `X \\| Y` | `typing.Union[X, Y]` | **>=3.10** | >=3.8 | [PEP 604](https://peps.python.org/pep-0604/) |\n\nAdditionally, `__modern_types__` also allows you to use `collections.abc` and `contextlib` generic classes.\n\n> [!Note]\n> Some optional replacements will automatically also be registered if possible,\n> according to those listed in the [`__modern_types__._typeshed`](https://github.com/bswck/modern_types/tree/HEAD/__modern_types__/_typeshed.py) source code.\n\n# Installation\n\n\n\nYou might simply install it with pip:\n\n```shell\npip install modern-types\n```\n\nIf you use [Poetry](https://python-poetry.org/), then run:\n\n```shell\npoetry add modern-types\n```\n\n## For contributors\n\n<!--\nThis section was generated from bswck/skeleton@837babb.\nInstead of changing this particular file, you might want to alter the template:\nhttps://github.com/bswck/skeleton/tree/837babb/fragments/readme.md\n-->\n\n> [!Note]\n> If you use Windows, it is highly recommended to complete the installation in the way presented below through [WSL2](https://learn.microsoft.com/en-us/windows/wsl/install).\n\n\n\n1. Fork the [modern_types repository](https://github.com/bswck/modern_types) on GitHub.\n\n1. [Install Poetry](https://python-poetry.org/docs/#installation).<br/>\n Poetry is an amazing tool for managing dependencies & virtual environments, building packages and publishing them.\n You might use [pipx](https://github.com/pypa/pipx#readme) to install it globally (recommended):\n\n ```shell\n pipx install poetry\n ```\n\n <sub>If you encounter any problems, refer to [the official documentation](https://python-poetry.org/docs/#installation) for the most up-to-date installation instructions.</sub>\n\n Be sure to have Python 3.8 installed\u2014if you use [pyenv](https://github.com/pyenv/pyenv#readme), simply run:\n\n ```shell\n pyenv install 3.8\n ```\n\n1. Clone your fork locally and install dependencies.\n\n ```shell\n git clone https://github.com/your-username/modern_types path/to/modern_types\n cd path/to/modern_types\n poetry env use $(cat .python-version)\n poetry install\n ```\n\n Next up, simply activate the virtual environment and install pre-commit hooks:\n\n ```shell\n poetry shell\n pre-commit install --hook-type pre-commit --hook-type pre-push\n ```\n\nFor more information on how to contribute, check out [CONTRIBUTING.md](https://github.com/bswck/modern_types/blob/HEAD/CONTRIBUTING.md).<br/>\nAlways happy to accept contributions! \u2764\ufe0f\n\n\n# Legal info\n\u00a9 Copyright by Bartosz S\u0142awecki ([@bswck](https://github.com/bswck)).\n<br />This software is licensed under the terms of [MIT License](https://github.com/bswck/modern_types/blob/HEAD/LICENSE).\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "PEP 585 + PEP 604 backports.",
"version": "2.0.8",
"project_urls": {
"Coverage": "https://coverage-badge.samuelcolvin.workers.dev/redirect/bswck/modern_types",
"Distribution": "https://pypi.org/project/modern-types/",
"Homepage": "https://github.com/bswck/modern_types",
"Issues": "https://github.com/bswck/modern_types/issues"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "a4e41ded53da92f4d6479957cd7dae3ad542277f4c266801535ab4e9b10a7ef0",
"md5": "4b35c1ffdb5b7dded747a3fbbfcca06a",
"sha256": "aa5583fb18ce505941882fcc4871270e247fb27afb83aa092ba88618797e96cb"
},
"downloads": -1,
"filename": "modern_types-2.0.8-py3-none-any.whl",
"has_sig": false,
"md5_digest": "4b35c1ffdb5b7dded747a3fbbfcca06a",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8,<=3.12",
"size": 15194,
"upload_time": "2023-12-23T10:01:33",
"upload_time_iso_8601": "2023-12-23T10:01:33.730708Z",
"url": "https://files.pythonhosted.org/packages/a4/e4/1ded53da92f4d6479957cd7dae3ad542277f4c266801535ab4e9b10a7ef0/modern_types-2.0.8-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "44e4f487b3de0d1d1bb90e7541be9db6ad7acd952d7d877c8defc34c40272f61",
"md5": "def15f671da3dbbd916211abbef2fe12",
"sha256": "07511f2b93b712ead67641f9374f9884a91753c67900bb947316e6ad0e5bf4e2"
},
"downloads": -1,
"filename": "modern_types-2.0.8.tar.gz",
"has_sig": false,
"md5_digest": "def15f671da3dbbd916211abbef2fe12",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8,<=3.12",
"size": 18178,
"upload_time": "2023-12-23T10:01:35",
"upload_time_iso_8601": "2023-12-23T10:01:35.282574Z",
"url": "https://files.pythonhosted.org/packages/44/e4/f487b3de0d1d1bb90e7541be9db6ad7acd952d7d877c8defc34c40272f61/modern_types-2.0.8.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-12-23 10:01:35",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "bswck",
"github_project": "modern_types",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "modern-types"
}