diff --git a/.flake8 b/.flake8 index 53cf55a0..ff64f42c 100644 --- a/.flake8 +++ b/.flake8 @@ -9,7 +9,3 @@ ignore = E129, # consistency with mypy W504 -exclude = - # tests have more relaxed formatting rules - # and its own specific config in .flake8-tests - typing_extensions/src/test_typing_extensions.py, diff --git a/.flake8-tests b/.flake8-tests deleted file mode 100644 index 5a97fe89..00000000 --- a/.flake8-tests +++ /dev/null @@ -1,28 +0,0 @@ -# This configuration is specific to test_*.py; you need to invoke it -# by specifically naming this config, like this: -# -# $ flake8 --config=.flake8-tests [SOURCES] -# -# This will be possibly merged in the future. - -[flake8] -max-line-length = 100 -ignore = - # temporary ignores until we sort it out - B017, - E302, - E303, - E306, - E501, - E701, - E704, - F722, - F811, - F821, - F841, - W503, - # irrelevant plugins - B3, - DW12, - # consistency with mypy - W504 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 302b2cae..14cb706e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,36 +8,6 @@ permissions: contents: read jobs: - tests: - name: Run tests - - strategy: - fail-fast: false - matrix: - # We try to test on the earliest available bugfix release of each - # Python version, because typing sometimes changed between bugfix releases. - # For available versions, see: - # https://raw.githubusercontent.com/actions/python-versions/main/versions-manifest.json - python-version: ["3.7", "3.7.1", "3.8", "3.8.0", "3.9", "3.9.0", "3.10", "3.10.0", "3.11-dev"] - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - - name: Test typing_extensions - continue-on-error: ${{ matrix.python-version == '3.11-dev' }} - run: | - # Be wary of running `pip install` here, since it becomes easy for us to - # accidentally pick up typing_extensions as installed by a dependency - cd typing_extensions/src - python -m unittest test_typing_extensions.py - linting: name: Lint @@ -59,6 +29,3 @@ jobs: - name: Lint implementation run: flake8 - - - name: Lint tests - run: flake8 --config=.flake8-tests typing_extensions/src/test_typing_extensions.py diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml deleted file mode 100644 index 25f95868..00000000 --- a/.github/workflows/package.yml +++ /dev/null @@ -1,71 +0,0 @@ -name: Test packaging - -on: - push: - pull_request: - -permissions: - contents: read - -jobs: - wheel: - name: Test wheel install - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: 3 - - - name: Install pypa/build - run: | - # Be wary of running `pip install` here, since it becomes easy for us to - # accidentally pick up typing_extensions as installed by a dependency - python -m pip install --upgrade build - python -m pip list - - - name: Build and install wheel - run: | - cd typing_extensions - python -m build . - export path_to_file=$(find dist -type f -name "typing_extensions-*.whl") - echo "::notice::Installing wheel: $path_to_file" - pip install -vvv $path_to_file - python -m pip list - - - name: Attempt to import typing_extensions - run: python -c "import typing_extensions; print(typing_extensions.__all__)" - - sdist: - name: Test sdist install - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: 3 - - - name: Install pypa/build - run: | - # Be wary of running `pip install` here, since it becomes easy for us to - # accidentally pick up typing_extensions as installed by a dependency - python -m pip install --upgrade build - python -m pip list - - - name: Build and install sdist - run: | - cd typing_extensions - python -m build . - export path_to_file=$(find dist -type f -name "typing_extensions-*.tar.gz") - echo "::notice::Installing sdist: $path_to_file" - pip install -vvv $path_to_file - python -m pip list - - - name: Attempt to import typing_extensions - run: python -c "import typing_extensions; print(typing_extensions.__all__)" diff --git a/README.md b/README.md index 64b91182..edb902fe 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,8 @@ [![Chat at https://gitter.im/python/typing](https://badges.gitter.im/python/typing.svg)](https://gitter.im/python/typing?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -Static Typing for Python -======================== +# Static Typing for Python -Documentation and Support -------------------------- +## Documentation and Support The documentation for Python's static typing can be found at [typing.readthedocs.io](https://typing.readthedocs.io/). You can get @@ -16,26 +14,29 @@ Improvements to the type system should be discussed on the mailing list, although the [issues](https://github.com/python/typing/issues) in this repository contain some historic discussions. -Repository Content ------------------- +## Repository Content This GitHub repository is used for several things: -- The `typing_extensions` module lives in the - [typing\_extensions](./typing_extensions) directory. - - The documentation at [typing.readthedocs.io](https://typing.readthedocs.io/) is maintained in the [docs directory](./docs). - A [discussion forum](https://github.com/python/typing/discussions) for typing-related user help is hosted here. -Historically, this repository hosted a backport of the -[`typing` module](https://docs.python.org/3/library/typing.html) for older -Python versions. The last released version, supporting Python 2.7 and 3.4, -is [available at PyPI](https://pypi.org/project/typing/). +Historically, this repository also hosted: + +- The `typing_extensions` package, which now lives in the + [typing_extensions](https://github.com/python/typing_extensions) repo. + It used to be in the `typing_extensions` directory. + +- A backport of the + [`typing` module](https://docs.python.org/3/library/typing.html) for older + Python versions. It was removed after all Python versions that lack `typing` + in the standard library reached end of life. The last released version, + supporting Python 2.7 and 3.4, + is [available at PyPI](https://pypi.org/project/typing/). -Workflow --------- +## Workflow See [CONTRIBUTING.md](/CONTRIBUTING.md) for more. diff --git a/typing_extensions/CHANGELOG.md b/typing_extensions/CHANGELOG.md deleted file mode 100644 index aa66e55c..00000000 --- a/typing_extensions/CHANGELOG.md +++ /dev/null @@ -1,81 +0,0 @@ -# Release 4.2.0 (April 17, 2022) - -- Re-export `typing.Unpack` and `typing.TypeVarTuple` on Python 3.11. -- Add `ParamSpecArgs` and `ParamSpecKwargs` to `__all__`. -- Improve "accepts only single type" error messages. -- Improve the distributed package. Patch by Marc Mueller (@cdce8p). -- Update `typing_extensions.dataclass_transform` to rename the - `field_descriptors` parameter to `field_specifiers` and accept - arbitrary keyword arguments. -- Add `typing_extensions.get_overloads` and - `typing_extensions.clear_overloads`, and add registry support to - `typing_extensions.overload`. Backport from python/cpython#89263. -- Add `typing_extensions.assert_type`. Backport from bpo-46480. -- Drop support for Python 3.6. Original patch by Adam Turner (@AA-Turner). - -# Release 4.1.1 (February 13, 2022) - -- Fix importing `typing_extensions` on Python 3.7.0 and 3.7.1. Original - patch by Nikita Sobolev (@sobolevn). - -# Release 4.1.0 (February 12, 2022) - -- Runtime support for PEP 646, adding `typing_extensions.TypeVarTuple` - and `typing_extensions.Unpack`. -- Add interaction of `Required` and `NotRequired` with `__required_keys__`, - `__optional_keys__` and `get_type_hints()`. Patch by David Cabot (@d-k-bo). -- Runtime support for PEP 675 and `typing_extensions.LiteralString`. -- Add `Never` and `assert_never`. Backport from bpo-46475. -- `ParamSpec` args and kwargs are now equal to themselves. Backport from - bpo-46676. Patch by Gregory Beauregard (@GBeauregard). -- Add `reveal_type`. Backport from bpo-46414. -- Runtime support for PEP 681 and `typing_extensions.dataclass_transform`. -- `Annotated` can now wrap `ClassVar` and `Final`. Backport from - bpo-46491. Patch by Gregory Beauregard (@GBeauregard). -- Add missed `Required` and `NotRequired` to `__all__`. Patch by - Yuri Karabas (@uriyyo). -- The `@final` decorator now sets the `__final__` attribute on the - decorated object to allow runtime introspection. Backport from - bpo-46342. -- Add `is_typeddict`. Patch by Chris Moradi (@chrismoradi) and James - Hilton-Balfe (@Gobot1234). - -# Release 4.0.1 (November 30, 2021) - -- Fix broken sdist in release 4.0.0. Patch by Adam Turner (@AA-Turner). -- Fix equality comparison for `Required` and `NotRequired`. Patch by - Jelle Zijlstra (@jellezijlstra). -- Fix usage of `Self` as a type argument. Patch by Chris Wesseling - (@CharString) and James Hilton-Balfe (@Gobot1234). - -# Release 4.0.0 (November 14, 2021) - -- Starting with version 4.0.0, typing_extensions uses Semantic Versioning. - See the README for more information. -- Dropped support for Python versions 3.5 and older, including Python 2.7. -- Simplified backports for Python 3.6.0 and newer. Patch by Adam Turner (@AA-Turner). - -## Added in version 4.0.0 - -- Runtime support for PEP 673 and `typing_extensions.Self`. Patch by - James Hilton-Balfe (@Gobot1234). -- Runtime support for PEP 655 and `typing_extensions.Required` and `NotRequired`. - Patch by David Foster (@davidfstr). - -## Removed in version 4.0.0 - -The following non-exported but non-private names have been removed as they are -unneeded for supporting Python 3.6 and newer. - -- TypingMeta -- OLD_GENERICS -- SUBS_TREE -- HAVE_ANNOTATED -- HAVE_PROTOCOLS -- V_co -- VT_co - -# Previous releases - -Prior to release 4.0.0 we did not provide a changelog. Please check -the Git history for details. diff --git a/typing_extensions/README.md b/typing_extensions/README.md deleted file mode 100644 index 54b93ddc..00000000 --- a/typing_extensions/README.md +++ /dev/null @@ -1,143 +0,0 @@ -# Typing Extensions - -[![Chat at https://gitter.im/python/typing](https://badges.gitter.im/python/typing.svg)](https://gitter.im/python/typing) - -## Overview - -The `typing_extensions` module serves two related purposes: - -- Enable use of new type system features on older Python versions. For example, - `typing.TypeGuard` is new in Python 3.10, but `typing_extensions` allows - users on Python 3.6 through 3.9 to use it too. -- Enable experimentation with new type system PEPs before they are accepted and - added to the `typing` module. - -New features may be added to `typing_extensions` as soon as they are specified -in a PEP that has been added to the [python/peps](https://github.com/python/peps) -repository. If the PEP is accepted, the feature will then be added to `typing` -for the next CPython release. No typing PEP has been rejected so far, so we -haven't yet figured out how to deal with that possibility. - -Starting with version 4.0.0, `typing_extensions` uses -[Semantic Versioning](https://semver.org/). The -major version is incremented for all backwards-incompatible changes. -Therefore, it's safe to depend -on `typing_extensions` like this: `typing_extensions >=x.y, <(x+1)`, -where `x.y` is the first version that includes all features you need. - -`typing_extensions` supports Python versions 3.7 and higher. In the future, -support for older Python versions will be dropped some time after that version -reaches end of life. - -## Included items - -This module currently contains the following: - -- Experimental features - - - `@dataclass_transform()` (see PEP 681) - -- In `typing` since Python 3.11 - - - `assert_never` - - `assert_type` - - `clear_overloads` - - `get_overloads` - - `LiteralString` (see PEP 675) - - `Never` - - `NotRequired` (see PEP 655) - - `reveal_type` - - `Required` (see PEP 655) - - `Self` (see PEP 673) - - `TypeVarTuple` (see PEP 646) - - `Unpack` (see PEP 646) - -- In `typing` since Python 3.10 - - - `Concatenate` (see PEP 612) - - `ParamSpec` (see PEP 612) - - `ParamSpecArgs` (see PEP 612) - - `ParamSpecKwargs` (see PEP 612) - - `TypeAlias` (see PEP 613) - - `TypeGuard` (see PEP 647) - - `is_typeddict` - -- In `typing` since Python 3.9 - - - `Annotated` (see PEP 593) - -- In `typing` since Python 3.8 - - - `final` (see PEP 591) - - `Final` (see PEP 591) - - `Literal` (see PEP 586) - - `Protocol` (see PEP 544) - - `runtime_checkable` (see PEP 544) - - `TypedDict` (see PEP 589) - - `get_origin` (`typing_extensions` provides this function only in Python 3.7+) - - `get_args` (`typing_extensions` provides this function only in Python 3.7+) - -- In `typing` since Python 3.7 - - - `OrderedDict` - -- In `typing` since Python 3.5 or 3.6 (see [the typing documentation](https://docs.python.org/3.10/library/typing.html) for details) - - - `AsyncContextManager` - - `AsyncGenerator` - - `AsyncIterable` - - `AsyncIterator` - - `Awaitable` - - `ChainMap` - - `ClassVar` (see PEP 526) - - `ContextManager` - - `Coroutine` - - `Counter` - - `DefaultDict` - - `Deque` - - `NewType` - - `NoReturn` - - `overload` - - `Text` - - `Type` - - `TYPE_CHECKING` - - `get_type_hints` - -# Other Notes and Limitations - -Certain objects were changed after they were added to `typing`, and -`typing_extensions` provides a backport even on newer Python versions: - -- `TypedDict` does not store runtime information - about which (if any) keys are non-required in Python 3.8, and does not - honor the `total` keyword with old-style `TypedDict()` in Python - 3.9.0 and 3.9.1. -- `get_origin` and `get_args` lack support for `Annotated` in - Python 3.8 and lack support for `ParamSpecArgs` and `ParamSpecKwargs` - in 3.9. -- `@final` was changed in Python 3.11 to set the `.__final__` attribute. -- `@overload` was changed in Python 3.11 to make function overloads - introspectable at runtime. In order to access overloads with - `typing_extensions.get_overloads()`, you must use - `@typing_extensions.overload`. - -There are a few types whose interface was modified between different -versions of typing. For example, `typing.Sequence` was modified to -subclass `typing.Reversible` as of Python 3.5.3. - -These changes are _not_ backported to prevent subtle compatibility -issues when mixing the differing implementations of modified classes. - -Certain types have incorrect runtime behavior due to limitations of older -versions of the typing module: - -- `ParamSpec` and `Concatenate` will not work with `get_args` and - `get_origin`. Certain PEP 612 special cases in user-defined - `Generic`s are also not available. - -These types are only guaranteed to work for static type checking. - -## Running tests - -To run tests, navigate into the appropriate source directory and run -`test_typing_extensions.py`. diff --git a/typing_extensions/README.rst b/typing_extensions/README.rst index d19c86e8..d9a860f1 100644 --- a/typing_extensions/README.rst +++ b/typing_extensions/README.rst @@ -1 +1 @@ -Please see `README.md `_ for the current version of the README file. +Please see `the typing_extensions repo `_ for the current version of the README file. diff --git a/typing_extensions/pyproject.toml b/typing_extensions/pyproject.toml deleted file mode 100644 index e40ad862..00000000 --- a/typing_extensions/pyproject.toml +++ /dev/null @@ -1,60 +0,0 @@ -# Build system requirements. -[build-system] -requires = ["flit_core >=3.4,<4"] -build-backend = "flit_core.buildapi" - -# Project metadata -[project] -name = "typing_extensions" -version = "4.2.0" -description = "Backported and Experimental Type Hints for Python 3.7+" -readme = "README.md" -requires-python = ">=3.7" -license.file = "LICENSE" -keywords = [ - "annotations", - "backport", - "checker", - "checking", - "function", - "hinting", - "hints", - "type", - "typechecking", - "typehinting", - "typehints", - "typing", -] -# Classifiers list: https://pypi.org/classifiers/ -classifiers = [ - "Development Status :: 5 - Production/Stable", - "Environment :: Console", - "Intended Audience :: Developers", - "License :: OSI Approved :: Python Software Foundation License", - "Operating System :: OS Independent", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Topic :: Software Development", -] - -[project.urls] -Home = "https://github.com/python/typing/tree/master/typing_extensions" -Repository = "https://github.com/python/typing" -Changes = "https://github.com/python/typing/blob/master/typing_extensions/CHANGELOG.md" -Documentation = "https://typing.readthedocs.io/" -"Bug Tracker" = "https://github.com/python/typing/issues" -"Q & A" = "https://github.com/python/typing/discussions" - -# Project metadata -- authors. Flit stores this as a list of dicts, so it can't -# be inline above. -[[project.authors]] -name = "Guido van Rossum, Jukka Lehtosalo, Ɓukasz Langa, Michael Lee" -email = "levkivskyi@gmail.com" - -[tool.flit.sdist] -include = ["CHANGELOG.md", "README.md", "*/test*.py"] -exclude = [] diff --git a/typing_extensions/src/test_typing_extensions.py b/typing_extensions/src/test_typing_extensions.py deleted file mode 100644 index 7f14f3f9..00000000 --- a/typing_extensions/src/test_typing_extensions.py +++ /dev/null @@ -1,2897 +0,0 @@ -import sys -import os -import abc -import contextlib -import collections -from collections import defaultdict -import collections.abc -from functools import lru_cache -import inspect -import pickle -import subprocess -import types -from unittest import TestCase, main, skipUnless, skipIf -from unittest.mock import patch -from test import ann_module, ann_module2, ann_module3 -import typing -from typing import TypeVar, Optional, Union, Any, AnyStr -from typing import T, KT, VT # Not in __all__. -from typing import Tuple, List, Dict, Iterable, Iterator, Callable -from typing import Generic, NamedTuple -from typing import no_type_check -import typing_extensions -from typing_extensions import NoReturn, ClassVar, Final, IntVar, Literal, Type, NewType, TypedDict, Self -from typing_extensions import TypeAlias, ParamSpec, Concatenate, ParamSpecArgs, ParamSpecKwargs, TypeGuard -from typing_extensions import Awaitable, AsyncIterator, AsyncContextManager, Required, NotRequired -from typing_extensions import Protocol, runtime, runtime_checkable, Annotated, final, is_typeddict -from typing_extensions import TypeVarTuple, Unpack, dataclass_transform, reveal_type, Never, assert_never, LiteralString -from typing_extensions import assert_type, get_type_hints, get_origin, get_args -from typing_extensions import clear_overloads, get_overloads, overload - -# Flags used to mark tests that only apply after a specific -# version of the typing module. -TYPING_3_8_0 = sys.version_info[:3] >= (3, 8, 0) -TYPING_3_10_0 = sys.version_info[:3] >= (3, 10, 0) - -# 3.11 makes runtime type checks (_type_check) more lenient. -TYPING_3_11_0 = sys.version_info[:3] >= (3, 11, 0) - - -class BaseTestCase(TestCase): - def assertIsSubclass(self, cls, class_or_tuple, msg=None): - if not issubclass(cls, class_or_tuple): - message = f'{cls!r} is not a subclass of {repr(class_or_tuple)}' - if msg is not None: - message += f' : {msg}' - raise self.failureException(message) - - def assertNotIsSubclass(self, cls, class_or_tuple, msg=None): - if issubclass(cls, class_or_tuple): - message = f'{cls!r} is a subclass of {repr(class_or_tuple)}' - if msg is not None: - message += f' : {msg}' - raise self.failureException(message) - - -class Employee: - pass - - -class BottomTypeTestsMixin: - bottom_type: ClassVar[Any] - - def test_equality(self): - self.assertEqual(self.bottom_type, self.bottom_type) - self.assertIs(self.bottom_type, self.bottom_type) - self.assertNotEqual(self.bottom_type, None) - - def test_get_origin(self): - self.assertIs(get_origin(self.bottom_type), None) - - def test_instance_type_error(self): - with self.assertRaises(TypeError): - isinstance(42, self.bottom_type) - - def test_subclass_type_error(self): - with self.assertRaises(TypeError): - issubclass(Employee, self.bottom_type) - with self.assertRaises(TypeError): - issubclass(NoReturn, self.bottom_type) - - def test_not_generic(self): - with self.assertRaises(TypeError): - self.bottom_type[int] - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class A(self.bottom_type): - pass - with self.assertRaises(TypeError): - class A(type(self.bottom_type)): - pass - - def test_cannot_instantiate(self): - with self.assertRaises(TypeError): - self.bottom_type() - with self.assertRaises(TypeError): - type(self.bottom_type)() - - def test_pickle(self): - for proto in range(pickle.HIGHEST_PROTOCOL): - pickled = pickle.dumps(self.bottom_type, protocol=proto) - self.assertIs(self.bottom_type, pickle.loads(pickled)) - - -class NoReturnTests(BottomTypeTestsMixin, BaseTestCase): - bottom_type = NoReturn - - def test_repr(self): - if hasattr(typing, 'NoReturn'): - self.assertEqual(repr(NoReturn), 'typing.NoReturn') - else: - self.assertEqual(repr(NoReturn), 'typing_extensions.NoReturn') - - def test_get_type_hints(self): - def some(arg: NoReturn) -> NoReturn: ... - def some_str(arg: 'NoReturn') -> 'typing.NoReturn': ... - - expected = {'arg': NoReturn, 'return': NoReturn} - targets = [some] - - # On 3.7.0 and 3.7.1, https://github.com/python/cpython/pull/10772 - # wasn't applied yet and NoReturn fails _type_check. - if not ((3, 7, 0) <= sys.version_info < (3, 7, 2)): - targets.append(some_str) - for target in targets: - with self.subTest(target=target): - self.assertEqual(gth(target), expected) - - def test_not_equality(self): - self.assertNotEqual(NoReturn, Never) - self.assertNotEqual(Never, NoReturn) - - -class NeverTests(BottomTypeTestsMixin, BaseTestCase): - bottom_type = Never - - def test_repr(self): - if hasattr(typing, 'Never'): - self.assertEqual(repr(Never), 'typing.Never') - else: - self.assertEqual(repr(Never), 'typing_extensions.Never') - - def test_get_type_hints(self): - def some(arg: Never) -> Never: ... - def some_str(arg: 'Never') -> 'typing_extensions.Never': ... - - expected = {'arg': Never, 'return': Never} - for target in [some, some_str]: - with self.subTest(target=target): - self.assertEqual(gth(target), expected) - - -class AssertNeverTests(BaseTestCase): - def test_exception(self): - with self.assertRaises(AssertionError): - assert_never(None) - - -class ClassVarTests(BaseTestCase): - - def test_basics(self): - if not TYPING_3_11_0: - with self.assertRaises(TypeError): - ClassVar[1] - with self.assertRaises(TypeError): - ClassVar[int, str] - with self.assertRaises(TypeError): - ClassVar[int][str] - - def test_repr(self): - if hasattr(typing, 'ClassVar'): - mod_name = 'typing' - else: - mod_name = 'typing_extensions' - self.assertEqual(repr(ClassVar), mod_name + '.ClassVar') - cv = ClassVar[int] - self.assertEqual(repr(cv), mod_name + '.ClassVar[int]') - cv = ClassVar[Employee] - self.assertEqual(repr(cv), mod_name + f'.ClassVar[{__name__}.Employee]') - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class C(type(ClassVar)): - pass - with self.assertRaises(TypeError): - class C(type(ClassVar[int])): - pass - - def test_cannot_init(self): - with self.assertRaises(TypeError): - ClassVar() - with self.assertRaises(TypeError): - type(ClassVar)() - with self.assertRaises(TypeError): - type(ClassVar[Optional[int]])() - - def test_no_isinstance(self): - with self.assertRaises(TypeError): - isinstance(1, ClassVar[int]) - with self.assertRaises(TypeError): - issubclass(int, ClassVar) - - -class FinalTests(BaseTestCase): - - def test_basics(self): - if not TYPING_3_11_0: - with self.assertRaises(TypeError): - Final[1] - with self.assertRaises(TypeError): - Final[int, str] - with self.assertRaises(TypeError): - Final[int][str] - - def test_repr(self): - if hasattr(typing, 'Final') and sys.version_info[:2] >= (3, 7): - mod_name = 'typing' - else: - mod_name = 'typing_extensions' - self.assertEqual(repr(Final), mod_name + '.Final') - cv = Final[int] - self.assertEqual(repr(cv), mod_name + '.Final[int]') - cv = Final[Employee] - self.assertEqual(repr(cv), mod_name + f'.Final[{__name__}.Employee]') - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class C(type(Final)): - pass - with self.assertRaises(TypeError): - class C(type(Final[int])): - pass - - def test_cannot_init(self): - with self.assertRaises(TypeError): - Final() - with self.assertRaises(TypeError): - type(Final)() - with self.assertRaises(TypeError): - type(Final[Optional[int]])() - - def test_no_isinstance(self): - with self.assertRaises(TypeError): - isinstance(1, Final[int]) - with self.assertRaises(TypeError): - issubclass(int, Final) - - -class RequiredTests(BaseTestCase): - - def test_basics(self): - if not TYPING_3_11_0: - with self.assertRaises(TypeError): - Required[1] - with self.assertRaises(TypeError): - Required[int, str] - with self.assertRaises(TypeError): - Required[int][str] - - def test_repr(self): - if hasattr(typing, 'Required'): - mod_name = 'typing' - else: - mod_name = 'typing_extensions' - self.assertEqual(repr(Required), mod_name + '.Required') - cv = Required[int] - self.assertEqual(repr(cv), mod_name + '.Required[int]') - cv = Required[Employee] - self.assertEqual(repr(cv), mod_name + '.Required[%s.Employee]' % __name__) - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class C(type(Required)): - pass - with self.assertRaises(TypeError): - class C(type(Required[int])): - pass - - def test_cannot_init(self): - with self.assertRaises(TypeError): - Required() - with self.assertRaises(TypeError): - type(Required)() - with self.assertRaises(TypeError): - type(Required[Optional[int]])() - - def test_no_isinstance(self): - with self.assertRaises(TypeError): - isinstance(1, Required[int]) - with self.assertRaises(TypeError): - issubclass(int, Required) - - -class NotRequiredTests(BaseTestCase): - - def test_basics(self): - if not TYPING_3_11_0: - with self.assertRaises(TypeError): - NotRequired[1] - with self.assertRaises(TypeError): - NotRequired[int, str] - with self.assertRaises(TypeError): - NotRequired[int][str] - - def test_repr(self): - if hasattr(typing, 'NotRequired'): - mod_name = 'typing' - else: - mod_name = 'typing_extensions' - self.assertEqual(repr(NotRequired), mod_name + '.NotRequired') - cv = NotRequired[int] - self.assertEqual(repr(cv), mod_name + '.NotRequired[int]') - cv = NotRequired[Employee] - self.assertEqual(repr(cv), mod_name + '.NotRequired[%s.Employee]' % __name__) - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class C(type(NotRequired)): - pass - with self.assertRaises(TypeError): - class C(type(NotRequired[int])): - pass - - def test_cannot_init(self): - with self.assertRaises(TypeError): - NotRequired() - with self.assertRaises(TypeError): - type(NotRequired)() - with self.assertRaises(TypeError): - type(NotRequired[Optional[int]])() - - def test_no_isinstance(self): - with self.assertRaises(TypeError): - isinstance(1, NotRequired[int]) - with self.assertRaises(TypeError): - issubclass(int, NotRequired) - - -class IntVarTests(BaseTestCase): - def test_valid(self): - T_ints = IntVar("T_ints") # noqa - - def test_invalid(self): - with self.assertRaises(TypeError): - T_ints = IntVar("T_ints", int) - with self.assertRaises(TypeError): - T_ints = IntVar("T_ints", bound=int) - with self.assertRaises(TypeError): - T_ints = IntVar("T_ints", covariant=True) # noqa - - -class LiteralTests(BaseTestCase): - def test_basics(self): - Literal[1] - Literal[1, 2, 3] - Literal["x", "y", "z"] - Literal[None] - - def test_illegal_parameters_do_not_raise_runtime_errors(self): - # Type checkers should reject these types, but we do not - # raise errors at runtime to maintain maximum flexibility - Literal[int] - Literal[Literal[1, 2], Literal[4, 5]] - Literal[3j + 2, ..., ()] - Literal[b"foo", u"bar"] - Literal[{"foo": 3, "bar": 4}] - Literal[T] - - def test_literals_inside_other_types(self): - List[Literal[1, 2, 3]] - List[Literal[("foo", "bar", "baz")]] - - def test_repr(self): - if hasattr(typing, 'Literal'): - mod_name = 'typing' - else: - mod_name = 'typing_extensions' - self.assertEqual(repr(Literal[1]), mod_name + ".Literal[1]") - self.assertEqual(repr(Literal[1, True, "foo"]), mod_name + ".Literal[1, True, 'foo']") - self.assertEqual(repr(Literal[int]), mod_name + ".Literal[int]") - self.assertEqual(repr(Literal), mod_name + ".Literal") - self.assertEqual(repr(Literal[None]), mod_name + ".Literal[None]") - - def test_cannot_init(self): - with self.assertRaises(TypeError): - Literal() - with self.assertRaises(TypeError): - Literal[1]() - with self.assertRaises(TypeError): - type(Literal)() - with self.assertRaises(TypeError): - type(Literal[1])() - - def test_no_isinstance_or_issubclass(self): - with self.assertRaises(TypeError): - isinstance(1, Literal[1]) - with self.assertRaises(TypeError): - isinstance(int, Literal[1]) - with self.assertRaises(TypeError): - issubclass(1, Literal[1]) - with self.assertRaises(TypeError): - issubclass(int, Literal[1]) - - def test_no_subclassing(self): - with self.assertRaises(TypeError): - class Foo(Literal[1]): pass - with self.assertRaises(TypeError): - class Bar(Literal): pass - - def test_no_multiple_subscripts(self): - with self.assertRaises(TypeError): - Literal[1][1] - - -class MethodHolder: - @classmethod - def clsmethod(cls): ... - @staticmethod - def stmethod(): ... - def method(self): ... - - -if TYPING_3_11_0: - registry_holder = typing -else: - registry_holder = typing_extensions - - -class OverloadTests(BaseTestCase): - - def test_overload_fails(self): - with self.assertRaises(RuntimeError): - - @overload - def blah(): - pass - - blah() - - def test_overload_succeeds(self): - @overload - def blah(): - pass - - def blah(): - pass - - blah() - - def set_up_overloads(self): - def blah(): - pass - - overload1 = blah - overload(blah) - - def blah(): - pass - - overload2 = blah - overload(blah) - - def blah(): - pass - - return blah, [overload1, overload2] - - # Make sure we don't clear the global overload registry - @patch( - f"{registry_holder.__name__}._overload_registry", - defaultdict(lambda: defaultdict(dict)) - ) - def test_overload_registry(self): - registry = registry_holder._overload_registry - # The registry starts out empty - self.assertEqual(registry, {}) - - impl, overloads = self.set_up_overloads() - self.assertNotEqual(registry, {}) - self.assertEqual(list(get_overloads(impl)), overloads) - - def some_other_func(): pass - overload(some_other_func) - other_overload = some_other_func - def some_other_func(): pass - self.assertEqual(list(get_overloads(some_other_func)), [other_overload]) - - # Make sure that after we clear all overloads, the registry is - # completely empty. - clear_overloads() - self.assertEqual(registry, {}) - self.assertEqual(get_overloads(impl), []) - - # Querying a function with no overloads shouldn't change the registry. - def the_only_one(): pass - self.assertEqual(get_overloads(the_only_one), []) - self.assertEqual(registry, {}) - - def test_overload_registry_repeated(self): - for _ in range(2): - impl, overloads = self.set_up_overloads() - - self.assertEqual(list(get_overloads(impl)), overloads) - - -class AssertTypeTests(BaseTestCase): - - def test_basics(self): - arg = 42 - self.assertIs(assert_type(arg, int), arg) - self.assertIs(assert_type(arg, Union[str, float]), arg) - self.assertIs(assert_type(arg, AnyStr), arg) - self.assertIs(assert_type(arg, None), arg) - - def test_errors(self): - # Bogus calls are not expected to fail. - arg = 42 - self.assertIs(assert_type(arg, 42), arg) - self.assertIs(assert_type(arg, 'hello'), arg) - - -T_a = TypeVar('T_a') - -class AwaitableWrapper(Awaitable[T_a]): - - def __init__(self, value): - self.value = value - - def __await__(self) -> typing.Iterator[T_a]: - yield - return self.value - -class AsyncIteratorWrapper(AsyncIterator[T_a]): - - def __init__(self, value: Iterable[T_a]): - self.value = value - - def __aiter__(self) -> AsyncIterator[T_a]: - return self - - async def __anext__(self) -> T_a: - data = await self.value - if data: - return data - else: - raise StopAsyncIteration - -class ACM: - async def __aenter__(self) -> int: - return 42 - - async def __aexit__(self, etype, eval, tb): - return None - - - -class A: - y: float -class B(A): - x: ClassVar[Optional['B']] = None - y: int - b: int -class CSub(B): - z: ClassVar['CSub'] = B() -class G(Generic[T]): - lst: ClassVar[List[T]] = [] - -class Loop: - attr: Final['Loop'] - -class NoneAndForward: - parent: 'NoneAndForward' - meaning: None - -class XRepr(NamedTuple): - x: int - y: int = 1 - - def __str__(self): - return f'{self.x} -> {self.y}' - - def __add__(self, other): - return 0 - -@runtime -class HasCallProtocol(Protocol): - __call__: typing.Callable - - -async def g_with(am: AsyncContextManager[int]): - x: int - async with am as x: - return x - -try: - g_with(ACM()).send(None) -except StopIteration as e: - assert e.args[0] == 42 - -Label = TypedDict('Label', [('label', str)]) - -class Point2D(TypedDict): - x: int - y: int - -class Point2Dor3D(Point2D, total=False): - z: int - -class LabelPoint2D(Point2D, Label): ... - -class Options(TypedDict, total=False): - log_level: int - log_path: str - -class BaseAnimal(TypedDict): - name: str - -class Animal(BaseAnimal, total=False): - voice: str - tail: bool - -class Cat(Animal): - fur_color: str - -class TotalMovie(TypedDict): - title: str - year: NotRequired[int] - -class NontotalMovie(TypedDict, total=False): - title: Required[str] - year: int - -class AnnotatedMovie(TypedDict): - title: Annotated[Required[str], "foobar"] - year: NotRequired[Annotated[int, 2000]] - - -gth = get_type_hints - - -class GetTypeHintTests(BaseTestCase): - def test_get_type_hints_modules(self): - ann_module_type_hints = {1: 2, 'f': Tuple[int, int], 'x': int, 'y': str} - if (TYPING_3_11_0 - or (TYPING_3_10_0 and sys.version_info.releaselevel in {'candidate', 'final'})): - # More tests were added in 3.10rc1. - ann_module_type_hints['u'] = int | float - self.assertEqual(gth(ann_module), ann_module_type_hints) - self.assertEqual(gth(ann_module2), {}) - self.assertEqual(gth(ann_module3), {}) - - def test_get_type_hints_classes(self): - self.assertEqual(gth(ann_module.C, ann_module.__dict__), - {'y': Optional[ann_module.C]}) - self.assertIsInstance(gth(ann_module.j_class), dict) - self.assertEqual(gth(ann_module.M), {'123': 123, 'o': type}) - self.assertEqual(gth(ann_module.D), - {'j': str, 'k': str, 'y': Optional[ann_module.C]}) - self.assertEqual(gth(ann_module.Y), {'z': int}) - self.assertEqual(gth(ann_module.h_class), - {'y': Optional[ann_module.C]}) - self.assertEqual(gth(ann_module.S), {'x': str, 'y': str}) - self.assertEqual(gth(ann_module.foo), {'x': int}) - self.assertEqual(gth(NoneAndForward, globals()), - {'parent': NoneAndForward, 'meaning': type(None)}) - - def test_respect_no_type_check(self): - @no_type_check - class NoTpCheck: - class Inn: - def __init__(self, x: 'not a type'): ... # noqa - self.assertTrue(NoTpCheck.__no_type_check__) - self.assertTrue(NoTpCheck.Inn.__init__.__no_type_check__) - self.assertEqual(gth(ann_module2.NTC.meth), {}) - class ABase(Generic[T]): - def meth(x: int): ... - @no_type_check - class Der(ABase): ... - self.assertEqual(gth(ABase.meth), {'x': int}) - - def test_get_type_hints_ClassVar(self): - self.assertEqual(gth(ann_module2.CV, ann_module2.__dict__), - {'var': ClassVar[ann_module2.CV]}) - self.assertEqual(gth(B, globals()), - {'y': int, 'x': ClassVar[Optional[B]], 'b': int}) - self.assertEqual(gth(CSub, globals()), - {'z': ClassVar[CSub], 'y': int, 'b': int, - 'x': ClassVar[Optional[B]]}) - self.assertEqual(gth(G), {'lst': ClassVar[List[T]]}) - - def test_final_forward_ref(self): - self.assertEqual(gth(Loop, globals())['attr'], Final[Loop]) - self.assertNotEqual(gth(Loop, globals())['attr'], Final[int]) - self.assertNotEqual(gth(Loop, globals())['attr'], Final) - - -class GetUtilitiesTestCase(TestCase): - def test_get_origin(self): - T = TypeVar('T') - P = ParamSpec('P') - Ts = TypeVarTuple('Ts') - class C(Generic[T]): pass - self.assertIs(get_origin(C[int]), C) - self.assertIs(get_origin(C[T]), C) - self.assertIs(get_origin(int), None) - self.assertIs(get_origin(ClassVar[int]), ClassVar) - self.assertIs(get_origin(Union[int, str]), Union) - self.assertIs(get_origin(Literal[42, 43]), Literal) - self.assertIs(get_origin(Final[List[int]]), Final) - self.assertIs(get_origin(Generic), Generic) - self.assertIs(get_origin(Generic[T]), Generic) - self.assertIs(get_origin(List[Tuple[T, T]][int]), list) - self.assertIs(get_origin(Annotated[T, 'thing']), Annotated) - self.assertIs(get_origin(List), list) - self.assertIs(get_origin(Tuple), tuple) - self.assertIs(get_origin(Callable), collections.abc.Callable) - if sys.version_info >= (3, 9): - self.assertIs(get_origin(list[int]), list) - self.assertIs(get_origin(list), None) - self.assertIs(get_origin(P.args), P) - self.assertIs(get_origin(P.kwargs), P) - self.assertIs(get_origin(Required[int]), Required) - self.assertIs(get_origin(NotRequired[int]), NotRequired) - self.assertIs(get_origin(Unpack[Ts]), Unpack) - self.assertIs(get_origin(Unpack), None) - - def test_get_args(self): - T = TypeVar('T') - Ts = TypeVarTuple('Ts') - class C(Generic[T]): pass - self.assertEqual(get_args(C[int]), (int,)) - self.assertEqual(get_args(C[T]), (T,)) - self.assertEqual(get_args(int), ()) - self.assertEqual(get_args(ClassVar[int]), (int,)) - self.assertEqual(get_args(Union[int, str]), (int, str)) - self.assertEqual(get_args(Literal[42, 43]), (42, 43)) - self.assertEqual(get_args(Final[List[int]]), (List[int],)) - self.assertEqual(get_args(Union[int, Tuple[T, int]][str]), - (int, Tuple[str, int])) - self.assertEqual(get_args(typing.Dict[int, Tuple[T, T]][Optional[int]]), - (int, Tuple[Optional[int], Optional[int]])) - self.assertEqual(get_args(Callable[[], T][int]), ([], int)) - self.assertEqual(get_args(Callable[..., int]), (..., int)) - self.assertEqual(get_args(Union[int, Callable[[Tuple[T, ...]], str]]), - (int, Callable[[Tuple[T, ...]], str])) - self.assertEqual(get_args(Tuple[int, ...]), (int, ...)) - if TYPING_3_11_0: - self.assertEqual(get_args(Tuple[()]), ()) - else: - self.assertEqual(get_args(Tuple[()]), ((),)) - self.assertEqual(get_args(Annotated[T, 'one', 2, ['three']]), (T, 'one', 2, ['three'])) - self.assertEqual(get_args(List), ()) - self.assertEqual(get_args(Tuple), ()) - self.assertEqual(get_args(Callable), ()) - if sys.version_info >= (3, 9): - self.assertEqual(get_args(list[int]), (int,)) - self.assertEqual(get_args(list), ()) - if sys.version_info >= (3, 9): - # Support Python versions with and without the fix for - # https://bugs.python.org/issue42195 - # The first variant is for 3.9.2+, the second for 3.9.0 and 1 - self.assertIn(get_args(collections.abc.Callable[[int], str]), - (([int], str), ([[int]], str))) - self.assertIn(get_args(collections.abc.Callable[[], str]), - (([], str), ([[]], str))) - self.assertEqual(get_args(collections.abc.Callable[..., str]), (..., str)) - P = ParamSpec('P') - # In 3.9 and lower we use typing_extensions's hacky implementation - # of ParamSpec, which gets incorrectly wrapped in a list - self.assertIn(get_args(Callable[P, int]), [(P, int), ([P], int)]) - self.assertEqual(get_args(Callable[Concatenate[int, P], int]), - (Concatenate[int, P], int)) - self.assertEqual(get_args(Required[int]), (int,)) - self.assertEqual(get_args(NotRequired[int]), (int,)) - self.assertEqual(get_args(Unpack[Ts]), (Ts,)) - self.assertEqual(get_args(Unpack), ()) - - -class CollectionsAbcTests(BaseTestCase): - - def test_isinstance_collections(self): - self.assertNotIsInstance(1, collections.abc.Mapping) - self.assertNotIsInstance(1, collections.abc.Iterable) - self.assertNotIsInstance(1, collections.abc.Container) - self.assertNotIsInstance(1, collections.abc.Sized) - with self.assertRaises(TypeError): - isinstance(collections.deque(), typing_extensions.Deque[int]) - with self.assertRaises(TypeError): - issubclass(collections.Counter, typing_extensions.Counter[str]) - - def test_awaitable(self): - ns = {} - exec( - "async def foo() -> typing_extensions.Awaitable[int]:\n" - " return await AwaitableWrapper(42)\n", - globals(), ns) - foo = ns['foo'] - g = foo() - self.assertIsInstance(g, typing_extensions.Awaitable) - self.assertNotIsInstance(foo, typing_extensions.Awaitable) - g.send(None) # Run foo() till completion, to avoid warning. - - def test_coroutine(self): - ns = {} - exec( - "async def foo():\n" - " return\n", - globals(), ns) - foo = ns['foo'] - g = foo() - self.assertIsInstance(g, typing_extensions.Coroutine) - with self.assertRaises(TypeError): - isinstance(g, typing_extensions.Coroutine[int]) - self.assertNotIsInstance(foo, typing_extensions.Coroutine) - try: - g.send(None) - except StopIteration: - pass - - def test_async_iterable(self): - base_it = range(10) # type: Iterator[int] - it = AsyncIteratorWrapper(base_it) - self.assertIsInstance(it, typing_extensions.AsyncIterable) - self.assertIsInstance(it, typing_extensions.AsyncIterable) - self.assertNotIsInstance(42, typing_extensions.AsyncIterable) - - def test_async_iterator(self): - base_it = range(10) # type: Iterator[int] - it = AsyncIteratorWrapper(base_it) - self.assertIsInstance(it, typing_extensions.AsyncIterator) - self.assertNotIsInstance(42, typing_extensions.AsyncIterator) - - def test_deque(self): - self.assertIsSubclass(collections.deque, typing_extensions.Deque) - class MyDeque(typing_extensions.Deque[int]): ... - self.assertIsInstance(MyDeque(), collections.deque) - - def test_counter(self): - self.assertIsSubclass(collections.Counter, typing_extensions.Counter) - - def test_defaultdict_instantiation(self): - self.assertIs( - type(typing_extensions.DefaultDict()), - collections.defaultdict) - self.assertIs( - type(typing_extensions.DefaultDict[KT, VT]()), - collections.defaultdict) - self.assertIs( - type(typing_extensions.DefaultDict[str, int]()), - collections.defaultdict) - - def test_defaultdict_subclass(self): - - class MyDefDict(typing_extensions.DefaultDict[str, int]): - pass - - dd = MyDefDict() - self.assertIsInstance(dd, MyDefDict) - - self.assertIsSubclass(MyDefDict, collections.defaultdict) - self.assertNotIsSubclass(collections.defaultdict, MyDefDict) - - def test_ordereddict_instantiation(self): - self.assertIs( - type(typing_extensions.OrderedDict()), - collections.OrderedDict) - self.assertIs( - type(typing_extensions.OrderedDict[KT, VT]()), - collections.OrderedDict) - self.assertIs( - type(typing_extensions.OrderedDict[str, int]()), - collections.OrderedDict) - - def test_ordereddict_subclass(self): - - class MyOrdDict(typing_extensions.OrderedDict[str, int]): - pass - - od = MyOrdDict() - self.assertIsInstance(od, MyOrdDict) - - self.assertIsSubclass(MyOrdDict, collections.OrderedDict) - self.assertNotIsSubclass(collections.OrderedDict, MyOrdDict) - - def test_chainmap_instantiation(self): - self.assertIs(type(typing_extensions.ChainMap()), collections.ChainMap) - self.assertIs(type(typing_extensions.ChainMap[KT, VT]()), collections.ChainMap) - self.assertIs(type(typing_extensions.ChainMap[str, int]()), collections.ChainMap) - class CM(typing_extensions.ChainMap[KT, VT]): ... - self.assertIs(type(CM[int, str]()), CM) - - def test_chainmap_subclass(self): - - class MyChainMap(typing_extensions.ChainMap[str, int]): - pass - - cm = MyChainMap() - self.assertIsInstance(cm, MyChainMap) - - self.assertIsSubclass(MyChainMap, collections.ChainMap) - self.assertNotIsSubclass(collections.ChainMap, MyChainMap) - - def test_deque_instantiation(self): - self.assertIs(type(typing_extensions.Deque()), collections.deque) - self.assertIs(type(typing_extensions.Deque[T]()), collections.deque) - self.assertIs(type(typing_extensions.Deque[int]()), collections.deque) - class D(typing_extensions.Deque[T]): ... - self.assertIs(type(D[int]()), D) - - def test_counter_instantiation(self): - self.assertIs(type(typing_extensions.Counter()), collections.Counter) - self.assertIs(type(typing_extensions.Counter[T]()), collections.Counter) - self.assertIs(type(typing_extensions.Counter[int]()), collections.Counter) - class C(typing_extensions.Counter[T]): ... - self.assertIs(type(C[int]()), C) - self.assertEqual(C.__bases__, (collections.Counter, typing.Generic)) - - def test_counter_subclass_instantiation(self): - - class MyCounter(typing_extensions.Counter[int]): - pass - - d = MyCounter() - self.assertIsInstance(d, MyCounter) - self.assertIsInstance(d, collections.Counter) - self.assertIsInstance(d, typing_extensions.Counter) - - def test_async_generator(self): - ns = {} - exec("async def f():\n" - " yield 42\n", globals(), ns) - g = ns['f']() - self.assertIsSubclass(type(g), typing_extensions.AsyncGenerator) - - def test_no_async_generator_instantiation(self): - with self.assertRaises(TypeError): - typing_extensions.AsyncGenerator() - with self.assertRaises(TypeError): - typing_extensions.AsyncGenerator[T, T]() - with self.assertRaises(TypeError): - typing_extensions.AsyncGenerator[int, int]() - - def test_subclassing_async_generator(self): - class G(typing_extensions.AsyncGenerator[int, int]): - def asend(self, value): - pass - def athrow(self, typ, val=None, tb=None): - pass - - ns = {} - exec('async def g(): yield 0', globals(), ns) - g = ns['g'] - self.assertIsSubclass(G, typing_extensions.AsyncGenerator) - self.assertIsSubclass(G, typing_extensions.AsyncIterable) - self.assertIsSubclass(G, collections.abc.AsyncGenerator) - self.assertIsSubclass(G, collections.abc.AsyncIterable) - self.assertNotIsSubclass(type(g), G) - - instance = G() - self.assertIsInstance(instance, typing_extensions.AsyncGenerator) - self.assertIsInstance(instance, typing_extensions.AsyncIterable) - self.assertIsInstance(instance, collections.abc.AsyncGenerator) - self.assertIsInstance(instance, collections.abc.AsyncIterable) - self.assertNotIsInstance(type(g), G) - self.assertNotIsInstance(g, G) - - -class OtherABCTests(BaseTestCase): - - def test_contextmanager(self): - @contextlib.contextmanager - def manager(): - yield 42 - - cm = manager() - self.assertIsInstance(cm, typing_extensions.ContextManager) - self.assertNotIsInstance(42, typing_extensions.ContextManager) - - def test_async_contextmanager(self): - class NotACM: - pass - self.assertIsInstance(ACM(), typing_extensions.AsyncContextManager) - self.assertNotIsInstance(NotACM(), typing_extensions.AsyncContextManager) - @contextlib.contextmanager - def manager(): - yield 42 - - cm = manager() - self.assertNotIsInstance(cm, typing_extensions.AsyncContextManager) - self.assertEqual(typing_extensions.AsyncContextManager[int].__args__, (int,)) - with self.assertRaises(TypeError): - isinstance(42, typing_extensions.AsyncContextManager[int]) - with self.assertRaises(TypeError): - typing_extensions.AsyncContextManager[int, str] - - -class TypeTests(BaseTestCase): - - def test_type_basic(self): - - class User: pass - class BasicUser(User): pass - class ProUser(User): pass - - def new_user(user_class: Type[User]) -> User: - return user_class() - - new_user(BasicUser) - - def test_type_typevar(self): - - class User: pass - class BasicUser(User): pass - class ProUser(User): pass - - U = TypeVar('U', bound=User) - - def new_user(user_class: Type[U]) -> U: - return user_class() - - new_user(BasicUser) - - def test_type_optional(self): - A = Optional[Type[BaseException]] - - def foo(a: A) -> Optional[BaseException]: - if a is None: - return None - else: - return a() - - assert isinstance(foo(KeyboardInterrupt), KeyboardInterrupt) - assert foo(None) is None - - -class NewTypeTests(BaseTestCase): - - def test_basic(self): - UserId = NewType('UserId', int) - UserName = NewType('UserName', str) - self.assertIsInstance(UserId(5), int) - self.assertIsInstance(UserName('Joe'), str) - self.assertEqual(UserId(5) + 1, 6) - - def test_errors(self): - UserId = NewType('UserId', int) - UserName = NewType('UserName', str) - with self.assertRaises(TypeError): - issubclass(UserId, int) - with self.assertRaises(TypeError): - class D(UserName): - pass - - -class Coordinate(Protocol): - x: int - y: int - -@runtime -class Point(Coordinate, Protocol): - label: str - -class MyPoint: - x: int - y: int - label: str - -class XAxis(Protocol): - x: int - -class YAxis(Protocol): - y: int - -@runtime -class Position(XAxis, YAxis, Protocol): - pass - -@runtime -class Proto(Protocol): - attr: int - - def meth(self, arg: str) -> int: - ... - -class Concrete(Proto): - pass - -class Other: - attr: int = 1 - - def meth(self, arg: str) -> int: - if arg == 'this': - return 1 - return 0 - -class NT(NamedTuple): - x: int - y: int - - -class ProtocolTests(BaseTestCase): - - def test_basic_protocol(self): - @runtime - class P(Protocol): - def meth(self): - pass - class C: pass - class D: - def meth(self): - pass - def f(): - pass - self.assertIsSubclass(D, P) - self.assertIsInstance(D(), P) - self.assertNotIsSubclass(C, P) - self.assertNotIsInstance(C(), P) - self.assertNotIsSubclass(types.FunctionType, P) - self.assertNotIsInstance(f, P) - - def test_everything_implements_empty_protocol(self): - @runtime - class Empty(Protocol): pass - class C: pass - def f(): - pass - for thing in (object, type, tuple, C, types.FunctionType): - self.assertIsSubclass(thing, Empty) - for thing in (object(), 1, (), typing, f): - self.assertIsInstance(thing, Empty) - - def test_function_implements_protocol(self): - def f(): - pass - self.assertIsInstance(f, HasCallProtocol) - - def test_no_inheritance_from_nominal(self): - class C: pass - class BP(Protocol): pass - with self.assertRaises(TypeError): - class P(C, Protocol): - pass - with self.assertRaises(TypeError): - class P(Protocol, C): - pass - with self.assertRaises(TypeError): - class P(BP, C, Protocol): - pass - class D(BP, C): pass - class E(C, BP): pass - self.assertNotIsInstance(D(), E) - self.assertNotIsInstance(E(), D) - - def test_no_instantiation(self): - class P(Protocol): pass - with self.assertRaises(TypeError): - P() - class C(P): pass - self.assertIsInstance(C(), C) - T = TypeVar('T') - class PG(Protocol[T]): pass - with self.assertRaises(TypeError): - PG() - with self.assertRaises(TypeError): - PG[int]() - with self.assertRaises(TypeError): - PG[T]() - class CG(PG[T]): pass - self.assertIsInstance(CG[int](), CG) - - def test_cannot_instantiate_abstract(self): - @runtime - class P(Protocol): - @abc.abstractmethod - def ameth(self) -> int: - raise NotImplementedError - class B(P): - pass - class C(B): - def ameth(self) -> int: - return 26 - with self.assertRaises(TypeError): - B() - self.assertIsInstance(C(), P) - - def test_subprotocols_extending(self): - class P1(Protocol): - def meth1(self): - pass - @runtime - class P2(P1, Protocol): - def meth2(self): - pass - class C: - def meth1(self): - pass - def meth2(self): - pass - class C1: - def meth1(self): - pass - class C2: - def meth2(self): - pass - self.assertNotIsInstance(C1(), P2) - self.assertNotIsInstance(C2(), P2) - self.assertNotIsSubclass(C1, P2) - self.assertNotIsSubclass(C2, P2) - self.assertIsInstance(C(), P2) - self.assertIsSubclass(C, P2) - - def test_subprotocols_merging(self): - class P1(Protocol): - def meth1(self): - pass - class P2(Protocol): - def meth2(self): - pass - @runtime - class P(P1, P2, Protocol): - pass - class C: - def meth1(self): - pass - def meth2(self): - pass - class C1: - def meth1(self): - pass - class C2: - def meth2(self): - pass - self.assertNotIsInstance(C1(), P) - self.assertNotIsInstance(C2(), P) - self.assertNotIsSubclass(C1, P) - self.assertNotIsSubclass(C2, P) - self.assertIsInstance(C(), P) - self.assertIsSubclass(C, P) - - def test_protocols_issubclass(self): - T = TypeVar('T') - @runtime - class P(Protocol): - def x(self): ... - @runtime - class PG(Protocol[T]): - def x(self): ... - class BadP(Protocol): - def x(self): ... - class BadPG(Protocol[T]): - def x(self): ... - class C: - def x(self): ... - self.assertIsSubclass(C, P) - self.assertIsSubclass(C, PG) - self.assertIsSubclass(BadP, PG) - with self.assertRaises(TypeError): - issubclass(C, PG[T]) - with self.assertRaises(TypeError): - issubclass(C, PG[C]) - with self.assertRaises(TypeError): - issubclass(C, BadP) - with self.assertRaises(TypeError): - issubclass(C, BadPG) - with self.assertRaises(TypeError): - issubclass(P, PG[T]) - with self.assertRaises(TypeError): - issubclass(PG, PG[int]) - - def test_protocols_issubclass_non_callable(self): - class C: - x = 1 - @runtime - class PNonCall(Protocol): - x = 1 - with self.assertRaises(TypeError): - issubclass(C, PNonCall) - self.assertIsInstance(C(), PNonCall) - PNonCall.register(C) - with self.assertRaises(TypeError): - issubclass(C, PNonCall) - self.assertIsInstance(C(), PNonCall) - # check that non-protocol subclasses are not affected - class D(PNonCall): ... - self.assertNotIsSubclass(C, D) - self.assertNotIsInstance(C(), D) - D.register(C) - self.assertIsSubclass(C, D) - self.assertIsInstance(C(), D) - with self.assertRaises(TypeError): - issubclass(D, PNonCall) - - def test_protocols_isinstance(self): - T = TypeVar('T') - @runtime - class P(Protocol): - def meth(x): ... - @runtime - class PG(Protocol[T]): - def meth(x): ... - class BadP(Protocol): - def meth(x): ... - class BadPG(Protocol[T]): - def meth(x): ... - class C: - def meth(x): ... - self.assertIsInstance(C(), P) - self.assertIsInstance(C(), PG) - with self.assertRaises(TypeError): - isinstance(C(), PG[T]) - with self.assertRaises(TypeError): - isinstance(C(), PG[C]) - with self.assertRaises(TypeError): - isinstance(C(), BadP) - with self.assertRaises(TypeError): - isinstance(C(), BadPG) - - def test_protocols_isinstance_py36(self): - class APoint: - def __init__(self, x, y, label): - self.x = x - self.y = y - self.label = label - class BPoint: - label = 'B' - def __init__(self, x, y): - self.x = x - self.y = y - class C: - def __init__(self, attr): - self.attr = attr - def meth(self, arg): - return 0 - class Bad: pass - self.assertIsInstance(APoint(1, 2, 'A'), Point) - self.assertIsInstance(BPoint(1, 2), Point) - self.assertNotIsInstance(MyPoint(), Point) - self.assertIsInstance(BPoint(1, 2), Position) - self.assertIsInstance(Other(), Proto) - self.assertIsInstance(Concrete(), Proto) - self.assertIsInstance(C(42), Proto) - self.assertNotIsInstance(Bad(), Proto) - self.assertNotIsInstance(Bad(), Point) - self.assertNotIsInstance(Bad(), Position) - self.assertNotIsInstance(Bad(), Concrete) - self.assertNotIsInstance(Other(), Concrete) - self.assertIsInstance(NT(1, 2), Position) - - def test_protocols_isinstance_init(self): - T = TypeVar('T') - @runtime - class P(Protocol): - x = 1 - @runtime - class PG(Protocol[T]): - x = 1 - class C: - def __init__(self, x): - self.x = x - self.assertIsInstance(C(1), P) - self.assertIsInstance(C(1), PG) - - def test_protocols_support_register(self): - @runtime - class P(Protocol): - x = 1 - class PM(Protocol): - def meth(self): pass - class D(PM): pass - class C: pass - D.register(C) - P.register(C) - self.assertIsInstance(C(), P) - self.assertIsInstance(C(), D) - - def test_none_on_non_callable_doesnt_block_implementation(self): - @runtime - class P(Protocol): - x = 1 - class A: - x = 1 - class B(A): - x = None - class C: - def __init__(self): - self.x = None - self.assertIsInstance(B(), P) - self.assertIsInstance(C(), P) - - def test_none_on_callable_blocks_implementation(self): - @runtime - class P(Protocol): - def x(self): ... - class A: - def x(self): ... - class B(A): - x = None - class C: - def __init__(self): - self.x = None - self.assertNotIsInstance(B(), P) - self.assertNotIsInstance(C(), P) - - def test_non_protocol_subclasses(self): - class P(Protocol): - x = 1 - @runtime - class PR(Protocol): - def meth(self): pass - class NonP(P): - x = 1 - class NonPR(PR): pass - class C: - x = 1 - class D: - def meth(self): pass - self.assertNotIsInstance(C(), NonP) - self.assertNotIsInstance(D(), NonPR) - self.assertNotIsSubclass(C, NonP) - self.assertNotIsSubclass(D, NonPR) - self.assertIsInstance(NonPR(), PR) - self.assertIsSubclass(NonPR, PR) - - def test_custom_subclasshook(self): - class P(Protocol): - x = 1 - class OKClass: pass - class BadClass: - x = 1 - class C(P): - @classmethod - def __subclasshook__(cls, other): - return other.__name__.startswith("OK") - self.assertIsInstance(OKClass(), C) - self.assertNotIsInstance(BadClass(), C) - self.assertIsSubclass(OKClass, C) - self.assertNotIsSubclass(BadClass, C) - - def test_issubclass_fails_correctly(self): - @runtime - class P(Protocol): - x = 1 - class C: pass - with self.assertRaises(TypeError): - issubclass(C(), P) - - def test_defining_generic_protocols(self): - T = TypeVar('T') - S = TypeVar('S') - @runtime - class PR(Protocol[T, S]): - def meth(self): pass - class P(PR[int, T], Protocol[T]): - y = 1 - with self.assertRaises(TypeError): - issubclass(PR[int, T], PR) - with self.assertRaises(TypeError): - issubclass(P[str], PR) - with self.assertRaises(TypeError): - PR[int] - with self.assertRaises(TypeError): - P[int, str] - if not TYPING_3_10_0: - with self.assertRaises(TypeError): - PR[int, 1] - with self.assertRaises(TypeError): - PR[int, ClassVar] - class C(PR[int, T]): pass - self.assertIsInstance(C[str](), C) - - def test_defining_generic_protocols_old_style(self): - T = TypeVar('T') - S = TypeVar('S') - @runtime - class PR(Protocol, Generic[T, S]): - def meth(self): pass - class P(PR[int, str], Protocol): - y = 1 - with self.assertRaises(TypeError): - self.assertIsSubclass(PR[int, str], PR) - self.assertIsSubclass(P, PR) - with self.assertRaises(TypeError): - PR[int] - if not TYPING_3_10_0: - with self.assertRaises(TypeError): - PR[int, 1] - class P1(Protocol, Generic[T]): - def bar(self, x: T) -> str: ... - class P2(Generic[T], Protocol): - def bar(self, x: T) -> str: ... - @runtime - class PSub(P1[str], Protocol): - x = 1 - class Test: - x = 1 - def bar(self, x: str) -> str: - return x - self.assertIsInstance(Test(), PSub) - if not TYPING_3_10_0: - with self.assertRaises(TypeError): - PR[int, ClassVar] - - def test_init_called(self): - T = TypeVar('T') - class P(Protocol[T]): pass - class C(P[T]): - def __init__(self): - self.test = 'OK' - self.assertEqual(C[int]().test, 'OK') - - def test_protocols_bad_subscripts(self): - T = TypeVar('T') - S = TypeVar('S') - with self.assertRaises(TypeError): - class P(Protocol[T, T]): pass - with self.assertRaises(TypeError): - class P(Protocol[int]): pass - with self.assertRaises(TypeError): - class P(Protocol[T], Protocol[S]): pass - with self.assertRaises(TypeError): - class P(typing.Mapping[T, S], Protocol[T]): pass - - def test_generic_protocols_repr(self): - T = TypeVar('T') - S = TypeVar('S') - class P(Protocol[T, S]): pass - self.assertTrue(repr(P[T, S]).endswith('P[~T, ~S]')) - self.assertTrue(repr(P[int, str]).endswith('P[int, str]')) - - def test_generic_protocols_eq(self): - T = TypeVar('T') - S = TypeVar('S') - class P(Protocol[T, S]): pass - self.assertEqual(P, P) - self.assertEqual(P[int, T], P[int, T]) - self.assertEqual(P[T, T][Tuple[T, S]][int, str], - P[Tuple[int, str], Tuple[int, str]]) - - def test_generic_protocols_special_from_generic(self): - T = TypeVar('T') - class P(Protocol[T]): pass - self.assertEqual(P.__parameters__, (T,)) - self.assertEqual(P[int].__parameters__, ()) - self.assertEqual(P[int].__args__, (int,)) - self.assertIs(P[int].__origin__, P) - - def test_generic_protocols_special_from_protocol(self): - @runtime - class PR(Protocol): - x = 1 - class P(Protocol): - def meth(self): - pass - T = TypeVar('T') - class PG(Protocol[T]): - x = 1 - def meth(self): - pass - self.assertTrue(P._is_protocol) - self.assertTrue(PR._is_protocol) - self.assertTrue(PG._is_protocol) - if hasattr(typing, 'Protocol'): - self.assertFalse(P._is_runtime_protocol) - else: - with self.assertRaises(AttributeError): - self.assertFalse(P._is_runtime_protocol) - self.assertTrue(PR._is_runtime_protocol) - self.assertTrue(PG[int]._is_protocol) - self.assertEqual(typing_extensions._get_protocol_attrs(P), {'meth'}) - self.assertEqual(typing_extensions._get_protocol_attrs(PR), {'x'}) - self.assertEqual(frozenset(typing_extensions._get_protocol_attrs(PG)), - frozenset({'x', 'meth'})) - - def test_no_runtime_deco_on_nominal(self): - with self.assertRaises(TypeError): - @runtime - class C: pass - class Proto(Protocol): - x = 1 - with self.assertRaises(TypeError): - @runtime - class Concrete(Proto): - pass - - def test_none_treated_correctly(self): - @runtime - class P(Protocol): - x = None # type: int - class B(object): pass - self.assertNotIsInstance(B(), P) - class C: - x = 1 - class D: - x = None - self.assertIsInstance(C(), P) - self.assertIsInstance(D(), P) - class CI: - def __init__(self): - self.x = 1 - class DI: - def __init__(self): - self.x = None - self.assertIsInstance(C(), P) - self.assertIsInstance(D(), P) - - def test_protocols_in_unions(self): - class P(Protocol): - x = None # type: int - Alias = typing.Union[typing.Iterable, P] - Alias2 = typing.Union[P, typing.Iterable] - self.assertEqual(Alias, Alias2) - - def test_protocols_pickleable(self): - global P, CP # pickle wants to reference the class by name - T = TypeVar('T') - - @runtime - class P(Protocol[T]): - x = 1 - class CP(P[int]): - pass - - c = CP() - c.foo = 42 - c.bar = 'abc' - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - z = pickle.dumps(c, proto) - x = pickle.loads(z) - self.assertEqual(x.foo, 42) - self.assertEqual(x.bar, 'abc') - self.assertEqual(x.x, 1) - self.assertEqual(x.__dict__, {'foo': 42, 'bar': 'abc'}) - s = pickle.dumps(P) - D = pickle.loads(s) - class E: - x = 1 - self.assertIsInstance(E(), D) - - def test_collections_protocols_allowed(self): - @runtime_checkable - class Custom(collections.abc.Iterable, Protocol): - def close(self): pass - - class A: ... - class B: - def __iter__(self): - return [] - def close(self): - return 0 - - self.assertIsSubclass(B, Custom) - self.assertNotIsSubclass(A, Custom) - - def test_no_init_same_for_different_protocol_implementations(self): - class CustomProtocolWithoutInitA(Protocol): - pass - - class CustomProtocolWithoutInitB(Protocol): - pass - - self.assertEqual(CustomProtocolWithoutInitA.__init__, CustomProtocolWithoutInitB.__init__) - - -class TypedDictTests(BaseTestCase): - - def test_basics_iterable_syntax(self): - Emp = TypedDict('Emp', {'name': str, 'id': int}) - self.assertIsSubclass(Emp, dict) - self.assertIsSubclass(Emp, typing.MutableMapping) - self.assertNotIsSubclass(Emp, collections.abc.Sequence) - jim = Emp(name='Jim', id=1) - self.assertIs(type(jim), dict) - self.assertEqual(jim['name'], 'Jim') - self.assertEqual(jim['id'], 1) - self.assertEqual(Emp.__name__, 'Emp') - self.assertEqual(Emp.__module__, __name__) - self.assertEqual(Emp.__bases__, (dict,)) - self.assertEqual(Emp.__annotations__, {'name': str, 'id': int}) - self.assertEqual(Emp.__total__, True) - - def test_basics_keywords_syntax(self): - Emp = TypedDict('Emp', name=str, id=int) - self.assertIsSubclass(Emp, dict) - self.assertIsSubclass(Emp, typing.MutableMapping) - self.assertNotIsSubclass(Emp, collections.abc.Sequence) - jim = Emp(name='Jim', id=1) - self.assertIs(type(jim), dict) - self.assertEqual(jim['name'], 'Jim') - self.assertEqual(jim['id'], 1) - self.assertEqual(Emp.__name__, 'Emp') - self.assertEqual(Emp.__module__, __name__) - self.assertEqual(Emp.__bases__, (dict,)) - self.assertEqual(Emp.__annotations__, {'name': str, 'id': int}) - self.assertEqual(Emp.__total__, True) - - def test_typeddict_special_keyword_names(self): - TD = TypedDict("TD", cls=type, self=object, typename=str, _typename=int, - fields=list, _fields=dict) - self.assertEqual(TD.__name__, 'TD') - self.assertEqual(TD.__annotations__, {'cls': type, 'self': object, 'typename': str, - '_typename': int, 'fields': list, '_fields': dict}) - a = TD(cls=str, self=42, typename='foo', _typename=53, - fields=[('bar', tuple)], _fields={'baz', set}) - self.assertEqual(a['cls'], str) - self.assertEqual(a['self'], 42) - self.assertEqual(a['typename'], 'foo') - self.assertEqual(a['_typename'], 53) - self.assertEqual(a['fields'], [('bar', tuple)]) - self.assertEqual(a['_fields'], {'baz', set}) - - @skipIf(hasattr(typing, 'TypedDict'), "Should be tested by upstream") - def test_typeddict_create_errors(self): - with self.assertRaises(TypeError): - TypedDict.__new__() - with self.assertRaises(TypeError): - TypedDict() - with self.assertRaises(TypeError): - TypedDict('Emp', [('name', str)], None) - - with self.assertWarns(DeprecationWarning): - Emp = TypedDict(_typename='Emp', name=str, id=int) - self.assertEqual(Emp.__name__, 'Emp') - self.assertEqual(Emp.__annotations__, {'name': str, 'id': int}) - - with self.assertWarns(DeprecationWarning): - Emp = TypedDict('Emp', _fields={'name': str, 'id': int}) - self.assertEqual(Emp.__name__, 'Emp') - self.assertEqual(Emp.__annotations__, {'name': str, 'id': int}) - - def test_typeddict_errors(self): - Emp = TypedDict('Emp', {'name': str, 'id': int}) - if hasattr(typing, "Required"): - self.assertEqual(TypedDict.__module__, 'typing') - else: - self.assertEqual(TypedDict.__module__, 'typing_extensions') - jim = Emp(name='Jim', id=1) - with self.assertRaises(TypeError): - isinstance({}, Emp) - with self.assertRaises(TypeError): - isinstance(jim, Emp) - with self.assertRaises(TypeError): - issubclass(dict, Emp) - - if not TYPING_3_11_0: - with self.assertRaises(TypeError): - TypedDict('Hi', x=1) - with self.assertRaises(TypeError): - TypedDict('Hi', [('x', int), ('y', 1)]) - with self.assertRaises(TypeError): - TypedDict('Hi', [('x', int)], y=int) - - def test_py36_class_syntax_usage(self): - self.assertEqual(LabelPoint2D.__name__, 'LabelPoint2D') - self.assertEqual(LabelPoint2D.__module__, __name__) - self.assertEqual(get_type_hints(LabelPoint2D), {'x': int, 'y': int, 'label': str}) - self.assertEqual(LabelPoint2D.__bases__, (dict,)) - self.assertEqual(LabelPoint2D.__total__, True) - self.assertNotIsSubclass(LabelPoint2D, typing.Sequence) - not_origin = Point2D(x=0, y=1) - self.assertEqual(not_origin['x'], 0) - self.assertEqual(not_origin['y'], 1) - other = LabelPoint2D(x=0, y=1, label='hi') - self.assertEqual(other['label'], 'hi') - - def test_pickle(self): - global EmpD # pickle wants to reference the class by name - EmpD = TypedDict('EmpD', name=str, id=int) - jane = EmpD({'name': 'jane', 'id': 37}) - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - z = pickle.dumps(jane, proto) - jane2 = pickle.loads(z) - self.assertEqual(jane2, jane) - self.assertEqual(jane2, {'name': 'jane', 'id': 37}) - ZZ = pickle.dumps(EmpD, proto) - EmpDnew = pickle.loads(ZZ) - self.assertEqual(EmpDnew({'name': 'jane', 'id': 37}), jane) - - def test_optional(self): - EmpD = TypedDict('EmpD', name=str, id=int) - - self.assertEqual(typing.Optional[EmpD], typing.Union[None, EmpD]) - self.assertNotEqual(typing.List[EmpD], typing.Tuple[EmpD]) - - def test_total(self): - D = TypedDict('D', {'x': int}, total=False) - self.assertEqual(D(), {}) - self.assertEqual(D(x=1), {'x': 1}) - self.assertEqual(D.__total__, False) - self.assertEqual(D.__required_keys__, frozenset()) - self.assertEqual(D.__optional_keys__, {'x'}) - - self.assertEqual(Options(), {}) - self.assertEqual(Options(log_level=2), {'log_level': 2}) - self.assertEqual(Options.__total__, False) - self.assertEqual(Options.__required_keys__, frozenset()) - self.assertEqual(Options.__optional_keys__, {'log_level', 'log_path'}) - - def test_optional_keys(self): - assert Point2Dor3D.__required_keys__ == frozenset(['x', 'y']) - assert Point2Dor3D.__optional_keys__ == frozenset(['z']) - - def test_required_notrequired_keys(self): - assert NontotalMovie.__required_keys__ == frozenset({'title'}) - assert NontotalMovie.__optional_keys__ == frozenset({'year'}) - - assert TotalMovie.__required_keys__ == frozenset({'title'}) - assert TotalMovie.__optional_keys__ == frozenset({'year'}) - - - def test_keys_inheritance(self): - assert BaseAnimal.__required_keys__ == frozenset(['name']) - assert BaseAnimal.__optional_keys__ == frozenset([]) - assert get_type_hints(BaseAnimal) == {'name': str} - - assert Animal.__required_keys__ == frozenset(['name']) - assert Animal.__optional_keys__ == frozenset(['tail', 'voice']) - assert get_type_hints(Animal) == { - 'name': str, - 'tail': bool, - 'voice': str, - } - - assert Cat.__required_keys__ == frozenset(['name', 'fur_color']) - assert Cat.__optional_keys__ == frozenset(['tail', 'voice']) - assert get_type_hints(Cat) == { - 'fur_color': str, - 'name': str, - 'tail': bool, - 'voice': str, - } - - def test_is_typeddict(self): - assert is_typeddict(Point2D) is True - assert is_typeddict(Point2Dor3D) is True - assert is_typeddict(Union[str, int]) is False - # classes, not instances - assert is_typeddict(Point2D()) is False - - @skipUnless(TYPING_3_8_0, "Python 3.8+ required") - def test_is_typeddict_against_typeddict_from_typing(self): - Point = typing.TypedDict('Point', {'x': int, 'y': int}) - - class PointDict2D(typing.TypedDict): - x: int - y: int - - class PointDict3D(PointDict2D, total=False): - z: int - - assert is_typeddict(Point) is True - assert is_typeddict(PointDict2D) is True - assert is_typeddict(PointDict3D) is True - - -class AnnotatedTests(BaseTestCase): - - def test_repr(self): - if hasattr(typing, 'Annotated'): - mod_name = 'typing' - else: - mod_name = "typing_extensions" - self.assertEqual( - repr(Annotated[int, 4, 5]), - mod_name + ".Annotated[int, 4, 5]" - ) - self.assertEqual( - repr(Annotated[List[int], 4, 5]), - mod_name + ".Annotated[typing.List[int], 4, 5]" - ) - - def test_flatten(self): - A = Annotated[Annotated[int, 4], 5] - self.assertEqual(A, Annotated[int, 4, 5]) - self.assertEqual(A.__metadata__, (4, 5)) - self.assertEqual(A.__origin__, int) - - def test_specialize(self): - L = Annotated[List[T], "my decoration"] - LI = Annotated[List[int], "my decoration"] - self.assertEqual(L[int], Annotated[List[int], "my decoration"]) - self.assertEqual(L[int].__metadata__, ("my decoration",)) - self.assertEqual(L[int].__origin__, List[int]) - with self.assertRaises(TypeError): - LI[int] - with self.assertRaises(TypeError): - L[int, float] - - def test_hash_eq(self): - self.assertEqual(len({Annotated[int, 4, 5], Annotated[int, 4, 5]}), 1) - self.assertNotEqual(Annotated[int, 4, 5], Annotated[int, 5, 4]) - self.assertNotEqual(Annotated[int, 4, 5], Annotated[str, 4, 5]) - self.assertNotEqual(Annotated[int, 4], Annotated[int, 4, 4]) - self.assertEqual( - {Annotated[int, 4, 5], Annotated[int, 4, 5], Annotated[T, 4, 5]}, - {Annotated[int, 4, 5], Annotated[T, 4, 5]} - ) - - def test_instantiate(self): - class C: - classvar = 4 - - def __init__(self, x): - self.x = x - - def __eq__(self, other): - if not isinstance(other, C): - return NotImplemented - return other.x == self.x - - A = Annotated[C, "a decoration"] - a = A(5) - c = C(5) - self.assertEqual(a, c) - self.assertEqual(a.x, c.x) - self.assertEqual(a.classvar, c.classvar) - - def test_instantiate_generic(self): - MyCount = Annotated[typing_extensions.Counter[T], "my decoration"] - self.assertEqual(MyCount([4, 4, 5]), {4: 2, 5: 1}) - self.assertEqual(MyCount[int]([4, 4, 5]), {4: 2, 5: 1}) - - def test_cannot_instantiate_forward(self): - A = Annotated["int", (5, 6)] - with self.assertRaises(TypeError): - A(5) - - def test_cannot_instantiate_type_var(self): - A = Annotated[T, (5, 6)] - with self.assertRaises(TypeError): - A(5) - - def test_cannot_getattr_typevar(self): - with self.assertRaises(AttributeError): - Annotated[T, (5, 7)].x - - def test_attr_passthrough(self): - class C: - classvar = 4 - - A = Annotated[C, "a decoration"] - self.assertEqual(A.classvar, 4) - A.x = 5 - self.assertEqual(C.x, 5) - - @skipIf(sys.version_info[:2] in ((3, 9), (3, 10)), "Waiting for bpo-46491 bugfix.") - def test_special_form_containment(self): - class C: - classvar: Annotated[ClassVar[int], "a decoration"] = 4 - const: Annotated[Final[int], "Const"] = 4 - - if sys.version_info[:2] >= (3, 7): - self.assertEqual(get_type_hints(C, globals())["classvar"], ClassVar[int]) - self.assertEqual(get_type_hints(C, globals())["const"], Final[int]) - else: - self.assertEqual( - get_type_hints(C, globals())["classvar"], - Annotated[ClassVar[int], "a decoration"] - ) - self.assertEqual( - get_type_hints(C, globals())["const"], Annotated[Final[int], "Const"] - ) - - def test_hash_eq(self): - self.assertEqual(len({Annotated[int, 4, 5], Annotated[int, 4, 5]}), 1) - self.assertNotEqual(Annotated[int, 4, 5], Annotated[int, 5, 4]) - self.assertNotEqual(Annotated[int, 4, 5], Annotated[str, 4, 5]) - self.assertNotEqual(Annotated[int, 4], Annotated[int, 4, 4]) - self.assertEqual( - {Annotated[int, 4, 5], Annotated[int, 4, 5], Annotated[T, 4, 5]}, - {Annotated[int, 4, 5], Annotated[T, 4, 5]} - ) - - def test_cannot_subclass(self): - with self.assertRaisesRegex(TypeError, "Cannot subclass .*Annotated"): - class C(Annotated): - pass - - def test_cannot_check_instance(self): - with self.assertRaises(TypeError): - isinstance(5, Annotated[int, "positive"]) - - def test_cannot_check_subclass(self): - with self.assertRaises(TypeError): - issubclass(int, Annotated[int, "positive"]) - - def test_pickle(self): - samples = [typing.Any, typing.Union[int, str], - typing.Optional[str], Tuple[int, ...], - typing.Callable[[str], bytes], - Self, LiteralString, Never] - - for t in samples: - x = Annotated[t, "a"] - - for prot in range(pickle.HIGHEST_PROTOCOL + 1): - with self.subTest(protocol=prot, type=t): - pickled = pickle.dumps(x, prot) - restored = pickle.loads(pickled) - self.assertEqual(x, restored) - - global _Annotated_test_G - - class _Annotated_test_G(Generic[T]): - x = 1 - - G = Annotated[_Annotated_test_G[int], "A decoration"] - G.foo = 42 - G.bar = 'abc' - - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - z = pickle.dumps(G, proto) - x = pickle.loads(z) - self.assertEqual(x.foo, 42) - self.assertEqual(x.bar, 'abc') - self.assertEqual(x.x, 1) - - def test_subst(self): - dec = "a decoration" - dec2 = "another decoration" - - S = Annotated[T, dec2] - self.assertEqual(S[int], Annotated[int, dec2]) - - self.assertEqual(S[Annotated[int, dec]], Annotated[int, dec, dec2]) - L = Annotated[List[T], dec] - - self.assertEqual(L[int], Annotated[List[int], dec]) - with self.assertRaises(TypeError): - L[int, int] - - self.assertEqual(S[L[int]], Annotated[List[int], dec, dec2]) - - D = Annotated[Dict[KT, VT], dec] - self.assertEqual(D[str, int], Annotated[Dict[str, int], dec]) - with self.assertRaises(TypeError): - D[int] - - It = Annotated[int, dec] - with self.assertRaises(TypeError): - It[None] - - LI = L[int] - with self.assertRaises(TypeError): - LI[None] - - def test_annotated_in_other_types(self): - X = List[Annotated[T, 5]] - self.assertEqual(X[int], List[Annotated[int, 5]]) - - -class GetTypeHintsTests(BaseTestCase): - def test_get_type_hints(self): - def foobar(x: List['X']): ... - X = Annotated[int, (1, 10)] - self.assertEqual( - get_type_hints(foobar, globals(), locals()), - {'x': List[int]} - ) - self.assertEqual( - get_type_hints(foobar, globals(), locals(), include_extras=True), - {'x': List[Annotated[int, (1, 10)]]} - ) - BA = Tuple[Annotated[T, (1, 0)], ...] - def barfoo(x: BA): ... - self.assertEqual(get_type_hints(barfoo, globals(), locals())['x'], Tuple[T, ...]) - self.assertIs( - get_type_hints(barfoo, globals(), locals(), include_extras=True)['x'], - BA - ) - def barfoo2(x: typing.Callable[..., Annotated[List[T], "const"]], - y: typing.Union[int, Annotated[T, "mutable"]]): ... - self.assertEqual( - get_type_hints(barfoo2, globals(), locals()), - {'x': typing.Callable[..., List[T]], 'y': typing.Union[int, T]} - ) - BA2 = typing.Callable[..., List[T]] - def barfoo3(x: BA2): ... - self.assertIs( - get_type_hints(barfoo3, globals(), locals(), include_extras=True)["x"], - BA2 - ) - - def test_get_type_hints_refs(self): - - Const = Annotated[T, "Const"] - - class MySet(Generic[T]): - - def __ior__(self, other: "Const[MySet[T]]") -> "MySet[T]": - ... - - def __iand__(self, other: Const["MySet[T]"]) -> "MySet[T]": - ... - - self.assertEqual( - get_type_hints(MySet.__iand__, globals(), locals()), - {'other': MySet[T], 'return': MySet[T]} - ) - - self.assertEqual( - get_type_hints(MySet.__iand__, globals(), locals(), include_extras=True), - {'other': Const[MySet[T]], 'return': MySet[T]} - ) - - self.assertEqual( - get_type_hints(MySet.__ior__, globals(), locals()), - {'other': MySet[T], 'return': MySet[T]} - ) - - def test_get_type_hints_typeddict(self): - assert get_type_hints(TotalMovie) == {'title': str, 'year': int} - assert get_type_hints(TotalMovie, include_extras=True) == { - 'title': str, - 'year': NotRequired[int], - } - - assert get_type_hints(AnnotatedMovie) == {'title': str, 'year': int} - assert get_type_hints(AnnotatedMovie, include_extras=True) == { - 'title': Annotated[Required[str], "foobar"], - 'year': NotRequired[Annotated[int, 2000]], - } - - -class TypeAliasTests(BaseTestCase): - def test_canonical_usage_with_variable_annotation(self): - ns = {} - exec('Alias: TypeAlias = Employee', globals(), ns) - - def test_canonical_usage_with_type_comment(self): - Alias = Employee # type: TypeAlias - - def test_cannot_instantiate(self): - with self.assertRaises(TypeError): - TypeAlias() - - def test_no_isinstance(self): - with self.assertRaises(TypeError): - isinstance(42, TypeAlias) - - def test_no_issubclass(self): - with self.assertRaises(TypeError): - issubclass(Employee, TypeAlias) - - with self.assertRaises(TypeError): - issubclass(TypeAlias, Employee) - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class C(TypeAlias): - pass - - with self.assertRaises(TypeError): - class C(type(TypeAlias)): - pass - - def test_repr(self): - if hasattr(typing, 'TypeAlias'): - self.assertEqual(repr(TypeAlias), 'typing.TypeAlias') - else: - self.assertEqual(repr(TypeAlias), 'typing_extensions.TypeAlias') - - def test_cannot_subscript(self): - with self.assertRaises(TypeError): - TypeAlias[int] - -class ParamSpecTests(BaseTestCase): - - def test_basic_plain(self): - P = ParamSpec('P') - self.assertEqual(P, P) - self.assertIsInstance(P, ParamSpec) - # Should be hashable - hash(P) - - def test_repr(self): - P = ParamSpec('P') - P_co = ParamSpec('P_co', covariant=True) - P_contra = ParamSpec('P_contra', contravariant=True) - P_2 = ParamSpec('P_2') - self.assertEqual(repr(P), '~P') - self.assertEqual(repr(P_2), '~P_2') - - # Note: PEP 612 doesn't require these to be repr-ed correctly, but - # just follow CPython. - self.assertEqual(repr(P_co), '+P_co') - self.assertEqual(repr(P_contra), '-P_contra') - - def test_valid_uses(self): - P = ParamSpec('P') - T = TypeVar('T') - C1 = typing.Callable[P, int] - self.assertEqual(C1.__args__, (P, int)) - self.assertEqual(C1.__parameters__, (P,)) - C2 = typing.Callable[P, T] - self.assertEqual(C2.__args__, (P, T)) - self.assertEqual(C2.__parameters__, (P, T)) - - - # Test collections.abc.Callable too. - if sys.version_info[:2] >= (3, 9): - # Note: no tests for Callable.__parameters__ here - # because types.GenericAlias Callable is hardcoded to search - # for tp_name "TypeVar" in C. This was changed in 3.10. - C3 = collections.abc.Callable[P, int] - self.assertEqual(C3.__args__, (P, int)) - C4 = collections.abc.Callable[P, T] - self.assertEqual(C4.__args__, (P, T)) - - # ParamSpec instances should also have args and kwargs attributes. - # Note: not in dir(P) because of __class__ hacks - self.assertTrue(hasattr(P, 'args')) - self.assertTrue(hasattr(P, 'kwargs')) - - @skipIf((3, 10, 0) <= sys.version_info[:3] <= (3, 10, 2), "Needs bpo-46676.") - def test_args_kwargs(self): - P = ParamSpec('P') - P_2 = ParamSpec('P_2') - # Note: not in dir(P) because of __class__ hacks - self.assertTrue(hasattr(P, 'args')) - self.assertTrue(hasattr(P, 'kwargs')) - self.assertIsInstance(P.args, ParamSpecArgs) - self.assertIsInstance(P.kwargs, ParamSpecKwargs) - self.assertIs(P.args.__origin__, P) - self.assertIs(P.kwargs.__origin__, P) - self.assertEqual(P.args, P.args) - self.assertEqual(P.kwargs, P.kwargs) - self.assertNotEqual(P.args, P_2.args) - self.assertNotEqual(P.kwargs, P_2.kwargs) - self.assertNotEqual(P.args, P.kwargs) - self.assertNotEqual(P.kwargs, P.args) - self.assertNotEqual(P.args, P_2.kwargs) - self.assertEqual(repr(P.args), "P.args") - self.assertEqual(repr(P.kwargs), "P.kwargs") - - def test_user_generics(self): - T = TypeVar("T") - P = ParamSpec("P") - P_2 = ParamSpec("P_2") - - class X(Generic[T, P]): - pass - - G1 = X[int, P_2] - self.assertEqual(G1.__args__, (int, P_2)) - self.assertEqual(G1.__parameters__, (P_2,)) - - G2 = X[int, Concatenate[int, P_2]] - self.assertEqual(G2.__args__, (int, Concatenate[int, P_2])) - self.assertEqual(G2.__parameters__, (P_2,)) - - # The following are some valid uses cases in PEP 612 that don't work: - # These do not work in 3.9, _type_check blocks the list and ellipsis. - # G3 = X[int, [int, bool]] - # G4 = X[int, ...] - # G5 = Z[[int, str, bool]] - # Not working because this is special-cased in 3.10. - # G6 = Z[int, str, bool] - - class Z(Generic[P]): - pass - - def test_pickle(self): - global P, P_co, P_contra - P = ParamSpec('P') - P_co = ParamSpec('P_co', covariant=True) - P_contra = ParamSpec('P_contra', contravariant=True) - for proto in range(pickle.HIGHEST_PROTOCOL): - with self.subTest(f'Pickle protocol {proto}'): - for paramspec in (P, P_co, P_contra): - z = pickle.loads(pickle.dumps(paramspec, proto)) - self.assertEqual(z.__name__, paramspec.__name__) - self.assertEqual(z.__covariant__, paramspec.__covariant__) - self.assertEqual(z.__contravariant__, paramspec.__contravariant__) - self.assertEqual(z.__bound__, paramspec.__bound__) - - def test_eq(self): - P = ParamSpec('P') - self.assertEqual(P, P) - self.assertEqual(hash(P), hash(P)) - # ParamSpec should compare by id similar to TypeVar in CPython - self.assertNotEqual(ParamSpec('P'), P) - self.assertIsNot(ParamSpec('P'), P) - # Note: normally you don't test this as it breaks when there's - # a hash collision. However, ParamSpec *must* guarantee that - # as long as two objects don't have the same ID, their hashes - # won't be the same. - self.assertNotEqual(hash(ParamSpec('P')), hash(P)) - - -class ConcatenateTests(BaseTestCase): - def test_basics(self): - P = ParamSpec('P') - - class MyClass: ... - - c = Concatenate[MyClass, P] - self.assertNotEqual(c, Concatenate) - - def test_valid_uses(self): - P = ParamSpec('P') - T = TypeVar('T') - - C1 = Callable[Concatenate[int, P], int] - C2 = Callable[Concatenate[int, T, P], T] - - # Test collections.abc.Callable too. - if sys.version_info[:2] >= (3, 9): - C3 = collections.abc.Callable[Concatenate[int, P], int] - C4 = collections.abc.Callable[Concatenate[int, T, P], T] - - def test_invalid_uses(self): - P = ParamSpec('P') - T = TypeVar('T') - - with self.assertRaisesRegex( - TypeError, - 'Cannot take a Concatenate of no types', - ): - Concatenate[()] - - with self.assertRaisesRegex( - TypeError, - 'The last parameter to Concatenate should be a ParamSpec variable', - ): - Concatenate[P, T] - - if not TYPING_3_11_0: - with self.assertRaisesRegex( - TypeError, - 'each arg must be a type', - ): - Concatenate[1, P] - - def test_basic_introspection(self): - P = ParamSpec('P') - C1 = Concatenate[int, P] - C2 = Concatenate[int, T, P] - self.assertEqual(C1.__origin__, Concatenate) - self.assertEqual(C1.__args__, (int, P)) - self.assertEqual(C2.__origin__, Concatenate) - self.assertEqual(C2.__args__, (int, T, P)) - - def test_eq(self): - P = ParamSpec('P') - C1 = Concatenate[int, P] - C2 = Concatenate[int, P] - C3 = Concatenate[int, T, P] - self.assertEqual(C1, C2) - self.assertEqual(hash(C1), hash(C2)) - self.assertNotEqual(C1, C3) - - -class TypeGuardTests(BaseTestCase): - def test_basics(self): - TypeGuard[int] # OK - self.assertEqual(TypeGuard[int], TypeGuard[int]) - - def foo(arg) -> TypeGuard[int]: ... - self.assertEqual(gth(foo), {'return': TypeGuard[int]}) - - def test_repr(self): - if hasattr(typing, 'TypeGuard'): - mod_name = 'typing' - else: - mod_name = 'typing_extensions' - self.assertEqual(repr(TypeGuard), f'{mod_name}.TypeGuard') - cv = TypeGuard[int] - self.assertEqual(repr(cv), f'{mod_name}.TypeGuard[int]') - cv = TypeGuard[Employee] - self.assertEqual(repr(cv), f'{mod_name}.TypeGuard[{__name__}.Employee]') - cv = TypeGuard[Tuple[int]] - self.assertEqual(repr(cv), f'{mod_name}.TypeGuard[typing.Tuple[int]]') - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class C(type(TypeGuard)): - pass - with self.assertRaises(TypeError): - class C(type(TypeGuard[int])): - pass - - def test_cannot_init(self): - with self.assertRaises(TypeError): - TypeGuard() - with self.assertRaises(TypeError): - type(TypeGuard)() - with self.assertRaises(TypeError): - type(TypeGuard[Optional[int]])() - - def test_no_isinstance(self): - with self.assertRaises(TypeError): - isinstance(1, TypeGuard[int]) - with self.assertRaises(TypeError): - issubclass(int, TypeGuard) - - -class LiteralStringTests(BaseTestCase): - def test_basics(self): - class Foo: - def bar(self) -> LiteralString: ... - def baz(self) -> "LiteralString": ... - - self.assertEqual(gth(Foo.bar), {'return': LiteralString}) - self.assertEqual(gth(Foo.baz), {'return': LiteralString}) - - def test_get_origin(self): - self.assertIsNone(get_origin(LiteralString)) - - def test_repr(self): - if hasattr(typing, 'LiteralString'): - mod_name = 'typing' - else: - mod_name = 'typing_extensions' - self.assertEqual(repr(LiteralString), '{}.LiteralString'.format(mod_name)) - - def test_cannot_subscript(self): - with self.assertRaises(TypeError): - LiteralString[int] - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class C(type(LiteralString)): - pass - with self.assertRaises(TypeError): - class C(LiteralString): - pass - - def test_cannot_init(self): - with self.assertRaises(TypeError): - LiteralString() - with self.assertRaises(TypeError): - type(LiteralString)() - - def test_no_isinstance(self): - with self.assertRaises(TypeError): - isinstance(1, LiteralString) - with self.assertRaises(TypeError): - issubclass(int, LiteralString) - - def test_alias(self): - StringTuple = Tuple[LiteralString, LiteralString] - class Alias: - def return_tuple(self) -> StringTuple: - return ("foo", "pep" + "675") - - def test_typevar(self): - StrT = TypeVar("StrT", bound=LiteralString) - self.assertIs(StrT.__bound__, LiteralString) - - def test_pickle(self): - for proto in range(pickle.HIGHEST_PROTOCOL): - pickled = pickle.dumps(LiteralString, protocol=proto) - self.assertIs(LiteralString, pickle.loads(pickled)) - - -class SelfTests(BaseTestCase): - def test_basics(self): - class Foo: - def bar(self) -> Self: ... - - self.assertEqual(gth(Foo.bar), {'return': Self}) - - def test_repr(self): - if hasattr(typing, 'Self'): - mod_name = 'typing' - else: - mod_name = 'typing_extensions' - self.assertEqual(repr(Self), '{}.Self'.format(mod_name)) - - def test_cannot_subscript(self): - with self.assertRaises(TypeError): - Self[int] - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class C(type(Self)): - pass - - def test_cannot_init(self): - with self.assertRaises(TypeError): - Self() - with self.assertRaises(TypeError): - type(Self)() - - def test_no_isinstance(self): - with self.assertRaises(TypeError): - isinstance(1, Self) - with self.assertRaises(TypeError): - issubclass(int, Self) - - def test_alias(self): - TupleSelf = Tuple[Self, Self] - class Alias: - def return_tuple(self) -> TupleSelf: - return (self, self) - - def test_pickle(self): - for proto in range(pickle.HIGHEST_PROTOCOL): - pickled = pickle.dumps(Self, protocol=proto) - self.assertIs(Self, pickle.loads(pickled)) - - -class UnpackTests(BaseTestCase): - def test_basic_plain(self): - Ts = TypeVarTuple('Ts') - self.assertEqual(Unpack[Ts], Unpack[Ts]) - with self.assertRaises(TypeError): - Unpack() - - def test_repr(self): - Ts = TypeVarTuple('Ts') - if TYPING_3_11_0: - self.assertEqual(repr(Unpack[Ts]), '*Ts') - else: - self.assertEqual(repr(Unpack[Ts]), 'typing_extensions.Unpack[Ts]') - - def test_cannot_subclass_vars(self): - with self.assertRaises(TypeError): - class V(Unpack[TypeVarTuple('Ts')]): - pass - - def test_tuple(self): - Ts = TypeVarTuple('Ts') - Tuple[Unpack[Ts]] - - def test_union(self): - Xs = TypeVarTuple('Xs') - Ys = TypeVarTuple('Ys') - self.assertEqual( - Union[Unpack[Xs]], - Unpack[Xs] - ) - self.assertNotEqual( - Union[Unpack[Xs]], - Union[Unpack[Xs], Unpack[Ys]] - ) - self.assertEqual( - Union[Unpack[Xs], Unpack[Xs]], - Unpack[Xs] - ) - self.assertNotEqual( - Union[Unpack[Xs], int], - Union[Unpack[Xs]] - ) - self.assertNotEqual( - Union[Unpack[Xs], int], - Union[int] - ) - self.assertEqual( - Union[Unpack[Xs], int].__args__, - (Unpack[Xs], int) - ) - self.assertEqual( - Union[Unpack[Xs], int].__parameters__, - (Xs,) - ) - self.assertIs( - Union[Unpack[Xs], int].__origin__, - Union - ) - - def test_concatenation(self): - Xs = TypeVarTuple('Xs') - self.assertEqual(Tuple[int, Unpack[Xs]].__args__, (int, Unpack[Xs])) - self.assertEqual(Tuple[Unpack[Xs], int].__args__, (Unpack[Xs], int)) - self.assertEqual(Tuple[int, Unpack[Xs], str].__args__, - (int, Unpack[Xs], str)) - class C(Generic[Unpack[Xs]]): pass - self.assertEqual(C[int, Unpack[Xs]].__args__, (int, Unpack[Xs])) - self.assertEqual(C[Unpack[Xs], int].__args__, (Unpack[Xs], int)) - self.assertEqual(C[int, Unpack[Xs], str].__args__, - (int, Unpack[Xs], str)) - - def test_class(self): - Ts = TypeVarTuple('Ts') - - class C(Generic[Unpack[Ts]]): pass - self.assertEqual(C[int].__args__, (int,)) - self.assertEqual(C[int, str].__args__, (int, str)) - - with self.assertRaises(TypeError): - class C(Generic[Unpack[Ts], int]): pass - - T1 = TypeVar('T') - T2 = TypeVar('T') - class C(Generic[T1, T2, Unpack[Ts]]): pass - self.assertEqual(C[int, str].__args__, (int, str)) - self.assertEqual(C[int, str, float].__args__, (int, str, float)) - self.assertEqual(C[int, str, float, bool].__args__, (int, str, float, bool)) - # TODO This should probably also fail on 3.11, pending changes to CPython. - if not TYPING_3_11_0: - with self.assertRaises(TypeError): - C[int] - - -class TypeVarTupleTests(BaseTestCase): - - def test_basic_plain(self): - Ts = TypeVarTuple('Ts') - self.assertEqual(Ts, Ts) - self.assertIsInstance(Ts, TypeVarTuple) - Xs = TypeVarTuple('Xs') - Ys = TypeVarTuple('Ys') - self.assertNotEqual(Xs, Ys) - - def test_repr(self): - Ts = TypeVarTuple('Ts') - self.assertEqual(repr(Ts), 'Ts') - - def test_no_redefinition(self): - self.assertNotEqual(TypeVarTuple('Ts'), TypeVarTuple('Ts')) - - def test_cannot_subclass_vars(self): - with self.assertRaises(TypeError): - class V(TypeVarTuple('Ts')): - pass - - def test_cannot_subclass_var_itself(self): - with self.assertRaises(TypeError): - class V(TypeVarTuple): - pass - - def test_cannot_instantiate_vars(self): - Ts = TypeVarTuple('Ts') - with self.assertRaises(TypeError): - Ts() - - def test_tuple(self): - Ts = TypeVarTuple('Ts') - # Not legal at type checking time but we can't really check against it. - Tuple[Ts] - - def test_args_and_parameters(self): - Ts = TypeVarTuple('Ts') - - t = Tuple[tuple(Ts)] - self.assertEqual(t.__args__, (Unpack[Ts],)) - self.assertEqual(t.__parameters__, (Ts,)) - - -class FinalDecoratorTests(BaseTestCase): - def test_final_unmodified(self): - def func(x): ... - self.assertIs(func, final(func)) - - def test_dunder_final(self): - @final - def func(): ... - @final - class Cls: ... - self.assertIs(True, func.__final__) - self.assertIs(True, Cls.__final__) - - class Wrapper: - __slots__ = ("func",) - def __init__(self, func): - self.func = func - def __call__(self, *args, **kwargs): - return self.func(*args, **kwargs) - - # Check that no error is thrown if the attribute - # is not writable. - @final - @Wrapper - def wrapped(): ... - self.assertIsInstance(wrapped, Wrapper) - self.assertIs(False, hasattr(wrapped, "__final__")) - - class Meta(type): - @property - def __final__(self): return "can't set me" - @final - class WithMeta(metaclass=Meta): ... - self.assertEqual(WithMeta.__final__, "can't set me") - - # Builtin classes throw TypeError if you try to set an - # attribute. - final(int) - self.assertIs(False, hasattr(int, "__final__")) - - # Make sure it works with common builtin decorators - class Methods: - @final - @classmethod - def clsmethod(cls): ... - - @final - @staticmethod - def stmethod(): ... - - # The other order doesn't work because property objects - # don't allow attribute assignment. - @property - @final - def prop(self): ... - - @final - @lru_cache() # noqa: B019 - def cached(self): ... - - # Use getattr_static because the descriptor returns the - # underlying function, which doesn't have __final__. - self.assertIs( - True, - inspect.getattr_static(Methods, "clsmethod").__final__ - ) - self.assertIs( - True, - inspect.getattr_static(Methods, "stmethod").__final__ - ) - self.assertIs(True, Methods.prop.fget.__final__) - self.assertIs(True, Methods.cached.__final__) - - -class RevealTypeTests(BaseTestCase): - def test_reveal_type(self): - obj = object() - self.assertIs(obj, reveal_type(obj)) - - -class DataclassTransformTests(BaseTestCase): - def test_decorator(self): - def create_model(*, frozen: bool = False, kw_only: bool = True): - return lambda cls: cls - - decorated = dataclass_transform(kw_only_default=True, order_default=False)(create_model) - - class CustomerModel: - id: int - - self.assertIs(decorated, create_model) - self.assertEqual( - decorated.__dataclass_transform__, - { - "eq_default": True, - "order_default": False, - "kw_only_default": True, - "field_specifiers": (), - "kwargs": {}, - } - ) - self.assertIs( - decorated(frozen=True, kw_only=False)(CustomerModel), - CustomerModel - ) - - def test_base_class(self): - class ModelBase: - def __init_subclass__(cls, *, frozen: bool = False): ... - - Decorated = dataclass_transform( - eq_default=True, - order_default=True, - # Arbitrary unrecognized kwargs are accepted at runtime. - make_everything_awesome=True, - )(ModelBase) - - class CustomerModel(Decorated, frozen=True): - id: int - - self.assertIs(Decorated, ModelBase) - self.assertEqual( - Decorated.__dataclass_transform__, - { - "eq_default": True, - "order_default": True, - "kw_only_default": False, - "field_specifiers": (), - "kwargs": {"make_everything_awesome": True}, - } - ) - self.assertIsSubclass(CustomerModel, Decorated) - - def test_metaclass(self): - class Field: ... - - class ModelMeta(type): - def __new__( - cls, name, bases, namespace, *, init: bool = True, - ): - return super().__new__(cls, name, bases, namespace) - - Decorated = dataclass_transform( - order_default=True, field_specifiers=(Field,) - )(ModelMeta) - - class ModelBase(metaclass=Decorated): ... - - class CustomerModel(ModelBase, init=False): - id: int - - self.assertIs(Decorated, ModelMeta) - self.assertEqual( - Decorated.__dataclass_transform__, - { - "eq_default": True, - "order_default": True, - "kw_only_default": False, - "field_specifiers": (Field,), - "kwargs": {}, - } - ) - self.assertIsInstance(CustomerModel, Decorated) - - -class AllTests(BaseTestCase): - - def test_typing_extensions_includes_standard(self): - a = typing_extensions.__all__ - self.assertIn('ClassVar', a) - self.assertIn('Type', a) - self.assertIn('ChainMap', a) - self.assertIn('ContextManager', a) - self.assertIn('Counter', a) - self.assertIn('DefaultDict', a) - self.assertIn('Deque', a) - self.assertIn('NewType', a) - self.assertIn('overload', a) - self.assertIn('Text', a) - self.assertIn('TYPE_CHECKING', a) - self.assertIn('TypeAlias', a) - self.assertIn('ParamSpec', a) - self.assertIn("Concatenate", a) - - self.assertIn('Annotated', a) - self.assertIn('get_type_hints', a) - - self.assertIn('Awaitable', a) - self.assertIn('AsyncIterator', a) - self.assertIn('AsyncIterable', a) - self.assertIn('Coroutine', a) - self.assertIn('AsyncContextManager', a) - - self.assertIn('AsyncGenerator', a) - - self.assertIn('Protocol', a) - self.assertIn('runtime', a) - - # Check that all objects in `__all__` are present in the module - for name in a: - self.assertTrue(hasattr(typing_extensions, name)) - - def test_all_names_in___all__(self): - exclude = { - 'GenericMeta', - 'KT', - 'PEP_560', - 'T', - 'T_co', - 'T_contra', - 'VT', - } - actual_names = { - name for name in dir(typing_extensions) - if not name.startswith("_") - and not isinstance(getattr(typing_extensions, name), types.ModuleType) - } - # Make sure all public names are in __all__ - self.assertEqual({*exclude, *typing_extensions.__all__}, - actual_names) - # Make sure all excluded names actually exist - self.assertLessEqual(exclude, actual_names) - - def test_typing_extensions_defers_when_possible(self): - exclude = { - 'overload', - 'Text', - 'TypedDict', - 'TYPE_CHECKING', - 'Final', - 'get_type_hints', - 'is_typeddict', - } - if sys.version_info < (3, 10): - exclude |= {'get_args', 'get_origin'} - if sys.version_info < (3, 11): - exclude.add('final') - for item in typing_extensions.__all__: - if item not in exclude and hasattr(typing, item): - self.assertIs( - getattr(typing_extensions, item), - getattr(typing, item)) - - def test_typing_extensions_compiles_with_opt(self): - file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), - 'typing_extensions.py') - try: - subprocess.check_output(f'{sys.executable} -OO {file_path}', - stderr=subprocess.STDOUT, - shell=True) - except subprocess.CalledProcessError: - self.fail('Module does not compile with optimize=2 (-OO flag).') - - - -if __name__ == '__main__': - main() diff --git a/typing_extensions/src/typing_extensions.py b/typing_extensions/src/typing_extensions.py deleted file mode 100644 index dc038819..00000000 --- a/typing_extensions/src/typing_extensions.py +++ /dev/null @@ -1,1960 +0,0 @@ -import abc -import collections -import collections.abc -import functools -import operator -import sys -import types as _types -import typing - - -# Please keep __all__ alphabetized within each category. -__all__ = [ - # Super-special typing primitives. - 'ClassVar', - 'Concatenate', - 'Final', - 'LiteralString', - 'ParamSpec', - 'ParamSpecArgs', - 'ParamSpecKwargs', - 'Self', - 'Type', - 'TypeVarTuple', - 'Unpack', - - # ABCs (from collections.abc). - 'Awaitable', - 'AsyncIterator', - 'AsyncIterable', - 'Coroutine', - 'AsyncGenerator', - 'AsyncContextManager', - 'ChainMap', - - # Concrete collection types. - 'ContextManager', - 'Counter', - 'Deque', - 'DefaultDict', - 'OrderedDict', - 'TypedDict', - - # Structural checks, a.k.a. protocols. - 'SupportsIndex', - - # One-off things. - 'Annotated', - 'assert_never', - 'assert_type', - 'clear_overloads', - 'dataclass_transform', - 'get_overloads', - 'final', - 'get_args', - 'get_origin', - 'get_type_hints', - 'IntVar', - 'is_typeddict', - 'Literal', - 'NewType', - 'overload', - 'Protocol', - 'reveal_type', - 'runtime', - 'runtime_checkable', - 'Text', - 'TypeAlias', - 'TypeGuard', - 'TYPE_CHECKING', - 'Never', - 'NoReturn', - 'Required', - 'NotRequired', -] - -# for backward compatibility -PEP_560 = True -GenericMeta = type - -# The functions below are modified copies of typing internal helpers. -# They are needed by _ProtocolMeta and they provide support for PEP 646. - -_marker = object() - - -def _check_generic(cls, parameters, elen=_marker): - """Check correct count for parameters of a generic cls (internal helper). - This gives a nice error message in case of count mismatch. - """ - if not elen: - raise TypeError(f"{cls} is not a generic class") - if elen is _marker: - if not hasattr(cls, "__parameters__") or not cls.__parameters__: - raise TypeError(f"{cls} is not a generic class") - elen = len(cls.__parameters__) - alen = len(parameters) - if alen != elen: - if hasattr(cls, "__parameters__"): - parameters = [p for p in cls.__parameters__ if not _is_unpack(p)] - num_tv_tuples = sum(isinstance(p, TypeVarTuple) for p in parameters) - if (num_tv_tuples > 0) and (alen >= elen - num_tv_tuples): - return - raise TypeError(f"Too {'many' if alen > elen else 'few'} parameters for {cls};" - f" actual {alen}, expected {elen}") - - -if sys.version_info >= (3, 10): - def _should_collect_from_parameters(t): - return isinstance( - t, (typing._GenericAlias, _types.GenericAlias, _types.UnionType) - ) -elif sys.version_info >= (3, 9): - def _should_collect_from_parameters(t): - return isinstance(t, (typing._GenericAlias, _types.GenericAlias)) -else: - def _should_collect_from_parameters(t): - return isinstance(t, typing._GenericAlias) and not t._special - - -def _collect_type_vars(types, typevar_types=None): - """Collect all type variable contained in types in order of - first appearance (lexicographic order). For example:: - - _collect_type_vars((T, List[S, T])) == (T, S) - """ - if typevar_types is None: - typevar_types = typing.TypeVar - tvars = [] - for t in types: - if ( - isinstance(t, typevar_types) and - t not in tvars and - not _is_unpack(t) - ): - tvars.append(t) - if _should_collect_from_parameters(t): - tvars.extend([t for t in t.__parameters__ if t not in tvars]) - return tuple(tvars) - - -NoReturn = typing.NoReturn - -# Some unconstrained type variables. These are used by the container types. -# (These are not for export.) -T = typing.TypeVar('T') # Any type. -KT = typing.TypeVar('KT') # Key type. -VT = typing.TypeVar('VT') # Value type. -T_co = typing.TypeVar('T_co', covariant=True) # Any type covariant containers. -T_contra = typing.TypeVar('T_contra', contravariant=True) # Ditto contravariant. - -ClassVar = typing.ClassVar - -# On older versions of typing there is an internal class named "Final". -# 3.8+ -if hasattr(typing, 'Final') and sys.version_info[:2] >= (3, 7): - Final = typing.Final -# 3.7 -else: - class _FinalForm(typing._SpecialForm, _root=True): - - def __repr__(self): - return 'typing_extensions.' + self._name - - def __getitem__(self, parameters): - item = typing._type_check(parameters, - f'{self._name} accepts only a single type.') - return typing._GenericAlias(self, (item,)) - - Final = _FinalForm('Final', - doc="""A special typing construct to indicate that a name - cannot be re-assigned or overridden in a subclass. - For example: - - MAX_SIZE: Final = 9000 - MAX_SIZE += 1 # Error reported by type checker - - class Connection: - TIMEOUT: Final[int] = 10 - class FastConnector(Connection): - TIMEOUT = 1 # Error reported by type checker - - There is no runtime checking of these properties.""") - -if sys.version_info >= (3, 11): - final = typing.final -else: - # @final exists in 3.8+, but we backport it for all versions - # before 3.11 to keep support for the __final__ attribute. - # See https://bugs.python.org/issue46342 - def final(f): - """This decorator can be used to indicate to type checkers that - the decorated method cannot be overridden, and decorated class - cannot be subclassed. For example: - - class Base: - @final - def done(self) -> None: - ... - class Sub(Base): - def done(self) -> None: # Error reported by type checker - ... - @final - class Leaf: - ... - class Other(Leaf): # Error reported by type checker - ... - - There is no runtime checking of these properties. The decorator - sets the ``__final__`` attribute to ``True`` on the decorated object - to allow runtime introspection. - """ - try: - f.__final__ = True - except (AttributeError, TypeError): - # Skip the attribute silently if it is not writable. - # AttributeError happens if the object has __slots__ or a - # read-only property, TypeError if it's a builtin class. - pass - return f - - -def IntVar(name): - return typing.TypeVar(name) - - -# 3.8+: -if hasattr(typing, 'Literal'): - Literal = typing.Literal -# 3.7: -else: - class _LiteralForm(typing._SpecialForm, _root=True): - - def __repr__(self): - return 'typing_extensions.' + self._name - - def __getitem__(self, parameters): - return typing._GenericAlias(self, parameters) - - Literal = _LiteralForm('Literal', - doc="""A type that can be used to indicate to type checkers - that the corresponding value has a value literally equivalent - to the provided parameter. For example: - - var: Literal[4] = 4 - - The type checker understands that 'var' is literally equal to - the value 4 and no other value. - - Literal[...] cannot be subclassed. There is no runtime - checking verifying that the parameter is actually a value - instead of a type.""") - - -_overload_dummy = typing._overload_dummy # noqa - - -if hasattr(typing, "get_overloads"): # 3.11+ - overload = typing.overload - get_overloads = typing.get_overloads - clear_overloads = typing.clear_overloads -else: - # {module: {qualname: {firstlineno: func}}} - _overload_registry = collections.defaultdict( - functools.partial(collections.defaultdict, dict) - ) - - def overload(func): - """Decorator for overloaded functions/methods. - - In a stub file, place two or more stub definitions for the same - function in a row, each decorated with @overload. For example: - - @overload - def utf8(value: None) -> None: ... - @overload - def utf8(value: bytes) -> bytes: ... - @overload - def utf8(value: str) -> bytes: ... - - In a non-stub file (i.e. a regular .py file), do the same but - follow it with an implementation. The implementation should *not* - be decorated with @overload. For example: - - @overload - def utf8(value: None) -> None: ... - @overload - def utf8(value: bytes) -> bytes: ... - @overload - def utf8(value: str) -> bytes: ... - def utf8(value): - # implementation goes here - - The overloads for a function can be retrieved at runtime using the - get_overloads() function. - """ - # classmethod and staticmethod - f = getattr(func, "__func__", func) - try: - _overload_registry[f.__module__][f.__qualname__][ - f.__code__.co_firstlineno - ] = func - except AttributeError: - # Not a normal function; ignore. - pass - return _overload_dummy - - def get_overloads(func): - """Return all defined overloads for *func* as a sequence.""" - # classmethod and staticmethod - f = getattr(func, "__func__", func) - if f.__module__ not in _overload_registry: - return [] - mod_dict = _overload_registry[f.__module__] - if f.__qualname__ not in mod_dict: - return [] - return list(mod_dict[f.__qualname__].values()) - - def clear_overloads(): - """Clear all overloads in the registry.""" - _overload_registry.clear() - - -# This is not a real generic class. Don't use outside annotations. -Type = typing.Type - -# Various ABCs mimicking those in collections.abc. -# A few are simply re-exported for completeness. - - -Awaitable = typing.Awaitable -Coroutine = typing.Coroutine -AsyncIterable = typing.AsyncIterable -AsyncIterator = typing.AsyncIterator -Deque = typing.Deque -ContextManager = typing.ContextManager -AsyncContextManager = typing.AsyncContextManager -DefaultDict = typing.DefaultDict - -# 3.7.2+ -if hasattr(typing, 'OrderedDict'): - OrderedDict = typing.OrderedDict -# 3.7.0-3.7.2 -else: - OrderedDict = typing._alias(collections.OrderedDict, (KT, VT)) - -Counter = typing.Counter -ChainMap = typing.ChainMap -AsyncGenerator = typing.AsyncGenerator -NewType = typing.NewType -Text = typing.Text -TYPE_CHECKING = typing.TYPE_CHECKING - - -_PROTO_WHITELIST = ['Callable', 'Awaitable', - 'Iterable', 'Iterator', 'AsyncIterable', 'AsyncIterator', - 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', - 'ContextManager', 'AsyncContextManager'] - - -def _get_protocol_attrs(cls): - attrs = set() - for base in cls.__mro__[:-1]: # without object - if base.__name__ in ('Protocol', 'Generic'): - continue - annotations = getattr(base, '__annotations__', {}) - for attr in list(base.__dict__.keys()) + list(annotations.keys()): - if (not attr.startswith('_abc_') and attr not in ( - '__abstractmethods__', '__annotations__', '__weakref__', - '_is_protocol', '_is_runtime_protocol', '__dict__', - '__args__', '__slots__', - '__next_in_mro__', '__parameters__', '__origin__', - '__orig_bases__', '__extra__', '__tree_hash__', - '__doc__', '__subclasshook__', '__init__', '__new__', - '__module__', '_MutableMapping__marker', '_gorg')): - attrs.add(attr) - return attrs - - -def _is_callable_members_only(cls): - return all(callable(getattr(cls, attr, None)) for attr in _get_protocol_attrs(cls)) - - -# 3.8+ -if hasattr(typing, 'Protocol'): - Protocol = typing.Protocol -# 3.7 -else: - - def _no_init(self, *args, **kwargs): - if type(self)._is_protocol: - raise TypeError('Protocols cannot be instantiated') - - class _ProtocolMeta(abc.ABCMeta): - # This metaclass is a bit unfortunate and exists only because of the lack - # of __instancehook__. - def __instancecheck__(cls, instance): - # We need this method for situations where attributes are - # assigned in __init__. - if ((not getattr(cls, '_is_protocol', False) or - _is_callable_members_only(cls)) and - issubclass(instance.__class__, cls)): - return True - if cls._is_protocol: - if all(hasattr(instance, attr) and - (not callable(getattr(cls, attr, None)) or - getattr(instance, attr) is not None) - for attr in _get_protocol_attrs(cls)): - return True - return super().__instancecheck__(instance) - - class Protocol(metaclass=_ProtocolMeta): - # There is quite a lot of overlapping code with typing.Generic. - # Unfortunately it is hard to avoid this while these live in two different - # modules. The duplicated code will be removed when Protocol is moved to typing. - """Base class for protocol classes. Protocol classes are defined as:: - - class Proto(Protocol): - def meth(self) -> int: - ... - - Such classes are primarily used with static type checkers that recognize - structural subtyping (static duck-typing), for example:: - - class C: - def meth(self) -> int: - return 0 - - def func(x: Proto) -> int: - return x.meth() - - func(C()) # Passes static type check - - See PEP 544 for details. Protocol classes decorated with - @typing_extensions.runtime act as simple-minded runtime protocol that checks - only the presence of given attributes, ignoring their type signatures. - - Protocol classes can be generic, they are defined as:: - - class GenProto(Protocol[T]): - def meth(self) -> T: - ... - """ - __slots__ = () - _is_protocol = True - - def __new__(cls, *args, **kwds): - if cls is Protocol: - raise TypeError("Type Protocol cannot be instantiated; " - "it can only be used as a base class") - return super().__new__(cls) - - @typing._tp_cache - def __class_getitem__(cls, params): - if not isinstance(params, tuple): - params = (params,) - if not params and cls is not typing.Tuple: - raise TypeError( - f"Parameter list to {cls.__qualname__}[...] cannot be empty") - msg = "Parameters to generic types must be types." - params = tuple(typing._type_check(p, msg) for p in params) # noqa - if cls is Protocol: - # Generic can only be subscripted with unique type variables. - if not all(isinstance(p, typing.TypeVar) for p in params): - i = 0 - while isinstance(params[i], typing.TypeVar): - i += 1 - raise TypeError( - "Parameters to Protocol[...] must all be type variables." - f" Parameter {i + 1} is {params[i]}") - if len(set(params)) != len(params): - raise TypeError( - "Parameters to Protocol[...] must all be unique") - else: - # Subscripting a regular Generic subclass. - _check_generic(cls, params, len(cls.__parameters__)) - return typing._GenericAlias(cls, params) - - def __init_subclass__(cls, *args, **kwargs): - tvars = [] - if '__orig_bases__' in cls.__dict__: - error = typing.Generic in cls.__orig_bases__ - else: - error = typing.Generic in cls.__bases__ - if error: - raise TypeError("Cannot inherit from plain Generic") - if '__orig_bases__' in cls.__dict__: - tvars = typing._collect_type_vars(cls.__orig_bases__) - # Look for Generic[T1, ..., Tn] or Protocol[T1, ..., Tn]. - # If found, tvars must be a subset of it. - # If not found, tvars is it. - # Also check for and reject plain Generic, - # and reject multiple Generic[...] and/or Protocol[...]. - gvars = None - for base in cls.__orig_bases__: - if (isinstance(base, typing._GenericAlias) and - base.__origin__ in (typing.Generic, Protocol)): - # for error messages - the_base = base.__origin__.__name__ - if gvars is not None: - raise TypeError( - "Cannot inherit from Generic[...]" - " and/or Protocol[...] multiple types.") - gvars = base.__parameters__ - if gvars is None: - gvars = tvars - else: - tvarset = set(tvars) - gvarset = set(gvars) - if not tvarset <= gvarset: - s_vars = ', '.join(str(t) for t in tvars if t not in gvarset) - s_args = ', '.join(str(g) for g in gvars) - raise TypeError(f"Some type variables ({s_vars}) are" - f" not listed in {the_base}[{s_args}]") - tvars = gvars - cls.__parameters__ = tuple(tvars) - - # Determine if this is a protocol or a concrete subclass. - if not cls.__dict__.get('_is_protocol', None): - cls._is_protocol = any(b is Protocol for b in cls.__bases__) - - # Set (or override) the protocol subclass hook. - def _proto_hook(other): - if not cls.__dict__.get('_is_protocol', None): - return NotImplemented - if not getattr(cls, '_is_runtime_protocol', False): - if sys._getframe(2).f_globals['__name__'] in ['abc', 'functools']: - return NotImplemented - raise TypeError("Instance and class checks can only be used with" - " @runtime protocols") - if not _is_callable_members_only(cls): - if sys._getframe(2).f_globals['__name__'] in ['abc', 'functools']: - return NotImplemented - raise TypeError("Protocols with non-method members" - " don't support issubclass()") - if not isinstance(other, type): - # Same error as for issubclass(1, int) - raise TypeError('issubclass() arg 1 must be a class') - for attr in _get_protocol_attrs(cls): - for base in other.__mro__: - if attr in base.__dict__: - if base.__dict__[attr] is None: - return NotImplemented - break - annotations = getattr(base, '__annotations__', {}) - if (isinstance(annotations, typing.Mapping) and - attr in annotations and - isinstance(other, _ProtocolMeta) and - other._is_protocol): - break - else: - return NotImplemented - return True - if '__subclasshook__' not in cls.__dict__: - cls.__subclasshook__ = _proto_hook - - # We have nothing more to do for non-protocols. - if not cls._is_protocol: - return - - # Check consistency of bases. - for base in cls.__bases__: - if not (base in (object, typing.Generic) or - base.__module__ == 'collections.abc' and - base.__name__ in _PROTO_WHITELIST or - isinstance(base, _ProtocolMeta) and base._is_protocol): - raise TypeError('Protocols can only inherit from other' - f' protocols, got {repr(base)}') - cls.__init__ = _no_init - - -# 3.8+ -if hasattr(typing, 'runtime_checkable'): - runtime_checkable = typing.runtime_checkable -# 3.7 -else: - def runtime_checkable(cls): - """Mark a protocol class as a runtime protocol, so that it - can be used with isinstance() and issubclass(). Raise TypeError - if applied to a non-protocol class. - - This allows a simple-minded structural check very similar to the - one-offs in collections.abc such as Hashable. - """ - if not isinstance(cls, _ProtocolMeta) or not cls._is_protocol: - raise TypeError('@runtime_checkable can be only applied to protocol classes,' - f' got {cls!r}') - cls._is_runtime_protocol = True - return cls - - -# Exists for backwards compatibility. -runtime = runtime_checkable - - -# 3.8+ -if hasattr(typing, 'SupportsIndex'): - SupportsIndex = typing.SupportsIndex -# 3.7 -else: - @runtime_checkable - class SupportsIndex(Protocol): - __slots__ = () - - @abc.abstractmethod - def __index__(self) -> int: - pass - - -if hasattr(typing, "Required"): - # The standard library TypedDict in Python 3.8 does not store runtime information - # about which (if any) keys are optional. See https://bugs.python.org/issue38834 - # The standard library TypedDict in Python 3.9.0/1 does not honour the "total" - # keyword with old-style TypedDict(). See https://bugs.python.org/issue42059 - # The standard library TypedDict below Python 3.11 does not store runtime - # information about optional and required keys when using Required or NotRequired. - TypedDict = typing.TypedDict - _TypedDictMeta = typing._TypedDictMeta - is_typeddict = typing.is_typeddict -else: - def _check_fails(cls, other): - try: - if sys._getframe(1).f_globals['__name__'] not in ['abc', - 'functools', - 'typing']: - # Typed dicts are only for static structural subtyping. - raise TypeError('TypedDict does not support instance and class checks') - except (AttributeError, ValueError): - pass - return False - - def _dict_new(*args, **kwargs): - if not args: - raise TypeError('TypedDict.__new__(): not enough arguments') - _, args = args[0], args[1:] # allow the "cls" keyword be passed - return dict(*args, **kwargs) - - _dict_new.__text_signature__ = '($cls, _typename, _fields=None, /, **kwargs)' - - def _typeddict_new(*args, total=True, **kwargs): - if not args: - raise TypeError('TypedDict.__new__(): not enough arguments') - _, args = args[0], args[1:] # allow the "cls" keyword be passed - if args: - typename, args = args[0], args[1:] # allow the "_typename" keyword be passed - elif '_typename' in kwargs: - typename = kwargs.pop('_typename') - import warnings - warnings.warn("Passing '_typename' as keyword argument is deprecated", - DeprecationWarning, stacklevel=2) - else: - raise TypeError("TypedDict.__new__() missing 1 required positional " - "argument: '_typename'") - if args: - try: - fields, = args # allow the "_fields" keyword be passed - except ValueError: - raise TypeError('TypedDict.__new__() takes from 2 to 3 ' - f'positional arguments but {len(args) + 2} ' - 'were given') - elif '_fields' in kwargs and len(kwargs) == 1: - fields = kwargs.pop('_fields') - import warnings - warnings.warn("Passing '_fields' as keyword argument is deprecated", - DeprecationWarning, stacklevel=2) - else: - fields = None - - if fields is None: - fields = kwargs - elif kwargs: - raise TypeError("TypedDict takes either a dict or keyword arguments," - " but not both") - - ns = {'__annotations__': dict(fields)} - try: - # Setting correct module is necessary to make typed dict classes pickleable. - ns['__module__'] = sys._getframe(1).f_globals.get('__name__', '__main__') - except (AttributeError, ValueError): - pass - - return _TypedDictMeta(typename, (), ns, total=total) - - _typeddict_new.__text_signature__ = ('($cls, _typename, _fields=None,' - ' /, *, total=True, **kwargs)') - - class _TypedDictMeta(type): - def __init__(cls, name, bases, ns, total=True): - super().__init__(name, bases, ns) - - def __new__(cls, name, bases, ns, total=True): - # Create new typed dict class object. - # This method is called directly when TypedDict is subclassed, - # or via _typeddict_new when TypedDict is instantiated. This way - # TypedDict supports all three syntaxes described in its docstring. - # Subclasses and instances of TypedDict return actual dictionaries - # via _dict_new. - ns['__new__'] = _typeddict_new if name == 'TypedDict' else _dict_new - tp_dict = super().__new__(cls, name, (dict,), ns) - - annotations = {} - own_annotations = ns.get('__annotations__', {}) - msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type" - own_annotations = { - n: typing._type_check(tp, msg) for n, tp in own_annotations.items() - } - required_keys = set() - optional_keys = set() - - for base in bases: - annotations.update(base.__dict__.get('__annotations__', {})) - required_keys.update(base.__dict__.get('__required_keys__', ())) - optional_keys.update(base.__dict__.get('__optional_keys__', ())) - - annotations.update(own_annotations) - for annotation_key, annotation_type in own_annotations.items(): - annotation_origin = get_origin(annotation_type) - if annotation_origin is Annotated: - annotation_args = get_args(annotation_type) - if annotation_args: - annotation_type = annotation_args[0] - annotation_origin = get_origin(annotation_type) - - if annotation_origin is Required: - required_keys.add(annotation_key) - elif annotation_origin is NotRequired: - optional_keys.add(annotation_key) - elif total: - required_keys.add(annotation_key) - else: - optional_keys.add(annotation_key) - - tp_dict.__annotations__ = annotations - tp_dict.__required_keys__ = frozenset(required_keys) - tp_dict.__optional_keys__ = frozenset(optional_keys) - if not hasattr(tp_dict, '__total__'): - tp_dict.__total__ = total - return tp_dict - - __instancecheck__ = __subclasscheck__ = _check_fails - - TypedDict = _TypedDictMeta('TypedDict', (dict,), {}) - TypedDict.__module__ = __name__ - TypedDict.__doc__ = \ - """A simple typed name space. At runtime it is equivalent to a plain dict. - - TypedDict creates a dictionary type that expects all of its - instances to have a certain set of keys, with each key - associated with a value of a consistent type. This expectation - is not checked at runtime but is only enforced by type checkers. - Usage:: - - class Point2D(TypedDict): - x: int - y: int - label: str - - a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK - b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check - - assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first') - - The type info can be accessed via the Point2D.__annotations__ dict, and - the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets. - TypedDict supports two additional equivalent forms:: - - Point2D = TypedDict('Point2D', x=int, y=int, label=str) - Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str}) - - The class syntax is only supported in Python 3.6+, while two other - syntax forms work for Python 2.7 and 3.2+ - """ - - if hasattr(typing, "_TypedDictMeta"): - _TYPEDDICT_TYPES = (typing._TypedDictMeta, _TypedDictMeta) - else: - _TYPEDDICT_TYPES = (_TypedDictMeta,) - - def is_typeddict(tp): - """Check if an annotation is a TypedDict class - - For example:: - class Film(TypedDict): - title: str - year: int - - is_typeddict(Film) # => True - is_typeddict(Union[list, str]) # => False - """ - return isinstance(tp, tuple(_TYPEDDICT_TYPES)) - - -if hasattr(typing, "assert_type"): - assert_type = typing.assert_type - -else: - def assert_type(__val, __typ): - """Assert (to the type checker) that the value is of the given type. - - When the type checker encounters a call to assert_type(), it - emits an error if the value is not of the specified type:: - - def greet(name: str) -> None: - assert_type(name, str) # ok - assert_type(name, int) # type checker error - - At runtime this returns the first argument unchanged and otherwise - does nothing. - """ - return __val - - -if hasattr(typing, "Required"): - get_type_hints = typing.get_type_hints -else: - import functools - import types - - # replaces _strip_annotations() - def _strip_extras(t): - """Strips Annotated, Required and NotRequired from a given type.""" - if isinstance(t, _AnnotatedAlias): - return _strip_extras(t.__origin__) - if hasattr(t, "__origin__") and t.__origin__ in (Required, NotRequired): - return _strip_extras(t.__args__[0]) - if isinstance(t, typing._GenericAlias): - stripped_args = tuple(_strip_extras(a) for a in t.__args__) - if stripped_args == t.__args__: - return t - return t.copy_with(stripped_args) - if hasattr(types, "GenericAlias") and isinstance(t, types.GenericAlias): - stripped_args = tuple(_strip_extras(a) for a in t.__args__) - if stripped_args == t.__args__: - return t - return types.GenericAlias(t.__origin__, stripped_args) - if hasattr(types, "UnionType") and isinstance(t, types.UnionType): - stripped_args = tuple(_strip_extras(a) for a in t.__args__) - if stripped_args == t.__args__: - return t - return functools.reduce(operator.or_, stripped_args) - - return t - - def get_type_hints(obj, globalns=None, localns=None, include_extras=False): - """Return type hints for an object. - - This is often the same as obj.__annotations__, but it handles - forward references encoded as string literals, adds Optional[t] if a - default value equal to None is set and recursively replaces all - 'Annotated[T, ...]', 'Required[T]' or 'NotRequired[T]' with 'T' - (unless 'include_extras=True'). - - The argument may be a module, class, method, or function. The annotations - are returned as a dictionary. For classes, annotations include also - inherited members. - - TypeError is raised if the argument is not of a type that can contain - annotations, and an empty dictionary is returned if no annotations are - present. - - BEWARE -- the behavior of globalns and localns is counterintuitive - (unless you are familiar with how eval() and exec() work). The - search order is locals first, then globals. - - - If no dict arguments are passed, an attempt is made to use the - globals from obj (or the respective module's globals for classes), - and these are also used as the locals. If the object does not appear - to have globals, an empty dictionary is used. - - - If one dict argument is passed, it is used for both globals and - locals. - - - If two dict arguments are passed, they specify globals and - locals, respectively. - """ - if hasattr(typing, "Annotated"): - hint = typing.get_type_hints( - obj, globalns=globalns, localns=localns, include_extras=True - ) - else: - hint = typing.get_type_hints(obj, globalns=globalns, localns=localns) - if include_extras: - return hint - return {k: _strip_extras(t) for k, t in hint.items()} - - -# Python 3.9+ has PEP 593 (Annotated) -if hasattr(typing, 'Annotated'): - Annotated = typing.Annotated - # Not exported and not a public API, but needed for get_origin() and get_args() - # to work. - _AnnotatedAlias = typing._AnnotatedAlias -# 3.7-3.8 -else: - class _AnnotatedAlias(typing._GenericAlias, _root=True): - """Runtime representation of an annotated type. - - At its core 'Annotated[t, dec1, dec2, ...]' is an alias for the type 't' - with extra annotations. The alias behaves like a normal typing alias, - instantiating is the same as instantiating the underlying type, binding - it to types is also the same. - """ - def __init__(self, origin, metadata): - if isinstance(origin, _AnnotatedAlias): - metadata = origin.__metadata__ + metadata - origin = origin.__origin__ - super().__init__(origin, origin) - self.__metadata__ = metadata - - def copy_with(self, params): - assert len(params) == 1 - new_type = params[0] - return _AnnotatedAlias(new_type, self.__metadata__) - - def __repr__(self): - return (f"typing_extensions.Annotated[{typing._type_repr(self.__origin__)}, " - f"{', '.join(repr(a) for a in self.__metadata__)}]") - - def __reduce__(self): - return operator.getitem, ( - Annotated, (self.__origin__,) + self.__metadata__ - ) - - def __eq__(self, other): - if not isinstance(other, _AnnotatedAlias): - return NotImplemented - if self.__origin__ != other.__origin__: - return False - return self.__metadata__ == other.__metadata__ - - def __hash__(self): - return hash((self.__origin__, self.__metadata__)) - - class Annotated: - """Add context specific metadata to a type. - - Example: Annotated[int, runtime_check.Unsigned] indicates to the - hypothetical runtime_check module that this type is an unsigned int. - Every other consumer of this type can ignore this metadata and treat - this type as int. - - The first argument to Annotated must be a valid type (and will be in - the __origin__ field), the remaining arguments are kept as a tuple in - the __extra__ field. - - Details: - - - It's an error to call `Annotated` with less than two arguments. - - Nested Annotated are flattened:: - - Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] - - - Instantiating an annotated type is equivalent to instantiating the - underlying type:: - - Annotated[C, Ann1](5) == C(5) - - - Annotated can be used as a generic type alias:: - - Optimized = Annotated[T, runtime.Optimize()] - Optimized[int] == Annotated[int, runtime.Optimize()] - - OptimizedList = Annotated[List[T], runtime.Optimize()] - OptimizedList[int] == Annotated[List[int], runtime.Optimize()] - """ - - __slots__ = () - - def __new__(cls, *args, **kwargs): - raise TypeError("Type Annotated cannot be instantiated.") - - @typing._tp_cache - def __class_getitem__(cls, params): - if not isinstance(params, tuple) or len(params) < 2: - raise TypeError("Annotated[...] should be used " - "with at least two arguments (a type and an " - "annotation).") - allowed_special_forms = (ClassVar, Final) - if get_origin(params[0]) in allowed_special_forms: - origin = params[0] - else: - msg = "Annotated[t, ...]: t must be a type." - origin = typing._type_check(params[0], msg) - metadata = tuple(params[1:]) - return _AnnotatedAlias(origin, metadata) - - def __init_subclass__(cls, *args, **kwargs): - raise TypeError( - f"Cannot subclass {cls.__module__}.Annotated" - ) - -# Python 3.8 has get_origin() and get_args() but those implementations aren't -# Annotated-aware, so we can't use those. Python 3.9's versions don't support -# ParamSpecArgs and ParamSpecKwargs, so only Python 3.10's versions will do. -if sys.version_info[:2] >= (3, 10): - get_origin = typing.get_origin - get_args = typing.get_args -# 3.7-3.9 -else: - try: - # 3.9+ - from typing import _BaseGenericAlias - except ImportError: - _BaseGenericAlias = typing._GenericAlias - try: - # 3.9+ - from typing import GenericAlias as _typing_GenericAlias - except ImportError: - _typing_GenericAlias = typing._GenericAlias - - def get_origin(tp): - """Get the unsubscripted version of a type. - - This supports generic types, Callable, Tuple, Union, Literal, Final, ClassVar - and Annotated. Return None for unsupported types. Examples:: - - get_origin(Literal[42]) is Literal - get_origin(int) is None - get_origin(ClassVar[int]) is ClassVar - get_origin(Generic) is Generic - get_origin(Generic[T]) is Generic - get_origin(Union[T, int]) is Union - get_origin(List[Tuple[T, T]][int]) == list - get_origin(P.args) is P - """ - if isinstance(tp, _AnnotatedAlias): - return Annotated - if isinstance(tp, (typing._GenericAlias, _typing_GenericAlias, _BaseGenericAlias, - ParamSpecArgs, ParamSpecKwargs)): - return tp.__origin__ - if tp is typing.Generic: - return typing.Generic - return None - - def get_args(tp): - """Get type arguments with all substitutions performed. - - For unions, basic simplifications used by Union constructor are performed. - Examples:: - get_args(Dict[str, int]) == (str, int) - get_args(int) == () - get_args(Union[int, Union[T, int], str][int]) == (int, str) - get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int]) - get_args(Callable[[], T][int]) == ([], int) - """ - if isinstance(tp, _AnnotatedAlias): - return (tp.__origin__,) + tp.__metadata__ - if isinstance(tp, (typing._GenericAlias, _typing_GenericAlias)): - if getattr(tp, "_special", False): - return () - res = tp.__args__ - if get_origin(tp) is collections.abc.Callable and res[0] is not Ellipsis: - res = (list(res[:-1]), res[-1]) - return res - return () - - -# 3.10+ -if hasattr(typing, 'TypeAlias'): - TypeAlias = typing.TypeAlias -# 3.9 -elif sys.version_info[:2] >= (3, 9): - class _TypeAliasForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - @_TypeAliasForm - def TypeAlias(self, parameters): - """Special marker indicating that an assignment should - be recognized as a proper type alias definition by type - checkers. - - For example:: - - Predicate: TypeAlias = Callable[..., bool] - - It's invalid when used anywhere except as in the example above. - """ - raise TypeError(f"{self} is not subscriptable") -# 3.7-3.8 -else: - class _TypeAliasForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - TypeAlias = _TypeAliasForm('TypeAlias', - doc="""Special marker indicating that an assignment should - be recognized as a proper type alias definition by type - checkers. - - For example:: - - Predicate: TypeAlias = Callable[..., bool] - - It's invalid when used anywhere except as in the example - above.""") - - -# Python 3.10+ has PEP 612 -if hasattr(typing, 'ParamSpecArgs'): - ParamSpecArgs = typing.ParamSpecArgs - ParamSpecKwargs = typing.ParamSpecKwargs -# 3.7-3.9 -else: - class _Immutable: - """Mixin to indicate that object should not be copied.""" - __slots__ = () - - def __copy__(self): - return self - - def __deepcopy__(self, memo): - return self - - class ParamSpecArgs(_Immutable): - """The args for a ParamSpec object. - - Given a ParamSpec object P, P.args is an instance of ParamSpecArgs. - - ParamSpecArgs objects have a reference back to their ParamSpec: - - P.args.__origin__ is P - - This type is meant for runtime introspection and has no special meaning to - static type checkers. - """ - def __init__(self, origin): - self.__origin__ = origin - - def __repr__(self): - return f"{self.__origin__.__name__}.args" - - def __eq__(self, other): - if not isinstance(other, ParamSpecArgs): - return NotImplemented - return self.__origin__ == other.__origin__ - - class ParamSpecKwargs(_Immutable): - """The kwargs for a ParamSpec object. - - Given a ParamSpec object P, P.kwargs is an instance of ParamSpecKwargs. - - ParamSpecKwargs objects have a reference back to their ParamSpec: - - P.kwargs.__origin__ is P - - This type is meant for runtime introspection and has no special meaning to - static type checkers. - """ - def __init__(self, origin): - self.__origin__ = origin - - def __repr__(self): - return f"{self.__origin__.__name__}.kwargs" - - def __eq__(self, other): - if not isinstance(other, ParamSpecKwargs): - return NotImplemented - return self.__origin__ == other.__origin__ - -# 3.10+ -if hasattr(typing, 'ParamSpec'): - ParamSpec = typing.ParamSpec -# 3.7-3.9 -else: - - # Inherits from list as a workaround for Callable checks in Python < 3.9.2. - class ParamSpec(list): - """Parameter specification variable. - - Usage:: - - P = ParamSpec('P') - - Parameter specification variables exist primarily for the benefit of static - type checkers. They are used to forward the parameter types of one - callable to another callable, a pattern commonly found in higher order - functions and decorators. They are only valid when used in ``Concatenate``, - or s the first argument to ``Callable``. In Python 3.10 and higher, - they are also supported in user-defined Generics at runtime. - See class Generic for more information on generic types. An - example for annotating a decorator:: - - T = TypeVar('T') - P = ParamSpec('P') - - def add_logging(f: Callable[P, T]) -> Callable[P, T]: - '''A type-safe decorator to add logging to a function.''' - def inner(*args: P.args, **kwargs: P.kwargs) -> T: - logging.info(f'{f.__name__} was called') - return f(*args, **kwargs) - return inner - - @add_logging - def add_two(x: float, y: float) -> float: - '''Add two numbers together.''' - return x + y - - Parameter specification variables defined with covariant=True or - contravariant=True can be used to declare covariant or contravariant - generic types. These keyword arguments are valid, but their actual semantics - are yet to be decided. See PEP 612 for details. - - Parameter specification variables can be introspected. e.g.: - - P.__name__ == 'T' - P.__bound__ == None - P.__covariant__ == False - P.__contravariant__ == False - - Note that only parameter specification variables defined in global scope can - be pickled. - """ - - # Trick Generic __parameters__. - __class__ = typing.TypeVar - - @property - def args(self): - return ParamSpecArgs(self) - - @property - def kwargs(self): - return ParamSpecKwargs(self) - - def __init__(self, name, *, bound=None, covariant=False, contravariant=False): - super().__init__([self]) - self.__name__ = name - self.__covariant__ = bool(covariant) - self.__contravariant__ = bool(contravariant) - if bound: - self.__bound__ = typing._type_check(bound, 'Bound must be a type.') - else: - self.__bound__ = None - - # for pickling: - try: - def_mod = sys._getframe(1).f_globals.get('__name__', '__main__') - except (AttributeError, ValueError): - def_mod = None - if def_mod != 'typing_extensions': - self.__module__ = def_mod - - def __repr__(self): - if self.__covariant__: - prefix = '+' - elif self.__contravariant__: - prefix = '-' - else: - prefix = '~' - return prefix + self.__name__ - - def __hash__(self): - return object.__hash__(self) - - def __eq__(self, other): - return self is other - - def __reduce__(self): - return self.__name__ - - # Hack to get typing._type_check to pass. - def __call__(self, *args, **kwargs): - pass - - -# 3.7-3.9 -if not hasattr(typing, 'Concatenate'): - # Inherits from list as a workaround for Callable checks in Python < 3.9.2. - class _ConcatenateGenericAlias(list): - - # Trick Generic into looking into this for __parameters__. - __class__ = typing._GenericAlias - - # Flag in 3.8. - _special = False - - def __init__(self, origin, args): - super().__init__(args) - self.__origin__ = origin - self.__args__ = args - - def __repr__(self): - _type_repr = typing._type_repr - return (f'{_type_repr(self.__origin__)}' - f'[{", ".join(_type_repr(arg) for arg in self.__args__)}]') - - def __hash__(self): - return hash((self.__origin__, self.__args__)) - - # Hack to get typing._type_check to pass in Generic. - def __call__(self, *args, **kwargs): - pass - - @property - def __parameters__(self): - return tuple( - tp for tp in self.__args__ if isinstance(tp, (typing.TypeVar, ParamSpec)) - ) - - -# 3.7-3.9 -@typing._tp_cache -def _concatenate_getitem(self, parameters): - if parameters == (): - raise TypeError("Cannot take a Concatenate of no types.") - if not isinstance(parameters, tuple): - parameters = (parameters,) - if not isinstance(parameters[-1], ParamSpec): - raise TypeError("The last parameter to Concatenate should be a " - "ParamSpec variable.") - msg = "Concatenate[arg, ...]: each arg must be a type." - parameters = tuple(typing._type_check(p, msg) for p in parameters) - return _ConcatenateGenericAlias(self, parameters) - - -# 3.10+ -if hasattr(typing, 'Concatenate'): - Concatenate = typing.Concatenate - _ConcatenateGenericAlias = typing._ConcatenateGenericAlias # noqa -# 3.9 -elif sys.version_info[:2] >= (3, 9): - @_TypeAliasForm - def Concatenate(self, parameters): - """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a - higher order function which adds, removes or transforms parameters of a - callable. - - For example:: - - Callable[Concatenate[int, P], int] - - See PEP 612 for detailed information. - """ - return _concatenate_getitem(self, parameters) -# 3.7-8 -else: - class _ConcatenateForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - def __getitem__(self, parameters): - return _concatenate_getitem(self, parameters) - - Concatenate = _ConcatenateForm( - 'Concatenate', - doc="""Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a - higher order function which adds, removes or transforms parameters of a - callable. - - For example:: - - Callable[Concatenate[int, P], int] - - See PEP 612 for detailed information. - """) - -# 3.10+ -if hasattr(typing, 'TypeGuard'): - TypeGuard = typing.TypeGuard -# 3.9 -elif sys.version_info[:2] >= (3, 9): - class _TypeGuardForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - @_TypeGuardForm - def TypeGuard(self, parameters): - """Special typing form used to annotate the return type of a user-defined - type guard function. ``TypeGuard`` only accepts a single type argument. - At runtime, functions marked this way should return a boolean. - - ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static - type checkers to determine a more precise type of an expression within a - program's code flow. Usually type narrowing is done by analyzing - conditional code flow and applying the narrowing to a block of code. The - conditional expression here is sometimes referred to as a "type guard". - - Sometimes it would be convenient to use a user-defined boolean function - as a type guard. Such a function should use ``TypeGuard[...]`` as its - return type to alert static type checkers to this intention. - - Using ``-> TypeGuard`` tells the static type checker that for a given - function: - - 1. The return value is a boolean. - 2. If the return value is ``True``, the type of its argument - is the type inside ``TypeGuard``. - - For example:: - - def is_str(val: Union[str, float]): - # "isinstance" type guard - if isinstance(val, str): - # Type of ``val`` is narrowed to ``str`` - ... - else: - # Else, type of ``val`` is narrowed to ``float``. - ... - - Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower - form of ``TypeA`` (it can even be a wider form) and this may lead to - type-unsafe results. The main reason is to allow for things like - narrowing ``List[object]`` to ``List[str]`` even though the latter is not - a subtype of the former, since ``List`` is invariant. The responsibility of - writing type-safe type guards is left to the user. - - ``TypeGuard`` also works with type variables. For more information, see - PEP 647 (User-Defined Type Guards). - """ - item = typing._type_check(parameters, f'{self} accepts only a single type.') - return typing._GenericAlias(self, (item,)) -# 3.7-3.8 -else: - class _TypeGuardForm(typing._SpecialForm, _root=True): - - def __repr__(self): - return 'typing_extensions.' + self._name - - def __getitem__(self, parameters): - item = typing._type_check(parameters, - f'{self._name} accepts only a single type') - return typing._GenericAlias(self, (item,)) - - TypeGuard = _TypeGuardForm( - 'TypeGuard', - doc="""Special typing form used to annotate the return type of a user-defined - type guard function. ``TypeGuard`` only accepts a single type argument. - At runtime, functions marked this way should return a boolean. - - ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static - type checkers to determine a more precise type of an expression within a - program's code flow. Usually type narrowing is done by analyzing - conditional code flow and applying the narrowing to a block of code. The - conditional expression here is sometimes referred to as a "type guard". - - Sometimes it would be convenient to use a user-defined boolean function - as a type guard. Such a function should use ``TypeGuard[...]`` as its - return type to alert static type checkers to this intention. - - Using ``-> TypeGuard`` tells the static type checker that for a given - function: - - 1. The return value is a boolean. - 2. If the return value is ``True``, the type of its argument - is the type inside ``TypeGuard``. - - For example:: - - def is_str(val: Union[str, float]): - # "isinstance" type guard - if isinstance(val, str): - # Type of ``val`` is narrowed to ``str`` - ... - else: - # Else, type of ``val`` is narrowed to ``float``. - ... - - Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower - form of ``TypeA`` (it can even be a wider form) and this may lead to - type-unsafe results. The main reason is to allow for things like - narrowing ``List[object]`` to ``List[str]`` even though the latter is not - a subtype of the former, since ``List`` is invariant. The responsibility of - writing type-safe type guards is left to the user. - - ``TypeGuard`` also works with type variables. For more information, see - PEP 647 (User-Defined Type Guards). - """) - - -# Vendored from cpython typing._SpecialFrom -class _SpecialForm(typing._Final, _root=True): - __slots__ = ('_name', '__doc__', '_getitem') - - def __init__(self, getitem): - self._getitem = getitem - self._name = getitem.__name__ - self.__doc__ = getitem.__doc__ - - def __getattr__(self, item): - if item in {'__name__', '__qualname__'}: - return self._name - - raise AttributeError(item) - - def __mro_entries__(self, bases): - raise TypeError(f"Cannot subclass {self!r}") - - def __repr__(self): - return f'typing_extensions.{self._name}' - - def __reduce__(self): - return self._name - - def __call__(self, *args, **kwds): - raise TypeError(f"Cannot instantiate {self!r}") - - def __or__(self, other): - return typing.Union[self, other] - - def __ror__(self, other): - return typing.Union[other, self] - - def __instancecheck__(self, obj): - raise TypeError(f"{self} cannot be used with isinstance()") - - def __subclasscheck__(self, cls): - raise TypeError(f"{self} cannot be used with issubclass()") - - @typing._tp_cache - def __getitem__(self, parameters): - return self._getitem(self, parameters) - - -if hasattr(typing, "LiteralString"): - LiteralString = typing.LiteralString -else: - @_SpecialForm - def LiteralString(self, params): - """Represents an arbitrary literal string. - - Example:: - - from typing_extensions import LiteralString - - def query(sql: LiteralString) -> ...: - ... - - query("SELECT * FROM table") # ok - query(f"SELECT * FROM {input()}") # not ok - - See PEP 675 for details. - - """ - raise TypeError(f"{self} is not subscriptable") - - -if hasattr(typing, "Self"): - Self = typing.Self -else: - @_SpecialForm - def Self(self, params): - """Used to spell the type of "self" in classes. - - Example:: - - from typing import Self - - class ReturnsSelf: - def parse(self, data: bytes) -> Self: - ... - return self - - """ - - raise TypeError(f"{self} is not subscriptable") - - -if hasattr(typing, "Never"): - Never = typing.Never -else: - @_SpecialForm - def Never(self, params): - """The bottom type, a type that has no members. - - This can be used to define a function that should never be - called, or a function that never returns:: - - from typing_extensions import Never - - def never_call_me(arg: Never) -> None: - pass - - def int_or_str(arg: int | str) -> None: - never_call_me(arg) # type checker error - match arg: - case int(): - print("It's an int") - case str(): - print("It's a str") - case _: - never_call_me(arg) # ok, arg is of type Never - - """ - - raise TypeError(f"{self} is not subscriptable") - - -if hasattr(typing, 'Required'): - Required = typing.Required - NotRequired = typing.NotRequired -elif sys.version_info[:2] >= (3, 9): - class _ExtensionsSpecialForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - @_ExtensionsSpecialForm - def Required(self, parameters): - """A special typing construct to mark a key of a total=False TypedDict - as required. For example: - - class Movie(TypedDict, total=False): - title: Required[str] - year: int - - m = Movie( - title='The Matrix', # typechecker error if key is omitted - year=1999, - ) - - There is no runtime checking that a required key is actually provided - when instantiating a related TypedDict. - """ - item = typing._type_check(parameters, f'{self._name} accepts only a single type.') - return typing._GenericAlias(self, (item,)) - - @_ExtensionsSpecialForm - def NotRequired(self, parameters): - """A special typing construct to mark a key of a TypedDict as - potentially missing. For example: - - class Movie(TypedDict): - title: str - year: NotRequired[int] - - m = Movie( - title='The Matrix', # typechecker error if key is omitted - year=1999, - ) - """ - item = typing._type_check(parameters, f'{self._name} accepts only a single type.') - return typing._GenericAlias(self, (item,)) - -else: - class _RequiredForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - def __getitem__(self, parameters): - item = typing._type_check(parameters, - f'{self._name} accepts only a single type.') - return typing._GenericAlias(self, (item,)) - - Required = _RequiredForm( - 'Required', - doc="""A special typing construct to mark a key of a total=False TypedDict - as required. For example: - - class Movie(TypedDict, total=False): - title: Required[str] - year: int - - m = Movie( - title='The Matrix', # typechecker error if key is omitted - year=1999, - ) - - There is no runtime checking that a required key is actually provided - when instantiating a related TypedDict. - """) - NotRequired = _RequiredForm( - 'NotRequired', - doc="""A special typing construct to mark a key of a TypedDict as - potentially missing. For example: - - class Movie(TypedDict): - title: str - year: NotRequired[int] - - m = Movie( - title='The Matrix', # typechecker error if key is omitted - year=1999, - ) - """) - - -if hasattr(typing, "Unpack"): # 3.11+ - Unpack = typing.Unpack -elif sys.version_info[:2] >= (3, 9): - class _UnpackSpecialForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - class _UnpackAlias(typing._GenericAlias, _root=True): - __class__ = typing.TypeVar - - @_UnpackSpecialForm - def Unpack(self, parameters): - """A special typing construct to unpack a variadic type. For example: - - Shape = TypeVarTuple('Shape') - Batch = NewType('Batch', int) - - def add_batch_axis( - x: Array[Unpack[Shape]] - ) -> Array[Batch, Unpack[Shape]]: ... - - """ - item = typing._type_check(parameters, f'{self._name} accepts only a single type.') - return _UnpackAlias(self, (item,)) - - def _is_unpack(obj): - return isinstance(obj, _UnpackAlias) - -else: - class _UnpackAlias(typing._GenericAlias, _root=True): - __class__ = typing.TypeVar - - class _UnpackForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - def __getitem__(self, parameters): - item = typing._type_check(parameters, - f'{self._name} accepts only a single type.') - return _UnpackAlias(self, (item,)) - - Unpack = _UnpackForm( - 'Unpack', - doc="""A special typing construct to unpack a variadic type. For example: - - Shape = TypeVarTuple('Shape') - Batch = NewType('Batch', int) - - def add_batch_axis( - x: Array[Unpack[Shape]] - ) -> Array[Batch, Unpack[Shape]]: ... - - """) - - def _is_unpack(obj): - return isinstance(obj, _UnpackAlias) - - -if hasattr(typing, "TypeVarTuple"): # 3.11+ - TypeVarTuple = typing.TypeVarTuple -else: - class TypeVarTuple: - """Type variable tuple. - - Usage:: - - Ts = TypeVarTuple('Ts') - - In the same way that a normal type variable is a stand-in for a single - type such as ``int``, a type variable *tuple* is a stand-in for a *tuple* - type such as ``Tuple[int, str]``. - - Type variable tuples can be used in ``Generic`` declarations. - Consider the following example:: - - class Array(Generic[*Ts]): ... - - The ``Ts`` type variable tuple here behaves like ``tuple[T1, T2]``, - where ``T1`` and ``T2`` are type variables. To use these type variables - as type parameters of ``Array``, we must *unpack* the type variable tuple using - the star operator: ``*Ts``. The signature of ``Array`` then behaves - as if we had simply written ``class Array(Generic[T1, T2]): ...``. - In contrast to ``Generic[T1, T2]``, however, ``Generic[*Shape]`` allows - us to parameterise the class with an *arbitrary* number of type parameters. - - Type variable tuples can be used anywhere a normal ``TypeVar`` can. - This includes class definitions, as shown above, as well as function - signatures and variable annotations:: - - class Array(Generic[*Ts]): - - def __init__(self, shape: Tuple[*Ts]): - self._shape: Tuple[*Ts] = shape - - def get_shape(self) -> Tuple[*Ts]: - return self._shape - - shape = (Height(480), Width(640)) - x: Array[Height, Width] = Array(shape) - y = abs(x) # Inferred type is Array[Height, Width] - z = x + x # ... is Array[Height, Width] - x.get_shape() # ... is tuple[Height, Width] - - """ - - # Trick Generic __parameters__. - __class__ = typing.TypeVar - - def __iter__(self): - yield self.__unpacked__ - - def __init__(self, name): - self.__name__ = name - - # for pickling: - try: - def_mod = sys._getframe(1).f_globals.get('__name__', '__main__') - except (AttributeError, ValueError): - def_mod = None - if def_mod != 'typing_extensions': - self.__module__ = def_mod - - self.__unpacked__ = Unpack[self] - - def __repr__(self): - return self.__name__ - - def __hash__(self): - return object.__hash__(self) - - def __eq__(self, other): - return self is other - - def __reduce__(self): - return self.__name__ - - def __init_subclass__(self, *args, **kwds): - if '_root' not in kwds: - raise TypeError("Cannot subclass special typing classes") - - -if hasattr(typing, "reveal_type"): - reveal_type = typing.reveal_type -else: - def reveal_type(__obj: T) -> T: - """Reveal the inferred type of a variable. - - When a static type checker encounters a call to ``reveal_type()``, - it will emit the inferred type of the argument:: - - x: int = 1 - reveal_type(x) - - Running a static type checker (e.g., ``mypy``) on this example - will produce output similar to 'Revealed type is "builtins.int"'. - - At runtime, the function prints the runtime type of the - argument and returns it unchanged. - - """ - print(f"Runtime type is {type(__obj).__name__!r}", file=sys.stderr) - return __obj - - -if hasattr(typing, "assert_never"): - assert_never = typing.assert_never -else: - def assert_never(__arg: Never) -> Never: - """Assert to the type checker that a line of code is unreachable. - - Example:: - - def int_or_str(arg: int | str) -> None: - match arg: - case int(): - print("It's an int") - case str(): - print("It's a str") - case _: - assert_never(arg) - - If a type checker finds that a call to assert_never() is - reachable, it will emit an error. - - At runtime, this throws an exception when called. - - """ - raise AssertionError("Expected code to be unreachable") - - -if hasattr(typing, 'dataclass_transform'): - dataclass_transform = typing.dataclass_transform -else: - def dataclass_transform( - *, - eq_default: bool = True, - order_default: bool = False, - kw_only_default: bool = False, - field_specifiers: typing.Tuple[ - typing.Union[typing.Type[typing.Any], typing.Callable[..., typing.Any]], - ... - ] = (), - **kwargs: typing.Any, - ) -> typing.Callable[[T], T]: - """Decorator that marks a function, class, or metaclass as providing - dataclass-like behavior. - - Example: - - from typing_extensions import dataclass_transform - - _T = TypeVar("_T") - - # Used on a decorator function - @dataclass_transform() - def create_model(cls: type[_T]) -> type[_T]: - ... - return cls - - @create_model - class CustomerModel: - id: int - name: str - - # Used on a base class - @dataclass_transform() - class ModelBase: ... - - class CustomerModel(ModelBase): - id: int - name: str - - # Used on a metaclass - @dataclass_transform() - class ModelMeta(type): ... - - class ModelBase(metaclass=ModelMeta): ... - - class CustomerModel(ModelBase): - id: int - name: str - - Each of the ``CustomerModel`` classes defined in this example will now - behave similarly to a dataclass created with the ``@dataclasses.dataclass`` - decorator. For example, the type checker will synthesize an ``__init__`` - method. - - The arguments to this decorator can be used to customize this behavior: - - ``eq_default`` indicates whether the ``eq`` parameter is assumed to be - True or False if it is omitted by the caller. - - ``order_default`` indicates whether the ``order`` parameter is - assumed to be True or False if it is omitted by the caller. - - ``kw_only_default`` indicates whether the ``kw_only`` parameter is - assumed to be True or False if it is omitted by the caller. - - ``field_specifiers`` specifies a static list of supported classes - or functions that describe fields, similar to ``dataclasses.field()``. - - At runtime, this decorator records its arguments in the - ``__dataclass_transform__`` attribute on the decorated object. - - See PEP 681 for details. - - """ - def decorator(cls_or_fn): - cls_or_fn.__dataclass_transform__ = { - "eq_default": eq_default, - "order_default": order_default, - "kw_only_default": kw_only_default, - "field_specifiers": field_specifiers, - "kwargs": kwargs, - } - return cls_or_fn - return decorator - - -# We have to do some monkey patching to deal with the dual nature of -# Unpack/TypeVarTuple: -# - We want Unpack to be a kind of TypeVar so it gets accepted in -# Generic[Unpack[Ts]] -# - We want it to *not* be treated as a TypeVar for the purposes of -# counting generic parameters, so that when we subscript a generic, -# the runtime doesn't try to substitute the Unpack with the subscripted type. -if not hasattr(typing, "TypeVarTuple"): - typing._collect_type_vars = _collect_type_vars - typing._check_generic = _check_generic diff --git a/typing_extensions/tox.ini b/typing_extensions/tox.ini deleted file mode 100644 index 08869364..00000000 --- a/typing_extensions/tox.ini +++ /dev/null @@ -1,7 +0,0 @@ -[tox] -isolated_build = True -envlist = py36, py37, py38, py39, py310 - -[testenv] -changedir = src -commands = python -m unittest discover