Skip to content

Commit

Permalink
[3.12] gh-105486: Change the repr of ParamSpec list of args in `G…
Browse files Browse the repository at this point in the history
…enericAlias` (GH-105488) (#106297)

gh-105486: Change the `repr` of `ParamSpec` list of args in `GenericAlias` (GH-105488)
(cherry picked from commit eb7d6e7)

Co-authored-by: Nikita Sobolev <mail@sobolevn.me>
  • Loading branch information
miss-islington and sobolevn committed Jul 1, 2023
1 parent 0616c83 commit c4298d5
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 1 deletion.
8 changes: 8 additions & 0 deletions Lib/test/test_genericalias.py
Expand Up @@ -209,6 +209,9 @@ class MyList(list):
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, ...]')
Expand All @@ -221,6 +224,11 @@ class MyList(list):
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)
Expand Down
16 changes: 16 additions & 0 deletions Lib/test/test_type_aliases.py
Expand Up @@ -142,7 +142,16 @@ def test_subscripting(self):

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
Expand All @@ -151,6 +160,13 @@ def test_recursive_repr(self):
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):
Expand Down
@@ -0,0 +1 @@
Change the repr of ``ParamSpec`` list of args in ``types.GenericAlias``.
38 changes: 37 additions & 1 deletion Objects/genericaliasobject.c
Expand Up @@ -121,6 +121,36 @@ ga_repr_item(_PyUnicodeWriter *writer, PyObject *p)
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)
{
Expand Down Expand Up @@ -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;
}
}
Expand Down

0 comments on commit c4298d5

Please sign in to comment.