mirror of https://github.com/python/cpython
gh-104600: Make type.__type_params__ writable (#104634)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
parent
dbe171e609
commit
8f1f3b9abd
|
@ -18,6 +18,7 @@ import re
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
import types
|
import types
|
||||||
|
import typing
|
||||||
import unittest
|
import unittest
|
||||||
import warnings
|
import warnings
|
||||||
from contextlib import ExitStack
|
from contextlib import ExitStack
|
||||||
|
@ -2485,6 +2486,17 @@ class TestType(unittest.TestCase):
|
||||||
A.__qualname__ = b'B'
|
A.__qualname__ = b'B'
|
||||||
self.assertEqual(A.__qualname__, 'D.E')
|
self.assertEqual(A.__qualname__, 'D.E')
|
||||||
|
|
||||||
|
def test_type_typeparams(self):
|
||||||
|
class A[T]:
|
||||||
|
pass
|
||||||
|
T, = A.__type_params__
|
||||||
|
self.assertIsInstance(T, typing.TypeVar)
|
||||||
|
A.__type_params__ = "whatever"
|
||||||
|
self.assertEqual(A.__type_params__, "whatever")
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
del A.__type_params__
|
||||||
|
self.assertEqual(A.__type_params__, "whatever")
|
||||||
|
|
||||||
def test_type_doc(self):
|
def test_type_doc(self):
|
||||||
for doc in 'x', '\xc4', '\U0001f40d', 'x\x00y', b'x', 42, None:
|
for doc in 'x', '\xc4', '\U0001f40d', 'x\x00y', b'x', 42, None:
|
||||||
A = type('A', (), {'__doc__': doc})
|
A = type('A', (), {'__doc__': doc})
|
||||||
|
|
|
@ -816,10 +816,11 @@ class TypeParamsTypeParamsDunder(unittest.TestCase):
|
||||||
class ClassA[A]():
|
class ClassA[A]():
|
||||||
pass
|
pass
|
||||||
ClassA.__type_params__ = ()
|
ClassA.__type_params__ = ()
|
||||||
|
params = ClassA.__type_params__
|
||||||
"""
|
"""
|
||||||
|
|
||||||
with self.assertRaisesRegex(AttributeError, "attribute '__type_params__' of 'type' objects is not writable"):
|
ns = run_code(code)
|
||||||
run_code(code)
|
self.assertEqual(ns["params"], ())
|
||||||
|
|
||||||
def test_typeparams_dunder_function_01(self):
|
def test_typeparams_dunder_function_01(self):
|
||||||
def outer[A, B]():
|
def outer[A, B]():
|
||||||
|
|
|
@ -6810,6 +6810,19 @@ class NamedTupleTests(BaseTestCase):
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
G[int, str]
|
G[int, str]
|
||||||
|
|
||||||
|
def test_generic_pep695(self):
|
||||||
|
class X[T](NamedTuple):
|
||||||
|
x: T
|
||||||
|
T, = X.__type_params__
|
||||||
|
self.assertIsInstance(T, TypeVar)
|
||||||
|
self.assertEqual(T.__name__, 'T')
|
||||||
|
self.assertEqual(X.__bases__, (tuple, Generic))
|
||||||
|
self.assertEqual(X.__orig_bases__, (NamedTuple, Generic[T]))
|
||||||
|
self.assertEqual(X.__mro__, (X, tuple, Generic, object))
|
||||||
|
self.assertEqual(X.__parameters__, (T,))
|
||||||
|
self.assertEqual(X[str].__args__, (str,))
|
||||||
|
self.assertEqual(X[str].__parameters__, ())
|
||||||
|
|
||||||
def test_non_generic_subscript(self):
|
def test_non_generic_subscript(self):
|
||||||
# For backward compatibility, subscription works
|
# For backward compatibility, subscription works
|
||||||
# on arbitrary NamedTuple types.
|
# on arbitrary NamedTuple types.
|
||||||
|
@ -7220,6 +7233,20 @@ class TypedDictTests(BaseTestCase):
|
||||||
{'a': typing.Optional[T], 'b': int, 'c': str}
|
{'a': typing.Optional[T], 'b': int, 'c': str}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_pep695_generic_typeddict(self):
|
||||||
|
class A[T](TypedDict):
|
||||||
|
a: T
|
||||||
|
|
||||||
|
T, = A.__type_params__
|
||||||
|
self.assertIsInstance(T, TypeVar)
|
||||||
|
self.assertEqual(T.__name__, 'T')
|
||||||
|
self.assertEqual(A.__bases__, (Generic, dict))
|
||||||
|
self.assertEqual(A.__orig_bases__, (TypedDict, Generic[T]))
|
||||||
|
self.assertEqual(A.__mro__, (A, Generic, dict, object))
|
||||||
|
self.assertEqual(A.__parameters__, (T,))
|
||||||
|
self.assertEqual(A[str].__parameters__, ())
|
||||||
|
self.assertEqual(A[str].__args__, (str,))
|
||||||
|
|
||||||
def test_generic_inheritance(self):
|
def test_generic_inheritance(self):
|
||||||
class A(TypedDict, Generic[T]):
|
class A(TypedDict, Generic[T]):
|
||||||
a: T
|
a: T
|
||||||
|
|
|
@ -1460,18 +1460,6 @@ type_get_annotations(PyTypeObject *type, void *context)
|
||||||
return annotations;
|
return annotations;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
type_get_type_params(PyTypeObject *type, void *context)
|
|
||||||
{
|
|
||||||
PyObject *params = PyDict_GetItem(lookup_tp_dict(type), &_Py_ID(__type_params__));
|
|
||||||
|
|
||||||
if (params) {
|
|
||||||
return Py_NewRef(params);
|
|
||||||
}
|
|
||||||
|
|
||||||
return PyTuple_New(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
type_set_annotations(PyTypeObject *type, PyObject *value, void *context)
|
type_set_annotations(PyTypeObject *type, PyObject *value, void *context)
|
||||||
{
|
{
|
||||||
|
@ -1502,6 +1490,34 @@ type_set_annotations(PyTypeObject *type, PyObject *value, void *context)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
type_get_type_params(PyTypeObject *type, void *context)
|
||||||
|
{
|
||||||
|
PyObject *params = PyDict_GetItem(lookup_tp_dict(type), &_Py_ID(__type_params__));
|
||||||
|
|
||||||
|
if (params) {
|
||||||
|
return Py_NewRef(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
return PyTuple_New(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
type_set_type_params(PyTypeObject *type, PyObject *value, void *context)
|
||||||
|
{
|
||||||
|
if (!check_set_special_type_attr(type, value, "__type_params__")) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *dict = lookup_tp_dict(type);
|
||||||
|
int result = PyDict_SetItem(dict, &_Py_ID(__type_params__), value);
|
||||||
|
|
||||||
|
if (result == 0) {
|
||||||
|
PyType_Modified(type);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
type.__instancecheck__ -> bool
|
type.__instancecheck__ -> bool
|
||||||
|
@ -1548,7 +1564,7 @@ static PyGetSetDef type_getsets[] = {
|
||||||
{"__doc__", (getter)type_get_doc, (setter)type_set_doc, NULL},
|
{"__doc__", (getter)type_get_doc, (setter)type_set_doc, NULL},
|
||||||
{"__text_signature__", (getter)type_get_text_signature, NULL, NULL},
|
{"__text_signature__", (getter)type_get_text_signature, NULL, NULL},
|
||||||
{"__annotations__", (getter)type_get_annotations, (setter)type_set_annotations, NULL},
|
{"__annotations__", (getter)type_get_annotations, (setter)type_set_annotations, NULL},
|
||||||
{"__type_params__", (getter)type_get_type_params, NULL, NULL},
|
{"__type_params__", (getter)type_get_type_params, (setter)type_set_type_params, NULL},
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue