gh-139817: Attribute __qualname__ is added to TypeAliasType (#139919)

This commit is contained in:
Mikhail Efimov 2025-10-15 19:08:17 +03:00 committed by GitHub
parent 5213f1b684
commit f673f0e7b4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 144 additions and 33 deletions

View file

@ -2243,7 +2243,7 @@ without the dedicated syntax, as documented below.
.. versionadded:: 3.10 .. versionadded:: 3.10
.. class:: TypeAliasType(name, value, *, type_params=()) .. class:: TypeAliasType(name, value, *, type_params=(), qualname=None)
The type of type aliases created through the :keyword:`type` statement. The type of type aliases created through the :keyword:`type` statement.
@ -2267,6 +2267,20 @@ without the dedicated syntax, as documented below.
>>> Alias.__name__ >>> Alias.__name__
'Alias' 'Alias'
.. attribute:: __qualname__
The :term:`qualified name` of the type alias:
.. doctest::
>>> class Class:
... type Alias = int
...
>>> Class.Alias.__qualname__
'Class.Alias'
.. versionadded:: 3.15
.. attribute:: __module__ .. attribute:: __module__
The name of the module in which the type alias was defined:: The name of the module in which the type alias was defined::

View file

@ -1974,6 +1974,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ps1)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ps1));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ps2)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ps2));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(qid)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(qid));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(qualname));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(query)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(query));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(queuetype)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(queuetype));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(quotetabs)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(quotetabs));

View file

@ -697,6 +697,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(ps1) STRUCT_FOR_ID(ps1)
STRUCT_FOR_ID(ps2) STRUCT_FOR_ID(ps2)
STRUCT_FOR_ID(qid) STRUCT_FOR_ID(qid)
STRUCT_FOR_ID(qualname)
STRUCT_FOR_ID(query) STRUCT_FOR_ID(query)
STRUCT_FOR_ID(queuetype) STRUCT_FOR_ID(queuetype)
STRUCT_FOR_ID(quotetabs) STRUCT_FOR_ID(quotetabs)

View file

@ -1972,6 +1972,7 @@ extern "C" {
INIT_ID(ps1), \ INIT_ID(ps1), \
INIT_ID(ps2), \ INIT_ID(ps2), \
INIT_ID(qid), \ INIT_ID(qid), \
INIT_ID(qualname), \
INIT_ID(query), \ INIT_ID(query), \
INIT_ID(queuetype), \ INIT_ID(queuetype), \
INIT_ID(quotetabs), \ INIT_ID(quotetabs), \

View file

@ -2576,6 +2576,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1); assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(qualname);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(query); string = &_Py_ID(query);
_PyUnicode_InternStatic(interp, &string); _PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));

View file

