-
Notifications
You must be signed in to change notification settings - Fork 2.2k
common: Prevent module re-import duplication in Python3 #1558
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
common: Prevent module re-import duplication in Python3 #1558
Conversation
I can't seem to match up your description to the contents of the PR. In particular, PYBIND11_CHECK_REIMPORT only has a non-empty definition when compiling for Python 2.x. In any case, it would be important to fix the issue both 2.x and 3.x versions of Python (is one not affected for some reason?). |
c25ca33
to
ae7ad8b
Compare
Ah, oops! Sorry, the comment at the And it seems that this is specific to Python3's method of constructing C extension modules.
|
ae7ad8b
to
dcdc0d3
Compare
Updated to use EDIT: Hm... Just one failure for |
dcdc0d3
to
b319216
Compare
b319216
to
f29efce
Compare
Any chance this might be able to move forward? Got bit by this in our lib again. |
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 agree with @henryiii (slack channel) that this would be good to merge.
auto& modules = pybind11::get_or_create_shared_data< \ | ||
std::unordered_map<int*, pybind11::handle>>("__pybind11_modules"); \ | ||
pybind11::handle& original = modules[&module_key]; \ | ||
if (original) return original.inc_ref().ptr(); \ | ||
original = m; \ |
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.
Uncertain myself, but asking anyway: could it make sense to move this code to an inline function in the pybind11::detail
namespace?
It would also be nice to add a terse comment (here or in the function) with a hint why this is needed, so that people don't have to dig up this PR to find out.
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.
Yeah, I can delegate most of this code to a function, and could add a comment, pending other discussions - thanks!
This does feel like a rather heavy fix (always keeping track of all modules in a shared variable) for a small window of time where things can go wrong (during import of the module). Just curious if there's no other way; this is not a pybind11-specific problem, so how do other frameworks (or even the raw C API) approach this? Secondary part of this concern: storing |
I agree with Yannick, this strikes me as to heavy of a change given the benefit that it provides. It's not just the runtime cost of creating yet another hash table (negligible), but the fact that we have to generate and include code for another hash table variant with template arguments Can't we do this with a simple global flag to prevent the kind of re-entrant behavior you mention? |
Agreed with y'all's points on heavy-handedness and non-reentrancy of the current solution. Rather than trying to address those in this current incantation, perhaps the right thing is ensuring that, when available, Python 3 modules use multi-phase initialization by default, as Yannick pointed out in #2548. I would vote for either re-catering this PR towards that issue, or closing this out and opening a new PR addressing that more specifically? (I think this would slip on the release schedule, but we're fine in Drake for doing this manually, and not sure if other people have encountered this as a pain point?) |
Not sure if I understand how this current solution would be solvable via a global flag. @wjakob If you can, can you speak to this? |
👍 Sounds good to me. But maybe better to start a new PR whenever someone has a bit of time, rather than repurpose this? That PR should probably also follow/coordinate with #2552 & #2251?
If you would need an easy workaround included in pybind11, I'd be fine with that, but so far, this is the only time I heard about problems in this case. So if you don't mind keeping your own workaround, it might be better to solve this with the multi-phase initialization in 2.7.0 or so? |
Yup, sounds great! I'm totally fine with us keeping our workaround! |
Resolves #1559
With my system's version of Python3 (Ubuntu 16.04, Python 3.5.2), if I import a given module while that module is being constructed, it will duplicate the module object.
This captures this behavior in a test, and provides a potential workaround.