Skip to content

Commit 1ed8d03

Browse files
gh-87390: Fix starred tuple equality and pickling (GH-92337)
1 parent 354ab7a commit 1ed8d03

File tree

4 files changed

+31
-0
lines changed

4 files changed

+31
-0
lines changed

Include/internal/pycore_global_strings.h

+1
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ struct _Py_global_strings {
300300
STRUCT_FOR_ID(n_unnamed_fields)
301301
STRUCT_FOR_ID(name)
302302
STRUCT_FOR_ID(newlines)
303+
STRUCT_FOR_ID(next)
303304
STRUCT_FOR_ID(obj)
304305
STRUCT_FOR_ID(offset)
305306
STRUCT_FOR_ID(onceregistry)

Include/internal/pycore_runtime_init.h

+1
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,7 @@ extern "C" {
923923
INIT_ID(n_unnamed_fields), \
924924
INIT_ID(name), \
925925
INIT_ID(newlines), \
926+
INIT_ID(next), \
926927
INIT_ID(obj), \
927928
INIT_ID(offset), \
928929
INIT_ID(onceregistry), \

Lib/test/test_genericalias.py

+3
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,8 @@ def test_equality(self):
358358
self.assertNotEqual(dict[str, int], dict[str, str])
359359
self.assertNotEqual(list, list[int])
360360
self.assertNotEqual(list[int], list)
361+
self.assertNotEqual(list[int], tuple[int])
362+
self.assertNotEqual((*tuple[int],)[0], tuple[int])
361363

362364
def test_isinstance(self):
363365
self.assertTrue(isinstance([], list))
@@ -394,6 +396,7 @@ def test_pickle(self):
394396
self.assertEqual(loaded.__origin__, alias.__origin__)
395397
self.assertEqual(loaded.__args__, alias.__args__)
396398
self.assertEqual(loaded.__parameters__, alias.__parameters__)
399+
self.assertEqual(type(loaded), type(alias))
397400

398401
def test_copy(self):
399402
class X(list):

Objects/genericaliasobject.c

+26
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,9 @@ ga_richcompare(PyObject *a, PyObject *b, int op)
567567

568568
gaobject *aa = (gaobject *)a;
569569
gaobject *bb = (gaobject *)b;
570+
if (aa->starred != bb->starred) {
571+
Py_RETURN_FALSE;
572+
}
570573
int eq = PyObject_RichCompareBool(aa->origin, bb->origin, Py_EQ);
571574
if (eq < 0) {
572575
return NULL;
@@ -604,6 +607,16 @@ static PyObject *
604607
ga_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
605608
{
606609
gaobject *alias = (gaobject *)self;
610+
if (alias->starred) {
611+
PyObject *tmp = Py_GenericAlias(alias->origin, alias->args);
612+
if (tmp != NULL) {
613+
Py_SETREF(tmp, PyObject_GetIter(tmp));
614+
}
615+
if (tmp == NULL) {
616+
return NULL;
617+
}
618+
return Py_BuildValue("N(N)", _PyEval_GetBuiltin(&_Py_ID(next)), tmp);
619+
}
607620
return Py_BuildValue("O(OO)", Py_TYPE(alias),
608621
alias->origin, alias->args);
609622
}
@@ -775,6 +788,18 @@ ga_iter_clear(PyObject *self) {
775788
return 0;
776789
}
777790

791+
static PyObject *
792+
ga_iter_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
793+
{
794+
gaiterobject *gi = (gaiterobject *)self;
795+
return Py_BuildValue("N(O)", _PyEval_GetBuiltin(&_Py_ID(iter)), gi->obj);
796+
}
797+
798+
static PyMethodDef ga_iter_methods[] = {
799+
{"__reduce__", ga_iter_reduce, METH_NOARGS},
800+
{0}
801+
};
802+
778803
// gh-91632: _Py_GenericAliasIterType is exported to be cleared
779804
// in _PyTypes_FiniTypes.
780805
PyTypeObject _Py_GenericAliasIterType = {
@@ -784,6 +809,7 @@ PyTypeObject _Py_GenericAliasIterType = {
784809
.tp_iter = PyObject_SelfIter,
785810
.tp_iternext = (iternextfunc)ga_iternext,
786811
.tp_traverse = (traverseproc)ga_iter_traverse,
812+
.tp_methods = ga_iter_methods,
787813
.tp_dealloc = (destructor)ga_iter_dealloc,
788814
.tp_clear = (inquiry)ga_iter_clear,
789815
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,

0 commit comments

Comments
 (0)