Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
219b4ee
Add ParamSpec and Concatenate
Fidget-Spinner Dec 8, 2020
a1c0d0a
support ParamSpec in generics
Fidget-Spinner Dec 8, 2020
7b3beab
Add typing tests, disallow Concatenate in other types
Fidget-Spinner Dec 9, 2020
5dd3b44
Add news
Fidget-Spinner Dec 9, 2020
59c0b20
Address some of Guido's review comments
Fidget-Spinner Dec 10, 2020
4c381b3
remove extraneous empty lines
Fidget-Spinner Dec 10, 2020
b36b62d
Support ParamSpec in __parameters__ of typing and builtin GenericAlias
Fidget-Spinner Dec 10, 2020
d09d088
add tests for user defined generics
Fidget-Spinner Dec 10, 2020
0a19f34
Merge remote-tracking branch 'upstream/master' into pep612
Fidget-Spinner Dec 14, 2020
9727e2a
cast list to tuple done, loosened type checks for Generic
Fidget-Spinner Dec 14, 2020
cc7fc1c
loosen generics, allow typevar-like subst, flatten out args if Callable
Fidget-Spinner Dec 15, 2020
3e67f23
fix whitespace issue, cast list to tuple for types.GenericAlias
Fidget-Spinner Dec 15, 2020
d9baa1a
convert list to tuples if substituting paramspecs in types.GenericAlias
Fidget-Spinner Dec 16, 2020
c4155b6
done! flattened __args__ in substitutions for collections.abc.Callable
Fidget-Spinner Dec 16, 2020
2dbf861
fix repr problems, add repr tests
Fidget-Spinner Dec 16, 2020
87c2d19
Add another test for multiple chaining
Fidget-Spinner Dec 16, 2020
2b09de6
fix typo
Fidget-Spinner Dec 16, 2020
d980702
Clean up some comments
Fidget-Spinner Dec 17, 2020
45f7894
Merge remote-tracking branch 'upstream/master' into pep612
Fidget-Spinner Dec 22, 2020
d6f777c
remove stray whitespace
Fidget-Spinner Dec 22, 2020
9a8176b
Address nearly all of Guido's reviews
Fidget-Spinner Dec 23, 2020
fa06838
more reviews; fix some docstrings, clean up code, cast list to tuple …
Fidget-Spinner Dec 23, 2020
b8672cd
remove uneeded tests copied over from typevar
Fidget-Spinner Dec 23, 2020
51a463c
remove unused variable
Fidget-Spinner Dec 23, 2020
6d5b754
Merge remote-tracking branch 'upstream/master' into pep612
Fidget-Spinner Dec 24, 2020
c05d5d7
merge length checking into _has_special_args too
Fidget-Spinner Dec 24, 2020
c49ba30
Update Lib/_collections_abc.py
gvanrossum Dec 24, 2020
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
Prev Previous commit
Next Next commit
Support ParamSpec in __parameters__ of typing and builtin GenericAlias
also reduced runtime checks
  • Loading branch information
Fidget-Spinner committed Dec 10, 2020
commit b36b62dc46e859b8afa836ca1a8ed15114c3f7a4
18 changes: 9 additions & 9 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -4266,17 +4266,17 @@ def test_valid_uses(self):
T = TypeVar('T')
C1 = Callable[P, int]
self.assertEqual(C1.__args__, (P, int))
self.assertEqual(C1.__parameters__, ())
self.assertEqual(C1.__parameters__, (P,))
C2 = Callable[P, T]
self.assertEqual(C2.__args__, (P, T))
self.assertEqual(C2.__parameters__, (T,))
self.assertEqual(C2.__parameters__, (P, T))
# Test collections.abc.Callable too.
C3 = collections.abc.Callable[P, int]
self.assertEqual(C3.__args__, (P, int))
self.assertEqual(C3.__parameters__, ())
self.assertEqual(C3.__parameters__, (P,))
C4 = collections.abc.Callable[P, T]
self.assertEqual(C4.__args__, (P, T))
self.assertEqual(C4.__parameters__, (T,))
self.assertEqual(C4.__parameters__, (P, T))

# ParamSpec instances should also have args and kwargs attributes.
self.assertIn('args', dir(P))
Expand Down Expand Up @@ -4306,7 +4306,7 @@ def test_union_unique(self):
self.assertNotEqual(Union[P1, int], Union[P1])
self.assertNotEqual(Union[P1, int], Union[int])
self.assertEqual(Union[P1, int].__args__, (P1, int))
self.assertEqual(Union[P1, int].__parameters__, ())
self.assertEqual(Union[P1, int].__parameters__, (P1,))
self.assertIs(Union[P1, int].__origin__, Union)

