Skip to content

gh-126085: Add tp_iter to TypeAliasType to allow star unpacking #127981

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 13 commits into from
Mar 4, 2025
14 changes: 14 additions & 0 deletions Doc/library/typing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2292,6 +2292,20 @@ without the dedicated syntax, as documented below.

.. versionadded:: 3.14

.. rubric:: Unpacking

Type aliases support star unpacking using the ``*Alias`` syntax.
This is equivalent to using ``Unpack[Alias]`` directly:

.. doctest::

>>> type Alias = tuple[int, str]
>>> type Unpacked = tuple[bool, *Alias]
>>> Unpacked.__value__
tuple[bool, typing.Unpack[Alias]]

.. versionadded:: next


Other special directives
""""""""""""""""""""""""
Expand Down
2 changes: 2 additions & 0 deletions Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1326,6 +1326,8 @@ typing
* Remove :class:`!typing.ByteString`. It had previously raised a
:exc:`DeprecationWarning` since Python 3.12.

* :class:`typing.TypeAliasType` now supports star unpacking.

urllib
------

Expand Down
13 changes: 12 additions & 1 deletion Lib/test/test_type_aliases.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from test.typinganndata import mod_generics_cache

from typing import (
Callable, TypeAliasType, TypeVar, TypeVarTuple, ParamSpec, get_args,
Callable, TypeAliasType, TypeVar, TypeVarTuple, ParamSpec, Unpack, get_args,
)


Expand Down Expand Up @@ -317,6 +317,17 @@ def test_module(self):
self.assertEqual(mod_generics_cache.OldStyle.__module__,
mod_generics_cache.__name__)

def test_unpack(self):
type Alias = tuple[int, int]
unpacked = (*Alias,)[0]
self.assertEqual(unpacked, Unpack[Alias])

class Foo[*Ts]:
pass

x = Foo[str, *Alias]
self.assertEqual(x.__args__, (str, Unpack[Alias]))


# All these type aliases are used for pickling tests:
T = TypeVar('T')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:class:`typing.TypeAliasType` now supports star unpacking.
15 changes: 8 additions & 7 deletions Objects/typevarobject.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// TypeVar, TypeVarTuple, and ParamSpec
// TypeVar, TypeVarTuple, ParamSpec, and TypeAlias
#include "Python.h"
#include "pycore_object.h" // _PyObject_GC_TRACK/UNTRACK, PyAnnotateFormat
#include "pycore_typevarobject.h"
Expand Down Expand Up @@ -394,7 +394,7 @@ caller(void)
}

static PyObject *
typevartuple_unpack(PyObject *tvt)
unpack(PyObject *self)
{
PyObject *typing = PyImport_ImportModule("typing");
if (typing == NULL) {
Expand All @@ -405,7 +405,7 @@ typevartuple_unpack(PyObject *tvt)
Py_DECREF(typing);
return NULL;
}
PyObject *unpacked = PyObject_GetItem(unpack, tvt);
PyObject *unpacked = PyObject_GetItem(unpack, self);
Py_DECREF(typing);
Py_DECREF(unpack);
return unpacked;
Expand Down Expand Up @@ -440,7 +440,7 @@ unpack_typevartuples(PyObject *params)
for (Py_ssize_t i = 0; i < n; i++) {
PyObject *param = PyTuple_GET_ITEM(params, i);
if (Py_IS_TYPE(param, tp)) {
PyObject *unpacked = typevartuple_unpack(param);
PyObject *unpacked = unpack(param);
if (unpacked == NULL) {
Py_DECREF(new_params);
return NULL;
Expand Down Expand Up @@ -1524,9 +1524,9 @@ typevartuple_dealloc(PyObject *self)
}

static PyObject *
typevartuple_iter(PyObject *self)
unpack_iter(PyObject *self)
{
PyObject *unpacked = typevartuple_unpack(self);
PyObject *unpacked = unpack(self);
if (unpacked == NULL) {
return NULL;
}
Expand Down Expand Up @@ -1782,7 +1782,7 @@ PyType_Slot typevartuple_slots[] = {
{Py_tp_methods, typevartuple_methods},
{Py_tp_getset, typevartuple_getset},
{Py_tp_new, typevartuple},
{Py_tp_iter, typevartuple_iter},
{Py_tp_iter, unpack_iter},
{Py_tp_repr, typevartuple_repr},
{Py_tp_dealloc, typevartuple_dealloc},
{Py_tp_alloc, PyType_GenericAlloc},
Expand Down Expand Up @@ -2158,6 +2158,7 @@ PyTypeObject _PyTypeAlias_Type = {
.tp_dealloc = typealias_dealloc,
.tp_new = typealias_new,
.tp_free = PyObject_GC_Del,
.tp_iter = unpack_iter,
.tp_traverse = typealias_traverse,
.tp_clear = typealias_clear,
.tp_repr = typealias_repr,
Expand Down
Loading