Skip to content

Refactoring typing_inspect.py #1435

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 38 additions & 116 deletions azure_functions_worker/_thirdparty/typing_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,10 @@
# NOTE: This module must support Python 2.7 in addition to Python 3.x

import sys
NEW_TYPING = sys.version_info[:3] >= (3, 7, 0) # PEP 560
if NEW_TYPING:
import collections.abc

if NEW_TYPING:
from typing import (
Generic, Callable, Union, TypeVar, ClassVar, Tuple, _GenericAlias
)
else:
from typing import (
Callable, CallableMeta, Union, _Union, TupleMeta, TypeVar,
_ClassVar, GenericMeta,
)
import collections.abc
from typing import (
Generic, Callable, Union, TypeVar, ClassVar, Tuple, _GenericAlias
)

NEW_39_TYPING = sys.version_info[:3] >= (3, 9, 0) # PEP 560
if NEW_39_TYPING:
Expand All @@ -33,17 +24,6 @@

# from mypy_extensions import _TypedDictMeta


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


def is_generic_type(tp):
"""Test if the given type is a generic type. This includes Generic itself,
but excludes special typing constructs such as Union, Tuple, Callable,
Expand All @@ -66,13 +46,10 @@ def is_generic_type(tp):
return (isinstance(tp, type) and issubclass(tp, Generic)
or ((isinstance(tp, _GenericAlias) or isinstance(tp, _SpecialGenericAlias)) # NoQA E501
and tp.__origin__ not in (Union, tuple, ClassVar, collections.abc.Callable))) # NoQA E501
if NEW_TYPING:
return (isinstance(tp, type)
and issubclass(tp, Generic)
or isinstance(tp, _GenericAlias)
and tp.__origin__ not in (Union, tuple, ClassVar, collections.abc.Callable)) # NoQA E501
return (isinstance(tp, GenericMeta) and not
isinstance(tp, (CallableMeta, TupleMeta)))
return (isinstance(tp, type)
and issubclass(tp, Generic)
or isinstance(tp, _GenericAlias)
and tp.__origin__ not in (Union, tuple, ClassVar, collections.abc.Callable)) # NoQA E501


def is_callable_type(tp):
Expand All @@ -94,12 +71,10 @@ class MyClass(Callable[[int], int]):

get_origin(tp) is collections.abc.Callable # Callable prior to Python 3.7 # NoQA E501
"""
if NEW_TYPING:
return (tp is Callable or isinstance(tp, _GenericAlias) and
tp.__origin__ is collections.abc.Callable or
isinstance(tp, type) and issubclass(tp, Generic) and
issubclass(tp, collections.abc.Callable))
return type(tp) is CallableMeta
return (tp is Callable or isinstance(tp, _GenericAlias) and
tp.__origin__ is collections.abc.Callable or
isinstance(tp, type) and issubclass(tp, Generic) and
issubclass(tp, collections.abc.Callable))


def is_tuple_type(tp):
Expand All @@ -120,12 +95,10 @@ class MyClass(Tuple[str, int]):

get_origin(tp) is tuple # Tuple prior to Python 3.7
"""
if NEW_TYPING:
return (tp is Tuple or isinstance(tp, _GenericAlias) and
tp.__origin__ is tuple or
isinstance(tp, type) and issubclass(tp, Generic) and
issubclass(tp, tuple))
return type(tp) is TupleMeta
return (tp is Tuple or isinstance(tp, _GenericAlias) and
tp.__origin__ is tuple or
isinstance(tp, type) and issubclass(tp, Generic) and
issubclass(tp, tuple))


def is_union_type(tp):
Expand All @@ -136,10 +109,8 @@ def is_union_type(tp):
is_union_type(Union[int, int]) == False
is_union_type(Union[T, int]) == True
"""
if NEW_TYPING:
return (tp is Union or
isinstance(tp, _GenericAlias) and tp.__origin__ is Union)
return type(tp) is _Union
return (tp is Union or
isinstance(tp, _GenericAlias) and tp.__origin__ is Union)


