-
-
Notifications
You must be signed in to change notification settings - Fork 30.7k
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
bpo-42327: Add PyModule_Add() (smaller). #23443
bpo-42327: Add PyModule_Add() (smaller). #23443
Conversation
Also fix possible leaks in initialization of modules: _csv, _curses_panel, _elementtree, _io, _pickle, _stat, _testinternalcapi, _threadmodule, _zoneinfo, _codecs_*, cmath, math, ossaudiodev, time, xxlimited, xxmodule, xxsubtype.
This is the same as #23240, but without large changes to modules _ssl, _testbuffer, _testcapi, posix, select, socket, _msi, msvcrt. They will be extracted to separate PRs. |
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 like the new functon, but I prefer PyModule_AddObjectRef(obj)
rather than Py_INCREF(obj); PyModule_Add(obj)
. In some cases, you removed a test for NULL, but I don't think that it's worth it (I prefer an explicit test with PyModule_AddObjectRef, but that's a personal preference, I guess). At least, when not test for == NULL
is needed, PyModule_AddObjectRef() should be preferred IMO.
Misc/NEWS.d/next/C API/2020-11-11-22-36-29.bpo-42327.ODSZBM.rst
Outdated
Show resolved
Hide resolved
Could you split this PR in two parts? The first uncontroversial PR which only adds the function, and then a second PR which modify PyInit functions to use it. These days, there are dozens of PRs modifying PyInit functions which would be in conflict with the second part. See bpo-40077 and bpo-1635741. |
I still prefer https://github.com/python/cpython/pull/23286/files over
How about we land PR #23286 first, port more code to the new API, and then see if we still need |
This PR is stale because it has been open for 30 days with no activity. |
I dislike APIs stealing references. IMO we should stop adding such API. I would prefer regular (boring and verbose) reference counting to make the C API easier to understand. Currently, developers have to check the documentation of each function to check if it returns a borrowed or strong reference, if it adds or removes a reference (and leave the ref count unchanged), etc. |
It is a convenient API. How else would you fix Modules/mathmodule.c, for example? The "N" code in return Py_BuildValue("Nl", _PyLong_FromTime_t(sec), nsec); instead of: PyObject *tmp = _PyLong_FromTime_t(sec);
if (tmp == NULL) {
return NULL;
}
PyObject *res = Py_BuildValue("Ol", tmp, nsec);
Py_DECREF(tmp);
return res; |
Usually, a macro is written to create a temporary object and add it to the module. If you use PyModule_AddObjectRef(), the macro would also clear the reference. I dislike the fact that macro is "required" to write correct code. In 2020, @tiran proposed designing a new API to make this work easier with a declarative syntax: https://discuss.python.org/t/define-module-constants-in-pymoduledef/5749 |
Macro is convenient because it can include "goto error" or "return NULL". But having to write such macro in every module is tiring. |
We can make it a private function at first if you so dislike adding it to the public API. Then we can add new @tiran's API and decide whether it is worth to add public |
IMO, that's a good guideline, but But it should be very clear from the name. I don't think |
To be clear, I dislike APIs stealing references, but I don't plan to block this PR. I will just not endorse it :-) If using PyModule_AddObjectRef() is not convenient, maybe we need to provide "something" to make it easier to use. Sadly, the C language is limited in terms of macros/templates :-( The approach based on a description is promising, but I also know that there are many technical challenges which may not be possible to be solved. By the way, I'm really unhappy on the bad state of our PyInit functions: many of them simply have no error checking, or just one final PyErr_Occurred() check. That's bad. The trend is more to disallow calling functions with an exception set (it might be enforced later). If this new function makes the situation better: go ahead ;-) |
What does "New" stand for? This function does not create a new reference, but steals a reference. Is is "New" because its a new function replacing an old one? What if tomorrow, there is a newer function? Should we call it PyModule_AddNewer or PyModule_AddNewEx? I suggest to just call it PyModule_Add(). |
It adds a newly created object. |
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.
It may be easier to review this big PR if you could move code fixing PyInit functions into a separated PR.
.. c:function:: int PyModule_Add(PyObject *module, const char *name, PyObject *value) | ||
|
||
Similar to :c:func:`PyModule_AddObjectRef`, but "steals" a reference | ||
to *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.
PyModule_AddObjectRef() must not be called with NULL. Can you please elaborate the behavior when value is NULL? Something like:
If value is NULL, just return -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.
PyModule_AddObjectRef()
can be called with NULL if an exception is set. Actually, some of my fixes which use PyModule_AddObjectRef()
rely on this.
// Similar to PyModule_AddObjectRef() but steal a reference to 'obj' | ||
// (Py_DECREF(obj)) on success (if it returns 0). | ||
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000 | ||
// Similar to PyModule_AddObjectRef() but steal a reference to '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.
I suggest to add "and value can be NULL".
PyAPI_FUNC(int) PyModule_Add(PyObject *mod, const char *name, PyObject *value); | ||
#endif /* Py_LIMITED_API */ | ||
|
||
// Similar to PyModule_AddObjectRef() and PyModule_Add() but steal |
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.
It's not similar to PyModule_AddObjectRef(): value can be NULL.
// Similar to PyModule_AddObjectRef() and PyModule_Add() but steal | |
// Similar to PyModule_Add() but steal |
|
||
// Similar to PyModule_AddObjectRef() and PyModule_Add() but steal | ||
// a reference to 'value' on success and only on success. | ||
// Errorprone. Should not be used in new code. |
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.
IMO it's important important to put it in the documentation. This kind of definition fits perfectly with the Soft Deprecated status. Maybe also soft deprecate this API, similar to getopt and optparse soft deprecation. Example with getopt:
.. deprecated:: 3.13
The :mod:`getopt` module is :term:`soft deprecated` and will not be
developed further; development will continue with the :mod:`argparse`
module.
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.
Do you suggest to convert the note
block into deprecated
?
Ok, but this PR changes |
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.
LGTM.
If I have further comments, I may propose them as a separated PR.
Thanks Victor. |
Even if I dislike stealing references, the API seems to help simplifying PyInit code a lot. |
I added the |
I wrote PR #106859 to document PyModule_AddObject() soft deprecation in What's New in Python 3.13. |
Also fix possible leaks in initialization of modules:
_curses_panel
,_decimal
,_ssl
,_stat
,_testinternalcapi
,_threadmodule
,cmath
,math
,posix
,time
,xxsubtype
.https://bugs.python.org/issue42327
#86493