New submission from Paul Ganssle <p.gans...@gmail.com>:
It seems that test.support.import_fresh_module gets tripped up with its module blocking when you attempt to get a fresh copy of a submodule of a module where you are also importing the module that you are trying to block (bit of a doozy of a sentence there...). So, for example, with the following configuration in mymodule/__init__.py: from .other import other try: from ._a import attr except ImportError: from ._b import attr (Assuming _a.attr = "A" and _b.attr = "B"), if you attempt to do: m = test.support.import_fresh_module("mymodule", fresh=("mymodule._other",), blocked=("mymodule._a")) Then you'll find that m.attr is pulled from _a.attr. Here's a small script to demonstrate: from test.support import import_fresh_module import sys def import_ab(fresh_other): fresh = ("mymodule._other", ) if fresh_other else () mods_out = [] for to_block in "_b", "_a": blocked = (f"mymodule.{to_block}",) mods_out.append(import_fresh_module("mymodule", fresh=fresh, blocked=blocked)) return mods_out for fresh_other in [True, False]: mymodule_a, mymodule_b = import_ab(fresh_other) qualifier = "With" if fresh_other else "Without" print(f"{qualifier} a fresh import of mymodule._other") print(f"a: {mymodule_a.attr}") print(f"b: {mymodule_b.attr}") print() When you run it with a suitably configured module on Python 3.8: $ python importer.py With a fresh import of mymodule._other a: A b: A Without a fresh import of mymodule._other a: A b: B It also happens if you add `mymodule._a` or `mymodule._b` to the fresh list when you are trying to block the other one. I *think* the problem is that in the step where _save_and_remove_module is called on fresh_name (see here: https://github.com/python/cpython/blob/76db37b1d37a9daadd9e5b320f2d5a53cd1352ec/Lib/test/support/__init__.py#L328-L329), it's necessarily populating `sys.modules` with a fresh import of the top-level module we're trying to import (mymodule) *before* the blocking goes into effect, then the final call to importlib.import_module just hits that cache. I think either of the following options will fix this issue: 1. Switching the order of how "fresh" and "blocked" are resolved or 2. Deleting `sys.modules[name]` if it exists immediately before calling `importlib.import_module(name) That said, I'm still having some weird statefulness problems if I block a C module's import and *then* block a Python module's import, so there may be some other underlying pathology to the current approach. ---------- components: Tests files: test_support_repro.zip messages: 365702 nosy: brett.cannon, eric.snow, ncoghlan, p-ganssle priority: normal severity: normal status: open title: test.support.import_fresh_module fails to correctly block submodules when fresh is specified type: behavior versions: Python 3.7, Python 3.8, Python 3.9 Added file: https://bugs.python.org/file49031/test_support_repro.zip _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue40173> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com