8000 Refactor Union, Tuple, and Callable by ilevkivskyi · Pull Request #308 · python/typing · GitHub
[go: up one dir, main page]

Skip to content

Refactor Union, Tuple, and Callable #308

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 39 commits into from
Oct 29, 2016
Merged
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
e8c3ad6
Make Tuple[T, S] subcriptable and subclassable
ilevkivskyi Oct 23, 2016
cfcf81f
Make Callable[..., T] subscriptable and subclassable
ilevkivskyi Oct 23, 2016
1368e97
Make Union[T, S] subsctiptable
ilevkivskyi Oct 23, 2016
7ee4a1a
Disable plain Union and Optional as type arguments
ilevkivskyi Oct 23, 2016
5fdceba
Implement __eq__ for GenericMeta
ilevkivskyi Oct 23, 2016
f339586
Implement __eq__ for Unions
ilevkivskyi Oct 23, 2016
26f50a3
Refactor common code in __eq__ and __repr__
ilevkivskyi Oct 23, 2016
65de907
Remove redundant code
ilevkivskyi Oct 23, 2016
897de4e
Fix minor bugs + mini-refactoring
ilevkivskyi Oct 23, 2016
c687ffa
Fix repr of Callable subclasses
ilevkivskyi Oct 23, 2016
582a37f
Don't be too pedantic in GenericMeta._eval_type
ilevkivskyi Oct 23, 2016
02e6b14
Simplify __hash__ and factor out orig_chain
ilevkivskyi Oct 23, 2016
8d802cc
Remove outdated tests + be more pedanctic in _Union._eval_type
ilevkivskyi Oct 23, 2016
4e2527c
Add tests
ilevkivskyi Oct 23, 2016
92da67f
Factor out _subs_tree for Union and Generic
ilevkivskyi Oct 24, 2016
7563c92
Prohibit plain Generic[T] as type argument
ilevkivskyi Oct 24, 2016
f33545b
Correct a comment
ilevkivskyi Oct 24, 2016
4a996b2
Erase but preserve type also for Callable
ilevkivskyi Oct 24, 2016
6564742
Erase but preserve type for all generics
ilevkivskyi Oct 24, 2016
184f089
Restore original __next_in_mro__ and use more precise bases
Oct 24, 2016
b613325
Preserve __qualname__ on subscription
Oct 24, 2016
011b9d8
Add tests and factor common stuff for Union
ilevkivskyi Oct 24, 2016
52712a6
Add even more tests
ilevkivskyi Oct 24, 2016
2641151
One more test + minor code simplification
ilevkivskyi Oct 24, 2016
9f1fb98
Polishing code
ilevkivskyi Oct 25, 2016
279a67e
Minor changes
ilevkivskyi Oct 25, 2016
f173fde
Precalculate hash + refactor + more tests
ilevkivskyi Oct 25, 2016
819d472
Simplify repr for Union
ilevkivskyi Oct 25, 2016
e6f19a8
Add big test for __eq__, __repr__, and Any substitution
ilevkivskyi Oct 25, 2016
deed806
Add test to illustrate substitution
ilevkivskyi Oct 25, 2016
f6382a7
Minor change in tests
ilevkivskyi Oct 25, 2016
9bc7374
Add/expand comments and docstrings
ilevkivskyi Oct 25, 2016
c2724ce
Fix the __qualname__ in PY 3.2
ilevkivskyi Oct 25, 2016
fd3e344
Add tests to Python 2
ilevkivskyi Oct 25, 2016
cd7bbe2
Modify Union in Python 2
ilevkivskyi Oct 25, 2016
068ab5e
Update Python 2 tests
ilevkivskyi Oct 25, 2016
09c4797
Change remaining parts in Python 2
ilevkivskyi Oct 25, 2016
60303f7
Fix final test in PY 2
ilevkivskyi Oct 25, 2016
ea5dd05
Also call super().__init__ in PY 2 Generic
ilevkivskyi Oct 26, 2016
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
8000
Diff view
Prev Previous commit
Next Next commit
Refactor common code in __eq__ and __repr__
  • Loading branch information
ilevkivskyi committed Oct 23, 2016
commit 26f50a3b68cf55de825466faa67d01346393861d
123 changes: 54 additions & 69 deletions src/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,8 @@ def __new__(cls, parameters=None, origin=None, *args, _root=False):
self.__args__ = None
self.__origin__ = None
return self
if not isinstance(parameters, tuple):
raise TypeError("Expected parameters=<tuple>")
if origin is not Union:
self.__parameters__ = _type_vars(parameters)
self.__args__ = parameters
Expand All @@ -596,12 +598,11 @@ def __new__(cls, parameters=None, origin=None, *args, _root=False):
raise TypeError("Expected parameters=<tuple>")
# Flatten out Union[Union[...], ...] and type-check non-Union args.
params = []
msg = "Union[arg, ...]: each arg must be a type."
for p in parameters:
if isinstance(p, _Union) and p.__origin__ is Union:
params.extend(p.__args__)
else:
params.append(_type_check(p, msg))
params.append(p)
# Weed out strict duplicates, preserving the first of each occurrence.
params = remove_dups(params)
# Weed out subclasses.
Expand Down Expand Up @@ -643,34 +644,31 @@ def _get_type_vars(self, tvars):
def __repr__(self):
if self.__origin__ is None:
return super().__repr__()
return self._subs_repr([], [])