def is_typevar(tp):
Expand All @@ -161,10 +132,8 @@ def is_classvar(tp):
is_classvar(ClassVar[int]) == True
is_classvar(ClassVar[List[T]]) == True
"""
if NEW_TYPING:
return (tp is ClassVar or
isinstance(tp, _GenericAlias) and tp.__origin__ is ClassVar)
return type(tp) is _ClassVar
return (tp is ClassVar or
isinstance(tp, _GenericAlias) and tp.__origin__ is ClassVar)


def get_last_origin(tp):
Expand All @@ -179,16 +148,8 @@ def get_last_origin(tp):
get_last_origin(List[Tuple[T, T]][int]) == List[Tuple[T, T]]
get_last_origin(List) == List
"""
if NEW_TYPING:
raise ValueError('This function is only supported in Python 3.6,'
' use get_origin instead')
sentinel = object()
origin = getattr(tp, '__origin__', sentinel)
if origin is sentinel:
return None
if origin is None:
return tp
return origin
raise ValueError('This function is only supported in Python 3.6,'
' use get_origin instead')


def get_origin(tp):
Expand All @@ -202,17 +163,10 @@ def get_origin(tp):
get_origin(Union[T, int]) == Union
get_origin(List[Tuple[T, T]][int]) == list # List prior to Python 3.7
"""
if NEW_TYPING:
if isinstance(tp, _GenericAlias):
return tp.__origin__ if tp.__origin__ is not ClassVar else None
if tp is Generic:
return Generic
return None
if isinstance(tp, GenericMeta):
return _gorg(tp)
if is_union_type(tp):
return Union

if isinstance(tp, _GenericAlias):
return tp.__origin__ if tp.__origin__ is not ClassVar else None
if tp is Generic:
return Generic
return None


Expand All @@ -231,16 +185,9 @@ def get_parameters(tp):
get_parameters(Union[S_co, Tuple[T, T]][int, U]) == (U,)
get_parameters(Mapping[T, Tuple[S_co, T]]) == (T, S_co)
"""
if NEW_TYPING:
if (isinstance(tp, _GenericAlias) or isinstance(tp, type) and
issubclass(tp, Generic) and tp is not Generic): # NoQA E129
return tp.__parameters__
return ()
if (
is_generic_type(tp) or is_union_type(tp) or
is_callable_type(tp) or is_tuple_type(tp)
):
return tp.__parameters__ if tp.__parameters__ is not None else ()
if (isinstance(tp, _GenericAlias) or isinstance(tp, type) and
issubclass(tp, Generic) and tp is not Generic): # NoQA E129
return tp.__parameters__
return ()


Expand All @@ -256,17 +203,8 @@ def get_last_args(tp):
get_last_args(Callable[[T], int]) == (T, int)
get_last_args(Callable[[], int]) == (int,)
"""
if NEW_TYPING:
raise ValueError('This function is only supported in Python 3.6,'
' use get_args instead')
if is_classvar(tp):
return (tp.__type__,) if tp.__type__ is not None else ()
if (
is_generic_type(tp) or is_union_type(tp) or
is_callable_type(tp) or is_tuple_type(tp)
):
return tp.__args__ if tp.__args__ is not None else ()
return ()
raise ValueError('This function is only supported in Python 3.6,'
' use get_args instead')


def _eval_args(args):
Expand Down Expand Up @@ -307,29 +245,13 @@ def get_args(tp, evaluate=None):
(int, Tuple[Optional[int], Optional[int]])
get_args(Callable[[], T][int], evaluate=True) == ([], int,)
"""
if NEW_TYPING:
if evaluate is not None and not evaluate:
raise ValueError('evaluate can only be True in Python 3.7')
if isinstance(tp, _GenericAlias):
res = tp.__args__
if get_origin(tp) is collections.abc.Callable and res[0] is not Ellipsis: # NoQA E501
res = (list(res[:-1]), res[-1])
return res
return ()
if is_classvar(tp):
return (tp.__type__,)
if (
is_generic_type(tp) or is_union_type(tp) or
is_callable_type(tp) or is_tuple_type(tp)
):
tree = tp._subs_tree()
if isinstance(tree, tuple) and len(tree) > 1:
if not evaluate:
return tree[1:]
res = _eval_args(tree[1:])
if get_origin(tp) is Callable and res[0] is not Ellipsis:
res = (list(res[:-1]), res[-1])
return res
if evaluate is not None and not evaluate:
raise ValueError('evaluate can only be True in Python 3.7')
if isinstance(tp, _GenericAlias):
res = tp.__args__
if get_origin(tp) is collections.abc.Callable and res[0] is not Ellipsis: # NoQA E501
res = (list(res[:-1]), res[-1])
return res
return ()


