diff options
| author | Bobby <[email protected]> | 2026-07-11 17:44:20 +0530 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-07-11 17:44:20 +0530 |
| commit | abdaeb4aad4284986f012efcce35a6e4189f2929 (patch) | |
| tree | 9eaff3968954dc8f5bf079684dba46b6026e2221 /tests/pattern/boundaries.test.py | |
| parent | 2038ee5c4a5e473c20cf1e38af5c32ab450a2aea (diff) | |
| parent | c7a8a902eb86dfec5dd5c4ec77c532f5b920d3ac (diff) | |
| download | edify-abdaeb4aad4284986f012efcce35a6e4189f2929.tar.xz edify-abdaeb4aad4284986f012efcce35a6e4189f2929.zip | |
feat!: callable-Pattern validator API + 223-pattern library across 22 category folders (#274)
Ships the callable-`Pattern` validator API and expands the built-in
library from 14 validators to **223**, organized into 22 category
folders.
## Callable-`Pattern` contract
Every built-in validator is now a `Pattern` instance whose `__call__`
returns `bool`. The old function-style `validator(value)` call form
still works; every `Pattern` method is now also available on each
validator (`match`, `to_regex_string`, `.explain()`, `.visualize()`,
etc.).
```python
from edify import Pattern
from edify.library import uuid, email
isinstance(uuid, Pattern) # True
uuid("550e8400-e29b-11d4-a716-446655440000") # True
uuid.match("550e8400-e29b-11d4-a716-446655440000") # <re.Match ...>
email("[email protected]", strict=True) # available on parameterized validators
```
Implementation:
- `Pattern.__call__(value) -> bool` on the base class (non-string
returns `False`, no crash on user input).
- **Every validator is built via the fluent chain** —
`Pattern().start_of_input().exactly(8).any_of()....end_of_input()`. No
raw-regex escape hatch anywhere in the library.
- Composable atoms in `edify/library/_support/atoms.py` (`hex_any`,
`octet`, etc.) keep the chains readable across categories.
## The 223 patterns across 22 categories
| Category | Count | Patterns |
|---|---|---|
| `identifier/` | 26 | uuid, guid, mac, ssn, ein, tin, itin, iban, bic,
lei, isin, cusip, sedol, sku, asin, imei, meid, iccid, vin, imo, mmsi,
iata, icao, arn, orcid, did |
| `data/` | 14 | xml, json, yaml, toml, csv, tsv, ini, avro, protobuf,
msgpack, html, hdf5, parquet, orc |
| `address/` | 13 | ip, cidr, subnet, hostname, domain, subdomain, tld,
url, uri, path, port, socket, ptr |
| `software/` | 13 | semver, version, package, docker, image, digest,
git, ref, checksum, component, makefile, cargo, bump |
| `api/` | 12 | oauth, openid, saml, openapi, swagger, jsonapi, hal,
graphql, soap, webhook, rss, atom |
| `auth/` | 19 | password, pin, token, jwt, otp, apikey, bearer,
session, csrf, mnemonic, hmac, passkey, mfa, webauthn, secret, sso,
refresh, signing, challenge |
| `temporal/` | 11 | date, time, datetime, duration, timezone, offset,
epoch, timestamp, year, cron, interval |
| `text/` | 11 | slug, base, script, ascii, printable, alphanumeric,
alpha, numeric, word, unicode, emoji |
| `media/` | 11 | mimetype, extension, filename, glob, regex, shebang,
encoding, charset, locale, favicon, codec |
| `document/` | 11 | svg, pdf, epub, mobi, docx, xlsx, pptx, odt,
readme, rtf, tex |
| `security/` | 11 | pgp, pem, der, csr, x509, certificate, ssh, age,
keyring, nonce, signature |
| `web/` | 11 | sitemap, captcha, robots, manifest, htaccess, humans,
nginx, apache, cookie, csp, useragent |
| `numeric/` | 10 | number, integer, hash, percentage, ratio, fraction,
scientific, roman, ordinal, natural |
| `geo/` | 8 | coordinate, geohash, plus, postal, place, altitude, mgrs,
bearing |
| `contact/` | 7 | email, phone, fax, pager, address, username, handle |
| `financial/` | 7 | currency, card, wallet, crypto, routing, sortcode,
vat |
| `publishing/` | 6 | isbn, issn, doi, arxiv, pmid, pmc |
| `grammar/` | 6 | bnf, ebnf, abnf, peg, pest, antlr |
| `color/` | 5 | color, palette, swatch, gradient, filter |
| `transport/` | 4 | vehicle, aircraft, flight, plate |
| `medical/` | 4 | medical, blood, dosage, dicom |
| `product/` | 3 | gtin, mpn, barcode |
| **Total** | **223** | |
Each pattern is importable both from its category submodule and from the
flat top-level namespace:
```python
from edify.library import uuid # flat
from edify.library.identifier import uuid # category
```
## Merged and renamed 0.3 validators
Per the \"each pattern is unique / everything doable via a form must be
merged\" rule:
- `iso_date` → `date` (accepts every recognised date form)
- `email_rfc_5322` → `email` (accepts basic or RFC 5322)
- `ipv4` + `ipv6` → `ip`
- `phone_number` → `phone`
- `zip` → `postal`
Documented in \`docs/upgrading/0.3-to-1.0.rst\` under the \`..
_validators-callable:\` anchor.
Closes #176
Closes #177
Closes #178
Closes #179
Closes #180
Closes #181
Closes #182
Closes #183
Closes #184
Closes #185
Closes #186
Closes #187
Closes #188
Closes #189
Closes #190
Diffstat (limited to 'tests/pattern/boundaries.test.py')
| -rw-r--r-- | tests/pattern/boundaries.test.py | 4 |
1 files changed, 2 insertions, 2 deletions
diff --git a/tests/pattern/boundaries.test.py b/tests/pattern/boundaries.test.py index b391733..2892866 100644 --- a/tests/pattern/boundaries.test.py +++ b/tests/pattern/boundaries.test.py @@ -20,8 +20,8 @@ def test_non_word_boundary_compiles_to_backslash_capital_b(): def test_word_boundary_matches_fluent_chain_output(): - assert WORD_BOUNDARY._state == Pattern().word_boundary()._state + assert Pattern().word_boundary() == WORD_BOUNDARY def test_non_word_boundary_matches_fluent_chain_output(): - assert NON_WORD_BOUNDARY._state == Pattern().non_word_boundary()._state + assert Pattern().non_word_boundary() == NON_WORD_BOUNDARY |
