{"id":46736908,"url":"https://github.com/pilosus/pathbridge","last_synced_at":"2026-03-09T16:54:22.526Z","repository":{"id":338495168,"uuid":"1147284465","full_name":"pilosus/pathbridge","owner":"pilosus","description":"Translate validator error locations (XPath/JSONPath/JSON Pointer) back to your application's schema paths and emit structured errors (Marshmallow-ready)","archived":false,"fork":false,"pushed_at":"2026-03-07T12:57:07.000Z","size":231,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-07T19:31:04.649Z","etag":null,"topics":["error-mapping","marshmallow","schematron","tracing","validation","xpath","xsd","xsdata"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pilosus.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-01T14:06:30.000Z","updated_at":"2026-03-07T12:57:10.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/pilosus/pathbridge","commit_stats":null,"previous_names":["pilosus/pathbridge"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/pilosus/pathbridge","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pilosus%2Fpathbridge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pilosus%2Fpathbridge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pilosus%2Fpathbridge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pilosus%2Fpathbridge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pilosus","download_url":"https://codeload.github.com/pilosus/pathbridge/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pilosus%2Fpathbridge/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30303162,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-09T14:33:48.460Z","status":"ssl_error","status_checked_at":"2026-03-09T14:33:48.027Z","response_time":61,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["error-mapping","marshmallow","schematron","tracing","validation","xpath","xsd","xsdata"],"created_at":"2026-03-09T16:54:21.793Z","updated_at":"2026-03-09T16:54:22.510Z","avatar_url":"https://github.com/pilosus.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PathBridge\n\n\u003e Bridge validator locations (XPath/JSONPath/JSON Pointer) back to your application model paths, and emit structured errors (Marshmallow-ready).\n\n[![PyPI version](https://img.shields.io/pypi/v/pathbridge.svg)](https://pypi.org/project/pathbridge/)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n[![Python](https://img.shields.io/pypi/pyversions/pathbridge.svg)](https://pypi.org/project/pathbridge/)\n[![Documentation](https://readthedocs.org/projects/pathbridge/badge/?version=latest)](https://pathbridge.readthedocs.io/en/latest/)\n\n## Why\n\nValidators (XSD/Schematron, JSON Schema) report failures at **document locations** (XPath/JSONPath).  \nYour users need errors on **your model** (Pydantic/Marshmallow/dataclasses). PathBridge converts between the two.\n\n- Prefix \u0026 case tolerant (e.g., `hd:`, `MTR:`).\n- Fixes 1-based indices to Python 0-based.\n- Works with plain mappings or an optional tracer (add-on) that learns rules from your converter.\n- Includes `make_shape` (shaper) and `build_rules` (tracer) to generate rules\n  from destination classes and your converter.\n\n## Install\n\n```bash\npip install pathbridge\n```\n\n## Quick start\n\n```python\nfrom pathbridge import compile_rules, translate_location, to_marshmallow\n\n# 1. Provide or load rules: destination path -\u003e facade (your app models) path \nrules = {\n    \"Return[1]/Contact[1]/Phone[1]\": \"person/phones[0]\",\n    \"Return[1]/Contact[1]/Phone[2]\": \"person/phones[1]\",\n}\n\ncompiled = compile_rules(rules)\n\n# 2. Translate validator location (e.g. from Schematron SVRL)\nloc = \"/Return[1]/Contact[1]/Phone[2]\"\nprint(translate_location(loc, compiled))\n# \"person/phones[1]\"\n\n# 3. Transform error location into a Marshmallow-style error dict\nerrors = to_marshmallow([(loc, \"Invalid phone\")], compiled)\n# {'person': {'phones': {1: ['Invalid phone']}}}\n```\n\n## Extras\n\n`pathbridge.extras` provides helper utilities for generating rules from your\nconverter:\n\n- `make_shape(...)`: build a populated sample facade object.\n- `build_rules(...)`: trace a sample conversion and produce `Destination -\u003e Facade`\n  mapping rules.\n\n### Extras example\n\n```python\nimport dataclasses\nimport types\n\nfrom pathbridge import compile_rules, to_marshmallow\nfrom pathbridge.extras import build_rules, make_shape\n\n\n@dataclasses.dataclass\nclass FacadeName:\n    first: str\n    last: str\n\n\n@dataclasses.dataclass\nclass Facade:\n    name: FacadeName\n    phones: list[str]\n\n\n@dataclasses.dataclass\nclass NameXml:\n    first_name: str = dataclasses.field(metadata={\"name\": \"FirstName\"})\n    surname: str = dataclasses.field(metadata={\"name\": \"Surname\"})\n\n\n@dataclasses.dataclass\nclass ReturnXml:\n    name: NameXml = dataclasses.field(metadata={\"name\": \"YourName\"})\n    phones: list[str] = dataclasses.field(metadata={\"name\": \"Phone\"})\n\n    class Meta:\n        name = \"Return\"\n\n\ndef convert(src: Facade) -\u003e ReturnXml:\n    return ReturnXml(\n        name=NameXml(first_name=src.name.first, surname=src.name.last),\n        phones=src.phones,\n    )\n\n\nshape = make_shape(Facade, list_len=2)\nrules = build_rules(\n    destination_module=types.SimpleNamespace(ReturnXml=ReturnXml, NameXml=NameXml),\n    facade_to_destination=convert,\n    facade_shape=shape,\n    facade_root_tag=\"facade\",\n)\n\ncompiled = compile_rules(rules)\nerrors = to_marshmallow(\n    [\n        (\"/Return[1]/NameXml[1]/FirstName[1]\", \"Required field\"),\n        (\"/Return[1]/Phone[2]/Phone[1]\", \"Invalid phone\"),\n    ],\n    compiled,\n)\n\nprint(rules)\n# {\n#   'Return[1]/NameXml[1]/FirstName[1]': 'facade/name/first',\n#   'Return[1]/Phone[2]/Phone[1]': 'facade/phones[1]',\n#   ...\n# }\nprint(errors)\n# {\n#   'facade': {\n#     'name': {'first': ['Required field']},\n#     'phones': {1: ['Invalid phone']},\n#   }\n# }\n```\n\n### Custom shape defaults\n\n`make_shape(...)` accepts `type_defaults` so you can override generated defaults\nfor specific types:\n\n```python\nfrom decimal import Decimal\n\nshape = make_shape(\n    Facade,\n    list_len=2,\n    type_defaults={\n        str: \"sample\",\n        int: 42,\n        Decimal: Decimal(\"1.23\"),\n    },\n)\n```\n\n## CLI\n\nPathBridge provides a `pathbridge` CLI with a `compile` command that runs:\n\n1. `make_shape(...)`\n2. `build_rules(...)`\n3. `compile_rules(...)` (when `--emit` includes compiled output)\n4. Python module generation\n\n\n### CLI example\n\nRun from the repository root:\n\n```bash\npathbridge compile \\\n  --output-dir . \\\n  --output-package mtr.translation_rules \\\n  --output-module compiled \\\n  --facade-class ./tests/integration/hmrc_main_tax_return/facade/mtr_facade.py:MTR \\\n  --destination-module ./tests/integration/hmrc_main_tax_return/destination/mtr_v1_1.py \\\n  --facade-to-destination ./tests/integration/hmrc_main_tax_return/converter/mtr_converter.py:to_mtr_v1_1 \\\n  --shape-list-len 10 \\\n  --facade-root-tag mtr \\\n  --lift-functions _yes \\\n  --lift-functions _yes_no \\\n  --lift-functions _tax_payer_status \\\n  --lift-functions _student_loan_plan \\\n  --lift-functions _postgraduate_loan_plan \\\n  --lift-functions _attachment_file_format \\\n  --lift-functions decimal_str_or_none \\\n  --lift-functions xml_date_or_none \\\n  --lift-functions decode_attachment\n```\n\n## Help\n\nSee [documentation](https://pathbridge.readthedocs.io/) for more details.\n\n## Real-world examples\n\nReal-life PathBridge integrations:\n\n- [HMRC Main Tax Return integration](https://github.com/pilosus/pathbridge/tree/main/tests/integration/hmrc_main_tax_return)\n- [OpenAPI JSON Schema integration](https://github.com/pilosus/pathbridge/tree/main/tests/integration/openapi_json_schema)\n- [ISO 20022 payments integration](https://github.com/pilosus/pathbridge/tree/main/tests/integration/iso20022_payments)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpilosus%2Fpathbridge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpilosus%2Fpathbridge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpilosus%2Fpathbridge/lists"}