pytest: monkeypatch doesn't patch a module if it has already been imported by production code.
Thank you for this great testing library đ
If I understand #762 correctly, modules should be reimported if pytest monkeypatch a module, like this:
monkeypatch.setattr('pytest_bug.b.foo', foo_patch)
even if the module has been imported this way:
from pytest_bug.b import foo
I have a reduced test case in this repo: https://github.com/JohanLorenzo/pytest-bug-2229. The README contains instructions about how to run it.
I checked the contexts via PDB:
- When youâre in the test,
foo
is correctly patched. - However, when youâre in the function youâd like to test,
foo
hasnât been changed.
Environment
- Python 3.5.3 (On Arch Linux)
- pip list: appdirs==1.4.0,packaging==16.8,py==1.4.32,pyparsing==2.1.10,pytest==3.0.6,pytest-bug==0.0.1,pytest-bug-2229==0.0.1,six==1.10.0
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 1
- Comments: 25 (15 by maintainers)
I think pytest-forked will do this for you, I actually use
billiard.get_context("spawn")
for this sort of thing in my projects.Thatâs why a plugin should contain that difference in design that stems from from different design goals driven by different target audiences
@RonnyPfannschmidt unfortunately, I donât think your advice would work for most mainstream, recommended, common workflows. For example itâs even one of the core principles of 12 Factor apps to store all config in the environment.
Itâs extremely common to need to read
os.environ
and set module-level constants at import time. For example, it may be critical that the setting cannot change between function calls (thusos.environ
shouldnât be reconsulted on subsequent calls), and you may have logic of module instantiation that has to run at import time and is customized / affected by the state of the environment. Some use cases may have the luxury to replace this with function calls or maybe a clever use of anlru_cache
, but itâs deeply unreasonable to say all use cases must refactor from first principles to do it that way.This is especially common with third party dependencies that canât be omitted or replaced, so the developer may have no control over relying on checks to
os.environ
happening at import time. The advice to longterm remove such dependencies would be literally intractable for the strong majority of users.Instead, what is needed is a way for pytest to sandbox the import mechanism in tests, so that for the duration of the test, any uses of
reload
or manipulations ofsys.modules
cache doesnât have a wider impact on any other test cases, parallel test executors, etc., and can be cleaned up / restored after the fact.@nicoddemus Iâd like to also add that the standard âpatching in the wrong placeâ advice doesnât help if you need to patch a module-level variable specifically before the module is imported, because the setting of that variable will have a side-effect during the moment when the module itself is imported.
For example consider something like this:
Suppose in my tests I want to monkeypatch the OS environment variable
'MY_SETTING'
but before any tests will importmy_module.py
. I may even want to patch it multiple different ways and importmy_module.py
different ways with different patched variables that have different âstart upâ side effects.Such as some
conftest.py
file similar to thisBut this does not appear to actually apply the patching, as though pytest collects and imports the module first, presenting no opportunity to get different on-import side effects.
@spearsem
short term: run the testrunner multiple times long term: try to completely remove the need for those dependencies as their global configuration is a liability
@spearsem loading of specific datasets in those cases is done by invoking functions, not by reloading modules after changing env vars
Hi @JohanLorenzo,
Thatâs a common gotcha with mocking in Python, and is not particular to
monkeypatch
but affects also other mocking modules includingunittest.mock
. I found an article that explains this common issue here: http://alexmarandon.com/articles/python_mock_gotchas, see the âPatching in the wrong placeâ section.Closing this for now, but feel free to ask further questions!