Expand Down
36 changes: 1 addition & 35 deletions tests/unittests/test_typing_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@
MutableMapping, Iterable, Generic, List, Any, Dict, Tuple, NamedTuple,
)

import sys
NEW_TYPING = sys.version_info[:3] >= (3, 7, 0) # PEP 560


class IsUtilityTestCase(TestCase):
def sample_test(self, fun, samples, nonsamples):
Expand Down Expand Up @@ -74,23 +71,13 @@ def test_classvar(self):

class GetUtilityTestCase(TestCase):

@skipIf(NEW_TYPING, "Not supported in Python 3.7")
def test_last_origin(self):
T = TypeVar('T')
self.assertEqual(get_last_origin(int), None)
self.assertEqual(get_last_origin(ClassVar[int]), None)
self.assertEqual(get_last_origin(Generic[T]), Generic)
self.assertEqual(get_last_origin(Union[T, int][str]), Union[T, int])
self.assertEqual(get_last_origin(List[Tuple[T, T]][int]), List[Tuple[T, T]])
self.assertEqual(get_last_origin(List), List)

def test_origin(self):
T = TypeVar('T')
self.assertEqual(get_origin(int), None)
self.assertEqual(get_origin(ClassVar[int]), None)
self.assertEqual(get_origin(Generic), Generic)
self.assertEqual(get_origin(Generic[T]), Generic)
self.assertEqual(get_origin(List[Tuple[T, T]][int]), list if NEW_TYPING else List)
self.assertEqual(get_origin(List[Tuple[T, T]][int]), list)

def test_parameters(self):
T = TypeVar('T')
Expand All @@ -105,27 +92,6 @@ def test_parameters(self):
self.assertEqual(get_parameters(Union[S_co, Tuple[T, T]][int, U]), (U,))
self.assertEqual(get_parameters(Mapping[T, Tuple[S_co, T]]), (T, S_co))

@skipIf(NEW_TYPING, "Not supported in Python 3.7")
def test_last_args(self):
T = TypeVar('T')
S = TypeVar('S')
self.assertEqual(get_last_args(int), ())
self.assertEqual(get_last_args(Union), ())
self.assertEqual(get_last_args(ClassVar[int]), (int,))
self.assertEqual(get_last_args(Union[T, int]), (T, int))
self.assertEqual(get_last_args(Iterable[Tuple[T, S]][int, T]), (int, T))
self.assertEqual(get_last_args(Callable[[T, S], int]), (T, S, int))
self.assertEqual(get_last_args(Callable[[], int]), (int,))

@skipIf(NEW_TYPING, "Not supported in Python 3.7")
def test_args(self):
T = TypeVar('T')
self.assertEqual(get_args(Union[int, Tuple[T, int]][str]),
(int, (Tuple, str, int)))
self.assertEqual(get_args(Union[int, Union[T, int], str][int]),
(int, str))
self.assertEqual(get_args(int), ())

def test_args_evaluated(self):
T = TypeVar('T')
self.assertEqual(get_args(Union[int, Tuple[T, int]][str], evaluate=True),
Expand Down