@ -8,6 +8,11 @@ from typing import (
Callable, TypeAliasType, TypeVar, TypeVarTuple, ParamSpec, Unpack, get_args, Callable, TypeAliasType, TypeVar, TypeVarTuple, ParamSpec, Unpack, get_args,
) )
type GlobalTypeAlias = int
def get_type_alias():
type TypeAliasInFunc = str
return TypeAliasInFunc
class TypeParamsInvalidTest(unittest.TestCase): class TypeParamsInvalidTest(unittest.TestCase):
def test_name_collisions(self): def test_name_collisions(self):
@ -70,6 +75,8 @@ class TypeParamsAccessTest(unittest.TestCase):
class TypeParamsAliasValueTest(unittest.TestCase): class TypeParamsAliasValueTest(unittest.TestCase):
type TypeAliasInClass = dict
def test_alias_value_01(self): def test_alias_value_01(self):
type TA1 = int type TA1 = int
@ -142,33 +149,67 @@ class TypeParamsAliasValueTest(unittest.TestCase):
self.assertIs(specialized2.__origin__, VeryGeneric) self.assertIs(specialized2.__origin__, VeryGeneric)
self.assertEqual(specialized2.__args__, (int, str, float, [bool, range])) self.assertEqual(specialized2.__args__, (int, str, float, [bool, range]))
def test___name__(self):
type TypeAliasLocal = GlobalTypeAlias
self.assertEqual(GlobalTypeAlias.__name__, 'GlobalTypeAlias')
self.assertEqual(get_type_alias().__name__, 'TypeAliasInFunc')
self.assertEqual(self.TypeAliasInClass.__name__, 'TypeAliasInClass')
self.assertEqual(TypeAliasLocal.__name__, 'TypeAliasLocal')
with self.assertRaisesRegex(
AttributeError,
"readonly attribute",
):
setattr(TypeAliasLocal, '__name__', 'TA')
def test___qualname__(self):
type TypeAliasLocal = GlobalTypeAlias
self.assertEqual(GlobalTypeAlias.__qualname__,
'GlobalTypeAlias')
self.assertEqual(get_type_alias().__qualname__,
'get_type_alias.<locals>.TypeAliasInFunc')
self.assertEqual(self.TypeAliasInClass.__qualname__,
'TypeParamsAliasValueTest.TypeAliasInClass')
self.assertEqual(TypeAliasLocal.__qualname__,
'TypeParamsAliasValueTest.test___qualname__.<locals>.TypeAliasLocal')
with self.assertRaisesRegex(
AttributeError,
"readonly attribute",
):
setattr(TypeAliasLocal, '__qualname__', 'TA')
def test_repr(self): def test_repr(self):
type Simple = int type Simple = int
type VeryGeneric[T, *Ts, **P] = Callable[P, tuple[T, *Ts]] self.assertEqual(repr(Simple), Simple.__qualname__)
self.assertEqual(repr(Simple), "Simple") type VeryGeneric[T, *Ts, **P] = Callable[P, tuple[T, *Ts]]
self.assertEqual(repr(VeryGeneric), "VeryGeneric") self.assertEqual(repr(VeryGeneric), VeryGeneric.__qualname__)
fullname = f"{VeryGeneric.__module__}.{VeryGeneric.__qualname__}"
self.assertEqual(repr(VeryGeneric[int, bytes, str, [float, object]]), self.assertEqual(repr(VeryGeneric[int, bytes, str, [float, object]]),
"VeryGeneric[int, bytes, str, [float, object]]") f"{fullname}[int, bytes, str, [float, object]]")
self.assertEqual(repr(VeryGeneric[int, []]), self.assertEqual(repr(VeryGeneric[int, []]),
"VeryGeneric[int, []]") f"{fullname}[int, []]")
self.assertEqual(repr(VeryGeneric[int, [VeryGeneric[int], list[str]]]), self.assertEqual(repr(VeryGeneric[int, [VeryGeneric[int], list[str]]]),
"VeryGeneric[int, [VeryGeneric[int], list[str]]]") f"{fullname}[int, [{fullname}[int], list[str]]]")
def test_recursive_repr(self): def test_recursive_repr(self):
type Recursive = Recursive type Recursive = Recursive
self.assertEqual(repr(Recursive), "Recursive") self.assertEqual(repr(Recursive), Recursive.__qualname__)
type X = list[Y] type X = list[Y]
type Y = list[X] type Y = list[X]
self.assertEqual(repr(X), "X") self.assertEqual(repr(X), X.__qualname__)
self.assertEqual(repr(Y), "Y") self.assertEqual(repr(Y), Y.__qualname__)
type GenericRecursive[X] = list[X | GenericRecursive[X]] type GenericRecursive[X] = list[X | GenericRecursive[X]]
self.assertEqual(repr(GenericRecursive), "GenericRecursive") self.assertEqual(repr(GenericRecursive), GenericRecursive.__qualname__)
self.assertEqual(repr(GenericRecursive[int]), "GenericRecursive[int]") fullname = f"{GenericRecursive.__module__}.{GenericRecursive.__qualname__}"
self.assertEqual(repr(GenericRecursive[int]), f"{fullname}[int]")
self.assertEqual(repr(GenericRecursive[GenericRecursive[int]]), self.assertEqual(repr(GenericRecursive[GenericRecursive[int]]),
"GenericRecursive[GenericRecursive[int]]") f"{fullname}[{fullname}[int]]")
def test_raising(self): def test_raising(self):
type MissingName = list[_My_X] type MissingName = list[_My_X]
@ -193,15 +234,25 @@ class TypeAliasConstructorTest(unittest.TestCase):
def test_basic(self): def test_basic(self):
TA = TypeAliasType("TA", int) TA = TypeAliasType("TA", int)
self.assertEqual(TA.__name__, "TA") self.assertEqual(TA.__name__, "TA")
self.assertEqual(TA.__qualname__, "TA")
self.assertIs(TA.__value__, int) self.assertIs(TA.__value__, int)
self.assertEqual(TA.__type_params__, ()) self.assertEqual(TA.__type_params__, ())
self.assertEqual(TA.__module__, __name__) self.assertEqual(TA.__module__, __name__)
def test_with_qualname(self):
TA = TypeAliasType("TA", str, qualname="Class.TA")
self.assertEqual(TA.__name__, "TA")
self.assertEqual(TA.__qualname__, "Class.TA")
self.assertIs(TA.__value__, str)
self.assertEqual(TA.__type_params__, ())
self.assertEqual(TA.__module__, __name__)
def test_attributes_with_exec(self): def test_attributes_with_exec(self):
ns = {} ns = {}
exec("type TA = int", ns, ns) exec("type TA = int", ns, ns)
TA = ns["TA"] TA = ns["TA"]
self.assertEqual(TA.__name__, "TA") self.assertEqual(TA.__name__, "TA")
self.assertEqual(TA.__qualname__, "TA")
self.assertIs(TA.__value__, int) self.assertIs(TA.__value__, int)
self.assertEqual(TA.__type_params__, ()) self.assertEqual(TA.__type_params__, ())
self.assertIs(TA.__module__, None) self.assertIs(TA.__module__, None)
@ -210,6 +261,7 @@ class TypeAliasConstructorTest(unittest.TestCase):
T = TypeVar("T") T = TypeVar("T")
TA = TypeAliasType("TA", list[T], type_params=(T,)) TA = TypeAliasType("TA", list[T], type_params=(T,))
self.assertEqual(TA.__name__, "TA") self.assertEqual(TA.__name__, "TA")
self.assertEqual(TA.__qualname__, "TA")
self.assertEqual(TA.__value__, list[T]) self.assertEqual(TA.__value__, list[T])
self.assertEqual(TA.__type_params__, (T,)) self.assertEqual(TA.__type_params__, (T,))
self.assertEqual(TA.__module__, __name__) self.assertEqual(TA.__module__, __name__)
@ -218,6 +270,7 @@ class TypeAliasConstructorTest(unittest.TestCase):
def test_not_generic(self): def test_not_generic(self):
TA = TypeAliasType("TA", list[int], type_params=()) TA = TypeAliasType("TA", list[int], type_params=())
self.assertEqual(TA.__name__, "TA") self.assertEqual(TA.__name__, "TA")
self.assertEqual(TA.__qualname__, "TA")
self.assertEqual(TA.__value__, list[int]) self.assertEqual(TA.__value__, list[int])
self.assertEqual(TA.__type_params__, ()) self.assertEqual(TA.__type_params__, ())
self.assertEqual(TA.__module__, __name__) self.assertEqual(TA.__module__, __name__)
@ -268,8 +321,9 @@ class TypeAliasConstructorTest(unittest.TestCase):
TypeAliasType("A", int, type_params=(T, 2)) TypeAliasType("A", int, type_params=(T, 2))
def test_keywords(self): def test_keywords(self):
TA = TypeAliasType(name="TA", value=int) TA = TypeAliasType(name="TA", value=int, type_params=(), qualname=None)
self.assertEqual(TA.__name__, "TA") self.assertEqual(TA.__name__, "TA")
self.assertEqual(TA.__qualname__, "TA")
self.assertIs(TA.__value__, int) self.assertIs(TA.__value__, int)
self.assertEqual(TA.__type_params__, ()) self.assertEqual(TA.__type_params__, ())
self.assertEqual(TA.__module__, __name__) self.assertEqual(TA.__module__, __name__)
@ -283,6 +337,8 @@ class TypeAliasConstructorTest(unittest.TestCase):
TypeAliasType("TA", list, ()) TypeAliasType("TA", list, ())
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
TypeAliasType("TA", list, type_params=42) TypeAliasType("TA", list, type_params=42)
with self.assertRaises(TypeError):
TypeAliasType("TA", list, qualname=range(5))
class TypeAliasTypeTest(unittest.TestCase): class TypeAliasTypeTest(unittest.TestCase):