def _subs_repr(self, tvars, args):
# This is an adapted equivalent of code in GenericMeta.
# Look there for detailed explanations.
if not self.__args__:
return super().__repr__()
current = self.__origin__
orig_chain = []
while current.__origin__ is not None:
orig_chain.append(current)
current = current.__origin__
str_args = []
for arg in self.__args__:
str_args.append(_replace_arg(arg, tvars, args))
for cls in orig_chain:
new_str_args = []
for i, arg in enumerate(cls.__args__):
new_str_args.append(_replace_arg(arg, cls.__parameters__, str_args))
str_args = new_str_args
return super().__repr__() + '[%s]' % ', '.join(str_args)
tree = self._subs_tree([], [])
if not isinstance(tree, tuple):
return repr(tree)
return self._tree_repr(tree)

def _tree_repr(self, tree):
arg_list = []
for arg in tree[1:]:
if not isinstance(arg, tuple):
arg_list.append(_type_repr(arg))
else:
arg_list.append(arg[0]._tree_repr(arg))
return super().__repr__() + '[%s]' % ', '.join(arg_list)

@_tp_cache
def __getitem__(self, parameters):
if parameters == ():
raise TypeError("Cannot take a Union of no types.")
if not isinstance(parameters, tuple):
parameters = (parameters,)
if self.__origin__ is None:
msg = "Union[arg, ...]: each arg must be a type."
else:
msg = "Parameters to generic types must be types."
parameters = tuple(_type_check(p, msg) for p in parameters)
if self is not Union:
if not self.__parameters__:
raise TypeError("%s is not a generic class" % repr(self))
Expand Down Expand Up @@ -948,40 +946,24 @@ def _eval_type(self, globalns, localns):
def __repr__(self):
if self.__origin__ is None:
return super().__repr__()
return self._subs_repr([], [])

def _subs_repr(self, tvars, args, *, for_callable=False):
assert len(tvars) == len(args)
# Construct the chain of __origin__'s.
current = self.__origin__
orig_chain = []
while current.__origin__ is not None:
orig_chain.append(current)
current = current.__origin__
# Replace type variables in __args__ if asked ...
str_args = []
for arg in self.__args__:
str_args.append(_replace_arg(arg, tvars, args))
# ... then continue replacing down the origin chain.
for cls in orig_chain:
new_str_args = []
for i, arg in enumerate(cls.__args__):
new_str_args.append(_replace_arg(arg, cls.__parameters__, str_args))
str_args = new_str_args
if not for_callable:
return super().__repr__() + '[%s]' % ', '.join(str_args)
# Special format fot Callable
if str_args[0] == '...':
return super().__repr__() + '[..., %s]' % str_args[1]
if str_args[0] == '()':
return super().__repr__() + '[[], %s]' % str_args[1]
else:
return (super().__repr__() +
'[[%s], %s]' % (', '.join(str_args[:-1]), str_args[-1]))
return self._tree_repr(self._subs_tree([], []))

def _tree_repr(self, tree):
arg_list = []
for arg in tree[1:]:
if arg == ():
arg_list.append('()')
elif not isinstance(arg, tuple):
arg_list.append(_type_repr(arg))
else:
arg_list.append(arg[0]._tree_repr(arg))
return super().__repr__() + '[%s]' % ', '.join(arg_list)

def _subs_tree(self, tvars, args):
# Construct the chain of __origin__'s.
current = self.__origin__
if current is None:
return self
orig_chain = []
while current.__origin__ is not None:
orig_chain.append(current)
Expand Down Expand Up @@ -1121,16 +1103,6 @@ class _TypingEmpty:
class TupleMeta(GenericMeta):
"""Metaclass for Tuple"""

def __repr__(self):
if self.__args__ == ((),):
return repr(Tuple) + '[()]'
return super().__repr__()

def _subs_repr(self, tvars, args):
if not self.__args__:
return super().__repr__()
return super()._subs_repr(tvars, args)

@_tp_cache
def __getitem__(self, parameters):
if self.__origin__ is not None or not _geqv(self, Tuple):
Expand Down Expand Up @@ -1194,12 +1166,25 @@ class CallableMeta(GenericMeta):
def __repr__(self):
if self.__origin__ is None:
return super().__repr__()
return super()._subs_repr([], [], for_callable=True)

def _subs_repr(self, tvars, args):
if not self.__args__:
return super().__repr__()
return super()._subs_repr(tvars, args)
return self._tree_repr(self._subs_tree([], []))

def _tree_repr(self, tree):
arg_list = []
for arg in tree[1:]:
if not isinstance(arg, tuple) or len(arg) == 0:
if arg == ():
r = '[]'
elif arg == Ellipsis:
r = '...'
else:
r = _type_repr(arg)
arg_list.append(r)
else:
arg_list.append(arg[0]._tree_repr(arg))
if len(arg_list) == 2:
return repr(tree[0]) + '[%s]' % ', '.join(arg_list)
return (repr(tree[0]) +
'[[%s], %s]' % (', '.join(arg_list[:-1]), arg_list[-1]))

def __getitem__(self, parameters):
if self.__origin__ is not None or not _geqv(self, Callable):
Expand Down
0