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 traceback
|
||||
import types
|
||||
import typing
|
||||
import unittest
|
||||
import warnings
|
||||
from contextlib import ExitStack
|
||||
|
@ -2485,6 +2486,17 @@ class TestType(unittest.TestCase):
|
|||
A.__qualname__ = b'B'
|
||||
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):
|
||||
for doc in 'x', '\xc4', '\U0001f40d', 'x\x00y', b'x', 42, None:
|
||||
A = type('A', (), {'__doc__': doc})
|
||||
|
|
|
@ -816,10 +816,11 @@ class TypeParamsTypeParamsDunder(unittest.TestCase):
|
|||
class ClassA[A]():
|
||||
pass
|
||||
ClassA.__type_params__ = ()
|
||||
params = ClassA.__type_params__
|
||||
"""
|
||||
|
||||
with self.assertRaisesRegex(AttributeError, "attribute '__type_params__' of 'type' objects is not writable"):
|
||||
run_code(code)
|
||||
ns = run_code(code)
|
||||
self.assertEqual(ns["params"], ())
|
||||
|
||||
def test_typeparams_dunder_function_01(self):
|
||||
def outer[A, B]():
|
||||
|
|
|
@ -6810,6 +6810,19 @@ class NamedTupleTests(BaseTestCase):
|
|||
with self.assertRaises(TypeError):
|
||||
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):
|
||||
# For backward compatibility, subscription works
|
||||
# on arbitrary NamedTuple types.
|
||||
|
@ -7220,6 +7233,20 @@ class TypedDictTests(BaseTestCase):
|
|||
{'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):
|
||||
class A(TypedDict, Generic[T]):
|
||||
a: T
|
||||
|
|
|
@ -1460,18 +1460,6 @@ type_get_annotations(PyTypeObject *type, void *context)
|
|||
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
|
||||
type_set_annotations(PyTypeObject *type, PyObject *value, void *context)
|
||||
{
|
||||
|
@ -1502,6 +1490,34 @@ type_set_annotations(PyTypeObject *type, PyObject *value, void *context)
|
|||
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]
|
||||
type.__instancecheck__ -> bool
|
||||
|
@ -1548,7 +1564,7 @@ static PyGetSetDef type_getsets[] = {
|
|||
{"__doc__", (getter)type_get_doc, (setter)type_set_doc, NULL},
|
||||
{"__text_signature__", (getter)type_get_text_signature, NULL, 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}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue