aboutsummaryrefslogtreecommitdiff
path: root/.github
diff options
context:
space:
mode:
authorBobby <[email protected]>2026-07-16 14:21:24 +0530
committerGitHub <[email protected]>2026-07-16 14:21:24 +0530
commitb9914de793844d3ad6e2d7503209ac8fd339d6de (patch)
treeede1621e0daf6e15706595fb905c0fbc91f26dfd /.github
parent433d41bf5887e61cc570a874e244e226c25b8a41 (diff)
parent453aea2b3ec5ae941407ac781ede7e4efda43ae8 (diff)
downloadedify-b9914de793844d3ad6e2d7503209ac8fd339d6de.tar.xz
edify-b9914de793844d3ad6e2d7503209ac8fd339d6de.zip
feat(integrations): pydantic, fastapi, django integration modules as opt-in extras (#284)
Ships the framework-integrations bundle end to end so an :class:`edify.Pattern` can drop straight into the field-validation layers of the three Python frameworks most teams actually use. ## Integration modules - **`edify.integrations.pydantic`** — `pattern_validator(pattern)` returns a Pydantic-compatible validator callable; `pattern_field(pattern)` returns an `Annotated[str, AfterValidator(...)]` type you drop into a `BaseModel` field. - **`edify.integrations.fastapi`** — `pattern_query(pattern, ...)` and `pattern_path(pattern, ...)` return `fastapi.Query` / `fastapi.Path` values pinned to the pattern's emitted regex string, with `default=` and every other FastAPI kwarg forwarded through. - **`edify.integrations.django`** — `pattern_validator(pattern, message=..., code=...)` returns a `django.core.validators.RegexValidator` pinned to the pattern's regex source, with the message default derived from the pattern. Every integration follows the same deferred-import pattern that `edify[regex]` uses: `import edify.integrations.pydantic` (etc.) succeeds without the framework installed; the first helper call resolves the framework lazily and raises `MissingIntegrationDependencyError` (annotated summary + pointer block + `= note:` + `help:` line) telling the caller to `pip install edify[<framework>]`. ## Extras + optional-dependencies - `[project.optional-dependencies]` gains `pydantic = ["pydantic>=2.0"]`, `fastapi = ["fastapi>=0.100"]`, `django = ["django>=4.2"]`, and `all = [everything]`. - The `dev` group installs all three frameworks so local + CI runs cover the integrations without gating on the extras. ## CI install-per-extra verification - New matrix job `install-with-integration-extra` runs one entry per extra (`pydantic`, `fastapi`, `django`, `all`). - Each entry installs into a fresh venv, imports the integration module, and drives a small probe script that verifies the helper accepts a matching value and rejects a non-matching value. - Same shape as the existing `install: edify[regex]` verification — any drift in the `[project.optional-dependencies]` declarations fails loudly. ## Sphinx autodoc - New `docs/integrations/index.rst` page with `.. automodule::` blocks for each of the three integration modules. - Wired into `docs/index.rst` toctree. - `.readthedocs.yml` installs `.[all]` so autodoc always has every framework annotation available to resolve. Closes #220, closes #221, closes #222, closes #223, closes #224, closes #225, closes #226, closes #227.
Diffstat (limited to '.github')
-rw-r--r--.github/workflows/github-actions.yml75
1 files changed, 75 insertions, 0 deletions
diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml
index c0ed6e2..f9f49d6 100644
--- a/.github/workflows/github-actions.yml
+++ b/.github/workflows/github-actions.yml
@@ -131,6 +131,81 @@ jobs:
assert via_regex.search("foofoobar") is not None
PYCHECK
+ install-with-integration-extra:
+ name: ${{ matrix.name }}
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - name: 'install: edify[pydantic]'
+ extra: 'pydantic'
+ probe: |
+ import edify
+ from edify.integrations.pydantic import pattern_validator
+ from edify.library import email
+ validate = pattern_validator(email)
+ assert validate("[email protected]") == "[email protected]"
+ try:
+ validate("bad")
+ except ValueError:
+ pass
+ else:
+ raise SystemExit("expected ValueError on non-matching input")
+ - name: 'install: edify[fastapi]'
+ extra: 'fastapi'
+ probe: |
+ import edify
+ from edify.integrations.fastapi import pattern_query, pattern_path
+ from edify.library import uuid
+ from fastapi.params import Query, Path
+ assert isinstance(pattern_query(uuid), Query)
+ assert isinstance(pattern_path(uuid), Path)
+ - name: 'install: edify[django]'
+ extra: 'django'
+ probe: |
+ import edify
+ from edify.integrations.django import pattern_validator
+ from edify.library import uuid
+ from django.core.exceptions import ValidationError
+ from django.core.validators import RegexValidator
+ validator = pattern_validator(uuid)
+ assert isinstance(validator, RegexValidator)
+ validator("01234567-89ab-1cde-8f01-23456789abcd")
+ try:
+ validator("not-a-uuid")
+ except ValidationError:
+ pass
+ else:
+ raise SystemExit("expected ValidationError on non-matching input")
+ - name: 'install: edify[all]'
+ extra: 'all'
+ probe: |
+ import edify
+ import pydantic
+ import fastapi
+ import django
+ from edify.integrations import pydantic as edify_pydantic
+ from edify.integrations import fastapi as edify_fastapi
+ from edify.integrations import django as edify_django
+ from edify.library import email
+ assert edify_pydantic.pattern_validator(email)("[email protected]") == "[email protected]"
+ steps:
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
+ - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39
+ with:
+ python-version: '3.11'
+ - name: install edify[${{ matrix.extra }}]
+ run: |
+ uv venv .venv-${{ matrix.extra }}
+ uv pip install --python .venv-${{ matrix.extra }}/bin/python '.[${{ matrix.extra }}]'
+ - name: probe integration surface
+ env:
+ PROBE_SCRIPT: ${{ matrix.probe }}
+ run: |
+ .venv-${{ matrix.extra }}/bin/python -c "$PROBE_SCRIPT"
+
bench:
name: 'bench (advisory)'
runs-on: ubuntu-latest