diff options
| author | natsuoto <[email protected]> | 2026-07-15 11:36:16 +0530 |
|---|---|---|
| committer | natsuoto <[email protected]> | 2026-07-15 11:36:16 +0530 |
| commit | b91d28b669974abdcebacf0c8c13abaa5b124f9a (patch) | |
| tree | c1603efc7dec936895cb74a50fe9d20c407a74f1 | |
| parent | ec570ac862110c7f3445750d7122e1cea7029980 (diff) | |
| download | edify-b91d28b669974abdcebacf0c8c13abaa5b124f9a.tar.xz edify-b91d28b669974abdcebacf0c8c13abaa5b124f9a.zip | |
feat(builder): typed engine=Literal kwarg on to_regex with EngineNotWiredError
| -rw-r--r-- | edify/builder/mixins/terminals.py | 9 | ||||
| -rw-r--r-- | edify/builder/types/engine.py | 8 | ||||
| -rw-r--r-- | edify/errors/engine.py | 31 | ||||
| -rw-r--r-- | tests/builder/engine.test.py | 19 |
4 files changed, 67 insertions, 0 deletions
diff --git a/edify/builder/mixins/terminals.py b/edify/builder/mixins/terminals.py index 1b83c10..25d8191 100644 --- a/edify/builder/mixins/terminals.py +++ b/edify/builder/mixins/terminals.py @@ -11,10 +11,12 @@ from __future__ import annotations import re +from edify.builder.types.engine import Engine from edify.builder.types.flags import Flags from edify.builder.types.protocol import BuilderProtocol from edify.compile.dispatch import render_element from edify.elements.types.root import RootElement +from edify.errors.engine import EngineNotWiredError from edify.errors.quantifier import DanglingQuantifierError from edify.errors.structure import CannotCallSubexpressionError from edify.result import Regex @@ -51,6 +53,7 @@ class TerminalsMixin(BuilderProtocol): multiline: bool = False, dotall: bool = False, verbose: bool = False, + engine: Engine = "re", ) -> Regex: """Return the pattern + flags compiled and wrapped in :class:`edify.result.Regex`. @@ -62,8 +65,14 @@ class TerminalsMixin(BuilderProtocol): already carries — passing ``ignore_case=True`` here is equivalent to having called ``.ignore_case()`` in the chain. Flags never turn off, only on. + + The ``engine`` kwarg selects the compilation backend. Only ``"re"`` is + wired today; ``"regex"`` is reserved for the opt-in third-party engine + and raises :class:`NotImplementedError` until that dispatch lands. """ pattern_string = self.to_regex_string() + if engine != "re": + raise EngineNotWiredError(engine) kwarg_flags = Flags( ascii_only=ascii_only, debug=debug, diff --git a/edify/builder/types/engine.py b/edify/builder/types/engine.py new file mode 100644 index 0000000..9af27e6 --- /dev/null +++ b/edify/builder/types/engine.py @@ -0,0 +1,8 @@ +"""Type alias for the ``engine`` kwarg accepted by every builder terminal.""" + +from __future__ import annotations + +from typing import Literal + +Engine = Literal["re", "regex"] +"""The compilation-backend identifier accepted by :meth:`edify.RegexBuilder.to_regex`.""" diff --git a/edify/errors/engine.py b/edify/errors/engine.py new file mode 100644 index 0000000..5a9e6cb --- /dev/null +++ b/edify/errors/engine.py @@ -0,0 +1,31 @@ +"""Exception classes raised when the ``engine`` kwarg selects an unavailable backend.""" + +from __future__ import annotations + +from edify.errors.formatting import compose_annotated_message +from edify.errors.syntax import EdifySyntaxError + + +class EngineNotWiredError(EdifySyntaxError): + """Raised when ``.to_regex(engine=...)`` selects a backend this build does not wire. + + Args: + requested_engine: The value the caller passed for the ``engine`` kwarg. + """ + + def __init__(self, requested_engine: str) -> None: + message = compose_annotated_message( + summary=( + f"engine={requested_engine!r} is not wired in this build; only 're' is available" + ), + trigger_hint=".to_regex(engine=…) called here", + note=( + f"the {requested_engine!r} backend is a planned optional dependency " + "and its dispatch has not shipped yet." + ), + help_line=( + "help: call .to_regex() without the engine kwarg, or pin edify to a " + "release that wires the requested backend." + ), + ) + super().__init__(message) diff --git a/tests/builder/engine.test.py b/tests/builder/engine.test.py new file mode 100644 index 0000000..e569c71 --- /dev/null +++ b/tests/builder/engine.test.py @@ -0,0 +1,19 @@ +import pytest + +from edify import RegexBuilder +from edify.errors.engine import EngineNotWiredError + + +def test_engine_defaults_to_re_and_compiles(): + compiled = RegexBuilder().digit().to_regex() + assert compiled.source == "\\d" + + +def test_engine_re_explicit_is_accepted(): + compiled = RegexBuilder().digit().to_regex(engine="re") + assert compiled.source == "\\d" + + +def test_engine_regex_raises_until_wired(): + with pytest.raises(EngineNotWiredError, match="engine='regex'"): + RegexBuilder().digit().to_regex(engine="regex") |
