diff options
| author | natsuoto <[email protected]> | 2026-07-11 11:19:20 +0530 |
|---|---|---|
| committer | natsuoto <[email protected]> | 2026-07-11 11:19:20 +0530 |
| commit | ace5f7c2a92f3fb8ba80ff06d7a543182919095f (patch) | |
| tree | f2dd0c96e3238b82430a6cb7b795d0c093744168 | |
| parent | 3a3fe09ddad3ad9649f0990de33ffeaeca46413c (diff) | |
| download | edify-ace5f7c2a92f3fb8ba80ff06d7a543182919095f.tar.xz edify-ace5f7c2a92f3fb8ba80ff06d7a543182919095f.zip | |
feat(library): infrastructure and first three identifier migrations (uuid, guid, mac)
| -rw-r--r-- | edify/library/_support/atoms.py | 62 | ||||
| -rw-r--r-- | edify/library/_support/coerce.py | 20 | ||||
| -rw-r--r-- | edify/library/identifier/__init__.py | 0 | ||||
| -rw-r--r-- | edify/library/identifier/guid.py | 34 | ||||
| -rw-r--r-- | edify/library/identifier/mac.py | 29 | ||||
| -rw-r--r-- | edify/library/identifier/uuid.py | 36 |
6 files changed, 181 insertions, 0 deletions
diff --git a/edify/library/_support/atoms.py b/edify/library/_support/atoms.py new file mode 100644 index 0000000..8eab9e3 --- /dev/null +++ b/edify/library/_support/atoms.py @@ -0,0 +1,62 @@ +"""Private composable atoms shared by the library validators. + +Every atom is a :class:`Pattern` fragment that renders exactly what the +comment beside it says; nothing here is exported publicly, but every entry +is imported freely by the exported validators to keep their fluent chains +readable. +""" + +from __future__ import annotations + +from edify import RegexBuilder, any_of, char, range_of +from edify.library._support.coerce import as_pattern + + +def _hex_lower_atom() -> object: + return as_pattern(RegexBuilder().any_of().range("0", "9").range("a", "f").end()) + + +def _hex_upper_atom() -> object: + return as_pattern(RegexBuilder().any_of().range("0", "9").range("A", "F").end()) + + +def _hex_any_atom() -> object: + chain = ( + RegexBuilder().any_of().range("0", "9").range("a", "f").range("A", "F").end() + ) + return as_pattern(chain) + + +def _digit_atom() -> object: + return as_pattern(RegexBuilder().digit()) + + +def _octet_atom() -> object: + branch_250_255 = RegexBuilder().string("25").range("0", "5") + branch_200_249 = RegexBuilder().char("2").range("0", "4").digit() + branch_100_199 = RegexBuilder().char("1").digit().digit() + branch_10_99 = RegexBuilder().range("1", "9").digit() + branch_0_9 = RegexBuilder().digit() + return any_of( + as_pattern(branch_250_255), + as_pattern(branch_200_249), + as_pattern(branch_100_199), + as_pattern(branch_10_99), + as_pattern(branch_0_9), + ) + + +hex_lower = _hex_lower_atom() +"""A single lowercase hex nibble: ``[0-9a-f]``.""" + +hex_upper = _hex_upper_atom() +"""A single uppercase hex nibble: ``[0-9A-F]``.""" + +hex_any = _hex_any_atom() +"""A single mixed-case hex nibble: ``[0-9a-fA-F]``.""" + +digit_atom = _digit_atom() +"""A single decimal digit: ``\\d``.""" + +octet = _octet_atom() +"""An IPv4 octet in ``0``-``255``."""
\ No newline at end of file diff --git a/edify/library/_support/coerce.py b/edify/library/_support/coerce.py new file mode 100644 index 0000000..b77ec29 --- /dev/null +++ b/edify/library/_support/coerce.py @@ -0,0 +1,20 @@ +"""Helper to freeze a :class:`RegexBuilder` chain into an exported :class:`Pattern`. + +The library validators build their regex via ``RegexBuilder()`` chains at +import time and expose the result at module level as a :class:`Pattern` +instance so ``isinstance(uuid, Pattern) is True`` and ``uuid(value)`` works. +This helper copies the immutable builder state into a fresh :class:`Pattern` +instance without recompiling or reparsing the emitted regex. +""" + +from __future__ import annotations + +from edify.builder.core import BuilderCore +from edify.pattern.composition import Pattern + + +def as_pattern(builder: BuilderCore) -> Pattern: + """Return a fresh :class:`Pattern` carrying ``builder``'s immutable state.""" + pattern_instance = Pattern() + pattern_instance._state = builder._state + return pattern_instance
\ No newline at end of file diff --git a/edify/library/identifier/__init__.py b/edify/library/identifier/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/edify/library/identifier/__init__.py diff --git a/edify/library/identifier/guid.py b/edify/library/identifier/guid.py new file mode 100644 index 0000000..b17d2f4 --- /dev/null +++ b/edify/library/identifier/guid.py @@ -0,0 +1,34 @@ +"""``guid`` — Microsoft-flavour GUID 8-4-4-4-12 hex shape (callable :class:`Pattern`).""" + +from __future__ import annotations + +from edify import RegexBuilder +from edify.library._support.coerce import as_pattern + + +def _build() -> object: + chain = ( + RegexBuilder() + .start_of_input() + .optional().char("{") + .exactly(8).any_of().range("0", "9").range("a", "f").range("A", "F").end() + .char("-") + .exactly(4).any_of().range("0", "9").range("a", "f").range("A", "F").end() + .char("-") + .exactly(4).any_of().range("0", "9").range("a", "f").range("A", "F").end() + .char("-") + .exactly(4).any_of().range("0", "9").range("a", "f").range("A", "F").end() + .char("-") + .exactly(12).any_of().range("0", "9").range("a", "f").range("A", "F").end() + .optional().char("}") + .end_of_input() + ) + return as_pattern(chain) + + +guid = _build() +"""Callable :class:`Pattern` that validates the Microsoft-flavour GUID shape: +the 8-4-4-4-12 hex form (either case) optionally wrapped in braces. +""" + +del _build diff --git a/edify/library/identifier/mac.py b/edify/library/identifier/mac.py new file mode 100644 index 0000000..0a1e270 --- /dev/null +++ b/edify/library/identifier/mac.py @@ -0,0 +1,29 @@ +"""``mac`` — IEEE 802 MAC-address 6-octet hex shape (callable :class:`Pattern`).""" + +from __future__ import annotations + +from edify import RegexBuilder +from edify.library._support.coerce import as_pattern + + +def _build() -> object: + chain = ( + RegexBuilder() + .start_of_input() + .exactly(5) + .group() + .exactly(2).any_of().range("0", "9").range("a", "f").range("A", "F").end() + .any_of_chars(":-") + .end() + .exactly(2).any_of().range("0", "9").range("a", "f").range("A", "F").end() + .end_of_input() + ) + return as_pattern(chain) + + +mac = _build() +"""Callable :class:`Pattern` that validates the IEEE 802 MAC-address form: +six ``:``- or ``-``-separated hex octets (either case). +""" + +del _build diff --git a/edify/library/identifier/uuid.py b/edify/library/identifier/uuid.py new file mode 100644 index 0000000..09774d9 --- /dev/null +++ b/edify/library/identifier/uuid.py @@ -0,0 +1,36 @@ +"""``uuid`` — canonical UUID 8-4-4-4-12 hex shape (callable :class:`Pattern`).""" + +from __future__ import annotations + +from edify import RegexBuilder +from edify.library._support.atoms import hex_lower +from edify.library._support.coerce import as_pattern + + +def _build() -> object: + chain = ( + RegexBuilder() + .start_of_input() + .exactly(8).any_of().range("0", "9").range("a", "f").end() + .char("-") + .exactly(4).any_of().range("0", "9").range("a", "f").end() + .char("-") + .range("0", "5") + .exactly(3).any_of().range("0", "9").range("a", "f").end() + .char("-") + .any_of_chars("089ab") + .exactly(3).any_of().range("0", "9").range("a", "f").end() + .char("-") + .exactly(12).any_of().range("0", "9").range("a", "f").end() + .end_of_input() + ) + return as_pattern(chain) + + +uuid = _build() +"""Callable :class:`Pattern` that validates the canonical UUID 8-4-4-4-12 +lowercase-hex shape with the version digit pinned to ``1``–``5`` and the +variant digit pinned to ``8``–``b``. +""" + +del _build, hex_lower |
