]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-105486: Change the `repr` of `ParamSpec` list of args in `GenericAlias` (#105488)
authorNikita Sobolev <mail@sobolevn.me>
Sat, 1 Jul 2023 00:04:50 +0000 (03:04 +0300)
committerGitHub <noreply@github.com>
Sat, 1 Jul 2023 00:04:50 +0000 (00:04 +0000)
Lib/test/test_genericalias.py
Lib/test/test_type_aliases.py
Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-10-15.gh-issue-105486.dev-WS.rst [new file with mode: 0644]
Objects/genericaliasobject.c

index 24d4216417521ceeabe1ff18f14670f400a4d8e2..bf600a0f4d1834537652882c02074937f94cfd1f 100644 (file)
@@ -209,6 +209,9 @@ class BaseTest(unittest.TestCase):
     def test_repr(self):
         class MyList(list):
             pass
+        class MyGeneric:
+            __class_getitem__ = classmethod(GenericAlias)
+
         self.assertEqual(repr(list[str]), 'list[str]')
         self.assertEqual(repr(list[()]), 'list[()]')
         self.assertEqual(repr(tuple[int, ...]), 'tuple[int, ...]')
@@ -221,6 +224,11 @@ class BaseTest(unittest.TestCase):
         self.assertTrue(repr(MyList[int]).endswith('.BaseTest.test_repr.<locals>.MyList[int]'))
         self.assertEqual(repr(list[str]()), '[]')  # instances should keep their normal repr
 
+        # gh-105488
+        self.assertTrue(repr(MyGeneric[int]).endswith('MyGeneric[int]'))
+        self.assertTrue(repr(MyGeneric[[]]).endswith('MyGeneric[[]]'))
+        self.assertTrue(repr(MyGeneric[[int, str]]).endswith('MyGeneric[[int, str]]'))
+
     def test_exposed_type(self):
         import types
         a = types.GenericAlias(list, int)
index b9b24448e83d8ee5eb82bc364f1416098979c90c..0ce97f57de6860961bee2c07696daddd0dc9cb9b 100644 (file)
@@ -142,7 +142,16 @@ class TypeParamsAliasValueTest(unittest.TestCase):
 
     def test_repr(self):
         type Simple = int
+        type VeryGeneric[T, *Ts, **P] = Callable[P, tuple[T, *Ts]]
+
         self.assertEqual(repr(Simple), "Simple")
+        self.assertEqual(repr(VeryGeneric), "VeryGeneric")
+        self.assertEqual(repr(VeryGeneric[int, bytes, str, [float, object]]),
+                         "VeryGeneric[int, bytes, str, [float, object]]")
+        self.assertEqual(repr(VeryGeneric[int, []]),
+                         "VeryGeneric[int, []]")
+        self.assertEqual(repr(VeryGeneric[int, [VeryGeneric[int], list[str]]]),
+                         "VeryGeneric[int, [VeryGeneric[int], list[str]]]")
 
     def test_recursive_repr(self):
         type Recursive = Recursive
@@ -151,6 +160,13 @@ class TypeParamsAliasValueTest(unittest.TestCase):
         type X = list[Y]
         type Y = list[X]
         self.assertEqual(repr(X), "X")
+        self.assertEqual(repr(Y), "Y")
+
+        type GenericRecursive[X] = list[X | GenericRecursive[X]]
+        self.assertEqual(repr(GenericRecursive), "GenericRecursive")
+        self.assertEqual(repr(GenericRecursive[int]), "GenericRecursive[int]")
+        self.assertEqual(repr(GenericRecursive[GenericRecursive[int]]),
+                         "GenericRecursive[GenericRecursive[int]]")
 
 
 class TypeAliasConstructorTest(unittest.TestCase):
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-10-15.gh-issue-105486.dev-WS.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-10-15.gh-issue-105486.dev-WS.rst
new file mode 100644 (file)
index 0000000..9f735db
--- /dev/null
@@ -0,0 +1 @@
+Change the repr of ``ParamSpec`` list of args in ``types.GenericAlias``.
index 888cb16edd1b460b02e4feaf319a3b579eaefc65..117b4e8dfb960ae17c80b970a7714b25def62ad3 100644 (file)
@@ -121,6 +121,36 @@ done:
     return err;
 }
 
+static int
+ga_repr_items_list(_PyUnicodeWriter *writer, PyObject *p)
+{
+    assert(PyList_CheckExact(p));
+
+    Py_ssize_t len = PyList_GET_SIZE(p);
+
+    if (_PyUnicodeWriter_WriteASCIIString(writer, "[", 1) < 0) {
+        return -1;
+    }
+
+    for (Py_ssize_t i = 0; i < len; i++) {
+        if (i > 0) {
+            if (_PyUnicodeWriter_WriteASCIIString(writer, ", ", 2) < 0) {
+                return -1;
+            }
+        }
+        PyObject *item = PyList_GET_ITEM(p, i);
+        if (ga_repr_item(writer, item) < 0) {
+            return -1;
+        }
+    }
+
+    if (_PyUnicodeWriter_WriteASCIIString(writer, "]", 1) < 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
 static PyObject *
 ga_repr(PyObject *self)
 {
@@ -148,7 +178,13 @@ ga_repr(PyObject *self)
             }
         }
         PyObject *p = PyTuple_GET_ITEM(alias->args, i);
-        if (ga_repr_item(&writer, p) < 0) {
+        if (PyList_CheckExact(p)) {
+            // Looks like we are working with ParamSpec's list of type args:
+            if (ga_repr_items_list(&writer, p) < 0) {
+                goto error;
+            }
+        }
+        else if (ga_repr_item(&writer, p) < 0) {
             goto error;
         }
     }