def test_repr(self):
Expand Down Expand Up @@ -4352,18 +4352,18 @@ def test_valid_uses(self):
T = TypeVar('T')
C1 = Callable[Concatenate[int, P], int]
self.assertEqual(C1.__args__, (Concatenate[int, P], int))
self.assertEqual(C1.__parameters__, ())
self.assertEqual(C1.__parameters__, (P,))
C2 = Callable[Concatenate[int, T, P], T]
self.assertEqual(C2.__args__, (Concatenate[int, T, P], T))
self.assertEqual(C2.__parameters__, (T,))
self.assertEqual(C2.__parameters__, (T, P))

# Test collections.abc.Callable too.
C3 = collections.abc.Callable[Concatenate[int, P], int]
self.assertEqual(C3.__args__, (Concatenate[int, P], int))
self.assertEqual(C3.__parameters__, ())
self.assertEqual(C3.__parameters__, (P,))
C4 = collections.abc.Callable[Concatenate[int, T, P], T]
self.assertEqual(C4.__args__, (Concatenate[int, T, P], T))
self.assertEqual(C4.__parameters__, (T,))
self.assertEqual(C4.__parameters__, (T, P))


class AllTests(BaseTestCase):
Expand Down
23 changes: 8 additions & 15 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,14 +180,14 @@ def _type_repr(obj):


def _collect_type_vars(types):
"""Collect all type variable contained in types in order of
first appearance (lexicographic order). For example::
"""Collect all type variable and parameter specification variables contained
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if things would become easier if we just treated ParamSpec as a subclass of TypeVar? Then it's just a type variable except in those few cases where it actually needs to behave differently at runtime (maybe only the weird exception in the PEP for Z[[int, int]] == Z[int, int]?). Might save on tests as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts about this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed all the methods that check for (TypeVar, ParamSpec) to just check for _TypeVarLike instead. Which means I can probably get rid of some tests for ParamSpec since it uses the exact same __reduce__, __repr__, __ror__ etc. methods as TypeVar, and TypeVar already has tests for them.

in types in order of first appearance (lexicographic order). For example::

_collect_type_vars((T, List[S, T])) == (T, S)
"""
tvars = []
for t in types:
if isinstance(t, TypeVar) and t not in tvars:
if isinstance(t, (TypeVar, ParamSpec)) and t not in tvars:
tvars.append(t)
if isinstance(t, (_GenericAlias, GenericAlias)):
tvars.extend([t for t in t.__parameters__ if t not in tvars])
Expand Down Expand Up @@ -529,10 +529,7 @@ def Concatenate(self, parameters):

Callable[Concatenate[int, P], int]

.. seealso::

:pep:`612` -- Parameter Specification Variables

See PEP 612 for detailed information.
"""
if parameters == ():
raise TypeError("Cannot take a Concatenate of no types.")
Expand Down Expand Up @@ -1008,8 +1005,9 @@ def __getitem__(self, params):
params = (Ellipsis, result)
else:
if not isinstance(args, (list, ParamSpec, _ConcatenateGenericAlias)):
raise TypeError(f"Callable[args, result]: args must be a list."
f" Got {args}")
raise TypeError(f"Callable[args, result]: args must be a list, "
f"ParamSpec or Concatenate. "
f"Got {args}")
if isinstance(args, list):
params = (tuple(args), result)
return self.__getitem_inner__(params)
Expand Down Expand Up @@ -1092,12 +1090,7 @@ def __hash__(self):


class _ConcatenateGenericAlias(_GenericAlias, _root=True):

def __or__(self, right):
return NotImplemented

def __ror__(self, right):
return NotImplemented
pass


class Generic:
Expand Down
5 changes: 3 additions & 2 deletions Objects/genericaliasobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,13 +156,14 @@ ga_repr(PyObject *self)
return NULL;
}

// isinstance(obj, TypeVar) without importing typing.py.
// isinstance(obj, (TypeVar, ParamSpec)) without importing typing.py.
// Returns -1 for errors.
static int
is_typevar(PyObject *obj)
{
PyTypeObject *type = Py_TYPE(obj);
if (strcmp(type->tp_name, "TypeVar") != 0) {
if ((strcmp(type->tp_name, "TypeVar") &
strcmp(type->tp_name, "ParamSpec")) != 0) {
return 0;
}
PyObject *module = PyObject_GetAttrString((PyObject *)type, "__module__");
Expand Down