From 9ce6e72e2ccc60ed862b3bedf0a6a263844ee530 Mon Sep 17 00:00:00 2001 From: degerahmet Date: Thu, 20 Mar 2025 00:11:18 -0700 Subject: [PATCH] add fixture to mock importlib.util.find_spec for custom loaders in tests --- tests/test_instance_config.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/test_instance_config.py b/tests/test_instance_config.py index 1918bd99..b540b4c3 100644 --- a/tests/test_instance_config.py +++ b/tests/test_instance_config.py @@ -1,3 +1,4 @@ +import importlib.util import os import pytest @@ -5,6 +6,40 @@ import pytest import flask +@pytest.fixture(params=(True, False)) +def limit_loader(request, monkeypatch): + """Patch importlib.util.find_spec to give loader without get_filename or archive. + + This provides for tests where a system has custom loaders, e.g. Google App + Engine's HardenedModulesHook, which have neither the `get_filename` method + nor the `archive` attribute. + + This fixture will run the testcase twice, once with and once without the + limitation/mock. + """ + if not request.param: + return + + class LimitedLoader: + def __init__(self, loader): + self.loader = loader + + def __getattr__(self, name): + if name in {"archive", "get_filename"}: + raise AttributeError(f"Mocking a loader which does not have {name!r}.") + return getattr(self.loader, name) + + original_find_spec = importlib.util.find_spec + + def mock_find_spec(name, package=None): + spec = original_find_spec(name, package) + if spec and spec.loader: + spec.loader = LimitedLoader(spec.loader) + return spec + + monkeypatch.setattr(importlib.util, "find_spec", mock_find_spec) + + def test_explicit_instance_paths(modules_tmp_path): with pytest.raises(ValueError, match=".*must be absolute"): flask.Flask(__name__, instance_path="instance")