Skip to content

gh-94936: C getters: co_varnames, co_cellvars, co_freevars #95008

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

Merged
merged 2 commits into from
Aug 4, 2022

Conversation

Fidget-Spinner
Copy link
Member

@Fidget-Spinner Fidget-Spinner commented Jul 19, 2022

@Fidget-Spinner Fidget-Spinner requested a review from vstinner July 19, 2022 14:38
return NULL;
}
/* co_varnames */
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make more sense to expose the functions here, and test them in test/test_capi.py, checking that the C version returns the same as the Python version?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be better, but I'm fine with these tests.

PyObject *
PyCode_GetVarnames(PyCodeObject *code)
{
return _PyCode_GetVarnames(code);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the advantage of separate wrapper functions rather than just removing the leading _ from the wrapped functions?

Copy link
Member

@vstinner vstinner Aug 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I concur wuth @gvanrossum, unless it's implemented as a static inline function, I see no advantage, but that's not the case here. Just rename _PyCode_GetVarnames() to PyCode_GetVarnames(). Same remark for the 2 other functions.

PyObject *
PyCode_GetVarnames(PyCodeObject *code)
{
return _PyCode_GetVarnames(code);
Copy link
Member

@vstinner vstinner Aug 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I concur wuth @gvanrossum, unless it's implemented as a static inline function, I see no advantage, but that's not the case here. Just rename _PyCode_GetVarnames() to PyCode_GetVarnames(). Same remark for the 2 other functions.

return NULL;
}
/* co_varnames */
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be better, but I'm fine with these tests.

@vstinner
Copy link
Member

vstinner commented Aug 3, 2022

This change targets Python 3.11 which no longer accepts new features (after beta1). But it seems like the lack of public C API functions to the removed PyCodeObject members is an issue, see: https://discuss.python.org/t/getting-the-class-name-of-a-code-frame-object-in-cpython-3-11-c-api/17396

Should we target Python 3.11 or is it ok to leave Python 3.11 with no public C API for that?

@gvanrossum
Copy link
Member

@pablogsal -- These three new C getter APIs would be useful for some and don't really add any risk for 3.11, but at the same time I don't think they are essential. What do you think?

@vstinner
Copy link
Member

vstinner commented Aug 3, 2022

but at the same time I don't think they are essential

A datapoint: when I proposed to replace a direct access to a structure member in C with PyObject_GetAttrString(), @nedbat reported a serious slowdown in his https://github.com/nedbat/coveragepy/ project. PyFrame_GetLasti() was added to Python 3.11 to solve this performance issue: https://docs.python.org/dev/c-api/frame.html#c.PyFrame_GetLasti

I failed to find the discussion about the performance regression caused by PyObject_GetAttrString() but it's obviously way more work than just reading directly a C structure member... The function decodes a bytes string from UTF-8, creates a temporary Unicode object, lookup in a dictionary, delete the temporary Unicode code... But then you get a Python object, you need to unbox its content and delete the second (temporary?) result object...

@gvanrossum
Copy link
Member

FWIW one suggestion (see #94936 (comment)) to avoid the perf regression of PyObject_GetAttrString() is to just include internal headers and call the _Py versions of the functions. That would have to be done just for 3.11. Of course a shortcut would also be to just duplicate the extern declarations for these from the headers. Again just for 3.11.

@pablogsal
Copy link
Member

@pablogsal -- These three new C getter APIs would be useful for some and don't really add any risk for 3.11, but at the same time I don't think they are essential. What do you think?

I would be ok landing this in 3.11 but we are one day from an already delayed release candidate so if these APIs are not essential I would prefer delaying them to 3.12 because they won't be tested when we release them (before the RC) and I'm not sure of we can properly review the implementation in one day.

If you think is going to be much better to land these in 3.11 then let's do it, but we are going to need at least 2 core Devs to review and approve the PR.

Copy link
Member

@vstinner vstinner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. @gvanrossum: Would you mind to review this PR as well?

I can rename _PyCode_GetVarnames() to PyCode_GetVarnames() in a following PR. But I would prefer to see these functions added to Python 3.11. Avoiding the internal API to access code members in C is way more convenient to port extensions to Python 3.11!

Copy link
Member

@gvanrossum gvanrossum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it’s urgent I’m fine with this as is. We can clean up later.

@gvanrossum gvanrossum merged commit 42b102b into python:main Aug 4, 2022
@miss-islington
Copy link
Contributor

Thanks @Fidget-Spinner for the PR, and @gvanrossum for merging it 🌮🎉.. I'm working now to backport this PR to: 3.11.
🐍🍒⛏🤖

miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Aug 4, 2022
@bedevere-bot
Copy link

GH-95653 is a backport of this pull request to the 3.11 branch.

@bedevere-bot bedevere-bot removed the needs backport to 3.11 only security fixes label Aug 4, 2022
@vstinner
Copy link
Member

vstinner commented Aug 4, 2022

I wrote python/pythoncapi-compat#44 to add the 3 functions to pythoncapi-compat (for Python 3.10 and older).

miss-islington added a commit that referenced this pull request Aug 4, 2022
@Fidget-Spinner
Copy link
Member Author

Fidget-Spinner commented Aug 4, 2022

Oops I missed the convo on this one.I planned to direct extension authors to use PyObject_GetAttrString. I want a better/more performant implementation for 3.12. It will cache the debug info in a lazy debug struct much like how we do it for PyInterpreterFrame and PyFrameObject now.

@Fidget-Spinner Fidget-Spinner deleted the code_getters branch August 4, 2022 15:38
@joerick
Copy link

joerick commented Aug 5, 2022

Thank you so much for getting this in! 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants