Skip to content

Fix race condition for import of modules which use apipkg in Python 3.3+ #27

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
Oct 5, 2021

Conversation

GlenWalker
Copy link
Contributor

@GlenWalker GlenWalker commented Oct 5, 2021

Update existing module in-place rather than replacing in sys.modules with a new ApiModule instance

This race condition exists for import statements (and __import__) in Python 3.3+ where sys.modules is checked before obtaining an import lock, and for importlib.import_module in Python 3.11+ for the same reason.

@GlenWalker GlenWalker force-pushed the fix_py3_import_race branch 2 times, most recently from e68ae61 to 15b5526 Compare October 5, 2021 11:55
* Update existing module in-place rather than replacing in sys.modules with
  a new ApiModule instance
@GlenWalker GlenWalker force-pushed the fix_py3_import_race branch from 15b5526 to 1be7d47 Compare October 5, 2021 11:57
@GlenWalker GlenWalker force-pushed the fix_py3_import_race branch from d330845 to ed7adce Compare October 5, 2021 12:16
@RonnyPfannschmidt
Copy link
Member

yikes ^^

@RonnyPfannschmidt RonnyPfannschmidt merged commit 4322f61 into pytest-dev:main Oct 5, 2021
@GlenWalker GlenWalker deleted the fix_py3_import_race branch October 5, 2021 21:53
@GlenWalker
Copy link
Contributor Author

It looks like there was an "Internal Server Error" while running the GitHub actions for your merge, so they never finished. Is it possible to re-run them?

delattr(mod, name)

# Updating class of existing module as per importlib.util.LazyLoader
mod.__class__ = ApiModule
Copy link
Member

Choose a reason for hiding this comment

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

This breaks the compatibility with Python 3.4: #29.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is unfortunate, I'm not sure there's a way to fix the race condition if we can't update the module in place.

Options:

  • Figure out a way to update the module in place in Python <= 3.4, maybe by copying from ApiModule into module instance?
  • Accept the race condition in Python <= 3.4 and don't try to update in place
  • Drop support for Python 3.4 completely, and update python_requires appropriately

I'm not sure what @RonnyPfannschmidt's intention was for 3.4 support, I just relied on the automated tests.

Copy link
Member

Choose a reason for hiding this comment

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

I wonder if setattr() would somehow work.

Copy link
Member

@webknjaz webknjaz Nov 25, 2021

Choose a reason for hiding this comment

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

@GlenWalker dropping 3.4 from the matrix was accidental: #31

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wonder if setattr() would somehow work.

Setting attributes directly on the original module instance would probably work for eager=True, but not for eager=False. I had a quick look, but so far the only options for lazy loading require support from the module class (i.e. Python calls __getattr__ from the module class, and not the module instance). We wouldn't want to update __getattr__ on types.ModuleType globally, so if we can't update __class__ on the module instance then we are stuck.

I suspect that for Python 3.4 we'll just have to accept the race condition, and replace the module, rather than updating it in place. Unless anyway has any good ideas?

(The race condition has existed for a long time without anyone complaining, so this might be acceptable)

Copy link
Member

Choose a reason for hiding this comment

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

Sounds reasonable.

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.

3 participants