From c880179bf0ddcea4260f86ff0efa91894beee605 Mon Sep 17 00:00:00 2001 From: Qubitium Date: Mon, 24 Aug 2026 12:02:44 +0000 Subject: [PATCH] fix: handle Python 3.15 removal of the legacy sre_parse module Python 3.15 removes the deprecated top-level sre_parse/sre_compile/ sre_constants modules. The _stdlib_re parser loader still imported sre_parse unconditionally whenever re._parser was absent, so any interpreter without re._parser failed with an opaque ModuleNotFoundError instead of a clear error. Guard the fallback import, raise an ImportError that names both supported internals (re._parser on 3.11+, sre_parse on <= 3.10) when neither is available, and make test_stdlib_parser_fallback version-aware: expect a parser where sre_parse still exists and an ImportError where it has been removed. --- pcre/_stdlib_re.py | 15 ++++++++++++--- tests/test_python_coverage_audit.py | 11 ++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) 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: