Skip to main content

formkrafter (Python)

FormKrafter for Python backends. The server validates a submission with the same spec the browser renders, and reaches the same verdict: same error keys (items[0].hs_code), same messages, same warnings as @streamline-pulse/formkrafter-core.

pip install formkrafter            # no dependency
pip install "formkrafter[pydantic]"  # Pydantic models for specs built in code
from formkrafter import validate_form_data

result = validate_form_data(spec, payload, locale="fr")
if not result.valid:
    # {"items[0].declared_value": "Minimum 0", "origin": "Ce champ est obligatoire"}
    return 422, result.errors

What it does

Function Core equivalent
build_validation_schema(spec, locale) buildValidationSchema: the same Ajv schema, key for key
validate_form_data(spec, data, locale, rule_scope) validateFormData: empty strings and nulls count as missing, collections are validated row by row, fields hidden by rules are not checked
lint_spec(spec) lintSpec: keyless inputs, validations without a dataType, duplicate keys, empty collections
register_validation_messages(locale, messages) registerValidationMessages
jsonlogic.apply(logic, data) jsonLogic.apply from json-logic-js 2.0.5, JavaScript coercions included
get_affected_properties(rules, data), is_rule_active, hidden_keys(spec, data) getAffectedProperties and the hidden walk of the validator
check_identity(format, value), check_iban, format_iban checkIdentity, checkIban, formatIban (NIR, NPI, SIREN, SIRET, IFU, IBAN, digits-<n>)
check_plate, format_plate, check_company_registry, format_company_registry same names (plates FR/BJ/CI/SN, RCCM OHADA, RCS)
parse_mrz(text) parseMrz: TD3 passports and TD1 identity cards, every check digit
default_form_data, iterate_bricks, iterate_schema_bricks, resolve_localized_text same names in camelCase

validate_form_data returns a ValidationResult:

  • valid, errors (key → message) and warnings, as in the browser; to_dict() gives the core's shape;
  • details (key → ErrorDetail(validator, message, value)), so an API can return a stable code and let the client word it: {"items[0].declared_value": {"validator": "min", "value": 0, "message": "Minimum 0"}}.

Every function takes a plain dict or a formkrafter.models.BrickSpec.

Supported

  • Validations: required, min/max, minLength/maxLength, pattern, minItems/maxItems, email, url.
  • Bricks: panels, inputs, selects (multiple included), collections (data grids, nested at any depth), outputs. On top of those:
    • national-id and tax-id check their idFormat, iban its key;
    • vehicle-plate and company-registry check their format;
    • date-range must not end before it starts;
    • mrz must hold a readable zone whose check digits match.
  • Rules: JsonLogic rules are evaluated on the submitted data (plus rule_scope): a field they hide is not checked, as in the browser. Rules that only disable, prefill or require never change the verdict, whatever their language.

One deliberate difference: the browser trusts the valid flag the mrz brick stores, while the server re-reads the zone (raw) it was sent. Honest data gets the same verdict; a forged flag does not pass.

The details that usually make a Python port drift are reproduced:

  • Ajv's email and uri formats, copied verbatim;
  • the browser's RegExp: $ never matches before a trailing newline, and \d is ASCII;
  • String(1e-7) is 1e-7;
  • the core compares lengths in code points;
  • JsonLogic's ==, < and + coerce like JavaScript ("1" == 1, [2] < 10), and [] is falsy;
  • a schema Ajv refuses to compile enforces no rule (with a warning). An idFormat, plateFormat or registryFormat the core does not know is one such case.

Refused

JavaScript never runs server-side. validate_form_data raises SpecNotSupported rather than half-validating a spec where JavaScript decides the verdict:

  • custom validators (validator: "custom"): move the check to the server, or to a declarative validation;
  • JavaScript rules, or code effects, that hide data-carrying fields: write the condition in JsonLogic.

JavaScript rules that hide nothing (a disabled effect, a note) are accepted.

build_validation_schema and lint_spec work on every spec. assert_supported(spec) checks up front, for instance in the tests that cover the specs a backend serves.

Parity with the core

tests/parity/cases.json holds specs and data samples. The core compiles and validates them:

bun scripts/python-parity.ts      # from the repository root: rewrites tests/parity/expected.json
uv run pytest                     # the port must reach the same schemas, lint issues and verdicts

CI regenerates the fixtures and fails when they are stale, so a change in the core shows up in the Python tests. formkrafter.CORE_VERSION names the core release a version follows.

In your own project

formkrafter.testing checks your specs against the real core, through Node and your web app's installed @streamline-pulse/formkrafter-core:

from formkrafter.testing import assert_matches_core

def test_served_forms_match_the_browser():
    assert_matches_core(SPEC, samples=[VALID, {}, {"items": []}], locales=["fr", "en"], node_project="../web")

export_contract(spec, locales) returns the spec with its schema per locale. Write it where your web tests read it to assert that buildValidationSchema(spec, locale) gives the same.

Metadata

Release files for formkrafter 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for formkrafter 0.2.0
File Size Uploaded Provenance Actions
formkrafter-0.2.0.tar.gz 88.0 kB With provenance Details for formkrafter-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for formkrafter 0.2.0
File Interpreter ABI Platform Actions
formkrafter-0.2.0-py3-none-any.whl Python 3 none any Details for formkrafter-0.2.0-py3-none-any.whl

Total release size: 118.8 kB

Release files / formkrafter-0.2.0.tar.gz

Download URL formkrafter-0.2.0.tar.gz
Size 88.0 kB
Tags Source
SHA-256 checksum
How to use checksums
714379bbcaa750d15fbc7d72bff80edb7190dc59c7a8966f83e77d2dd136d876
BLAKE2b-256 checksum
How to use checksums
217d809b4b3360347bf0daa8ee917664818054ac6f24c1ff83a1d702045510d5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.

Transparency log

Release files / formkrafter-0.2.0-py3-none-any.whl

Download URL formkrafter-0.2.0-py3-none-any.whl
Size 30.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
16810bdce50be53bd72e7f46f3c55800d2cf2e44ff1d77761767c6f5be596f0e
BLAKE2b-256 checksum
How to use checksums
d0e622a36e9cac16ef4f005b5337d0ab395aebdbdb33b5ace133ef323e4b1368
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.

Transparency log

Security for formkrafter 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for formkrafter-0.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page