Callable, TypeAliasType, TypeVar, TypeVarTuple, ParamSpec, Unpack, get_args,
)
+type GlobalTypeAlias = int
+
+def get_type_alias():
+ type TypeAliasInFunc = str
+ return TypeAliasInFunc
class TypeParamsInvalidTest(unittest.TestCase):
def test_name_collisions(self):
class TypeParamsAliasValueTest(unittest.TestCase):
+ type TypeAliasInClass = dict
+
def test_alias_value_01(self):
type TA1 = int
self.assertIs(specialized2.__origin__, VeryGeneric)
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):
type Simple = int
- type VeryGeneric[T, *Ts, **P] = Callable[P, tuple[T, *Ts]]
+ self.assertEqual(repr(Simple), Simple.__qualname__)
- self.assertEqual(repr(Simple), "Simple")
- self.assertEqual(repr(VeryGeneric), "VeryGeneric")
+ type VeryGeneric[T, *Ts, **P] = Callable[P, tuple[T, *Ts]]
+ self.assertEqual(repr(VeryGeneric), VeryGeneric.__qualname__)
+ fullname = f"{VeryGeneric.__module__}.{VeryGeneric.__qualname__}"
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, []]),
- "VeryGeneric[int, []]")
+ f"{fullname}[int, []]")
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):
type Recursive = Recursive
- self.assertEqual(repr(Recursive), "Recursive")
+ self.assertEqual(repr(Recursive), Recursive.__qualname__)
type X = list[Y]
type Y = list[X]
- self.assertEqual(repr(X), "X")
- self.assertEqual(repr(Y), "Y")
+ self.assertEqual(repr(X), X.__qualname__)
+ self.assertEqual(repr(Y), Y.__qualname__)
type GenericRecursive[X] = list[X | GenericRecursive[X]]
- self.assertEqual(repr(GenericRecursive), "GenericRecursive")
- self.assertEqual(repr(GenericRecursive[int]), "GenericRecursive[int]")
+ self.assertEqual(repr(GenericRecursive), GenericRecursive.__qualname__)
+ fullname = f"{GenericRecursive.__module__}.{GenericRecursive.__qualname__}"
+ self.assertEqual(repr(GenericRecursive[int]), f"{fullname}[int]")
self.assertEqual(repr(GenericRecursive[GenericRecursive[int]]),
- "GenericRecursive[GenericRecursive[int]]")
+ f"{fullname}[{fullname}[int]]")
def test_raising(self):
type MissingName = list[_My_X]
def test_basic(self):
TA = TypeAliasType("TA", int)
self.assertEqual(TA.__name__, "TA")
+ self.assertEqual(TA.__qualname__, "TA")
self.assertIs(TA.__value__, int)
self.assertEqual(TA.__type_params__, ())
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):
ns = {}
exec("type TA = int", ns, ns)
TA = ns["TA"]
self.assertEqual(TA.__name__, "TA")
+ self.assertEqual(TA.__qualname__, "TA")
self.assertIs(TA.__value__, int)
self.assertEqual(TA.__type_params__, ())
self.assertIs(TA.__module__, None)
T = TypeVar("T")
TA = TypeAliasType("TA", list[T], type_params=(T,))
self.assertEqual(TA.__name__, "TA")
+ self.assertEqual(TA.__qualname__, "TA")
self.assertEqual(TA.__value__, list[T])
self.assertEqual(TA.__type_params__, (T,))
self.assertEqual(TA.__module__, __name__)
def test_not_generic(self):
TA = TypeAliasType("TA", list[int], type_params=())
self.assertEqual(TA.__name__, "TA")
+ self.assertEqual(TA.__qualname__, "TA")
self.assertEqual(TA.__value__, list[int])
self.assertEqual(TA.__type_params__, ())
self.assertEqual(TA.__module__, __name__)
TypeAliasType("A", int, type_params=(T, 2))
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.__qualname__, "TA")
self.assertIs(TA.__value__, int)
self.assertEqual(TA.__type_params__, ())
self.assertEqual(TA.__module__, __name__)
TypeAliasType("TA", list, ())
with self.assertRaises(TypeError):
TypeAliasType("TA", list, type_params=42)
+ with self.assertRaises(TypeError):
+ TypeAliasType("TA", list, qualname=range(5))
class TypeAliasTypeTest(unittest.TestCase):
}
PyDoc_STRVAR(typealias_new__doc__,
-"typealias(name, value, *, type_params=<unrepresentable>)\n"
+"typealias(name, value, *, type_params=<unrepresentable>, qualname=None)\n"
"--\n"
"\n"
"Create a TypeAliasType.");
static PyObject *
typealias_new_impl(PyTypeObject *type, PyObject *name, PyObject *value,
- PyObject *type_params);
+ PyObject *type_params, PyObject *qualname);
static PyObject *
typealias_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 3
+ #define NUM_KEYWORDS 4
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.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
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
# define KWTUPLE NULL
#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 = {
.keywords = _keywords,
.fname = "typealias",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[3];
+ PyObject *argsbuf[4];
PyObject * const *fastargs;
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 2;
PyObject *name;
PyObject *value;
PyObject *type_params = NULL;
+ PyObject *qualname = NULL;
fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser,
/*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
if (!noptargs) {
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:
- return_value = typealias_new_impl(type, name, value, type_params);
+ return_value = typealias_new_impl(type, name, value, type_params, qualname);
exit:
return return_value;
}
-/*[clinic end generated code: output=9dad71445e079303 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=67ab9a5d1869f2c9 input=a9049054013a1b77]*/
typedef struct {
PyObject_HEAD
PyObject *name;
+ PyObject *qualname;
PyObject *type_params;
PyObject *compute_value;
PyObject *value;
_PyObject_GC_UNTRACK(self);
typealiasobject *ta = typealiasobject_CAST(self);
Py_XDECREF(ta->name);
+ Py_XDECREF(ta->qualname);
Py_XDECREF(ta->type_params);
Py_XDECREF(ta->compute_value);
Py_XDECREF(ta->value);
typealias_repr(PyObject *self)
{
typealiasobject *ta = (typealiasobject *)self;
- return Py_NewRef(ta->name);
+ return Py_NewRef(ta->qualname);
}
static PyMemberDef typealias_members[] = {
{"__name__", _Py_T_OBJECT, offsetof(typealiasobject, name), Py_READONLY},
+ {"__qualname__", _Py_T_OBJECT, offsetof(typealiasobject, qualname), Py_READONLY},
{0}
};
}
static PyObject *
-typelias_convert_type_params(PyObject *type_params)
+typealias_convert_type_params(PyObject *type_params)
{
if (
type_params == NULL
}
static typealiasobject *
-typealias_alloc(PyObject *name, PyObject *type_params, PyObject *compute_value,
- PyObject *value, PyObject *module)
+typealias_alloc(PyObject *name, PyObject *qualname, PyObject *type_params,
+ PyObject *compute_value, PyObject *value, PyObject *module)
{
typealiasobject *ta = PyObject_GC_New(typealiasobject, &_PyTypeAlias_Type);
if (ta == NULL) {
return NULL;
}
ta->name = Py_NewRef(name);
+ ta->qualname = Py_NewRef(qualname);
ta->type_params = Py_XNewRef(type_params);
ta->compute_value = Py_XNewRef(compute_value);
ta->value = Py_XNewRef(value);
{
typealiasobject *self = typealiasobject_CAST(op);
Py_VISIT(self->name);
+ Py_VISIT(self->qualname);
Py_VISIT(self->type_params);
Py_VISIT(self->compute_value);
Py_VISIT(self->value);
{
typealiasobject *self = typealiasobject_CAST(op);
Py_CLEAR(self->name);
+ Py_CLEAR(self->qualname);
Py_CLEAR(self->type_params);
Py_CLEAR(self->compute_value);
Py_CLEAR(self->value);
value: object
*
type_params: object = NULL
+ qualname: object(c_default="NULL") = None
Create a TypeAliasType.
[clinic start generated code]*/
static PyObject *
typealias_new_impl(PyTypeObject *type, PyObject *name, PyObject *value,
- PyObject *type_params)
-/*[clinic end generated code: output=8920ce6bdff86f00 input=df163c34e17e1a35]*/
+ PyObject *type_params, PyObject *qualname)
+/*[clinic end generated code: output=b7f6d9f1c577cd9c input=cbec290f8c4886ef]*/
{
if (type_params != NULL && !PyTuple_Check(type_params)) {
PyErr_SetString(PyExc_TypeError, "type_params must be a tuple");
if (module == 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);
return ta;
}
assert(PyTuple_GET_SIZE(args) == 3);
PyObject *name = PyTuple_GET_ITEM(args, 0);
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);
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,