Bridge validator locations (XPath/JSONPath/JSON Pointer) back to your application model paths, and emit structured errors (Marshmallow-ready).
Validators (XSD/Schematron, JSON Schema) report failures at document locations (XPath/JSONPath).
Your users need errors on your model (Pydantic/Marshmallow/dataclasses). PathBridge converts between the two.
- Prefix & case tolerant (e.g.,
hd:,MTR:). - Fixes 1-based indices to Python 0-based.
- Works with plain mappings or an optional tracer (add-on) that learns rules from your converter.
- Includes
make_shape(shaper) andbuild_rules(tracer) to generate rules from destination classes and your converter.
pip install pathbridgefrompathbridgeimportcompile_rules, translate_location, to_marshmallow# 1. Provide or load rules: destination path -> facade (your app models) path rules= {
"Return[1]/Contact[1]/Phone[1]": "person/phones[0]",
"Return[1]/Contact[1]/Phone[2]": "person/phones[1]",
}
compiled=compile_rules(rules)
# 2. Translate validator location (e.g. from Schematron SVRL)loc="/Return[1]/Contact[1]/Phone[2]"print(translate_location(loc, compiled))
# "person/phones[1]"# 3. Transform error location into a Marshmallow-style error dicterrors=to_marshmallow([(loc, "Invalid phone")], compiled)
# {'person': {'phones': {1: ['Invalid phone']}}}pathbridge.extras provides helper utilities for generating rules from your
converter:
make_shape(...): build a populated sample facade object.build_rules(...): trace a sample conversion and produceDestination -> Facademapping rules.
importdataclassesimporttypesfrompathbridgeimportcompile_rules, to_marshmallowfrompathbridge.extrasimportbuild_rules, make_shape@dataclasses.dataclassclassFacadeName:
first: strlast: str@dataclasses.dataclassclassFacade:
name: FacadeNamephones: list[str]
@dataclasses.dataclassclassNameXml:
first_name: str=dataclasses.field(metadata={"name": "FirstName"})
surname: str=dataclasses.field(metadata={"name": "Surname"})
@dataclasses.dataclassclassReturnXml:
name: NameXml=dataclasses.field(metadata={"name": "YourName"})
phones: list[str] =dataclasses.field(metadata={"name": "Phone"})
classMeta:
name="Return"defconvert(src: Facade) ->ReturnXml:
returnReturnXml(
name=NameXml(first_name=src.name.first, surname=src.name.last),
phones=src.phones,
)
shape=make_shape(Facade, list_len=2)
rules=build_rules(
destination_module=types.SimpleNamespace(ReturnXml=ReturnXml, NameXml=NameXml),
facade_to_destination=convert,
facade_shape=shape,
facade_root_tag="facade",
)
compiled=compile_rules(rules)
errors=to_marshmallow(
[
("/Return[1]/NameXml[1]/FirstName[1]", "Required field"),
("/Return[1]/Phone[2]/Phone[1]", "Invalid phone"),
],
compiled,
)
print(rules)
# {# 'Return[1]/NameXml[1]/FirstName[1]': 'facade/name/first',# 'Return[1]/Phone[2]/Phone[1]': 'facade/phones[1]',# ...# }print(errors)
# {# 'facade': {# 'name': {'first': ['Required field']},# 'phones': {1: ['Invalid phone']},# }# }make_shape(...) accepts type_defaults so you can override generated defaults
for specific types:
fromdecimalimportDecimalshape=make_shape(
Facade,
list_len=2,
type_defaults={
str: "sample",
int: 42,
Decimal: Decimal("1.23"),
},
)PathBridge provides a pathbridge CLI with a compile command that runs:
make_shape(...)build_rules(...)compile_rules(...)(when--emitincludes compiled output)- Python module generation
Run from the repository root:
pathbridge compile \
--output-dir . \
--output-package mtr.translation_rules \
--output-module compiled \
--facade-class ./tests/integration/hmrc_main_tax_return/facade/mtr_facade.py:MTR \
--destination-module ./tests/integration/hmrc_main_tax_return/destination/mtr_v1_1.py \
--facade-to-destination ./tests/integration/hmrc_main_tax_return/converter/mtr_converter.py:to_mtr_v1_1 \
--shape-list-len 10 \
--facade-root-tag mtr \
--lift-functions _yes \
--lift-functions _yes_no \
--lift-functions _tax_payer_status \
--lift-functions _student_loan_plan \
--lift-functions _postgraduate_loan_plan \
--lift-functions _attachment_file_format \
--lift-functions decimal_str_or_none \
--lift-functions xml_date_or_none \
--lift-functions decode_attachmentSee documentation for more details.
Real-life PathBridge integrations: