diff --git a/tox.ini b/.flake8 similarity index 71% rename from tox.ini rename to .flake8 index 750c38ff7..b61006a00 100644 --- a/tox.ini +++ b/.flake8 @@ -1,14 +1,5 @@ -[tox] -envlist = py27, py34 - -[testenv] -changedir = src -commands = python -m unittest discover - -[testenv:py27] -changedir = python2 - [flake8] + # fake builtins for python2/* builtins = basestring, unicode max-line-length = 90 @@ -23,7 +14,5 @@ ignore = exclude = # tests have more relaxed formatting rules # and its own specific config in .flake8-tests - python2/test_typing.py, - src/test_typing.py, typing_extensions/src_py2/test_typing_extensions.py, typing_extensions/src_py3/test_typing_extensions.py, diff --git a/.flake8-tests b/.flake8-tests index 6af938e1f..dab93cc62 100644 --- a/.flake8-tests +++ b/.flake8-tests @@ -1,7 +1,7 @@ # This configuration is specific to test_*.py; you need to invoke it # by specifically naming this config, like this: # -# $ flake8 --config=.flake8-tests src/test_typing.py python2/test_typing.py +# $ flake8 --config=.flake8-tests [SOURCES] # # This will be possibly merged in the future. @@ -28,8 +28,3 @@ ignore = DW12, # consistency with mypy W504 -exclude = - # This config is NOT for the main module. - setup.py, - python2/typing.py, - src/typing.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6ed45a5b4..0e9d09ce6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,9 +25,6 @@ jobs: python -m pip install --upgrade pip pip install -r test-requirements.txt - - name: Test typing - run: pytest python2 - - name: Test typing_extensions run: | pip install typing @@ -97,4 +94,4 @@ jobs: run: flake8 - name: Lint tests - run: flake8 --config=.flake8-tests src/test_typing.py python2/test_typing.py typing_extensions/src_py2/test_typing_extensions.py typing_extensions/src_py3/test_typing_extensions.py + run: flake8 --config=.flake8-tests typing_extensions/src_py2/test_typing_extensions.py typing_extensions/src_py3/test_typing_extensions.py diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 14d7b2168..a26372d55 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,16 +1,6 @@ -This repository contains backports of the CPython `typing` module to earlier versions of -Python. Therefore, code in this repo should follow CPython's style guidelines and +Code in this repository should follow CPython's style guidelines and contributors need to sign the PSF Contributor Agreement. -# typing - -The `typing` module provided by this repository is a backport for Python versions that -do not have `typing` in the standard library: Python 2.7 and 3.4. These versions are no -longer officially supported by CPython, so there is little remaining interest in keeping -the backport up to date. We will accept contributions backporting new features to -`typing`, but we are no longer actively requiring Python 2 support for all -contributions. - # typing_extensions The `typing_extensions` module provides a way to access new features from the standard @@ -36,8 +26,7 @@ because async generators were added to the language in 3.6. # Versioning scheme -`typing_extensions` and `typing` are usually released together using the same version -numbers. The version number indicates the version of the standard library `typing` +The version number of `typing_extensions` indicates the version of the standard library `typing` module that is reflected in the backport. For example, `typing_extensions` version 3.10.0.0 includes features from the Python 3.10.0 standard library's `typing` module. A new release that doesn't include any new standard library features would be called @@ -45,25 +34,7 @@ new release that doesn't include any new standard library features would be call # Workflow for PyPI releases -- Do this for both `typing` and `typing_extensions` - -- Run tests under all supported versions. As of April 2021 this includes 2.7, 3.4, 3.5, - 3.6, 3.7, 3.8, 3.9. - -- On macOS, you can use `pyenv `\_ to manage multiple - Python installations. Long story short: - - - `xcode-select --install` - - `brew install pyenv` - - `echo 'eval "$(pyenv init -)"' >> ~/.bash_profile` - - Open a new shell - - `pyenv install 3.5.3` - - `pyenv install 3.4.6` - - (assuming you already have 2.7.13 and 3.6.1 from Homebrew) - - `pyenv global system 3.5.3 3.4.6` - - (or some more recent versions) - -- You can use `tox` to automate running tests. +- Ensure that GitHub Actions reports no errors. - Update the version number in `setup.py`. diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 3dc64dfeb..000000000 --- a/MANIFEST.in +++ /dev/null @@ -1,7 +0,0 @@ -include LICENSE README.rst -include src/typing.py -include src/test_typing.py -include src/mod_generics_cache.py -include python2/typing.py -include python2/test_typing.py -include python2/mod_generics_cache.py diff --git a/README.md b/README.md index 860cc5678..64b91182b 100644 --- a/README.md +++ b/README.md @@ -19,13 +19,7 @@ repository contain some historic discussions. Repository Content ------------------ -This GitHub repo is used for several things: - -- A backport of the `typing` module for older Python versions (2.7 and - 3.4) is maintained in the [src directory](./src). - Note that the canonical source lives - [upstream](https://github.com/python/cpython/blob/master/Lib/typing.py) - in the CPython repo. +This GitHub repository is used for several things: - The `typing_extensions` module lives in the [typing\_extensions](./typing_extensions) directory. @@ -36,11 +30,12 @@ This GitHub repo is used for several things: - 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/). + Workflow -------- -* See [CONTRIBUTING.md](/CONTRIBUTING.md) for more. - -* The typing.py module and its unittests are edited in the `src` - subdirectory of this repo. The `python2` subdirectory contains the - Python 2 backport. +See [CONTRIBUTING.md](/CONTRIBUTING.md) for more. diff --git a/python2/mod_generics_cache.py b/python2/mod_generics_cache.py deleted file mode 100644 index d9a60b4b2..000000000 --- a/python2/mod_generics_cache.py +++ /dev/null @@ -1,14 +0,0 @@ -"""Module for testing the behavior of generics across different modules.""" - -from typing import TypeVar, Generic - -T = TypeVar('T') - - -class A(Generic[T]): - pass - - -class B(Generic[T]): - class A(Generic[T]): - pass diff --git a/python2/test_typing.py b/python2/test_typing.py deleted file mode 100644 index 95677c9ea..000000000 --- a/python2/test_typing.py +++ /dev/null @@ -1,2706 +0,0 @@ -from __future__ import absolute_import, unicode_literals - -import collections -import contextlib -import os -import pickle -import re -import subprocess -import sys -import abc -import types -from unittest import TestCase, main, SkipTest -from copy import copy, deepcopy - -from typing import Any, NoReturn -from typing import TypeVar, AnyStr -from typing import T, KT, VT # Not in __all__. -from typing import Union, Optional -from typing import Tuple, List, MutableMapping -from typing import Callable -from typing import Generic, ClassVar, GenericMeta, Final, Literal -from typing import cast -from typing import Type, Protocol, runtime_checkable -from typing import NewType -from typing import NamedTuple, TypedDict -from typing import Pattern, Match -import typing -import weakref -import collections - - -class BaseTestCase(TestCase): - - def assertIsSubclass(self, cls, class_or_tuple, msg=None): - if not issubclass(cls, class_or_tuple): - message = '%r is not a subclass of %r' % (cls, class_or_tuple) - if msg is not None: - message += ' : %s' % msg - raise self.failureException(message) - - def assertNotIsSubclass(self, cls, class_or_tuple, msg=None): - if issubclass(cls, class_or_tuple): - message = '%r is a subclass of %r' % (cls, class_or_tuple) - if msg is not None: - message += ' : %s' % msg - raise self.failureException(message) - - def clear_caches(self): - for f in typing._cleanups: - f() - - -class Employee(object): - pass - - -class Manager(Employee): - pass - - -class Founder(Employee): - pass - - -class ManagingFounder(Manager, Founder): - pass - - -class AnyTests(BaseTestCase): - - def test_any_instance_type_error(self): - with self.assertRaises(TypeError): - isinstance(42, Any) - - def test_any_subclass_type_error(self): - with self.assertRaises(TypeError): - issubclass(Employee, Any) - with self.assertRaises(TypeError): - issubclass(Any, Employee) - - def test_repr(self): - self.assertEqual(repr(Any), 'typing.Any') - - def test_errors(self): - with self.assertRaises(TypeError): - issubclass(42, Any) - with self.assertRaises(TypeError): - Any[int] # Any is not a generic type. - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class A(Any): - pass - with self.assertRaises(TypeError): - class A(type(Any)): - pass - - def test_cannot_instantiate(self): - with self.assertRaises(TypeError): - Any() - with self.assertRaises(TypeError): - type(Any)() - - def test_any_is_subclass(self): - # These expressions must simply not fail. - typing.Match[Any] - typing.Pattern[Any] - typing.IO[Any] - - -class NoReturnTests(BaseTestCase): - - def test_noreturn_instance_type_error(self): - with self.assertRaises(TypeError): - isinstance(42, NoReturn) - - def test_noreturn_subclass_type_error(self): - with self.assertRaises(TypeError): - issubclass(Employee, NoReturn) - with self.assertRaises(TypeError): - issubclass(NoReturn, Employee) - - def test_repr(self): - self.assertEqual(repr(NoReturn), 'typing.NoReturn') - - def test_not_generic(self): - with self.assertRaises(TypeError): - NoReturn[int] - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class A(NoReturn): - pass - with self.assertRaises(TypeError): - class A(type(NoReturn)): - pass - - def test_cannot_instantiate(self): - with self.assertRaises(TypeError): - NoReturn() - with self.assertRaises(TypeError): - type(NoReturn)() - - -class TypeVarTests(BaseTestCase): - - def test_basic_plain(self): - T = TypeVar('T') - # T equals itself. - self.assertEqual(T, T) - # T is an instance of TypeVar - self.assertIsInstance(T, TypeVar) - - def test_typevar_instance_type_error(self): - T = TypeVar('T') - with self.assertRaises(TypeError): - isinstance(42, T) - - def test_typevar_subclass_type_error(self): - T = TypeVar('T') - with self.assertRaises(TypeError): - issubclass(int, T) - with self.assertRaises(TypeError): - issubclass(T, int) - - def test_constrained_error(self): - with self.assertRaises(TypeError): - X = TypeVar('X', int) - X - - def test_union_unique(self): - X = TypeVar('X') - Y = TypeVar('Y') - self.assertNotEqual(X, Y) - self.assertEqual(Union[X], X) - self.assertNotEqual(Union[X], Union[X, Y]) - self.assertEqual(Union[X, X], X) - self.assertNotEqual(Union[X, int], Union[X]) - self.assertNotEqual(Union[X, int], Union[int]) - self.assertEqual(Union[X, int].__args__, (X, int)) - self.assertEqual(Union[X, int].__parameters__, (X,)) - self.assertIs(Union[X, int].__origin__, Union) - - def test_union_constrained(self): - A = TypeVar('A', str, bytes) - self.assertNotEqual(Union[A, str], Union[A]) - - def test_repr(self): - self.assertEqual(repr(T), '~T') - self.assertEqual(repr(KT), '~KT') - self.assertEqual(repr(VT), '~VT') - self.assertEqual(repr(AnyStr), '~AnyStr') - T_co = TypeVar('T_co', covariant=True) - self.assertEqual(repr(T_co), '+T_co') - T_contra = TypeVar('T_contra', contravariant=True) - self.assertEqual(repr(T_contra), '-T_contra') - - def test_no_redefinition(self): - self.assertNotEqual(TypeVar('T'), TypeVar('T')) - self.assertNotEqual(TypeVar('T', int, str), TypeVar('T', int, str)) - - def test_cannot_subclass_vars(self): - with self.assertRaises(TypeError): - class V(TypeVar('T')): - pass - - def test_cannot_subclass_var_itself(self): - with self.assertRaises(TypeError): - class V(TypeVar): - pass - - def test_cannot_instantiate_vars(self): - with self.assertRaises(TypeError): - TypeVar('A')() - - def test_bound_errors(self): - with self.assertRaises(TypeError): - TypeVar('X', bound=42) - with self.assertRaises(TypeError): - TypeVar('X', str, float, bound=Employee) - - def test_no_bivariant(self): - with self.assertRaises(ValueError): - TypeVar('T', covariant=True, contravariant=True) - - -class UnionTests(BaseTestCase): - - def test_basics(self): - u = Union[int, float] - self.assertNotEqual(u, Union) - - def test_subclass_error(self): - with self.assertRaises(TypeError): - issubclass(int, Union) - with self.assertRaises(TypeError): - issubclass(Union, int) - with self.assertRaises(TypeError): - issubclass(int, Union[int, str]) - with self.assertRaises(TypeError): - issubclass(Union[int, str], int) - - def test_union_any(self): - u = Union[Any] - self.assertEqual(u, Any) - u1 = Union[int, Any] - u2 = Union[Any, int] - u3 = Union[Any, object] - self.assertEqual(u1, u2) - self.assertNotEqual(u1, Any) - self.assertNotEqual(u2, Any) - self.assertNotEqual(u3, Any) - - def test_union_object(self): - u = Union[object] - self.assertEqual(u, object) - u = Union[int, object] - self.assertEqual(u, object) - u = Union[object, int] - self.assertEqual(u, object) - - def test_unordered(self): - u1 = Union[int, float] - u2 = Union[float, int] - self.assertEqual(u1, u2) - - def test_single_class_disappears(self): - t = Union[Employee] - self.assertIs(t, Employee) - - def test_base_class_disappears(self): - u = Union[Employee, Manager, int] - self.assertEqual(u, Union[int, Employee]) - u = Union[Manager, int, Employee] - self.assertEqual(u, Union[int, Employee]) - u = Union[Employee, Manager] - self.assertIs(u, Employee) - - def test_union_union(self): - u = Union[int, float] - v = Union[u, Employee] - self.assertEqual(v, Union[int, float, Employee]) - - def test_repr(self): - self.assertEqual(repr(Union), 'typing.Union') - u = Union[Employee, int] - self.assertEqual(repr(u), 'typing.Union[%s.Employee, int]' % __name__) - u = Union[int, Employee] - self.assertEqual(repr(u), 'typing.Union[int, %s.Employee]' % __name__) - T = TypeVar('T') - u = Union[T, int][int] - self.assertEqual(repr(u), repr(int)) - u = Union[List[int], int] - self.assertEqual(repr(u), 'typing.Union[typing.List[int], int]') - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class C(Union): - pass - with self.assertRaises(TypeError): - class C(type(Union)): - pass - with self.assertRaises(TypeError): - class C(Union[int, str]): - pass - - def test_cannot_instantiate(self): - with self.assertRaises(TypeError): - Union() - u = Union[int, float] - with self.assertRaises(TypeError): - u() - with self.assertRaises(TypeError): - type(u)() - - def test_union_generalization(self): - self.assertFalse(Union[str, typing.Iterable[int]] == str) - self.assertFalse(Union[str, typing.Iterable[int]] == typing.Iterable[int]) - self.assertTrue(Union[str, typing.Iterable] == typing.Iterable) - - def test_union_compare_other(self): - self.assertNotEqual(Union, object) - self.assertNotEqual(Union, Any) - self.assertNotEqual(ClassVar, Union) - self.assertNotEqual(Optional, Union) - self.assertNotEqual([None], Optional) - self.assertNotEqual(Optional, typing.Mapping) - self.assertNotEqual(Optional[typing.MutableMapping], Union) - - def test_optional(self): - o = Optional[int] - u = Union[int, None] - self.assertEqual(o, u) - - def test_empty(self): - with self.assertRaises(TypeError): - Union[()] - - def test_union_instance_type_error(self): - with self.assertRaises(TypeError): - isinstance(42, Union[int, str]) - - def test_no_eval_union(self): - u = Union[int, str] - self.assertIs(u._eval_type({}, {}), u) - - def test_function_repr_union(self): - def fun(): pass - self.assertEqual(repr(Union[fun, int]), 'typing.Union[fun, int]') - - def test_union_str_pattern(self): - # Shouldn't crash; see http://bugs.python.org/issue25390 - A = Union[str, Pattern] - A - - def test_etree(self): - # See https://github.com/python/typing/issues/229 - # (Only relevant for Python 2.) - try: - from xml.etree.cElementTree import Element - except ImportError: - raise SkipTest("cElementTree not found") - Union[Element, str] # Shouldn't crash - - def Elem(*args): - return Element(*args) - - Union[Elem, str] # Nor should this - - -class TupleTests(BaseTestCase): - - def test_basics(self): - with self.assertRaises(TypeError): - issubclass(Tuple, Tuple[int, str]) - with self.assertRaises(TypeError): - issubclass(tuple, Tuple[int, str]) - - class TP(tuple): pass - self.assertTrue(issubclass(tuple, Tuple)) - self.assertTrue(issubclass(TP, Tuple)) - - def test_equality(self): - self.assertEqual(Tuple[int], Tuple[int]) - self.assertEqual(Tuple[int, ...], Tuple[int, ...]) - self.assertNotEqual(Tuple[int], Tuple[int, int]) - self.assertNotEqual(Tuple[int], Tuple[int, ...]) - - def test_tuple_subclass(self): - class MyTuple(tuple): - pass - self.assertTrue(issubclass(MyTuple, Tuple)) - - def test_tuple_instance_type_error(self): - with self.assertRaises(TypeError): - isinstance((0, 0), Tuple[int, int]) - isinstance((0, 0), Tuple) - - def test_repr(self): - self.assertEqual(repr(Tuple), 'typing.Tuple') - self.assertEqual(repr(Tuple[()]), 'typing.Tuple[()]') - self.assertEqual(repr(Tuple[int, float]), 'typing.Tuple[int, float]') - self.assertEqual(repr(Tuple[int, ...]), 'typing.Tuple[int, ...]') - - def test_errors(self): - with self.assertRaises(TypeError): - issubclass(42, Tuple) - with self.assertRaises(TypeError): - issubclass(42, Tuple[int]) - - -class CallableTests(BaseTestCase): - - def test_self_subclass(self): - with self.assertRaises(TypeError): - self.assertTrue(issubclass(type(lambda x: x), Callable[[int], int])) - self.assertTrue(issubclass(type(lambda x: x), Callable)) - - def test_eq_hash(self): - self.assertEqual(Callable[[int], int], Callable[[int], int]) - self.assertEqual(len({Callable[[int], int], Callable[[int], int]}), 1) - self.assertNotEqual(Callable[[int], int], Callable[[int], str]) - self.assertNotEqual(Callable[[int], int], Callable[[str], int]) - self.assertNotEqual(Callable[[int], int], Callable[[int, int], int]) - self.assertNotEqual(Callable[[int], int], Callable[[], int]) - self.assertNotEqual(Callable[[int], int], Callable) - - def test_cannot_instantiate(self): - with self.assertRaises(TypeError): - Callable() - with self.assertRaises(TypeError): - type(Callable)() - c = Callable[[int], str] - with self.assertRaises(TypeError): - c() - with self.assertRaises(TypeError): - type(c)() - - def test_callable_wrong_forms(self): - with self.assertRaises(TypeError): - Callable[(), int] - with self.assertRaises(TypeError): - Callable[[()], int] - with self.assertRaises(TypeError): - Callable[[int, 1], 2] - with self.assertRaises(TypeError): - Callable[int] - - def test_callable_instance_works(self): - def f(): - pass - self.assertIsInstance(f, Callable) - self.assertNotIsInstance(None, Callable) - - def test_callable_instance_type_error(self): - def f(): - pass - with self.assertRaises(TypeError): - self.assertIsInstance(f, Callable[[], None]) - with self.assertRaises(TypeError): - self.assertIsInstance(f, Callable[[], Any]) - with self.assertRaises(TypeError): - self.assertNotIsInstance(None, Callable[[], None]) - with self.assertRaises(TypeError): - self.assertNotIsInstance(None, Callable[[], Any]) - - def test_repr(self): - ct0 = Callable[[], bool] - self.assertEqual(repr(ct0), 'typing.Callable[[], bool]') - ct2 = Callable[[str, float], int] - self.assertEqual(repr(ct2), 'typing.Callable[[str, float], int]') - ctv = Callable[..., str] - self.assertEqual(repr(ctv), 'typing.Callable[..., str]') - - def test_ellipsis_in_generic(self): - # Shouldn't crash; see https://github.com/python/typing/issues/259 - typing.List[Callable[..., str]] - - -XK = TypeVar('XK', unicode, bytes) -XV = TypeVar('XV') - - -class SimpleMapping(Generic[XK, XV]): - - def __getitem__(self, key): - pass - - def __setitem__(self, key, value): - pass - - def get(self, key, default=None): - pass - - -class MySimpleMapping(SimpleMapping[XK, XV]): - - def __init__(self): - self.store = {} - - def __getitem__(self, key): - return self.store[key] - - def __setitem__(self, key, value): - self.store[key] = value - - def get(self, key, default=None): - try: - return self.store[key] - except KeyError: - return default - - -class ProtocolTests(BaseTestCase): - - def test_basic_protocol(self): - @runtime_checkable - class P(Protocol): - def meth(self): - pass - class C(object): pass - class D(object): - 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_checkable - class Empty(Protocol): pass - class C(object): 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): - @runtime_checkable - class Function(Protocol): - def __call__(self, *args, **kwargs): - pass - def f(): - pass - self.assertIsInstance(f, Function) - - def test_no_inheritance_from_nominal(self): - class C(object): 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 = typing.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_checkable - class P(Protocol): - @abc.abstractmethod - def ameth(self): - raise NotImplementedError - class B(P): - pass - class C(B): - def ameth(self): - return 26 - with self.assertRaises(TypeError): - B() - self.assertIsInstance(C(), P) - - def test_subprotocols_extending(self): - class P1(Protocol): - def meth1(self): - pass - @runtime_checkable - class P2(P1, Protocol): - def meth2(self): - pass - class C(object): - def meth1(self): - pass - def meth2(self): - pass - class C1(object): - def meth1(self): - pass - class C2(object): - 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_checkable - class P(P1, P2, Protocol): - pass - class C(object): - def meth1(self): - pass - def meth2(self): - pass - class C1(object): - def meth1(self): - pass - class C2(object): - 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 = typing.TypeVar('T') - @runtime_checkable - class P(Protocol): - def x(self): pass - @runtime_checkable - class PG(Protocol[T]): - def x(self): pass - class BadP(Protocol): - def x(self): pass - class BadPG(Protocol[T]): - def x(self): pass - class C(object): - def x(self): pass - self.assertIsSubclass(C, P) - self.assertIsSubclass(C, PG) - self.assertIsSubclass(BadP, PG) - self.assertIsSubclass(PG[int], PG) - self.assertIsSubclass(BadPG[int], P) - self.assertIsSubclass(BadPG[T], 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(object): - x = 1 - @runtime_checkable - 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): pass - 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 = typing.TypeVar('T') - @runtime_checkable - class P(Protocol): - def meth(x): pass - @runtime_checkable - class PG(Protocol[T]): - def meth(x): pass - class BadP(Protocol): - def meth(x): pass - class BadPG(Protocol[T]): - def meth(x): pass - class C(object): - def meth(x): pass - 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_init(self): - T = typing.TypeVar('T') - @runtime_checkable - class P(Protocol): - x = 1 - @runtime_checkable - class PG(Protocol[T]): - x = 1 - class C(object): - def __init__(self, x): - self.x = x - self.assertIsInstance(C(1), P) - self.assertIsInstance(C(1), PG) - - def test_protocol_checks_after_subscript(self): - class P(Protocol[T]): pass - class C(P[T]): pass - class Old1: pass - class New1(object): pass - class Old2: pass - class New2(object): pass - CA = C[Any] # noqa - - self.assertNotIsInstance(Old1(), C) - self.assertNotIsInstance(New1(), C) - self.assertNotIsSubclass(Old2, C) - self.assertNotIsSubclass(New2, C) - - class D1(C[Any]): pass - class D2(C[Any]): pass - CI = C[int] # noqa - - self.assertIsInstance(D1(), C) - self.assertIsSubclass(D2, C) - - def test_protocols_support_register(self): - @runtime_checkable - class P(Protocol): - x = 1 - class PM(Protocol): - def meth(self): pass - class D(PM): pass - class C(object): 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_checkable - class P(Protocol): - x = 1 - class A(object): - x = 1 - class B(A): - x = None - class C(object): - def __init__(self): - self.x = None - self.assertIsInstance(B(), P) - self.assertIsInstance(C(), P) - - def test_none_on_callable_blocks_implementation(self): - @runtime_checkable - class P(Protocol): - def x(self): pass - class A(object): - def x(self): pass - class B(A): - x = None - class C(object): - 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_checkable - class PR(Protocol): - def meth(self): pass - class NonP(P): - x = 1 - class NonPR(PR): pass - class C(object): - x = 1 - class D(object): - 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(object): pass - class BadClass(object): - 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_checkable - class P(Protocol): - x = 1 - class C: pass - with self.assertRaises(TypeError): - issubclass(C(), P) - - def test_defining_generic_protocols(self): - T = typing.TypeVar('T') - S = typing.TypeVar('S') - @runtime_checkable - class PR(Protocol[T, S]): - def meth(self): pass - class P(PR[int, T], Protocol[T]): - y = 1 - self.assertIsSubclass(PR[int, T], PR) - self.assertIsSubclass(P[str], PR) - with self.assertRaises(TypeError): - PR[int] - with self.assertRaises(TypeError): - P[int, str] - 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 = typing.TypeVar('T') - S = typing.TypeVar('S') - @runtime_checkable - class PR(Protocol, typing.Generic[T, S]): - def meth(self): pass - class P(PR[int, str], Protocol): - y = 1 - self.assertIsSubclass(PR[int, str], PR) - self.assertIsSubclass(P, PR) - with self.assertRaises(TypeError): - PR[int] - with self.assertRaises(TypeError): - PR[int, 1] - class P1(Protocol, typing.Generic[T]): - def bar(self, x): pass - class P2(typing.Generic[T], Protocol): - def bar(self, x): pass - @runtime_checkable - class PSub(P1[str], Protocol): - x = 1 - class Test(object): - x = 1 - def bar(self, x): - return x - self.assertIsInstance(Test(), PSub) - with self.assertRaises(TypeError): - PR[int, ClassVar] - - def test_init_called(self): - T = typing.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 = typing.TypeVar('T') - S = typing.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(Protocol[T], typing.Mapping[T, S]): pass - - def test_generic_protocols_repr(self): - T = typing.TypeVar('T') - S = typing.TypeVar('S') - class P(Protocol[T, S]): pass - self.assertTrue(repr(P).endswith('P')) - 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 = typing.TypeVar('T') - S = typing.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][typing.Tuple[T, S]][int, str], - P[typing.Tuple[int, str], typing.Tuple[int, str]]) - - def test_generic_protocols_special_from_generic(self): - T = typing.TypeVar('T') - class P(Protocol[T]): pass - self.assertEqual(P.__parameters__, (T,)) - self.assertIs(P.__args__, None) - self.assertIs(P.__origin__, None) - 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_checkable - class PR(Protocol): - x = 1 - class P(Protocol): - def meth(self): - pass - T = typing.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) - with self.assertRaises(AttributeError): - self.assertFalse(P._is_runtime_protocol) - self.assertTrue(PR._is_runtime_protocol) - self.assertTrue(PG[int]._is_protocol) - self.assertEqual(P._get_protocol_attrs(), {'meth'}) - self.assertEqual(PR._get_protocol_attrs(), {'x'}) - self.assertEqual(frozenset(PG._get_protocol_attrs()), - frozenset({'x', 'meth'})) - self.assertEqual(frozenset(PG[int]._get_protocol_attrs()), - frozenset({'x', 'meth'})) - - def test_no_runtime_deco_on_nominal(self): - with self.assertRaises(TypeError): - @runtime_checkable - class C(object): pass - class Proto(Protocol): - x = 1 - with self.assertRaises(TypeError): - @runtime_checkable - class Concrete(Proto): - pass - - def test_none_treated_correctly(self): - @runtime_checkable - class P(Protocol): - x = None # type: int - class B(object): pass - self.assertNotIsInstance(B(), P) - class C(object): - x = 1 - class D(object): - x = None - self.assertIsInstance(C(), P) - self.assertIsInstance(D(), P) - class CI(object): - def __init__(self): - self.x = 1 - class DI(object): - 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 = typing.TypeVar('T') - - @runtime_checkable - 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(object): - x = 1 - self.assertIsInstance(E(), D) - - def test_supports_int(self): - self.assertIsSubclass(int, typing.SupportsInt) - self.assertNotIsSubclass(str, typing.SupportsInt) - - def test_supports_float(self): - self.assertIsSubclass(float, typing.SupportsFloat) - self.assertNotIsSubclass(str, typing.SupportsFloat) - - def test_supports_complex(self): - - # Note: complex itself doesn't have __complex__. - class C(object): - def __complex__(self): - return 0j - - self.assertIsSubclass(C, typing.SupportsComplex) - self.assertNotIsSubclass(str, typing.SupportsComplex) - - def test_supports_abs(self): - self.assertIsSubclass(float, typing.SupportsAbs) - self.assertIsSubclass(int, typing.SupportsAbs) - self.assertNotIsSubclass(str, typing.SupportsAbs) - - def test_reversible(self): - self.assertIsSubclass(list, typing.Reversible) - self.assertNotIsSubclass(int, typing.Reversible) - - def test_supports_index(self): - self.assertIsSubclass(int, typing.SupportsIndex) - self.assertNotIsSubclass(str, typing.SupportsIndex) - - def test_protocol_instance_works(self): - self.assertIsInstance(0, typing.SupportsAbs) - self.assertNotIsInstance('no', typing.SupportsAbs) - class C1(typing.SupportsInt): - def __int__(self): - return 42 - class C2(C1): - pass - c = C2() - self.assertIsInstance(c, C1) - - def test_collections_protocols_allowed(self): - @runtime_checkable - class Custom(collections.Iterable, Protocol): - def close(self): pass - - class A(object): pass - class B(object): - def __iter__(self): - return [] - def close(self): - return 0 - - self.assertIsSubclass(B, Custom) - self.assertNotIsSubclass(A, Custom) - - -class GenericTests(BaseTestCase): - - def test_basics(self): - X = SimpleMapping[str, Any] - self.assertEqual(X.__parameters__, ()) - with self.assertRaises(TypeError): - X[unicode] - with self.assertRaises(TypeError): - X[unicode, unicode] - Y = SimpleMapping[XK, unicode] - self.assertEqual(Y.__parameters__, (XK,)) - Y[unicode] - with self.assertRaises(TypeError): - Y[unicode, unicode] - self.assertIsSubclass(SimpleMapping[str, int], SimpleMapping) - - def test_generic_errors(self): - T = TypeVar('T') - S = TypeVar('S') - with self.assertRaises(TypeError): - Generic[T]() - with self.assertRaises(TypeError): - Generic[T][T] - with self.assertRaises(TypeError): - Generic[T][S] - with self.assertRaises(TypeError): - isinstance([], List[int]) - with self.assertRaises(TypeError): - issubclass(list, List[int]) - with self.assertRaises(TypeError): - class NewGeneric(Generic): pass - with self.assertRaises(TypeError): - class MyGeneric(Generic[T], Generic[S]): pass - with self.assertRaises(TypeError): - class MyGeneric(List[T], Generic[S]): pass - - def test_init(self): - T = TypeVar('T') - S = TypeVar('S') - with self.assertRaises(TypeError): - Generic[T, T] - with self.assertRaises(TypeError): - Generic[T, S, T] - - def test_repr(self): - self.assertEqual(repr(SimpleMapping), - __name__ + '.' + 'SimpleMapping') - self.assertEqual(repr(MySimpleMapping), - __name__ + '.' + 'MySimpleMapping') - - def test_chain_repr(self): - T = TypeVar('T') - S = TypeVar('S') - - class C(Generic[T]): - pass - - X = C[Tuple[S, T]] - self.assertEqual(X, C[Tuple[S, T]]) - self.assertNotEqual(X, C[Tuple[T, S]]) - - Y = X[T, int] - self.assertEqual(Y, X[T, int]) - self.assertNotEqual(Y, X[S, int]) - self.assertNotEqual(Y, X[T, str]) - - Z = Y[str] - self.assertEqual(Z, Y[str]) - self.assertNotEqual(Z, Y[int]) - self.assertNotEqual(Z, Y[T]) - - self.assertTrue(str(Z).endswith( - '.C[typing.Tuple[str, int]]')) - - def test_new_repr(self): - T = TypeVar('T') - U = TypeVar('U', covariant=True) - S = TypeVar('S') - - self.assertEqual(repr(List), 'typing.List') - self.assertEqual(repr(List[T]), 'typing.List[~T]') - self.assertEqual(repr(List[U]), 'typing.List[+U]') - self.assertEqual(repr(List[S][T][int]), 'typing.List[int]') - self.assertEqual(repr(List[int]), 'typing.List[int]') - - def test_new_repr_complex(self): - T = TypeVar('T') - TS = TypeVar('TS') - - self.assertEqual(repr(typing.Mapping[T, TS][TS, T]), 'typing.Mapping[~TS, ~T]') - self.assertEqual(repr(List[Tuple[T, TS]][int, T]), - 'typing.List[typing.Tuple[int, ~T]]') - self.assertEqual( - repr(List[Tuple[T, T]][List[int]]), - 'typing.List[typing.Tuple[typing.List[int], typing.List[int]]]' - ) - - def test_new_repr_bare(self): - T = TypeVar('T') - self.assertEqual(repr(Generic[T]), 'typing.Generic[~T]') - self.assertEqual(repr(typing.Protocol[T]), 'typing.Protocol[~T]') - class C(typing.Dict[Any, Any]): pass - # this line should just work - repr(C.__mro__) - - def test_dict(self): - T = TypeVar('T') - - class B(Generic[T]): - pass - - b = B() - b.foo = 42 - self.assertEqual(b.__dict__, {'foo': 42}) - - class C(B[int]): - pass - - c = C() - c.bar = 'abc' - self.assertEqual(c.__dict__, {'bar': 'abc'}) - - def test_subscripted_generics_as_proxies(self): - T = TypeVar('T') - class C(Generic[T]): - x = 'def' - self.assertEqual(C[int].x, 'def') - self.assertEqual(C[C[int]].x, 'def') - C[C[int]].x = 'changed' - self.assertEqual(C.x, 'changed') - self.assertEqual(C[str].x, 'changed') - C[List[str]].z = 'new' - self.assertEqual(C.z, 'new') - self.assertEqual(C[Tuple[int]].z, 'new') - - self.assertEqual(C().x, 'changed') - self.assertEqual(C[Tuple[str]]().z, 'new') - - class D(C[T]): - pass - self.assertEqual(D[int].x, 'changed') - self.assertEqual(D.z, 'new') - D.z = 'from derived z' - D[int].x = 'from derived x' - self.assertEqual(C.x, 'changed') - self.assertEqual(C[int].z, 'new') - self.assertEqual(D.x, 'from derived x') - self.assertEqual(D[str].z, 'from derived z') - - def test_abc_registry_kept(self): - T = TypeVar('T') - class C(Generic[T]): pass - C.register(int) - self.assertIsInstance(1, C) - C[int] - self.assertIsInstance(1, C) - - def test_false_subclasses(self): - class MyMapping(MutableMapping[str, str]): pass - self.assertNotIsInstance({}, MyMapping) - self.assertNotIsSubclass(dict, MyMapping) - - def test_abc_bases(self): - class MM(MutableMapping[str, str]): - def __getitem__(self, k): - return None - def __setitem__(self, k, v): - pass - def __delitem__(self, k): - pass - def __iter__(self): - return iter(()) - def __len__(self): - return 0 - # this should just work - MM().update() - self.assertIsInstance(MM(), collections.MutableMapping) - self.assertIsInstance(MM(), MutableMapping) - self.assertNotIsInstance(MM(), List) - self.assertNotIsInstance({}, MM) - - def test_multiple_bases(self): - class MM1(MutableMapping[str, str], collections.MutableMapping): - pass - with self.assertRaises(TypeError): - # consistent MRO not possible - class MM2(collections.MutableMapping, MutableMapping[str, str]): - pass - - def test_orig_bases(self): - T = TypeVar('T') - class C(typing.Dict[str, T]): pass - self.assertEqual(C.__orig_bases__, (typing.Dict[str, T],)) - - def test_naive_runtime_checks(self): - def naive_dict_check(obj, tp): - # Check if a dictionary conforms to Dict type - if len(tp.__parameters__) > 0: - raise NotImplementedError - if tp.__args__: - KT, VT = tp.__args__ - return all( - isinstance(k, KT) and isinstance(v, VT) - for k, v in obj.items() - ) - self.assertTrue(naive_dict_check({'x': 1}, typing.Dict[typing.Text, int])) - self.assertFalse(naive_dict_check({1: 'x'}, typing.Dict[typing.Text, int])) - with self.assertRaises(NotImplementedError): - naive_dict_check({1: 'x'}, typing.Dict[typing.Text, T]) - - def naive_generic_check(obj, tp): - # Check if an instance conforms to the generic class - if not hasattr(obj, '__orig_class__'): - raise NotImplementedError - return obj.__orig_class__ == tp - class Node(Generic[T]): pass - self.assertTrue(naive_generic_check(Node[int](), Node[int])) - self.assertFalse(naive_generic_check(Node[str](), Node[int])) - self.assertFalse(naive_generic_check(Node[str](), List)) - with self.assertRaises(NotImplementedError): - naive_generic_check([1, 2, 3], Node[int]) - - def naive_list_base_check(obj, tp): - # Check if list conforms to a List subclass - return all(isinstance(x, tp.__orig_bases__[0].__args__[0]) - for x in obj) - class C(List[int]): pass - self.assertTrue(naive_list_base_check([1, 2, 3], C)) - self.assertFalse(naive_list_base_check(['a', 'b'], C)) - - def test_multi_subscr_base(self): - T = TypeVar('T') - U = TypeVar('U') - V = TypeVar('V') - class C(List[T][U][V]): pass - class D(C, List[T][U][V]): pass - self.assertEqual(C.__parameters__, (V,)) - self.assertEqual(D.__parameters__, (V,)) - self.assertEqual(C[int].__parameters__, ()) - self.assertEqual(D[int].__parameters__, ()) - self.assertEqual(C[int].__args__, (int,)) - self.assertEqual(D[int].__args__, (int,)) - self.assertEqual(C.__bases__, (List,)) - self.assertEqual(D.__bases__, (C, List)) - self.assertEqual(C.__orig_bases__, (List[T][U][V],)) - self.assertEqual(D.__orig_bases__, (C, List[T][U][V])) - - def test_subscript_meta(self): - T = TypeVar('T') - self.assertEqual(Type[GenericMeta], Type[GenericMeta]) - self.assertEqual(Union[T, int][GenericMeta], Union[GenericMeta, int]) - self.assertEqual(Callable[..., GenericMeta].__args__, (Ellipsis, GenericMeta)) - - def test_generic_hashes(self): - import mod_generics_cache - class A(Generic[T]): - __module__ = 'test_typing' - - class B(Generic[T]): - class A(Generic[T]): - pass - - self.assertEqual(A, A) - self.assertEqual(mod_generics_cache.A[str], mod_generics_cache.A[str]) - self.assertEqual(B.A, B.A) - self.assertEqual(mod_generics_cache.B.A[B.A[str]], - mod_generics_cache.B.A[B.A[str]]) - - self.assertNotEqual(A, B.A) - self.assertNotEqual(A, mod_generics_cache.A) - self.assertNotEqual(A, mod_generics_cache.B.A) - self.assertNotEqual(B.A, mod_generics_cache.A) - self.assertNotEqual(B.A, mod_generics_cache.B.A) - - self.assertNotEqual(A[str], B.A[str]) - self.assertNotEqual(A[List[Any]], B.A[List[Any]]) - self.assertNotEqual(A[str], mod_generics_cache.A[str]) - self.assertNotEqual(A[str], mod_generics_cache.B.A[str]) - self.assertNotEqual(B.A[int], mod_generics_cache.A[int]) - self.assertNotEqual(B.A[List[Any]], mod_generics_cache.B.A[List[Any]]) - - self.assertNotEqual(Tuple[A[str]], Tuple[B.A[str]]) - self.assertNotEqual(Tuple[A[List[Any]]], Tuple[B.A[List[Any]]]) - self.assertNotEqual(Union[str, A[str]], Union[str, mod_generics_cache.A[str]]) - self.assertNotEqual(Union[A[str], A[str]], - Union[A[str], mod_generics_cache.A[str]]) - self.assertNotEqual(typing.FrozenSet[A[str]], - typing.FrozenSet[mod_generics_cache.B.A[str]]) - - self.assertTrue(repr(Tuple[A[str]]).endswith('test_typing.A[str]]')) - self.assertTrue(repr(Tuple[mod_generics_cache.A[str]]) - .endswith('mod_generics_cache.A[str]]')) - - def test_extended_generic_rules_eq(self): - T = TypeVar('T') - U = TypeVar('U') - self.assertEqual(Tuple[T, T][int], Tuple[int, int]) - self.assertEqual(typing.Iterable[Tuple[T, T]][T], typing.Iterable[Tuple[T, T]]) - with self.assertRaises(TypeError): - Tuple[T, int][()] - with self.assertRaises(TypeError): - Tuple[T, U][T, ...] - - self.assertEqual(Union[T, int][int], int) - self.assertEqual(Union[T, U][int, Union[int, str]], Union[int, str]) - class Base(object): pass - class Derived(Base): pass - self.assertEqual(Union[T, Base][Derived], Base) - with self.assertRaises(TypeError): - Union[T, int][1] - - self.assertEqual(Callable[[T], T][KT], Callable[[KT], KT]) - self.assertEqual(Callable[..., List[T]][int], Callable[..., List[int]]) - with self.assertRaises(TypeError): - Callable[[T], U][..., int] - with self.assertRaises(TypeError): - Callable[[T], U][[], int] - - def test_extended_generic_rules_repr(self): - T = TypeVar('T') - self.assertEqual(repr(Union[Tuple, Callable]).replace('typing.', ''), - 'Union[Tuple, Callable]') - self.assertEqual(repr(Union[Tuple, Tuple[int]]).replace('typing.', ''), - 'Tuple') - self.assertEqual(repr(Callable[..., Optional[T]][int]).replace('typing.', ''), - 'Callable[..., Union[int, NoneType]]') - self.assertEqual(repr(Callable[[], List[T]][int]).replace('typing.', ''), - 'Callable[[], List[int]]') - - def test_generic_forvard_ref(self): - LLT = List[List['CC']] - class CC: pass - self.assertEqual(typing._eval_type(LLT, globals(), locals()), List[List[CC]]) - T = TypeVar('T') - AT = Tuple[T, ...] - self.assertIs(typing._eval_type(AT, globals(), locals()), AT) - CT = Callable[..., List[T]] - self.assertIs(typing._eval_type(CT, globals(), locals()), CT) - - def test_extended_generic_rules_subclassing(self): - class T1(Tuple[T, KT]): pass - class T2(Tuple[T, ...]): pass - class C1(Callable[[T], T]): pass - class C2(Callable[..., int]): - def __call__(self): - return None - - self.assertEqual(T1.__parameters__, (T, KT)) - self.assertEqual(T1[int, str].__args__, (int, str)) - self.assertEqual(T1[int, T].__origin__, T1) - - self.assertEqual(T2.__parameters__, (T,)) - with self.assertRaises(TypeError): - T1[int] - with self.assertRaises(TypeError): - T2[int, str] - - self.assertEqual(repr(C1[int]).split('.')[-1], 'C1[int]') - self.assertEqual(C2.__parameters__, ()) - self.assertIsInstance(C2(), collections.Callable) - self.assertIsSubclass(C2, collections.Callable) - self.assertIsSubclass(C1, collections.Callable) - self.assertIsInstance(T1(), tuple) - self.assertIsSubclass(T2, tuple) - self.assertIsSubclass(Tuple[int, ...], typing.Sequence) - self.assertIsSubclass(Tuple[int, ...], typing.Iterable) - - def test_fail_with_bare_union(self): - with self.assertRaises(TypeError): - List[Union] - with self.assertRaises(TypeError): - Tuple[Optional] - with self.assertRaises(TypeError): - ClassVar[ClassVar] - with self.assertRaises(TypeError): - List[ClassVar[int]] - - def test_fail_with_bare_generic(self): - T = TypeVar('T') - with self.assertRaises(TypeError): - List[Generic] - with self.assertRaises(TypeError): - Tuple[Generic[T]] - with self.assertRaises(TypeError): - List[typing.Protocol] - with self.assertRaises(TypeError): - isinstance(1, Generic) - - def test_type_erasure_special(self): - T = TypeVar('T') - # this is the only test that checks type caching - self.clear_caches() - class MyTup(Tuple[T, T]): pass - self.assertIs(MyTup[int]().__class__, MyTup) - self.assertIs(MyTup[int]().__orig_class__, MyTup[int]) - class MyCall(Callable[..., T]): - def __call__(self): return None - self.assertIs(MyCall[T]().__class__, MyCall) - self.assertIs(MyCall[T]().__orig_class__, MyCall[T]) - class MyDict(typing.Dict[T, T]): pass - self.assertIs(MyDict[int]().__class__, MyDict) - self.assertIs(MyDict[int]().__orig_class__, MyDict[int]) - class MyDef(typing.DefaultDict[str, T]): pass - self.assertIs(MyDef[int]().__class__, MyDef) - self.assertIs(MyDef[int]().__orig_class__, MyDef[int]) - - def test_all_repr_eq_any(self): - objs = (getattr(typing, el) for el in typing.__all__) - for obj in objs: - self.assertNotEqual(repr(obj), '') - self.assertEqual(obj, obj) - if getattr(obj, '__parameters__', None) and len(obj.__parameters__) == 1: - self.assertEqual(obj[Any].__args__, (Any,)) - if isinstance(obj, type): - for base in obj.__mro__: - self.assertNotEqual(repr(base), '') - self.assertEqual(base, base) - - def test_pickle(self): - global C # pickle wants to reference the class by name - T = TypeVar('T') - - class B(Generic[T]): - pass - - class C(B[int]): - pass - - c = C() - 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.__dict__, {'foo': 42, 'bar': 'abc'}) - simples = [Any, Union, Tuple, Callable, ClassVar, List, typing.Iterable] - for s in simples: - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - z = pickle.dumps(s, proto) - x = pickle.loads(z) - self.assertEqual(s, x) - - def test_copy_and_deepcopy(self): - T = TypeVar('T') - class Node(Generic[T]): pass - things = [ - Any, - Callable[..., T], - Callable[[int], int], - ClassVar[List[T]], - ClassVar[int], - List['T'], - Node[Any], - Node[T], - Node[int], - Tuple['T', 'T'], - Tuple[Any, Any], - Tuple[T, int], - Union['T', int], - Union[T, int], - typing.Dict[T, Any], - typing.Dict[int, str], - typing.Iterable[Any], - typing.Iterable[T], - typing.Iterable[int], - typing.Mapping['T', int] - ] - for t in things: - self.assertEqual(t, deepcopy(t)) - self.assertEqual(t, copy(t)) - - def test_copy_generic_instances(self): - T = TypeVar('T') - class C(Generic[T]): - def __init__(self, attr): - self.attr = attr - - c = C(42) - self.assertEqual(copy(c).attr, 42) - self.assertEqual(deepcopy(c).attr, 42) - self.assertIsNot(copy(c), c) - self.assertIsNot(deepcopy(c), c) - c.attr = 1 - self.assertEqual(copy(c).attr, 1) - self.assertEqual(deepcopy(c).attr, 1) - ci = C[int](42) - self.assertEqual(copy(ci).attr, 42) - self.assertEqual(deepcopy(ci).attr, 42) - self.assertIsNot(copy(ci), ci) - self.assertIsNot(deepcopy(ci), ci) - ci.attr = 1 - self.assertEqual(copy(ci).attr, 1) - self.assertEqual(deepcopy(ci).attr, 1) - self.assertEqual(ci.__orig_class__, C[int]) - - def test_weakref_all(self): - T = TypeVar('T') - things = [Any, Union[T, int], Callable[..., T], Tuple[Any, Any], - Optional[List[int]], typing.Mapping[int, str], - typing.re.Match[bytes], typing.Iterable['whatever']] - for t in things: - self.assertEqual(weakref.ref(t)(), t) - - def test_parameterized_slots(self): - T = TypeVar('T') - class C(Generic[T]): - __slots__ = ('potato',) - - c = C() - c_int = C[int]() - self.assertEqual(C.__slots__, C[str].__slots__) - - c.potato = 0 - c_int.potato = 0 - with self.assertRaises(AttributeError): - c.tomato = 0 - with self.assertRaises(AttributeError): - c_int.tomato = 0 - - self.assertEqual(typing._eval_type(C['C'], globals(), locals()), C[C]) - self.assertEqual(typing._eval_type(C['C'], globals(), locals()).__slots__, - C.__slots__) - self.assertEqual(copy(C[int]), deepcopy(C[int])) - - def test_parameterized_slots_dict(self): - T = TypeVar('T') - class D(Generic[T]): - __slots__ = {'banana': 42} - - d = D() - d_int = D[int]() - self.assertEqual(D.__slots__, D[str].__slots__) - - d.banana = 'yes' - d_int.banana = 'yes' - with self.assertRaises(AttributeError): - d.foobar = 'no' - with self.assertRaises(AttributeError): - d_int.foobar = 'no' - - def test_errors(self): - with self.assertRaises(TypeError): - B = SimpleMapping[XK, Any] - - class C(Generic[B]): - pass - - def test_repr_2(self): - PY32 = sys.version_info[:2] < (3, 3) - - class C(Generic[T]): - pass - - self.assertEqual(C.__module__, __name__) - if not PY32: - self.assertEqual(C.__qualname__, - 'GenericTests.test_repr_2..C') - self.assertEqual(repr(C).split('.')[-1], 'C') - X = C[int] - self.assertEqual(X.__module__, __name__) - if not PY32: - self.assertTrue(X.__qualname__.endswith('..C')) - self.assertEqual(repr(X).split('.')[-1], 'C[int]') - - class Y(C[int]): - pass - - self.assertEqual(Y.__module__, __name__) - if not PY32: - self.assertEqual(Y.__qualname__, - 'GenericTests.test_repr_2..Y') - self.assertEqual(repr(Y).split('.')[-1], 'Y') - - def test_eq_1(self): - self.assertEqual(Generic, Generic) - self.assertEqual(Generic[T], Generic[T]) - self.assertNotEqual(Generic[KT], Generic[VT]) - - def test_eq_2(self): - - class A(Generic[T]): - pass - - class B(Generic[T]): - pass - - self.assertEqual(A, A) - self.assertNotEqual(A, B) - self.assertEqual(A[T], A[T]) - self.assertNotEqual(A[T], B[T]) - - def test_multiple_inheritance(self): - - class A(Generic[T, VT]): - pass - - class B(Generic[KT, T]): - pass - - class C(A[T, VT], Generic[VT, T, KT], B[KT, T]): - pass - - self.assertEqual(C.__parameters__, (VT, T, KT)) - - def test_nested(self): - - G = Generic - - class Visitor(G[T]): - - a = None - - def set(self, a): - self.a = a - - def get(self): - return self.a - - def visit(self): - return self.a - - V = Visitor[typing.List[int]] - - class IntListVisitor(V): - - def append(self, x): - self.a.append(x) - - a = IntListVisitor() - a.set([]) - a.append(1) - a.append(42) - self.assertEqual(a.get(), [1, 42]) - - def test_type_erasure(self): - T = TypeVar('T') - - class Node(Generic[T]): - def __init__(self, label, - left=None, - right=None): - self.label = label # type: T - self.left = left # type: Optional[Node[T]] - self.right = right # type: Optional[Node[T]] - - def foo(x): - a = Node(x) - b = Node[T](x) - c = Node[Any](x) - self.assertIs(type(a), Node) - self.assertIs(type(b), Node) - self.assertIs(type(c), Node) - self.assertEqual(a.label, x) - self.assertEqual(b.label, x) - self.assertEqual(c.label, x) - - foo(42) - - def test_implicit_any(self): - T = TypeVar('T') - - class C(Generic[T]): - pass - - class D(C): - pass - - self.assertEqual(D.__parameters__, ()) - - with self.assertRaises(Exception): - D[int] - with self.assertRaises(Exception): - D[Any] - with self.assertRaises(Exception): - D[T] - - def test_new_with_args(self): - - class A(Generic[T]): - pass - - class B(object): - def __new__(cls, arg): - # call object.__new__ - obj = super(B, cls).__new__(cls) - obj.arg = arg - return obj - - # mro: C, A, Generic, B, object - class C(A, B): - pass - - c = C('foo') - self.assertEqual(c.arg, 'foo') - - def test_new_with_args2(self): - - class A(object): - def __init__(self, arg): - self.from_a = arg - # call object - super(A, self).__init__() - - # mro: C, Generic, A, object - class C(Generic[T], A): - def __init__(self, arg): - self.from_c = arg - # call Generic - super(C, self).__init__(arg) - - c = C('foo') - self.assertEqual(c.from_a, 'foo') - self.assertEqual(c.from_c, 'foo') - - def test_new_no_args(self): - - class A(Generic[T]): - pass - - with self.assertRaises(TypeError): - A('foo') - - class B(object): - def __new__(cls): - # call object - obj = super(B, cls).__new__(cls) - obj.from_b = 'b' - return obj - - # mro: C, A, Generic, B, object - class C(A, B): - def __init__(self, arg): - self.arg = arg - - def __new__(cls, arg): - # call A - obj = super(C, cls).__new__(cls) - obj.from_c = 'c' - return obj - - c = C('foo') - self.assertEqual(c.arg, 'foo') - self.assertEqual(c.from_b, 'b') - self.assertEqual(c.from_c, 'c') - - -class ClassVarTests(BaseTestCase): - - def test_basics(self): - with self.assertRaises(TypeError): - ClassVar[1] - with self.assertRaises(TypeError): - ClassVar[int, str] - with self.assertRaises(TypeError): - ClassVar[int][str] - - def test_repr(self): - self.assertEqual(repr(ClassVar), 'typing.ClassVar') - cv = ClassVar[int] - self.assertEqual(repr(cv), 'typing.ClassVar[int]') - cv = ClassVar[Employee] - self.assertEqual(repr(cv), 'typing.ClassVar[%s.Employee]' % __name__) - - 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): - with self.assertRaises(TypeError): - Final[1] - with self.assertRaises(TypeError): - Final[int, str] - with self.assertRaises(TypeError): - Final[int][str] - - def test_repr(self): - self.assertEqual(repr(Final), 'typing.Final') - cv = Final[int] - self.assertEqual(repr(cv), 'typing.Final[int]') - cv = Final[Employee] - self.assertEqual(repr(cv), 'typing.Final[%s.Employee]' % __name__) - - 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[typing.Optional[int]])() - - def test_no_isinstance(self): - with self.assertRaises(TypeError): - isinstance(1, Final[int]) - with self.assertRaises(TypeError): - issubclass(int, Final) - - -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 maximium 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): - typing.List[Literal[1, 2, 3]] - typing.List[Literal[("foo", "bar", "baz")]] - - def test_repr(self): - self.assertEqual(repr(Literal[1]), "typing.Literal[1]") - self.assertEqual(repr(Literal[1, True, "foo"]), "typing.Literal[1, True, u'foo']") - self.assertEqual(repr(Literal[int]), "typing.Literal[int]") - self.assertEqual(repr(Literal), "typing.Literal") - self.assertEqual(repr(Literal[None]), "typing.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 CastTests(BaseTestCase): - - def test_basics(self): - self.assertEqual(cast(int, 42), 42) - self.assertEqual(cast(float, 42), 42) - self.assertIs(type(cast(float, 42)), int) - self.assertEqual(cast(Any, 42), 42) - self.assertEqual(cast(list, 42), 42) - self.assertEqual(cast(Union[str, float], 42), 42) - self.assertEqual(cast(AnyStr, 42), 42) - self.assertEqual(cast(None, 42), 42) - - def test_errors(self): - # Bogus calls are not expected to fail. - cast(42, 42) - cast('hello', 42) - - -class ForwardRefTests(BaseTestCase): - - def test_forwardref_instance_type_error(self): - fr = typing._ForwardRef('int') - with self.assertRaises(TypeError): - isinstance(42, fr) - - def test_syntax_error(self): - - with self.assertRaises(SyntaxError): - Generic['/T'] - - def test_forwardref_subclass_type_error(self): - fr = typing._ForwardRef('int') - with self.assertRaises(TypeError): - issubclass(int, fr) - - def test_forward_equality(self): - fr = typing._ForwardRef('int') - self.assertEqual(fr, typing._ForwardRef('int')) - self.assertNotEqual(List['int'], List[int]) - - def test_forward_repr(self): - self.assertEqual(repr(List['int']), "typing.List[_ForwardRef(%r)]" % 'int') - - -class OverloadTests(BaseTestCase): - - def test_overload_fails(self): - from typing import overload - - with self.assertRaises(RuntimeError): - - @overload - def blah(): - pass - - blah() - - def test_overload_succeeds(self): - from typing import overload - - @overload - def blah(): - pass - - def blah(): - pass - - blah() - - -class CollectionsAbcTests(BaseTestCase): - - def test_hashable(self): - self.assertIsInstance(42, typing.Hashable) - self.assertNotIsInstance([], typing.Hashable) - - def test_iterable(self): - self.assertIsInstance([], typing.Iterable) - # Due to ABC caching, the second time takes a separate code - # path and could fail. So call this a few times. - self.assertIsInstance([], typing.Iterable) - self.assertIsInstance([], typing.Iterable) - self.assertNotIsInstance(42, typing.Iterable) - # Just in case, also test issubclass() a few times. - self.assertIsSubclass(list, typing.Iterable) - self.assertIsSubclass(list, typing.Iterable) - - def test_iterator(self): - it = iter([]) - self.assertIsInstance(it, typing.Iterator) - self.assertNotIsInstance(42, typing.Iterator) - - def test_sized(self): - self.assertIsInstance([], typing.Sized) - self.assertNotIsInstance(42, typing.Sized) - - def test_container(self): - self.assertIsInstance([], typing.Container) - self.assertNotIsInstance(42, typing.Container) - - def test_abstractset(self): - self.assertIsInstance(set(), typing.AbstractSet) - self.assertNotIsInstance(42, typing.AbstractSet) - - def test_mutableset(self): - self.assertIsInstance(set(), typing.MutableSet) - self.assertNotIsInstance(frozenset(), typing.MutableSet) - - def test_mapping(self): - self.assertIsInstance({}, typing.Mapping) - self.assertNotIsInstance(42, typing.Mapping) - - def test_mutablemapping(self): - self.assertIsInstance({}, typing.MutableMapping) - self.assertNotIsInstance(42, typing.MutableMapping) - - def test_sequence(self): - self.assertIsInstance([], typing.Sequence) - self.assertNotIsInstance(42, typing.Sequence) - - def test_mutablesequence(self): - self.assertIsInstance([], typing.MutableSequence) - self.assertNotIsInstance((), typing.MutableSequence) - - def test_bytestring(self): - self.assertIsInstance(b'', typing.ByteString) - self.assertIsInstance(bytearray(b''), typing.ByteString) - - def test_list(self): - self.assertIsSubclass(list, typing.List) - - def test_deque(self): - self.assertIsSubclass(collections.deque, typing.Deque) - class MyDeque(typing.Deque[int]): pass - self.assertIsInstance(MyDeque(), collections.deque) - - def test_counter(self): - self.assertIsSubclass(collections.Counter, typing.Counter) - - def test_set(self): - self.assertIsSubclass(set, typing.Set) - self.assertNotIsSubclass(frozenset, typing.Set) - - def test_frozenset(self): - self.assertIsSubclass(frozenset, typing.FrozenSet) - self.assertNotIsSubclass(set, typing.FrozenSet) - - def test_dict(self): - self.assertIsSubclass(dict, typing.Dict) - - def test_no_list_instantiation(self): - with self.assertRaises(TypeError): - typing.List() - with self.assertRaises(TypeError): - typing.List[T]() - with self.assertRaises(TypeError): - typing.List[int]() - - def test_list_subclass(self): - - class MyList(typing.List[int]): - pass - - a = MyList() - self.assertIsInstance(a, MyList) - self.assertIsInstance(a, typing.Sequence) - - self.assertIsSubclass(MyList, list) - self.assertNotIsSubclass(list, MyList) - - def test_no_dict_instantiation(self): - with self.assertRaises(TypeError): - typing.Dict() - with self.assertRaises(TypeError): - typing.Dict[KT, VT]() - with self.assertRaises(TypeError): - typing.Dict[str, int]() - - def test_dict_subclass(self): - - class MyDict(typing.Dict[str, int]): - pass - - d = MyDict() - self.assertIsInstance(d, MyDict) - self.assertIsInstance(d, typing.MutableMapping) - - self.assertIsSubclass(MyDict, dict) - self.assertNotIsSubclass(dict, MyDict) - - def test_defaultdict_instantiation(self): - self.assertIs(type(typing.DefaultDict()), collections.defaultdict) - self.assertIs(type(typing.DefaultDict[KT, VT]()), collections.defaultdict) - self.assertIs(type(typing.DefaultDict[str, int]()), collections.defaultdict) - - def test_defaultdict_subclass(self): - - class MyDefDict(typing.DefaultDict[str, int]): - pass - - dd = MyDefDict() - self.assertIsInstance(dd, MyDefDict) - - self.assertIsSubclass(MyDefDict, collections.defaultdict) - self.assertNotIsSubclass(collections.defaultdict, MyDefDict) - - def test_deque_instantiation(self): - self.assertIs(type(typing.Deque()), collections.deque) - self.assertIs(type(typing.Deque[T]()), collections.deque) - self.assertIs(type(typing.Deque[int]()), collections.deque) - class D(typing.Deque[T]): pass - self.assertIs(type(D[int]()), D) - - def test_counter_instantiation(self): - self.assertIs(type(typing.Counter()), collections.Counter) - self.assertIs(type(typing.Counter[T]()), collections.Counter) - self.assertIs(type(typing.Counter[int]()), collections.Counter) - class C(typing.Counter[T]): pass - self.assertIs(type(C[int]()), C) - - def test_counter_subclass_instantiation(self): - - class MyCounter(typing.Counter[int]): - pass - - d = MyCounter() - self.assertIsInstance(d, MyCounter) - self.assertIsInstance(d, typing.Counter) - self.assertIsInstance(d, collections.Counter) - - def test_no_set_instantiation(self): - with self.assertRaises(TypeError): - typing.Set() - with self.assertRaises(TypeError): - typing.Set[T]() - with self.assertRaises(TypeError): - typing.Set[int]() - - def test_set_subclass_instantiation(self): - - class MySet(typing.Set[int]): - pass - - d = MySet() - self.assertIsInstance(d, MySet) - - def test_no_frozenset_instantiation(self): - with self.assertRaises(TypeError): - typing.FrozenSet() - with self.assertRaises(TypeError): - typing.FrozenSet[T]() - with self.assertRaises(TypeError): - typing.FrozenSet[int]() - - def test_frozenset_subclass_instantiation(self): - - class MyFrozenSet(typing.FrozenSet[int]): - pass - - d = MyFrozenSet() - self.assertIsInstance(d, MyFrozenSet) - - def test_no_tuple_instantiation(self): - with self.assertRaises(TypeError): - Tuple() - with self.assertRaises(TypeError): - Tuple[T]() - with self.assertRaises(TypeError): - Tuple[int]() - - def test_generator(self): - def foo(): - yield 42 - g = foo() - self.assertIsSubclass(type(g), typing.Generator) - - def test_no_generator_instantiation(self): - with self.assertRaises(TypeError): - typing.Generator() - with self.assertRaises(TypeError): - typing.Generator[T, T, T]() - with self.assertRaises(TypeError): - typing.Generator[int, int, int]() - - def test_subclassing(self): - - class MMA(typing.MutableMapping): - pass - - with self.assertRaises(TypeError): # It's abstract - MMA() - - class MMC(MMA): - def __getitem__(self, k): - return None - def __setitem__(self, k, v): - pass - def __delitem__(self, k): - pass - def __iter__(self): - return iter(()) - def __len__(self): - return 0 - - self.assertEqual(len(MMC()), 0) - assert callable(MMC.update) - self.assertIsInstance(MMC(), typing.Mapping) - - class MMB(typing.MutableMapping[KT, VT]): - def __getitem__(self, k): - return None - def __setitem__(self, k, v): - pass - def __delitem__(self, k): - pass - def __iter__(self): - return iter(()) - def __len__(self): - return 0 - - self.assertEqual(len(MMB()), 0) - self.assertEqual(len(MMB[str, str]()), 0) - self.assertEqual(len(MMB[KT, VT]()), 0) - - self.assertNotIsSubclass(dict, MMA) - self.assertNotIsSubclass(dict, MMB) - - self.assertIsSubclass(MMA, typing.Mapping) - self.assertIsSubclass(MMB, typing.Mapping) - self.assertIsSubclass(MMC, typing.Mapping) - - self.assertIsInstance(MMB[KT, VT](), typing.Mapping) - self.assertIsInstance(MMB[KT, VT](), collections.Mapping) - - self.assertIsSubclass(MMA, collections.Mapping) - self.assertIsSubclass(MMB, collections.Mapping) - self.assertIsSubclass(MMC, collections.Mapping) - - self.assertIsSubclass(MMB[str, str], typing.Mapping) - self.assertIsSubclass(MMC, MMA) - - class It(typing.Iterable): pass - self.assertNotIsSubclass(list, It) - - class G(typing.Generator[int, int, int]): pass - def g(): yield 0 - self.assertIsSubclass(G, typing.Generator) - self.assertIsSubclass(G, typing.Iterable) - if hasattr(collections, 'Generator'): - self.assertIsSubclass(G, collections.Generator) - self.assertIsSubclass(G, collections.Iterable) - self.assertNotIsSubclass(type(g), G) - - def test_subclassing_subclasshook(self): - - class Base(typing.Iterable): - @classmethod - def __subclasshook__(cls, other): - if other.__name__ == 'Foo': - return True - else: - return False - - class C(Base): pass - class Foo: pass - class Bar: pass - self.assertIsSubclass(Foo, Base) - self.assertIsSubclass(Foo, C) - self.assertNotIsSubclass(Bar, C) - - def test_subclassing_register(self): - - class A(typing.Container): pass - class B(A): pass - - class C: pass - A.register(C) - self.assertIsSubclass(C, A) - self.assertNotIsSubclass(C, B) - - class D: pass - B.register(D) - self.assertIsSubclass(D, A) - self.assertIsSubclass(D, B) - - class M(): pass - collections.MutableMapping.register(M) - self.assertIsSubclass(M, typing.Mapping) - - def test_collections_as_base(self): - - class M(collections.Mapping): pass - self.assertIsSubclass(M, typing.Mapping) - self.assertIsSubclass(M, typing.Iterable) - - class S(collections.MutableSequence): pass - self.assertIsSubclass(S, typing.MutableSequence) - self.assertIsSubclass(S, typing.Iterable) - - class It(collections.Iterable): pass - self.assertIsSubclass(It, typing.Iterable) - - class A(collections.Mapping): pass - class B: pass - A.register(B) - self.assertIsSubclass(B, typing.Mapping) - - -class OtherABCTests(BaseTestCase): - - def test_contextmanager(self): - @contextlib.contextmanager - def manager(): - yield 42 - - cm = manager() - self.assertIsInstance(cm, typing.ContextManager) - self.assertNotIsInstance(42, typing.ContextManager) - - -class TypeTests(BaseTestCase): - - def test_type_basic(self): - - class User(object): pass - class BasicUser(User): pass - class ProUser(User): pass - - def new_user(user_class): - # type: (Type[User]) -> User - return user_class() - - new_user(BasicUser) - - def test_type_typevar(self): - - class User(object): pass - class BasicUser(User): pass - class ProUser(User): pass - - global U - U = TypeVar('U', bound=User) - - def new_user(user_class): - # type: (Type[U]) -> U - return user_class() - - new_user(BasicUser) - - def test_type_optional(self): - A = Optional[Type[BaseException]] # noqa - - def foo(a): - # type: (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'), type('Joe')) - 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 NamedTupleTests(BaseTestCase): - - def test_basics(self): - Emp = NamedTuple('Emp', [('name', str), ('id', int)]) - self.assertIsSubclass(Emp, tuple) - joe = Emp('Joe', 42) - jim = Emp(name='Jim', id=1) - self.assertIsInstance(joe, Emp) - self.assertIsInstance(joe, tuple) - self.assertEqual(joe.name, 'Joe') - self.assertEqual(joe.id, 42) - self.assertEqual(jim.name, 'Jim') - self.assertEqual(jim.id, 1) - self.assertEqual(Emp.__name__, 'Emp') - self.assertEqual(Emp._fields, ('name', 'id')) - self.assertEqual(Emp._field_types, dict(name=str, id=int)) - - def test_pickle(self): - global Emp # pickle wants to reference the class by name - Emp = NamedTuple('Emp', [('name', str), ('id', int)]) - jane = Emp('jane', 37) - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - z = pickle.dumps(jane, proto) - jane2 = pickle.loads(z) - self.assertEqual(jane2, jane) - - -class TypedDictTests(BaseTestCase): - - def test_basics_iterable_syntax(self): - Emp = TypedDict(b'Emp', {'name': str, 'id': int}) - self.assertIsSubclass(Emp, dict) - self.assertIsSubclass(Emp, typing.MutableMapping) - if sys.version_info[0] >= 3: - import collections.abc - 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(b'Emp', name=str, id=int) - self.assertIsSubclass(Emp, dict) - self.assertIsSubclass(Emp, typing.MutableMapping) - if sys.version_info[0] >= 3: - import collections.abc - 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_errors(self): - Emp = TypedDict(b'Emp', {'name': str, 'id': int}) - self.assertEqual(TypedDict.__module__, 'typing') - 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) - 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_pickle(self): - global EmpD # pickle wants to reference the class by name - EmpD = TypedDict(b'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(b'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(b'D', {'x': int}, total=False) - self.assertEqual(D(), {}) - self.assertEqual(D(x=1), {'x': 1}) - self.assertEqual(D.__total__, False) - - -class IOTests(BaseTestCase): - - def test_io_submodule(self): - from typing.io import IO, TextIO, BinaryIO, __all__, __name__ - self.assertIs(IO, typing.IO) - self.assertIs(TextIO, typing.TextIO) - self.assertIs(BinaryIO, typing.BinaryIO) - self.assertEqual(set(__all__), set(['IO', 'TextIO', 'BinaryIO'])) - self.assertEqual(__name__, 'typing.io') - - -class RETests(BaseTestCase): - # Much of this is really testing _TypeAlias. - - def test_basics(self): - pat = re.compile('[a-z]+', re.I) - self.assertIsSubclass(pat.__class__, Pattern) - self.assertIsSubclass(type(pat), Pattern) - self.assertIsInstance(pat, Pattern) - - mat = pat.search('12345abcde.....') - self.assertIsSubclass(mat.__class__, Match) - self.assertIsSubclass(type(mat), Match) - self.assertIsInstance(mat, Match) - - # these should just work - Pattern[Union[str, bytes]] - Match[Union[bytes, str]] - - def test_alias_equality(self): - self.assertEqual(Pattern[str], Pattern[str]) - self.assertNotEqual(Pattern[str], Pattern[bytes]) - self.assertNotEqual(Pattern[str], Match[str]) - self.assertNotEqual(Pattern[str], str) - - def test_errors(self): - with self.assertRaises(TypeError): - # Doesn't fit AnyStr. - Pattern[int] - with self.assertRaises(TypeError): - # Can't change type vars? - Match[T] - m = Match[Union[str, bytes]] - with self.assertRaises(TypeError): - # Too complicated? - m[str] - with self.assertRaises(TypeError): - # We don't support isinstance(). - isinstance(42, Pattern[str]) - with self.assertRaises(TypeError): - # We don't support issubclass(). - issubclass(Pattern[bytes], Pattern[str]) - - def test_repr(self): - self.assertEqual(repr(Pattern), 'Pattern[~AnyStr]') - self.assertEqual(repr(Pattern[unicode]), 'Pattern[unicode]') - self.assertEqual(repr(Pattern[str]), 'Pattern[str]') - self.assertEqual(repr(Match), 'Match[~AnyStr]') - self.assertEqual(repr(Match[unicode]), 'Match[unicode]') - self.assertEqual(repr(Match[str]), 'Match[str]') - - def test_re_submodule(self): - from typing.re import Match, Pattern, __all__, __name__ - self.assertIs(Match, typing.Match) - self.assertIs(Pattern, typing.Pattern) - self.assertEqual(set(__all__), set(['Match', 'Pattern'])) - self.assertEqual(__name__, 'typing.re') - - def test_cannot_subclass(self): - with self.assertRaises(TypeError) as ex: - - class A(typing.Match): - pass - - self.assertEqual(str(ex.exception), - "Cannot subclass typing._TypeAlias") - - -class AllTests(BaseTestCase): - """Tests for __all__.""" - - def test_all(self): - from typing import __all__ as a - # Just spot-check the first and last of every category. - self.assertIn('AbstractSet', a) - self.assertIn('ValuesView', a) - self.assertIn('cast', a) - self.assertIn('overload', a) - # Check that io and re are not exported. - self.assertNotIn('io', a) - self.assertNotIn('re', a) - # Spot-check that stdlib modules aren't exported. - self.assertNotIn('os', a) - self.assertNotIn('sys', a) - # Check that Text is defined. - self.assertIn('Text', a) - # Check previously missing class. - self.assertIn('SupportsComplex', a) - - def test_respect_no_type_check(self): - @typing.no_type_check - class NoTpCheck(object): - class Inn(object): - def __init__(self, x): - # type: (this is not actually a type) -> None # noqa - pass - self.assertTrue(NoTpCheck.__no_type_check__) - self.assertTrue(NoTpCheck.Inn.__init__.__no_type_check__) - - def test_get_type_hints_dummy(self): - - def foo(x): - # type: (int) -> int - return x + 1 - - self.assertIsNone(typing.get_type_hints(foo)) - - def test_typing_compiles_with_opt(self): - file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), - 'typing.py') - try: - subprocess.check_output([sys.executable, '-OO', file_path], - stderr=subprocess.STDOUT) - except subprocess.CalledProcessError: - self.fail('Module does not compile with optimize=2 (-OO flag).') - - -if __name__ == '__main__': - main() diff --git a/python2/typing.py b/python2/typing.py deleted file mode 100644 index dd16d9af9..000000000 --- a/python2/typing.py +++ /dev/null @@ -1,2550 +0,0 @@ -from __future__ import absolute_import, unicode_literals - -import abc -from abc import abstractmethod, abstractproperty -import collections -import functools -import re as stdlib_re # Avoid confusion with the re we export. -import sys -import types -import copy -try: - import collections.abc as collections_abc -except ImportError: - import collections as collections_abc # Fallback for PY3.2. - - -# Please keep __all__ alphabetized within each category. -__all__ = [ - # Super-special typing primitives. - 'Any', - 'Callable', - 'ClassVar', - 'Final', - 'Generic', - 'Literal', - 'Optional', - 'Protocol', - 'Tuple', - 'Type', - 'TypeVar', - 'Union', - - # ABCs (from collections.abc). - 'AbstractSet', # collections.abc.Set. - 'GenericMeta', # subclass of abc.ABCMeta and a metaclass - # for 'Generic' and ABCs below. - 'ByteString', - 'Container', - 'ContextManager', - 'Hashable', - 'ItemsView', - 'Iterable', - 'Iterator', - 'KeysView', - 'Mapping', - 'MappingView', - 'MutableMapping', - 'MutableSequence', - 'MutableSet', - 'Sequence', - 'Sized', - 'ValuesView', - - # Structural checks, a.k.a. protocols. - 'Reversible', - 'SupportsAbs', - 'SupportsComplex', - 'SupportsFloat', - 'SupportsIndex', - 'SupportsInt', - - # Concrete collection types. - 'Counter', - 'Deque', - 'Dict', - 'DefaultDict', - 'List', - 'Set', - 'FrozenSet', - 'NamedTuple', # Not really a type. - 'TypedDict', # Not really a type. - 'Generator', - - # One-off things. - 'AnyStr', - 'cast', - 'final', - 'get_type_hints', - 'NewType', - 'no_type_check', - 'no_type_check_decorator', - 'NoReturn', - 'overload', - 'runtime_checkable', - 'Text', - 'TYPE_CHECKING', -] - -# The pseudo-submodules 're' and 'io' are part of the public -# namespace, but excluded from __all__ because they might stomp on -# legitimate imports of those modules. - - -def _qualname(x): - if sys.version_info[:2] >= (3, 3): - return x.__qualname__ - else: - # Fall back to just name. - return x.__name__ - - -def _trim_name(nm): - whitelist = ('_TypeAlias', '_ForwardRef', '_TypingBase', '_FinalTypingBase') - if nm.startswith('_') and nm not in whitelist: - nm = nm[1:] - return nm - - -class TypingMeta(type): - """Metaclass for most types defined in typing module - (not a part of public API). - - This also defines a dummy constructor (all the work for most typing - constructs is done in __new__) and a nicer repr(). - """ - - _is_protocol = False - - def __new__(cls, name, bases, namespace): - return super(TypingMeta, cls).__new__(cls, str(name), bases, namespace) - - @classmethod - def assert_no_subclassing(cls, bases): - for base in bases: - if isinstance(base, cls): - raise TypeError("Cannot subclass %s" % - (', '.join(map(_type_repr, bases)) or '()')) - - def __init__(self, *args, **kwds): - pass - - def _eval_type(self, globalns, localns): - """Override this in subclasses to interpret forward references. - - For example, List['C'] is internally stored as - List[_ForwardRef('C')], which should evaluate to List[C], - where C is an object found in globalns or localns (searching - localns first, of course). - """ - return self - - def _get_type_vars(self, tvars): - pass - - def __repr__(self): - qname = _trim_name(_qualname(self)) - return '%s.%s' % (self.__module__, qname) - - -class _TypingBase(object): - """Internal indicator of special typing constructs.""" - __metaclass__ = TypingMeta - __slots__ = ('__weakref__',) - - def __init__(self, *args, **kwds): - pass - - def __new__(cls, *args, **kwds): - """Constructor. - - This only exists to give a better error message in case - someone tries to subclass a special typing object (not a good idea). - """ - if (len(args) == 3 and - isinstance(args[0], str) and - isinstance(args[1], tuple)): - # Close enough. - raise TypeError("Cannot subclass %r" % cls) - return super(_TypingBase, cls).__new__(cls) - - # Things that are not classes also need these. - def _eval_type(self, globalns, localns): - return self - - def _get_type_vars(self, tvars): - pass - - def __repr__(self): - cls = type(self) - qname = _trim_name(_qualname(cls)) - return '%s.%s' % (cls.__module__, qname) - - def __call__(self, *args, **kwds): - raise TypeError("Cannot instantiate %r" % type(self)) - - -class _FinalTypingBase(_TypingBase): - """Internal mix-in class to prevent instantiation. - - Prevents instantiation unless _root=True is given in class call. - It is used to create pseudo-singleton instances Any, Union, Optional, etc. - """ - - __slots__ = () - - def __new__(cls, *args, **kwds): - self = super(_FinalTypingBase, cls).__new__(cls, *args, **kwds) - if '_root' in kwds and kwds['_root'] is True: - return self - raise TypeError("Cannot instantiate %r" % cls) - - def __reduce__(self): - return _trim_name(type(self).__name__) - - -class _ForwardRef(_TypingBase): - """Internal wrapper to hold a forward reference.""" - - __slots__ = ('__forward_arg__', '__forward_code__', - '__forward_evaluated__', '__forward_value__') - - def __init__(self, arg): - super(_ForwardRef, self).__init__(arg) - if not isinstance(arg, basestring): - raise TypeError('Forward reference must be a string -- got %r' % (arg,)) - try: - code = compile(arg, '', 'eval') - except SyntaxError: - raise SyntaxError('Forward reference must be an expression -- got %r' % - (arg,)) - self.__forward_arg__ = arg - self.__forward_code__ = code - self.__forward_evaluated__ = False - self.__forward_value__ = None - - def _eval_type(self, globalns, localns): - if not self.__forward_evaluated__ or localns is not globalns: - if globalns is None and localns is None: - globalns = localns = {} - elif globalns is None: - globalns = localns - elif localns is None: - localns = globalns - self.__forward_value__ = _type_check( - eval(self.__forward_code__, globalns, localns), - "Forward references must evaluate to types.") - self.__forward_evaluated__ = True - return self.__forward_value__ - - def __eq__(self, other): - if not isinstance(other, _ForwardRef): - return NotImplemented - return (self.__forward_arg__ == other.__forward_arg__ and - self.__forward_value__ == other.__forward_value__) - - def __hash__(self): - return hash((self.__forward_arg__, self.__forward_value__)) - - def __instancecheck__(self, obj): - raise TypeError("Forward references cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("Forward references cannot be used with issubclass().") - - def __repr__(self): - return '_ForwardRef(%r)' % (self.__forward_arg__,) - - -class _TypeAlias(_TypingBase): - """Internal helper class for defining generic variants of concrete types. - - Note that this is not a type; let's call it a pseudo-type. It cannot - be used in instance and subclass checks in parameterized form, i.e. - ``isinstance(42, Match[str])`` raises ``TypeError`` instead of returning - ``False``. - """ - - __slots__ = ('name', 'type_var', 'impl_type', 'type_checker') - - def __init__(self, name, type_var, impl_type, type_checker): - """Initializer. - - Args: - name: The name, e.g. 'Pattern'. - type_var: The type parameter, e.g. AnyStr, or the - specific type, e.g. str. - impl_type: The implementation type. - type_checker: Function that takes an impl_type instance. - and returns a value that should be a type_var instance. - """ - assert isinstance(name, basestring), repr(name) - assert isinstance(impl_type, type), repr(impl_type) - assert not isinstance(impl_type, TypingMeta), repr(impl_type) - assert isinstance(type_var, (type, _TypingBase)), repr(type_var) - self.name = name - self.type_var = type_var - self.impl_type = impl_type - self.type_checker = type_checker - - def __repr__(self): - return "%s[%s]" % (self.name, _type_repr(self.type_var)) - - def __getitem__(self, parameter): - if not isinstance(self.type_var, TypeVar): - raise TypeError("%s cannot be further parameterized." % self) - if self.type_var.__constraints__ and isinstance(parameter, type): - if not issubclass(parameter, self.type_var.__constraints__): - raise TypeError("%s is not a valid substitution for %s." % - (parameter, self.type_var)) - if isinstance(parameter, TypeVar) and parameter is not self.type_var: - raise TypeError("%s cannot be re-parameterized." % self) - return self.__class__(self.name, parameter, - self.impl_type, self.type_checker) - - def __eq__(self, other): - if not isinstance(other, _TypeAlias): - return NotImplemented - return self.name == other.name and self.type_var == other.type_var - - def __hash__(self): - return hash((self.name, self.type_var)) - - def __instancecheck__(self, obj): - if not isinstance(self.type_var, TypeVar): - raise TypeError("Parameterized type aliases cannot be used " - "with isinstance().") - return isinstance(obj, self.impl_type) - - def __subclasscheck__(self, cls): - if not isinstance(self.type_var, TypeVar): - raise TypeError("Parameterized type aliases cannot be used " - "with issubclass().") - return issubclass(cls, self.impl_type) - - -def _get_type_vars(types, tvars): - for t in types: - if isinstance(t, TypingMeta) or isinstance(t, _TypingBase): - t._get_type_vars(tvars) - - -def _type_vars(types): - tvars = [] - _get_type_vars(types, tvars) - return tuple(tvars) - - -def _eval_type(t, globalns, localns): - if isinstance(t, TypingMeta) or isinstance(t, _TypingBase): - return t._eval_type(globalns, localns) - return t - - -def _type_check(arg, msg): - """Check that the argument is a type, and return it (internal helper). - - As a special case, accept None and return type(None) instead. - Also, _TypeAlias instances (e.g. Match, Pattern) are acceptable. - - The msg argument is a human-readable error message, e.g. - - "Union[arg, ...]: arg should be a type." - - We append the repr() of the actual value (truncated to 100 chars). - """ - if arg is None: - return type(None) - if isinstance(arg, basestring): - arg = _ForwardRef(arg) - if ( - isinstance(arg, _TypingBase) and type(arg).__name__ == '_ClassVar' or - not isinstance(arg, (type, _TypingBase)) and not callable(arg) - ): - raise TypeError(msg + " Got %.100r." % (arg,)) - # Bare Union etc. are not valid as type arguments - if ( - type(arg).__name__ in ('_Union', '_Optional') and - not getattr(arg, '__origin__', None) or - isinstance(arg, TypingMeta) and arg._gorg in (Generic, Protocol) - ): - raise TypeError("Plain %s is not valid as type argument" % arg) - return arg - - -def _type_repr(obj): - """Return the repr() of an object, special-casing types (internal helper). - - If obj is a type, we return a shorter version than the default - type.__repr__, based on the module and qualified name, which is - typically enough to uniquely identify a type. For everything - else, we fall back on repr(obj). - """ - if isinstance(obj, type) and not isinstance(obj, TypingMeta): - if obj.__module__ == '__builtin__': - return _qualname(obj) - return '%s.%s' % (obj.__module__, _qualname(obj)) - if obj is Ellipsis: - return '...' - if isinstance(obj, types.FunctionType): - return obj.__name__ - return repr(obj) - - -class ClassVarMeta(TypingMeta): - """Metaclass for _ClassVar""" - - def __new__(cls, name, bases, namespace): - cls.assert_no_subclassing(bases) - self = super(ClassVarMeta, cls).__new__(cls, name, bases, namespace) - return self - - -class _ClassVar(_FinalTypingBase): - """Special type construct to mark class variables. - - An annotation wrapped in ClassVar indicates that a given - attribute is intended to be used as a class variable and - should not be set on instances of that class. Usage:: - - class Starship: - stats = {} # type: ClassVar[Dict[str, int]] # class variable - damage = 10 # type: int # instance variable - - ClassVar accepts only types and cannot be further subscribed. - - Note that ClassVar is not a class itself, and should not - be used with isinstance() or issubclass(). - """ - - __metaclass__ = ClassVarMeta - __slots__ = ('__type__',) - - def __init__(self, tp=None, _root=False): - self.__type__ = tp - - def __getitem__(self, item): - cls = type(self) - if self.__type__ is None: - return cls(_type_check(item, - '{} accepts only types.'.format(cls.__name__[1:])), - _root=True) - raise TypeError('{} cannot be further subscripted' - .format(cls.__name__[1:])) - - def _eval_type(self, globalns, localns): - return type(self)(_eval_type(self.__type__, globalns, localns), - _root=True) - - def __repr__(self): - r = super(_ClassVar, self).__repr__() - if self.__type__ is not None: - r += '[{}]'.format(_type_repr(self.__type__)) - return r - - def __hash__(self): - return hash((type(self).__name__, self.__type__)) - - def __eq__(self, other): - if not isinstance(other, _ClassVar): - return NotImplemented - if self.__type__ is not None: - return self.__type__ == other.__type__ - return self is other - - -ClassVar = _ClassVar(_root=True) - - -class _FinalMeta(TypingMeta): - """Metaclass for _Final""" - - def __new__(cls, name, bases, namespace): - cls.assert_no_subclassing(bases) - self = super(_FinalMeta, cls).__new__(cls, name, bases, namespace) - return self - - -class _Final(_FinalTypingBase): - """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. - """ - - __metaclass__ = _FinalMeta - __slots__ = ('__type__',) - - def __init__(self, tp=None, **kwds): - self.__type__ = tp - - def __getitem__(self, item): - cls = type(self) - if self.__type__ is None: - return cls(_type_check(item, - '{} accepts only single type.'.format(cls.__name__[1:])), - _root=True) - raise TypeError('{} cannot be further subscripted' - .format(cls.__name__[1:])) - - def _eval_type(self, globalns, localns): - new_tp = _eval_type(self.__type__, globalns, localns) - if new_tp == self.__type__: - return self - return type(self)(new_tp, _root=True) - - def __repr__(self): - r = super(_Final, self).__repr__() - if self.__type__ is not None: - r += '[{}]'.format(_type_repr(self.__type__)) - return r - - def __hash__(self): - return hash((type(self).__name__, self.__type__)) - - def __eq__(self, other): - if not isinstance(other, _Final): - return NotImplemented - if self.__type__ is not None: - return self.__type__ == other.__type__ - return self is other - - -Final = _Final(_root=True) - - -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. - """ - return f - - -class _LiteralMeta(TypingMeta): - """Metaclass for _Literal""" - - def __new__(cls, name, bases, namespace): - cls.assert_no_subclassing(bases) - self = super(_LiteralMeta, cls).__new__(cls, name, bases, namespace) - return self - - -class _Literal(_FinalTypingBase): - """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. - """ - - __metaclass__ = _LiteralMeta - __slots__ = ('__values__',) - - def __init__(self, values=None, **kwds): - self.__values__ = values - - def __getitem__(self, item): - cls = type(self) - if self.__values__ is None: - if not isinstance(item, tuple): - item = (item,) - return cls(values=item, - _root=True) - raise TypeError('{} cannot be further subscripted' - .format(cls.__name__[1:])) - - def _eval_type(self, globalns, localns): - return self - - def __repr__(self): - r = super(_Literal, self).__repr__() - if self.__values__ is not None: - r += '[{}]'.format(', '.join(map(_type_repr, self.__values__))) - return r - - def __hash__(self): - return hash((type(self).__name__, self.__values__)) - - def __eq__(self, other): - if not isinstance(other, _Literal): - return NotImplemented - if self.__values__ is not None: - return self.__values__ == other.__values__ - return self is other - - -Literal = _Literal(_root=True) - - -class AnyMeta(TypingMeta): - """Metaclass for Any.""" - - def __new__(cls, name, bases, namespace): - cls.assert_no_subclassing(bases) - self = super(AnyMeta, cls).__new__(cls, name, bases, namespace) - return self - - -class _Any(_FinalTypingBase): - """Special type indicating an unconstrained type. - - - Any is compatible with every type. - - Any assumed to have all methods. - - All values assumed to be instances of Any. - - Note that all the above statements are true from the point of view of - static type checkers. At runtime, Any should not be used with instance - or class checks. - """ - __metaclass__ = AnyMeta - __slots__ = () - - def __instancecheck__(self, obj): - raise TypeError("Any cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("Any cannot be used with issubclass().") - - -Any = _Any(_root=True) - - -class NoReturnMeta(TypingMeta): - """Metaclass for NoReturn.""" - - def __new__(cls, name, bases, namespace): - cls.assert_no_subclassing(bases) - self = super(NoReturnMeta, cls).__new__(cls, name, bases, namespace) - return self - - -class _NoReturn(_FinalTypingBase): - """Special type indicating functions that never return. - Example:: - - from typing import NoReturn - - def stop() -> NoReturn: - raise Exception('no way') - - This type is invalid in other positions, e.g., ``List[NoReturn]`` - will fail in static type checkers. - """ - __metaclass__ = NoReturnMeta - __slots__ = () - - def __instancecheck__(self, obj): - raise TypeError("NoReturn cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("NoReturn cannot be used with issubclass().") - - -NoReturn = _NoReturn(_root=True) - - -class TypeVarMeta(TypingMeta): - def __new__(cls, name, bases, namespace): - cls.assert_no_subclassing(bases) - return super(TypeVarMeta, cls).__new__(cls, name, bases, namespace) - - -class TypeVar(_TypingBase): - """Type variable. - - Usage:: - - T = TypeVar('T') # Can be anything - A = TypeVar('A', str, bytes) # Must be str or bytes - - Type variables exist primarily for the benefit of static type - checkers. They serve as the parameters for generic types as well - as for generic function definitions. See class Generic for more - information on generic types. Generic functions work as follows: - - def repeat(x: T, n: int) -> List[T]: - '''Return a list containing n references to x.''' - return [x]*n - - def longest(x: A, y: A) -> A: - '''Return the longest of two strings.''' - return x if len(x) >= len(y) else y - - The latter example's signature is essentially the overloading - of (str, str) -> str and (bytes, bytes) -> bytes. Also note - that if the arguments are instances of some subclass of str, - the return type is still plain str. - - At runtime, isinstance(x, T) and issubclass(C, T) will raise TypeError. - - Type variables defined with covariant=True or contravariant=True - can be used do declare covariant or contravariant generic types. - See PEP 484 for more details. By default generic types are invariant - in all type variables. - - Type variables can be introspected. e.g.: - - T.__name__ == 'T' - T.__constraints__ == () - T.__covariant__ == False - T.__contravariant__ = False - A.__constraints__ == (str, bytes) - """ - - __metaclass__ = TypeVarMeta - __slots__ = ('__name__', '__bound__', '__constraints__', - '__covariant__', '__contravariant__') - - def __init__(self, name, *constraints, **kwargs): - super(TypeVar, self).__init__(name, *constraints, **kwargs) - bound = kwargs.get('bound', None) - covariant = kwargs.get('covariant', False) - contravariant = kwargs.get('contravariant', False) - self.__name__ = name - if covariant and contravariant: - raise ValueError("Bivariant types are not supported.") - self.__covariant__ = bool(covariant) - self.__contravariant__ = bool(contravariant) - if constraints and bound is not None: - raise TypeError("Constraints cannot be combined with bound=...") - if constraints and len(constraints) == 1: - raise TypeError("A single constraint is not allowed") - msg = "TypeVar(name, constraint, ...): constraints must be types." - self.__constraints__ = tuple(_type_check(t, msg) for t in constraints) - if bound: - self.__bound__ = _type_check(bound, "Bound must be a type.") - else: - self.__bound__ = None - - def _get_type_vars(self, tvars): - if self not in tvars: - tvars.append(self) - - def __repr__(self): - if self.__covariant__: - prefix = '+' - elif self.__contravariant__: - prefix = '-' - else: - prefix = '~' - return prefix + self.__name__ - - def __instancecheck__(self, instance): - raise TypeError("Type variables cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("Type variables cannot be used with issubclass().") - - -# Some unconstrained type variables. These are used by the container types. -# (These are not for export.) -T = TypeVar('T') # Any type. -KT = TypeVar('KT') # Key type. -VT = TypeVar('VT') # Value type. -T_co = TypeVar('T_co', covariant=True) # Any type covariant containers. -V_co = TypeVar('V_co', covariant=True) # Any type covariant containers. -VT_co = TypeVar('VT_co', covariant=True) # Value type covariant containers. -T_contra = TypeVar('T_contra', contravariant=True) # Ditto contravariant. - -# A useful type variable with constraints. This represents string types. -# (This one *is* for export!) -AnyStr = TypeVar('AnyStr', bytes, unicode) - - -def _replace_arg(arg, tvars, args): - """An internal helper function: replace arg if it is a type variable - found in tvars with corresponding substitution from args or - with corresponding substitution sub-tree if arg is a generic type. - """ - - if tvars is None: - tvars = [] - if hasattr(arg, '_subs_tree') and isinstance(arg, (GenericMeta, _TypingBase)): - return arg._subs_tree(tvars, args) - if isinstance(arg, TypeVar): - for i, tvar in enumerate(tvars): - if arg == tvar: - return args[i] - return arg - - -# Special typing constructs Union, Optional, Generic, Callable and Tuple -# use three special attributes for internal bookkeeping of generic types: -# * __parameters__ is a tuple of unique free type parameters of a generic -# type, for example, Dict[T, T].__parameters__ == (T,); -# * __origin__ keeps a reference to a type that was subscripted, -# e.g., Union[T, int].__origin__ == Union; -# * __args__ is a tuple of all arguments used in subscripting, -# e.g., Dict[T, int].__args__ == (T, int). - - -def _subs_tree(cls, tvars=None, args=None): - """An internal helper function: calculate substitution tree - for generic cls after replacing its type parameters with - substitutions in tvars -> args (if any). - Repeat the same following __origin__'s. - - Return a list of arguments with all possible substitutions - performed. Arguments that are generic classes themselves are represented - as tuples (so that no new classes are created by this function). - For example: _subs_tree(List[Tuple[int, T]][str]) == [(Tuple, int, str)] - """ - - if cls.__origin__ is None: - return cls - # Make of chain of origins (i.e. cls -> cls.__origin__) - current = cls.__origin__ - orig_chain = [] - while current.__origin__ is not None: - orig_chain.append(current) - current = current.__origin__ - # Replace type variables in __args__ if asked ... - tree_args = [] - for arg in cls.__args__: - tree_args.append(_replace_arg(arg, tvars, args)) - # ... then continue replacing down the origin chain. - for ocls in orig_chain: - new_tree_args = [] - for arg in ocls.__args__: - new_tree_args.append(_replace_arg(arg, ocls.__parameters__, tree_args)) - tree_args = new_tree_args - return tree_args - - -def _remove_dups_flatten(parameters): - """An internal helper for Union creation and substitution: flatten Union's - among parameters, then remove duplicates and strict subclasses. - """ - - # Flatten out Union[Union[...], ...]. - params = [] - for p in parameters: - if isinstance(p, _Union) and p.__origin__ is Union: - params.extend(p.__args__) - elif isinstance(p, tuple) and len(p) > 0 and p[0] is Union: - params.extend(p[1:]) - else: - params.append(p) - # Weed out strict duplicates, preserving the first of each occurrence. - all_params = set(params) - if len(all_params) < len(params): - new_params = [] - for t in params: - if t in all_params: - new_params.append(t) - all_params.remove(t) - params = new_params - assert not all_params, all_params - # Weed out subclasses. - # E.g. Union[int, Employee, Manager] == Union[int, Employee]. - # If object is present it will be sole survivor among proper classes. - # Never discard type variables. - # (In particular, Union[str, AnyStr] != AnyStr.) - all_params = set(params) - for t1 in params: - if not isinstance(t1, type): - continue - if any(isinstance(t2, type) and issubclass(t1, t2) - for t2 in all_params - {t1} - if not (isinstance(t2, GenericMeta) and - t2.__origin__ is not None)): - all_params.remove(t1) - return tuple(t for t in params if t in all_params) - - -def _check_generic(cls, parameters): - # Check correct count for parameters of a generic cls (internal helper). - if not cls.__parameters__: - raise TypeError("%s is not a generic class" % repr(cls)) - alen = len(parameters) - elen = len(cls.__parameters__) - if alen != elen: - raise TypeError("Too %s parameters for %s; actual %s, expected %s" % - ("many" if alen > elen else "few", repr(cls), alen, elen)) - - -_cleanups = [] - - -def _tp_cache(func): - maxsize = 128 - cache = {} - _cleanups.append(cache.clear) - - @functools.wraps(func) - def inner(*args): - key = args - try: - return cache[key] - except TypeError: - # Assume it's an unhashable argument. - return func(*args) - except KeyError: - value = func(*args) - if len(cache) >= maxsize: - # If the cache grows too much, just start over. - cache.clear() - cache[key] = value - return value - - return inner - - -class UnionMeta(TypingMeta): - """Metaclass for Union.""" - - def __new__(cls, name, bases, namespace): - cls.assert_no_subclassing(bases) - return super(UnionMeta, cls).__new__(cls, name, bases, namespace) - - -class _Union(_FinalTypingBase): - """Union type; Union[X, Y] means either X or Y. - - To define a union, use e.g. Union[int, str]. Details: - - - The arguments must be types and there must be at least one. - - - None as an argument is a special case and is replaced by - type(None). - - - Unions of unions are flattened, e.g.:: - - Union[Union[int, str], float] == Union[int, str, float] - - - Unions of a single argument vanish, e.g.:: - - Union[int] == int # The constructor actually returns int - - - Redundant arguments are skipped, e.g.:: - - Union[int, str, int] == Union[int, str] - - - When comparing unions, the argument order is ignored, e.g.:: - - Union[int, str] == Union[str, int] - - - When two arguments have a subclass relationship, the least - derived argument is kept, e.g.:: - - class Employee: pass - class Manager(Employee): pass - Union[int, Employee, Manager] == Union[int, Employee] - Union[Manager, int, Employee] == Union[int, Employee] - Union[Employee, Manager] == Employee - - - Similar for object:: - - Union[int, object] == object - - - You cannot subclass or instantiate a union. - - - You can use Optional[X] as a shorthand for Union[X, None]. - """ - - __metaclass__ = UnionMeta - __slots__ = ('__parameters__', '__args__', '__origin__', '__tree_hash__') - - def __new__(cls, parameters=None, origin=None, *args, **kwds): - self = super(_Union, cls).__new__(cls, parameters, origin, *args, **kwds) - if origin is None: - self.__parameters__ = None - self.__args__ = None - self.__origin__ = None - self.__tree_hash__ = hash(frozenset(('Union',))) - return self - if not isinstance(parameters, tuple): - raise TypeError("Expected parameters=") - if origin is Union: - parameters = _remove_dups_flatten(parameters) - # It's not a union if there's only one type left. - if len(parameters) == 1: - return parameters[0] - self.__parameters__ = _type_vars(parameters) - self.__args__ = parameters - self.__origin__ = origin - # Pre-calculate the __hash__ on instantiation. - # This improves speed for complex substitutions. - subs_tree = self._subs_tree() - if isinstance(subs_tree, tuple): - self.__tree_hash__ = hash(frozenset(subs_tree)) - else: - self.__tree_hash__ = hash(subs_tree) - return self - - def _eval_type(self, globalns, localns): - if self.__args__ is None: - return self - ev_args = tuple(_eval_type(t, globalns, localns) for t in self.__args__) - ev_origin = _eval_type(self.__origin__, globalns, localns) - if ev_args == self.__args__ and ev_origin == self.__origin__: - # Everything is already evaluated. - return self - return self.__class__(ev_args, ev_origin, _root=True) - - def _get_type_vars(self, tvars): - if self.__origin__ and self.__parameters__: - _get_type_vars(self.__parameters__, tvars) - - def __repr__(self): - if self.__origin__ is None: - return super(_Union, self).__repr__() - tree = self._subs_tree() - if not isinstance(tree, tuple): - return repr(tree) - return tree[0]._tree_repr(tree) - - def _tree_repr(self, tree): - arg_list = [] - for arg in tree[1:]: - if not isinstance(arg, tuple): - arg_list.append(_type_repr(arg)) - else: - arg_list.append(arg[0]._tree_repr(arg)) - return super(_Union, self).__repr__() + '[%s]' % ', '.join(arg_list) - - @_tp_cache - def __getitem__(self, parameters): - if parameters == (): - raise TypeError("Cannot take a Union of no types.") - if not isinstance(parameters, tuple): - parameters = (parameters,) - if self.__origin__ is None: - msg = "Union[arg, ...]: each arg must be a type." - else: - msg = "Parameters to generic types must be types." - parameters = tuple(_type_check(p, msg) for p in parameters) - if self is not Union: - _check_generic(self, parameters) - return self.__class__(parameters, origin=self, _root=True) - - def _subs_tree(self, tvars=None, args=None): - if self is Union: - return Union # Nothing to substitute - tree_args = _subs_tree(self, tvars, args) - tree_args = _remove_dups_flatten(tree_args) - if len(tree_args) == 1: - return tree_args[0] # Union of a single type is that type - return (Union,) + tree_args - - def __eq__(self, other): - if isinstance(other, _Union): - return self.__tree_hash__ == other.__tree_hash__ - elif self is not Union: - return self._subs_tree() == other - else: - return self is other - - def __hash__(self): - return self.__tree_hash__ - - def __instancecheck__(self, obj): - raise TypeError("Unions cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("Unions cannot be used with issubclass().") - - -Union = _Union(_root=True) - - -class OptionalMeta(TypingMeta): - """Metaclass for Optional.""" - - def __new__(cls, name, bases, namespace): - cls.assert_no_subclassing(bases) - return super(OptionalMeta, cls).__new__(cls, name, bases, namespace) - - -class _Optional(_FinalTypingBase): - """Optional type. - - Optional[X] is equivalent to Union[X, None]. - """ - - __metaclass__ = OptionalMeta - __slots__ = () - - @_tp_cache - def __getitem__(self, arg): - arg = _type_check(arg, "Optional[t] requires a single type.") - return Union[arg, type(None)] - - -Optional = _Optional(_root=True) - - -def _next_in_mro(cls): - """Helper for Generic.__new__. - - Returns the class after the last occurrence of Generic or - Generic[...] in cls.__mro__. - """ - next_in_mro = object - # Look for the last occurrence of Generic or Generic[...]. - for i, c in enumerate(cls.__mro__[:-1]): - if isinstance(c, GenericMeta) and c._gorg is Generic: - next_in_mro = cls.__mro__[i + 1] - return next_in_mro - - -def _make_subclasshook(cls): - """Construct a __subclasshook__ callable that incorporates - the associated __extra__ class in subclass checks performed - against cls. - """ - if isinstance(cls.__extra__, abc.ABCMeta): - # The logic mirrors that of ABCMeta.__subclasscheck__. - # Registered classes need not be checked here because - # cls and its extra share the same _abc_registry. - def __extrahook__(cls, subclass): - res = cls.__extra__.__subclasshook__(subclass) - if res is not NotImplemented: - return res - if cls.__extra__ in getattr(subclass, '__mro__', ()): - return True - for scls in cls.__extra__.__subclasses__(): - if isinstance(scls, GenericMeta): - continue - if issubclass(subclass, scls): - return True - return NotImplemented - else: - # For non-ABC extras we'll just call issubclass(). - def __extrahook__(cls, subclass): - if cls.__extra__ and issubclass(subclass, cls.__extra__): - return True - return NotImplemented - return classmethod(__extrahook__) - - -class GenericMeta(TypingMeta, abc.ABCMeta): - """Metaclass for generic types. - - This is a metaclass for typing.Generic and generic ABCs defined in - typing module. User defined subclasses of GenericMeta can override - __new__ and invoke super().__new__. Note that GenericMeta.__new__ - has strict rules on what is allowed in its bases argument: - * plain Generic is disallowed in bases; - * Generic[...] should appear in bases at most once; - * if Generic[...] is present, then it should list all type variables - that appear in other bases. - In addition, type of all generic bases is erased, e.g., C[int] is - stripped to plain C. - """ - - def __new__(cls, name, bases, namespace, - tvars=None, args=None, origin=None, extra=None, orig_bases=None): - """Create a new generic class. GenericMeta.__new__ accepts - keyword arguments that are used for internal bookkeeping, therefore - an override should pass unused keyword arguments to super(). - """ - if tvars is not None: - # Called from __getitem__() below. - assert origin is not None - assert all(isinstance(t, TypeVar) for t in tvars), tvars - else: - # Called from class statement. - assert tvars is None, tvars - assert args is None, args - assert origin is None, origin - - # Get the full set of tvars from the bases. - tvars = _type_vars(bases) - # Look for Generic[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[...]. - gvars = None - for base in bases: - if base is Generic: - raise TypeError("Cannot inherit from plain Generic") - if (isinstance(base, GenericMeta) and - base.__origin__ in (Generic, Protocol)): - if gvars is not None: - raise TypeError( - "Cannot inherit from Generic[...] or" - " Protocol[...] multiple times.") - gvars = base.__parameters__ - if gvars is None: - gvars = tvars - else: - tvarset = set(tvars) - gvarset = set(gvars) - if not tvarset <= gvarset: - raise TypeError( - "Some type variables (%s) " - "are not listed in %s[%s]" % - (", ".join(str(t) for t in tvars if t not in gvarset), - "Generic" if any(b.__origin__ is Generic - for b in bases) else "Protocol", - ", ".join(str(g) for g in gvars))) - tvars = gvars - - initial_bases = bases - if extra is None: - extra = namespace.get('__extra__') - if extra is not None and type(extra) is abc.ABCMeta and extra not in bases: - bases = (extra,) + bases - bases = tuple(b._gorg if isinstance(b, GenericMeta) else b for b in bases) - - # remove bare Generic from bases if there are other generic bases - if any(isinstance(b, GenericMeta) and b is not Generic for b in bases): - bases = tuple(b for b in bases if b is not Generic) - namespace.update({'__origin__': origin, '__extra__': extra}) - self = super(GenericMeta, cls).__new__(cls, name, bases, namespace) - super(GenericMeta, self).__setattr__('_gorg', - self if not origin else origin._gorg) - - self.__parameters__ = tvars - # Be prepared that GenericMeta will be subclassed by TupleMeta - # and CallableMeta, those two allow ..., (), or [] in __args___. - self.__args__ = tuple(Ellipsis if a is _TypingEllipsis else - () if a is _TypingEmpty else - a for a in args) if args else None - # Speed hack (https://github.com/python/typing/issues/196). - self.__next_in_mro__ = _next_in_mro(self) - # Preserve base classes on subclassing (__bases__ are type erased now). - if orig_bases is None: - self.__orig_bases__ = initial_bases - - # This allows unparameterized generic collections to be used - # with issubclass() and isinstance() in the same way as their - # collections.abc counterparts (e.g., isinstance([], Iterable)). - if ( - '__subclasshook__' not in namespace and extra or - # allow overriding - getattr(self.__subclasshook__, '__name__', '') == '__extrahook__' - ): - self.__subclasshook__ = _make_subclasshook(self) - - if origin and hasattr(origin, '__qualname__'): # Fix for Python 3.2. - self.__qualname__ = origin.__qualname__ - self.__tree_hash__ = (hash(self._subs_tree()) if origin else - super(GenericMeta, self).__hash__()) - return self - - def __init__(self, *args, **kwargs): - super(GenericMeta, self).__init__(*args, **kwargs) - if isinstance(self.__extra__, abc.ABCMeta): - self._abc_registry = self.__extra__._abc_registry - self._abc_cache = self.__extra__._abc_cache - elif self.__origin__ is not None: - self._abc_registry = self.__origin__._abc_registry - self._abc_cache = self.__origin__._abc_cache - - # _abc_negative_cache and _abc_negative_cache_version - # realised as descriptors, since GenClass[t1, t2, ...] always - # share subclass info with GenClass. - # This is an important memory optimization. - @property - def _abc_negative_cache(self): - if isinstance(self.__extra__, abc.ABCMeta): - return self.__extra__._abc_negative_cache - return self._gorg._abc_generic_negative_cache - - @_abc_negative_cache.setter - def _abc_negative_cache(self, value): - if self.__origin__ is None: - if isinstance(self.__extra__, abc.ABCMeta): - self.__extra__._abc_negative_cache = value - else: - self._abc_generic_negative_cache = value - - @property - def _abc_negative_cache_version(self): - if isinstance(self.__extra__, abc.ABCMeta): - return self.__extra__._abc_negative_cache_version - return self._gorg._abc_generic_negative_cache_version - - @_abc_negative_cache_version.setter - def _abc_negative_cache_version(self, value): - if self.__origin__ is None: - if isinstance(self.__extra__, abc.ABCMeta): - self.__extra__._abc_negative_cache_version = value - else: - self._abc_generic_negative_cache_version = value - - def _get_type_vars(self, tvars): - if self.__origin__ and self.__parameters__: - _get_type_vars(self.__parameters__, tvars) - - def _eval_type(self, globalns, localns): - ev_origin = (self.__origin__._eval_type(globalns, localns) - if self.__origin__ else None) - ev_args = tuple(_eval_type(a, globalns, localns) for a - in self.__args__) if self.__args__ else None - if ev_origin == self.__origin__ and ev_args == self.__args__: - return self - return self.__class__(self.__name__, - self.__bases__, - dict(self.__dict__), - tvars=_type_vars(ev_args) if ev_args else None, - args=ev_args, - origin=ev_origin, - extra=self.__extra__, - orig_bases=self.__orig_bases__) - - def __repr__(self): - if self.__origin__ is None: - return super(GenericMeta, self).__repr__() - return self._tree_repr(self._subs_tree()) - - def _tree_repr(self, tree): - arg_list = [] - for arg in tree[1:]: - if arg == (): - arg_list.append('()') - elif not isinstance(arg, tuple): - arg_list.append(_type_repr(arg)) - else: - arg_list.append(arg[0]._tree_repr(arg)) - return super(GenericMeta, self).__repr__() + '[%s]' % ', '.join(arg_list) - - def _subs_tree(self, tvars=None, args=None): - if self.__origin__ is None: - return self - tree_args = _subs_tree(self, tvars, args) - return (self._gorg,) + tuple(tree_args) - - def __eq__(self, other): - if not isinstance(other, GenericMeta): - return NotImplemented - if self.__origin__ is None or other.__origin__ is None: - return self is other - return self.__tree_hash__ == other.__tree_hash__ - - def __hash__(self): - return self.__tree_hash__ - - @_tp_cache - def __getitem__(self, params): - if not isinstance(params, tuple): - params = (params,) - if not params and self._gorg is not Tuple: - raise TypeError( - "Parameter list to %s[...] cannot be empty" % _qualname(self)) - msg = "Parameters to generic types must be types." - params = tuple(_type_check(p, msg) for p in params) - if self in (Generic, Protocol): - # Generic can only be subscripted with unique type variables. - if not all(isinstance(p, TypeVar) for p in params): - raise TypeError( - "Parameters to %s[...] must all be type variables" % self.__name__) - if len(set(params)) != len(params): - raise TypeError( - "Parameters to %s[...] must all be unique" % self.__name__) - tvars = params - args = params - elif self in (Tuple, Callable): - tvars = _type_vars(params) - args = params - elif self.__origin__ in (Generic, Protocol): - # Can't subscript Generic[...] or Protocol[...]. - raise TypeError("Cannot subscript already-subscripted %s" % - repr(self)) - else: - # Subscripting a regular Generic subclass. - _check_generic(self, params) - tvars = _type_vars(params) - args = params - - prepend = (self,) if self.__origin__ is None else () - return self.__class__(self.__name__, - prepend + self.__bases__, - dict(self.__dict__), - tvars=tvars, - args=args, - origin=self, - extra=self.__extra__, - orig_bases=self.__orig_bases__) - - def __subclasscheck__(self, cls): - if self.__origin__ is not None: - # These should only be modules within the standard library. - # singledispatch is an exception, because it's a Python 2 backport - # of functools.singledispatch. - whitelist = ['abc', 'functools', 'singledispatch'] - if (sys._getframe(1).f_globals['__name__'] in whitelist or - # The second frame is needed for the case where we came - # from _ProtocolMeta.__subclasscheck__. - sys._getframe(2).f_globals['__name__'] in whitelist): - return False - raise TypeError("Parameterized generics cannot be used with class " - "or instance checks") - if self is Generic: - raise TypeError("Class %r cannot be used with class " - "or instance checks" % self) - return super(GenericMeta, self).__subclasscheck__(cls) - - def __instancecheck__(self, instance): - # Since we extend ABC.__subclasscheck__ and - # ABC.__instancecheck__ inlines the cache checking done by the - # latter, we must extend __instancecheck__ too. For simplicity - # we just skip the cache check -- instance checks for generic - # classes are supposed to be rare anyways. - if hasattr(instance, "__class__"): - return issubclass(instance.__class__, self) - return False - - def __setattr__(self, attr, value): - # We consider all the subscripted genrics as proxies for original class - if ( - attr.startswith('__') and attr.endswith('__') or - attr.startswith('_abc_') - ): - super(GenericMeta, self).__setattr__(attr, value) - else: - super(GenericMeta, self._gorg).__setattr__(attr, value) - - -def _copy_generic(self): - """Hack to work around https://bugs.python.org/issue11480 on Python 2""" - return self.__class__(self.__name__, self.__bases__, dict(self.__dict__), - self.__parameters__, self.__args__, self.__origin__, - self.__extra__, self.__orig_bases__) - - -copy._copy_dispatch[GenericMeta] = _copy_generic - - -# Prevent checks for Generic to crash when defining Generic. -Generic = None - - -def _generic_new(base_cls, cls, *args, **kwds): - # Assure type is erased on instantiation, - # but attempt to store it in __orig_class__ - if cls.__origin__ is None: - if (base_cls.__new__ is object.__new__ and - cls.__init__ is not object.__init__): - return base_cls.__new__(cls) - else: - return base_cls.__new__(cls, *args, **kwds) - else: - origin = cls._gorg - if (base_cls.__new__ is object.__new__ and - cls.__init__ is not object.__init__): - obj = base_cls.__new__(origin) - else: - obj = base_cls.__new__(origin, *args, **kwds) - try: - obj.__orig_class__ = cls - except AttributeError: - pass - obj.__init__(*args, **kwds) - return obj - - -class Generic(object): - """Abstract base class for generic types. - - A generic type is typically declared by inheriting from - this class parameterized with one or more type variables. - For example, a generic mapping type might be defined as:: - - class Mapping(Generic[KT, VT]): - def __getitem__(self, key: KT) -> VT: - ... - # Etc. - - This class can then be used as follows:: - - def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT: - try: - return mapping[key] - except KeyError: - return default - """ - - __metaclass__ = GenericMeta - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is Generic: - raise TypeError("Type Generic cannot be instantiated; " - "it can be used only as a base class") - return _generic_new(cls.__next_in_mro__, cls, *args, **kwds) - - -class _TypingEmpty(object): - """Internal placeholder for () or []. Used by TupleMeta and CallableMeta - to allow empty list/tuple in specific places, without allowing them - to sneak in where prohibited. - """ - - -class _TypingEllipsis(object): - """Internal placeholder for ... (ellipsis).""" - - -class TupleMeta(GenericMeta): - """Metaclass for Tuple (internal).""" - - @_tp_cache - def __getitem__(self, parameters): - if self.__origin__ is not None or self._gorg is not Tuple: - # Normal generic rules apply if this is not the first subscription - # or a subscription of a subclass. - return super(TupleMeta, self).__getitem__(parameters) - if parameters == (): - return super(TupleMeta, self).__getitem__((_TypingEmpty,)) - if not isinstance(parameters, tuple): - parameters = (parameters,) - if len(parameters) == 2 and parameters[1] is Ellipsis: - msg = "Tuple[t, ...]: t must be a type." - p = _type_check(parameters[0], msg) - return super(TupleMeta, self).__getitem__((p, _TypingEllipsis)) - msg = "Tuple[t0, t1, ...]: each t must be a type." - parameters = tuple(_type_check(p, msg) for p in parameters) - return super(TupleMeta, self).__getitem__(parameters) - - def __instancecheck__(self, obj): - if self.__args__ is None: - return isinstance(obj, tuple) - raise TypeError("Parameterized Tuple cannot be used " - "with isinstance().") - - def __subclasscheck__(self, cls): - if self.__args__ is None: - return issubclass(cls, tuple) - raise TypeError("Parameterized Tuple cannot be used " - "with issubclass().") - - -copy._copy_dispatch[TupleMeta] = _copy_generic - - -class Tuple(tuple): - """Tuple type; Tuple[X, Y] is the cross-product type of X and Y. - - Example: Tuple[T1, T2] is a tuple of two elements corresponding - to type variables T1 and T2. Tuple[int, float, str] is a tuple - of an int, a float and a string. - - To specify a variable-length tuple of homogeneous type, use Tuple[T, ...]. - """ - - __metaclass__ = TupleMeta - __extra__ = tuple - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is Tuple: - raise TypeError("Type Tuple cannot be instantiated; " - "use tuple() instead") - return _generic_new(tuple, cls, *args, **kwds) - - -class CallableMeta(GenericMeta): - """ Metaclass for Callable.""" - - def __repr__(self): - if self.__origin__ is None: - return super(CallableMeta, self).__repr__() - return self._tree_repr(self._subs_tree()) - - def _tree_repr(self, tree): - if self._gorg is not Callable: - return super(CallableMeta, self)._tree_repr(tree) - # For actual Callable (not its subclass) we override - # super(CallableMeta, self)._tree_repr() for nice formatting. - arg_list = [] - for arg in tree[1:]: - if not isinstance(arg, tuple): - arg_list.append(_type_repr(arg)) - else: - arg_list.append(arg[0]._tree_repr(arg)) - if arg_list[0] == '...': - return repr(tree[0]) + '[..., %s]' % arg_list[1] - return (repr(tree[0]) + - '[[%s], %s]' % (', '.join(arg_list[:-1]), arg_list[-1])) - - def __getitem__(self, parameters): - """A thin wrapper around __getitem_inner__ to provide the latter - with hashable arguments to improve speed. - """ - - if self.__origin__ is not None or self._gorg is not Callable: - return super(CallableMeta, self).__getitem__(parameters) - if not isinstance(parameters, tuple) or len(parameters) != 2: - raise TypeError("Callable must be used as " - "Callable[[arg, ...], result].") - args, result = parameters - if args is Ellipsis: - parameters = (Ellipsis, result) - else: - if not isinstance(args, list): - raise TypeError("Callable[args, result]: args must be a list." - " Got %.100r." % (args,)) - parameters = (tuple(args), result) - return self.__getitem_inner__(parameters) - - @_tp_cache - def __getitem_inner__(self, parameters): - args, result = parameters - msg = "Callable[args, result]: result must be a type." - result = _type_check(result, msg) - if args is Ellipsis: - return super(CallableMeta, self).__getitem__((_TypingEllipsis, result)) - msg = "Callable[[arg, ...], result]: each arg must be a type." - args = tuple(_type_check(arg, msg) for arg in args) - parameters = args + (result,) - return super(CallableMeta, self).__getitem__(parameters) - - -copy._copy_dispatch[CallableMeta] = _copy_generic - - -class Callable(object): - """Callable type; Callable[[int], str] is a function of (int) -> str. - - The subscription syntax must always be used with exactly two - values: the argument list and the return type. The argument list - must be a list of types or ellipsis; the return type must be a single type. - - There is no syntax to indicate optional or keyword arguments, - such function types are rarely used as callback types. - """ - - __metaclass__ = CallableMeta - __extra__ = collections_abc.Callable - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is Callable: - raise TypeError("Type Callable cannot be instantiated; " - "use a non-abstract subclass instead") - return _generic_new(cls.__next_in_mro__, cls, *args, **kwds) - - -def cast(typ, val): - """Cast a value to a type. - - This returns the value unchanged. To the type checker this - signals that the return value has the designated type, but at - runtime we intentionally don't check anything (we want this - to be as fast as possible). - """ - return val - - -def _get_defaults(func): - """Internal helper to extract the default arguments, by name.""" - code = func.__code__ - pos_count = code.co_argcount - arg_names = code.co_varnames - arg_names = arg_names[:pos_count] - defaults = func.__defaults__ or () - kwdefaults = func.__kwdefaults__ - res = dict(kwdefaults) if kwdefaults else {} - pos_offset = pos_count - len(defaults) - for name, value in zip(arg_names[pos_offset:], defaults): - assert name not in res - res[name] = value - return res - - -def get_type_hints(obj, globalns=None, localns=None): - """In Python 2 this is not supported and always returns None.""" - return None - - -def no_type_check(arg): - """Decorator to indicate that annotations are not type hints. - - The argument must be a class or function; if it is a class, it - applies recursively to all methods and classes defined in that class - (but not to methods defined in its superclasses or subclasses). - - This mutates the function(s) or class(es) in place. - """ - if isinstance(arg, type): - arg_attrs = arg.__dict__.copy() - for attr, val in arg.__dict__.items(): - if val in arg.__bases__ + (arg,): - arg_attrs.pop(attr) - for obj in arg_attrs.values(): - if isinstance(obj, types.FunctionType): - obj.__no_type_check__ = True - if isinstance(obj, type): - no_type_check(obj) - try: - arg.__no_type_check__ = True - except TypeError: # built-in classes - pass - return arg - - -def no_type_check_decorator(decorator): - """Decorator to give another decorator the @no_type_check effect. - - This wraps the decorator with something that wraps the decorated - function in @no_type_check. - """ - - @functools.wraps(decorator) - def wrapped_decorator(*args, **kwds): - func = decorator(*args, **kwds) - func = no_type_check(func) - return func - - return wrapped_decorator - - -def _overload_dummy(*args, **kwds): - """Helper for @overload to raise when called.""" - raise NotImplementedError( - "You should not call an overloaded function. " - "A series of @overload-decorated functions " - "outside a stub module should always be followed " - "by an implementation that is not @overload-ed.") - - -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 - """ - return _overload_dummy - - -_PROTO_WHITELIST = ['Callable', 'Iterable', 'Iterator', - 'Hashable', 'Sized', 'Container', 'Collection', - 'Reversible', 'ContextManager'] - - -class _ProtocolMeta(GenericMeta): - """Internal metaclass for Protocol. - - This exists so Protocol classes can be generic without deriving - from Generic. - """ - def __init__(cls, *args, **kwargs): - super(_ProtocolMeta, cls).__init__(*args, **kwargs) - if not cls.__dict__.get('_is_protocol', None): - cls._is_protocol = any(b is Protocol or - isinstance(b, _ProtocolMeta) and - b.__origin__ is Protocol - for b in cls.__bases__) - if cls._is_protocol: - for base in cls.__mro__[1:]: - if not (base in (object, Generic) or - base.__module__ == '_abcoll' and - base.__name__ in _PROTO_WHITELIST or - isinstance(base, TypingMeta) and base._is_protocol or - isinstance(base, GenericMeta) and base.__origin__ is Generic): - raise TypeError('Protocols can only inherit from other protocols,' - ' got %r' % base) - cls._callable_members_only = all(callable(getattr(cls, attr)) - for attr in cls._get_protocol_attrs()) - - def _no_init(self, *args, **kwargs): - if type(self)._is_protocol: - raise TypeError('Protocols cannot be instantiated') - cls.__init__ = _no_init - - def _proto_hook(cls, other): - if not cls.__dict__.get('_is_protocol', None): - return NotImplemented - if not isinstance(other, type): - # Similar error as for issubclass(1, int) - # (also not a chance for old-style classes) - raise TypeError('issubclass() arg 1 must be a new-style class') - for attr in cls._get_protocol_attrs(): - for base in other.__mro__: - if attr in base.__dict__: - if base.__dict__[attr] is None: - return NotImplemented - break - else: - return NotImplemented - return True - if '__subclasshook__' not in cls.__dict__: - cls.__subclasshook__ = classmethod(_proto_hook) - - def __instancecheck__(self, instance): - # We need this method for situations where attributes are assigned in __init__ - if isinstance(instance, type): - # This looks like a fundamental limitation of Python 2. - # It cannot support runtime protocol metaclasses, On Python 2 classes - # cannot be correctly inspected as instances of protocols. - return False - if ((not getattr(self, '_is_protocol', False) or - self._callable_members_only) and - issubclass(instance.__class__, self)): - return True - if self._is_protocol: - if all(hasattr(instance, attr) and - (not callable(getattr(self, attr)) or - getattr(instance, attr) is not None) - for attr in self._get_protocol_attrs()): - return True - return super(GenericMeta, self).__instancecheck__(instance) - - def __subclasscheck__(self, cls): - if (self.__dict__.get('_is_protocol', None) and - not self.__dict__.get('_is_runtime_protocol', None)): - if (sys._getframe(1).f_globals['__name__'] in ['abc', 'functools'] or - # This is needed because we remove subclasses from unions on Python 2. - sys._getframe(2).f_globals['__name__'] == 'typing'): - return False - raise TypeError("Instance and class checks can only be used with" - " @runtime_checkable protocols") - if (self.__dict__.get('_is_runtime_protocol', None) and - not self._callable_members_only): - if sys._getframe(1).f_globals['__name__'] in ['abc', 'functools']: - return super(GenericMeta, self).__subclasscheck__(cls) - raise TypeError("Protocols with non-method members" - " don't support issubclass()") - return super(_ProtocolMeta, self).__subclasscheck__(cls) - - def _get_protocol_attrs(self): - attrs = set() - for base in self.__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__', '_get_protocol_attrs', - '__next_in_mro__', '__parameters__', '__origin__', - '__orig_bases__', '__extra__', '__tree_hash__', - '__doc__', '__subclasshook__', '__init__', '__new__', - '__module__', '_MutableMapping__marker', - '__metaclass__', '_gorg', '_callable_members_only')): - attrs.add(attr) - return attrs - - -class Protocol(object): - """Base class for protocol classes. Protocol classes are defined as:: - - class Proto(Protocol): - def meth(self): - # type: () -> int - pass - - Such classes are primarily used with static type checkers that recognize - structural subtyping (static duck-typing), for example:: - - class C: - def meth(self): - # type: () -> int - return 0 - - def func(x): - # type: (Proto) -> int - return x.meth() - - func(C()) # Passes static type check - - See PEP 544 for details. Protocol classes decorated with @typing.runtime_checkable - act as simple-minded runtime protocols 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): - # type: () -> T - pass - """ - - __metaclass__ = _ProtocolMeta - __slots__ = () - _is_protocol = True - - def __new__(cls, *args, **kwds): - if cls._gorg is Protocol: - raise TypeError("Type Protocol cannot be instantiated; " - "it can be used only as a base class") - return _generic_new(cls.__next_in_mro__, cls, *args, **kwds) - - -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,' - ' got %r' % cls) - cls._is_runtime_protocol = True - return cls - - -# Various ABCs mimicking those in collections.abc. -# A few are simply re-exported for completeness. - -Hashable = collections_abc.Hashable # Not generic. - - -class Iterable(Generic[T_co]): - __slots__ = () - __extra__ = collections_abc.Iterable - - -class Iterator(Iterable[T_co]): - __slots__ = () - __extra__ = collections_abc.Iterator - - -@runtime_checkable -class SupportsInt(Protocol): - __slots__ = () - - @abstractmethod - def __int__(self): - pass - - -@runtime_checkable -class SupportsFloat(Protocol): - __slots__ = () - - @abstractmethod - def __float__(self): - pass - - -@runtime_checkable -class SupportsComplex(Protocol): - __slots__ = () - - @abstractmethod - def __complex__(self): - pass - - -@runtime_checkable -class SupportsIndex(Protocol): - __slots__ = () - - @abstractmethod - def __index__(self): - pass - - -@runtime_checkable -class SupportsAbs(Protocol[T_co]): - __slots__ = () - - @abstractmethod - def __abs__(self): - pass - - -if hasattr(collections_abc, 'Reversible'): - class Reversible(Iterable[T_co]): - __slots__ = () - __extra__ = collections_abc.Reversible -else: - @runtime_checkable - class Reversible(Protocol[T_co]): - __slots__ = () - - @abstractmethod - def __reversed__(self): - pass - - -Sized = collections_abc.Sized # Not generic. - - -class Container(Generic[T_co]): - __slots__ = () - __extra__ = collections_abc.Container - - -# Callable was defined earlier. - - -class AbstractSet(Sized, Iterable[T_co], Container[T_co]): - __slots__ = () - __extra__ = collections_abc.Set - - -class MutableSet(AbstractSet[T]): - __slots__ = () - __extra__ = collections_abc.MutableSet - - -# NOTE: It is only covariant in the value type. -class Mapping(Sized, Iterable[KT], Container[KT], Generic[KT, VT_co]): - __slots__ = () - __extra__ = collections_abc.Mapping - - -class MutableMapping(Mapping[KT, VT]): - __slots__ = () - __extra__ = collections_abc.MutableMapping - - -if hasattr(collections_abc, 'Reversible'): - class Sequence(Sized, Reversible[T_co], Container[T_co]): - __slots__ = () - __extra__ = collections_abc.Sequence -else: - class Sequence(Sized, Iterable[T_co], Container[T_co]): - __slots__ = () - __extra__ = collections_abc.Sequence - - -class MutableSequence(Sequence[T]): - __slots__ = () - __extra__ = collections_abc.MutableSequence - - -class ByteString(Sequence[int]): - pass - - -ByteString.register(str) -ByteString.register(bytearray) - - -class List(list, MutableSequence[T]): - __slots__ = () - __extra__ = list - - def __new__(cls, *args, **kwds): - if cls._gorg is List: - raise TypeError("Type List cannot be instantiated; " - "use list() instead") - return _generic_new(list, cls, *args, **kwds) - - -class Deque(collections.deque, MutableSequence[T]): - __slots__ = () - __extra__ = collections.deque - - def __new__(cls, *args, **kwds): - if cls._gorg is Deque: - return collections.deque(*args, **kwds) - return _generic_new(collections.deque, cls, *args, **kwds) - - -class Set(set, MutableSet[T]): - __slots__ = () - __extra__ = set - - def __new__(cls, *args, **kwds): - if cls._gorg is Set: - raise TypeError("Type Set cannot be instantiated; " - "use set() instead") - return _generic_new(set, cls, *args, **kwds) - - -class FrozenSet(frozenset, AbstractSet[T_co]): - __slots__ = () - __extra__ = frozenset - - def __new__(cls, *args, **kwds): - if cls._gorg is FrozenSet: - raise TypeError("Type FrozenSet cannot be instantiated; " - "use frozenset() instead") - return _generic_new(frozenset, cls, *args, **kwds) - - -class MappingView(Sized, Iterable[T_co]): - __slots__ = () - __extra__ = collections_abc.MappingView - - -class KeysView(MappingView[KT], AbstractSet[KT]): - __slots__ = () - __extra__ = collections_abc.KeysView - - -class ItemsView(MappingView[Tuple[KT, VT_co]], - AbstractSet[Tuple[KT, VT_co]], - Generic[KT, VT_co]): - __slots__ = () - __extra__ = collections_abc.ItemsView - - -class ValuesView(MappingView[VT_co]): - __slots__ = () - __extra__ = collections_abc.ValuesView - - -class ContextManager(Generic[T_co]): - __slots__ = () - - def __enter__(self): - return self - - @abc.abstractmethod - def __exit__(self, exc_type, exc_value, traceback): - return None - - @classmethod - def __subclasshook__(cls, C): - if cls is ContextManager: - # In Python 3.6+, it is possible to set a method to None to - # explicitly indicate that the class does not implement an ABC - # (https://bugs.python.org/issue25958), but we do not support - # that pattern here because this fallback class is only used - # in Python 3.5 and earlier. - if (any("__enter__" in B.__dict__ for B in C.__mro__) and - any("__exit__" in B.__dict__ for B in C.__mro__)): - return True - return NotImplemented - - -class Dict(dict, MutableMapping[KT, VT]): - __slots__ = () - __extra__ = dict - - def __new__(cls, *args, **kwds): - if cls._gorg is Dict: - raise TypeError("Type Dict cannot be instantiated; " - "use dict() instead") - return _generic_new(dict, cls, *args, **kwds) - - -class DefaultDict(collections.defaultdict, MutableMapping[KT, VT]): - __slots__ = () - __extra__ = collections.defaultdict - - def __new__(cls, *args, **kwds): - if cls._gorg is DefaultDict: - return collections.defaultdict(*args, **kwds) - return _generic_new(collections.defaultdict, cls, *args, **kwds) - - -class Counter(collections.Counter, Dict[T, int]): - __slots__ = () - __extra__ = collections.Counter - - def __new__(cls, *args, **kwds): - if cls._gorg is Counter: - return collections.Counter(*args, **kwds) - return _generic_new(collections.Counter, cls, *args, **kwds) - - -# Determine what base class to use for Generator. -if hasattr(collections_abc, 'Generator'): - # Sufficiently recent versions of 3.5 have a Generator ABC. - _G_base = collections_abc.Generator -else: - # Fall back on the exact type. - _G_base = types.GeneratorType - - -class Generator(Iterator[T_co], Generic[T_co, T_contra, V_co]): - __slots__ = () - __extra__ = _G_base - - def __new__(cls, *args, **kwds): - if cls._gorg is Generator: - raise TypeError("Type Generator cannot be instantiated; " - "create a subclass instead") - return _generic_new(_G_base, cls, *args, **kwds) - - -# Internal type variable used for Type[]. -CT_co = TypeVar('CT_co', covariant=True, bound=type) - - -# This is not a real generic class. Don't use outside annotations. -class Type(Generic[CT_co]): - """A special construct usable to annotate class objects. - - For example, suppose we have the following classes:: - - class User: ... # Abstract base for User classes - class BasicUser(User): ... - class ProUser(User): ... - class TeamUser(User): ... - - And a function that takes a class argument that's a subclass of - User and returns an instance of the corresponding class:: - - U = TypeVar('U', bound=User) - def new_user(user_class: Type[U]) -> U: - user = user_class() - # (Here we could write the user object to a database) - return user - - joe = new_user(BasicUser) - - At this point the type checker knows that joe has type BasicUser. - """ - __slots__ = () - __extra__ = type - - -def NamedTuple(typename, fields): - """Typed version of namedtuple. - - Usage:: - - Employee = typing.NamedTuple('Employee', [('name', str), ('id', int)]) - - This is equivalent to:: - - Employee = collections.namedtuple('Employee', ['name', 'id']) - - The resulting class has one extra attribute: _field_types, - giving a dict mapping field names to types. (The field names - are in the _fields attribute, which is part of the namedtuple - API.) - """ - fields = [(n, t) for n, t in fields] - cls = collections.namedtuple(typename, [n for n, t in fields]) - cls._field_types = dict(fields) - # Set the module to the caller's module (otherwise it'd be 'typing'). - try: - cls.__module__ = sys._getframe(1).f_globals.get('__name__', '__main__') - except (AttributeError, ValueError): - pass - return cls - - -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(cls, *args, **kwargs): - return dict(*args, **kwargs) - - -def _typeddict_new(cls, _typename, _fields=None, **kwargs): - total = kwargs.pop('total', True) - 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), '__total__': total} - 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) - - -class _TypedDictMeta(type): - 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 == b'TypedDict' else _dict_new - tp_dict = super(_TypedDictMeta, cls).__new__(cls, name, (dict,), ns) - - anns = ns.get('__annotations__', {}) - msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type" - anns = {n: _type_check(tp, msg) for n, tp in anns.items()} - for base in bases: - anns.update(base.__dict__.get('__annotations__', {})) - tp_dict.__annotations__ = anns - if not hasattr(tp_dict, '__total__'): - tp_dict.__total__ = total - return tp_dict - - __instancecheck__ = __subclasscheck__ = _check_fails - - -TypedDict = _TypedDictMeta(b'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:: - - Point2D = TypedDict('Point2D', {'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 could be accessed via Point2D.__annotations__. TypedDict - supports an additional equivalent form:: - - Point2D = TypedDict('Point2D', x=int, y=int, label=str) - """ - - -def NewType(name, tp): - """NewType creates simple unique types with almost zero - runtime overhead. NewType(name, tp) is considered a subtype of tp - by static type checkers. At runtime, NewType(name, tp) returns - a dummy function that simply returns its argument. Usage:: - - UserId = NewType('UserId', int) - - def name_by_id(user_id): - # type: (UserId) -> str - ... - - UserId('user') # Fails type check - - name_by_id(42) # Fails type check - name_by_id(UserId(42)) # OK - - num = UserId(5) + 1 # type: int - """ - - def new_type(x): - return x - - # Some versions of Python 2 complain because of making all strings unicode - new_type.__name__ = str(name) - new_type.__supertype__ = tp - return new_type - - -# Python-version-specific alias (Python 2: unicode; Python 3: str) -Text = unicode - - -# Constant that's True when type checking, but False here. -TYPE_CHECKING = False - - -class IO(Generic[AnyStr]): - """Generic base class for TextIO and BinaryIO. - - This is an abstract, generic version of the return of open(). - - NOTE: This does not distinguish between the different possible - classes (text vs. binary, read vs. write vs. read/write, - append-only, unbuffered). The TextIO and BinaryIO subclasses - below capture the distinctions between text vs. binary, which is - pervasive in the interface; however we currently do not offer a - way to track the other distinctions in the type system. - """ - - __slots__ = () - - @abstractproperty - def mode(self): - pass - - @abstractproperty - def name(self): - pass - - @abstractmethod - def close(self): - pass - - @abstractproperty - def closed(self): - pass - - @abstractmethod - def fileno(self): - pass - - @abstractmethod - def flush(self): - pass - - @abstractmethod - def isatty(self): - pass - - @abstractmethod - def read(self, n=-1): - pass - - @abstractmethod - def readable(self): - pass - - @abstractmethod - def readline(self, limit=-1): - pass - - @abstractmethod - def readlines(self, hint=-1): - pass - - @abstractmethod - def seek(self, offset, whence=0): - pass - - @abstractmethod - def seekable(self): - pass - - @abstractmethod - def tell(self): - pass - - @abstractmethod - def truncate(self, size=None): - pass - - @abstractmethod - def writable(self): - pass - - @abstractmethod - def write(self, s): - pass - - @abstractmethod - def writelines(self, lines): - pass - - @abstractmethod - def __enter__(self): - pass - - @abstractmethod - def __exit__(self, type, value, traceback): - pass - - -class BinaryIO(IO[bytes]): - """Typed version of the return of open() in binary mode.""" - - __slots__ = () - - @abstractmethod - def write(self, s): - pass - - @abstractmethod - def __enter__(self): - pass - - -class TextIO(IO[unicode]): - """Typed version of the return of open() in text mode.""" - - __slots__ = () - - @abstractproperty - def buffer(self): - pass - - @abstractproperty - def encoding(self): - pass - - @abstractproperty - def errors(self): - pass - - @abstractproperty - def line_buffering(self): - pass - - @abstractproperty - def newlines(self): - pass - - @abstractmethod - def __enter__(self): - pass - - -class io(object): - """Wrapper namespace for IO generic classes.""" - - __all__ = ['IO', 'TextIO', 'BinaryIO'] - IO = IO - TextIO = TextIO - BinaryIO = BinaryIO - - -io.__name__ = __name__ + b'.io' -sys.modules[io.__name__] = io - - -Pattern = _TypeAlias('Pattern', AnyStr, type(stdlib_re.compile('')), - lambda p: p.pattern) -Match = _TypeAlias('Match', AnyStr, type(stdlib_re.match('', '')), - lambda m: m.re.pattern) - - -class re(object): - """Wrapper namespace for re type aliases.""" - - __all__ = ['Pattern', 'Match'] - Pattern = Pattern - Match = Match - - -re.__name__ = __name__ + b'.re' -sys.modules[re.__name__] = re diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 637292647..000000000 --- a/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[metadata] -license-file = LICENSE diff --git a/setup.py b/setup.py deleted file mode 100644 index 49578939c..000000000 --- a/setup.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python -# coding: utf-8 - -import sys -from setuptools import setup - -if sys.version_info < (2, 7, 0) or (3, 0, 0) <= sys.version_info < (3, 4, 0): - sys.stderr.write('ERROR: You need Python 2.7 or 3.4+ ' - 'to install the typing package.\n') - exit(1) - -version = '3.10.0.0' -description = 'Type Hints for Python' -long_description = '''\ -Typing -- Type Hints for Python - -This is a backport of the standard library typing module to Python -versions older than 3.5. (See note below for newer versions.) - -Typing defines a standard notation for Python function and variable -type annotations. The notation can be used for documenting code in a -concise, standard format, and it has been designed to also be used by -static and runtime type checkers, static analyzers, IDEs and other -tools. - -NOTE: in Python 3.5 and later, the typing module lives in the stdlib, -and installing this package has NO EFFECT, because stdlib takes higher -precedence than the installation directory. To get a newer version of -the typing module in Python 3.5 or later, you have to upgrade to a -newer Python (bugfix) version. For example, typing in Python 3.6.0 is -missing the definition of 'Type' -- upgrading to 3.6.2 will fix this. - -Also note that most improvements to the typing module in Python 3.7 -will not be included in this package, since Python 3.7 has some -built-in support that is not present in older versions (See PEP 560.) - -For package maintainers, it is preferred to use -``typing;python_version<"3.5"`` if your package requires it to support -earlier Python versions. This will avoid shadowing the stdlib typing -module when your package is installed via ``pip install -t .`` on -Python 3.5 or later. -''' - -package_dir = {2: 'python2', 3: 'src'}[sys.version_info.major] - -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 :: 2.7', - 'Programming Language :: Python :: 3.4', - 'Topic :: Software Development', -] - -setup(name='typing', - version=version, - description=description, - long_description=long_description, - author='Guido van Rossum, Jukka Lehtosalo, Łukasz Langa, Ivan Levkivskyi', - author_email='jukka.lehtosalo@iki.fi', - url='https://docs.python.org/3/library/typing.html', - project_urls={'Source': 'https://github.com/python/typing'}, - license='PSF', - keywords='typing function annotations type hints hinting checking ' - 'checker typehints typehinting typechecking backport', - package_dir={'': package_dir}, - py_modules=['typing'], - python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <3.5', - classifiers=classifiers) diff --git a/src/mod_generics_cache.py b/src/mod_generics_cache.py deleted file mode 100644 index 51cef0f03..000000000 --- a/src/mod_generics_cache.py +++ /dev/null @@ -1,49 +0,0 @@ -"""Module for testing the behavior of generics across different modules.""" - -import sys -from textwrap import dedent -from typing import TypeVar, Generic, Optional - - -if sys.version_info[:2] >= (3, 6): - exec(dedent(""" - default_a: Optional['A'] = None - default_b: Optional['B'] = None - - T = TypeVar('T') - - class A(Generic[T]): - some_b: 'B' - - class B(Generic[T]): - class A(Generic[T]): - pass - - my_inner_a1: 'B.A' - my_inner_a2: A - my_outer_a: 'A' # unless somebody calls get_type_hints with localns=B.__dict__ - """)) -else: # This should stay in sync with the syntax above. - __annotations__ = dict( - default_a=Optional['A'], - default_b=Optional['B'], - ) - default_a = None - default_b = None - - T = TypeVar('T') - - class A(Generic[T]): - __annotations__ = dict( - some_b='B' - ) - - class B(Generic[T]): - class A(Generic[T]): - pass - - __annotations__ = dict( - my_inner_a1='B.A', - my_inner_a2=A, - my_outer_a='A' # unless somebody calls get_type_hints with localns=B.__dict__ - ) diff --git a/src/test_typing.py b/src/test_typing.py deleted file mode 100644 index a987a8dc7..000000000 --- a/src/test_typing.py +++ /dev/null @@ -1,2815 +0,0 @@ -import contextlib -import collections -import os -import pickle -import re -import subprocess -import sys -from unittest import TestCase, main, skipUnless, SkipTest, expectedFailure -from copy import copy, deepcopy - -from typing import Any, NoReturn -from typing import TypeVar, AnyStr -from typing import T, KT, VT # Not in __all__. -from typing import Union, Optional -from typing import Tuple, List, MutableMapping, Iterator -from typing import Callable -from typing import Generic, ClassVar, GenericMeta -from typing import cast -from typing import get_type_hints -from typing import no_type_check, no_type_check_decorator -from typing import Type -from typing import NewType -from typing import NamedTuple -from typing import IO, TextIO, BinaryIO -from typing import Pattern, Match -import abc -import typing -import weakref -try: - import collections.abc as collections_abc -except ImportError: - import collections as collections_abc # Fallback for PY3.2. - - -try: - import mod_generics_cache -except ImportError: - # try to use the builtin one, Python 3.5+ - from test import mod_generics_cache - - -PY36 = sys.version_info[:2] >= (3, 6) - - -class BaseTestCase(TestCase): - - def assertIsSubclass(self, cls, class_or_tuple, msg=None): - if not issubclass(cls, class_or_tuple): - message = '%r is not a subclass of %r' % (cls, class_or_tuple) - if msg is not None: - message += ' : %s' % msg - raise self.failureException(message) - - def assertNotIsSubclass(self, cls, class_or_tuple, msg=None): - if issubclass(cls, class_or_tuple): - message = '%r is a subclass of %r' % (cls, class_or_tuple) - if msg is not None: - message += ' : %s' % msg - raise self.failureException(message) - - def clear_caches(self): - for f in typing._cleanups: - f() - - -class Employee: - pass - - -class Manager(Employee): - pass - - -class Founder(Employee): - pass - - -class ManagingFounder(Manager, Founder): - pass - - -class AnyTests(BaseTestCase): - - def test_any_instance_type_error(self): - with self.assertRaises(TypeError): - isinstance(42, Any) - - def test_any_subclass_type_error(self): - with self.assertRaises(TypeError): - issubclass(Employee, Any) - with self.assertRaises(TypeError): - issubclass(Any, Employee) - - def test_repr(self): - self.assertEqual(repr(Any), 'typing.Any') - - def test_errors(self): - with self.assertRaises(TypeError): - issubclass(42, Any) - with self.assertRaises(TypeError): - Any[int] # Any is not a generic type. - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class A(Any): - pass - with self.assertRaises(TypeError): - class A(type(Any)): - pass - - def test_cannot_instantiate(self): - with self.assertRaises(TypeError): - Any() - with self.assertRaises(TypeError): - type(Any)() - - def test_any_works_with_alias(self): - # These expressions must simply not fail. - typing.Match[Any] - typing.Pattern[Any] - typing.IO[Any] - - -class NoReturnTests(BaseTestCase): - - def test_noreturn_instance_type_error(self): - with self.assertRaises(TypeError): - isinstance(42, NoReturn) - - def test_noreturn_subclass_type_error(self): - with self.assertRaises(TypeError): - issubclass(Employee, NoReturn) - with self.assertRaises(TypeError): - issubclass(NoReturn, Employee) - - def test_repr(self): - self.assertEqual(repr(NoReturn), 'typing.NoReturn') - - def test_not_generic(self): - with self.assertRaises(TypeError): - NoReturn[int] - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class A(NoReturn): - pass - with self.assertRaises(TypeError): - class A(type(NoReturn)): - pass - - def test_cannot_instantiate(self): - with self.assertRaises(TypeError): - NoReturn() - with self.assertRaises(TypeError): - type(NoReturn)() - - -class TypeVarTests(BaseTestCase): - - def test_basic_plain(self): - T = TypeVar('T') - # T equals itself. - self.assertEqual(T, T) - # T is an instance of TypeVar - self.assertIsInstance(T, TypeVar) - - def test_typevar_instance_type_error(self): - T = TypeVar('T') - with self.assertRaises(TypeError): - isinstance(42, T) - - def test_typevar_subclass_type_error(self): - T = TypeVar('T') - with self.assertRaises(TypeError): - issubclass(int, T) - with self.assertRaises(TypeError): - issubclass(T, int) - - def test_constrained_error(self): - with self.assertRaises(TypeError): - X = TypeVar('X', int) - X - - def test_union_unique(self): - X = TypeVar('X') - Y = TypeVar('Y') - self.assertNotEqual(X, Y) - self.assertEqual(Union[X], X) - self.assertNotEqual(Union[X], Union[X, Y]) - self.assertEqual(Union[X, X], X) - self.assertNotEqual(Union[X, int], Union[X]) - self.assertNotEqual(Union[X, int], Union[int]) - self.assertEqual(Union[X, int].__args__, (X, int)) - self.assertEqual(Union[X, int].__parameters__, (X,)) - self.assertIs(Union[X, int].__origin__, Union) - - def test_union_constrained(self): - A = TypeVar('A', str, bytes) - self.assertNotEqual(Union[A, str], Union[A]) - - def test_repr(self): - self.assertEqual(repr(T), '~T') - self.assertEqual(repr(KT), '~KT') - self.assertEqual(repr(VT), '~VT') - self.assertEqual(repr(AnyStr), '~AnyStr') - T_co = TypeVar('T_co', covariant=True) - self.assertEqual(repr(T_co), '+T_co') - T_contra = TypeVar('T_contra', contravariant=True) - self.assertEqual(repr(T_contra), '-T_contra') - - def test_no_redefinition(self): - self.assertNotEqual(TypeVar('T'), TypeVar('T')) - self.assertNotEqual(TypeVar('T', int, str), TypeVar('T', int, str)) - - def test_cannot_subclass_vars(self): - with self.assertRaises(TypeError): - class V(TypeVar('T')): - pass - - def test_cannot_subclass_var_itself(self): - with self.assertRaises(TypeError): - class V(TypeVar): - pass - - def test_cannot_instantiate_vars(self): - with self.assertRaises(TypeError): - TypeVar('A')() - - def test_bound_errors(self): - with self.assertRaises(TypeError): - TypeVar('X', bound=42) - with self.assertRaises(TypeError): - TypeVar('X', str, float, bound=Employee) - - def test_no_bivariant(self): - with self.assertRaises(ValueError): - TypeVar('T', covariant=True, contravariant=True) - - -class UnionTests(BaseTestCase): - - def test_basics(self): - u = Union[int, float] - self.assertNotEqual(u, Union) - - def test_subclass_error(self): - with self.assertRaises(TypeError): - issubclass(int, Union) - with self.assertRaises(TypeError): - issubclass(Union, int) - with self.assertRaises(TypeError): - issubclass(int, Union[int, str]) - with self.assertRaises(TypeError): - issubclass(Union[int, str], int) - - def test_union_any(self): - u = Union[Any] - self.assertEqual(u, Any) - u1 = Union[int, Any] - u2 = Union[Any, int] - u3 = Union[Any, object] - self.assertEqual(u1, u2) - self.assertNotEqual(u1, Any) - self.assertNotEqual(u2, Any) - self.assertNotEqual(u3, Any) - - def test_union_object(self): - u = Union[object] - self.assertEqual(u, object) - u = Union[int, object] - self.assertEqual(u, object) - u = Union[object, int] - self.assertEqual(u, object) - - def test_unordered(self): - u1 = Union[int, float] - u2 = Union[float, int] - self.assertEqual(u1, u2) - - def test_single_class_disappears(self): - t = Union[Employee] - self.assertIs(t, Employee) - - def test_base_class_disappears(self): - u = Union[Employee, Manager, int] - self.assertEqual(u, Union[int, Employee]) - u = Union[Manager, int, Employee] - self.assertEqual(u, Union[int, Employee]) - u = Union[Employee, Manager] - self.assertIs(u, Employee) - - def test_union_union(self): - u = Union[int, float] - v = Union[u, Employee] - self.assertEqual(v, Union[int, float, Employee]) - - def test_repr(self): - self.assertEqual(repr(Union), 'typing.Union') - u = Union[Employee, int] - self.assertEqual(repr(u), 'typing.Union[%s.Employee, int]' % __name__) - u = Union[int, Employee] - self.assertEqual(repr(u), 'typing.Union[int, %s.Employee]' % __name__) - T = TypeVar('T') - u = Union[T, int][int] - self.assertEqual(repr(u), repr(int)) - u = Union[List[int], int] - self.assertEqual(repr(u), 'typing.Union[typing.List[int], int]') - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class C(Union): - pass - with self.assertRaises(TypeError): - class C(type(Union)): - pass - with self.assertRaises(TypeError): - class C(Union[int, str]): - pass - - def test_cannot_instantiate(self): - with self.assertRaises(TypeError): - Union() - with self.assertRaises(TypeError): - type(Union)() - u = Union[int, float] - with self.assertRaises(TypeError): - u() - with self.assertRaises(TypeError): - type(u)() - - def test_union_generalization(self): - self.assertFalse(Union[str, typing.Iterable[int]] == str) - self.assertFalse(Union[str, typing.Iterable[int]] == typing.Iterable[int]) - self.assertTrue(Union[str, typing.Iterable] == typing.Iterable) - - def test_union_compare_other(self): - self.assertNotEqual(Union, object) - self.assertNotEqual(Union, Any) - self.assertNotEqual(ClassVar, Union) - self.assertNotEqual(Optional, Union) - self.assertNotEqual([None], Optional) - self.assertNotEqual(Optional, typing.Mapping) - self.assertNotEqual(Optional[typing.MutableMapping], Union) - - def test_optional(self): - o = Optional[int] - u = Union[int, None] - self.assertEqual(o, u) - - def test_empty(self): - with self.assertRaises(TypeError): - Union[()] - - def test_union_instance_type_error(self): - with self.assertRaises(TypeError): - isinstance(42, Union[int, str]) - - def test_no_eval_union(self): - u = Union[int, str] - def f(x: u): ... - self.assertIs(get_type_hints(f)['x'], u) - - def test_function_repr_union(self): - def fun() -> int: ... - self.assertEqual(repr(Union[fun, int]), 'typing.Union[fun, int]') - - def test_union_str_pattern(self): - # Shouldn't crash; see http://bugs.python.org/issue25390 - A = Union[str, Pattern] - A - - def test_etree(self): - # See https://github.com/python/typing/issues/229 - # (Only relevant for Python 2.) - try: - from xml.etree.cElementTree import Element - except ImportError: - raise SkipTest("cElementTree not found") - Union[Element, str] # Shouldn't crash - - def Elem(*args): - return Element(*args) - - Union[Elem, str] # Nor should this - - -class TupleTests(BaseTestCase): - - def test_basics(self): - with self.assertRaises(TypeError): - issubclass(Tuple, Tuple[int, str]) - with self.assertRaises(TypeError): - issubclass(tuple, Tuple[int, str]) - - class TP(tuple): ... - self.assertTrue(issubclass(tuple, Tuple)) - self.assertTrue(issubclass(TP, Tuple)) - - def test_equality(self): - self.assertEqual(Tuple[int], Tuple[int]) - self.assertEqual(Tuple[int, ...], Tuple[int, ...]) - self.assertNotEqual(Tuple[int], Tuple[int, int]) - self.assertNotEqual(Tuple[int], Tuple[int, ...]) - - def test_tuple_subclass(self): - class MyTuple(tuple): - pass - self.assertTrue(issubclass(MyTuple, Tuple)) - - def test_tuple_instance_type_error(self): - with self.assertRaises(TypeError): - isinstance((0, 0), Tuple[int, int]) - self.assertIsInstance((0, 0), Tuple) - - def test_repr(self): - self.assertEqual(repr(Tuple), 'typing.Tuple') - self.assertEqual(repr(Tuple[()]), 'typing.Tuple[()]') - self.assertEqual(repr(Tuple[int, float]), 'typing.Tuple[int, float]') - self.assertEqual(repr(Tuple[int, ...]), 'typing.Tuple[int, ...]') - - def test_errors(self): - with self.assertRaises(TypeError): - issubclass(42, Tuple) - with self.assertRaises(TypeError): - issubclass(42, Tuple[int]) - - -class CallableTests(BaseTestCase): - - def test_self_subclass(self): - with self.assertRaises(TypeError): - self.assertTrue(issubclass(type(lambda x: x), Callable[[int], int])) - self.assertTrue(issubclass(type(lambda x: x), Callable)) - - def test_eq_hash(self): - self.assertEqual(Callable[[int], int], Callable[[int], int]) - self.assertEqual(len({Callable[[int], int], Callable[[int], int]}), 1) - self.assertNotEqual(Callable[[int], int], Callable[[int], str]) - self.assertNotEqual(Callable[[int], int], Callable[[str], int]) - self.assertNotEqual(Callable[[int], int], Callable[[int, int], int]) - self.assertNotEqual(Callable[[int], int], Callable[[], int]) - self.assertNotEqual(Callable[[int], int], Callable) - - def test_cannot_instantiate(self): - with self.assertRaises(TypeError): - Callable() - with self.assertRaises(TypeError): - type(Callable)() - c = Callable[[int], str] - with self.assertRaises(TypeError): - c() - with self.assertRaises(TypeError): - type(c)() - - def test_callable_wrong_forms(self): - with self.assertRaises(TypeError): - Callable[[...], int] - with self.assertRaises(TypeError): - Callable[(), int] - with self.assertRaises(TypeError): - Callable[[()], int] - with self.assertRaises(TypeError): - Callable[[int, 1], 2] - with self.assertRaises(TypeError): - Callable[int] - - def test_callable_instance_works(self): - def f(): - pass - self.assertIsInstance(f, Callable) - self.assertNotIsInstance(None, Callable) - - def test_callable_instance_type_error(self): - def f(): - pass - with self.assertRaises(TypeError): - self.assertIsInstance(f, Callable[[], None]) - with self.assertRaises(TypeError): - self.assertIsInstance(f, Callable[[], Any]) - with self.assertRaises(TypeError): - self.assertNotIsInstance(None, Callable[[], None]) - with self.assertRaises(TypeError): - self.assertNotIsInstance(None, Callable[[], Any]) - - def test_repr(self): - ct0 = Callable[[], bool] - self.assertEqual(repr(ct0), 'typing.Callable[[], bool]') - ct2 = Callable[[str, float], int] - self.assertEqual(repr(ct2), 'typing.Callable[[str, float], int]') - ctv = Callable[..., str] - self.assertEqual(repr(ctv), 'typing.Callable[..., str]') - - def test_callable_with_ellipsis(self): - - def foo(a: Callable[..., T]): - pass - - self.assertEqual(get_type_hints(foo, globals(), locals()), - {'a': Callable[..., T]}) - - def test_ellipsis_in_generic(self): - # Shouldn't crash; see https://github.com/python/typing/issues/259 - typing.List[Callable[..., str]] - - -XK = TypeVar('XK', str, bytes) -XV = TypeVar('XV') - - -class SimpleMapping(Generic[XK, XV]): - - def __getitem__(self, key: XK) -> XV: - ... - - def __setitem__(self, key: XK, value: XV): - ... - - def get(self, key: XK, default: XV = None) -> XV: - ... - - -class MySimpleMapping(SimpleMapping[XK, XV]): - - def __init__(self): - self.store = {} - - def __getitem__(self, key: str): - return self.store[key] - - def __setitem__(self, key: str, value): - self.store[key] = value - - def get(self, key: str, default=None): - try: - return self.store[key] - except KeyError: - return default - - -class ProtocolTests(BaseTestCase): - - def test_supports_int(self): - self.assertIsSubclass(int, typing.SupportsInt) - self.assertNotIsSubclass(str, typing.SupportsInt) - - def test_supports_float(self): - self.assertIsSubclass(float, typing.SupportsFloat) - self.assertNotIsSubclass(str, typing.SupportsFloat) - - def test_supports_complex(self): - - # Note: complex itself doesn't have __complex__. - class C: - def __complex__(self): - return 0j - - self.assertIsSubclass(C, typing.SupportsComplex) - self.assertNotIsSubclass(str, typing.SupportsComplex) - - def test_supports_bytes(self): - - # Note: bytes itself doesn't have __bytes__. - class B: - def __bytes__(self): - return b'' - - self.assertIsSubclass(B, typing.SupportsBytes) - self.assertNotIsSubclass(str, typing.SupportsBytes) - - def test_supports_abs(self): - self.assertIsSubclass(float, typing.SupportsAbs) - self.assertIsSubclass(int, typing.SupportsAbs) - self.assertNotIsSubclass(str, typing.SupportsAbs) - - def test_supports_round(self): - issubclass(float, typing.SupportsRound) - self.assertIsSubclass(float, typing.SupportsRound) - self.assertIsSubclass(int, typing.SupportsRound) - self.assertNotIsSubclass(str, typing.SupportsRound) - - def test_reversible(self): - self.assertIsSubclass(list, typing.Reversible) - self.assertNotIsSubclass(int, typing.Reversible) - - def test_supports_index(self): - self.assertIsSubclass(int, typing.SupportsIndex) - self.assertNotIsSubclass(str, typing.SupportsIndex) - - def test_protocol_instance_type_error(self): - with self.assertRaises(TypeError): - isinstance(0, typing.SupportsAbs) - class C1(typing.SupportsInt): - def __int__(self) -> int: - return 42 - class C2(C1): - pass - c = C2() - self.assertIsInstance(c, C1) - - -class GenericTests(BaseTestCase): - - def test_basics(self): - X = SimpleMapping[str, Any] - self.assertEqual(X.__parameters__, ()) - with self.assertRaises(TypeError): - X[str] - with self.assertRaises(TypeError): - X[str, str] - Y = SimpleMapping[XK, str] - self.assertEqual(Y.__parameters__, (XK,)) - Y[str] - with self.assertRaises(TypeError): - Y[str, str] - self.assertIsSubclass(SimpleMapping[str, int], SimpleMapping) - - def test_generic_errors(self): - T = TypeVar('T') - S = TypeVar('S') - with self.assertRaises(TypeError): - Generic[T]() - with self.assertRaises(TypeError): - Generic[T][T] - with self.assertRaises(TypeError): - Generic[T][S] - with self.assertRaises(TypeError): - isinstance([], List[int]) - with self.assertRaises(TypeError): - issubclass(list, List[int]) - with self.assertRaises(TypeError): - class NewGeneric(Generic): ... - with self.assertRaises(TypeError): - class MyGeneric(Generic[T], Generic[S]): ... - with self.assertRaises(TypeError): - class MyGeneric(List[T], Generic[S]): ... - - def test_init(self): - T = TypeVar('T') - S = TypeVar('S') - with self.assertRaises(TypeError): - Generic[T, T] - with self.assertRaises(TypeError): - Generic[T, S, T] - - @skipUnless(PY36, "__init_subclass__ support required") - def test_init_subclass(self): - class X(typing.Generic[T]): - def __init_subclass__(cls, **kwargs): - super().__init_subclass__(**kwargs) - cls.attr = 42 - class Y(X): - pass - self.assertEqual(Y.attr, 42) - with self.assertRaises(AttributeError): - X.attr - X.attr = 1 - Y.attr = 2 - class Z(Y): - pass - class W(X[int]): - pass - self.assertEqual(Y.attr, 2) - self.assertEqual(Z.attr, 42) - self.assertEqual(W.attr, 42) - - def test_repr(self): - self.assertEqual(repr(SimpleMapping), - __name__ + '.' + 'SimpleMapping') - self.assertEqual(repr(MySimpleMapping), - __name__ + '.' + 'MySimpleMapping') - - def test_chain_repr(self): - T = TypeVar('T') - S = TypeVar('S') - - class C(Generic[T]): - pass - - X = C[Tuple[S, T]] - self.assertEqual(X, C[Tuple[S, T]]) - self.assertNotEqual(X, C[Tuple[T, S]]) - - Y = X[T, int] - self.assertEqual(Y, X[T, int]) - self.assertNotEqual(Y, X[S, int]) - self.assertNotEqual(Y, X[T, str]) - - Z = Y[str] - self.assertEqual(Z, Y[str]) - self.assertNotEqual(Z, Y[int]) - self.assertNotEqual(Z, Y[T]) - - self.assertTrue(str(Z).endswith( - '.C[typing.Tuple[str, int]]')) - - def test_new_repr(self): - T = TypeVar('T') - U = TypeVar('U', covariant=True) - S = TypeVar('S') - - self.assertEqual(repr(List), 'typing.List') - self.assertEqual(repr(List[T]), 'typing.List[~T]') - self.assertEqual(repr(List[U]), 'typing.List[+U]') - self.assertEqual(repr(List[S][T][int]), 'typing.List[int]') - self.assertEqual(repr(List[int]), 'typing.List[int]') - - def test_new_repr_complex(self): - T = TypeVar('T') - TS = TypeVar('TS') - - self.assertEqual(repr(typing.Mapping[T, TS][TS, T]), 'typing.Mapping[~TS, ~T]') - self.assertEqual(repr(List[Tuple[T, TS]][int, T]), - 'typing.List[typing.Tuple[int, ~T]]') - self.assertEqual( - repr(List[Tuple[T, T]][List[int]]), - 'typing.List[typing.Tuple[typing.List[int], typing.List[int]]]' - ) - - def test_new_repr_bare(self): - T = TypeVar('T') - self.assertEqual(repr(Generic[T]), 'typing.Generic[~T]') - self.assertEqual(repr(typing._Protocol[T]), 'typing.Protocol[~T]') - class C(typing.Dict[Any, Any]): ... - # this line should just work - repr(C.__mro__) - - def test_dict(self): - T = TypeVar('T') - - class B(Generic[T]): - pass - - b = B() - b.foo = 42 - self.assertEqual(b.__dict__, {'foo': 42}) - - class C(B[int]): - pass - - c = C() - c.bar = 'abc' - self.assertEqual(c.__dict__, {'bar': 'abc'}) - - def test_subscripted_generics_as_proxies(self): - T = TypeVar('T') - class C(Generic[T]): - x = 'def' - self.assertEqual(C[int].x, 'def') - self.assertEqual(C[C[int]].x, 'def') - C[C[int]].x = 'changed' - self.assertEqual(C.x, 'changed') - self.assertEqual(C[str].x, 'changed') - C[List[str]].z = 'new' - self.assertEqual(C.z, 'new') - self.assertEqual(C[Tuple[int]].z, 'new') - - self.assertEqual(C().x, 'changed') - self.assertEqual(C[Tuple[str]]().z, 'new') - - class D(C[T]): - pass - self.assertEqual(D[int].x, 'changed') - self.assertEqual(D.z, 'new') - D.z = 'from derived z' - D[int].x = 'from derived x' - self.assertEqual(C.x, 'changed') - self.assertEqual(C[int].z, 'new') - self.assertEqual(D.x, 'from derived x') - self.assertEqual(D[str].z, 'from derived z') - - def test_abc_registry_kept(self): - T = TypeVar('T') - class C(Generic[T]): ... - C.register(int) - self.assertIsInstance(1, C) - C[int] - self.assertIsInstance(1, C) - - def test_false_subclasses(self): - class MyMapping(MutableMapping[str, str]): pass - self.assertNotIsInstance({}, MyMapping) - self.assertNotIsSubclass(dict, MyMapping) - - def test_abc_bases(self): - class MM(MutableMapping[str, str]): - def __getitem__(self, k): - return None - def __setitem__(self, k, v): - pass - def __delitem__(self, k): - pass - def __iter__(self): - return iter(()) - def __len__(self): - return 0 - # this should just work - MM().update() - self.assertIsInstance(MM(), collections_abc.MutableMapping) - self.assertIsInstance(MM(), MutableMapping) - self.assertNotIsInstance(MM(), List) - self.assertNotIsInstance({}, MM) - - def test_multiple_bases(self): - class MM1(MutableMapping[str, str], collections_abc.MutableMapping): - pass - with self.assertRaises(TypeError): - # consistent MRO not possible - class MM2(collections_abc.MutableMapping, MutableMapping[str, str]): - pass - - def test_orig_bases(self): - T = TypeVar('T') - class C(typing.Dict[str, T]): ... - self.assertEqual(C.__orig_bases__, (typing.Dict[str, T],)) - - def test_naive_runtime_checks(self): - def naive_dict_check(obj, tp): - # Check if a dictionary conforms to Dict type - if len(tp.__parameters__) > 0: - raise NotImplementedError - if tp.__args__: - KT, VT = tp.__args__ - return all( - isinstance(k, KT) and isinstance(v, VT) - for k, v in obj.items() - ) - self.assertTrue(naive_dict_check({'x': 1}, typing.Dict[str, int])) - self.assertFalse(naive_dict_check({1: 'x'}, typing.Dict[str, int])) - with self.assertRaises(NotImplementedError): - naive_dict_check({1: 'x'}, typing.Dict[str, T]) - - def naive_generic_check(obj, tp): - # Check if an instance conforms to the generic class - if not hasattr(obj, '__orig_class__'): - raise NotImplementedError - return obj.__orig_class__ == tp - class Node(Generic[T]): ... - self.assertTrue(naive_generic_check(Node[int](), Node[int])) - self.assertFalse(naive_generic_check(Node[str](), Node[int])) - self.assertFalse(naive_generic_check(Node[str](), List)) - with self.assertRaises(NotImplementedError): - naive_generic_check([1, 2, 3], Node[int]) - - def naive_list_base_check(obj, tp): - # Check if list conforms to a List subclass - return all(isinstance(x, tp.__orig_bases__[0].__args__[0]) - for x in obj) - class C(List[int]): ... - self.assertTrue(naive_list_base_check([1, 2, 3], C)) - self.assertFalse(naive_list_base_check(['a', 'b'], C)) - - def test_multi_subscr_base(self): - T = TypeVar('T') - U = TypeVar('U') - V = TypeVar('V') - class C(List[T][U][V]): ... - class D(C, List[T][U][V]): ... - self.assertEqual(C.__parameters__, (V,)) - self.assertEqual(D.__parameters__, (V,)) - self.assertEqual(C[int].__parameters__, ()) - self.assertEqual(D[int].__parameters__, ()) - self.assertEqual(C[int].__args__, (int,)) - self.assertEqual(D[int].__args__, (int,)) - self.assertEqual(C.__bases__, (List,)) - self.assertEqual(D.__bases__, (C, List)) - self.assertEqual(C.__orig_bases__, (List[T][U][V],)) - self.assertEqual(D.__orig_bases__, (C, List[T][U][V])) - - def test_subscript_meta(self): - T = TypeVar('T') - self.assertEqual(Type[GenericMeta], Type[GenericMeta]) - self.assertEqual(Union[T, int][GenericMeta], Union[GenericMeta, int]) - self.assertEqual(Callable[..., GenericMeta].__args__, (Ellipsis, GenericMeta)) - - def test_generic_hashes(self): - class A(Generic[T]): - ... - - class B(Generic[T]): - class A(Generic[T]): - ... - - self.assertEqual(A, A) - self.assertEqual(mod_generics_cache.A[str], mod_generics_cache.A[str]) - self.assertEqual(B.A, B.A) - self.assertEqual(mod_generics_cache.B.A[B.A[str]], - mod_generics_cache.B.A[B.A[str]]) - - self.assertNotEqual(A, B.A) - self.assertNotEqual(A, mod_generics_cache.A) - self.assertNotEqual(A, mod_generics_cache.B.A) - self.assertNotEqual(B.A, mod_generics_cache.A) - self.assertNotEqual(B.A, mod_generics_cache.B.A) - - self.assertNotEqual(A[str], B.A[str]) - self.assertNotEqual(A[List[Any]], B.A[List[Any]]) - self.assertNotEqual(A[str], mod_generics_cache.A[str]) - self.assertNotEqual(A[str], mod_generics_cache.B.A[str]) - self.assertNotEqual(B.A[int], mod_generics_cache.A[int]) - self.assertNotEqual(B.A[List[Any]], mod_generics_cache.B.A[List[Any]]) - - self.assertNotEqual(Tuple[A[str]], Tuple[B.A[str]]) - self.assertNotEqual(Tuple[A[List[Any]]], Tuple[B.A[List[Any]]]) - self.assertNotEqual(Union[str, A[str]], Union[str, mod_generics_cache.A[str]]) - self.assertNotEqual(Union[A[str], A[str]], - Union[A[str], mod_generics_cache.A[str]]) - self.assertNotEqual(typing.FrozenSet[A[str]], - typing.FrozenSet[mod_generics_cache.B.A[str]]) - - if sys.version_info[:2] > (3, 2): - self.assertTrue(repr(Tuple[A[str]]).endswith('.A[str]]')) - self.assertTrue(repr(Tuple[B.A[str]]).endswith('.B.A[str]]')) - self.assertTrue(repr(Tuple[mod_generics_cache.A[str]]) - .endswith('mod_generics_cache.A[str]]')) - self.assertTrue(repr(Tuple[mod_generics_cache.B.A[str]]) - .endswith('mod_generics_cache.B.A[str]]')) - - def test_extended_generic_rules_eq(self): - T = TypeVar('T') - U = TypeVar('U') - self.assertEqual(Tuple[T, T][int], Tuple[int, int]) - self.assertEqual(typing.Iterable[Tuple[T, T]][T], typing.Iterable[Tuple[T, T]]) - with self.assertRaises(TypeError): - Tuple[T, int][()] - with self.assertRaises(TypeError): - Tuple[T, U][T, ...] - - self.assertEqual(Union[T, int][int], int) - self.assertEqual(Union[T, U][int, Union[int, str]], Union[int, str]) - class Base: ... - class Derived(Base): ... - self.assertEqual(Union[T, Base][Derived], Base) - with self.assertRaises(TypeError): - Union[T, int][1] - - self.assertEqual(Callable[[T], T][KT], Callable[[KT], KT]) - self.assertEqual(Callable[..., List[T]][int], Callable[..., List[int]]) - with self.assertRaises(TypeError): - Callable[[T], U][..., int] - with self.assertRaises(TypeError): - Callable[[T], U][[], int] - - def test_extended_generic_rules_repr(self): - T = TypeVar('T') - self.assertEqual(repr(Union[Tuple, Callable]).replace('typing.', ''), - 'Union[Tuple, Callable]') - self.assertEqual(repr(Union[Tuple, Tuple[int]]).replace('typing.', ''), - 'Tuple') - self.assertEqual(repr(Callable[..., Optional[T]][int]).replace('typing.', ''), - 'Callable[..., Union[int, NoneType]]') - self.assertEqual(repr(Callable[[], List[T]][int]).replace('typing.', ''), - 'Callable[[], List[int]]') - - def test_generic_forward_ref(self): - def foobar(x: List[List['CC']]): ... - class CC: ... - self.assertEqual( - get_type_hints(foobar, globals(), locals()), - {'x': List[List[CC]]} - ) - T = TypeVar('T') - AT = Tuple[T, ...] - def barfoo(x: AT): ... - self.assertIs(get_type_hints(barfoo, globals(), locals())['x'], AT) - CT = Callable[..., List[T]] - def barfoo2(x: CT): ... - self.assertIs(get_type_hints(barfoo2, globals(), locals())['x'], CT) - - def test_extended_generic_rules_subclassing(self): - class T1(Tuple[T, KT]): ... - class T2(Tuple[T, ...]): ... - class C1(Callable[[T], T]): ... - class C2(Callable[..., int]): - def __call__(self): - return None - - self.assertEqual(T1.__parameters__, (T, KT)) - self.assertEqual(T1[int, str].__args__, (int, str)) - self.assertEqual(T1[int, T].__origin__, T1) - - self.assertEqual(T2.__parameters__, (T,)) - with self.assertRaises(TypeError): - T1[int] - with self.assertRaises(TypeError): - T2[int, str] - - self.assertEqual(repr(C1[int]).split('.')[-1], 'C1[int]') - self.assertEqual(C2.__parameters__, ()) - self.assertIsInstance(C2(), collections_abc.Callable) - self.assertIsSubclass(C2, collections_abc.Callable) - self.assertIsSubclass(C1, collections_abc.Callable) - self.assertIsInstance(T1(), tuple) - self.assertIsSubclass(T2, tuple) - self.assertIsSubclass(Tuple[int, ...], typing.Sequence) - self.assertIsSubclass(Tuple[int, ...], typing.Iterable) - - def test_fail_with_bare_union(self): - with self.assertRaises(TypeError): - List[Union] - with self.assertRaises(TypeError): - Tuple[Optional] - with self.assertRaises(TypeError): - ClassVar[ClassVar] - with self.assertRaises(TypeError): - List[ClassVar[int]] - - def test_fail_with_bare_generic(self): - T = TypeVar('T') - with self.assertRaises(TypeError): - List[Generic] - with self.assertRaises(TypeError): - Tuple[Generic[T]] - with self.assertRaises(TypeError): - List[typing._Protocol] - with self.assertRaises(TypeError): - isinstance(1, Generic) - - def test_type_erasure_special(self): - T = TypeVar('T') - # this is the only test that checks type caching - self.clear_caches() - class MyTup(Tuple[T, T]): ... - self.assertIs(MyTup[int]().__class__, MyTup) - self.assertIs(MyTup[int]().__orig_class__, MyTup[int]) - class MyCall(Callable[..., T]): - def __call__(self): return None - self.assertIs(MyCall[T]().__class__, MyCall) - self.assertIs(MyCall[T]().__orig_class__, MyCall[T]) - class MyDict(typing.Dict[T, T]): ... - self.assertIs(MyDict[int]().__class__, MyDict) - self.assertIs(MyDict[int]().__orig_class__, MyDict[int]) - class MyDef(typing.DefaultDict[str, T]): ... - self.assertIs(MyDef[int]().__class__, MyDef) - self.assertIs(MyDef[int]().__orig_class__, MyDef[int]) - # ChainMap was added in 3.3 - if sys.version_info >= (3, 3): - class MyChain(typing.ChainMap[str, T]): ... - self.assertIs(MyChain[int]().__class__, MyChain) - self.assertIs(MyChain[int]().__orig_class__, MyChain[int]) - - def test_all_repr_eq_any(self): - objs = (getattr(typing, el) for el in typing.__all__) - for obj in objs: - self.assertNotEqual(repr(obj), '') - self.assertEqual(obj, obj) - if getattr(obj, '__parameters__', None) and len(obj.__parameters__) == 1: - self.assertEqual(obj[Any].__args__, (Any,)) - if isinstance(obj, type): - for base in obj.__mro__: - self.assertNotEqual(repr(base), '') - self.assertEqual(base, base) - - def test_substitution_helper(self): - T = TypeVar('T') - KT = TypeVar('KT') - VT = TypeVar('VT') - class Map(Generic[KT, VT]): - def meth(self, k: KT, v: VT): ... - StrMap = Map[str, T] - obj = StrMap[int]() - - new_args = typing._subs_tree(obj.__orig_class__) - new_annots = {k: typing._replace_arg(v, type(obj).__parameters__, new_args) - for k, v in obj.meth.__annotations__.items()} - - self.assertEqual(new_annots, {'k': str, 'v': int}) - - def test_pickle(self): - global C # pickle wants to reference the class by name - T = TypeVar('T') - - class B(Generic[T]): - pass - - class C(B[int]): - pass - - c = C() - 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.__dict__, {'foo': 42, 'bar': 'abc'}) - simples = [Any, Union, Tuple, Callable, ClassVar, List, typing.Iterable] - for s in simples: - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - z = pickle.dumps(s, proto) - x = pickle.loads(z) - self.assertEqual(s, x) - - def test_copy_and_deepcopy(self): - T = TypeVar('T') - class Node(Generic[T]): ... - things = [Union[T, int], Tuple[T, int], Callable[..., T], Callable[[int], int], - Tuple[Any, Any], Node[T], Node[int], Node[Any], typing.Iterable[T], - typing.Iterable[Any], typing.Iterable[int], typing.Dict[int, str], - typing.Dict[T, Any], ClassVar[int], ClassVar[List[T]], Tuple['T', 'T'], - Union['T', int], List['T'], typing.Mapping['T', int]] - for t in things + [Any]: - self.assertEqual(t, copy(t)) - self.assertEqual(t, deepcopy(t)) - if sys.version_info >= (3, 3): - # From copy module documentation: - # It does "copy" functions and classes (shallow and deeply), by returning - # the original object unchanged; this is compatible with the way these - # are treated by the pickle module. - self.assertTrue(t is copy(t)) - self.assertTrue(t is deepcopy(t)) - - def test_copy_generic_instances(self): - T = TypeVar('T') - class C(Generic[T]): - def __init__(self, attr: T) -> None: - self.attr = attr - - c = C(42) - self.assertEqual(copy(c).attr, 42) - self.assertEqual(deepcopy(c).attr, 42) - self.assertIsNot(copy(c), c) - self.assertIsNot(deepcopy(c), c) - c.attr = 1 - self.assertEqual(copy(c).attr, 1) - self.assertEqual(deepcopy(c).attr, 1) - ci = C[int](42) - self.assertEqual(copy(ci).attr, 42) - self.assertEqual(deepcopy(ci).attr, 42) - self.assertIsNot(copy(ci), ci) - self.assertIsNot(deepcopy(ci), ci) - ci.attr = 1 - self.assertEqual(copy(ci).attr, 1) - self.assertEqual(deepcopy(ci).attr, 1) - self.assertEqual(ci.__orig_class__, C[int]) - - def test_weakref_all(self): - T = TypeVar('T') - things = [Any, Union[T, int], Callable[..., T], Tuple[Any, Any], - Optional[List[int]], typing.Mapping[int, str], - typing.re.Match[bytes], typing.Iterable['whatever']] - for t in things: - self.assertEqual(weakref.ref(t)(), t) - - def test_parameterized_slots(self): - T = TypeVar('T') - class C(Generic[T]): - __slots__ = ('potato',) - - c = C() - c_int = C[int]() - self.assertEqual(C.__slots__, C[str].__slots__) - - c.potato = 0 - c_int.potato = 0 - with self.assertRaises(AttributeError): - c.tomato = 0 - with self.assertRaises(AttributeError): - c_int.tomato = 0 - - def foo(x: C['C']): ... - self.assertEqual(get_type_hints(foo, globals(), locals())['x'], C[C]) - self.assertEqual(get_type_hints(foo, globals(), locals())['x'].__slots__, - C.__slots__) - self.assertEqual(copy(C[int]), deepcopy(C[int])) - - def test_parameterized_slots_dict(self): - T = TypeVar('T') - class D(Generic[T]): - __slots__ = {'banana': 42} - - d = D() - d_int = D[int]() - self.assertEqual(D.__slots__, D[str].__slots__) - - d.banana = 'yes' - d_int.banana = 'yes' - with self.assertRaises(AttributeError): - d.foobar = 'no' - with self.assertRaises(AttributeError): - d_int.foobar = 'no' - - def test_errors(self): - with self.assertRaises(TypeError): - B = SimpleMapping[XK, Any] - - class C(Generic[B]): - pass - - def test_repr_2(self): - PY32 = sys.version_info[:2] < (3, 3) - - class C(Generic[T]): - pass - - self.assertEqual(C.__module__, __name__) - if not PY32: - self.assertEqual(C.__qualname__, - 'GenericTests.test_repr_2..C') - self.assertEqual(repr(C).split('.')[-1], 'C') - X = C[int] - self.assertEqual(X.__module__, __name__) - if not PY32: - self.assertTrue(X.__qualname__.endswith('..C')) - self.assertEqual(repr(X).split('.')[-1], 'C[int]') - - class Y(C[int]): - pass - - self.assertEqual(Y.__module__, __name__) - if not PY32: - self.assertEqual(Y.__qualname__, - 'GenericTests.test_repr_2..Y') - self.assertEqual(repr(Y).split('.')[-1], 'Y') - - def test_eq_1(self): - self.assertEqual(Generic, Generic) - self.assertEqual(Generic[T], Generic[T]) - self.assertNotEqual(Generic[KT], Generic[VT]) - - def test_eq_2(self): - - class A(Generic[T]): - pass - - class B(Generic[T]): - pass - - self.assertEqual(A, A) - self.assertNotEqual(A, B) - self.assertEqual(A[T], A[T]) - self.assertNotEqual(A[T], B[T]) - - def test_multiple_inheritance(self): - - class A(Generic[T, VT]): - pass - - class B(Generic[KT, T]): - pass - - class C(A[T, VT], Generic[VT, T, KT], B[KT, T]): - pass - - self.assertEqual(C.__parameters__, (VT, T, KT)) - - def test_nested(self): - - G = Generic - - class Visitor(G[T]): - - a = None - - def set(self, a: T): - self.a = a - - def get(self): - return self.a - - def visit(self) -> T: - return self.a - - V = Visitor[typing.List[int]] - - class IntListVisitor(V): - - def append(self, x: int): - self.a.append(x) - - a = IntListVisitor() - a.set([]) - a.append(1) - a.append(42) - self.assertEqual(a.get(), [1, 42]) - - def test_type_erasure(self): - T = TypeVar('T') - - class Node(Generic[T]): - def __init__(self, label: T, - left: 'Node[T]' = None, - right: 'Node[T]' = None): - self.label = label # type: T - self.left = left # type: Optional[Node[T]] - self.right = right # type: Optional[Node[T]] - - def foo(x: T): - a = Node(x) - b = Node[T](x) - c = Node[Any](x) - self.assertIs(type(a), Node) - self.assertIs(type(b), Node) - self.assertIs(type(c), Node) - self.assertEqual(a.label, x) - self.assertEqual(b.label, x) - self.assertEqual(c.label, x) - - foo(42) - - def test_implicit_any(self): - T = TypeVar('T') - - class C(Generic[T]): - pass - - class D(C): - pass - - self.assertEqual(D.__parameters__, ()) - - with self.assertRaises(Exception): - D[int] - with self.assertRaises(Exception): - D[Any] - with self.assertRaises(Exception): - D[T] - - def test_new_with_args(self): - - class A(Generic[T]): - pass - - class B: - def __new__(cls, arg): - # call object - obj = super().__new__(cls) - obj.arg = arg - return obj - - # mro: C, A, Generic, B, object - class C(A, B): - pass - - c = C('foo') - self.assertEqual(c.arg, 'foo') - - def test_new_with_args2(self): - - class A: - def __init__(self, arg): - self.from_a = arg - # call object - super().__init__() - - # mro: C, Generic, A, object - class C(Generic[T], A): - def __init__(self, arg): - self.from_c = arg - # call Generic - super().__init__(arg) - - c = C('foo') - self.assertEqual(c.from_a, 'foo') - self.assertEqual(c.from_c, 'foo') - - def test_new_no_args(self): - - class A(Generic[T]): - pass - - with self.assertRaises(TypeError): - A('foo') - - class B: - def __new__(cls): - # call object - obj = super().__new__(cls) - obj.from_b = 'b' - return obj - - # mro: C, A, Generic, B, object - class C(A, B): - def __init__(self, arg): - self.arg = arg - - def __new__(cls, arg): - # call A - obj = super().__new__(cls) - obj.from_c = 'c' - return obj - - c = C('foo') - self.assertEqual(c.arg, 'foo') - self.assertEqual(c.from_b, 'b') - self.assertEqual(c.from_c, 'c') - - -class ClassVarTests(BaseTestCase): - - def test_basics(self): - with self.assertRaises(TypeError): - ClassVar[1] - with self.assertRaises(TypeError): - ClassVar[int, str] - with self.assertRaises(TypeError): - ClassVar[int][str] - - def test_repr(self): - self.assertEqual(repr(ClassVar), 'typing.ClassVar') - cv = ClassVar[int] - self.assertEqual(repr(cv), 'typing.ClassVar[int]') - cv = ClassVar[Employee] - self.assertEqual(repr(cv), 'typing.ClassVar[%s.Employee]' % __name__) - - 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 CastTests(BaseTestCase): - - def test_basics(self): - self.assertEqual(cast(int, 42), 42) - self.assertEqual(cast(float, 42), 42) - self.assertIs(type(cast(float, 42)), int) - self.assertEqual(cast(Any, 42), 42) - self.assertEqual(cast(list, 42), 42) - self.assertEqual(cast(Union[str, float], 42), 42) - self.assertEqual(cast(AnyStr, 42), 42) - self.assertEqual(cast(None, 42), 42) - - def test_errors(self): - # Bogus calls are not expected to fail. - cast(42, 42) - cast('hello', 42) - - -class ForwardRefTests(BaseTestCase): - - def test_basics(self): - - class Node(Generic[T]): - - def __init__(self, label: T): - self.label = label - self.left = self.right = None - - def add_both(self, - left: 'Optional[Node[T]]', - right: 'Node[T]' = None, - stuff: int = None, - blah=None): - self.left = left - self.right = right - - def add_left(self, node: Optional['Node[T]']): - self.add_both(node, None) - - def add_right(self, node: 'Node[T]' = None): - self.add_both(None, node) - - t = Node[int] - both_hints = get_type_hints(t.add_both, globals(), locals()) - self.assertEqual(both_hints['left'], Optional[Node[T]]) - self.assertEqual(both_hints['right'], Optional[Node[T]]) - self.assertEqual(both_hints['left'], both_hints['right']) - self.assertEqual(both_hints['stuff'], Optional[int]) - self.assertNotIn('blah', both_hints) - - left_hints = get_type_hints(t.add_left, globals(), locals()) - self.assertEqual(left_hints['node'], Optional[Node[T]]) - - right_hints = get_type_hints(t.add_right, globals(), locals()) - self.assertEqual(right_hints['node'], Optional[Node[T]]) - - def test_forwardref_instance_type_error(self): - fr = typing._ForwardRef('int') - with self.assertRaises(TypeError): - isinstance(42, fr) - - def test_forwardref_subclass_type_error(self): - fr = typing._ForwardRef('int') - with self.assertRaises(TypeError): - issubclass(int, fr) - - def test_forward_equality(self): - fr = typing._ForwardRef('int') - self.assertEqual(fr, typing._ForwardRef('int')) - self.assertNotEqual(List['int'], List[int]) - - def test_forward_equality_gth(self): - c1 = typing._ForwardRef('C') - c1_gth = typing._ForwardRef('C') - c2 = typing._ForwardRef('C') - c2_gth = typing._ForwardRef('C') - - class C: - pass - def foo(a: c1_gth, b: c2_gth): - pass - - self.assertEqual(get_type_hints(foo, globals(), locals()), {'a': C, 'b': C}) - self.assertEqual(c1, c2) - self.assertEqual(c1, c1_gth) - self.assertEqual(c1_gth, c2_gth) - self.assertEqual(List[c1], List[c1_gth]) - self.assertNotEqual(List[c1], List[C]) - self.assertNotEqual(List[c1_gth], List[C]) - self.assertEqual(Union[c1, c1_gth], Union[c1]) - self.assertEqual(Union[c1, c1_gth, int], Union[c1, int]) - - def test_forward_equality_hash(self): - c1 = typing._ForwardRef('int') - c1_gth = typing._ForwardRef('int') - c2 = typing._ForwardRef('int') - c2_gth = typing._ForwardRef('int') - - def foo(a: c1_gth, b: c2_gth): - pass - get_type_hints(foo, globals(), locals()) - - self.assertEqual(hash(c1), hash(c2)) - self.assertEqual(hash(c1_gth), hash(c2_gth)) - self.assertEqual(hash(c1), hash(c1_gth)) - - def test_forward_equality_namespace(self): - class A: - pass - def namespace1(): - a = typing._ForwardRef('A') - def fun(x: a): - pass - get_type_hints(fun, globals(), locals()) - return a - - def namespace2(): - a = typing._ForwardRef('A') - - class A: - pass - def fun(x: a): - pass - - get_type_hints(fun, globals(), locals()) - return a - - self.assertEqual(namespace1(), namespace1()) - self.assertNotEqual(namespace1(), namespace2()) - - def test_forward_repr(self): - self.assertEqual(repr(List['int']), "typing.List[_ForwardRef('int')]") - - def test_union_forward(self): - - def foo(a: Union['T']): - pass - - self.assertEqual(get_type_hints(foo, globals(), locals()), - {'a': Union[T]}) - - def test_tuple_forward(self): - - def foo(a: Tuple['T']): - pass - - self.assertEqual(get_type_hints(foo, globals(), locals()), - {'a': Tuple[T]}) - - def test_forward_recursion_actually(self): - def namespace1(): - a = typing._ForwardRef('A') - A = a - def fun(x: a): pass - - ret = get_type_hints(fun, globals(), locals()) - return a - - def namespace2(): - a = typing._ForwardRef('A') - A = a - def fun(x: a): pass - - ret = get_type_hints(fun, globals(), locals()) - return a - - def cmp(o1, o2): - return o1 == o2 - - r1 = namespace1() - r2 = namespace2() - self.assertIsNot(r1, r2) - - try: - exc = RecursionError - except NameError: - exc = RuntimeError - self.assertRaises(exc, cmp, r1, r2) - - def test_union_forward_recursion(self): - ValueList = List['Value'] - Value = Union[str, ValueList] - - def c(foo: List[Value]): - pass - def d(foo: Union[Value, ValueList]): - pass - def e(foo: Union[List[Value], ValueList]): - pass - def f(foo: Union[Value, List[Value], ValueList]): - pass - - self.assertEqual(get_type_hints(c, globals(), locals()), - get_type_hints(c, globals(), locals())) - self.assertEqual(get_type_hints(c, globals(), locals()), - {'foo': List[Union[str, List[Union[str, List['Value']]]]]}) - self.assertEqual(get_type_hints(d, globals(), locals()), - {'foo': Union[str, List[Union[str, List['Value']]]]}) - self.assertEqual(get_type_hints(e, globals(), locals()), - {'foo': Union[ - List[Union[str, List[Union[str, List['Value']]]]], - List[Union[str, List['Value']]] - ]}) - self.assertEqual(get_type_hints(f, globals(), locals()), - {'foo': Union[ - str, - List[Union[str, List['Value']]], - List[Union[str, List[Union[str, List['Value']]]]] - ]}) - - def test_callable_forward(self): - - def foo(a: Callable[['T'], 'T']): - pass - - self.assertEqual(get_type_hints(foo, globals(), locals()), - {'a': Callable[[T], T]}) - - def test_callable_with_ellipsis_forward(self): - - def foo(a: 'Callable[..., T]'): - pass - - self.assertEqual(get_type_hints(foo, globals(), locals()), - {'a': Callable[..., T]}) - - def test_syntax_error(self): - - with self.assertRaises(SyntaxError): - Generic['/T'] - - def test_delayed_syntax_error(self): - - def foo(a: 'Node[T'): # noqa - pass - - with self.assertRaises(SyntaxError): - get_type_hints(foo) - - def test_type_error(self): - - def foo(a: Tuple['42']): - pass - - with self.assertRaises(TypeError): - get_type_hints(foo) - - def test_name_error(self): - - def foo(a: 'Noode[T]'): # noqa - pass - - with self.assertRaises(NameError): - get_type_hints(foo, locals()) - - def test_no_type_check(self): - - @no_type_check - def foo(a: 'whatevers') -> {}: # noqa - pass - - th = get_type_hints(foo) - self.assertEqual(th, {}) - - def test_no_type_check_class(self): - - @no_type_check - class C: - def foo(a: 'whatevers') -> {}: # noqa - pass - - cth = get_type_hints(C.foo) - self.assertEqual(cth, {}) - ith = get_type_hints(C().foo) - self.assertEqual(ith, {}) - - def test_no_type_check_no_bases(self): - class C: - def meth(self, x: int): ... - @no_type_check - class D(C): - c = C - # verify that @no_type_check never affects bases - self.assertEqual(get_type_hints(C.meth), {'x': int}) - - def test_meta_no_type_check(self): - - @no_type_check_decorator - def magic_decorator(deco): - return deco - - self.assertEqual(magic_decorator.__name__, 'magic_decorator') - - @magic_decorator - def foo(a: 'whatevers') -> {}: # noqa - pass - - @magic_decorator - class C: - def foo(a: 'whatevers') -> {}: # noqa - pass - - self.assertEqual(foo.__name__, 'foo') - th = get_type_hints(foo) - self.assertEqual(th, {}) - cth = get_type_hints(C.foo) - self.assertEqual(cth, {}) - ith = get_type_hints(C().foo) - self.assertEqual(ith, {}) - - def test_default_globals(self): - code = ("class C:\n" - " def foo(self, a: 'C') -> 'D': pass\n" - "class D:\n" - " def bar(self, b: 'D') -> C: pass\n" - ) - ns = {} - exec(code, ns) - hints = get_type_hints(ns['C'].foo) - self.assertEqual(hints, {'a': ns['C'], 'return': ns['D']}) - - -class OverloadTests(BaseTestCase): - - def test_overload_fails(self): - from typing import overload - - with self.assertRaises(RuntimeError): - - @overload - def blah(): - pass - - blah() - - def test_overload_succeeds(self): - from typing import overload - - @overload - def blah(): - pass - - def blah(): - pass - - blah() - - -ASYNCIO = sys.version_info[:2] >= (3, 5) - -ASYNCIO_TESTS = """ -import asyncio - -T_a = TypeVar('T_a') - -class AwaitableWrapper(typing.Awaitable[T_a]): - - def __init__(self, value): - self.value = value - - def __await__(self) -> typing.Iterator[T_a]: - yield - return self.value - -class AsyncIteratorWrapper(typing.AsyncIterator[T_a]): - - def __init__(self, value: typing.Iterable[T_a]): - self.value = value - - def __aiter__(self) -> typing.AsyncIterator[T_a]: - return self - - @asyncio.coroutine - def __anext__(self) -> T_a: - data = yield from 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 -""" - -if ASYNCIO: - try: - exec(ASYNCIO_TESTS) - except ImportError: - ASYNCIO = False -else: - # fake names for the sake of static analysis - asyncio = None - AwaitableWrapper = AsyncIteratorWrapper = ACM = object - -PY36_TESTS = """ -from test import ann_module, ann_module2, ann_module3 -from typing import AsyncContextManager - -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 NoneAndForward: - parent: 'NoneAndForward' - meaning: None - -class CoolEmployee(NamedTuple): - name: str - cool: int - -class CoolEmployeeWithDefault(NamedTuple): - name: str - cool: int = 0 - -class XMeth(NamedTuple): - x: int - def double(self): - return 2 * self.x - -class XRepr(NamedTuple): - x: int - y: int = 1 - def __str__(self): - return f'{self.x} -> {self.y}' - def __add__(self, other): - return 0 - -class HasForeignBaseClass(mod_generics_cache.A): - some_xrepr: 'XRepr' - other_a: 'mod_generics_cache.A' - -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 -""" - -if PY36: - exec(PY36_TESTS) -else: - # fake names for the sake of static analysis - ann_module = ann_module2 = ann_module3 = None - A = B = CSub = G = CoolEmployee = CoolEmployeeWithDefault = object - XMeth = XRepr = NoneAndForward = HasForeignBaseClass = object - -gth = get_type_hints - - -class GetTypeHintTests(BaseTestCase): - def test_get_type_hints_from_various_objects(self): - # For invalid objects should fail with TypeError (not AttributeError etc). - with self.assertRaises(TypeError): - gth(123) - with self.assertRaises(TypeError): - gth('abc') - with self.assertRaises(TypeError): - gth(None) - - @skipUnless(PY36, 'Python 3.6 required') - def test_get_type_hints_modules(self): - ann_module_type_hints = {1: 2, 'f': Tuple[int, int], 'x': int, 'y': str} - self.assertEqual(gth(ann_module), ann_module_type_hints) - self.assertEqual(gth(ann_module2), {}) - self.assertEqual(gth(ann_module3), {}) - - @skipUnless(PY36, 'Python 3.6 required') - @expectedFailure - def test_get_type_hints_modules_forwardref(self): - # FIXME: This currently exposes a bug in typing. Cached forward references - # don't account for the case where there are multiple types of the same - # name coming from different modules in the same program. - mgc_hints = {'default_a': Optional[mod_generics_cache.A], - 'default_b': Optional[mod_generics_cache.B]} - self.assertEqual(gth(mod_generics_cache), mgc_hints) - - @skipUnless(PY36, 'Python 3.6 required') - def test_get_type_hints_classes(self): - self.assertEqual(gth(ann_module.C), # gth will find the right globalns - {'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), - {'parent': NoneAndForward, 'meaning': type(None)}) - self.assertEqual(gth(HasForeignBaseClass), - {'some_xrepr': XRepr, 'other_a': mod_generics_cache.A, - 'some_b': mod_generics_cache.B}) - self.assertEqual(gth(XRepr.__new__), - {'x': int, 'y': int}) - self.assertEqual(gth(mod_generics_cache.B), - {'my_inner_a1': mod_generics_cache.B.A, - 'my_inner_a2': mod_generics_cache.B.A, - 'my_outer_a': mod_generics_cache.A}) - - @skipUnless(PY36, 'Python 3.6 required') - 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_for_builtins(self): - # Should not fail for built-in classes and functions. - self.assertEqual(gth(int), {}) - self.assertEqual(gth(type), {}) - self.assertEqual(gth(dir), {}) - self.assertEqual(gth(len), {}) - self.assertEqual(gth(object.__str__), {}) - self.assertEqual(gth(object().__str__), {}) - self.assertEqual(gth(str.join), {}) - - def test_previous_behavior(self): - def testf(x, y): ... - testf.__annotations__['x'] = 'int' - self.assertEqual(gth(testf), {'x': int}) - def testg(x: None): ... - self.assertEqual(gth(testg), {'x': type(None)}) - - def test_get_type_hints_for_object_with_annotations(self): - class A: ... - class B: ... - b = B() - b.__annotations__ = {'x': 'A'} - self.assertEqual(gth(b, locals()), {'x': A}) - - @skipUnless(PY36, 'Python 3.6 required') - def test_get_type_hints_ClassVar(self): - self.assertEqual(gth(ann_module2.CV, ann_module2.__dict__), - {'var': typing.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]]}) - - -class CollectionsAbcTests(BaseTestCase): - - def test_hashable(self): - self.assertIsInstance(42, typing.Hashable) - self.assertNotIsInstance([], typing.Hashable) - - def test_iterable(self): - self.assertIsInstance([], typing.Iterable) - # Due to ABC caching, the second time takes a separate code - # path and could fail. So call this a few times. - self.assertIsInstance([], typing.Iterable) - self.assertIsInstance([], typing.Iterable) - self.assertNotIsInstance(42, typing.Iterable) - # Just in case, also test issubclass() a few times. - self.assertIsSubclass(list, typing.Iterable) - self.assertIsSubclass(list, typing.Iterable) - - def test_iterator(self): - it = iter([]) - self.assertIsInstance(it, typing.Iterator) - self.assertNotIsInstance(42, typing.Iterator) - - @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') - def test_awaitable(self): - ns = {} - exec( - "async def foo() -> typing.Awaitable[int]:\n" - " return await AwaitableWrapper(42)\n", - globals(), ns) - foo = ns['foo'] - g = foo() - self.assertIsInstance(g, typing.Awaitable) - self.assertNotIsInstance(foo, typing.Awaitable) - g.send(None) # Run foo() till completion, to avoid warning. - - @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') - def test_coroutine(self): - ns = {} - exec( - "async def foo():\n" - " return\n", - globals(), ns) - foo = ns['foo'] - g = foo() - self.assertIsInstance(g, typing.Coroutine) - with self.assertRaises(TypeError): - isinstance(g, typing.Coroutine[int]) - self.assertNotIsInstance(foo, typing.Coroutine) - try: - g.send(None) - except StopIteration: - pass - - @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') - def test_async_iterable(self): - base_it = range(10) # type: Iterator[int] - it = AsyncIteratorWrapper(base_it) - self.assertIsInstance(it, typing.AsyncIterable) - self.assertIsInstance(it, typing.AsyncIterable) - self.assertNotIsInstance(42, typing.AsyncIterable) - - @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') - def test_async_iterator(self): - base_it = range(10) # type: Iterator[int] - it = AsyncIteratorWrapper(base_it) - self.assertIsInstance(it, typing.AsyncIterator) - self.assertNotIsInstance(42, typing.AsyncIterator) - - def test_sized(self): - self.assertIsInstance([], typing.Sized) - self.assertNotIsInstance(42, typing.Sized) - - def test_container(self): - self.assertIsInstance([], typing.Container) - self.assertNotIsInstance(42, typing.Container) - - def test_collection(self): - if hasattr(typing, 'Collection'): - self.assertIsInstance(tuple(), typing.Collection) - self.assertIsInstance(frozenset(), typing.Collection) - self.assertIsSubclass(dict, typing.Collection) - self.assertNotIsInstance(42, typing.Collection) - - def test_abstractset(self): - self.assertIsInstance(set(), typing.AbstractSet) - self.assertNotIsInstance(42, typing.AbstractSet) - - def test_mutableset(self): - self.assertIsInstance(set(), typing.MutableSet) - self.assertNotIsInstance(frozenset(), typing.MutableSet) - - def test_mapping(self): - self.assertIsInstance({}, typing.Mapping) - self.assertNotIsInstance(42, typing.Mapping) - - def test_mutablemapping(self): - self.assertIsInstance({}, typing.MutableMapping) - self.assertNotIsInstance(42, typing.MutableMapping) - - def test_sequence(self): - self.assertIsInstance([], typing.Sequence) - self.assertNotIsInstance(42, typing.Sequence) - - def test_mutablesequence(self): - self.assertIsInstance([], typing.MutableSequence) - self.assertNotIsInstance((), typing.MutableSequence) - - def test_bytestring(self): - self.assertIsInstance(b'', typing.ByteString) - self.assertIsInstance(bytearray(b''), typing.ByteString) - - def test_list(self): - self.assertIsSubclass(list, typing.List) - - def test_deque(self): - self.assertIsSubclass(collections.deque, typing.Deque) - class MyDeque(typing.Deque[int]): ... - self.assertIsInstance(MyDeque(), collections.deque) - - def test_counter(self): - self.assertIsSubclass(collections.Counter, typing.Counter) - - def test_set(self): - self.assertIsSubclass(set, typing.Set) - self.assertNotIsSubclass(frozenset, typing.Set) - - def test_frozenset(self): - self.assertIsSubclass(frozenset, typing.FrozenSet) - self.assertNotIsSubclass(set, typing.FrozenSet) - - def test_dict(self): - self.assertIsSubclass(dict, typing.Dict) - - def test_no_list_instantiation(self): - with self.assertRaises(TypeError): - typing.List() - with self.assertRaises(TypeError): - typing.List[T]() - with self.assertRaises(TypeError): - typing.List[int]() - - def test_list_subclass(self): - - class MyList(typing.List[int]): - pass - - a = MyList() - self.assertIsInstance(a, MyList) - self.assertIsInstance(a, typing.Sequence) - - self.assertIsSubclass(MyList, list) - self.assertNotIsSubclass(list, MyList) - - def test_no_dict_instantiation(self): - with self.assertRaises(TypeError): - typing.Dict() - with self.assertRaises(TypeError): - typing.Dict[KT, VT]() - with self.assertRaises(TypeError): - typing.Dict[str, int]() - - def test_dict_subclass(self): - - class MyDict(typing.Dict[str, int]): - pass - - d = MyDict() - self.assertIsInstance(d, MyDict) - self.assertIsInstance(d, typing.MutableMapping) - - self.assertIsSubclass(MyDict, dict) - self.assertNotIsSubclass(dict, MyDict) - - def test_defaultdict_instantiation(self): - self.assertIs(type(typing.DefaultDict()), collections.defaultdict) - self.assertIs(type(typing.DefaultDict[KT, VT]()), collections.defaultdict) - self.assertIs(type(typing.DefaultDict[str, int]()), collections.defaultdict) - - def test_defaultdict_subclass(self): - - class MyDefDict(typing.DefaultDict[str, int]): - pass - - dd = MyDefDict() - self.assertIsInstance(dd, MyDefDict) - - self.assertIsSubclass(MyDefDict, collections.defaultdict) - self.assertNotIsSubclass(collections.defaultdict, MyDefDict) - - @skipUnless(sys.version_info >= (3, 3), 'ChainMap was added in 3.3') - def test_chainmap_instantiation(self): - self.assertIs(type(typing.ChainMap()), collections.ChainMap) - self.assertIs(type(typing.ChainMap[KT, VT]()), collections.ChainMap) - self.assertIs(type(typing.ChainMap[str, int]()), collections.ChainMap) - class CM(typing.ChainMap[KT, VT]): ... - self.assertIs(type(CM[int, str]()), CM) - - @skipUnless(sys.version_info >= (3, 3), 'ChainMap was added in 3.3') - def test_chainmap_subclass(self): - - class MyChainMap(typing.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.Deque()), collections.deque) - self.assertIs(type(typing.Deque[T]()), collections.deque) - self.assertIs(type(typing.Deque[int]()), collections.deque) - class D(typing.Deque[T]): ... - self.assertIs(type(D[int]()), D) - - def test_counter_instantiation(self): - self.assertIs(type(typing.Counter()), collections.Counter) - self.assertIs(type(typing.Counter[T]()), collections.Counter) - self.assertIs(type(typing.Counter[int]()), collections.Counter) - class C(typing.Counter[T]): ... - self.assertIs(type(C[int]()), C) - - def test_counter_subclass_instantiation(self): - - class MyCounter(typing.Counter[int]): - pass - - d = MyCounter() - self.assertIsInstance(d, MyCounter) - self.assertIsInstance(d, typing.Counter) - self.assertIsInstance(d, collections.Counter) - - def test_no_set_instantiation(self): - with self.assertRaises(TypeError): - typing.Set() - with self.assertRaises(TypeError): - typing.Set[T]() - with self.assertRaises(TypeError): - typing.Set[int]() - - def test_set_subclass_instantiation(self): - - class MySet(typing.Set[int]): - pass - - d = MySet() - self.assertIsInstance(d, MySet) - - def test_no_frozenset_instantiation(self): - with self.assertRaises(TypeError): - typing.FrozenSet() - with self.assertRaises(TypeError): - typing.FrozenSet[T]() - with self.assertRaises(TypeError): - typing.FrozenSet[int]() - - def test_frozenset_subclass_instantiation(self): - - class MyFrozenSet(typing.FrozenSet[int]): - pass - - d = MyFrozenSet() - self.assertIsInstance(d, MyFrozenSet) - - def test_no_tuple_instantiation(self): - with self.assertRaises(TypeError): - Tuple() - with self.assertRaises(TypeError): - Tuple[T]() - with self.assertRaises(TypeError): - Tuple[int]() - - def test_generator(self): - def foo(): - yield 42 - g = foo() - self.assertIsSubclass(type(g), typing.Generator) - - def test_no_generator_instantiation(self): - with self.assertRaises(TypeError): - typing.Generator() - with self.assertRaises(TypeError): - typing.Generator[T, T, T]() - with self.assertRaises(TypeError): - typing.Generator[int, int, int]() - - @skipUnless(PY36, 'Python 3.6 required') - def test_async_generator(self): - ns = {} - exec("async def f():\n" - " yield 42\n", globals(), ns) - g = ns['f']() - self.assertIsSubclass(type(g), typing.AsyncGenerator) - - @skipUnless(PY36, 'Python 3.6 required') - def test_no_async_generator_instantiation(self): - with self.assertRaises(TypeError): - typing.AsyncGenerator() - with self.assertRaises(TypeError): - typing.AsyncGenerator[T, T]() - with self.assertRaises(TypeError): - typing.AsyncGenerator[int, int]() - - def test_subclassing(self): - - class MMA(typing.MutableMapping): - pass - - with self.assertRaises(TypeError): # It's abstract - MMA() - - class MMC(MMA): - def __getitem__(self, k): - return None - def __setitem__(self, k, v): - pass - def __delitem__(self, k): - pass - def __iter__(self): - return iter(()) - def __len__(self): - return 0 - - self.assertEqual(len(MMC()), 0) - assert callable(MMC.update) - self.assertIsInstance(MMC(), typing.Mapping) - - class MMB(typing.MutableMapping[KT, VT]): - def __getitem__(self, k): - return None - def __setitem__(self, k, v): - pass - def __delitem__(self, k): - pass - def __iter__(self): - return iter(()) - def __len__(self): - return 0 - - self.assertEqual(len(MMB()), 0) - self.assertEqual(len(MMB[str, str]()), 0) - self.assertEqual(len(MMB[KT, VT]()), 0) - - self.assertNotIsSubclass(dict, MMA) - self.assertNotIsSubclass(dict, MMB) - - self.assertIsSubclass(MMA, typing.Mapping) - self.assertIsSubclass(MMB, typing.Mapping) - self.assertIsSubclass(MMC, typing.Mapping) - - self.assertIsInstance(MMB[KT, VT](), typing.Mapping) - self.assertIsInstance(MMB[KT, VT](), collections_abc.Mapping) - - self.assertIsSubclass(MMA, collections_abc.Mapping) - self.assertIsSubclass(MMB, collections_abc.Mapping) - self.assertIsSubclass(MMC, collections_abc.Mapping) - - self.assertIsSubclass(MMB[str, str], typing.Mapping) - self.assertIsSubclass(MMC, MMA) - - class It(typing.Iterable): ... - self.assertNotIsSubclass(list, It) - - class G(typing.Generator[int, int, int]): ... - def g(): yield 0 - self.assertIsSubclass(G, typing.Generator) - self.assertIsSubclass(G, typing.Iterable) - if hasattr(collections_abc, 'Generator'): - self.assertIsSubclass(G, collections_abc.Generator) - self.assertIsSubclass(G, collections_abc.Iterable) - self.assertNotIsSubclass(type(g), G) - - @skipUnless(PY36, 'Python 3.6 required') - def test_subclassing_async_generator(self): - class G(typing.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.AsyncGenerator) - self.assertIsSubclass(G, typing.AsyncIterable) - self.assertIsSubclass(G, collections_abc.AsyncGenerator) - self.assertIsSubclass(G, collections_abc.AsyncIterable) - self.assertNotIsSubclass(type(g), G) - - instance = G() - self.assertIsInstance(instance, typing.AsyncGenerator) - self.assertIsInstance(instance, typing.AsyncIterable) - self.assertIsInstance(instance, collections_abc.AsyncGenerator) - self.assertIsInstance(instance, collections_abc.AsyncIterable) - self.assertNotIsInstance(type(g), G) - self.assertNotIsInstance(g, G) - - def test_subclassing_subclasshook(self): - - class Base(typing.Iterable): - @classmethod - def __subclasshook__(cls, other): - if other.__name__ == 'Foo': - return True - else: - return False - - class C(Base): ... - class Foo: ... - class Bar: ... - self.assertIsSubclass(Foo, Base) - self.assertIsSubclass(Foo, C) - self.assertNotIsSubclass(Bar, C) - - def test_subclassing_register(self): - - class A(typing.Container): ... - class B(A): ... - - class C: ... - A.register(C) - self.assertIsSubclass(C, A) - self.assertNotIsSubclass(C, B) - - class D: ... - B.register(D) - self.assertIsSubclass(D, A) - self.assertIsSubclass(D, B) - - class M(): ... - collections_abc.MutableMapping.register(M) - self.assertIsSubclass(M, typing.Mapping) - - def test_collections_as_base(self): - - class M(collections_abc.Mapping): ... - self.assertIsSubclass(M, typing.Mapping) - self.assertIsSubclass(M, typing.Iterable) - - class S(collections_abc.MutableSequence): ... - self.assertIsSubclass(S, typing.MutableSequence) - self.assertIsSubclass(S, typing.Iterable) - - class It(collections_abc.Iterable): ... - self.assertIsSubclass(It, typing.Iterable) - - class A(collections_abc.Mapping, metaclass=abc.ABCMeta): ... - class B: ... - A.register(B) - self.assertIsSubclass(B, typing.Mapping) - - -class OtherABCTests(BaseTestCase): - - def test_contextmanager(self): - @contextlib.contextmanager - def manager(): - yield 42 - - cm = manager() - self.assertIsInstance(cm, typing.ContextManager) - self.assertNotIsInstance(42, typing.ContextManager) - - @skipUnless(ASYNCIO, 'Python 3.5 required') - def test_async_contextmanager(self): - class NotACM: - pass - self.assertIsInstance(ACM(), typing.AsyncContextManager) - self.assertNotIsInstance(NotACM(), typing.AsyncContextManager) - @contextlib.contextmanager - def manager(): - yield 42 - - cm = manager() - self.assertNotIsInstance(cm, typing.AsyncContextManager) - self.assertEqual(typing.AsyncContextManager[int].__args__, (int,)) - with self.assertRaises(TypeError): - isinstance(42, typing.AsyncContextManager[int]) - with self.assertRaises(TypeError): - typing.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 NamedTupleTests(BaseTestCase): - - def test_basics(self): - Emp = NamedTuple('Emp', [('name', str), ('id', int)]) - self.assertIsSubclass(Emp, tuple) - joe = Emp('Joe', 42) - jim = Emp(name='Jim', id=1) - self.assertIsInstance(joe, Emp) - self.assertIsInstance(joe, tuple) - self.assertEqual(joe.name, 'Joe') - self.assertEqual(joe.id, 42) - self.assertEqual(jim.name, 'Jim') - self.assertEqual(jim.id, 1) - self.assertEqual(Emp.__name__, 'Emp') - self.assertEqual(Emp._fields, ('name', 'id')) - self.assertEqual(Emp.__annotations__, - collections.OrderedDict([('name', str), ('id', int)])) - self.assertIs(Emp._field_types, Emp.__annotations__) - - def test_namedtuple_pyversion(self): - if sys.version_info[:2] < (3, 6): - with self.assertRaises(TypeError): - NamedTuple('Name', one=int, other=str) - with self.assertRaises(TypeError): - class NotYet(NamedTuple): - whatever = 0 - - @skipUnless(PY36, 'Python 3.6 required') - def test_annotation_usage(self): - tim = CoolEmployee('Tim', 9000) - self.assertIsInstance(tim, CoolEmployee) - self.assertIsInstance(tim, tuple) - self.assertEqual(tim.name, 'Tim') - self.assertEqual(tim.cool, 9000) - self.assertEqual(CoolEmployee.__name__, 'CoolEmployee') - self.assertEqual(CoolEmployee._fields, ('name', 'cool')) - self.assertEqual(CoolEmployee.__annotations__, - collections.OrderedDict(name=str, cool=int)) - self.assertIs(CoolEmployee._field_types, CoolEmployee.__annotations__) - - @skipUnless(PY36, 'Python 3.6 required') - def test_annotation_usage_with_default(self): - jelle = CoolEmployeeWithDefault('Jelle') - self.assertIsInstance(jelle, CoolEmployeeWithDefault) - self.assertIsInstance(jelle, tuple) - self.assertEqual(jelle.name, 'Jelle') - self.assertEqual(jelle.cool, 0) - cooler_employee = CoolEmployeeWithDefault('Sjoerd', 1) - self.assertEqual(cooler_employee.cool, 1) - - self.assertEqual(CoolEmployeeWithDefault.__name__, 'CoolEmployeeWithDefault') - self.assertEqual(CoolEmployeeWithDefault._fields, ('name', 'cool')) - self.assertEqual(CoolEmployeeWithDefault._field_types, dict(name=str, cool=int)) - self.assertEqual(CoolEmployeeWithDefault._field_defaults, dict(cool=0)) - - with self.assertRaises(TypeError): - exec(""" -class NonDefaultAfterDefault(NamedTuple): - x: int = 3 - y: int -""") - - @skipUnless(PY36, 'Python 3.6 required') - def test_annotation_usage_with_methods(self): - self.assertEqual(XMeth(1).double(), 2) - self.assertEqual(XMeth(42).x, XMeth(42)[0]) - self.assertEqual(str(XRepr(42)), '42 -> 1') - self.assertEqual(XRepr(1, 2) + XRepr(3), 0) - - with self.assertRaises(AttributeError): - exec(""" -class XMethBad(NamedTuple): - x: int - def _fields(self): - return 'no chance for this' -""") - - with self.assertRaises(AttributeError): - exec(""" -class XMethBad2(NamedTuple): - x: int - def _source(self): - return 'no chance for this as well' -""") - - @skipUnless(PY36, 'Python 3.6 required') - def test_namedtuple_keyword_usage(self): - LocalEmployee = NamedTuple("LocalEmployee", name=str, age=int) - nick = LocalEmployee('Nick', 25) - self.assertIsInstance(nick, tuple) - self.assertEqual(nick.name, 'Nick') - self.assertEqual(LocalEmployee.__name__, 'LocalEmployee') - self.assertEqual(LocalEmployee._fields, ('name', 'age')) - self.assertEqual(LocalEmployee.__annotations__, dict(name=str, age=int)) - self.assertIs(LocalEmployee._field_types, LocalEmployee.__annotations__) - with self.assertRaises(TypeError): - NamedTuple('Name', [('x', int)], y=str) - with self.assertRaises(TypeError): - NamedTuple('Name', x=1, y='a') - - @skipUnless(PY36, 'Python 3.6 required') - def test_namedtuple_special_keyword_names(self): - NT = NamedTuple("NT", cls=type, self=object, typename=str, fields=list) - self.assertEqual(NT.__name__, 'NT') - self.assertEqual(NT._fields, ('cls', 'self', 'typename', 'fields')) - a = NT(cls=str, self=42, typename='foo', fields=[('bar', tuple)]) - self.assertEqual(a.cls, str) - self.assertEqual(a.self, 42) - self.assertEqual(a.typename, 'foo') - self.assertEqual(a.fields, [('bar', tuple)]) - - @skipUnless(PY36, 'Python 3.6 required') - def test_namedtuple_errors(self): - with self.assertRaises(TypeError): - NamedTuple.__new__() - with self.assertRaises(TypeError): - NamedTuple() - with self.assertRaises(TypeError): - NamedTuple('Emp', [('name', str)], None) - with self.assertRaises(ValueError): - NamedTuple('Emp', [('_name', str)]) - - with self.assertWarns(DeprecationWarning): - Emp = NamedTuple(typename='Emp', name=str, id=int) - self.assertEqual(Emp.__name__, 'Emp') - self.assertEqual(Emp._fields, ('name', 'id')) - - with self.assertWarns(DeprecationWarning): - Emp = NamedTuple('Emp', fields=[('name', str), ('id', int)]) - self.assertEqual(Emp.__name__, 'Emp') - self.assertEqual(Emp._fields, ('name', 'id')) - - def test_pickle(self): - global Emp # pickle wants to reference the class by name - Emp = NamedTuple('Emp', [('name', str), ('id', int)]) - jane = Emp('jane', 37) - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - z = pickle.dumps(jane, proto) - jane2 = pickle.loads(z) - self.assertEqual(jane2, jane) - - -class IOTests(BaseTestCase): - - def test_io(self): - - def stuff(a: IO) -> AnyStr: - return a.readline() - - a = stuff.__annotations__['a'] - self.assertEqual(a.__parameters__, (AnyStr,)) - - def test_textio(self): - - def stuff(a: TextIO) -> str: - return a.readline() - - a = stuff.__annotations__['a'] - self.assertEqual(a.__parameters__, ()) - - def test_binaryio(self): - - def stuff(a: BinaryIO) -> bytes: - return a.readline() - - a = stuff.__annotations__['a'] - self.assertEqual(a.__parameters__, ()) - - def test_io_submodule(self): - from typing.io import IO, TextIO, BinaryIO, __all__, __name__ - self.assertIs(IO, typing.IO) - self.assertIs(TextIO, typing.TextIO) - self.assertIs(BinaryIO, typing.BinaryIO) - self.assertEqual(set(__all__), set(['IO', 'TextIO', 'BinaryIO'])) - self.assertEqual(__name__, 'typing.io') - - -class RETests(BaseTestCase): - # Much of this is really testing _TypeAlias. - - def test_basics(self): - pat = re.compile('[a-z]+', re.I) - self.assertIsSubclass(pat.__class__, Pattern) - self.assertIsSubclass(type(pat), Pattern) - self.assertIsInstance(pat, Pattern) - - mat = pat.search('12345abcde.....') - self.assertIsSubclass(mat.__class__, Match) - self.assertIsSubclass(type(mat), Match) - self.assertIsInstance(mat, Match) - - # these should just work - Pattern[Union[str, bytes]] - Match[Union[bytes, str]] - - def test_alias_equality(self): - self.assertEqual(Pattern[str], Pattern[str]) - self.assertNotEqual(Pattern[str], Pattern[bytes]) - self.assertNotEqual(Pattern[str], Match[str]) - self.assertNotEqual(Pattern[str], str) - - def test_errors(self): - with self.assertRaises(TypeError): - # Doesn't fit AnyStr. - Pattern[int] - with self.assertRaises(TypeError): - # Can't change type vars? - Match[T] - m = Match[Union[str, bytes]] - with self.assertRaises(TypeError): - # Too complicated? - m[str] - with self.assertRaises(TypeError): - # We don't support isinstance(). - isinstance(42, Pattern[str]) - with self.assertRaises(TypeError): - # We don't support issubclass(). - issubclass(Pattern[bytes], Pattern[str]) - - def test_repr(self): - self.assertEqual(repr(Pattern), 'Pattern[~AnyStr]') - self.assertEqual(repr(Pattern[str]), 'Pattern[str]') - self.assertEqual(repr(Pattern[bytes]), 'Pattern[bytes]') - self.assertEqual(repr(Match), 'Match[~AnyStr]') - self.assertEqual(repr(Match[str]), 'Match[str]') - self.assertEqual(repr(Match[bytes]), 'Match[bytes]') - - def test_re_submodule(self): - from typing.re import Match, Pattern, __all__, __name__ - self.assertIs(Match, typing.Match) - self.assertIs(Pattern, typing.Pattern) - self.assertEqual(set(__all__), set(['Match', 'Pattern'])) - self.assertEqual(__name__, 'typing.re') - - def test_cannot_subclass(self): - with self.assertRaises(TypeError) as ex: - - class A(typing.Match): - pass - - self.assertEqual(str(ex.exception), - "Cannot subclass typing._TypeAlias") - - -class AllTests(BaseTestCase): - """Tests for __all__.""" - - def test_all(self): - from typing import __all__ as a - # Just spot-check the first and last of every category. - self.assertIn('AbstractSet', a) - self.assertIn('ValuesView', a) - self.assertIn('cast', a) - self.assertIn('overload', a) - if hasattr(contextlib, 'AbstractContextManager'): - self.assertIn('ContextManager', a) - # Check that io and re are not exported. - self.assertNotIn('io', a) - self.assertNotIn('re', a) - # Spot-check that stdlib modules aren't exported. - self.assertNotIn('os', a) - self.assertNotIn('sys', a) - # Check that Text is defined. - self.assertIn('Text', a) - # Check previously missing classes. - self.assertIn('SupportsBytes', a) - self.assertIn('SupportsComplex', a) - - def test_typing_compiles_with_opt(self): - file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), - 'typing.py') - try: - subprocess.check_output([sys.executable, '-OO', file_path], - stderr=subprocess.STDOUT) - except subprocess.CalledProcessError: - self.fail('Module does not compile with optimize=2 (-OO flag).') - - -if __name__ == '__main__': - main() diff --git a/src/typing.py b/src/typing.py deleted file mode 100644 index 70c59d851..000000000 --- a/src/typing.py +++ /dev/null @@ -1,2454 +0,0 @@ -import abc -from abc import abstractmethod, abstractproperty -import collections -import contextlib -import functools -import re as stdlib_re # Avoid confusion with the re we export. -import sys -import types -try: - import collections.abc as collections_abc -except ImportError: - import collections as collections_abc # Fallback for PY3.2. -if sys.version_info[:2] >= (3, 6): - import _collections_abc # Needed for private function _check_methods # noqa -try: - from types import WrapperDescriptorType, MethodWrapperType, MethodDescriptorType -except ImportError: - WrapperDescriptorType = type(object.__init__) - MethodWrapperType = type(object().__str__) - MethodDescriptorType = type(str.join) - - -# Please keep __all__ alphabetized within each category. -__all__ = [ - # Super-special typing primitives. - 'Any', - 'Callable', - 'ClassVar', - 'Generic', - 'Optional', - 'Tuple', - 'Type', - 'TypeVar', - 'Union', - - # ABCs (from collections.abc). - 'AbstractSet', # collections.abc.Set. - 'GenericMeta', # subclass of abc.ABCMeta and a metaclass - # for 'Generic' and ABCs below. - 'ByteString', - 'Container', - 'ContextManager', - 'Hashable', - 'ItemsView', - 'Iterable', - 'Iterator', - 'KeysView', - 'Mapping', - 'MappingView', - 'MutableMapping', - 'MutableSequence', - 'MutableSet', - 'Sequence', - 'Sized', - 'ValuesView', - # The following are added depending on presence - # of their non-generic counterparts in stdlib: - # Awaitable, - # AsyncIterator, - # AsyncIterable, - # Coroutine, - # Collection, - # AsyncGenerator, - # AsyncContextManager - - # Structural checks, a.k.a. protocols. - 'Reversible', - 'SupportsAbs', - 'SupportsBytes', - 'SupportsComplex', - 'SupportsFloat', - 'SupportsIndex', - 'SupportsInt', - 'SupportsRound', - - # Concrete collection types. - 'Counter', - 'Deque', - 'Dict', - 'DefaultDict', - 'List', - 'Set', - 'FrozenSet', - 'NamedTuple', # Not really a type. - 'Generator', - - # One-off things. - 'AnyStr', - 'cast', - 'get_type_hints', - 'NewType', - 'no_type_check', - 'no_type_check_decorator', - 'NoReturn', - 'overload', - 'Text', - 'TYPE_CHECKING', -] - -# The pseudo-submodules 're' and 'io' are part of the public -# namespace, but excluded from __all__ because they might stomp on -# legitimate imports of those modules. - - -def _qualname(x): - if sys.version_info[:2] >= (3, 3): - return x.__qualname__ - else: - # Fall back to just name. - return x.__name__ - - -def _trim_name(nm): - whitelist = ('_TypeAlias', '_ForwardRef', '_TypingBase', '_FinalTypingBase') - if nm.startswith('_') and nm not in whitelist: - nm = nm[1:] - return nm - - -class TypingMeta(type): - """Metaclass for most types defined in typing module - (not a part of public API). - - This overrides __new__() to require an extra keyword parameter - '_root', which serves as a guard against naive subclassing of the - typing classes. Any legitimate class defined using a metaclass - derived from TypingMeta must pass _root=True. - - This also defines a dummy constructor (all the work for most typing - constructs is done in __new__) and a nicer repr(). - """ - - _is_protocol = False - - def __new__(cls, name, bases, namespace, *, _root=False): - if not _root: - raise TypeError("Cannot subclass %s" % - (', '.join(map(_type_repr, bases)) or '()')) - return super().__new__(cls, name, bases, namespace) - - def __init__(self, *args, **kwds): - pass - - def _eval_type(self, globalns, localns): - """Override this in subclasses to interpret forward references. - - For example, List['C'] is internally stored as - List[_ForwardRef('C')], which should evaluate to List[C], - where C is an object found in globalns or localns (searching - localns first, of course). - """ - return self - - def _get_type_vars(self, tvars): - pass - - def __repr__(self): - qname = _trim_name(_qualname(self)) - return '%s.%s' % (self.__module__, qname) - - -class _TypingBase(metaclass=TypingMeta, _root=True): - """Internal indicator of special typing constructs.""" - - __slots__ = ('__weakref__',) - - def __init__(self, *args, **kwds): - pass - - def __new__(cls, *args, **kwds): - """Constructor. - - This only exists to give a better error message in case - someone tries to subclass a special typing object (not a good idea). - """ - if (len(args) == 3 and - isinstance(args[0], str) and - isinstance(args[1], tuple)): - # Close enough. - raise TypeError("Cannot subclass %r" % cls) - return super().__new__(cls) - - # Things that are not classes also need these. - def _eval_type(self, globalns, localns): - return self - - def _get_type_vars(self, tvars): - pass - - def __repr__(self): - cls = type(self) - qname = _trim_name(_qualname(cls)) - return '%s.%s' % (cls.__module__, qname) - - def __call__(self, *args, **kwds): - raise TypeError("Cannot instantiate %r" % type(self)) - - -class _FinalTypingBase(_TypingBase, _root=True): - """Internal mix-in class to prevent instantiation. - - Prevents instantiation unless _root=True is given in class call. - It is used to create pseudo-singleton instances Any, Union, Optional, etc. - """ - - __slots__ = () - - def __new__(cls, *args, _root=False, **kwds): - self = super().__new__(cls, *args, **kwds) - if _root is True: - return self - raise TypeError("Cannot instantiate %r" % cls) - - def __reduce__(self): - return _trim_name(type(self).__name__) - - -class _ForwardRef(_TypingBase, _root=True): - """Internal wrapper to hold a forward reference.""" - - __slots__ = ('__forward_arg__', '__forward_code__', - '__forward_evaluated__', '__forward_value__') - - def __init__(self, arg): - super().__init__(arg) - if not isinstance(arg, str): - raise TypeError('Forward reference must be a string -- got %r' % (arg,)) - try: - code = compile(arg, '', 'eval') - except SyntaxError: - raise SyntaxError('Forward reference must be an expression -- got %r' % - (arg,)) - self.__forward_arg__ = arg - self.__forward_code__ = code - self.__forward_evaluated__ = False - self.__forward_value__ = None - - def _eval_type(self, globalns, localns): - if not self.__forward_evaluated__ or localns is not globalns: - if globalns is None and localns is None: - globalns = localns = {} - elif globalns is None: - globalns = localns - elif localns is None: - localns = globalns - self.__forward_value__ = _type_check( - eval(self.__forward_code__, globalns, localns), - "Forward references must evaluate to types.") - self.__forward_evaluated__ = True - return self.__forward_value__ - - def __eq__(self, other): - if not isinstance(other, _ForwardRef): - return NotImplemented - if self.__forward_evaluated__ and other.__forward_evaluated__: - return (self.__forward_arg__ == other.__forward_arg__ and - self.__forward_value__ == other.__forward_value__) - return self.__forward_arg__ == other.__forward_arg__ - - def __hash__(self): - return hash(self.__forward_arg__) - - def __instancecheck__(self, obj): - raise TypeError("Forward references cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("Forward references cannot be used with issubclass().") - - def __repr__(self): - return '_ForwardRef(%r)' % (self.__forward_arg__,) - - -class _TypeAlias(_TypingBase, _root=True): - """Internal helper class for defining generic variants of concrete types. - - Note that this is not a type; let's call it a pseudo-type. It cannot - be used in instance and subclass checks in parameterized form, i.e. - ``isinstance(42, Match[str])`` raises ``TypeError`` instead of returning - ``False``. - """ - - __slots__ = ('name', 'type_var', 'impl_type', 'type_checker') - - def __init__(self, name, type_var, impl_type, type_checker): - """Initializer. - - Args: - name: The name, e.g. 'Pattern'. - type_var: The type parameter, e.g. AnyStr, or the - specific type, e.g. str. - impl_type: The implementation type. - type_checker: Function that takes an impl_type instance. - and returns a value that should be a type_var instance. - """ - assert isinstance(name, str), repr(name) - assert isinstance(impl_type, type), repr(impl_type) - assert not isinstance(impl_type, TypingMeta), repr(impl_type) - assert isinstance(type_var, (type, _TypingBase)), repr(type_var) - self.name = name - self.type_var = type_var - self.impl_type = impl_type - self.type_checker = type_checker - - def __repr__(self): - return "%s[%s]" % (self.name, _type_repr(self.type_var)) - - def __getitem__(self, parameter): - if not isinstance(self.type_var, TypeVar): - raise TypeError("%s cannot be further parameterized." % self) - if self.type_var.__constraints__ and isinstance(parameter, type): - if not issubclass(parameter, self.type_var.__constraints__): - raise TypeError("%s is not a valid substitution for %s." % - (parameter, self.type_var)) - if isinstance(parameter, TypeVar) and parameter is not self.type_var: - raise TypeError("%s cannot be re-parameterized." % self) - return self.__class__(self.name, parameter, - self.impl_type, self.type_checker) - - def __eq__(self, other): - if not isinstance(other, _TypeAlias): - return NotImplemented - return self.name == other.name and self.type_var == other.type_var - - def __hash__(self): - return hash((self.name, self.type_var)) - - def __instancecheck__(self, obj): - if not isinstance(self.type_var, TypeVar): - raise TypeError("Parameterized type aliases cannot be used " - "with isinstance().") - return isinstance(obj, self.impl_type) - - def __subclasscheck__(self, cls): - if not isinstance(self.type_var, TypeVar): - raise TypeError("Parameterized type aliases cannot be used " - "with issubclass().") - return issubclass(cls, self.impl_type) - - -def _get_type_vars(types, tvars): - for t in types: - if isinstance(t, TypingMeta) or isinstance(t, _TypingBase): - t._get_type_vars(tvars) - - -def _type_vars(types): - tvars = [] - _get_type_vars(types, tvars) - return tuple(tvars) - - -def _eval_type(t, globalns, localns): - if isinstance(t, TypingMeta) or isinstance(t, _TypingBase): - return t._eval_type(globalns, localns) - return t - - -def _type_check(arg, msg): - """Check that the argument is a type, and return it (internal helper). - - As a special case, accept None and return type(None) instead. - Also, _TypeAlias instances (e.g. Match, Pattern) are acceptable. - - The msg argument is a human-readable error message, e.g. - - "Union[arg, ...]: arg should be a type." - - We append the repr() of the actual value (truncated to 100 chars). - """ - if arg is None: - return type(None) - if isinstance(arg, str): - arg = _ForwardRef(arg) - if ( - isinstance(arg, _TypingBase) and type(arg).__name__ == '_ClassVar' or - not isinstance(arg, (type, _TypingBase)) and not callable(arg) - ): - raise TypeError(msg + " Got %.100r." % (arg,)) - # Bare Union etc. are not valid as type arguments - if ( - type(arg).__name__ in ('_Union', '_Optional') and - not getattr(arg, '__origin__', None) or - isinstance(arg, TypingMeta) and arg._gorg in (Generic, _Protocol) - ): - raise TypeError("Plain %s is not valid as type argument" % arg) - return arg - - -def _type_repr(obj): - """Return the repr() of an object, special-casing types (internal helper). - - If obj is a type, we return a shorter version than the default - type.__repr__, based on the module and qualified name, which is - typically enough to uniquely identify a type. For everything - else, we fall back on repr(obj). - """ - if isinstance(obj, type) and not isinstance(obj, TypingMeta): - if obj.__module__ == 'builtins': - return _qualname(obj) - return '%s.%s' % (obj.__module__, _qualname(obj)) - if obj is ...: - return('...') - if isinstance(obj, types.FunctionType): - return obj.__name__ - return repr(obj) - - -class _Any(_FinalTypingBase, _root=True): - """Special type indicating an unconstrained type. - - - Any is compatible with every type. - - Any assumed to have all methods. - - All values assumed to be instances of Any. - - Note that all the above statements are true from the point of view of - static type checkers. At runtime, Any should not be used with instance - or class checks. - """ - - __slots__ = () - - def __instancecheck__(self, obj): - raise TypeError("Any cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("Any cannot be used with issubclass().") - - -Any = _Any(_root=True) - - -class _NoReturn(_FinalTypingBase, _root=True): - """Special type indicating functions that never return. - Example:: - - from typing import NoReturn - - def stop() -> NoReturn: - raise Exception('no way') - - This type is invalid in other positions, e.g., ``List[NoReturn]`` - will fail in static type checkers. - """ - - __slots__ = () - - def __instancecheck__(self, obj): - raise TypeError("NoReturn cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("NoReturn cannot be used with issubclass().") - - -NoReturn = _NoReturn(_root=True) - - -class TypeVar(_TypingBase, _root=True): - """Type variable. - - Usage:: - - T = TypeVar('T') # Can be anything - A = TypeVar('A', str, bytes) # Must be str or bytes - - Type variables exist primarily for the benefit of static type - checkers. They serve as the parameters for generic types as well - as for generic function definitions. See class Generic for more - information on generic types. Generic functions work as follows: - - def repeat(x: T, n: int) -> List[T]: - '''Return a list containing n references to x.''' - return [x]*n - - def longest(x: A, y: A) -> A: - '''Return the longest of two strings.''' - return x if len(x) >= len(y) else y - - The latter example's signature is essentially the overloading - of (str, str) -> str and (bytes, bytes) -> bytes. Also note - that if the arguments are instances of some subclass of str, - the return type is still plain str. - - At runtime, isinstance(x, T) and issubclass(C, T) will raise TypeError. - - Type variables defined with covariant=True or contravariant=True - can be used do declare covariant or contravariant generic types. - See PEP 484 for more details. By default generic types are invariant - in all type variables. - - Type variables can be introspected. e.g.: - - T.__name__ == 'T' - T.__constraints__ == () - T.__covariant__ == False - T.__contravariant__ = False - A.__constraints__ == (str, bytes) - """ - - __slots__ = ('__name__', '__bound__', '__constraints__', - '__covariant__', '__contravariant__') - - def __init__(self, name, *constraints, bound=None, - covariant=False, contravariant=False): - super().__init__(name, *constraints, bound=bound, - covariant=covariant, contravariant=contravariant) - self.__name__ = name - if covariant and contravariant: - raise ValueError("Bivariant types are not supported.") - self.__covariant__ = bool(covariant) - self.__contravariant__ = bool(contravariant) - if constraints and bound is not None: - raise TypeError("Constraints cannot be combined with bound=...") - if constraints and len(constraints) == 1: - raise TypeError("A single constraint is not allowed") - msg = "TypeVar(name, constraint, ...): constraints must be types." - self.__constraints__ = tuple(_type_check(t, msg) for t in constraints) - if bound: - self.__bound__ = _type_check(bound, "Bound must be a type.") - else: - self.__bound__ = None - - def _get_type_vars(self, tvars): - if self not in tvars: - tvars.append(self) - - def __repr__(self): - if self.__covariant__: - prefix = '+' - elif self.__contravariant__: - prefix = '-' - else: - prefix = '~' - return prefix + self.__name__ - - def __instancecheck__(self, instance): - raise TypeError("Type variables cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("Type variables cannot be used with issubclass().") - - -# Some unconstrained type variables. These are used by the container types. -# (These are not for export.) -T = TypeVar('T') # Any type. -KT = TypeVar('KT') # Key type. -VT = TypeVar('VT') # Value type. -T_co = TypeVar('T_co', covariant=True) # Any type covariant containers. -V_co = TypeVar('V_co', covariant=True) # Any type covariant containers. -VT_co = TypeVar('VT_co', covariant=True) # Value type covariant containers. -T_contra = TypeVar('T_contra', contravariant=True) # Ditto contravariant. - -# A useful type variable with constraints. This represents string types. -# (This one *is* for export!) -AnyStr = TypeVar('AnyStr', bytes, str) - - -def _replace_arg(arg, tvars, args): - """An internal helper function: replace arg if it is a type variable - found in tvars with corresponding substitution from args or - with corresponding substitution sub-tree if arg is a generic type. - """ - - if tvars is None: - tvars = [] - if hasattr(arg, '_subs_tree') and isinstance(arg, (GenericMeta, _TypingBase)): - return arg._subs_tree(tvars, args) - if isinstance(arg, TypeVar): - for i, tvar in enumerate(tvars): - if arg == tvar: - return args[i] - return arg - - -# Special typing constructs Union, Optional, Generic, Callable and Tuple -# use three special attributes for internal bookkeeping of generic types: -# * __parameters__ is a tuple of unique free type parameters of a generic -# type, for example, Dict[T, T].__parameters__ == (T,); -# * __origin__ keeps a reference to a type that was subscripted, -# e.g., Union[T, int].__origin__ == Union; -# * __args__ is a tuple of all arguments used in subscripting, -# e.g., Dict[T, int].__args__ == (T, int). - - -def _subs_tree(cls, tvars=None, args=None): - """An internal helper function: calculate substitution tree - for generic cls after replacing its type parameters with - substitutions in tvars -> args (if any). - Repeat the same following __origin__'s. - - Return a list of arguments with all possible substitutions - performed. Arguments that are generic classes themselves are represented - as tuples (so that no new classes are created by this function). - For example: _subs_tree(List[Tuple[int, T]][str]) == [(Tuple, int, str)] - """ - - if cls.__origin__ is None: - return cls - # Make of chain of origins (i.e. cls -> cls.__origin__) - current = cls.__origin__ - orig_chain = [] - while current.__origin__ is not None: - orig_chain.append(current) - current = current.__origin__ - # Replace type variables in __args__ if asked ... - tree_args = [] - for arg in cls.__args__: - tree_args.append(_replace_arg(arg, tvars, args)) - # ... then continue replacing down the origin chain. - for ocls in orig_chain: - new_tree_args = [] - for arg in ocls.__args__: - new_tree_args.append(_replace_arg(arg, ocls.__parameters__, tree_args)) - tree_args = new_tree_args - return tree_args - - -def _remove_dups_flatten(parameters): - """An internal helper for Union creation and substitution: flatten Union's - among parameters, then remove duplicates and strict subclasses. - """ - - # Flatten out Union[Union[...], ...]. - params = [] - for p in parameters: - if isinstance(p, _Union) and p.__origin__ is Union: - params.extend(p.__args__) - elif isinstance(p, tuple) and len(p) > 0 and p[0] is Union: - params.extend(p[1:]) - else: - params.append(p) - # Weed out strict duplicates, preserving the first of each occurrence. - all_params = set(params) - if len(all_params) < len(params): - new_params = [] - for t in params: - if t in all_params: - new_params.append(t) - all_params.remove(t) - params = new_params - assert not all_params, all_params - # Weed out subclasses. - # E.g. Union[int, Employee, Manager] == Union[int, Employee]. - # If object is present it will be sole survivor among proper classes. - # Never discard type variables. - # (In particular, Union[str, AnyStr] != AnyStr.) - all_params = set(params) - for t1 in params: - if not isinstance(t1, type): - continue - if any(isinstance(t2, type) and issubclass(t1, t2) - for t2 in all_params - {t1} - if not (isinstance(t2, GenericMeta) and - t2.__origin__ is not None)): - all_params.remove(t1) - return tuple(t for t in params if t in all_params) - - -def _check_generic(cls, parameters): - # Check correct count for parameters of a generic cls (internal helper). - if not cls.__parameters__: - raise TypeError("%s is not a generic class" % repr(cls)) - alen = len(parameters) - elen = len(cls.__parameters__) - if alen != elen: - raise TypeError("Too %s parameters for %s; actual %s, expected %s" % - ("many" if alen > elen else "few", repr(cls), alen, elen)) - - -_cleanups = [] - - -def _tp_cache(func): - """Internal wrapper caching __getitem__ of generic types with a fallback to - original function for non-hashable arguments. - """ - - cached = functools.lru_cache()(func) - _cleanups.append(cached.cache_clear) - - @functools.wraps(func) - def inner(*args, **kwds): - try: - return cached(*args, **kwds) - except TypeError: - pass # All real errors (not unhashable args) are raised below. - return func(*args, **kwds) - return inner - - -class _Union(_FinalTypingBase, _root=True): - """Union type; Union[X, Y] means either X or Y. - - To define a union, use e.g. Union[int, str]. Details: - - - The arguments must be types and there must be at least one. - - - None as an argument is a special case and is replaced by - type(None). - - - Unions of unions are flattened, e.g.:: - - Union[Union[int, str], float] == Union[int, str, float] - - - Unions of a single argument vanish, e.g.:: - - Union[int] == int # The constructor actually returns int - - - Redundant arguments are skipped, e.g.:: - - Union[int, str, int] == Union[int, str] - - - When comparing unions, the argument order is ignored, e.g.:: - - Union[int, str] == Union[str, int] - - - When two arguments have a subclass relationship, the least - derived argument is kept, e.g.:: - - class Employee: pass - class Manager(Employee): pass - Union[int, Employee, Manager] == Union[int, Employee] - Union[Manager, int, Employee] == Union[int, Employee] - Union[Employee, Manager] == Employee - - - Similar for object:: - - Union[int, object] == object - - - You cannot subclass or instantiate a union. - - - You can use Optional[X] as a shorthand for Union[X, None]. - """ - - __slots__ = ('__parameters__', '__args__', '__origin__', '__tree_hash__') - - def __new__(cls, parameters=None, origin=None, *args, _root=False): - self = super().__new__(cls, parameters, origin, *args, _root=_root) - if origin is None: - self.__parameters__ = None - self.__args__ = None - self.__origin__ = None - self.__tree_hash__ = hash(frozenset(('Union',))) - return self - if not isinstance(parameters, tuple): - raise TypeError("Expected parameters=") - if origin is Union: - parameters = _remove_dups_flatten(parameters) - # It's not a union if there's only one type left. - if len(parameters) == 1: - return parameters[0] - self.__parameters__ = _type_vars(parameters) - self.__args__ = parameters - self.__origin__ = origin - # Pre-calculate the __hash__ on instantiation. - # This improves speed for complex substitutions. - subs_tree = self._subs_tree() - if isinstance(subs_tree, tuple): - self.__tree_hash__ = hash(frozenset(subs_tree)) - else: - self.__tree_hash__ = hash(subs_tree) - return self - - def _eval_type(self, globalns, localns): - if self.__args__ is None: - return self - ev_args = tuple(_eval_type(t, globalns, localns) for t in self.__args__) - ev_origin = _eval_type(self.__origin__, globalns, localns) - if ev_args == self.__args__ and ev_origin == self.__origin__: - # Everything is already evaluated. - return self - return self.__class__(ev_args, ev_origin, _root=True) - - def _get_type_vars(self, tvars): - if self.__origin__ and self.__parameters__: - _get_type_vars(self.__parameters__, tvars) - - def __repr__(self): - if self.__origin__ is None: - return super().__repr__() - tree = self._subs_tree() - if not isinstance(tree, tuple): - return repr(tree) - return tree[0]._tree_repr(tree) - - def _tree_repr(self, tree): - arg_list = [] - for arg in tree[1:]: - if not isinstance(arg, tuple): - arg_list.append(_type_repr(arg)) - else: - arg_list.append(arg[0]._tree_repr(arg)) - return super().__repr__() + '[%s]' % ', '.join(arg_list) - - @_tp_cache - def __getitem__(self, parameters): - if parameters == (): - raise TypeError("Cannot take a Union of no types.") - if not isinstance(parameters, tuple): - parameters = (parameters,) - if self.__origin__ is None: - msg = "Union[arg, ...]: each arg must be a type." - else: - msg = "Parameters to generic types must be types." - parameters = tuple(_type_check(p, msg) for p in parameters) - if self is not Union: - _check_generic(self, parameters) - return self.__class__(parameters, origin=self, _root=True) - - def _subs_tree(self, tvars=None, args=None): - if self is Union: - return Union # Nothing to substitute - tree_args = _subs_tree(self, tvars, args) - tree_args = _remove_dups_flatten(tree_args) - if len(tree_args) == 1: - return tree_args[0] # Union of a single type is that type - return (Union,) + tree_args - - def __eq__(self, other): - if isinstance(other, _Union): - return self.__tree_hash__ == other.__tree_hash__ - elif self is not Union: - return self._subs_tree() == other - else: - return self is other - - def __hash__(self): - return self.__tree_hash__ - - def __instancecheck__(self, obj): - raise TypeError("Unions cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("Unions cannot be used with issubclass().") - - -Union = _Union(_root=True) - - -class _Optional(_FinalTypingBase, _root=True): - """Optional type. - - Optional[X] is equivalent to Union[X, None]. - """ - - __slots__ = () - - @_tp_cache - def __getitem__(self, arg): - arg = _type_check(arg, "Optional[t] requires a single type.") - return Union[arg, type(None)] - - -Optional = _Optional(_root=True) - - -def _next_in_mro(cls): - """Helper for Generic.__new__. - - Returns the class after the last occurrence of Generic or - Generic[...] in cls.__mro__. - """ - next_in_mro = object - # Look for the last occurrence of Generic or Generic[...]. - for i, c in enumerate(cls.__mro__[:-1]): - if isinstance(c, GenericMeta) and c._gorg is Generic: - next_in_mro = cls.__mro__[i + 1] - return next_in_mro - - -def _make_subclasshook(cls): - """Construct a __subclasshook__ callable that incorporates - the associated __extra__ class in subclass checks performed - against cls. - """ - if isinstance(cls.__extra__, abc.ABCMeta): - # The logic mirrors that of ABCMeta.__subclasscheck__. - # Registered classes need not be checked here because - # cls and its extra share the same _abc_registry. - def __extrahook__(subclass): - res = cls.__extra__.__subclasshook__(subclass) - if res is not NotImplemented: - return res - if cls.__extra__ in subclass.__mro__: - return True - for scls in cls.__extra__.__subclasses__(): - if isinstance(scls, GenericMeta): - continue - if issubclass(subclass, scls): - return True - return NotImplemented - else: - # For non-ABC extras we'll just call issubclass(). - def __extrahook__(subclass): - if cls.__extra__ and issubclass(subclass, cls.__extra__): - return True - return NotImplemented - return __extrahook__ - - -def _no_slots_copy(dct): - """Internal helper: copy class __dict__ and clean slots class variables. - (They will be re-created if necessary by normal class machinery.) - """ - dict_copy = dict(dct) - if '__slots__' in dict_copy: - for slot in dict_copy['__slots__']: - dict_copy.pop(slot, None) - return dict_copy - - -class GenericMeta(TypingMeta, abc.ABCMeta): - """Metaclass for generic types. - - This is a metaclass for typing.Generic and generic ABCs defined in - typing module. User defined subclasses of GenericMeta can override - __new__ and invoke super().__new__. Note that GenericMeta.__new__ - has strict rules on what is allowed in its bases argument: - * plain Generic is disallowed in bases; - * Generic[...] should appear in bases at most once; - * if Generic[...] is present, then it should list all type variables - that appear in other bases. - In addition, type of all generic bases is erased, e.g., C[int] is - stripped to plain C. - """ - - def __new__(cls, name, bases, namespace, - tvars=None, args=None, origin=None, extra=None, orig_bases=None): - """Create a new generic class. GenericMeta.__new__ accepts - keyword arguments that are used for internal bookkeeping, therefore - an override should pass unused keyword arguments to super(). - """ - if tvars is not None: - # Called from __getitem__() below. - assert origin is not None - assert all(isinstance(t, TypeVar) for t in tvars), tvars - else: - # Called from class statement. - assert tvars is None, tvars - assert args is None, args - assert origin is None, origin - - # Get the full set of tvars from the bases. - tvars = _type_vars(bases) - # Look for Generic[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[...]. - gvars = None - for base in bases: - if base is Generic: - raise TypeError("Cannot inherit from plain Generic") - if (isinstance(base, GenericMeta) and - base.__origin__ is Generic): - if gvars is not None: - raise TypeError( - "Cannot inherit from Generic[...] multiple types.") - gvars = base.__parameters__ - if gvars is None: - gvars = tvars - else: - tvarset = set(tvars) - gvarset = set(gvars) - if not tvarset <= gvarset: - raise TypeError( - "Some type variables (%s) " - "are not listed in Generic[%s]" % - (", ".join(str(t) for t in tvars if t not in gvarset), - ", ".join(str(g) for g in gvars))) - tvars = gvars - - initial_bases = bases - if extra is not None and type(extra) is abc.ABCMeta and extra not in bases: - bases = (extra,) + bases - bases = tuple(b._gorg if isinstance(b, GenericMeta) else b for b in bases) - - # remove bare Generic from bases if there are other generic bases - if any(isinstance(b, GenericMeta) and b is not Generic for b in bases): - bases = tuple(b for b in bases if b is not Generic) - namespace.update({'__origin__': origin, '__extra__': extra, - '_gorg': None if not origin else origin._gorg}) - self = super().__new__(cls, name, bases, namespace, _root=True) - super(GenericMeta, self).__setattr__('_gorg', - self if not origin else origin._gorg) - self.__parameters__ = tvars - # Be prepared that GenericMeta will be subclassed by TupleMeta - # and CallableMeta, those two allow ..., (), or [] in __args___. - self.__args__ = tuple(... if a is _TypingEllipsis else - () if a is _TypingEmpty else - a for a in args) if args else None - # Speed hack (https://github.com/python/typing/issues/196). - self.__next_in_mro__ = _next_in_mro(self) - # Preserve base classes on subclassing (__bases__ are type erased now). - if orig_bases is None: - self.__orig_bases__ = initial_bases - - # This allows unparameterized generic collections to be used - # with issubclass() and isinstance() in the same way as their - # collections.abc counterparts (e.g., isinstance([], Iterable)). - if ( - '__subclasshook__' not in namespace and extra or - # allow overriding - getattr(self.__subclasshook__, '__name__', '') == '__extrahook__' - ): - self.__subclasshook__ = _make_subclasshook(self) - if isinstance(extra, abc.ABCMeta): - self._abc_registry = extra._abc_registry - self._abc_cache = extra._abc_cache - elif origin is not None: - self._abc_registry = origin._abc_registry - self._abc_cache = origin._abc_cache - - if origin and hasattr(origin, '__qualname__'): # Fix for Python 3.2. - self.__qualname__ = origin.__qualname__ - self.__tree_hash__ = (hash(self._subs_tree()) if origin else - super(GenericMeta, self).__hash__()) - return self - - # _abc_negative_cache and _abc_negative_cache_version - # realised as descriptors, since GenClass[t1, t2, ...] always - # share subclass info with GenClass. - # This is an important memory optimization. - @property - def _abc_negative_cache(self): - if isinstance(self.__extra__, abc.ABCMeta): - return self.__extra__._abc_negative_cache - return self._gorg._abc_generic_negative_cache - - @_abc_negative_cache.setter - def _abc_negative_cache(self, value): - if self.__origin__ is None: - if isinstance(self.__extra__, abc.ABCMeta): - self.__extra__._abc_negative_cache = value - else: - self._abc_generic_negative_cache = value - - @property - def _abc_negative_cache_version(self): - if isinstance(self.__extra__, abc.ABCMeta): - return self.__extra__._abc_negative_cache_version - return self._gorg._abc_generic_negative_cache_version - - @_abc_negative_cache_version.setter - def _abc_negative_cache_version(self, value): - if self.__origin__ is None: - if isinstance(self.__extra__, abc.ABCMeta): - self.__extra__._abc_negative_cache_version = value - else: - self._abc_generic_negative_cache_version = value - - def _get_type_vars(self, tvars): - if self.__origin__ and self.__parameters__: - _get_type_vars(self.__parameters__, tvars) - - def _eval_type(self, globalns, localns): - ev_origin = (self.__origin__._eval_type(globalns, localns) - if self.__origin__ else None) - ev_args = tuple(_eval_type(a, globalns, localns) for a - in self.__args__) if self.__args__ else None - if ev_origin == self.__origin__ and ev_args == self.__args__: - return self - return self.__class__(self.__name__, - self.__bases__, - _no_slots_copy(self.__dict__), - tvars=_type_vars(ev_args) if ev_args else None, - args=ev_args, - origin=ev_origin, - extra=self.__extra__, - orig_bases=self.__orig_bases__) - - def __repr__(self): - if self.__origin__ is None: - return super().__repr__() - return self._tree_repr(self._subs_tree()) - - def _tree_repr(self, tree): - arg_list = [] - for arg in tree[1:]: - if arg == (): - arg_list.append('()') - elif not isinstance(arg, tuple): - arg_list.append(_type_repr(arg)) - else: - arg_list.append(arg[0]._tree_repr(arg)) - return super().__repr__() + '[%s]' % ', '.join(arg_list) - - def _subs_tree(self, tvars=None, args=None): - if self.__origin__ is None: - return self - tree_args = _subs_tree(self, tvars, args) - return (self._gorg,) + tuple(tree_args) - - def __eq__(self, other): - if not isinstance(other, GenericMeta): - return NotImplemented - if self.__origin__ is None or other.__origin__ is None: - return self is other - return self.__tree_hash__ == other.__tree_hash__ - - def __hash__(self): - return self.__tree_hash__ - - @_tp_cache - def __getitem__(self, params): - if not isinstance(params, tuple): - params = (params,) - if not params and self._gorg is not Tuple: - raise TypeError( - "Parameter list to %s[...] cannot be empty" % _qualname(self)) - msg = "Parameters to generic types must be types." - params = tuple(_type_check(p, msg) for p in params) - if self is Generic: - # Generic can only be subscripted with unique type variables. - if not all(isinstance(p, TypeVar) for p in params): - raise TypeError( - "Parameters to Generic[...] must all be type variables") - if len(set(params)) != len(params): - raise TypeError( - "Parameters to Generic[...] must all be unique") - tvars = params - args = params - elif self in (Tuple, Callable): - tvars = _type_vars(params) - args = params - elif self is _Protocol: - # _Protocol is internal, don't check anything. - tvars = params - args = params - elif self.__origin__ in (Generic, _Protocol): - # Can't subscript Generic[...] or _Protocol[...]. - raise TypeError("Cannot subscript already-subscripted %s" % - repr(self)) - else: - # Subscripting a regular Generic subclass. - _check_generic(self, params) - tvars = _type_vars(params) - args = params - - prepend = (self,) if self.__origin__ is None else () - return self.__class__(self.__name__, - prepend + self.__bases__, - _no_slots_copy(self.__dict__), - tvars=tvars, - args=args, - origin=self, - extra=self.__extra__, - orig_bases=self.__orig_bases__) - - def __subclasscheck__(self, cls): - if self.__origin__ is not None: - if sys._getframe(1).f_globals['__name__'] not in ['abc', 'functools']: - raise TypeError("Parameterized generics cannot be used with class " - "or instance checks") - return False - if self is Generic: - raise TypeError("Class %r cannot be used with class " - "or instance checks" % self) - return super().__subclasscheck__(cls) - - def __instancecheck__(self, instance): - # Since we extend ABC.__subclasscheck__ and - # ABC.__instancecheck__ inlines the cache checking done by the - # latter, we must extend __instancecheck__ too. For simplicity - # we just skip the cache check -- instance checks for generic - # classes are supposed to be rare anyways. - return issubclass(instance.__class__, self) - - def __setattr__(self, attr, value): - # We consider all the subscripted generics as proxies for original class - if ( - attr.startswith('__') and attr.endswith('__') or - attr.startswith('_abc_') or - self._gorg is None # The class is not fully created, see #typing/506 - ): - super(GenericMeta, self).__setattr__(attr, value) - else: - super(GenericMeta, self._gorg).__setattr__(attr, value) - - -# Prevent checks for Generic to crash when defining Generic. -Generic = None - - -def _generic_new(base_cls, cls, *args, **kwds): - # Assure type is erased on instantiation, - # but attempt to store it in __orig_class__ - if cls.__origin__ is None: - if (base_cls.__new__ is object.__new__ and - cls.__init__ is not object.__init__): - return base_cls.__new__(cls) - else: - return base_cls.__new__(cls, *args, **kwds) - else: - origin = cls._gorg - if (base_cls.__new__ is object.__new__ and - cls.__init__ is not object.__init__): - obj = base_cls.__new__(origin) - else: - obj = base_cls.__new__(origin, *args, **kwds) - try: - obj.__orig_class__ = cls - except AttributeError: - pass - obj.__init__(*args, **kwds) - return obj - - -class Generic(metaclass=GenericMeta): - """Abstract base class for generic types. - - A generic type is typically declared by inheriting from - this class parameterized with one or more type variables. - For example, a generic mapping type might be defined as:: - - class Mapping(Generic[KT, VT]): - def __getitem__(self, key: KT) -> VT: - ... - # Etc. - - This class can then be used as follows:: - - def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT: - try: - return mapping[key] - except KeyError: - return default - """ - - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is Generic: - raise TypeError("Type Generic cannot be instantiated; " - "it can be used only as a base class") - return _generic_new(cls.__next_in_mro__, cls, *args, **kwds) - - -class _TypingEmpty: - """Internal placeholder for () or []. Used by TupleMeta and CallableMeta - to allow empty list/tuple in specific places, without allowing them - to sneak in where prohibited. - """ - - -class _TypingEllipsis: - """Internal placeholder for ... (ellipsis).""" - - -class TupleMeta(GenericMeta): - """Metaclass for Tuple (internal).""" - - @_tp_cache - def __getitem__(self, parameters): - if self.__origin__ is not None or self._gorg is not Tuple: - # Normal generic rules apply if this is not the first subscription - # or a subscription of a subclass. - return super().__getitem__(parameters) - if parameters == (): - return super().__getitem__((_TypingEmpty,)) - if not isinstance(parameters, tuple): - parameters = (parameters,) - if len(parameters) == 2 and parameters[1] is ...: - msg = "Tuple[t, ...]: t must be a type." - p = _type_check(parameters[0], msg) - return super().__getitem__((p, _TypingEllipsis)) - msg = "Tuple[t0, t1, ...]: each t must be a type." - parameters = tuple(_type_check(p, msg) for p in parameters) - return super().__getitem__(parameters) - - def __instancecheck__(self, obj): - if self.__args__ is None: - return isinstance(obj, tuple) - raise TypeError("Parameterized Tuple cannot be used " - "with isinstance().") - - def __subclasscheck__(self, cls): - if self.__args__ is None: - return issubclass(cls, tuple) - raise TypeError("Parameterized Tuple cannot be used " - "with issubclass().") - - -class Tuple(tuple, extra=tuple, metaclass=TupleMeta): - """Tuple type; Tuple[X, Y] is the cross-product type of X and Y. - - Example: Tuple[T1, T2] is a tuple of two elements corresponding - to type variables T1 and T2. Tuple[int, float, str] is a tuple - of an int, a float and a string. - - To specify a variable-length tuple of homogeneous type, use Tuple[T, ...]. - """ - - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is Tuple: - raise TypeError("Type Tuple cannot be instantiated; " - "use tuple() instead") - return _generic_new(tuple, cls, *args, **kwds) - - -class CallableMeta(GenericMeta): - """Metaclass for Callable (internal).""" - - def __repr__(self): - if self.__origin__ is None: - return super().__repr__() - return self._tree_repr(self._subs_tree()) - - def _tree_repr(self, tree): - if self._gorg is not Callable: - return super()._tree_repr(tree) - # For actual Callable (not its subclass) we override - # super()._tree_repr() for nice formatting. - arg_list = [] - for arg in tree[1:]: - if not isinstance(arg, tuple): - arg_list.append(_type_repr(arg)) - else: - arg_list.append(arg[0]._tree_repr(arg)) - if arg_list[0] == '...': - return repr(tree[0]) + '[..., %s]' % arg_list[1] - return (repr(tree[0]) + - '[[%s], %s]' % (', '.join(arg_list[:-1]), arg_list[-1])) - - def __getitem__(self, parameters): - """A thin wrapper around __getitem_inner__ to provide the latter - with hashable arguments to improve speed. - """ - - if self.__origin__ is not None or self._gorg is not Callable: - return super().__getitem__(parameters) - if not isinstance(parameters, tuple) or len(parameters) != 2: - raise TypeError("Callable must be used as " - "Callable[[arg, ...], result].") - args, result = parameters - if args is Ellipsis: - parameters = (Ellipsis, result) - else: - if not isinstance(args, list): - raise TypeError("Callable[args, result]: args must be a list." - " Got %.100r." % (args,)) - parameters = (tuple(args), result) - return self.__getitem_inner__(parameters) - - @_tp_cache - def __getitem_inner__(self, parameters): - args, result = parameters - msg = "Callable[args, result]: result must be a type." - result = _type_check(result, msg) - if args is Ellipsis: - return super().__getitem__((_TypingEllipsis, result)) - msg = "Callable[[arg, ...], result]: each arg must be a type." - args = tuple(_type_check(arg, msg) for arg in args) - parameters = args + (result,) - return super().__getitem__(parameters) - - -class Callable(extra=collections_abc.Callable, metaclass=CallableMeta): - """Callable type; Callable[[int], str] is a function of (int) -> str. - - The subscription syntax must always be used with exactly two - values: the argument list and the return type. The argument list - must be a list of types or ellipsis; the return type must be a single type. - - There is no syntax to indicate optional or keyword arguments, - such function types are rarely used as callback types. - """ - - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is Callable: - raise TypeError("Type Callable cannot be instantiated; " - "use a non-abstract subclass instead") - return _generic_new(cls.__next_in_mro__, cls, *args, **kwds) - - -class _ClassVar(_FinalTypingBase, _root=True): - """Special type construct to mark class variables. - - An annotation wrapped in ClassVar indicates that a given - attribute is intended to be used as a class variable and - should not be set on instances of that class. Usage:: - - class Starship: - stats: ClassVar[Dict[str, int]] = {} # class variable - damage: int = 10 # instance variable - - ClassVar accepts only types and cannot be further subscribed. - - Note that ClassVar is not a class itself, and should not - be used with isinstance() or issubclass(). - """ - - __slots__ = ('__type__',) - - def __init__(self, tp=None, **kwds): - self.__type__ = tp - - def __getitem__(self, item): - cls = type(self) - if self.__type__ is None: - return cls(_type_check(item, - '{} accepts only single type.'.format(cls.__name__[1:])), - _root=True) - raise TypeError('{} cannot be further subscripted' - .format(cls.__name__[1:])) - - def _eval_type(self, globalns, localns): - new_tp = _eval_type(self.__type__, globalns, localns) - if new_tp == self.__type__: - return self - return type(self)(new_tp, _root=True) - - def __repr__(self): - r = super().__repr__() - if self.__type__ is not None: - r += '[{}]'.format(_type_repr(self.__type__)) - return r - - def __hash__(self): - return hash((type(self).__name__, self.__type__)) - - def __eq__(self, other): - if not isinstance(other, _ClassVar): - return NotImplemented - if self.__type__ is not None: - return self.__type__ == other.__type__ - return self is other - - -ClassVar = _ClassVar(_root=True) - - -def cast(typ, val): - """Cast a value to a type. - - This returns the value unchanged. To the type checker this - signals that the return value has the designated type, but at - runtime we intentionally don't check anything (we want this - to be as fast as possible). - """ - return val - - -def _get_defaults(func): - """Internal helper to extract the default arguments, by name.""" - try: - code = func.__code__ - except AttributeError: - # Some built-in functions don't have __code__, __defaults__, etc. - return {} - pos_count = code.co_argcount - arg_names = code.co_varnames - arg_names = arg_names[:pos_count] - defaults = func.__defaults__ or () - kwdefaults = func.__kwdefaults__ - res = dict(kwdefaults) if kwdefaults else {} - pos_offset = pos_count - len(defaults) - for name, value in zip(arg_names[pos_offset:], defaults): - assert name not in res - res[name] = value - return res - - -_allowed_types = (types.FunctionType, types.BuiltinFunctionType, - types.MethodType, types.ModuleType, - WrapperDescriptorType, MethodWrapperType, MethodDescriptorType) - - -def get_type_hints(obj, globalns=None, localns=None): - """Return type hints for an object. - - This is often the same as obj.__annotations__, but it handles - forward references encoded as string literals, and if necessary - adds Optional[t] if a default value equal to None is set. - - 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 getattr(obj, '__no_type_check__', None): - return {} - # Classes require a special treatment. - if isinstance(obj, type): - hints = {} - for base in reversed(obj.__mro__): - if globalns is None: - base_globals = sys.modules[base.__module__].__dict__ - else: - base_globals = globalns - ann = base.__dict__.get('__annotations__', {}) - for name, value in ann.items(): - if value is None: - value = type(None) - if isinstance(value, str): - value = _ForwardRef(value) - value = _eval_type(value, base_globals, localns) - hints[name] = value - return hints - - if globalns is None: - if isinstance(obj, types.ModuleType): - globalns = obj.__dict__ - else: - globalns = getattr(obj, '__globals__', {}) - if localns is None: - localns = globalns - elif localns is None: - localns = globalns - hints = getattr(obj, '__annotations__', None) - if hints is None: - # Return empty annotations for something that _could_ have them. - if isinstance(obj, _allowed_types): - return {} - else: - raise TypeError('{!r} is not a module, class, method, ' - 'or function.'.format(obj)) - defaults = _get_defaults(obj) - hints = dict(hints) - for name, value in hints.items(): - if value is None: - value = type(None) - if isinstance(value, str): - value = _ForwardRef(value) - value = _eval_type(value, globalns, localns) - if name in defaults and defaults[name] is None: - value = Optional[value] - hints[name] = value - return hints - - -def no_type_check(arg): - """Decorator to indicate that annotations are not type hints. - - The argument must be a class or function; if it is a class, it - applies recursively to all methods and classes defined in that class - (but not to methods defined in its superclasses or subclasses). - - This mutates the function(s) or class(es) in place. - """ - if isinstance(arg, type): - arg_attrs = arg.__dict__.copy() - for attr, val in arg.__dict__.items(): - if val in arg.__bases__ + (arg,): - arg_attrs.pop(attr) - for obj in arg_attrs.values(): - if isinstance(obj, types.FunctionType): - obj.__no_type_check__ = True - if isinstance(obj, type): - no_type_check(obj) - try: - arg.__no_type_check__ = True - except TypeError: # built-in classes - pass - return arg - - -def no_type_check_decorator(decorator): - """Decorator to give another decorator the @no_type_check effect. - - This wraps the decorator with something that wraps the decorated - function in @no_type_check. - """ - - @functools.wraps(decorator) - def wrapped_decorator(*args, **kwds): - func = decorator(*args, **kwds) - func = no_type_check(func) - return func - - return wrapped_decorator - - -def _overload_dummy(*args, **kwds): - """Helper for @overload to raise when called.""" - raise NotImplementedError( - "You should not call an overloaded function. " - "A series of @overload-decorated functions " - "outside a stub module should always be followed " - "by an implementation that is not @overload-ed.") - - -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 - """ - return _overload_dummy - - -class _ProtocolMeta(GenericMeta): - """Internal metaclass for _Protocol. - - This exists so _Protocol classes can be generic without deriving - from Generic. - """ - - def __instancecheck__(self, obj): - if _Protocol not in self.__bases__: - return super().__instancecheck__(obj) - raise TypeError("Protocols cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - if not self._is_protocol: - # No structural checks since this isn't a protocol. - return NotImplemented - - if self is _Protocol: - # Every class is a subclass of the empty protocol. - return True - - # Find all attributes defined in the protocol. - attrs = self._get_protocol_attrs() - - for attr in attrs: - if not any(attr in d.__dict__ for d in cls.__mro__): - return False - return True - - def _get_protocol_attrs(self): - # Get all Protocol base classes. - protocol_bases = [] - for c in self.__mro__: - if getattr(c, '_is_protocol', False) and c.__name__ != '_Protocol': - protocol_bases.append(c) - - # Get attributes included in protocol. - attrs = set() - for base in protocol_bases: - for attr in base.__dict__.keys(): - # Include attributes not defined in any non-protocol bases. - for c in self.__mro__: - if (c is not base and attr in c.__dict__ and - not getattr(c, '_is_protocol', False)): - break - else: - if (not attr.startswith('_abc_') and - attr != '__abstractmethods__' and - attr != '__annotations__' and - attr != '__weakref__' and - attr != '_is_protocol' and - attr != '_gorg' and - attr != '__dict__' and - attr != '__args__' and - attr != '__slots__' and - attr != '_get_protocol_attrs' and - attr != '__next_in_mro__' and - attr != '__parameters__' and - attr != '__origin__' and - attr != '__orig_bases__' and - attr != '__extra__' and - attr != '__tree_hash__' and - attr != '__module__'): - attrs.add(attr) - - return attrs - - -class _Protocol(metaclass=_ProtocolMeta): - """Internal base class for protocol classes. - - This implements a simple-minded structural issubclass check - (similar but more general than the one-offs in collections.abc - such as Hashable). - """ - - __slots__ = () - - _is_protocol = True - - -# Various ABCs mimicking those in collections.abc. -# A few are simply re-exported for completeness. - -Hashable = collections_abc.Hashable # Not generic. - - -if hasattr(collections_abc, 'Awaitable'): - class Awaitable(Generic[T_co], extra=collections_abc.Awaitable): - __slots__ = () - - __all__.append('Awaitable') - - -if hasattr(collections_abc, 'Coroutine'): - class Coroutine(Awaitable[V_co], Generic[T_co, T_contra, V_co], - extra=collections_abc.Coroutine): - __slots__ = () - - __all__.append('Coroutine') - - -if hasattr(collections_abc, 'AsyncIterable'): - - class AsyncIterable(Generic[T_co], extra=collections_abc.AsyncIterable): - __slots__ = () - - class AsyncIterator(AsyncIterable[T_co], - extra=collections_abc.AsyncIterator): - __slots__ = () - - __all__.append('AsyncIterable') - __all__.append('AsyncIterator') - - -class Iterable(Generic[T_co], extra=collections_abc.Iterable): - __slots__ = () - - -class Iterator(Iterable[T_co], extra=collections_abc.Iterator): - __slots__ = () - - -class SupportsInt(_Protocol): - __slots__ = () - - @abstractmethod - def __int__(self) -> int: - pass - - -class SupportsFloat(_Protocol): - __slots__ = () - - @abstractmethod - def __float__(self) -> float: - pass - - -class SupportsComplex(_Protocol): - __slots__ = () - - @abstractmethod - def __complex__(self) -> complex: - pass - - -class SupportsBytes(_Protocol): - __slots__ = () - - @abstractmethod - def __bytes__(self) -> bytes: - pass - - -class SupportsIndex(_Protocol): - __slots__ = () - - @abstractmethod - def __index__(self) -> int: - pass - - -class SupportsAbs(_Protocol[T_co]): - __slots__ = () - - @abstractmethod - def __abs__(self) -> T_co: - pass - - -class SupportsRound(_Protocol[T_co]): - __slots__ = () - - @abstractmethod - def __round__(self, ndigits: int = 0) -> T_co: - pass - - -if hasattr(collections_abc, 'Reversible'): - class Reversible(Iterable[T_co], extra=collections_abc.Reversible): - __slots__ = () -else: - class Reversible(_Protocol[T_co]): - __slots__ = () - - @abstractmethod - def __reversed__(self) -> 'Iterator[T_co]': - pass - - -Sized = collections_abc.Sized # Not generic. - - -class Container(Generic[T_co], extra=collections_abc.Container): - __slots__ = () - - -if hasattr(collections_abc, 'Collection'): - class Collection(Sized, Iterable[T_co], Container[T_co], - extra=collections_abc.Collection): - __slots__ = () - - __all__.append('Collection') - - -# Callable was defined earlier. - -if hasattr(collections_abc, 'Collection'): - class AbstractSet(Collection[T_co], - extra=collections_abc.Set): - __slots__ = () -else: - class AbstractSet(Sized, Iterable[T_co], Container[T_co], - extra=collections_abc.Set): - __slots__ = () - - -class MutableSet(AbstractSet[T], extra=collections_abc.MutableSet): - __slots__ = () - - -# NOTE: It is only covariant in the value type. -if hasattr(collections_abc, 'Collection'): - class Mapping(Collection[KT], Generic[KT, VT_co], - extra=collections_abc.Mapping): - __slots__ = () -else: - class Mapping(Sized, Iterable[KT], Container[KT], Generic[KT, VT_co], - extra=collections_abc.Mapping): - __slots__ = () - - -class MutableMapping(Mapping[KT, VT], extra=collections_abc.MutableMapping): - __slots__ = () - - -if hasattr(collections_abc, 'Reversible'): - if hasattr(collections_abc, 'Collection'): - class Sequence(Reversible[T_co], Collection[T_co], - extra=collections_abc.Sequence): - __slots__ = () - else: - class Sequence(Sized, Reversible[T_co], Container[T_co], - extra=collections_abc.Sequence): - __slots__ = () -else: - class Sequence(Sized, Iterable[T_co], Container[T_co], - extra=collections_abc.Sequence): - __slots__ = () - - -class MutableSequence(Sequence[T], extra=collections_abc.MutableSequence): - __slots__ = () - - -class ByteString(Sequence[int], extra=collections_abc.ByteString): - __slots__ = () - - -class List(list, MutableSequence[T], extra=list): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is List: - raise TypeError("Type List cannot be instantiated; " - "use list() instead") - return _generic_new(list, cls, *args, **kwds) - - -class Deque(collections.deque, MutableSequence[T], extra=collections.deque): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is Deque: - return collections.deque(*args, **kwds) - return _generic_new(collections.deque, cls, *args, **kwds) - - -class Set(set, MutableSet[T], extra=set): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is Set: - raise TypeError("Type Set cannot be instantiated; " - "use set() instead") - return _generic_new(set, cls, *args, **kwds) - - -class FrozenSet(frozenset, AbstractSet[T_co], extra=frozenset): - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is FrozenSet: - raise TypeError("Type FrozenSet cannot be instantiated; " - "use frozenset() instead") - return _generic_new(frozenset, cls, *args, **kwds) - - -class MappingView(Sized, Iterable[T_co], extra=collections_abc.MappingView): - __slots__ = () - - -class KeysView(MappingView[KT], AbstractSet[KT], - extra=collections_abc.KeysView): - __slots__ = () - - -class ItemsView(MappingView[Tuple[KT, VT_co]], - AbstractSet[Tuple[KT, VT_co]], - Generic[KT, VT_co], - extra=collections_abc.ItemsView): - __slots__ = () - - -class ValuesView(MappingView[VT_co], extra=collections_abc.ValuesView): - __slots__ = () - - -if hasattr(contextlib, 'AbstractContextManager'): - class ContextManager(Generic[T_co], extra=contextlib.AbstractContextManager): - __slots__ = () -else: - class ContextManager(Generic[T_co]): - __slots__ = () - - def __enter__(self): - return self - - @abc.abstractmethod - def __exit__(self, exc_type, exc_value, traceback): - return None - - @classmethod - def __subclasshook__(cls, C): - if cls is ContextManager: - # In Python 3.6+, it is possible to set a method to None to - # explicitly indicate that the class does not implement an ABC - # (https://bugs.python.org/issue25958), but we do not support - # that pattern here because this fallback class is only used - # in Python 3.5 and earlier. - if (any("__enter__" in B.__dict__ for B in C.__mro__) and - any("__exit__" in B.__dict__ for B in C.__mro__)): - return True - return NotImplemented - - -if hasattr(contextlib, 'AbstractAsyncContextManager'): - class AsyncContextManager(Generic[T_co], - extra=contextlib.AbstractAsyncContextManager): - __slots__ = () - - __all__.append('AsyncContextManager') -elif sys.version_info[:2] >= (3, 5): - exec(""" -class AsyncContextManager(Generic[T_co]): - __slots__ = () - - async def __aenter__(self): - return self - - @abc.abstractmethod - async def __aexit__(self, exc_type, exc_value, traceback): - return None - - @classmethod - def __subclasshook__(cls, C): - if cls is AsyncContextManager: - if sys.version_info[:2] >= (3, 6): - return _collections_abc._check_methods(C, "__aenter__", "__aexit__") - if (any("__aenter__" in B.__dict__ for B in C.__mro__) and - any("__aexit__" in B.__dict__ for B in C.__mro__)): - return True - return NotImplemented - -__all__.append('AsyncContextManager') -""") - - -class Dict(dict, MutableMapping[KT, VT], extra=dict): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is Dict: - raise TypeError("Type Dict cannot be instantiated; " - "use dict() instead") - return _generic_new(dict, cls, *args, **kwds) - - -class DefaultDict(collections.defaultdict, MutableMapping[KT, VT], - extra=collections.defaultdict): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is DefaultDict: - return collections.defaultdict(*args, **kwds) - return _generic_new(collections.defaultdict, cls, *args, **kwds) - - -class Counter(collections.Counter, Dict[T, int], extra=collections.Counter): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is Counter: - return collections.Counter(*args, **kwds) - return _generic_new(collections.Counter, cls, *args, **kwds) - - -if hasattr(collections, 'ChainMap'): - # ChainMap only exists in 3.3+ - __all__.append('ChainMap') - - class ChainMap(collections.ChainMap, MutableMapping[KT, VT], - extra=collections.ChainMap): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is ChainMap: - return collections.ChainMap(*args, **kwds) - return _generic_new(collections.ChainMap, cls, *args, **kwds) - - -# Determine what base class to use for Generator. -if hasattr(collections_abc, 'Generator'): - # Sufficiently recent versions of 3.5 have a Generator ABC. - _G_base = collections_abc.Generator -else: - # Fall back on the exact type. - _G_base = types.GeneratorType - - -class Generator(Iterator[T_co], Generic[T_co, T_contra, V_co], - extra=_G_base): - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is Generator: - raise TypeError("Type Generator cannot be instantiated; " - "create a subclass instead") - return _generic_new(_G_base, cls, *args, **kwds) - - -if hasattr(collections_abc, 'AsyncGenerator'): - class AsyncGenerator(AsyncIterator[T_co], Generic[T_co, T_contra], - extra=collections_abc.AsyncGenerator): - __slots__ = () - - __all__.append('AsyncGenerator') - - -# Internal type variable used for Type[]. -CT_co = TypeVar('CT_co', covariant=True, bound=type) - - -# This is not a real generic class. Don't use outside annotations. -class Type(Generic[CT_co], extra=type): - """A special construct usable to annotate class objects. - - For example, suppose we have the following classes:: - - class User: ... # Abstract base for User classes - class BasicUser(User): ... - class ProUser(User): ... - class TeamUser(User): ... - - And a function that takes a class argument that's a subclass of - User and returns an instance of the corresponding class:: - - U = TypeVar('U', bound=User) - def new_user(user_class: Type[U]) -> U: - user = user_class() - # (Here we could write the user object to a database) - return user - - joe = new_user(BasicUser) - - At this point the type checker knows that joe has type BasicUser. - """ - - __slots__ = () - - -def _make_nmtuple(name, types): - msg = "NamedTuple('Name', [(f0, t0), (f1, t1), ...]); each t must be a type" - types = [(n, _type_check(t, msg)) for n, t in types] - nm_tpl = collections.namedtuple(name, [n for n, t in types]) - # Prior to PEP 526, only _field_types attribute was assigned. - # Now, both __annotations__ and _field_types are used to maintain compatibility. - nm_tpl.__annotations__ = nm_tpl._field_types = collections.OrderedDict(types) - try: - nm_tpl.__module__ = sys._getframe(2).f_globals.get('__name__', '__main__') - except (AttributeError, ValueError): - pass - return nm_tpl - - -_PY36 = sys.version_info[:2] >= (3, 6) - -# attributes prohibited to set in NamedTuple class syntax -_prohibited = ('__new__', '__init__', '__slots__', '__getnewargs__', - '_fields', '_field_defaults', '_field_types', - '_make', '_replace', '_asdict', '_source') - -_special = ('__module__', '__name__', '__qualname__', '__annotations__') - - -class NamedTupleMeta(type): - - def __new__(cls, typename, bases, ns): - if ns.get('_root', False): - return super().__new__(cls, typename, bases, ns) - if not _PY36: - raise TypeError("Class syntax for NamedTuple is only supported" - " in Python 3.6+") - types = ns.get('__annotations__', {}) - nm_tpl = _make_nmtuple(typename, types.items()) - defaults = [] - defaults_dict = {} - for field_name in types: - if field_name in ns: - default_value = ns[field_name] - defaults.append(default_value) - defaults_dict[field_name] = default_value - elif defaults: - raise TypeError("Non-default namedtuple field {field_name} cannot " - "follow default field(s) {default_names}" - .format(field_name=field_name, - default_names=', '.join(defaults_dict.keys()))) - nm_tpl.__new__.__annotations__ = collections.OrderedDict(types) - nm_tpl.__new__.__defaults__ = tuple(defaults) - nm_tpl._field_defaults = defaults_dict - # update from user namespace without overriding special namedtuple attributes - for key in ns: - if key in _prohibited: - raise AttributeError("Cannot overwrite NamedTuple attribute " + key) - elif key not in _special and key not in nm_tpl._fields: - setattr(nm_tpl, key, ns[key]) - return nm_tpl - - -class NamedTuple(metaclass=NamedTupleMeta): - """Typed version of namedtuple. - - Usage in Python versions >= 3.6:: - - class Employee(NamedTuple): - name: str - id: int - - This is equivalent to:: - - Employee = collections.namedtuple('Employee', ['name', 'id']) - - The resulting class has extra __annotations__ and _field_types - attributes, giving an ordered dict mapping field names to types. - __annotations__ should be preferred, while _field_types - is kept to maintain pre PEP 526 compatibility. (The field names - are in the _fields attribute, which is part of the namedtuple - API.) Alternative equivalent keyword syntax is also accepted:: - - Employee = NamedTuple('Employee', name=str, id=int) - - In Python versions <= 3.5 use:: - - Employee = NamedTuple('Employee', [('name', str), ('id', int)]) - """ - _root = True - - def __new__(*args, **kwargs): - if kwargs and not _PY36: - raise TypeError("Keyword syntax for NamedTuple is only supported" - " in Python 3.6+") - if not args: - raise TypeError('NamedTuple.__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("NamedTuple.__new__() missing 1 required positional " - "argument: 'typename'") - if args: - try: - fields, = args # allow the "fields" keyword be passed - except ValueError: - raise TypeError('NamedTuple.__new__() takes from 2 to 3 ' - 'positional arguments but {} ' - 'were given'.format(len(args) + 2)) - 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.items() - elif kwargs: - raise TypeError("Either list of fields or keywords" - " can be provided to NamedTuple, not both") - return _make_nmtuple(typename, fields) - - __new__.__text_signature__ = '($cls, typename, fields=None, /, **kwargs)' - - -def NewType(name, tp): - """NewType creates simple unique types with almost zero - runtime overhead. NewType(name, tp) is considered a subtype of tp - by static type checkers. At runtime, NewType(name, tp) returns - a dummy function that simply returns its argument. Usage:: - - UserId = NewType('UserId', int) - - def name_by_id(user_id: UserId) -> str: - ... - - UserId('user') # Fails type check - - name_by_id(42) # Fails type check - name_by_id(UserId(42)) # OK - - num = UserId(5) + 1 # type: int - """ - - def new_type(x): - return x - - new_type.__name__ = name - new_type.__supertype__ = tp - return new_type - - -# Python-version-specific alias (Python 2: unicode; Python 3: str) -Text = str - - -# Constant that's True when type checking, but False here. -TYPE_CHECKING = False - - -class IO(Generic[AnyStr]): - """Generic base class for TextIO and BinaryIO. - - This is an abstract, generic version of the return of open(). - - NOTE: This does not distinguish between the different possible - classes (text vs. binary, read vs. write vs. read/write, - append-only, unbuffered). The TextIO and BinaryIO subclasses - below capture the distinctions between text vs. binary, which is - pervasive in the interface; however we currently do not offer a - way to track the other distinctions in the type system. - """ - - __slots__ = () - - @abstractproperty - def mode(self) -> str: - pass - - @abstractproperty - def name(self) -> str: - pass - - @abstractmethod - def close(self) -> None: - pass - - @abstractproperty - def closed(self) -> bool: - pass - - @abstractmethod - def fileno(self) -> int: - pass - - @abstractmethod - def flush(self) -> None: - pass - - @abstractmethod - def isatty(self) -> bool: - pass - - @abstractmethod - def read(self, n: int = -1) -> AnyStr: - pass - - @abstractmethod - def readable(self) -> bool: - pass - - @abstractmethod - def readline(self, limit: int = -1) -> AnyStr: - pass - - @abstractmethod - def readlines(self, hint: int = -1) -> List[AnyStr]: - pass - - @abstractmethod - def seek(self, offset: int, whence: int = 0) -> int: - pass - - @abstractmethod - def seekable(self) -> bool: - pass - - @abstractmethod - def tell(self) -> int: - pass - - @abstractmethod - def truncate(self, size: int = None) -> int: - pass - - @abstractmethod - def writable(self) -> bool: - pass - - @abstractmethod - def write(self, s: AnyStr) -> int: - pass - - @abstractmethod - def writelines(self, lines: List[AnyStr]) -> None: - pass - - @abstractmethod - def __enter__(self) -> 'IO[AnyStr]': - pass - - @abstractmethod - def __exit__(self, type, value, traceback) -> None: - pass - - -class BinaryIO(IO[bytes]): - """Typed version of the return of open() in binary mode.""" - - __slots__ = () - - @abstractmethod - def write(self, s: Union[bytes, bytearray]) -> int: - pass - - @abstractmethod - def __enter__(self) -> 'BinaryIO': - pass - - -class TextIO(IO[str]): - """Typed version of the return of open() in text mode.""" - - __slots__ = () - - @abstractproperty - def buffer(self) -> BinaryIO: - pass - - @abstractproperty - def encoding(self) -> str: - pass - - @abstractproperty - def errors(self) -> Optional[str]: - pass - - @abstractproperty - def line_buffering(self) -> bool: - pass - - @abstractproperty - def newlines(self) -> Any: - pass - - @abstractmethod - def __enter__(self) -> 'TextIO': - pass - - -class io: - """Wrapper namespace for IO generic classes.""" - - __all__ = ['IO', 'TextIO', 'BinaryIO'] - IO = IO - TextIO = TextIO - BinaryIO = BinaryIO - - -io.__name__ = __name__ + '.io' -sys.modules[io.__name__] = io - - -Pattern = _TypeAlias('Pattern', AnyStr, type(stdlib_re.compile('')), - lambda p: p.pattern) -Match = _TypeAlias('Match', AnyStr, type(stdlib_re.match('', '')), - lambda m: m.re.pattern) - - -class re: - """Wrapper namespace for re type aliases.""" - - __all__ = ['Pattern', 'Match'] - Pattern = Pattern - Match = Match - - -re.__name__ = __name__ + '.re' -sys.modules[re.__name__] = re