-
-
Notifications
You must be signed in to change notification settings - Fork 2.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
Calling pytest.main() repeatedly (possible fix for ImportPathMismatchError) #13230
Comments
Honestly, I don't feel like such hacks belong in the project. This is something to exist externally. Especially, since import machinery manipulation can be dangerous, and it'd be costly to maintain. I doubt there's enough interest to warrant accepting such a change. |
The pytester fixture which is used for in process running of pytest in its own testsuite can serve as inspiration The outlined usecase is not something pytest itself ought to solve as a general solution has a certain fragility whose maintenance burden ought not to be on the pytest project itself |
I understand the hesitance to add in maintenance. I may not have been clear since my code was complicated by a specific list of exclusions. The point was that you wouldn't need them at all if this were an embedded option. Conceptually, the code would need only be something like: if preserve_env:
pretest_modules = [key for key in sys.modules.keys()]
pretest_path = sys.path.copy()
# ...MODIFY PATH AND EXEC TESTS...
if preserve_env:
posttest_modules = [key for key in sys.modules.keys() if key not in pretest_modules]
for module_name in posttest_modules:
del sys.modules[module_name]
sys.path = pretest_path.copy() Could even be written as a simple context manager. Why?
I don't see it as being overly hacky or unsafe. Discovered test files (and any additional modules loaded by the test files) will always be "last in" and should be safely deleted. At least they were in my testing. And if it's somehow unsafe for your particular test code, you just don't add the optional flag. I guess I don't see it as any more of a hack than mocking or the existing |
the fact that one needs lists of modules that need break prevention is enough to make this unsafe by default As such it is best provided as something that correctly enforces informed consent to the mechanisms |
@RonnyPfannschmidt I may not fully understand the alternative(s). Could you point me to the pytester fixture that you referenced in your earlier response? Thanks! |
I am using pytest to grade (a lot of) student assignments. Though documented as "not recommended" (https://docs.pytest.org/en/stable/how-to/usage.html#pytest-main-usage), the benefit for me of calling a bunch of tests within the same Python process were significant enough for me to bang my head against the wall on this for a couple of days.
If you don't (or can't) call pytest using the
--import-mode=importlib
option, then in my use case you always get the dreadedImportPathMismatchError
exception. I'm sure I'm oversimplifying, but this is because once a module is loaded, it's cached in memory and referenced by the name of the module. Assuming the modules are just files (as will be the case with the test files) then there will be duplicates as I'm running the same test files against student projects repeatedly. And Python won't overwrite the cached modules with the new versions.To get around this, I'm "restoring" a pre-invocation version of the in-memory modules by deleting any that are loaded during the pytest run. But it's overly complicated since I also want to optimize performance by avoiding modules that pytest needs and would have to reload. So the code looks something like this:
It works like a charm, but if something like this could be added directly to pytest.main()--perhaps as an optional argument ike
remove-loaded-modules=True
to avoid unexpected side effects for others)--it could be much more efficient. Simply capture the environment state immediately prior to invoking tests and restoring it immediately following.And of course it could save a lot of bruised foreheads and damaged walls.
I looked at the source and was too overwhelmed to attempt a pull request. But someone familiar with it likely could make this happen quite easily if it makes sense.
The text was updated successfully, but these errors were encountered: