-
-
Notifications
You must be signed in to change notification settings - Fork 31.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gh-87390: Fix starred tuple equality and pickling #92249
Conversation
b808ffd
to
335747d
Compare
I think this is worth a NEWS entry; it's been a while since we put the rest of this code into main. I'll review the PR now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I'm a little unhappy about making unpacked
a public argument to the constructor, but I'm not sure how else we'd get pickling to work.
Co-authored-by: Jelle Zijlstra <[email protected]>
I've added a NEWS entry for this specific change, but just to double check - were you thinking of this specific change, or the rest of the PEP 646-related changes we made to |
Just for this change (the PR title would be good as a NEWS entry too). |
"must be a bool (since it's a flag controlling " | ||
"whether the alias is unpacked)"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"must be a bool (since it's a flag controlling " | |
"whether the alias is unpacked)"); | |
"must be a bool"); |
We don't need the explanation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work! We're pretty close.
PyObject *starred = PyBool_FromLong(alias->starred); | ||
PyObject *value = Py_BuildValue("O(OOO)", Py_TYPE(alias), | ||
alias->origin, alias->args, starred); | ||
// Avoid double increment of reference count on Py_True/Py_False - once from | ||
// PyBool_FromLong, and once from Py_BuildValue. | ||
Py_CLEAR(starred); | ||
return value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about:
PyObject *starred = PyBool_FromLong(alias->starred); | |
PyObject *value = Py_BuildValue("O(OOO)", Py_TYPE(alias), | |
alias->origin, alias->args, starred); | |
// Avoid double increment of reference count on Py_True/Py_False - once from | |
// PyBool_FromLong, and once from Py_BuildValue. | |
Py_CLEAR(starred); | |
return value; | |
PyObject *starred = alias->starred ? Py_True : Py_False; | |
return Py_BuildValue("O(OOO)", Py_TYPE(alias), | |
alias->origin, alias->args, starred); | |
BTW, if you don't want to use the code above, you can avoid the double incref by using the format string O(OON)
. N
doesn't incref. https://docs.python.org/3/c-api/arg.html#c.Py_BuildValue
@@ -718,16 +727,33 @@ ga_new(PyTypeObject *type, PyObject *args, PyObject *kwds) | |||
if (!_PyArg_NoKeywords("GenericAlias", kwds)) { | |||
return NULL; | |||
} | |||
if (!_PyArg_CheckPositional("GenericAlias", PyTuple_GET_SIZE(args), 2, 2)) { | |||
if (!_PyArg_CheckPositional("GenericAlias", PyTuple_GET_SIZE(args), 2, 3)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please update the creation signature in the docs https://docs.python.org/3/library/types.html#types.GenericAlias.
Also, this doesn't break backwards compatibility right? IIUC, the two-argument form will still work.
PyObject *origin = PyTuple_GET_ITEM(args, 0); | ||
PyObject *arguments = PyTuple_GET_ITEM(args, 1); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code has gotten complex enough that I recommend using https://docs.python.org/3/c-api/arg.html#c.PyArg_ParseTuple or https://docs.python.org/3/c-api/arg.html#c.PyArg_UnpackTuple instead to parse our arguments for us.
The format value list is on that page. But off the top of my head, it should be OO|O:GenericAlias
. Then you keep your bool checking/error raising code below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Argument clinic can also be used here.
"whether the alias is unpacked)"); | ||
return NULL; | ||
} | ||
starred = PyLong_AsLong(py_starred); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm surprised you don't need to cast to (bool) here (or maybe it's implicit, I don't remember how C treats this).
Azure pipelines patcheck fail is unrelated, I will fix it on main. |
Nevermind, it seems that 65f88a6 fixed the whitespace issues, so this just needs updating from main. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not like an idea about extending GenericAlias()
with the third parameter. It is a public API.
I'll provide an alternate PR.
See #92337. |
Looks like this can be closed since the alternative was already merged. |
Hilariously, before this PR, it turned out that
*tuple[int]
was equal totuple[int]
. Fixing it, I realised that pickling was also broken: it didn't preservegaobject.starred
. This PR fixes both.I've tested for refleaks with
python3 -m test -v test_genericalias -R 3:3
, and it came back clean, so I think we're good.@Fidget-Spinner I guess you're the one most familiar with this code? :)