View file

@ -0,0 +1,2 @@
Attribute ``__qualname__`` is added to :class:`typing.TypeAliasType`.
Patch by Mikhail Efimov.

View file

@ -688,14 +688,14 @@ typealias_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
} }
PyDoc_STRVAR(typealias_new__doc__, PyDoc_STRVAR(typealias_new__doc__,
"typealias(name, value, *, type_params=<unrepresentable>)\n" "typealias(name, value, *, type_params=<unrepresentable>, qualname=None)\n"
"--\n" "--\n"
"\n" "\n"
"Create a TypeAliasType."); "Create a TypeAliasType.");
static PyObject * static PyObject *
typealias_new_impl(PyTypeObject *type, PyObject *name, PyObject *value, typealias_new_impl(PyTypeObject *type, PyObject *name, PyObject *value,
PyObject *type_params); PyObject *type_params, PyObject *qualname);
static PyObject * static PyObject *
typealias_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) typealias_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
@ -703,7 +703,7 @@ typealias_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
PyObject *return_value = NULL; PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
#define NUM_KEYWORDS 3 #define NUM_KEYWORDS 4
static struct { static struct {
PyGC_Head _this_is_not_used; PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD PyObject_VAR_HEAD
@ -712,7 +712,7 @@ typealias_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
} _kwtuple = { } _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1, .ob_hash = -1,
.ob_item = { &_Py_ID(name), &_Py_ID(value), &_Py_ID(type_params), }, .ob_item = { &_Py_ID(name), &_Py_ID(value), &_Py_ID(type_params), &_Py_ID(qualname), },
}; };
#undef NUM_KEYWORDS #undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base) #define KWTUPLE (&_kwtuple.ob_base.ob_base)
@ -721,20 +721,21 @@ typealias_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
# define KWTUPLE NULL # define KWTUPLE NULL
#endif // !Py_BUILD_CORE #endif // !Py_BUILD_CORE
static const char * const _keywords[] = {"name", "value", "type_params", NULL}; static const char * const _keywords[] = {"name", "value", "type_params", "qualname", NULL};
static _PyArg_Parser _parser = { static _PyArg_Parser _parser = {
.keywords = _keywords, .keywords = _keywords,
.fname = "typealias", .fname = "typealias",
.kwtuple = KWTUPLE, .kwtuple = KWTUPLE,
}; };
#undef KWTUPLE #undef KWTUPLE
PyObject *argsbuf[3]; PyObject *argsbuf[4];
PyObject * const *fastargs; PyObject * const *fastargs;
Py_ssize_t nargs = PyTuple_GET_SIZE(args); Py_ssize_t nargs = PyTuple_GET_SIZE(args);
Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 2; Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 2;
PyObject *name; PyObject *name;
PyObject *value; PyObject *value;
PyObject *type_params = NULL; PyObject *type_params = NULL;
PyObject *qualname = NULL;
fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser,
/*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
@ -750,11 +751,17 @@ typealias_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
if (!noptargs) { if (!noptargs) {
goto skip_optional_kwonly; goto skip_optional_kwonly;
} }
type_params = fastargs[2]; if (fastargs[2]) {
type_params = fastargs[2];
if (!--noptargs) {
goto skip_optional_kwonly;
}
}
qualname = fastargs[3];
skip_optional_kwonly: skip_optional_kwonly:
return_value = typealias_new_impl(type, name, value, type_params); return_value = typealias_new_impl(type, name, value, type_params, qualname);
exit: exit:
return return_value; return return_value;
} }
/*[clinic end generated code: output=9dad71445e079303 input=a9049054013a1b77]*/ /*[clinic end generated code: output=67ab9a5d1869f2c9 input=a9049054013a1b77]*/

