Reload a fixture module after changing it

importlib.reload() re-executes a module that was imported successfully, using its original loader. This example creates a temporary directory containing fixture_reload.py, adds that directory to sys.path, and imports the fixture. Its first concrete value is "one". The source is then replaced with a longer assignment whose value is "two changed"; invalidate_caches() asks import finders to discard relevant discovery caches before reload() is called. Assertions check the first value, that reload returned the same module object in this case, and the newly defined value.

The output contains only the final value, so it does not depend on the temporary directory name. The finally block removes this fixture's path entry and module-cache entry even if an assertion fails. Changing the file length also makes this small fixture less dependent on a filesystem timestamp with coarse resolution.

Reloading is not a general reset mechanism. Python retains the module dictionary, so names omitted by new source can remain. Existing references imported elsewhere are not rebound, and existing instances keep their old class methods. The operation is not thread-safe without external synchronization. reload() is available in Python 3.4; invalidate_caches() was added in Python 3.3. See the Python importlib documentation.

import importlib
import sys
from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as directory:
    root = Path(directory)
    module_path = root / "fixture_reload.py"
    module_path.write_text("VALUE = 'one'\n", encoding="utf-8")
    sys.path.insert(0, directory)
    try:
        fixture = importlib.import_module("fixture_reload")
        assert fixture.VALUE == "one"

        module_path.write_text("VALUE = 'two changed'\n", encoding="utf-8")
        importlib.invalidate_caches()
        reloaded = importlib.reload(fixture)

        assert reloaded is fixture
        assert fixture.VALUE == "two changed"
        print(f"value: {fixture.VALUE}")
    finally:
        sys.path.remove(directory)
        sys.modules.pop("fixture_reload", None)
value: two changed

AI-assistance disclosure: AI helped draft this explanation and example.

Sources

Comments

Popular posts from this blog

Compare Two Text Files in Python Without Modifying Them

Seven CSV Quality Checks to Run Before Importing Data

Explain why SQLite transactions cannot make an HTTP call atomic