summaryrefslogtreecommitdiffstats
path: root/contrib/python/propcache/tests/conftest.py
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/python/propcache/tests/conftest.py')
-rw-r--r--contrib/python/propcache/tests/conftest.py115
1 files changed, 115 insertions, 0 deletions
diff --git a/contrib/python/propcache/tests/conftest.py b/contrib/python/propcache/tests/conftest.py
new file mode 100644
index 00000000000..ee43f339231
--- /dev/null
+++ b/contrib/python/propcache/tests/conftest.py
@@ -0,0 +1,115 @@
+import argparse
+from dataclasses import dataclass
+from functools import cached_property
+from importlib import import_module
+from types import ModuleType
+
+import pytest
+
+C_EXT_MARK = pytest.mark.c_extension
+
+
+@dataclass(frozen=True)
+class PropcacheImplementation:
+ """A facade for accessing importable propcache module variants.
+
+ An instance essentially represents a c-extension or a pure-python module.
+ The actual underlying module is accessed dynamically through a property and
+ is cached.
+
+ It also has a text tag depending on what variant it is, and a string
+ representation suitable for use in Pytest's test IDs via parametrization.
+ """
+
+ is_pure_python: bool
+ """A flag showing whether this is a pure-python module or a C-extension."""
+
+ @cached_property
+ def tag(self) -> str:
+ """Return a text representation of the pure-python attribute."""
+ return "pure-python" if self.is_pure_python else "c-extension"
+
+ @cached_property
+ def imported_module(self) -> ModuleType:
+ """Return a loaded importable containing a propcache variant."""
+ importable_module = "_helpers_py" if self.is_pure_python else "_helpers_c"
+ return import_module(f"propcache.{importable_module}")
+
+ def __str__(self) -> str:
+ """Render the implementation facade instance as a string."""
+ return f"{self.tag}-module"
+
+
+ scope="session",
+ params=(
+ pytest.param(
+ PropcacheImplementation(is_pure_python=False),
+ marks=C_EXT_MARK,
+ ),
+ PropcacheImplementation(is_pure_python=True),
+ ),
+ ids=str,
+)
+def propcache_implementation(request: pytest.FixtureRequest) -> PropcacheImplementation:
+ """Return a propcache variant facade."""
+ return request.param # type: ignore[no-any-return]
+
+
[email protected](scope="session")
+def propcache_module(
+ propcache_implementation: PropcacheImplementation,
+) -> ModuleType:
+ """Return a pre-imported module containing a propcache variant."""
+ return propcache_implementation.imported_module
+
+
+def pytest_addoption(
+ parser: pytest.Parser,
+ pluginmanager: pytest.PytestPluginManager,
+) -> None:
+ """Define a new ``--c-extensions`` flag.
+
+ This lets the callers deselect tests executed against the C-extension
+ version of the ``propcache`` implementation.
+ """
+ del pluginmanager
+ parser.addoption(
+ "--c-extensions", # disabled with `--no-c-extensions`
+ action=argparse.BooleanOptionalAction,
+ default=True,
+ dest="c_extensions",
+ help="Test C-extensions (on by default)",
+ )
+
+
+def pytest_collection_modifyitems(
+ session: pytest.Session,
+ config: pytest.Config,
+ items: list[pytest.Item],
+) -> None:
+ """Deselect tests against C-extensions when requested via CLI."""
+ test_c_extensions = config.getoption("--c-extensions") is True
+
+ if test_c_extensions:
+ return
+
+ selected_tests: list[pytest.Item] = []
+ deselected_tests: list[pytest.Item] = []
+
+ for item in items:
+ c_ext = item.get_closest_marker(C_EXT_MARK.name) is not None
+
+ target_items_list = deselected_tests if c_ext else selected_tests
+ target_items_list.append(item)
+
+ config.hook.pytest_deselected(items=deselected_tests)
+ items[:] = selected_tests
+
+
+def pytest_configure(config: pytest.Config) -> None:
+ """Declare the C-extension marker in config."""
+ config.addinivalue_line(
+ "markers",
+ f"{C_EXT_MARK.name}: tests running against the C-extension implementation.",
+ )