View file

@ -53,6 +53,7 @@ typedef struct {
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
PyObject *name; PyObject *name;
PyObject *qualname;
PyObject *type_params; PyObject *type_params;
PyObject *compute_value; PyObject *compute_value;
PyObject *value; PyObject *value;
@ -1858,6 +1859,7 @@ typealias_dealloc(PyObject *self)
_PyObject_GC_UNTRACK(self); _PyObject_GC_UNTRACK(self);
typealiasobject *ta = typealiasobject_CAST(self); typealiasobject *ta = typealiasobject_CAST(self);
Py_XDECREF(ta->name); Py_XDECREF(ta->name);
Py_XDECREF(ta->qualname);
Py_XDECREF(ta->type_params); Py_XDECREF(ta->type_params);
Py_XDECREF(ta->compute_value); Py_XDECREF(ta->compute_value);
Py_XDECREF(ta->value); Py_XDECREF(ta->value);
@ -1884,11 +1886,12 @@ static PyObject *
typealias_repr(PyObject *self) typealias_repr(PyObject *self)
{ {
typealiasobject *ta = (typealiasobject *)self; typealiasobject *ta = (typealiasobject *)self;
return Py_NewRef(ta->name); return Py_NewRef(ta->qualname);
} }
static PyMemberDef typealias_members[] = { static PyMemberDef typealias_members[] = {
{"__name__", _Py_T_OBJECT, offsetof(typealiasobject, name), Py_READONLY}, {"__name__", _Py_T_OBJECT, offsetof(typealiasobject, name), Py_READONLY},
{"__qualname__", _Py_T_OBJECT, offsetof(typealiasobject, qualname), Py_READONLY},
{0} {0}
}; };
@ -2003,7 +2006,7 @@ typealias_check_type_params(PyObject *type_params, int *err) {
} }
static PyObject * static PyObject *
typelias_convert_type_params(PyObject *type_params) typealias_convert_type_params(PyObject *type_params)
{ {
if ( if (
type_params == NULL type_params == NULL
@ -2018,14 +2021,15 @@ typelias_convert_type_params(PyObject *type_params)
} }
static typealiasobject * static typealiasobject *
typealias_alloc(PyObject *name, PyObject *type_params, PyObject *compute_value, typealias_alloc(PyObject *name, PyObject *qualname, PyObject *type_params,
PyObject *value, PyObject *module) PyObject *compute_value, PyObject *value, PyObject *module)
{ {
typealiasobject *ta = PyObject_GC_New(typealiasobject, &_PyTypeAlias_Type); typealiasobject *ta = PyObject_GC_New(typealiasobject, &_PyTypeAlias_Type);
if (ta == NULL) { if (ta == NULL) {
return NULL; return NULL;
} }
ta->name = Py_NewRef(name); ta->name = Py_NewRef(name);
ta->qualname = Py_NewRef(qualname);
ta->type_params = Py_XNewRef(type_params); ta->type_params = Py_XNewRef(type_params);
ta->compute_value = Py_XNewRef(compute_value); ta->compute_value = Py_XNewRef(compute_value);
ta->value = Py_XNewRef(value); ta->value = Py_XNewRef(value);
@ -2039,6 +2043,7 @@ typealias_traverse(PyObject *op, visitproc visit, void *arg)
{ {
typealiasobject *self = typealiasobject_CAST(op); typealiasobject *self = typealiasobject_CAST(op);
Py_VISIT(self->name); Py_VISIT(self->name);
Py_VISIT(self->qualname);
Py_VISIT(self->type_params); Py_VISIT(self->type_params);
Py_VISIT(self->compute_value); Py_VISIT(self->compute_value);
Py_VISIT(self->value); Py_VISIT(self->value);
@ -2051,6 +2056,7 @@ typealias_clear(PyObject *op)
{ {
typealiasobject *self = typealiasobject_CAST(op); typealiasobject *self = typealiasobject_CAST(op);
Py_CLEAR(self->name); Py_CLEAR(self->name);
Py_CLEAR(self->qualname);
Py_CLEAR(self->type_params); Py_CLEAR(self->type_params);
Py_CLEAR(self->compute_value); Py_CLEAR(self->compute_value);
Py_CLEAR(self->value); Py_CLEAR(self->value);
@ -2096,14 +2102,15 @@ typealias.__new__ as typealias_new
value: object value: object
* *
type_params: object = NULL type_params: object = NULL
qualname: object(c_default="NULL") = None
Create a TypeAliasType. Create a TypeAliasType.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
typealias_new_impl(PyTypeObject *type, PyObject *name, PyObject *value, typealias_new_impl(PyTypeObject *type, PyObject *name, PyObject *value,
PyObject *type_params) PyObject *type_params, PyObject *qualname)
/*[clinic end generated code: output=8920ce6bdff86f00 input=df163c34e17e1a35]*/ /*[clinic end generated code: output=b7f6d9f1c577cd9c input=cbec290f8c4886ef]*/
{ {
if (type_params != NULL && !PyTuple_Check(type_params)) { if (type_params != NULL && !PyTuple_Check(type_params)) {
PyErr_SetString(PyExc_TypeError, "type_params must be a tuple"); PyErr_SetString(PyExc_TypeError, "type_params must be a tuple");
@ -2120,8 +2127,19 @@ typealias_new_impl(PyTypeObject *type, PyObject *name, PyObject *value,
if (module == NULL) { if (module == NULL) {
return NULL; return NULL;
} }
PyObject *ta = (PyObject *)typealias_alloc(name, checked_params, NULL, value,
module); if (qualname == NULL || qualname == Py_None) {
// If qualname was not set directly, we use name instead.
qualname = name;
} else {
if (!PyUnicode_Check(qualname)) {
PyErr_SetString(PyExc_TypeError, "qualname must be a string");
return NULL;
}
}
PyObject *ta = (PyObject *)typealias_alloc(
name, qualname, checked_params, NULL, value, module);
Py_DECREF(module); Py_DECREF(module);
return ta; return ta;
} }
@ -2187,10 +2205,17 @@ _Py_make_typealias(PyThreadState* unused, PyObject *args)
assert(PyTuple_GET_SIZE(args) == 3); assert(PyTuple_GET_SIZE(args) == 3);
PyObject *name = PyTuple_GET_ITEM(args, 0); PyObject *name = PyTuple_GET_ITEM(args, 0);
assert(PyUnicode_Check(name)); assert(PyUnicode_Check(name));
PyObject *type_params = typelias_convert_type_params(PyTuple_GET_ITEM(args, 1)); PyObject *type_params = typealias_convert_type_params(PyTuple_GET_ITEM(args, 1));
PyObject *compute_value = PyTuple_GET_ITEM(args, 2); PyObject *compute_value = PyTuple_GET_ITEM(args, 2);
assert(PyFunction_Check(compute_value)); assert(PyFunction_Check(compute_value));
return (PyObject *)typealias_alloc(name, type_params, compute_value, NULL, NULL);
PyFunctionObject *compute_func = (PyFunctionObject *)compute_value;
PyCodeObject *code_obj = (PyCodeObject *)compute_func->func_code;
PyObject *qualname = code_obj->co_qualname;
assert(qualname != NULL);
return (PyObject *)typealias_alloc(
name, qualname, type_params, compute_value, NULL, NULL);
} }
PyDoc_STRVAR(generic_doc, PyDoc_STRVAR(generic_doc,