From 4c5eddd63e94bacddb96bf61f81a6a8fcd9c33f0 Mon Sep 17 00:00:00 2001 From: Brock Date: Thu, 20 Aug 2020 21:19:10 -0700 Subject: [PATCH 01/12] REF: remove unnecesary try/except --- pandas/core/groupby/generic.py | 69 ++++++++++++++++------------------ 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/pandas/core/groupby/generic.py b/pandas/core/groupby/generic.py index 166631e69f523..51532a75d2d4a 100644 --- a/pandas/core/groupby/generic.py +++ b/pandas/core/groupby/generic.py @@ -31,7 +31,7 @@ import numpy as np from pandas._libs import lib -from pandas._typing import FrameOrSeries, FrameOrSeriesUnion +from pandas._typing import ArrayLike, FrameOrSeries, FrameOrSeriesUnion from pandas.util._decorators import Appender, Substitution, doc from pandas.core.dtypes.cast import ( @@ -60,6 +60,7 @@ validate_func_kwargs, ) import pandas.core.algorithms as algorithms +from pandas.core.arrays import ExtensionArray from pandas.core.base import DataError, SpecificationError import pandas.core.common as com from pandas.core.construction import create_series_with_explicit_dtype @@ -1034,32 +1035,31 @@ def _cython_agg_blocks( no_result = object() - def cast_result_block(result, block: "Block", how: str) -> "Block": - # see if we can cast the block to the desired dtype + def cast_agg_result(result, values: ArrayLike, how: str) -> ArrayLike: + # see if we can cast the values to the desired dtype # this may not be the original dtype assert not isinstance(result, DataFrame) assert result is not no_result - dtype = maybe_cast_result_dtype(block.dtype, how) + dtype = maybe_cast_result_dtype(values.dtype, how) result = maybe_downcast_numeric(result, dtype) - if block.is_extension and isinstance(result, np.ndarray): - # e.g. block.values was an IntegerArray - # (1, N) case can occur if block.values was Categorical + if isinstance(values, ExtensionArray) and isinstance(result, np.ndarray): + # e.g. values was an IntegerArray + # (1, N) case can occur if values was Categorical # and result is ndarray[object] # TODO(EA2D): special casing not needed with 2D EAs assert result.ndim == 1 or result.shape[0] == 1 try: # Cast back if feasible - result = type(block.values)._from_sequence( - result.ravel(), dtype=block.values.dtype + result = type(values)._from_sequence( + result.ravel(), dtype=values.dtype ) except (ValueError, TypeError): # reshape to be valid for non-Extension Block result = result.reshape(1, -1) - agg_block: "Block" = block.make_block(result) - return agg_block + return result def blk_func(block: "Block") -> List["Block"]: new_blocks: List["Block"] = [] @@ -1093,33 +1093,30 @@ def blk_func(block: "Block") -> List["Block"]: # Categoricals. This will done by later self._reindex_output() # Doing it here creates an error. See GH#34951 sgb = get_groupby(obj, self.grouper, observed=True) - try: - result = sgb.aggregate(lambda x: alt(x, axis=self.axis)) - except TypeError: - # we may have an exception in trying to aggregate - # continue and exclude the block - raise + result = sgb.aggregate(lambda x: alt(x, axis=self.axis)) + + result = cast(DataFrame, result) + # unwrap DataFrame to get array + if len(result._mgr.blocks) != 1: + # We've split an object block! Everything we've assumed + # about a single block input returning a single block output + # is a lie. To keep the code-path for the typical non-split case + # clean, we choose to clean up this mess later on. + assert len(locs) == result.shape[1] + for i, loc in enumerate(locs): + agg_block = result.iloc[:, [i]]._mgr.blocks[0] + agg_block.mgr_locs = [loc] + new_blocks.append(agg_block) else: - result = cast(DataFrame, result) - # unwrap DataFrame to get array - if len(result._mgr.blocks) != 1: - # We've split an object block! Everything we've assumed - # about a single block input returning a single block output - # is a lie. To keep the code-path for the typical non-split case - # clean, we choose to clean up this mess later on. - assert len(locs) == result.shape[1] - for i, loc in enumerate(locs): - agg_block = result.iloc[:, [i]]._mgr.blocks[0] - agg_block.mgr_locs = [loc] - new_blocks.append(agg_block) - else: - result = result._mgr.blocks[0].values - if isinstance(result, np.ndarray) and result.ndim == 1: - result = result.reshape(1, -1) - agg_block = cast_result_block(result, block, how) - new_blocks = [agg_block] + result = result._mgr.blocks[0].values + if isinstance(result, np.ndarray) and result.ndim == 1: + result = result.reshape(1, -1) + res_values = cast_agg_result(result, block.values, how) + agg_block = block.make_block(res_values) + new_blocks = [agg_block] else: - agg_block = cast_result_block(result, block, how) + res_values = cast_agg_result(result, block.values, how) + agg_block = block.make_block(res_values) new_blocks = [agg_block] return new_blocks From 42649fbb855a895ee5818d7dc80bdbd0ce0e9f5a Mon Sep 17 00:00:00 2001 From: Karthik Mathur <22126205+mathurk1@users.noreply.github.com> Date: Fri, 21 Aug 2020 17:34:51 -0500 Subject: [PATCH 02/12] TST: add test for agg on ordered categorical cols (#35630) --- .../tests/groupby/aggregate/test_aggregate.py | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/pandas/tests/groupby/aggregate/test_aggregate.py b/pandas/tests/groupby/aggregate/test_aggregate.py index ce9d4b892d775..8fe450fe6abfc 100644 --- a/pandas/tests/groupby/aggregate/test_aggregate.py +++ b/pandas/tests/groupby/aggregate/test_aggregate.py @@ -1063,6 +1063,85 @@ def test_groupby_get_by_index(): pd.testing.assert_frame_equal(res, expected) +@pytest.mark.parametrize( + "grp_col_dict, exp_data", + [ + ({"nr": "min", "cat_ord": "min"}, {"nr": [1, 5], "cat_ord": ["a", "c"]}), + ({"cat_ord": "min"}, {"cat_ord": ["a", "c"]}), + ({"nr": "min"}, {"nr": [1, 5]}), + ], +) +def test_groupby_single_agg_cat_cols(grp_col_dict, exp_data): + # test single aggregations on ordered categorical cols GHGH27800 + + # create the result dataframe + input_df = pd.DataFrame( + { + "nr": [1, 2, 3, 4, 5, 6, 7, 8], + "cat_ord": list("aabbccdd"), + "cat": list("aaaabbbb"), + } + ) + + input_df = input_df.astype({"cat": "category", "cat_ord": "category"}) + input_df["cat_ord"] = input_df["cat_ord"].cat.as_ordered() + result_df = input_df.groupby("cat").agg(grp_col_dict) + + # create expected dataframe + cat_index = pd.CategoricalIndex( + ["a", "b"], categories=["a", "b"], ordered=False, name="cat", dtype="category" + ) + + expected_df = pd.DataFrame(data=exp_data, index=cat_index) + + tm.assert_frame_equal(result_df, expected_df) + + +@pytest.mark.parametrize( + "grp_col_dict, exp_data", + [ + ({"nr": ["min", "max"], "cat_ord": "min"}, [(1, 4, "a"), (5, 8, "c")]), + ({"nr": "min", "cat_ord": ["min", "max"]}, [(1, "a", "b"), (5, "c", "d")]), + ({"cat_ord": ["min", "max"]}, [("a", "b"), ("c", "d")]), + ], +) +def test_groupby_combined_aggs_cat_cols(grp_col_dict, exp_data): + # test combined aggregations on ordered categorical cols GH27800 + + # create the result dataframe + input_df = pd.DataFrame( + { + "nr": [1, 2, 3, 4, 5, 6, 7, 8], + "cat_ord": list("aabbccdd"), + "cat": list("aaaabbbb"), + } + ) + + input_df = input_df.astype({"cat": "category", "cat_ord": "category"}) + input_df["cat_ord"] = input_df["cat_ord"].cat.as_ordered() + result_df = input_df.groupby("cat").agg(grp_col_dict) + + # create expected dataframe + cat_index = pd.CategoricalIndex( + ["a", "b"], categories=["a", "b"], ordered=False, name="cat", dtype="category" + ) + + # unpack the grp_col_dict to create the multi-index tuple + # this tuple will be used to create the expected dataframe index + multi_index_list = [] + for k, v in grp_col_dict.items(): + if isinstance(v, list): + for value in v: + multi_index_list.append([k, value]) + else: + multi_index_list.append([k, v]) + multi_index = pd.MultiIndex.from_tuples(tuple(multi_index_list)) + + expected_df = pd.DataFrame(data=exp_data, columns=multi_index, index=cat_index) + + tm.assert_frame_equal(result_df, expected_df) + + def test_nonagg_agg(): # GH 35490 - Single/Multiple agg of non-agg function give same results # TODO: agg should raise for functions that don't aggregate From 47121ddc1c655f428c6c3fcea8fbf02eba85600a Mon Sep 17 00:00:00 2001 From: tkmz-n <60312218+tkmz-n@users.noreply.github.com> Date: Sat, 22 Aug 2020 07:42:50 +0900 Subject: [PATCH 03/12] TST: resample does not yield empty groups (#10603) (#35799) --- pandas/tests/resample/test_timedelta.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pandas/tests/resample/test_timedelta.py b/pandas/tests/resample/test_timedelta.py index 0fbb60c176b30..3fa85e62d028c 100644 --- a/pandas/tests/resample/test_timedelta.py +++ b/pandas/tests/resample/test_timedelta.py @@ -150,3 +150,18 @@ def test_resample_timedelta_edge_case(start, end, freq, resample_freq): tm.assert_index_equal(result.index, expected_index) assert result.index.freq == expected_index.freq assert not np.isnan(result[-1]) + + +def test_resample_with_timedelta_yields_no_empty_groups(): + # GH 10603 + df = pd.DataFrame( + np.random.normal(size=(10000, 4)), + index=pd.timedelta_range(start="0s", periods=10000, freq="3906250n"), + ) + result = df.loc["1s":, :].resample("3s").apply(lambda x: len(x)) + + expected = pd.DataFrame( + [[768.0] * 4] * 12 + [[528.0] * 4], + index=pd.timedelta_range(start="1s", periods=13, freq="3s"), + ) + tm.assert_frame_equal(result, expected) From 1decb3e0ee1923a29b8eded7507bcb783b3870d0 Mon Sep 17 00:00:00 2001 From: Brock Date: Fri, 21 Aug 2020 18:48:02 -0700 Subject: [PATCH 04/12] revert accidental rebase --- pandas/core/groupby/generic.py | 61 ++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/pandas/core/groupby/generic.py b/pandas/core/groupby/generic.py index 4b1f6cfe0a662..60e23b14eaf09 100644 --- a/pandas/core/groupby/generic.py +++ b/pandas/core/groupby/generic.py @@ -30,7 +30,7 @@ import numpy as np from pandas._libs import lib -from pandas._typing import ArrayLike, FrameOrSeries, FrameOrSeriesUnion +from pandas._typing import FrameOrSeries, FrameOrSeriesUnion from pandas.util._decorators import Appender, Substitution, doc from pandas.core.dtypes.cast import ( @@ -59,7 +59,6 @@ validate_func_kwargs, ) import pandas.core.algorithms as algorithms -from pandas.core.arrays import ExtensionArray from pandas.core.base import DataError, SpecificationError import pandas.core.common as com from pandas.core.construction import create_series_with_explicit_dtype @@ -1034,31 +1033,32 @@ def _cython_agg_blocks( no_result = object() - def cast_agg_result(result, values: ArrayLike, how: str) -> ArrayLike: - # see if we can cast the values to the desired dtype + def cast_result_block(result, block: "Block", how: str) -> "Block": + # see if we can cast the block to the desired dtype # this may not be the original dtype assert not isinstance(result, DataFrame) assert result is not no_result - dtype = maybe_cast_result_dtype(values.dtype, how) + dtype = maybe_cast_result_dtype(block.dtype, how) result = maybe_downcast_numeric(result, dtype) - if isinstance(values, ExtensionArray) and isinstance(result, np.ndarray): - # e.g. values was an IntegerArray - # (1, N) case can occur if values was Categorical + if block.is_extension and isinstance(result, np.ndarray): + # e.g. block.values was an IntegerArray + # (1, N) case can occur if block.values was Categorical # and result is ndarray[object] # TODO(EA2D): special casing not needed with 2D EAs assert result.ndim == 1 or result.shape[0] == 1 try: # Cast back if feasible - result = type(values)._from_sequence( - result.ravel(), dtype=values.dtype + result = type(block.values)._from_sequence( + result.ravel(), dtype=block.values.dtype ) except (ValueError, TypeError): # reshape to be valid for non-Extension Block result = result.reshape(1, -1) - return result + agg_block: "Block" = block.make_block(result) + return agg_block def blk_func(block: "Block") -> List["Block"]: new_blocks: List["Block"] = [] @@ -1092,25 +1092,28 @@ def blk_func(block: "Block") -> List["Block"]: # Categoricals. This will done by later self._reindex_output() # Doing it here creates an error. See GH#34951 sgb = get_groupby(obj, self.grouper, observed=True) - result = sgb.aggregate(lambda x: alt(x, axis=self.axis)) - - assert isinstance(result, (Series, DataFrame)) # for mypy - # In the case of object dtype block, it may have been split - # in the operation. We un-split here. - result = result._consolidate() - assert isinstance(result, (Series, DataFrame)) # for mypy - assert len(result._mgr.blocks) == 1 - - # unwrap DataFrame to get array - result = result._mgr.blocks[0].values - if isinstance(result, np.ndarray) and result.ndim == 1: - result = result.reshape(1, -1) - res_values = cast_agg_result(result, block.values, how) - agg_block = block.make_block(res_values) - new_blocks = [agg_block] + try: + result = sgb.aggregate(lambda x: alt(x, axis=self.axis)) + except TypeError: + # we may have an exception in trying to aggregate + # continue and exclude the block + raise + else: + assert isinstance(result, (Series, DataFrame)) # for mypy + # In the case of object dtype block, it may have been split + # in the operation. We un-split here. + result = result._consolidate() + assert isinstance(result, (Series, DataFrame)) # for mypy + assert len(result._mgr.blocks) == 1 + + # unwrap DataFrame to get array + result = result._mgr.blocks[0].values + if isinstance(result, np.ndarray) and result.ndim == 1: + result = result.reshape(1, -1) + agg_block = cast_result_block(result, block, how) + new_blocks = [agg_block] else: - res_values = cast_agg_result(result, block.values, how) - agg_block = block.make_block(res_values) + agg_block = cast_result_block(result, block, how) new_blocks = [agg_block] return new_blocks From 94afda837375dd0e47c731753aa536bfb7a99007 Mon Sep 17 00:00:00 2001 From: Brock Date: Sun, 30 Aug 2020 19:46:37 -0700 Subject: [PATCH 05/12] vendor typing extensions --- pandas/_vendored/__init__.py | 0 pandas/_vendored/typing_extensions.py | 2177 +++++++++++++++++++++++++ setup.cfg | 10 +- 3 files changed, 2185 insertions(+), 2 deletions(-) create mode 100644 pandas/_vendored/__init__.py create mode 100644 pandas/_vendored/typing_extensions.py diff --git a/pandas/_vendored/__init__.py b/pandas/_vendored/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/pandas/_vendored/typing_extensions.py b/pandas/_vendored/typing_extensions.py new file mode 100644 index 0000000000000..f16154dfdb5d6 --- /dev/null +++ b/pandas/_vendored/typing_extensions.py @@ -0,0 +1,2177 @@ +""" +vendored copy of typing_extensions, copied from +https://raw.githubusercontent.com/python/typing/master/typing_extensions/src_py3/typing_extensions.py + +on 2020-08-30. + +typing_extensions is distributed under the Python Software Foundation License. +""" + +import abc +import collections +import contextlib +import sys +import typing +import collections.abc as collections_abc +import operator + +# These are used by Protocol implementation +# We use internal typing helpers here, but this significantly reduces +# code duplication. (Also this is only until Protocol is in typing.) +from typing import Generic, Callable, TypeVar, Tuple + +# After PEP 560, internal typing API was substantially reworked. +# This is especially important for Protocol class which uses internal APIs +# quite extensivelly. +PEP_560 = sys.version_info[:3] >= (3, 7, 0) + +if PEP_560: + GenericMeta = TypingMeta = type +else: + from typing import GenericMeta, TypingMeta +OLD_GENERICS = False +try: + from typing import _type_vars, _next_in_mro, _type_check +except ImportError: + OLD_GENERICS = True +try: + from typing import _subs_tree # noqa + SUBS_TREE = True +except ImportError: + SUBS_TREE = False +try: + from typing import _tp_cache +except ImportError: + def _tp_cache(x): + return x +try: + from typing import _TypingEllipsis, _TypingEmpty +except ImportError: + class _TypingEllipsis: + pass + + class _TypingEmpty: + pass + + +# The two functions below are copies of typing internal helpers. +# They are needed by _ProtocolMeta + + +def _no_slots_copy(dct): + dict_copy = dict(dct) + if '__slots__' in dict_copy: + for slot in dict_copy['__slots__']: + dict_copy.pop(slot, None) + return dict_copy + + +def _check_generic(cls, parameters): + 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)) + + +if hasattr(typing, '_generic_new'): + _generic_new = typing._generic_new +else: + # Note: The '_generic_new(...)' function is used as a part of the + # process of creating a generic type and was added to the typing module + # as of Python 3.5.3. + # + # We've defined '_generic_new(...)' below to exactly match the behavior + # implemented in older versions of 'typing' bundled with Python 3.5.0 to + # 3.5.2. This helps eliminate redundancy when defining collection types + # like 'Deque' later. + # + # See https://github.com/python/typing/pull/308 for more details -- in + # particular, compare and contrast the definition of types like + # 'typing.List' before and after the merge. + + def _generic_new(base_cls, cls, *args, **kwargs): + return base_cls.__new__(cls, *args, **kwargs) + +# See https://github.com/python/typing/pull/439 +if hasattr(typing, '_geqv'): + from typing import _geqv + _geqv_defined = True +else: + _geqv = None + _geqv_defined = False + +if sys.version_info[:2] >= (3, 6): + import _collections_abc + _check_methods_in_mro = _collections_abc._check_methods +else: + def _check_methods_in_mro(C, *methods): + mro = C.__mro__ + for method in methods: + for B in mro: + if method in B.__dict__: + if B.__dict__[method] is None: + return NotImplemented + break + else: + return NotImplemented + return True + + +# Please keep __all__ alphabetized within each category. +__all__ = [ + # Super-special typing primitives. + 'ClassVar', + 'Final', + 'Type', + + # ABCs (from collections.abc). + # The following are added depending on presence + # of their non-generic counterparts in stdlib: + # 'Awaitable', + # 'AsyncIterator', + # 'AsyncIterable', + # 'Coroutine', + # 'AsyncGenerator', + # 'AsyncContextManager', + # 'ChainMap', + + # Concrete collection types. + 'ContextManager', + 'Counter', + 'Deque', + 'DefaultDict', + 'TypedDict', + + # Structural checks, a.k.a. protocols. + 'SupportsIndex', + + # One-off things. + 'final', + 'IntVar', + 'Literal', + 'NewType', + 'overload', + 'Text', + 'TYPE_CHECKING', +] + +# Annotated relies on substitution trees of pep 560. It will not work for +# versions of typing older than 3.5.3 +HAVE_ANNOTATED = PEP_560 or SUBS_TREE + +if PEP_560: + __all__.extend(["get_args", "get_origin", "get_type_hints"]) + +if HAVE_ANNOTATED: + __all__.append("Annotated") + +# Protocols are hard to backport to the original version of typing 3.5.0 +HAVE_PROTOCOLS = sys.version_info[:3] != (3, 5, 0) + +if HAVE_PROTOCOLS: + __all__.extend(['Protocol', 'runtime', 'runtime_checkable']) + + +# TODO +if hasattr(typing, 'NoReturn'): + NoReturn = typing.NoReturn +elif hasattr(typing, '_FinalTypingBase'): + class _NoReturn(typing._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) +else: + class _NoReturnMeta(typing.TypingMeta): + """Metaclass for NoReturn""" + def __new__(cls, name, bases, namespace, _root=False): + return super().__new__(cls, name, bases, namespace, _root=_root) + + def __instancecheck__(self, obj): + raise TypeError("NoReturn cannot be used with isinstance().") + + def __subclasscheck__(self, cls): + raise TypeError("NoReturn cannot be used with issubclass().") + + class NoReturn(typing.Final, metaclass=_NoReturnMeta, _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__ = () + + +# Some unconstrained type variables. These are used by the container types. +# (These are not for export.) +T = typing.TypeVar('T') # Any type. +KT = typing.TypeVar('KT') # Key type. +VT = typing.TypeVar('VT') # Value type. +T_co = typing.TypeVar('T_co', covariant=True) # Any type covariant containers. +V_co = typing.TypeVar('V_co', covariant=True) # Any type covariant containers. +VT_co = typing.TypeVar('VT_co', covariant=True) # Value type covariant containers. +T_contra = typing.TypeVar('T_contra', contravariant=True) # Ditto contravariant. + + +if hasattr(typing, 'ClassVar'): + ClassVar = typing.ClassVar +elif hasattr(typing, '_FinalTypingBase'): + class _ClassVar(typing._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(typing._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 = typing._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(typing._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) +else: + class _ClassVarMeta(typing.TypingMeta): + """Metaclass for ClassVar""" + + def __new__(cls, name, bases, namespace, tp=None, _root=False): + self = super().__new__(cls, name, bases, namespace, _root=_root) + if tp is not None: + self.__type__ = tp + return self + + def __instancecheck__(self, obj): + raise TypeError("ClassVar cannot be used with isinstance().") + + def __subclasscheck__(self, cls): + raise TypeError("ClassVar cannot be used with issubclass().") + + def __getitem__(self, item): + cls = type(self) + if self.__type__ is not None: + raise TypeError('{} cannot be further subscripted' + .format(cls.__name__[1:])) + + param = typing._type_check( + item, + '{} accepts only single type.'.format(cls.__name__[1:])) + return cls(self.__name__, self.__bases__, + dict(self.__dict__), tp=param, _root=True) + + def _eval_type(self, globalns, localns): + new_tp = typing._eval_type(self.__type__, globalns, localns) + if new_tp == self.__type__: + return self + return type(self)(self.__name__, self.__bases__, + dict(self.__dict__), tp=self.__type__, + _root=True) + + def __repr__(self): + r = super().__repr__() + if self.__type__ is not None: + r += '[{}]'.format(typing._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 + + class ClassVar(typing.Final, metaclass=_ClassVarMeta, _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(). + """ + + __type__ = None + +# On older versions of typing there is an internal class named "Final". +if hasattr(typing, 'Final') and sys.version_info[:2] >= (3, 7): + Final = typing.Final +elif sys.version_info[:2] >= (3, 7): + class _FinalForm(typing._SpecialForm, _root=True): + + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + item = typing._type_check(parameters, + '{} accepts only single type'.format(self._name)) + return _GenericAlias(self, (item,)) + + Final = _FinalForm('Final', + doc="""A special typing construct to indicate that a name + cannot be re-assigned or overridden in a subclass. + For example: + + MAX_SIZE: Final = 9000 + MAX_SIZE += 1 # Error reported by type checker + + class Connection: + TIMEOUT: Final[int] = 10 + class FastConnector(Connection): + TIMEOUT = 1 # Error reported by type checker + + There is no runtime checking of these properties.""") +elif hasattr(typing, '_FinalTypingBase'): + class _Final(typing._FinalTypingBase, _root=True): + """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. + """ + + __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(typing._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 = typing._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(typing._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) +else: + class _FinalMeta(typing.TypingMeta): + """Metaclass for Final""" + + def __new__(cls, name, bases, namespace, tp=None, _root=False): + self = super().__new__(cls, name, bases, namespace, _root=_root) + if tp is not None: + self.__type__ = tp + return self + + def __instancecheck__(self, obj): + raise TypeError("Final cannot be used with isinstance().") + + def __subclasscheck__(self, cls): + raise TypeError("Final cannot be used with issubclass().") + + def __getitem__(self, item): + cls = type(self) + if self.__type__ is not None: + raise TypeError('{} cannot be further subscripted' + .format(cls.__name__[1:])) + + param = typing._type_check( + item, + '{} accepts only single type.'.format(cls.__name__[1:])) + return cls(self.__name__, self.__bases__, + dict(self.__dict__), tp=param, _root=True) + + def _eval_type(self, globalns, localns): + new_tp = typing._eval_type(self.__type__, globalns, localns) + if new_tp == self.__type__: + return self + return type(self)(self.__name__, self.__bases__, + dict(self.__dict__), tp=self.__type__, + _root=True) + + def __repr__(self): + r = super().__repr__() + if self.__type__ is not None: + r += '[{}]'.format(typing._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 + + class Final(typing.Final, metaclass=_FinalMeta, _root=True): + """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. + """ + + __type__ = None + + +if hasattr(typing, 'final'): + final = typing.final +else: + 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 + + +def IntVar(name): + return TypeVar(name) + + +if hasattr(typing, 'Literal'): + Literal = typing.Literal +elif sys.version_info[:2] >= (3, 7): + class _LiteralForm(typing._SpecialForm, _root=True): + + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + return _GenericAlias(self, parameters) + + Literal = _LiteralForm('Literal', + doc="""A type that can be used to indicate to type checkers + that the corresponding value has a value literally equivalent + to the provided parameter. For example: + + var: Literal[4] = 4 + + The type checker understands that 'var' is literally equal to + the value 4 and no other value. + + Literal[...] cannot be subclassed. There is no runtime + checking verifying that the parameter is actually a value + instead of a type.""") +elif hasattr(typing, '_FinalTypingBase'): + class _Literal(typing._FinalTypingBase, _root=True): + """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. + """ + + __slots__ = ('__values__',) + + def __init__(self, values=None, **kwds): + self.__values__ = values + + def __getitem__(self, values): + cls = type(self) + if self.__values__ is None: + if not isinstance(values, tuple): + values = (values,) + return cls(values, _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().__repr__() + if self.__values__ is not None: + r += '[{}]'.format(', '.join(map(typing._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) +else: + class _LiteralMeta(typing.TypingMeta): + """Metaclass for Literal""" + + def __new__(cls, name, bases, namespace, values=None, _root=False): + self = super().__new__(cls, name, bases, namespace, _root=_root) + if values is not None: + self.__values__ = values + return self + + def __instancecheck__(self, obj): + raise TypeError("Literal cannot be used with isinstance().") + + def __subclasscheck__(self, cls): + raise TypeError("Literal cannot be used with issubclass().") + + def __getitem__(self, item): + cls = type(self) + if self.__values__ is not None: + raise TypeError('{} cannot be further subscripted' + .format(cls.__name__[1:])) + + if not isinstance(item, tuple): + item = (item,) + return cls(self.__name__, self.__bases__, + dict(self.__dict__), values=item, _root=True) + + def _eval_type(self, globalns, localns): + return self + + def __repr__(self): + r = super().__repr__() + if self.__values__ is not None: + r += '[{}]'.format(', '.join(map(typing._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 + + class Literal(typing.Final, metaclass=_LiteralMeta, _root=True): + """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. + """ + + __values__ = None + + +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 + + +# This is not a real generic class. Don't use outside annotations. +if hasattr(typing, 'Type'): + Type = typing.Type +else: + # Internal type variable used for Type[]. + CT_co = typing.TypeVar('CT_co', covariant=True, bound=type) + + class Type(typing.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__ = () + + +# Various ABCs mimicking those in collections.abc. +# A few are simply re-exported for completeness. + +def _define_guard(type_name): + """ + Returns True if the given type isn't defined in typing but + is defined in collections_abc. + + Adds the type to __all__ if the collection is found in either + typing or collection_abc. + """ + if hasattr(typing, type_name): + __all__.append(type_name) + globals()[type_name] = getattr(typing, type_name) + return False + elif hasattr(collections_abc, type_name): + __all__.append(type_name) + return True + else: + return False + + +class _ExtensionsGenericMeta(GenericMeta): + def __subclasscheck__(self, subclass): + """This mimics a more modern GenericMeta.__subclasscheck__() logic + (that does not have problems with recursion) to work around interactions + between collections, typing, and typing_extensions on older + versions of Python, see https://github.com/python/typing/issues/501. + """ + if sys.version_info[:3] >= (3, 5, 3) or sys.version_info[:3] < (3, 5, 0): + 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 not self.__extra__: + return super().__subclasscheck__(subclass) + res = self.__extra__.__subclasshook__(subclass) + if res is not NotImplemented: + return res + if self.__extra__ in subclass.__mro__: + return True + for scls in self.__extra__.__subclasses__(): + if isinstance(scls, GenericMeta): + continue + if issubclass(subclass, scls): + return True + return False + + +if _define_guard('Awaitable'): + class Awaitable(typing.Generic[T_co], metaclass=_ExtensionsGenericMeta, + extra=collections_abc.Awaitable): + __slots__ = () + + +if _define_guard('Coroutine'): + class Coroutine(Awaitable[V_co], typing.Generic[T_co, T_contra, V_co], + metaclass=_ExtensionsGenericMeta, + extra=collections_abc.Coroutine): + __slots__ = () + + +if _define_guard('AsyncIterable'): + class AsyncIterable(typing.Generic[T_co], + metaclass=_ExtensionsGenericMeta, + extra=collections_abc.AsyncIterable): + __slots__ = () + + +if _define_guard('AsyncIterator'): + class AsyncIterator(AsyncIterable[T_co], + metaclass=_ExtensionsGenericMeta, + extra=collections_abc.AsyncIterator): + __slots__ = () + + +if hasattr(typing, 'Deque'): + Deque = typing.Deque +elif _geqv_defined: + class Deque(collections.deque, typing.MutableSequence[T], + metaclass=_ExtensionsGenericMeta, + extra=collections.deque): + __slots__ = () + + def __new__(cls, *args, **kwds): + if _geqv(cls, Deque): + return collections.deque(*args, **kwds) + return _generic_new(collections.deque, cls, *args, **kwds) +else: + class Deque(collections.deque, typing.MutableSequence[T], + metaclass=_ExtensionsGenericMeta, + 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) + + +if hasattr(typing, 'ContextManager'): + ContextManager = typing.ContextManager +elif hasattr(contextlib, 'AbstractContextManager'): + class ContextManager(typing.Generic[T_co], + metaclass=_ExtensionsGenericMeta, + extra=contextlib.AbstractContextManager): + __slots__ = () +else: + class ContextManager(typing.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(typing, 'AsyncContextManager'): + AsyncContextManager = typing.AsyncContextManager + __all__.append('AsyncContextManager') +elif hasattr(contextlib, 'AbstractAsyncContextManager'): + class AsyncContextManager(typing.Generic[T_co], + metaclass=_ExtensionsGenericMeta, + extra=contextlib.AbstractAsyncContextManager): + __slots__ = () + + __all__.append('AsyncContextManager') +elif sys.version_info[:2] >= (3, 5): + exec(""" +class AsyncContextManager(typing.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: + return _check_methods_in_mro(C, "__aenter__", "__aexit__") + return NotImplemented + +__all__.append('AsyncContextManager') +""") + + +if hasattr(typing, 'DefaultDict'): + DefaultDict = typing.DefaultDict +elif _geqv_defined: + class DefaultDict(collections.defaultdict, typing.MutableMapping[KT, VT], + metaclass=_ExtensionsGenericMeta, + extra=collections.defaultdict): + + __slots__ = () + + def __new__(cls, *args, **kwds): + if _geqv(cls, DefaultDict): + return collections.defaultdict(*args, **kwds) + return _generic_new(collections.defaultdict, cls, *args, **kwds) +else: + class DefaultDict(collections.defaultdict, typing.MutableMapping[KT, VT], + metaclass=_ExtensionsGenericMeta, + 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) + + +if hasattr(typing, 'Counter'): + Counter = typing.Counter +elif (3, 5, 0) <= sys.version_info[:3] <= (3, 5, 1): + assert _geqv_defined + _TInt = typing.TypeVar('_TInt') + + class _CounterMeta(typing.GenericMeta): + """Metaclass for Counter""" + def __getitem__(self, item): + return super().__getitem__((item, int)) + + class Counter(collections.Counter, + typing.Dict[T, int], + metaclass=_CounterMeta, + extra=collections.Counter): + + __slots__ = () + + def __new__(cls, *args, **kwds): + if _geqv(cls, Counter): + return collections.Counter(*args, **kwds) + return _generic_new(collections.Counter, cls, *args, **kwds) + +elif _geqv_defined: + class Counter(collections.Counter, + typing.Dict[T, int], + metaclass=_ExtensionsGenericMeta, extra=collections.Counter): + + __slots__ = () + + def __new__(cls, *args, **kwds): + if _geqv(cls, Counter): + return collections.Counter(*args, **kwds) + return _generic_new(collections.Counter, cls, *args, **kwds) + +else: + class Counter(collections.Counter, + typing.Dict[T, int], + metaclass=_ExtensionsGenericMeta, 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(typing, 'ChainMap'): + ChainMap = typing.ChainMap + __all__.append('ChainMap') +elif hasattr(collections, 'ChainMap'): + # ChainMap only exists in 3.3+ + if _geqv_defined: + class ChainMap(collections.ChainMap, typing.MutableMapping[KT, VT], + metaclass=_ExtensionsGenericMeta, + extra=collections.ChainMap): + + __slots__ = () + + def __new__(cls, *args, **kwds): + if _geqv(cls, ChainMap): + return collections.ChainMap(*args, **kwds) + return _generic_new(collections.ChainMap, cls, *args, **kwds) + else: + class ChainMap(collections.ChainMap, typing.MutableMapping[KT, VT], + metaclass=_ExtensionsGenericMeta, + 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) + + __all__.append('ChainMap') + + +if _define_guard('AsyncGenerator'): + class AsyncGenerator(AsyncIterator[T_co], typing.Generic[T_co, T_contra], + metaclass=_ExtensionsGenericMeta, + extra=collections_abc.AsyncGenerator): + __slots__ = () + + +if hasattr(typing, 'NewType'): + NewType = typing.NewType +else: + 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 + + +if hasattr(typing, 'Text'): + Text = typing.Text +else: + Text = str + + +if hasattr(typing, 'TYPE_CHECKING'): + TYPE_CHECKING = typing.TYPE_CHECKING +else: + # Constant that's True when type checking, but False here. + TYPE_CHECKING = False + + +def _gorg(cls): + """This function exists for compatibility with old typing versions.""" + assert isinstance(cls, GenericMeta) + if hasattr(cls, '_gorg'): + return cls._gorg + while cls.__origin__ is not None: + cls = cls.__origin__ + return cls + + +if OLD_GENERICS: + def _next_in_mro(cls): # noqa + """This function exists for compatibility with old typing versions.""" + next_in_mro = object + for i, c in enumerate(cls.__mro__[:-1]): + if isinstance(c, GenericMeta) and _gorg(c) is Generic: + next_in_mro = cls.__mro__[i + 1] + return next_in_mro + + +_PROTO_WHITELIST = ['Callable', 'Awaitable', + 'Iterable', 'Iterator', 'AsyncIterable', 'AsyncIterator', + 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', + 'ContextManager', 'AsyncContextManager'] + + +def _get_protocol_attrs(cls): + attrs = set() + for base in cls.__mro__[:-1]: # without object + if base.__name__ in ('Protocol', 'Generic'): + continue + annotations = getattr(base, '__annotations__', {}) + for attr in list(base.__dict__.keys()) + list(annotations.keys()): + if (not attr.startswith('_abc_') and attr not in ( + '__abstractmethods__', '__annotations__', '__weakref__', + '_is_protocol', '_is_runtime_protocol', '__dict__', + '__args__', '__slots__', + '__next_in_mro__', '__parameters__', '__origin__', + '__orig_bases__', '__extra__', '__tree_hash__', + '__doc__', '__subclasshook__', '__init__', '__new__', + '__module__', '_MutableMapping__marker', '_gorg')): + attrs.add(attr) + return attrs + + +def _is_callable_members_only(cls): + return all(callable(getattr(cls, attr, None)) for attr in _get_protocol_attrs(cls)) + + +if hasattr(typing, 'Protocol'): + Protocol = typing.Protocol +elif HAVE_PROTOCOLS and not PEP_560: + class _ProtocolMeta(GenericMeta): + """Internal metaclass for Protocol. + + This exists so Protocol classes can be generic without deriving + from Generic. + """ + if not OLD_GENERICS: + def __new__(cls, name, bases, namespace, + tvars=None, args=None, origin=None, extra=None, orig_bases=None): + # This is just a version copied from GenericMeta.__new__ that + # includes "Protocol" special treatment. (Comments removed for brevity.) + assert extra is None # Protocols should not have extra + if tvars is not None: + assert origin is not None + assert all(isinstance(t, TypeVar) for t in tvars), tvars + else: + tvars = _type_vars(bases) + 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 not None and type(extra) is abc.ABCMeta and + extra not in bases): + bases = (extra,) + bases + bases = tuple(_gorg(b) if isinstance(b, GenericMeta) else b + for b in 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, + _root=True) + super(GenericMeta, self).__setattr__('_gorg', + self if not origin else + _gorg(origin)) + self.__parameters__ = tvars + self.__args__ = tuple(... if a is _TypingEllipsis else + () if a is _TypingEmpty else + a for a in args) if args else None + self.__next_in_mro__ = _next_in_mro(self) + if orig_bases is None: + self.__orig_bases__ = initial_bases + elif origin is not None: + self._abc_registry = origin._abc_registry + self._abc_cache = origin._abc_cache + if hasattr(self, '_subs_tree'): + self.__tree_hash__ = (hash(self._subs_tree()) if origin else + super(GenericMeta, self).__hash__()) + return self + + def __init__(cls, *args, **kwargs): + super().__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__ == 'collections.abc' 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) + + def _no_init(self, *args, **kwargs): + if type(self)._is_protocol: + raise TypeError('Protocols cannot be instantiated') + cls.__init__ = _no_init + + def _proto_hook(other): + if not cls.__dict__.get('_is_protocol', None): + return NotImplemented + if not isinstance(other, type): + # Same error as for issubclass(1, int) + raise TypeError('issubclass() arg 1 must be a class') + for attr in _get_protocol_attrs(cls): + for base in other.__mro__: + if attr in base.__dict__: + if base.__dict__[attr] is None: + return NotImplemented + break + annotations = getattr(base, '__annotations__', {}) + if (isinstance(annotations, typing.Mapping) and + attr in annotations and + isinstance(other, _ProtocolMeta) and + other._is_protocol): + break + else: + return NotImplemented + return True + if '__subclasshook__' not in cls.__dict__: + cls.__subclasshook__ = _proto_hook + + def __instancecheck__(self, instance): + # We need this method for situations where attributes are + # assigned in __init__. + if ((not getattr(self, '_is_protocol', False) or + _is_callable_members_only(self)) and + issubclass(instance.__class__, self)): + return True + if self._is_protocol: + if all(hasattr(instance, attr) and + (not callable(getattr(self, attr, None)) or + getattr(instance, attr) is not None) + for attr in _get_protocol_attrs(self)): + return True + return super(GenericMeta, self).__instancecheck__(instance) + + 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.__dict__.get('_is_protocol', None) and + not self.__dict__.get('_is_runtime_protocol', None)): + if sys._getframe(1).f_globals['__name__'] in ['abc', + 'functools', + 'typing']: + return False + raise TypeError("Instance and class checks can only be used with" + " @runtime protocols") + if (self.__dict__.get('_is_runtime_protocol', None) and + not _is_callable_members_only(self)): + if sys._getframe(1).f_globals['__name__'] in ['abc', + 'functools', + 'typing']: + return super(GenericMeta, self).__subclasscheck__(cls) + raise TypeError("Protocols with non-method members" + " don't support issubclass()") + return super(GenericMeta, self).__subclasscheck__(cls) + + if not OLD_GENERICS: + @_tp_cache + def __getitem__(self, params): + # We also need to copy this from GenericMeta.__getitem__ to get + # special treatment of "Protocol". (Comments removed for brevity.) + if not isinstance(params, tuple): + params = (params,) + if not params and _gorg(self) is not Tuple: + raise TypeError( + "Parameter list to %s[...] cannot be empty" % self.__qualname__) + msg = "Parameters to generic types must be types." + params = tuple(_type_check(p, msg) for p in params) + if self in (Generic, Protocol): + if not all(isinstance(p, TypeVar) for p in params): + raise TypeError( + "Parameters to %r[...] must all be type variables" % self) + if len(set(params)) != len(params): + raise TypeError( + "Parameters to %r[...] must all be unique" % self) + tvars = params + args = params + elif self in (Tuple, Callable): + tvars = _type_vars(params) + args = params + elif self.__origin__ in (Generic, Protocol): + raise TypeError("Cannot subscript already-subscripted %s" % + repr(self)) + else: + _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__) + + class Protocol(metaclass=_ProtocolMeta): + """Base class for protocol classes. Protocol classes are defined as:: + + class Proto(Protocol): + def meth(self) -> int: + ... + + Such classes are primarily used with static type checkers that recognize + structural subtyping (static duck-typing), for example:: + + class C: + def meth(self) -> int: + return 0 + + def func(x: Proto) -> int: + return x.meth() + + func(C()) # Passes static type check + + See PEP 544 for details. Protocol classes decorated with + @typing_extensions.runtime act as simple-minded runtime protocol that checks + only the presence of given attributes, ignoring their type signatures. + + Protocol classes can be generic, they are defined as:: + + class GenProto({bases}): + def meth(self) -> T: + ... + """ + __slots__ = () + _is_protocol = True + + def __new__(cls, *args, **kwds): + if _gorg(cls) is Protocol: + raise TypeError("Type Protocol cannot be instantiated; " + "it can be used only as a base class") + if OLD_GENERICS: + return _generic_new(_next_in_mro(cls), cls, *args, **kwds) + return _generic_new(cls.__next_in_mro__, cls, *args, **kwds) + if Protocol.__doc__ is not None: + Protocol.__doc__ = Protocol.__doc__.format(bases="Protocol, Generic[T]" if + OLD_GENERICS else "Protocol[T]") + + +elif PEP_560: + from typing import _type_check, _GenericAlias, _collect_type_vars # noqa + + class _ProtocolMeta(abc.ABCMeta): + # This metaclass is a bit unfortunate and exists only because of the lack + # of __instancehook__. + def __instancecheck__(cls, instance): + # We need this method for situations where attributes are + # assigned in __init__. + if ((not getattr(cls, '_is_protocol', False) or + _is_callable_members_only(cls)) and + issubclass(instance.__class__, cls)): + return True + if cls._is_protocol: + if all(hasattr(instance, attr) and + (not callable(getattr(cls, attr, None)) or + getattr(instance, attr) is not None) + for attr in _get_protocol_attrs(cls)): + return True + return super().__instancecheck__(instance) + + class Protocol(metaclass=_ProtocolMeta): + # There is quite a lot of overlapping code with typing.Generic. + # Unfortunately it is hard to avoid this while these live in two different + # modules. The duplicated code will be removed when Protocol is moved to typing. + """Base class for protocol classes. Protocol classes are defined as:: + + class Proto(Protocol): + def meth(self) -> int: + ... + + Such classes are primarily used with static type checkers that recognize + structural subtyping (static duck-typing), for example:: + + class C: + def meth(self) -> int: + return 0 + + def func(x: Proto) -> int: + return x.meth() + + func(C()) # Passes static type check + + See PEP 544 for details. Protocol classes decorated with + @typing_extensions.runtime act as simple-minded runtime protocol that checks + only the presence of given attributes, ignoring their type signatures. + + Protocol classes can be generic, they are defined as:: + + class GenProto(Protocol[T]): + def meth(self) -> T: + ... + """ + __slots__ = () + _is_protocol = True + + def __new__(cls, *args, **kwds): + if cls is Protocol: + raise TypeError("Type Protocol cannot be instantiated; " + "it can only be used as a base class") + return super().__new__(cls) + + @_tp_cache + def __class_getitem__(cls, params): + if not isinstance(params, tuple): + params = (params,) + if not params and cls is not Tuple: + raise TypeError( + "Parameter list to {}[...] cannot be empty".format(cls.__qualname__)) + msg = "Parameters to generic types must be types." + params = tuple(_type_check(p, msg) for p in params) + if cls is Protocol: + # Generic can only be subscripted with unique type variables. + if not all(isinstance(p, TypeVar) for p in params): + i = 0 + while isinstance(params[i], TypeVar): + i += 1 + raise TypeError( + "Parameters to Protocol[...] must all be type variables." + " Parameter {} is {}".format(i + 1, params[i])) + if len(set(params)) != len(params): + raise TypeError( + "Parameters to Protocol[...] must all be unique") + else: + # Subscripting a regular Generic subclass. + _check_generic(cls, params) + return _GenericAlias(cls, params) + + def __init_subclass__(cls, *args, **kwargs): + tvars = [] + if '__orig_bases__' in cls.__dict__: + error = Generic in cls.__orig_bases__ + else: + error = Generic in cls.__bases__ + if error: + raise TypeError("Cannot inherit from plain Generic") + if '__orig_bases__' in cls.__dict__: + tvars = _collect_type_vars(cls.__orig_bases__) + # Look for Generic[T1, ..., Tn] or Protocol[T1, ..., Tn]. + # If found, tvars must be a subset of it. + # If not found, tvars is it. + # Also check for and reject plain Generic, + # and reject multiple Generic[...] and/or Protocol[...]. + gvars = None + for base in cls.__orig_bases__: + if (isinstance(base, _GenericAlias) and + base.__origin__ in (Generic, Protocol)): + # for error messages + the_base = 'Generic' if base.__origin__ is Generic else 'Protocol' + if gvars is not None: + raise TypeError( + "Cannot inherit from Generic[...]" + " and/or Protocol[...] multiple types.") + gvars = base.__parameters__ + if gvars is None: + gvars = tvars + else: + tvarset = set(tvars) + gvarset = set(gvars) + if not tvarset <= gvarset: + s_vars = ', '.join(str(t) for t in tvars if t not in gvarset) + s_args = ', '.join(str(g) for g in gvars) + raise TypeError("Some type variables ({}) are" + " not listed in {}[{}]".format(s_vars, + the_base, s_args)) + tvars = gvars + cls.__parameters__ = tuple(tvars) + + # Determine if this is a protocol or a concrete subclass. + if not cls.__dict__.get('_is_protocol', None): + cls._is_protocol = any(b is Protocol for b in cls.__bases__) + + # Set (or override) the protocol subclass hook. + def _proto_hook(other): + if not cls.__dict__.get('_is_protocol', None): + return NotImplemented + if not getattr(cls, '_is_runtime_protocol', False): + if sys._getframe(2).f_globals['__name__'] in ['abc', 'functools']: + return NotImplemented + raise TypeError("Instance and class checks can only be used with" + " @runtime protocols") + if not _is_callable_members_only(cls): + if sys._getframe(2).f_globals['__name__'] in ['abc', 'functools']: + return NotImplemented + raise TypeError("Protocols with non-method members" + " don't support issubclass()") + if not isinstance(other, type): + # Same error as for issubclass(1, int) + raise TypeError('issubclass() arg 1 must be a class') + for attr in _get_protocol_attrs(cls): + for base in other.__mro__: + if attr in base.__dict__: + if base.__dict__[attr] is None: + return NotImplemented + break + annotations = getattr(base, '__annotations__', {}) + if (isinstance(annotations, typing.Mapping) and + attr in annotations and + isinstance(other, _ProtocolMeta) and + other._is_protocol): + break + else: + return NotImplemented + return True + if '__subclasshook__' not in cls.__dict__: + cls.__subclasshook__ = _proto_hook + + # We have nothing more to do for non-protocols. + if not cls._is_protocol: + return + + # Check consistency of bases. + for base in cls.__bases__: + if not (base in (object, Generic) or + base.__module__ == 'collections.abc' and + base.__name__ in _PROTO_WHITELIST or + isinstance(base, _ProtocolMeta) and base._is_protocol): + raise TypeError('Protocols can only inherit from other' + ' protocols, got %r' % base) + + def _no_init(self, *args, **kwargs): + if type(self)._is_protocol: + raise TypeError('Protocols cannot be instantiated') + cls.__init__ = _no_init + + +if hasattr(typing, 'runtime_checkable'): + runtime_checkable = typing.runtime_checkable +elif HAVE_PROTOCOLS: + 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 + + +if HAVE_PROTOCOLS: + # Exists for backwards compatibility. + runtime = runtime_checkable + + +if hasattr(typing, 'SupportsIndex'): + SupportsIndex = typing.SupportsIndex +elif HAVE_PROTOCOLS: + @runtime_checkable + class SupportsIndex(Protocol): + __slots__ = () + + @abc.abstractmethod + def __index__(self) -> int: + pass + + +if sys.version_info[:2] >= (3, 9): + # The standard library TypedDict in Python 3.8 does not store runtime information + # about which (if any) keys are optional. See https://bugs.python.org/issue38834 + TypedDict = typing.TypedDict +else: + def _check_fails(cls, other): + try: + if sys._getframe(1).f_globals['__name__'] not in ['abc', + 'functools', + 'typing']: + # Typed dicts are only for static structural subtyping. + raise TypeError('TypedDict does not support instance and class checks') + except (AttributeError, ValueError): + pass + return False + + def _dict_new(*args, **kwargs): + if not args: + raise TypeError('TypedDict.__new__(): not enough arguments') + _, args = args[0], args[1:] # allow the "cls" keyword be passed + return dict(*args, **kwargs) + + _dict_new.__text_signature__ = '($cls, _typename, _fields=None, /, **kwargs)' + + def _typeddict_new(*args, total=True, **kwargs): + if not args: + raise TypeError('TypedDict.__new__(): not enough arguments') + _, args = args[0], args[1:] # allow the "cls" keyword be passed + if args: + typename, args = args[0], args[1:] # allow the "_typename" keyword be passed + elif '_typename' in kwargs: + typename = kwargs.pop('_typename') + import warnings + warnings.warn("Passing '_typename' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + raise TypeError("TypedDict.__new__() missing 1 required positional " + "argument: '_typename'") + if args: + try: + fields, = args # allow the "_fields" keyword be passed + except ValueError: + raise TypeError('TypedDict.__new__() takes from 2 to 3 ' + '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 + 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) + + _typeddict_new.__text_signature__ = ('($cls, _typename, _fields=None,' + ' /, *, total=True, **kwargs)') + + 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 == 'TypedDict' else _dict_new + tp_dict = super(_TypedDictMeta, cls).__new__(cls, name, (dict,), ns) + + annotations = {} + own_annotations = ns.get('__annotations__', {}) + own_annotation_keys = set(own_annotations.keys()) + msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type" + own_annotations = { + n: typing._type_check(tp, msg) for n, tp in own_annotations.items() + } + required_keys = set() + optional_keys = set() + + for base in bases: + annotations.update(base.__dict__.get('__annotations__', {})) + required_keys.update(base.__dict__.get('__required_keys__', ())) + optional_keys.update(base.__dict__.get('__optional_keys__', ())) + + annotations.update(own_annotations) + if total: + required_keys.update(own_annotation_keys) + else: + optional_keys.update(own_annotation_keys) + + tp_dict.__annotations__ = annotations + tp_dict.__required_keys__ = frozenset(required_keys) + tp_dict.__optional_keys__ = frozenset(optional_keys) + if not hasattr(tp_dict, '__total__'): + tp_dict.__total__ = total + return tp_dict + + __instancecheck__ = __subclasscheck__ = _check_fails + + TypedDict = _TypedDictMeta('TypedDict', (dict,), {}) + TypedDict.__module__ = __name__ + TypedDict.__doc__ = \ + """A simple typed name space. At runtime it is equivalent to a plain dict. + + TypedDict creates a dictionary type that expects all of its + instances to have a certain set of keys, with each key + associated with a value of a consistent type. This expectation + is not checked at runtime but is only enforced by type checkers. + Usage:: + + class Point2D(TypedDict): + x: int + y: int + label: str + + a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK + b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check + + assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first') + + The type info can be accessed via the Point2D.__annotations__ dict, and + the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets. + TypedDict supports two additional equivalent forms:: + + Point2D = TypedDict('Point2D', x=int, y=int, label=str) + Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str}) + + The class syntax is only supported in Python 3.6+, while two other + syntax forms work for Python 2.7 and 3.2+ + """ + + +# Python 3.9+ has PEP 593 (Annotated and modified get_type_hints) +if hasattr(typing, 'Annotated'): + Annotated = typing.Annotated + get_type_hints = typing.get_type_hints + # Not exported and not a public API, but needed for get_origin() and get_args() + # to work. + _AnnotatedAlias = typing._AnnotatedAlias +elif PEP_560: + class _AnnotatedAlias(typing._GenericAlias, _root=True): + """Runtime representation of an annotated type. + + At its core 'Annotated[t, dec1, dec2, ...]' is an alias for the type 't' + with extra annotations. The alias behaves like a normal typing alias, + instantiating is the same as instantiating the underlying type, binding + it to types is also the same. + """ + def __init__(self, origin, metadata): + if isinstance(origin, _AnnotatedAlias): + metadata = origin.__metadata__ + metadata + origin = origin.__origin__ + super().__init__(origin, origin) + self.__metadata__ = metadata + + def copy_with(self, params): + assert len(params) == 1 + new_type = params[0] + return _AnnotatedAlias(new_type, self.__metadata__) + + def __repr__(self): + return "typing_extensions.Annotated[{}, {}]".format( + typing._type_repr(self.__origin__), + ", ".join(repr(a) for a in self.__metadata__) + ) + + def __reduce__(self): + return operator.getitem, ( + Annotated, (self.__origin__,) + self.__metadata__ + ) + + def __eq__(self, other): + if not isinstance(other, _AnnotatedAlias): + return NotImplemented + if self.__origin__ != other.__origin__: + return False + return self.__metadata__ == other.__metadata__ + + def __hash__(self): + return hash((self.__origin__, self.__metadata__)) + + class Annotated: + """Add context specific metadata to a type. + + Example: Annotated[int, runtime_check.Unsigned] indicates to the + hypothetical runtime_check module that this type is an unsigned int. + Every other consumer of this type can ignore this metadata and treat + this type as int. + + The first argument to Annotated must be a valid type (and will be in + the __origin__ field), the remaining arguments are kept as a tuple in + the __extra__ field. + + Details: + + - It's an error to call `Annotated` with less than two arguments. + - Nested Annotated are flattened:: + + Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] + + - Instantiating an annotated type is equivalent to instantiating the + underlying type:: + + Annotated[C, Ann1](5) == C(5) + + - Annotated can be used as a generic type alias:: + + Optimized = Annotated[T, runtime.Optimize()] + Optimized[int] == Annotated[int, runtime.Optimize()] + + OptimizedList = Annotated[List[T], runtime.Optimize()] + OptimizedList[int] == Annotated[List[int], runtime.Optimize()] + """ + + __slots__ = () + + def __new__(cls, *args, **kwargs): + raise TypeError("Type Annotated cannot be instantiated.") + + @_tp_cache + def __class_getitem__(cls, params): + if not isinstance(params, tuple) or len(params) < 2: + raise TypeError("Annotated[...] should be used " + "with at least two arguments (a type and an " + "annotation).") + msg = "Annotated[t, ...]: t must be a type." + origin = typing._type_check(params[0], msg) + metadata = tuple(params[1:]) + return _AnnotatedAlias(origin, metadata) + + def __init_subclass__(cls, *args, **kwargs): + raise TypeError( + "Cannot subclass {}.Annotated".format(cls.__module__) + ) + + def _strip_annotations(t): + """Strips the annotations from a given type. + """ + if isinstance(t, _AnnotatedAlias): + return _strip_annotations(t.__origin__) + if isinstance(t, typing._GenericAlias): + stripped_args = tuple(_strip_annotations(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + res = t.copy_with(stripped_args) + res._special = t._special + return res + return t + + def get_type_hints(obj, globalns=None, localns=None, include_extras=False): + """Return type hints for an object. + + This is often the same as obj.__annotations__, but it handles + forward references encoded as string literals, adds Optional[t] if a + default value equal to None is set and recursively replaces all + 'Annotated[T, ...]' with 'T' (unless 'include_extras=True'). + + The argument may be a module, class, method, or function. The annotations + are returned as a dictionary. For classes, annotations include also + inherited members. + + TypeError is raised if the argument is not of a type that can contain + annotations, and an empty dictionary is returned if no annotations are + present. + + BEWARE -- the behavior of globalns and localns is counterintuitive + (unless you are familiar with how eval() and exec() work). The + search order is locals first, then globals. + + - If no dict arguments are passed, an attempt is made to use the + globals from obj (or the respective module's globals for classes), + and these are also used as the locals. If the object does not appear + to have globals, an empty dictionary is used. + + - If one dict argument is passed, it is used for both globals and + locals. + + - If two dict arguments are passed, they specify globals and + locals, respectively. + """ + hint = typing.get_type_hints(obj, globalns=globalns, localns=localns) + if include_extras: + return hint + return {k: _strip_annotations(t) for k, t in hint.items()} + +elif HAVE_ANNOTATED: + + def _is_dunder(name): + """Returns True if name is a __dunder_variable_name__.""" + return len(name) > 4 and name.startswith('__') and name.endswith('__') + + # Prior to Python 3.7 types did not have `copy_with`. A lot of the equality + # checks, argument expansion etc. are done on the _subs_tre. As a result we + # can't provide a get_type_hints function that strips out annotations. + + class AnnotatedMeta(typing.GenericMeta): + """Metaclass for Annotated""" + + def __new__(cls, name, bases, namespace, **kwargs): + if any(b is not object for b in bases): + raise TypeError("Cannot subclass " + str(Annotated)) + return super().__new__(cls, name, bases, namespace, **kwargs) + + @property + def __metadata__(self): + return self._subs_tree()[2] + + def _tree_repr(self, tree): + cls, origin, metadata = tree + if not isinstance(origin, tuple): + tp_repr = typing._type_repr(origin) + else: + tp_repr = origin[0]._tree_repr(origin) + metadata_reprs = ", ".join(repr(arg) for arg in metadata) + return '%s[%s, %s]' % (cls, tp_repr, metadata_reprs) + + def _subs_tree(self, tvars=None, args=None): # noqa + if self is Annotated: + return Annotated + res = super()._subs_tree(tvars=tvars, args=args) + # Flatten nested Annotated + if isinstance(res[1], tuple) and res[1][0] is Annotated: + sub_tp = res[1][1] + sub_annot = res[1][2] + return (Annotated, sub_tp, sub_annot + res[2]) + return res + + def _get_cons(self): + """Return the class used to create instance of this type.""" + if self.__origin__ is None: + raise TypeError("Cannot get the underlying type of a " + "non-specialized Annotated type.") + tree = self._subs_tree() + while isinstance(tree, tuple) and tree[0] is Annotated: + tree = tree[1] + if isinstance(tree, tuple): + return tree[0] + else: + return tree + + @_tp_cache + def __getitem__(self, params): + if not isinstance(params, tuple): + params = (params,) + if self.__origin__ is not None: # specializing an instantiated type + return super().__getitem__(params) + elif not isinstance(params, tuple) or len(params) < 2: + raise TypeError("Annotated[...] should be instantiated " + "with at least two arguments (a type and an " + "annotation).") + else: + msg = "Annotated[t, ...]: t must be a type." + tp = typing._type_check(params[0], msg) + metadata = tuple(params[1:]) + return self.__class__( + self.__name__, + self.__bases__, + _no_slots_copy(self.__dict__), + tvars=_type_vars((tp,)), + # Metadata is a tuple so it won't be touched by _replace_args et al. + args=(tp, metadata), + origin=self, + ) + + def __call__(self, *args, **kwargs): + cons = self._get_cons() + result = cons(*args, **kwargs) + try: + result.__orig_class__ = self + except AttributeError: + pass + return result + + def __getattr__(self, attr): + # For simplicity we just don't relay all dunder names + if self.__origin__ is not None and not _is_dunder(attr): + return getattr(self._get_cons(), attr) + raise AttributeError(attr) + + def __setattr__(self, attr, value): + if _is_dunder(attr) or attr.startswith('_abc_'): + super().__setattr__(attr, value) + elif self.__origin__ is None: + raise AttributeError(attr) + else: + setattr(self._get_cons(), attr, value) + + def __instancecheck__(self, obj): + raise TypeError("Annotated cannot be used with isinstance().") + + def __subclasscheck__(self, cls): + raise TypeError("Annotated cannot be used with issubclass().") + + class Annotated(metaclass=AnnotatedMeta): + """Add context specific metadata to a type. + + Example: Annotated[int, runtime_check.Unsigned] indicates to the + hypothetical runtime_check module that this type is an unsigned int. + Every other consumer of this type can ignore this metadata and treat + this type as int. + + The first argument to Annotated must be a valid type, the remaining + arguments are kept as a tuple in the __metadata__ field. + + Details: + + - It's an error to call `Annotated` with less than two arguments. + - Nested Annotated are flattened:: + + Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] + + - Instantiating an annotated type is equivalent to instantiating the + underlying type:: + + Annotated[C, Ann1](5) == C(5) + + - Annotated can be used as a generic type alias:: + + Optimized = Annotated[T, runtime.Optimize()] + Optimized[int] == Annotated[int, runtime.Optimize()] + + OptimizedList = Annotated[List[T], runtime.Optimize()] + OptimizedList[int] == Annotated[List[int], runtime.Optimize()] + """ + +# Python 3.8 has get_origin() and get_args() but those implementations aren't +# Annotated-aware, so we can't use those, only Python 3.9 versions will do. +if sys.version_info[:2] >= (3, 9): + get_origin = typing.get_origin + get_args = typing.get_args +elif PEP_560: + from typing import _GenericAlias # noqa + + def get_origin(tp): + """Get the unsubscripted version of a type. + + This supports generic types, Callable, Tuple, Union, Literal, Final, ClassVar + and Annotated. Return None for unsupported types. Examples:: + + get_origin(Literal[42]) is Literal + get_origin(int) is None + get_origin(ClassVar[int]) is ClassVar + get_origin(Generic) is Generic + get_origin(Generic[T]) is Generic + get_origin(Union[T, int]) is Union + get_origin(List[Tuple[T, T]][int]) == list + """ + if isinstance(tp, _AnnotatedAlias): + return Annotated + if isinstance(tp, _GenericAlias): + return tp.__origin__ + if tp is Generic: + return Generic + return None + + def get_args(tp): + """Get type arguments with all substitutions performed. + + For unions, basic simplifications used by Union constructor are performed. + Examples:: + get_args(Dict[str, int]) == (str, int) + get_args(int) == () + get_args(Union[int, Union[T, int], str][int]) == (int, str) + get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int]) + get_args(Callable[[], T][int]) == ([], int) + """ + if isinstance(tp, _AnnotatedAlias): + return (tp.__origin__,) + tp.__metadata__ + if isinstance(tp, _GenericAlias): + res = tp.__args__ + if get_origin(tp) is collections.abc.Callable and res[0] is not Ellipsis: + res = (list(res[:-1]), res[-1]) + return res + return () + + +if hasattr(typing, 'TypeAlias'): + TypeAlias = typing.TypeAlias +elif sys.version_info[:2] >= (3, 9): + class _TypeAliasForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + @_TypeAliasForm + def TypeAlias(self, parameters): + """Special marker indicating that an assignment should + be recognized as a proper type alias definition by type + checkers. + + For example:: + + Predicate: TypeAlias = Callable[..., bool] + + It's invalid when used anywhere except as in the example above. + """ + raise TypeError("{} is not subscriptable".format(self)) + +elif sys.version_info[:2] >= (3, 7): + class _TypeAliasForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + TypeAlias = _TypeAliasForm('TypeAlias', + doc="""Special marker indicating that an assignment should + be recognized as a proper type alias definition by type + checkers. + + For example:: + + Predicate: TypeAlias = Callable[..., bool] + + It's invalid when used anywhere except as in the example + above.""") + +elif hasattr(typing, '_FinalTypingBase'): + class _TypeAliasMeta(typing.TypingMeta): + """Metaclass for TypeAlias""" + + def __repr__(self): + return 'typing_extensions.TypeAlias' + + class _TypeAliasBase(typing._FinalTypingBase, metaclass=_TypeAliasMeta, _root=True): + """Special marker indicating that an assignment should + be recognized as a proper type alias definition by type + checkers. + + For example:: + + Predicate: TypeAlias = Callable[..., bool] + + It's invalid when used anywhere except as in the example above. + """ + __slots__ = () + + def __instancecheck__(self, obj): + raise TypeError("TypeAlias cannot be used with isinstance().") + + def __subclasscheck__(self, cls): + raise TypeError("TypeAlias cannot be used with issubclass().") + + def __repr__(self): + return 'typing_extensions.TypeAlias' + + TypeAlias = _TypeAliasBase(_root=True) +else: + class _TypeAliasMeta(typing.TypingMeta): + """Metaclass for TypeAlias""" + + def __instancecheck__(self, obj): + raise TypeError("TypeAlias cannot be used with isinstance().") + + def __subclasscheck__(self, cls): + raise TypeError("TypeAlias cannot be used with issubclass().") + + def __call__(self, *args, **kwargs): + raise TypeError("Cannot instantiate TypeAlias") + + class TypeAlias(metaclass=_TypeAliasMeta, _root=True): + """Special marker indicating that an assignment should + be recognized as a proper type alias definition by type + checkers. + + For example:: + + Predicate: TypeAlias = Callable[..., bool] + + It's invalid when used anywhere except as in the example above. + """ + __slots__ = () \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index 2ba22e5aad3c7..ad6bc2500a5aa 100644 --- a/setup.cfg +++ b/setup.cfg @@ -29,6 +29,7 @@ exclude = doc/build/*.py, doc/temp/*.py, .eggs/*.py, + pandas/_vendored/* versioneer.py, env # exclude asv benchmark environments from linting @@ -68,6 +69,7 @@ omit = */tests/* pandas/_typing.py pandas/_version.py + pandas/_vendored/typing_extensions.py plugins = Cython.Coverage [coverage:report] @@ -99,7 +101,7 @@ directory = coverage_html_report # To be kept consistent with "Import Formatting" section in contributing.rst [isort] -known_pre_libs = pandas._config +known_pre_libs = pandas._config,pandas._vendored known_pre_core = pandas._libs,pandas._typing,pandas.util._*,pandas.compat,pandas.errors known_dtypes = pandas.core.dtypes known_post_core = pandas.tseries,pandas.io,pandas.plotting @@ -113,7 +115,7 @@ combine_as_imports = True line_length = 88 force_sort_within_sections = True skip_glob = env, -skip = pandas/__init__.py +skip = pandas/__init__.py,pandas/_vendored/typing_extensions.py [mypy] ignore_missing_imports=True @@ -124,6 +126,10 @@ warn_redundant_casts = True warn_unused_ignores = True show_error_codes = True +[mypy-pandas._vendored.*] +check_untyped_defs=False +ignore_errors=True + [mypy-pandas.tests.*] check_untyped_defs=False From 831c33f78977ce5b444276a71522e86ac2329c11 Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 31 Aug 2020 17:43:59 -0700 Subject: [PATCH 06/12] black, isort --- pandas/_vendored/typing_extensions.py | 1101 ++++++++++++++++--------- 1 file changed, 694 insertions(+), 407 deletions(-) diff --git a/pandas/_vendored/typing_extensions.py b/pandas/_vendored/typing_extensions.py index f16154dfdb5d6..08f2c266c163e 100644 --- a/pandas/_vendored/typing_extensions.py +++ b/pandas/_vendored/typing_extensions.py @@ -7,18 +7,17 @@ typing_extensions is distributed under the Python Software Foundation License. """ +# These are used by Protocol implementation +# We use internal typing helpers here, but this significantly reduces +# code duplication. (Also this is only until Protocol is in typing.) import abc import collections +import collections.abc as collections_abc import contextlib +import operator import sys import typing -import collections.abc as collections_abc -import operator - -# These are used by Protocol implementation -# We use internal typing helpers here, but this significantly reduces -# code duplication. (Also this is only until Protocol is in typing.) -from typing import Generic, Callable, TypeVar, Tuple +from typing import Callable, Generic, Tuple, TypeVar # After PEP 560, internal typing API was substantially reworked. # This is especially important for Protocol class which uses internal APIs @@ -36,17 +35,22 @@ OLD_GENERICS = True try: from typing import _subs_tree # noqa + SUBS_TREE = True except ImportError: SUBS_TREE = False try: from typing import _tp_cache except ImportError: + def _tp_cache(x): return x + + try: from typing import _TypingEllipsis, _TypingEmpty except ImportError: + class _TypingEllipsis: pass @@ -60,8 +64,8 @@ class _TypingEmpty: def _no_slots_copy(dct): dict_copy = dict(dct) - if '__slots__' in dict_copy: - for slot in dict_copy['__slots__']: + if "__slots__" in dict_copy: + for slot in dict_copy["__slots__"]: dict_copy.pop(slot, None) return dict_copy @@ -72,11 +76,13 @@ def _check_generic(cls, parameters): 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)) + raise TypeError( + "Too %s parameters for %s; actual %s, expected %s" + % ("many" if alen > elen else "few", repr(cls), alen, elen) + ) -if hasattr(typing, '_generic_new'): +if hasattr(typing, "_generic_new"): _generic_new = typing._generic_new else: # Note: The '_generic_new(...)' function is used as a part of the @@ -95,9 +101,11 @@ def _check_generic(cls, parameters): def _generic_new(base_cls, cls, *args, **kwargs): return base_cls.__new__(cls, *args, **kwargs) + # See https://github.com/python/typing/pull/439 -if hasattr(typing, '_geqv'): +if hasattr(typing, "_geqv"): from typing import _geqv + _geqv_defined = True else: _geqv = None @@ -105,8 +113,10 @@ def _generic_new(base_cls, cls, *args, **kwargs): if sys.version_info[:2] >= (3, 6): import _collections_abc + _check_methods_in_mro = _collections_abc._check_methods else: + def _check_methods_in_mro(C, *methods): mro = C.__mro__ for method in methods: @@ -123,10 +133,9 @@ def _check_methods_in_mro(C, *methods): # Please keep __all__ alphabetized within each category. __all__ = [ # Super-special typing primitives. - 'ClassVar', - 'Final', - 'Type', - + "ClassVar", + "Final", + "Type", # ABCs (from collections.abc). # The following are added depending on presence # of their non-generic counterparts in stdlib: @@ -137,25 +146,22 @@ def _check_methods_in_mro(C, *methods): # 'AsyncGenerator', # 'AsyncContextManager', # 'ChainMap', - # Concrete collection types. - 'ContextManager', - 'Counter', - 'Deque', - 'DefaultDict', - 'TypedDict', - + "ContextManager", + "Counter", + "Deque", + "DefaultDict", + "TypedDict", # Structural checks, a.k.a. protocols. - 'SupportsIndex', - + "SupportsIndex", # One-off things. - 'final', - 'IntVar', - 'Literal', - 'NewType', - 'overload', - 'Text', - 'TYPE_CHECKING', + "final", + "IntVar", + "Literal", + "NewType", + "overload", + "Text", + "TYPE_CHECKING", ] # Annotated relies on substitution trees of pep 560. It will not work for @@ -172,13 +178,14 @@ def _check_methods_in_mro(C, *methods): HAVE_PROTOCOLS = sys.version_info[:3] != (3, 5, 0) if HAVE_PROTOCOLS: - __all__.extend(['Protocol', 'runtime', 'runtime_checkable']) + __all__.extend(["Protocol", "runtime", "runtime_checkable"]) # TODO -if hasattr(typing, 'NoReturn'): +if hasattr(typing, "NoReturn"): NoReturn = typing.NoReturn -elif hasattr(typing, '_FinalTypingBase'): +elif hasattr(typing, "_FinalTypingBase"): + class _NoReturn(typing._FinalTypingBase, _root=True): """Special type indicating functions that never return. Example:: @@ -191,6 +198,7 @@ def stop() -> NoReturn: This type is invalid in other positions, e.g., ``List[NoReturn]`` will fail in static type checkers. """ + __slots__ = () def __instancecheck__(self, obj): @@ -201,8 +209,10 @@ def __subclasscheck__(self, cls): NoReturn = _NoReturn(_root=True) else: + class _NoReturnMeta(typing.TypingMeta): """Metaclass for NoReturn""" + def __new__(cls, name, bases, namespace, _root=False): return super().__new__(cls, name, bases, namespace, _root=_root) @@ -224,23 +234,25 @@ def stop() -> NoReturn: This type is invalid in other positions, e.g., ``List[NoReturn]`` will fail in static type checkers. """ + __slots__ = () # Some unconstrained type variables. These are used by the container types. # (These are not for export.) -T = typing.TypeVar('T') # Any type. -KT = typing.TypeVar('KT') # Key type. -VT = typing.TypeVar('VT') # Value type. -T_co = typing.TypeVar('T_co', covariant=True) # Any type covariant containers. -V_co = typing.TypeVar('V_co', covariant=True) # Any type covariant containers. -VT_co = typing.TypeVar('VT_co', covariant=True) # Value type covariant containers. -T_contra = typing.TypeVar('T_contra', contravariant=True) # Ditto contravariant. +T = typing.TypeVar("T") # Any type. +KT = typing.TypeVar("KT") # Key type. +VT = typing.TypeVar("VT") # Value type. +T_co = typing.TypeVar("T_co", covariant=True) # Any type covariant containers. +V_co = typing.TypeVar("V_co", covariant=True) # Any type covariant containers. +VT_co = typing.TypeVar("VT_co", covariant=True) # Value type covariant containers. +T_contra = typing.TypeVar("T_contra", contravariant=True) # Ditto contravariant. -if hasattr(typing, 'ClassVar'): +if hasattr(typing, "ClassVar"): ClassVar = typing.ClassVar -elif hasattr(typing, '_FinalTypingBase'): +elif hasattr(typing, "_FinalTypingBase"): + class _ClassVar(typing._FinalTypingBase, _root=True): """Special type construct to mark class variables. @@ -258,7 +270,7 @@ class Starship: be used with isinstance() or issubclass(). """ - __slots__ = ('__type__',) + __slots__ = ("__type__",) def __init__(self, tp=None, **kwds): self.__type__ = tp @@ -266,11 +278,13 @@ def __init__(self, tp=None, **kwds): def __getitem__(self, item): cls = type(self) if self.__type__ is None: - return cls(typing._type_check(item, - '{} accepts only single type.'.format(cls.__name__[1:])), - _root=True) - raise TypeError('{} cannot be further subscripted' - .format(cls.__name__[1:])) + return cls( + typing._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 = typing._eval_type(self.__type__, globalns, localns) @@ -281,7 +295,7 @@ def _eval_type(self, globalns, localns): def __repr__(self): r = super().__repr__() if self.__type__ is not None: - r += '[{}]'.format(typing._type_repr(self.__type__)) + r += "[{}]".format(typing._type_repr(self.__type__)) return r def __hash__(self): @@ -296,6 +310,7 @@ def __eq__(self, other): ClassVar = _ClassVar(_root=True) else: + class _ClassVarMeta(typing.TypingMeta): """Metaclass for ClassVar""" @@ -314,27 +329,33 @@ def __subclasscheck__(self, cls): def __getitem__(self, item): cls = type(self) if self.__type__ is not None: - raise TypeError('{} cannot be further subscripted' - .format(cls.__name__[1:])) + raise TypeError( + "{} cannot be further subscripted".format(cls.__name__[1:]) + ) param = typing._type_check( - item, - '{} accepts only single type.'.format(cls.__name__[1:])) - return cls(self.__name__, self.__bases__, - dict(self.__dict__), tp=param, _root=True) + item, "{} accepts only single type.".format(cls.__name__[1:]) + ) + return cls( + self.__name__, self.__bases__, dict(self.__dict__), tp=param, _root=True + ) def _eval_type(self, globalns, localns): new_tp = typing._eval_type(self.__type__, globalns, localns) if new_tp == self.__type__: return self - return type(self)(self.__name__, self.__bases__, - dict(self.__dict__), tp=self.__type__, - _root=True) + return type(self)( + self.__name__, + self.__bases__, + dict(self.__dict__), + tp=self.__type__, + _root=True, + ) def __repr__(self): r = super().__repr__() if self.__type__ is not None: - r += '[{}]'.format(typing._type_repr(self.__type__)) + r += "[{}]".format(typing._type_repr(self.__type__)) return r def __hash__(self): @@ -366,22 +387,25 @@ class Starship: __type__ = None + # On older versions of typing there is an internal class named "Final". -if hasattr(typing, 'Final') and sys.version_info[:2] >= (3, 7): +if hasattr(typing, "Final") and sys.version_info[:2] >= (3, 7): Final = typing.Final elif sys.version_info[:2] >= (3, 7): - class _FinalForm(typing._SpecialForm, _root=True): + class _FinalForm(typing._SpecialForm, _root=True): def __repr__(self): - return 'typing_extensions.' + self._name + return "typing_extensions." + self._name def __getitem__(self, parameters): - item = typing._type_check(parameters, - '{} accepts only single type'.format(self._name)) + item = typing._type_check( + parameters, "{} accepts only single type".format(self._name) + ) return _GenericAlias(self, (item,)) - Final = _FinalForm('Final', - doc="""A special typing construct to indicate that a name + Final = _FinalForm( + "Final", + doc="""A special typing construct to indicate that a name cannot be re-assigned or overridden in a subclass. For example: @@ -393,8 +417,10 @@ class Connection: class FastConnector(Connection): TIMEOUT = 1 # Error reported by type checker - There is no runtime checking of these properties.""") -elif hasattr(typing, '_FinalTypingBase'): + There is no runtime checking of these properties.""", + ) +elif hasattr(typing, "_FinalTypingBase"): + class _Final(typing._FinalTypingBase, _root=True): """A special typing construct to indicate that a name cannot be re-assigned or overridden in a subclass. @@ -411,7 +437,7 @@ class FastConnector(Connection): There is no runtime checking of these properties. """ - __slots__ = ('__type__',) + __slots__ = ("__type__",) def __init__(self, tp=None, **kwds): self.__type__ = tp @@ -419,11 +445,13 @@ def __init__(self, tp=None, **kwds): def __getitem__(self, item): cls = type(self) if self.__type__ is None: - return cls(typing._type_check(item, - '{} accepts only single type.'.format(cls.__name__[1:])), - _root=True) - raise TypeError('{} cannot be further subscripted' - .format(cls.__name__[1:])) + return cls( + typing._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 = typing._eval_type(self.__type__, globalns, localns) @@ -434,7 +462,7 @@ def _eval_type(self, globalns, localns): def __repr__(self): r = super().__repr__() if self.__type__ is not None: - r += '[{}]'.format(typing._type_repr(self.__type__)) + r += "[{}]".format(typing._type_repr(self.__type__)) return r def __hash__(self): @@ -449,6 +477,7 @@ def __eq__(self, other): Final = _Final(_root=True) else: + class _FinalMeta(typing.TypingMeta): """Metaclass for Final""" @@ -467,27 +496,33 @@ def __subclasscheck__(self, cls): def __getitem__(self, item): cls = type(self) if self.__type__ is not None: - raise TypeError('{} cannot be further subscripted' - .format(cls.__name__[1:])) + raise TypeError( + "{} cannot be further subscripted".format(cls.__name__[1:]) + ) param = typing._type_check( - item, - '{} accepts only single type.'.format(cls.__name__[1:])) - return cls(self.__name__, self.__bases__, - dict(self.__dict__), tp=param, _root=True) + item, "{} accepts only single type.".format(cls.__name__[1:]) + ) + return cls( + self.__name__, self.__bases__, dict(self.__dict__), tp=param, _root=True + ) def _eval_type(self, globalns, localns): new_tp = typing._eval_type(self.__type__, globalns, localns) if new_tp == self.__type__: return self - return type(self)(self.__name__, self.__bases__, - dict(self.__dict__), tp=self.__type__, - _root=True) + return type(self)( + self.__name__, + self.__bases__, + dict(self.__dict__), + tp=self.__type__, + _root=True, + ) def __repr__(self): r = super().__repr__() if self.__type__ is not None: - r += '[{}]'.format(typing._type_repr(self.__type__)) + r += "[{}]".format(typing._type_repr(self.__type__)) return r def __hash__(self): @@ -519,9 +554,10 @@ class FastConnector(Connection): __type__ = None -if hasattr(typing, 'final'): +if hasattr(typing, "final"): final = typing.final else: + def final(f): """This decorator can be used to indicate to type checkers that the decorated method cannot be overridden, and decorated class @@ -549,19 +585,20 @@ def IntVar(name): return TypeVar(name) -if hasattr(typing, 'Literal'): +if hasattr(typing, "Literal"): Literal = typing.Literal elif sys.version_info[:2] >= (3, 7): - class _LiteralForm(typing._SpecialForm, _root=True): + class _LiteralForm(typing._SpecialForm, _root=True): def __repr__(self): - return 'typing_extensions.' + self._name + return "typing_extensions." + self._name def __getitem__(self, parameters): return _GenericAlias(self, parameters) - Literal = _LiteralForm('Literal', - doc="""A type that can be used to indicate to type checkers + Literal = _LiteralForm( + "Literal", + doc="""A type that can be used to indicate to type checkers that the corresponding value has a value literally equivalent to the provided parameter. For example: @@ -572,8 +609,10 @@ def __getitem__(self, parameters): Literal[...] cannot be subclassed. There is no runtime checking verifying that the parameter is actually a value - instead of a type.""") -elif hasattr(typing, '_FinalTypingBase'): + instead of a type.""", + ) +elif hasattr(typing, "_FinalTypingBase"): + class _Literal(typing._FinalTypingBase, _root=True): """A type that can be used to indicate to type checkers that the corresponding value has a value literally equivalent to the @@ -588,7 +627,7 @@ class _Literal(typing._FinalTypingBase, _root=True): verifying that the parameter is actually a value instead of a type. """ - __slots__ = ('__values__',) + __slots__ = ("__values__",) def __init__(self, values=None, **kwds): self.__values__ = values @@ -599,8 +638,7 @@ def __getitem__(self, values): if not isinstance(values, tuple): values = (values,) return cls(values, _root=True) - raise TypeError('{} cannot be further subscripted' - .format(cls.__name__[1:])) + raise TypeError("{} cannot be further subscripted".format(cls.__name__[1:])) def _eval_type(self, globalns, localns): return self @@ -608,7 +646,7 @@ def _eval_type(self, globalns, localns): def __repr__(self): r = super().__repr__() if self.__values__ is not None: - r += '[{}]'.format(', '.join(map(typing._type_repr, self.__values__))) + r += "[{}]".format(", ".join(map(typing._type_repr, self.__values__))) return r def __hash__(self): @@ -623,6 +661,7 @@ def __eq__(self, other): Literal = _Literal(_root=True) else: + class _LiteralMeta(typing.TypingMeta): """Metaclass for Literal""" @@ -641,13 +680,19 @@ def __subclasscheck__(self, cls): def __getitem__(self, item): cls = type(self) if self.__values__ is not None: - raise TypeError('{} cannot be further subscripted' - .format(cls.__name__[1:])) + raise TypeError( + "{} cannot be further subscripted".format(cls.__name__[1:]) + ) if not isinstance(item, tuple): item = (item,) - return cls(self.__name__, self.__bases__, - dict(self.__dict__), values=item, _root=True) + return cls( + self.__name__, + self.__bases__, + dict(self.__dict__), + values=item, + _root=True, + ) def _eval_type(self, globalns, localns): return self @@ -655,7 +700,7 @@ def _eval_type(self, globalns, localns): def __repr__(self): r = super().__repr__() if self.__values__ is not None: - r += '[{}]'.format(', '.join(map(typing._type_repr, self.__values__))) + r += "[{}]".format(", ".join(map(typing._type_repr, self.__values__))) return r def __hash__(self): @@ -691,7 +736,8 @@ def _overload_dummy(*args, **kwds): "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.") + "by an implementation that is not @overload-ed." + ) def overload(func): @@ -724,11 +770,11 @@ def utf8(value): # This is not a real generic class. Don't use outside annotations. -if hasattr(typing, 'Type'): +if hasattr(typing, "Type"): Type = typing.Type else: # Internal type variable used for Type[]. - CT_co = typing.TypeVar('CT_co', covariant=True, bound=type) + CT_co = typing.TypeVar("CT_co", covariant=True, bound=type) class Type(typing.Generic[CT_co], extra=type): """A special construct usable to annotate class objects. @@ -759,6 +805,7 @@ def new_user(user_class: Type[U]) -> U: # Various ABCs mimicking those in collections.abc. # A few are simply re-exported for completeness. + def _define_guard(type_name): """ Returns True if the given type isn't defined in typing but @@ -787,9 +834,11 @@ def __subclasscheck__(self, subclass): """ if sys.version_info[:3] >= (3, 5, 3) or sys.version_info[:3] < (3, 5, 0): 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") + 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 not self.__extra__: return super().__subclasscheck__(subclass) @@ -806,49 +855,73 @@ def __subclasscheck__(self, subclass): return False -if _define_guard('Awaitable'): - class Awaitable(typing.Generic[T_co], metaclass=_ExtensionsGenericMeta, - extra=collections_abc.Awaitable): +if _define_guard("Awaitable"): + + class Awaitable( + typing.Generic[T_co], + metaclass=_ExtensionsGenericMeta, + extra=collections_abc.Awaitable, + ): __slots__ = () -if _define_guard('Coroutine'): - class Coroutine(Awaitable[V_co], typing.Generic[T_co, T_contra, V_co], - metaclass=_ExtensionsGenericMeta, - extra=collections_abc.Coroutine): +if _define_guard("Coroutine"): + + class Coroutine( + Awaitable[V_co], + typing.Generic[T_co, T_contra, V_co], + metaclass=_ExtensionsGenericMeta, + extra=collections_abc.Coroutine, + ): __slots__ = () -if _define_guard('AsyncIterable'): - class AsyncIterable(typing.Generic[T_co], - metaclass=_ExtensionsGenericMeta, - extra=collections_abc.AsyncIterable): +if _define_guard("AsyncIterable"): + + class AsyncIterable( + typing.Generic[T_co], + metaclass=_ExtensionsGenericMeta, + extra=collections_abc.AsyncIterable, + ): __slots__ = () -if _define_guard('AsyncIterator'): - class AsyncIterator(AsyncIterable[T_co], - metaclass=_ExtensionsGenericMeta, - extra=collections_abc.AsyncIterator): +if _define_guard("AsyncIterator"): + + class AsyncIterator( + AsyncIterable[T_co], + metaclass=_ExtensionsGenericMeta, + extra=collections_abc.AsyncIterator, + ): __slots__ = () -if hasattr(typing, 'Deque'): +if hasattr(typing, "Deque"): Deque = typing.Deque elif _geqv_defined: - class Deque(collections.deque, typing.MutableSequence[T], - metaclass=_ExtensionsGenericMeta, - extra=collections.deque): + + class Deque( + collections.deque, + typing.MutableSequence[T], + metaclass=_ExtensionsGenericMeta, + extra=collections.deque, + ): __slots__ = () def __new__(cls, *args, **kwds): if _geqv(cls, Deque): return collections.deque(*args, **kwds) return _generic_new(collections.deque, cls, *args, **kwds) + + else: - class Deque(collections.deque, typing.MutableSequence[T], - metaclass=_ExtensionsGenericMeta, - extra=collections.deque): + + class Deque( + collections.deque, + typing.MutableSequence[T], + metaclass=_ExtensionsGenericMeta, + extra=collections.deque, + ): __slots__ = () def __new__(cls, *args, **kwds): @@ -857,14 +930,20 @@ def __new__(cls, *args, **kwds): return _generic_new(collections.deque, cls, *args, **kwds) -if hasattr(typing, 'ContextManager'): +if hasattr(typing, "ContextManager"): ContextManager = typing.ContextManager -elif hasattr(contextlib, 'AbstractContextManager'): - class ContextManager(typing.Generic[T_co], - metaclass=_ExtensionsGenericMeta, - extra=contextlib.AbstractContextManager): +elif hasattr(contextlib, "AbstractContextManager"): + + class ContextManager( + typing.Generic[T_co], + metaclass=_ExtensionsGenericMeta, + extra=contextlib.AbstractContextManager, + ): __slots__ = () + + else: + class ContextManager(typing.Generic[T_co]): __slots__ = () @@ -883,24 +962,29 @@ def __subclasshook__(cls, C): # (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__)): + 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(typing, 'AsyncContextManager'): +if hasattr(typing, "AsyncContextManager"): AsyncContextManager = typing.AsyncContextManager - __all__.append('AsyncContextManager') -elif hasattr(contextlib, 'AbstractAsyncContextManager'): - class AsyncContextManager(typing.Generic[T_co], - metaclass=_ExtensionsGenericMeta, - extra=contextlib.AbstractAsyncContextManager): + __all__.append("AsyncContextManager") +elif hasattr(contextlib, "AbstractAsyncContextManager"): + + class AsyncContextManager( + typing.Generic[T_co], + metaclass=_ExtensionsGenericMeta, + extra=contextlib.AbstractAsyncContextManager, + ): __slots__ = () - __all__.append('AsyncContextManager') + __all__.append("AsyncContextManager") elif sys.version_info[:2] >= (3, 5): - exec(""" + exec( + """ class AsyncContextManager(typing.Generic[T_co]): __slots__ = () @@ -918,15 +1002,20 @@ def __subclasshook__(cls, C): return NotImplemented __all__.append('AsyncContextManager') -""") +""" + ) -if hasattr(typing, 'DefaultDict'): +if hasattr(typing, "DefaultDict"): DefaultDict = typing.DefaultDict elif _geqv_defined: - class DefaultDict(collections.defaultdict, typing.MutableMapping[KT, VT], - metaclass=_ExtensionsGenericMeta, - extra=collections.defaultdict): + + class DefaultDict( + collections.defaultdict, + typing.MutableMapping[KT, VT], + metaclass=_ExtensionsGenericMeta, + extra=collections.defaultdict, + ): __slots__ = () @@ -934,10 +1023,16 @@ def __new__(cls, *args, **kwds): if _geqv(cls, DefaultDict): return collections.defaultdict(*args, **kwds) return _generic_new(collections.defaultdict, cls, *args, **kwds) + + else: - class DefaultDict(collections.defaultdict, typing.MutableMapping[KT, VT], - metaclass=_ExtensionsGenericMeta, - extra=collections.defaultdict): + + class DefaultDict( + collections.defaultdict, + typing.MutableMapping[KT, VT], + metaclass=_ExtensionsGenericMeta, + extra=collections.defaultdict, + ): __slots__ = () @@ -947,21 +1042,24 @@ def __new__(cls, *args, **kwds): return _generic_new(collections.defaultdict, cls, *args, **kwds) -if hasattr(typing, 'Counter'): +if hasattr(typing, "Counter"): Counter = typing.Counter elif (3, 5, 0) <= sys.version_info[:3] <= (3, 5, 1): assert _geqv_defined - _TInt = typing.TypeVar('_TInt') + _TInt = typing.TypeVar("_TInt") class _CounterMeta(typing.GenericMeta): """Metaclass for Counter""" + def __getitem__(self, item): return super().__getitem__((item, int)) - class Counter(collections.Counter, - typing.Dict[T, int], - metaclass=_CounterMeta, - extra=collections.Counter): + class Counter( + collections.Counter, + typing.Dict[T, int], + metaclass=_CounterMeta, + extra=collections.Counter, + ): __slots__ = () @@ -970,10 +1068,15 @@ def __new__(cls, *args, **kwds): return collections.Counter(*args, **kwds) return _generic_new(collections.Counter, cls, *args, **kwds) + elif _geqv_defined: - class Counter(collections.Counter, - typing.Dict[T, int], - metaclass=_ExtensionsGenericMeta, extra=collections.Counter): + + class Counter( + collections.Counter, + typing.Dict[T, int], + metaclass=_ExtensionsGenericMeta, + extra=collections.Counter, + ): __slots__ = () @@ -982,10 +1085,15 @@ def __new__(cls, *args, **kwds): return collections.Counter(*args, **kwds) return _generic_new(collections.Counter, cls, *args, **kwds) + else: - class Counter(collections.Counter, - typing.Dict[T, int], - metaclass=_ExtensionsGenericMeta, extra=collections.Counter): + + class Counter( + collections.Counter, + typing.Dict[T, int], + metaclass=_ExtensionsGenericMeta, + extra=collections.Counter, + ): __slots__ = () @@ -995,15 +1103,19 @@ def __new__(cls, *args, **kwds): return _generic_new(collections.Counter, cls, *args, **kwds) -if hasattr(typing, 'ChainMap'): +if hasattr(typing, "ChainMap"): ChainMap = typing.ChainMap - __all__.append('ChainMap') -elif hasattr(collections, 'ChainMap'): + __all__.append("ChainMap") +elif hasattr(collections, "ChainMap"): # ChainMap only exists in 3.3+ if _geqv_defined: - class ChainMap(collections.ChainMap, typing.MutableMapping[KT, VT], - metaclass=_ExtensionsGenericMeta, - extra=collections.ChainMap): + + class ChainMap( + collections.ChainMap, + typing.MutableMapping[KT, VT], + metaclass=_ExtensionsGenericMeta, + extra=collections.ChainMap, + ): __slots__ = () @@ -1011,10 +1123,15 @@ def __new__(cls, *args, **kwds): if _geqv(cls, ChainMap): return collections.ChainMap(*args, **kwds) return _generic_new(collections.ChainMap, cls, *args, **kwds) + else: - class ChainMap(collections.ChainMap, typing.MutableMapping[KT, VT], - metaclass=_ExtensionsGenericMeta, - extra=collections.ChainMap): + + class ChainMap( + collections.ChainMap, + typing.MutableMapping[KT, VT], + metaclass=_ExtensionsGenericMeta, + extra=collections.ChainMap, + ): __slots__ = () @@ -1023,19 +1140,24 @@ def __new__(cls, *args, **kwds): return collections.ChainMap(*args, **kwds) return _generic_new(collections.ChainMap, cls, *args, **kwds) - __all__.append('ChainMap') + __all__.append("ChainMap") -if _define_guard('AsyncGenerator'): - class AsyncGenerator(AsyncIterator[T_co], typing.Generic[T_co, T_contra], - metaclass=_ExtensionsGenericMeta, - extra=collections_abc.AsyncGenerator): +if _define_guard("AsyncGenerator"): + + class AsyncGenerator( + AsyncIterator[T_co], + typing.Generic[T_co, T_contra], + metaclass=_ExtensionsGenericMeta, + extra=collections_abc.AsyncGenerator, + ): __slots__ = () -if hasattr(typing, 'NewType'): +if hasattr(typing, "NewType"): NewType = typing.NewType else: + def NewType(name, tp): """NewType creates simple unique types with almost zero runtime overhead. NewType(name, tp) is considered a subtype of tp @@ -1063,13 +1185,13 @@ def new_type(x): return new_type -if hasattr(typing, 'Text'): +if hasattr(typing, "Text"): Text = typing.Text else: Text = str -if hasattr(typing, 'TYPE_CHECKING'): +if hasattr(typing, "TYPE_CHECKING"): TYPE_CHECKING = typing.TYPE_CHECKING else: # Constant that's True when type checking, but False here. @@ -1079,7 +1201,7 @@ def new_type(x): def _gorg(cls): """This function exists for compatibility with old typing versions.""" assert isinstance(cls, GenericMeta) - if hasattr(cls, '_gorg'): + if hasattr(cls, "_gorg"): return cls._gorg while cls.__origin__ is not None: cls = cls.__origin__ @@ -1087,6 +1209,7 @@ def _gorg(cls): if OLD_GENERICS: + def _next_in_mro(cls): # noqa """This function exists for compatibility with old typing versions.""" next_in_mro = object @@ -1096,27 +1219,53 @@ def _next_in_mro(cls): # noqa return next_in_mro -_PROTO_WHITELIST = ['Callable', 'Awaitable', - 'Iterable', 'Iterator', 'AsyncIterable', 'AsyncIterator', - 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', - 'ContextManager', 'AsyncContextManager'] +_PROTO_WHITELIST = [ + "Callable", + "Awaitable", + "Iterable", + "Iterator", + "AsyncIterable", + "AsyncIterator", + "Hashable", + "Sized", + "Container", + "Collection", + "Reversible", + "ContextManager", + "AsyncContextManager", +] def _get_protocol_attrs(cls): attrs = set() for base in cls.__mro__[:-1]: # without object - if base.__name__ in ('Protocol', 'Generic'): + if base.__name__ in ("Protocol", "Generic"): continue - annotations = getattr(base, '__annotations__', {}) + annotations = getattr(base, "__annotations__", {}) for attr in list(base.__dict__.keys()) + list(annotations.keys()): - if (not attr.startswith('_abc_') and attr not in ( - '__abstractmethods__', '__annotations__', '__weakref__', - '_is_protocol', '_is_runtime_protocol', '__dict__', - '__args__', '__slots__', - '__next_in_mro__', '__parameters__', '__origin__', - '__orig_bases__', '__extra__', '__tree_hash__', - '__doc__', '__subclasshook__', '__init__', '__new__', - '__module__', '_MutableMapping__marker', '_gorg')): + if not attr.startswith("_abc_") and attr not in ( + "__abstractmethods__", + "__annotations__", + "__weakref__", + "_is_protocol", + "_is_runtime_protocol", + "__dict__", + "__args__", + "__slots__", + "__next_in_mro__", + "__parameters__", + "__origin__", + "__orig_bases__", + "__extra__", + "__tree_hash__", + "__doc__", + "__subclasshook__", + "__init__", + "__new__", + "__module__", + "_MutableMapping__marker", + "_gorg", + ): attrs.add(attr) return attrs @@ -1125,18 +1274,30 @@ def _is_callable_members_only(cls): return all(callable(getattr(cls, attr, None)) for attr in _get_protocol_attrs(cls)) -if hasattr(typing, 'Protocol'): +if hasattr(typing, "Protocol"): Protocol = typing.Protocol elif HAVE_PROTOCOLS and not PEP_560: + class _ProtocolMeta(GenericMeta): """Internal metaclass for Protocol. This exists so Protocol classes can be generic without deriving from Generic. """ + if not OLD_GENERICS: - def __new__(cls, name, bases, namespace, - tvars=None, args=None, origin=None, extra=None, orig_bases=None): + + def __new__( + cls, + name, + bases, + namespace, + tvars=None, + args=None, + origin=None, + extra=None, + orig_bases=None, + ): # This is just a version copied from GenericMeta.__new__ that # includes "Protocol" special treatment. (Comments removed for brevity.) assert extra is None # Protocols should not have extra @@ -1149,12 +1310,15 @@ def __new__(cls, name, bases, namespace, 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 isinstance(base, GenericMeta) and base.__origin__ in ( + Generic, + Protocol, + ): if gvars is not None: raise TypeError( "Cannot inherit from Generic[...] or" - " Protocol[...] multiple times.") + " Protocol[...] multiple times." + ) gvars = base.__parameters__ if gvars is None: gvars = tvars @@ -1164,129 +1328,176 @@ def __new__(cls, name, bases, namespace, 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))) + "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 not None and type(extra) is abc.ABCMeta and - extra not in bases): + if ( + extra is not None + and type(extra) is abc.ABCMeta + and extra not in bases + ): bases = (extra,) + bases - bases = tuple(_gorg(b) if isinstance(b, GenericMeta) else b - for b in bases) + bases = tuple( + _gorg(b) if isinstance(b, GenericMeta) else b for b in 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, - _root=True) - super(GenericMeta, self).__setattr__('_gorg', - self if not origin else - _gorg(origin)) + namespace.update({"__origin__": origin, "__extra__": extra}) + self = super(GenericMeta, cls).__new__( + cls, name, bases, namespace, _root=True + ) + super(GenericMeta, self).__setattr__( + "_gorg", self if not origin else _gorg(origin) + ) self.__parameters__ = tvars - self.__args__ = tuple(... if a is _TypingEllipsis else - () if a is _TypingEmpty else - a for a in args) if args else None + self.__args__ = ( + tuple( + ... if a is _TypingEllipsis else () if a is _TypingEmpty else a + for a in args + ) + if args + else None + ) self.__next_in_mro__ = _next_in_mro(self) if orig_bases is None: self.__orig_bases__ = initial_bases elif origin is not None: self._abc_registry = origin._abc_registry self._abc_cache = origin._abc_cache - if hasattr(self, '_subs_tree'): - self.__tree_hash__ = (hash(self._subs_tree()) if origin else - super(GenericMeta, self).__hash__()) + if hasattr(self, "_subs_tree"): + self.__tree_hash__ = ( + hash(self._subs_tree()) + if origin + else super(GenericMeta, self).__hash__() + ) return self def __init__(cls, *args, **kwargs): super().__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 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__ == 'collections.abc' 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) + if not ( + base in (object, Generic) + or base.__module__ == "collections.abc" + 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 + ) def _no_init(self, *args, **kwargs): if type(self)._is_protocol: - raise TypeError('Protocols cannot be instantiated') + raise TypeError("Protocols cannot be instantiated") + cls.__init__ = _no_init def _proto_hook(other): - if not cls.__dict__.get('_is_protocol', None): + if not cls.__dict__.get("_is_protocol", None): return NotImplemented if not isinstance(other, type): # Same error as for issubclass(1, int) - raise TypeError('issubclass() arg 1 must be a class') + raise TypeError("issubclass() arg 1 must be a class") for attr in _get_protocol_attrs(cls): for base in other.__mro__: if attr in base.__dict__: if base.__dict__[attr] is None: return NotImplemented break - annotations = getattr(base, '__annotations__', {}) - if (isinstance(annotations, typing.Mapping) and - attr in annotations and - isinstance(other, _ProtocolMeta) and - other._is_protocol): + annotations = getattr(base, "__annotations__", {}) + if ( + isinstance(annotations, typing.Mapping) + and attr in annotations + and isinstance(other, _ProtocolMeta) + and other._is_protocol + ): break else: return NotImplemented return True - if '__subclasshook__' not in cls.__dict__: + + if "__subclasshook__" not in cls.__dict__: cls.__subclasshook__ = _proto_hook def __instancecheck__(self, instance): # We need this method for situations where attributes are # assigned in __init__. - if ((not getattr(self, '_is_protocol', False) or - _is_callable_members_only(self)) and - issubclass(instance.__class__, self)): + if ( + not getattr(self, "_is_protocol", False) + or _is_callable_members_only(self) + ) and issubclass(instance.__class__, self): return True if self._is_protocol: - if all(hasattr(instance, attr) and - (not callable(getattr(self, attr, None)) or - getattr(instance, attr) is not None) - for attr in _get_protocol_attrs(self)): + if all( + hasattr(instance, attr) + and ( + not callable(getattr(self, attr, None)) + or getattr(instance, attr) is not None + ) + for attr in _get_protocol_attrs(self) + ): return True return super(GenericMeta, self).__instancecheck__(instance) 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") + 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.__dict__.get('_is_protocol', None) and - not self.__dict__.get('_is_runtime_protocol', None)): - if sys._getframe(1).f_globals['__name__'] in ['abc', - 'functools', - 'typing']: + 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", + "typing", + ]: return False - raise TypeError("Instance and class checks can only be used with" - " @runtime protocols") - if (self.__dict__.get('_is_runtime_protocol', None) and - not _is_callable_members_only(self)): - if sys._getframe(1).f_globals['__name__'] in ['abc', - 'functools', - 'typing']: + raise TypeError( + "Instance and class checks can only be used with" + " @runtime protocols" + ) + if self.__dict__.get( + "_is_runtime_protocol", None + ) and not _is_callable_members_only(self): + if sys._getframe(1).f_globals["__name__"] in [ + "abc", + "functools", + "typing", + ]: return super(GenericMeta, self).__subclasscheck__(cls) - raise TypeError("Protocols with non-method members" - " don't support issubclass()") + raise TypeError( + "Protocols with non-method members" " don't support issubclass()" + ) return super(GenericMeta, self).__subclasscheck__(cls) if not OLD_GENERICS: + @_tp_cache def __getitem__(self, params): # We also need to copy this from GenericMeta.__getitem__ to get @@ -1295,38 +1506,44 @@ def __getitem__(self, params): params = (params,) if not params and _gorg(self) is not Tuple: raise TypeError( - "Parameter list to %s[...] cannot be empty" % self.__qualname__) + "Parameter list to %s[...] cannot be empty" % self.__qualname__ + ) msg = "Parameters to generic types must be types." params = tuple(_type_check(p, msg) for p in params) if self in (Generic, Protocol): if not all(isinstance(p, TypeVar) for p in params): raise TypeError( - "Parameters to %r[...] must all be type variables" % self) + "Parameters to %r[...] must all be type variables" % self + ) if len(set(params)) != len(params): raise TypeError( - "Parameters to %r[...] must all be unique" % self) + "Parameters to %r[...] must all be unique" % self + ) tvars = params args = params elif self in (Tuple, Callable): tvars = _type_vars(params) args = params elif self.__origin__ in (Generic, Protocol): - raise TypeError("Cannot subscript already-subscripted %s" % - repr(self)) + raise TypeError( + "Cannot subscript already-subscripted %s" % repr(self) + ) else: _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__) + 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__, + ) class Protocol(metaclass=_ProtocolMeta): """Base class for protocol classes. Protocol classes are defined as:: @@ -1357,19 +1574,24 @@ class GenProto({bases}): def meth(self) -> T: ... """ + __slots__ = () _is_protocol = True def __new__(cls, *args, **kwds): if _gorg(cls) is Protocol: - raise TypeError("Type Protocol cannot be instantiated; " - "it can be used only as a base class") + raise TypeError( + "Type Protocol cannot be instantiated; " + "it can be used only as a base class" + ) if OLD_GENERICS: return _generic_new(_next_in_mro(cls), cls, *args, **kwds) return _generic_new(cls.__next_in_mro__, cls, *args, **kwds) + if Protocol.__doc__ is not None: - Protocol.__doc__ = Protocol.__doc__.format(bases="Protocol, Generic[T]" if - OLD_GENERICS else "Protocol[T]") + Protocol.__doc__ = Protocol.__doc__.format( + bases="Protocol, Generic[T]" if OLD_GENERICS else "Protocol[T]" + ) elif PEP_560: @@ -1381,15 +1603,20 @@ class _ProtocolMeta(abc.ABCMeta): def __instancecheck__(cls, instance): # We need this method for situations where attributes are # assigned in __init__. - if ((not getattr(cls, '_is_protocol', False) or - _is_callable_members_only(cls)) and - issubclass(instance.__class__, cls)): + if ( + not getattr(cls, "_is_protocol", False) + or _is_callable_members_only(cls) + ) and issubclass(instance.__class__, cls): return True if cls._is_protocol: - if all(hasattr(instance, attr) and - (not callable(getattr(cls, attr, None)) or - getattr(instance, attr) is not None) - for attr in _get_protocol_attrs(cls)): + if all( + hasattr(instance, attr) + and ( + not callable(getattr(cls, attr, None)) + or getattr(instance, attr) is not None + ) + for attr in _get_protocol_attrs(cls) + ): return True return super().__instancecheck__(instance) @@ -1430,8 +1657,10 @@ def meth(self) -> T: def __new__(cls, *args, **kwds): if cls is Protocol: - raise TypeError("Type Protocol cannot be instantiated; " - "it can only be used as a base class") + raise TypeError( + "Type Protocol cannot be instantiated; " + "it can only be used as a base class" + ) return super().__new__(cls) @_tp_cache @@ -1440,7 +1669,8 @@ def __class_getitem__(cls, params): params = (params,) if not params and cls is not Tuple: raise TypeError( - "Parameter list to {}[...] cannot be empty".format(cls.__qualname__)) + "Parameter list to {}[...] cannot be empty".format(cls.__qualname__) + ) msg = "Parameters to generic types must be types." params = tuple(_type_check(p, msg) for p in params) if cls is Protocol: @@ -1451,10 +1681,10 @@ def __class_getitem__(cls, params): i += 1 raise TypeError( "Parameters to Protocol[...] must all be type variables." - " Parameter {} is {}".format(i + 1, params[i])) + " Parameter {} is {}".format(i + 1, params[i]) + ) if len(set(params)) != len(params): - raise TypeError( - "Parameters to Protocol[...] must all be unique") + raise TypeError("Parameters to Protocol[...] must all be unique") else: # Subscripting a regular Generic subclass. _check_generic(cls, params) @@ -1462,13 +1692,13 @@ def __class_getitem__(cls, params): def __init_subclass__(cls, *args, **kwargs): tvars = [] - if '__orig_bases__' in cls.__dict__: + if "__orig_bases__" in cls.__dict__: error = Generic in cls.__orig_bases__ else: error = Generic in cls.__bases__ if error: raise TypeError("Cannot inherit from plain Generic") - if '__orig_bases__' in cls.__dict__: + if "__orig_bases__" in cls.__dict__: tvars = _collect_type_vars(cls.__orig_bases__) # Look for Generic[T1, ..., Tn] or Protocol[T1, ..., Tn]. # If found, tvars must be a subset of it. @@ -1477,14 +1707,19 @@ def __init_subclass__(cls, *args, **kwargs): # and reject multiple Generic[...] and/or Protocol[...]. gvars = None for base in cls.__orig_bases__: - if (isinstance(base, _GenericAlias) and - base.__origin__ in (Generic, Protocol)): + if isinstance(base, _GenericAlias) and base.__origin__ in ( + Generic, + Protocol, + ): # for error messages - the_base = 'Generic' if base.__origin__ is Generic else 'Protocol' + the_base = ( + "Generic" if base.__origin__ is Generic else "Protocol" + ) if gvars is not None: raise TypeError( "Cannot inherit from Generic[...]" - " and/or Protocol[...] multiple types.") + " and/or Protocol[...] multiple types." + ) gvars = base.__parameters__ if gvars is None: gvars = tvars @@ -1492,51 +1727,59 @@ def __init_subclass__(cls, *args, **kwargs): tvarset = set(tvars) gvarset = set(gvars) if not tvarset <= gvarset: - s_vars = ', '.join(str(t) for t in tvars if t not in gvarset) - s_args = ', '.join(str(g) for g in gvars) - raise TypeError("Some type variables ({}) are" - " not listed in {}[{}]".format(s_vars, - the_base, s_args)) + s_vars = ", ".join(str(t) for t in tvars if t not in gvarset) + s_args = ", ".join(str(g) for g in gvars) + raise TypeError( + "Some type variables ({}) are" + " not listed in {}[{}]".format(s_vars, the_base, s_args) + ) tvars = gvars cls.__parameters__ = tuple(tvars) # Determine if this is a protocol or a concrete subclass. - if not cls.__dict__.get('_is_protocol', None): + if not cls.__dict__.get("_is_protocol", None): cls._is_protocol = any(b is Protocol for b in cls.__bases__) # Set (or override) the protocol subclass hook. def _proto_hook(other): - if not cls.__dict__.get('_is_protocol', None): + if not cls.__dict__.get("_is_protocol", None): return NotImplemented - if not getattr(cls, '_is_runtime_protocol', False): - if sys._getframe(2).f_globals['__name__'] in ['abc', 'functools']: + if not getattr(cls, "_is_runtime_protocol", False): + if sys._getframe(2).f_globals["__name__"] in ["abc", "functools"]: return NotImplemented - raise TypeError("Instance and class checks can only be used with" - " @runtime protocols") + raise TypeError( + "Instance and class checks can only be used with" + " @runtime protocols" + ) if not _is_callable_members_only(cls): - if sys._getframe(2).f_globals['__name__'] in ['abc', 'functools']: + if sys._getframe(2).f_globals["__name__"] in ["abc", "functools"]: return NotImplemented - raise TypeError("Protocols with non-method members" - " don't support issubclass()") + raise TypeError( + "Protocols with non-method members" + " don't support issubclass()" + ) if not isinstance(other, type): # Same error as for issubclass(1, int) - raise TypeError('issubclass() arg 1 must be a class') + raise TypeError("issubclass() arg 1 must be a class") for attr in _get_protocol_attrs(cls): for base in other.__mro__: if attr in base.__dict__: if base.__dict__[attr] is None: return NotImplemented break - annotations = getattr(base, '__annotations__', {}) - if (isinstance(annotations, typing.Mapping) and - attr in annotations and - isinstance(other, _ProtocolMeta) and - other._is_protocol): + annotations = getattr(base, "__annotations__", {}) + if ( + isinstance(annotations, typing.Mapping) + and attr in annotations + and isinstance(other, _ProtocolMeta) + and other._is_protocol + ): break else: return NotImplemented return True - if '__subclasshook__' not in cls.__dict__: + + if "__subclasshook__" not in cls.__dict__: cls.__subclasshook__ = _proto_hook # We have nothing more to do for non-protocols. @@ -1545,22 +1788,29 @@ def _proto_hook(other): # Check consistency of bases. for base in cls.__bases__: - if not (base in (object, Generic) or - base.__module__ == 'collections.abc' and - base.__name__ in _PROTO_WHITELIST or - isinstance(base, _ProtocolMeta) and base._is_protocol): - raise TypeError('Protocols can only inherit from other' - ' protocols, got %r' % base) + if not ( + base in (object, Generic) + or base.__module__ == "collections.abc" + and base.__name__ in _PROTO_WHITELIST + or isinstance(base, _ProtocolMeta) + and base._is_protocol + ): + raise TypeError( + "Protocols can only inherit from other" + " protocols, got %r" % base + ) def _no_init(self, *args, **kwargs): if type(self)._is_protocol: - raise TypeError('Protocols cannot be instantiated') + raise TypeError("Protocols cannot be instantiated") + cls.__init__ = _no_init -if hasattr(typing, 'runtime_checkable'): +if hasattr(typing, "runtime_checkable"): runtime_checkable = typing.runtime_checkable elif HAVE_PROTOCOLS: + def runtime_checkable(cls): """Mark a protocol class as a runtime protocol, so that it can be used with isinstance() and issubclass(). Raise TypeError @@ -1570,8 +1820,10 @@ def runtime_checkable(cls): 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) + raise TypeError( + "@runtime_checkable can be only applied to protocol classes," + " got %r" % cls + ) cls._is_runtime_protocol = True return cls @@ -1581,9 +1833,10 @@ def runtime_checkable(cls): runtime = runtime_checkable -if hasattr(typing, 'SupportsIndex'): +if hasattr(typing, "SupportsIndex"): SupportsIndex = typing.SupportsIndex elif HAVE_PROTOCOLS: + @runtime_checkable class SupportsIndex(Protocol): __slots__ = () @@ -1598,71 +1851,91 @@ def __index__(self) -> int: # about which (if any) keys are optional. See https://bugs.python.org/issue38834 TypedDict = typing.TypedDict else: + def _check_fails(cls, other): try: - if sys._getframe(1).f_globals['__name__'] not in ['abc', - 'functools', - 'typing']: + 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') + raise TypeError("TypedDict does not support instance and class checks") except (AttributeError, ValueError): pass return False def _dict_new(*args, **kwargs): if not args: - raise TypeError('TypedDict.__new__(): not enough arguments') + raise TypeError("TypedDict.__new__(): not enough arguments") _, args = args[0], args[1:] # allow the "cls" keyword be passed return dict(*args, **kwargs) - _dict_new.__text_signature__ = '($cls, _typename, _fields=None, /, **kwargs)' + _dict_new.__text_signature__ = "($cls, _typename, _fields=None, /, **kwargs)" def _typeddict_new(*args, total=True, **kwargs): if not args: - raise TypeError('TypedDict.__new__(): not enough arguments') + raise TypeError("TypedDict.__new__(): not enough arguments") _, args = args[0], args[1:] # allow the "cls" keyword be passed if args: - typename, args = args[0], args[1:] # allow the "_typename" keyword be passed - elif '_typename' in kwargs: - typename = kwargs.pop('_typename') + 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) + + warnings.warn( + "Passing '_typename' as keyword argument is deprecated", + DeprecationWarning, + stacklevel=2, + ) else: - raise TypeError("TypedDict.__new__() missing 1 required positional " - "argument: '_typename'") + raise TypeError( + "TypedDict.__new__() missing 1 required positional " + "argument: '_typename'" + ) if args: try: - fields, = args # allow the "_fields" keyword be passed + (fields,) = args # allow the "_fields" keyword be passed except ValueError: - raise TypeError('TypedDict.__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') + raise TypeError( + "TypedDict.__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) + + warnings.warn( + "Passing '_fields' as keyword argument is deprecated", + DeprecationWarning, + stacklevel=2, + ) else: fields = None if fields is None: fields = kwargs elif kwargs: - raise TypeError("TypedDict takes either a dict or keyword arguments," - " but not both") + raise TypeError( + "TypedDict takes either a dict or keyword arguments," " but not both" + ) - ns = {'__annotations__': dict(fields), '__total__': total} + 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__') + ns["__module__"] = sys._getframe(1).f_globals.get("__name__", "__main__") except (AttributeError, ValueError): pass return _TypedDictMeta(typename, (), ns) - _typeddict_new.__text_signature__ = ('($cls, _typename, _fields=None,' - ' /, *, total=True, **kwargs)') + _typeddict_new.__text_signature__ = ( + "($cls, _typename, _fields=None," " /, *, total=True, **kwargs)" + ) class _TypedDictMeta(type): def __new__(cls, name, bases, ns, total=True): @@ -1672,11 +1945,11 @@ def __new__(cls, name, bases, ns, total=True): # TypedDict supports all three syntaxes described in its docstring. # Subclasses and instances of TypedDict return actual dictionaries # via _dict_new. - ns['__new__'] = _typeddict_new if name == 'TypedDict' else _dict_new + ns["__new__"] = _typeddict_new if name == "TypedDict" else _dict_new tp_dict = super(_TypedDictMeta, cls).__new__(cls, name, (dict,), ns) annotations = {} - own_annotations = ns.get('__annotations__', {}) + own_annotations = ns.get("__annotations__", {}) own_annotation_keys = set(own_annotations.keys()) msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type" own_annotations = { @@ -1686,9 +1959,9 @@ def __new__(cls, name, bases, ns, total=True): optional_keys = set() for base in bases: - annotations.update(base.__dict__.get('__annotations__', {})) - required_keys.update(base.__dict__.get('__required_keys__', ())) - optional_keys.update(base.__dict__.get('__optional_keys__', ())) + annotations.update(base.__dict__.get("__annotations__", {})) + required_keys.update(base.__dict__.get("__required_keys__", ())) + optional_keys.update(base.__dict__.get("__optional_keys__", ())) annotations.update(own_annotations) if total: @@ -1699,16 +1972,15 @@ def __new__(cls, name, bases, ns, total=True): tp_dict.__annotations__ = annotations tp_dict.__required_keys__ = frozenset(required_keys) tp_dict.__optional_keys__ = frozenset(optional_keys) - if not hasattr(tp_dict, '__total__'): + if not hasattr(tp_dict, "__total__"): tp_dict.__total__ = total return tp_dict __instancecheck__ = __subclasscheck__ = _check_fails - TypedDict = _TypedDictMeta('TypedDict', (dict,), {}) + TypedDict = _TypedDictMeta("TypedDict", (dict,), {}) TypedDict.__module__ = __name__ - TypedDict.__doc__ = \ - """A simple typed name space. At runtime it is equivalent to a plain dict. + 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 @@ -1739,13 +2011,14 @@ class Point2D(TypedDict): # Python 3.9+ has PEP 593 (Annotated and modified get_type_hints) -if hasattr(typing, 'Annotated'): +if hasattr(typing, "Annotated"): Annotated = typing.Annotated get_type_hints = typing.get_type_hints # Not exported and not a public API, but needed for get_origin() and get_args() # to work. _AnnotatedAlias = typing._AnnotatedAlias elif PEP_560: + class _AnnotatedAlias(typing._GenericAlias, _root=True): """Runtime representation of an annotated type. @@ -1754,6 +2027,7 @@ class _AnnotatedAlias(typing._GenericAlias, _root=True): instantiating is the same as instantiating the underlying type, binding it to types is also the same. """ + def __init__(self, origin, metadata): if isinstance(origin, _AnnotatedAlias): metadata = origin.__metadata__ + metadata @@ -1769,13 +2043,11 @@ def copy_with(self, params): def __repr__(self): return "typing_extensions.Annotated[{}, {}]".format( typing._type_repr(self.__origin__), - ", ".join(repr(a) for a in self.__metadata__) + ", ".join(repr(a) for a in self.__metadata__), ) def __reduce__(self): - return operator.getitem, ( - Annotated, (self.__origin__,) + self.__metadata__ - ) + return operator.getitem, (Annotated, (self.__origin__,) + self.__metadata__) def __eq__(self, other): if not isinstance(other, _AnnotatedAlias): @@ -1828,18 +2100,18 @@ def __new__(cls, *args, **kwargs): @_tp_cache def __class_getitem__(cls, params): if not isinstance(params, tuple) or len(params) < 2: - raise TypeError("Annotated[...] should be used " - "with at least two arguments (a type and an " - "annotation).") + raise TypeError( + "Annotated[...] should be used " + "with at least two arguments (a type and an " + "annotation)." + ) msg = "Annotated[t, ...]: t must be a type." origin = typing._type_check(params[0], msg) metadata = tuple(params[1:]) return _AnnotatedAlias(origin, metadata) def __init_subclass__(cls, *args, **kwargs): - raise TypeError( - "Cannot subclass {}.Annotated".format(cls.__module__) - ) + raise TypeError("Cannot subclass {}.Annotated".format(cls.__module__)) def _strip_annotations(t): """Strips the annotations from a given type. @@ -1891,11 +2163,12 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False): return hint return {k: _strip_annotations(t) for k, t in hint.items()} + elif HAVE_ANNOTATED: def _is_dunder(name): """Returns True if name is a __dunder_variable_name__.""" - return len(name) > 4 and name.startswith('__') and name.endswith('__') + return len(name) > 4 and name.startswith("__") and name.endswith("__") # Prior to Python 3.7 types did not have `copy_with`. A lot of the equality # checks, argument expansion etc. are done on the _subs_tre. As a result we @@ -1920,7 +2193,7 @@ def _tree_repr(self, tree): else: tp_repr = origin[0]._tree_repr(origin) metadata_reprs = ", ".join(repr(arg) for arg in metadata) - return '%s[%s, %s]' % (cls, tp_repr, metadata_reprs) + return "%s[%s, %s]" % (cls, tp_repr, metadata_reprs) def _subs_tree(self, tvars=None, args=None): # noqa if self is Annotated: @@ -1936,8 +2209,10 @@ def _subs_tree(self, tvars=None, args=None): # noqa def _get_cons(self): """Return the class used to create instance of this type.""" if self.__origin__ is None: - raise TypeError("Cannot get the underlying type of a " - "non-specialized Annotated type.") + raise TypeError( + "Cannot get the underlying type of a " + "non-specialized Annotated type." + ) tree = self._subs_tree() while isinstance(tree, tuple) and tree[0] is Annotated: tree = tree[1] @@ -1953,9 +2228,11 @@ def __getitem__(self, params): if self.__origin__ is not None: # specializing an instantiated type return super().__getitem__(params) elif not isinstance(params, tuple) or len(params) < 2: - raise TypeError("Annotated[...] should be instantiated " - "with at least two arguments (a type and an " - "annotation).") + raise TypeError( + "Annotated[...] should be instantiated " + "with at least two arguments (a type and an " + "annotation)." + ) else: msg = "Annotated[t, ...]: t must be a type." tp = typing._type_check(params[0], msg) @@ -1986,7 +2263,7 @@ def __getattr__(self, attr): raise AttributeError(attr) def __setattr__(self, attr, value): - if _is_dunder(attr) or attr.startswith('_abc_'): + if _is_dunder(attr) or attr.startswith("_abc_"): super().__setattr__(attr, value) elif self.__origin__ is None: raise AttributeError(attr) @@ -2031,6 +2308,7 @@ class Annotated(metaclass=AnnotatedMeta): OptimizedList[int] == Annotated[List[int], runtime.Optimize()] """ + # Python 3.8 has get_origin() and get_args() but those implementations aren't # Annotated-aware, so we can't use those, only Python 3.9 versions will do. if sys.version_info[:2] >= (3, 9): @@ -2082,12 +2360,13 @@ def get_args(tp): return () -if hasattr(typing, 'TypeAlias'): +if hasattr(typing, "TypeAlias"): TypeAlias = typing.TypeAlias elif sys.version_info[:2] >= (3, 9): + class _TypeAliasForm(typing._SpecialForm, _root=True): def __repr__(self): - return 'typing_extensions.' + self._name + return "typing_extensions." + self._name @_TypeAliasForm def TypeAlias(self, parameters): @@ -2103,13 +2382,16 @@ def TypeAlias(self, parameters): """ raise TypeError("{} is not subscriptable".format(self)) + elif sys.version_info[:2] >= (3, 7): + class _TypeAliasForm(typing._SpecialForm, _root=True): def __repr__(self): - return 'typing_extensions.' + self._name + return "typing_extensions." + self._name - TypeAlias = _TypeAliasForm('TypeAlias', - doc="""Special marker indicating that an assignment should + TypeAlias = _TypeAliasForm( + "TypeAlias", + doc="""Special marker indicating that an assignment should be recognized as a proper type alias definition by type checkers. @@ -2118,14 +2400,16 @@ def __repr__(self): Predicate: TypeAlias = Callable[..., bool] It's invalid when used anywhere except as in the example - above.""") + above.""", + ) + +elif hasattr(typing, "_FinalTypingBase"): -elif hasattr(typing, '_FinalTypingBase'): class _TypeAliasMeta(typing.TypingMeta): """Metaclass for TypeAlias""" def __repr__(self): - return 'typing_extensions.TypeAlias' + return "typing_extensions.TypeAlias" class _TypeAliasBase(typing._FinalTypingBase, metaclass=_TypeAliasMeta, _root=True): """Special marker indicating that an assignment should @@ -2138,6 +2422,7 @@ class _TypeAliasBase(typing._FinalTypingBase, metaclass=_TypeAliasMeta, _root=Tr It's invalid when used anywhere except as in the example above. """ + __slots__ = () def __instancecheck__(self, obj): @@ -2147,10 +2432,11 @@ def __subclasscheck__(self, cls): raise TypeError("TypeAlias cannot be used with issubclass().") def __repr__(self): - return 'typing_extensions.TypeAlias' + return "typing_extensions.TypeAlias" TypeAlias = _TypeAliasBase(_root=True) else: + class _TypeAliasMeta(typing.TypingMeta): """Metaclass for TypeAlias""" @@ -2174,4 +2460,5 @@ class TypeAlias(metaclass=_TypeAliasMeta, _root=True): It's invalid when used anywhere except as in the example above. """ - __slots__ = () \ No newline at end of file + + __slots__ = () From 3c2cce4d3b680f5b568070616eba23d775c2d8aa Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 31 Aug 2020 18:11:05 -0700 Subject: [PATCH 07/12] post-black fixups --- pandas/_vendored/typing_extensions.py | 52 +++++++++++++++------------ 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/pandas/_vendored/typing_extensions.py b/pandas/_vendored/typing_extensions.py index 08f2c266c163e..473ee521caf55 100644 --- a/pandas/_vendored/typing_extensions.py +++ b/pandas/_vendored/typing_extensions.py @@ -5,6 +5,12 @@ on 2020-08-30. typing_extensions is distributed under the Python Software Foundation License. + +This is not a direct copy/paste of the original file. Changes are: + - this docstring + - ran `black` + - ran `isort` + - edited strings split by black to adhere to pandas style conventions """ # These are used by Protocol implementation @@ -1316,8 +1322,8 @@ def __new__( ): if gvars is not None: raise TypeError( - "Cannot inherit from Generic[...] or" - " Protocol[...] multiple times." + "Cannot inherit from Generic[...] or " + "Protocol[...] multiple times." ) gvars = base.__parameters__ if gvars is None: @@ -1404,8 +1410,8 @@ def __init__(cls, *args, **kwargs): and base.__origin__ is Generic ): raise TypeError( - "Protocols can only inherit from other" - " protocols, got %r" % base + "Protocols can only inherit from other " + "protocols, got %r" % base ) def _no_init(self, *args, **kwargs): @@ -1479,8 +1485,8 @@ def __subclasscheck__(self, cls): ]: return False raise TypeError( - "Instance and class checks can only be used with" - " @runtime protocols" + "Instance and class checks can only be used with " + "@runtime protocols" ) if self.__dict__.get( "_is_runtime_protocol", None @@ -1492,7 +1498,7 @@ def __subclasscheck__(self, cls): ]: return super(GenericMeta, self).__subclasscheck__(cls) raise TypeError( - "Protocols with non-method members" " don't support issubclass()" + "Protocols with non-method members don't support issubclass()" ) return super(GenericMeta, self).__subclasscheck__(cls) @@ -1680,8 +1686,8 @@ def __class_getitem__(cls, params): while isinstance(params[i], TypeVar): i += 1 raise TypeError( - "Parameters to Protocol[...] must all be type variables." - " Parameter {} is {}".format(i + 1, params[i]) + "Parameters to Protocol[...] must all be type variables. " + "Parameter {} is {}".format(i + 1, params[i]) ) if len(set(params)) != len(params): raise TypeError("Parameters to Protocol[...] must all be unique") @@ -1717,8 +1723,8 @@ def __init_subclass__(cls, *args, **kwargs): ) if gvars is not None: raise TypeError( - "Cannot inherit from Generic[...]" - " and/or Protocol[...] multiple types." + "Cannot inherit from Generic[...] " + "and/or Protocol[...] multiple types." ) gvars = base.__parameters__ if gvars is None: @@ -1730,8 +1736,8 @@ def __init_subclass__(cls, *args, **kwargs): s_vars = ", ".join(str(t) for t in tvars if t not in gvarset) s_args = ", ".join(str(g) for g in gvars) raise TypeError( - "Some type variables ({}) are" - " not listed in {}[{}]".format(s_vars, the_base, s_args) + "Some type variables ({}) are " + "not listed in {}[{}]".format(s_vars, the_base, s_args) ) tvars = gvars cls.__parameters__ = tuple(tvars) @@ -1748,15 +1754,15 @@ def _proto_hook(other): if sys._getframe(2).f_globals["__name__"] in ["abc", "functools"]: return NotImplemented raise TypeError( - "Instance and class checks can only be used with" - " @runtime protocols" + "Instance and class checks can only be used with " + "@runtime protocols" ) if not _is_callable_members_only(cls): if sys._getframe(2).f_globals["__name__"] in ["abc", "functools"]: return NotImplemented raise TypeError( - "Protocols with non-method members" - " don't support issubclass()" + "Protocols with non-method members " + "don't support issubclass()" ) if not isinstance(other, type): # Same error as for issubclass(1, int) @@ -1796,8 +1802,8 @@ def _proto_hook(other): and base._is_protocol ): raise TypeError( - "Protocols can only inherit from other" - " protocols, got %r" % base + "Protocols can only inherit from other " + "protocols, got %r" % base ) def _no_init(self, *args, **kwargs): @@ -1821,8 +1827,8 @@ def runtime_checkable(cls): """ if not isinstance(cls, _ProtocolMeta) or not cls._is_protocol: raise TypeError( - "@runtime_checkable can be only applied to protocol classes," - " got %r" % cls + "@runtime_checkable can be only applied to protocol classes, " + "got %r" % cls ) cls._is_runtime_protocol = True return cls @@ -1921,7 +1927,7 @@ def _typeddict_new(*args, total=True, **kwargs): fields = kwargs elif kwargs: raise TypeError( - "TypedDict takes either a dict or keyword arguments," " but not both" + "TypedDict takes either a dict or keyword arguments, but not both" ) ns = {"__annotations__": dict(fields), "__total__": total} @@ -1934,7 +1940,7 @@ def _typeddict_new(*args, total=True, **kwargs): return _TypedDictMeta(typename, (), ns) _typeddict_new.__text_signature__ = ( - "($cls, _typename, _fields=None," " /, *, total=True, **kwargs)" + "($cls, _typename, _fields=None, /, *, total=True, **kwargs)" ) class _TypedDictMeta(type): From b479de4cb38b6e3841d1e6e90e6d23377b3dc52b Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 31 Aug 2020 18:56:10 -0700 Subject: [PATCH 08/12] unwanted patterns --- pandas/_vendored/typing_extensions.py | 44 ++++++++++++--------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/pandas/_vendored/typing_extensions.py b/pandas/_vendored/typing_extensions.py index 473ee521caf55..369013d2a0419 100644 --- a/pandas/_vendored/typing_extensions.py +++ b/pandas/_vendored/typing_extensions.py @@ -11,6 +11,10 @@ - ran `black` - ran `isort` - edited strings split by black to adhere to pandas style conventions + - AsyncContextManager is defined without `exec` + - `super(Parent, self)` is replaced with `super()` + - foo.__class__ replaced with type(foo) + - Change a comment-syntax annotation in a docstring to newer syntax """ # These are used by Protocol implementation @@ -988,9 +992,8 @@ class AsyncContextManager( __slots__ = () __all__.append("AsyncContextManager") -elif sys.version_info[:2] >= (3, 5): - exec( - """ + + class AsyncContextManager(typing.Generic[T_co]): __slots__ = () @@ -1007,9 +1010,8 @@ def __subclasshook__(cls, C): return _check_methods_in_mro(C, "__aenter__", "__aexit__") return NotImplemented -__all__.append('AsyncContextManager') -""" - ) + +__all__.append("AsyncContextManager") if hasattr(typing, "DefaultDict"): @@ -1180,7 +1182,7 @@ def name_by_id(user_id: UserId) -> str: name_by_id(42) # Fails type check name_by_id(UserId(42)) # OK - num = UserId(5) + 1 # type: int + num: int = UserId(5) + 1 """ def new_type(x): @@ -1360,12 +1362,8 @@ def __new__( 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, _root=True - ) - super(GenericMeta, self).__setattr__( - "_gorg", self if not origin else _gorg(origin) - ) + self = super().__new__(cls, name, bases, namespace, _root=True) + super().__setattr__("_gorg", self if not origin else _gorg(origin)) self.__parameters__ = tvars self.__args__ = ( tuple( @@ -1383,9 +1381,7 @@ def __new__( self._abc_cache = origin._abc_cache if hasattr(self, "_subs_tree"): self.__tree_hash__ = ( - hash(self._subs_tree()) - if origin - else super(GenericMeta, self).__hash__() + hash(self._subs_tree()) if origin else super().__hash__() ) return self @@ -1453,7 +1449,7 @@ def __instancecheck__(self, instance): if ( not getattr(self, "_is_protocol", False) or _is_callable_members_only(self) - ) and issubclass(instance.__class__, self): + ) and issubclass(type(instance), self): return True if self._is_protocol: if all( @@ -1465,7 +1461,7 @@ def __instancecheck__(self, instance): for attr in _get_protocol_attrs(self) ): return True - return super(GenericMeta, self).__instancecheck__(instance) + return super().__instancecheck__(instance) def __subclasscheck__(self, cls): if self.__origin__ is not None: @@ -1496,11 +1492,11 @@ def __subclasscheck__(self, cls): "functools", "typing", ]: - return super(GenericMeta, self).__subclasscheck__(cls) + return super().__subclasscheck__(cls) raise TypeError( "Protocols with non-method members don't support issubclass()" ) - return super(GenericMeta, self).__subclasscheck__(cls) + return super().__subclasscheck__(cls) if not OLD_GENERICS: @@ -1540,7 +1536,7 @@ def __getitem__(self, params): args = params prepend = (self,) if self.__origin__ is None else () - return self.__class__( + return type(self)( self.__name__, prepend + self.__bases__, _no_slots_copy(self.__dict__), @@ -1612,7 +1608,7 @@ def __instancecheck__(cls, instance): if ( not getattr(cls, "_is_protocol", False) or _is_callable_members_only(cls) - ) and issubclass(instance.__class__, cls): + ) and issubclass(type(instance), cls): return True if cls._is_protocol: if all( @@ -1952,7 +1948,7 @@ def __new__(cls, name, bases, ns, total=True): # Subclasses and instances of TypedDict return actual dictionaries # via _dict_new. ns["__new__"] = _typeddict_new if name == "TypedDict" else _dict_new - tp_dict = super(_TypedDictMeta, cls).__new__(cls, name, (dict,), ns) + tp_dict = super().__new__(cls, name, (dict,), ns) annotations = {} own_annotations = ns.get("__annotations__", {}) @@ -2243,7 +2239,7 @@ def __getitem__(self, params): msg = "Annotated[t, ...]: t must be a type." tp = typing._type_check(params[0], msg) metadata = tuple(params[1:]) - return self.__class__( + return type(self)( self.__name__, self.__bases__, _no_slots_copy(self.__dict__), From 5f9976565009627f02e71c665c6236d50729740e Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 31 Aug 2020 19:50:31 -0700 Subject: [PATCH 09/12] code checks --- pandas/_vendored/typing_extensions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/_vendored/typing_extensions.py b/pandas/_vendored/typing_extensions.py index 369013d2a0419..56172cab95844 100644 --- a/pandas/_vendored/typing_extensions.py +++ b/pandas/_vendored/typing_extensions.py @@ -12,7 +12,7 @@ - ran `isort` - edited strings split by black to adhere to pandas style conventions - AsyncContextManager is defined without `exec` - - `super(Parent, self)` is replaced with `super()` + - python2-style super usages are updated - foo.__class__ replaced with type(foo) - Change a comment-syntax annotation in a docstring to newer syntax """ @@ -2146,7 +2146,7 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False): present. BEWARE -- the behavior of globalns and localns is counterintuitive - (unless you are familiar with how eval() and exec() work). The + (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 From 1ca607eebb55b80256284911b307384142163dc5 Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 31 Aug 2020 20:22:45 -0700 Subject: [PATCH 10/12] avoid unwanted pattern --- pandas/_vendored/typing_extensions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/_vendored/typing_extensions.py b/pandas/_vendored/typing_extensions.py index 56172cab95844..33c092f9625ca 100644 --- a/pandas/_vendored/typing_extensions.py +++ b/pandas/_vendored/typing_extensions.py @@ -13,7 +13,7 @@ - edited strings split by black to adhere to pandas style conventions - AsyncContextManager is defined without `exec` - python2-style super usages are updated - - foo.__class__ replaced with type(foo) + - replace foo[dot]__class__ with type(foo) - Change a comment-syntax annotation in a docstring to newer syntax """ From 1b29450597510adb80c8b29cfadecdfc1c86dce2 Mon Sep 17 00:00:00 2001 From: Brock Date: Tue, 1 Sep 2020 09:25:10 -0700 Subject: [PATCH 11/12] remove from flake-ignore --- setup.cfg | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 555344861e33c..29ae85f7985f7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -29,7 +29,6 @@ exclude = doc/build/*.py, doc/temp/*.py, .eggs/*.py, - pandas/_vendored/* versioneer.py, env # exclude asv benchmark environments from linting From b8f19cfa5a4724fd4cea83270ed0f8a86daf9e8a Mon Sep 17 00:00:00 2001 From: Brock Date: Tue, 1 Sep 2020 09:45:40 -0700 Subject: [PATCH 12/12] linting fixup --- pandas/_vendored/typing_extensions.py | 32 +++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/pandas/_vendored/typing_extensions.py b/pandas/_vendored/typing_extensions.py index 33c092f9625ca..53df8da175a56 100644 --- a/pandas/_vendored/typing_extensions.py +++ b/pandas/_vendored/typing_extensions.py @@ -40,7 +40,7 @@ from typing import GenericMeta, TypingMeta OLD_GENERICS = False try: - from typing import _type_vars, _next_in_mro, _type_check + from typing import _next_in_mro, _type_check, _type_vars except ImportError: OLD_GENERICS = True try: @@ -993,25 +993,25 @@ class AsyncContextManager( __all__.append("AsyncContextManager") +else: -class AsyncContextManager(typing.Generic[T_co]): - __slots__ = () - - async def __aenter__(self): - return self + class AsyncContextManager(typing.Generic[T_co]): + __slots__ = () - @abc.abstractmethod - async def __aexit__(self, exc_type, exc_value, traceback): - return None + async def __aenter__(self): + return self - @classmethod - def __subclasshook__(cls, C): - if cls is AsyncContextManager: - return _check_methods_in_mro(C, "__aenter__", "__aexit__") - return NotImplemented + @abc.abstractmethod + async def __aexit__(self, exc_type, exc_value, traceback): + return None + @classmethod + def __subclasshook__(cls, C): + if cls is AsyncContextManager: + return _check_methods_in_mro(C, "__aenter__", "__aexit__") + return NotImplemented -__all__.append("AsyncContextManager") + __all__.append("AsyncContextManager") if hasattr(typing, "DefaultDict"): @@ -1597,7 +1597,7 @@ def __new__(cls, *args, **kwds): elif PEP_560: - from typing import _type_check, _GenericAlias, _collect_type_vars # noqa + from typing import _collect_type_vars, _GenericAlias, _type_check # noqa class _ProtocolMeta(abc.ABCMeta): # This metaclass is a bit unfortunate and exists only because of the lack