summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_builtin.py12
-rw-r--r--Lib/test/test_type_params.py5
-rw-r--r--Lib/test/test_typing.py27
-rw-r--r--Objects/typeobject.c42
4 files changed, 71 insertions, 15 deletions
diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py
index 821710a..1257b52 100644
--- a/Lib/test/test_builtin.py
+++ b/Lib/test/test_builtin.py
@@ -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})
diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py
index d4f5de5..7b7b612 100644
--- a/Lib/test/test_type_params.py
+++ b/Lib/test/test_type_params.py
@@ -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]():
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 450c859..6459fa3 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -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
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 624dc63..2fbcafe 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -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}
};