diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 764d83a6800d15..44447400c29bca 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -5055,6 +5055,15 @@ All parameterized generics implement special read-only attributes. have correct ``__parameters__`` after substitution because :class:`typing.ParamSpec` is intended primarily for static type checking. + +.. attribute:: genericalias.__unpacked__ + + A boolean that is true if the alias has been unpacked using the + ``*`` operator (see :data:`~typing.TypeVarTuple`). + + .. versionadded:: 3.11 + + .. seealso:: :pep:`484` - Type Hints diff --git a/Lib/test/test_genericalias.py b/Lib/test/test_genericalias.py index bf96ba065fbb04..cd6a3abda3a1ff 100644 --- a/Lib/test/test_genericalias.py +++ b/Lib/test/test_genericalias.py @@ -416,6 +416,12 @@ def __deepcopy__(self, memo): self.assertEqual(copied.__args__, alias.__args__) self.assertEqual(copied.__parameters__, alias.__parameters__) + def test_unpack(self): + alias = tuple[str, ...] + self.assertIs(alias.__unpacked__, False) + unpacked = (*alias,)[0] + self.assertIs(unpacked.__unpacked__, True) + def test_union(self): a = typing.Union[list[int], list[str]] self.assertEqual(a.__args__, (list[int], list[str])) diff --git a/Misc/NEWS.d/next/Library/2022-04-29-16-41-08.gh-issue-87390.3LNNCv.rst b/Misc/NEWS.d/next/Library/2022-04-29-16-41-08.gh-issue-87390.3LNNCv.rst new file mode 100644 index 00000000000000..c368c1eb3be18b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-04-29-16-41-08.gh-issue-87390.3LNNCv.rst @@ -0,0 +1,2 @@ +Add an ``__unpacked__`` attribute to :class:`types.GenericAlias`. Patch by +Jelle Zijlstra. diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c index 7b689912dffc1b..c6ed1611bd29ec 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -516,6 +516,7 @@ ga_vectorcall(PyObject *self, PyObject *const *args, static const char* const attr_exceptions[] = { "__origin__", "__args__", + "__unpacked__", "__parameters__", "__mro_entries__", "__reduce_ex__", // needed so we don't look up object.__reduce_ex__ @@ -657,6 +658,7 @@ static PyMethodDef ga_methods[] = { static PyMemberDef ga_members[] = { {"__origin__", T_OBJECT, offsetof(gaobject, origin), READONLY}, {"__args__", T_OBJECT, offsetof(gaobject, args), READONLY}, + {"__unpacked__", T_BOOL, offsetof(gaobject, starred), READONLY}, {0} };