summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2023-07-01 00:32:44 (GMT)
committerGitHub <noreply@github.com>2023-07-01 00:32:44 (GMT)
commitc4298d5c648ba79d0a3dbf16e9aa8a6011802470 (patch)
tree13acfcbba0fd9f0d8bc8b4380b5cdf5943c96589
parent0616c83f57a8d2fd62d12ddaba987052c5015260 (diff)
downloadcpython-c4298d5c648ba79d0a3dbf16e9aa8a6011802470.zip
cpython-c4298d5c648ba79d0a3dbf16e9aa8a6011802470.tar.gz
cpython-c4298d5c648ba79d0a3dbf16e9aa8a6011802470.tar.bz2
[3.12] gh-105486: Change the `repr` of `ParamSpec` list of args in `GenericAlias` (GH-105488) (#106297)
gh-105486: Change the `repr` of `ParamSpec` list of args in `GenericAlias` (GH-105488) (cherry picked from commit eb7d6e7ad844955f9af88707d296e003c7ce4394) Co-authored-by: Nikita Sobolev <mail@sobolevn.me>
-rw-r--r--Lib/test/test_genericalias.py8
-rw-r--r--Lib/test/test_type_aliases.py16
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-10-15.gh-issue-105486.dev-WS.rst1
-rw-r--r--Objects/genericaliasobject.c38
4 files changed, 62 insertions, 1 deletions
diff --git a/Lib/test/test_genericalias.py b/Lib/test/test_genericalias.py
index 24d4216..bf600a0 100644
--- a/Lib/test/test_genericalias.py
+++ b/Lib/test/test_genericalias.py
@@ -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)
diff --git a/Lib/test/test_type_aliases.py b/Lib/test/test_type_aliases.py
index b9b2444..0ce97f5 100644
--- a/Lib/test/test_type_aliases.py
+++ b/Lib/test/test_type_aliases.py
@@ -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
index 0000000..9f735db
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-10-15.gh-issue-105486.dev-WS.rst
@@ -0,0 +1 @@
+Change the repr of ``ParamSpec`` list of args in ``types.GenericAlias``.
diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c
index 888cb16..117b4e8 100644
--- a/Objects/genericaliasobject.c
+++ b/Objects/genericaliasobject.c
@@ -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;
}
}