diff --git a/pcre/_stdlib_re.py b/pcre/_stdlib_re.py index a431683..4e14575 100644 --- a/pcre/_stdlib_re.py +++ b/pcre/_stdlib_re.py @@ -11,9 +11,18 @@ def _load_parser(): if parser is not None: return parser - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - import sre_parse as parser + # Python <= 3.10 hides the parser behind the deprecated top-level + # ``sre_parse`` module; Python 3.15 removes that alias entirely. + try: + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + import sre_parse as parser + except ModuleNotFoundError as exc: # pragma: no cover - Python >= 3.15 + raise ImportError( + "stdlib re internals unavailable: expected re._parser " + "(Python 3.11+) or sre_parse (Python <= 3.10); this interpreter " + "provides neither" + ) from exc return parser diff --git a/tests/test_python_coverage_audit.py b/tests/test_python_coverage_audit.py index fe02968..aa77958 100644 --- a/tests/test_python_coverage_audit.py +++ b/tests/test_python_coverage_audit.py @@ -28,10 +28,15 @@ def test_stdlib_parser_fallback(monkeypatch: pytest.MonkeyPatch) -> None: # Python 3.10 does not expose ``re._parser`` at module scope, while newer - # releases do. Either state should exercise our fallback loader. + # releases do. Python 3.15 removes the legacy ``sre_parse`` module, so on + # that interpreter the fallback must degrade with a clear ImportError. monkeypatch.delattr(re, "_parser", raising=False) - parser = stdlib_re._load_parser() - assert callable(parser.parse) + if importlib.util.find_spec("sre_parse") is not None: + parser = stdlib_re._load_parser() + assert callable(parser.parse) + else: + with pytest.raises(ImportError): + stdlib_re._load_parser() def test_stdlib_parser_exported_path(monkeypatch: pytest.MonkeyPatch) -> None: