Skip to main content

Map Pydantic models safely, using JMESPath

Project description

spaghettimap

A Python library for pydantic model-to-model conversion powered by JMESPath.

Features

  • Map any pydantic BaseModel to another using a declarative schema
  • Schema values can be JMESPath expressions, Python callables, or a dict combining both with an optional transform
  • Full support for all JMESPath built-in functions (length, sort, max_by, contains, join, keys, to_string, …)
  • Custom JMESPath functions via jmespath.functions.Functions subclass
  • Filter expressions, multi-select hash/list, pipe expressions, wildcards, and or-expressions
  • Solid error handling with ConfigurationError, MappingError, and FieldMappingError – all with clear, field-specific messages
  • Fail-fast config checks for invalid JMESPath expressions and schema fields missing from the target model
  • Pydantic validators (@field_validator, @model_validator) and type coercion run on the target model automatically
  • map_many() for batch conversion of model lists

Installation

pip install spaghettimap
# or with uv
uv add spaghettimap

Quick Start

from pydantic import BaseModel
from spaghettimap import Mapper, MappingConfig

class Source(BaseModel):
    first_name: str
    last_name: str
    contact: dict  # {"email": "...", "phone": "..."}
    tags: list[dict]  # [{"name": "...", "weight": 1.0}]

class Target(BaseModel):
    full_name: str
    email: str
    tag_count: int
    upper_name: str

mapper = Mapper()
mapper.add_config(
    MappingConfig(
        from_type=Source,
        to_type=Target,
        schema={
            # Python callable
            "full_name": lambda d: f"{d['first_name']} {d['last_name']}",
            # Nested JMESPath expression
            "email": "contact.email",
            # JMESPath built-in function
            "tag_count": "length(tags)",
            # JMESPath expression + Python transform
            "upper_name": {"expression": "first_name", "transform": str.upper},
        },
    )
)

result: Target = mapper.map(source_instance, Target)

Schema Value Types

Type Description Example
str JMESPath expression "contact.email", "tags[*].name", "length(tags)"
Callable[[dict], Any] Python function receiving the full source dict lambda d: d["x"] + d["y"]
dict {"expression": str|Callable, "transform": Callable} {"expression": "price", "transform": lambda p: f"£{p:.2f}"}

Custom JMESPath Functions

import jmespath.functions
from spaghettimap import Mapper, MappingConfig

class MyFunctions(jmespath.functions.Functions):
    @jmespath.functions.signature({"types": ["string"]})
    def _func_upper(self, value: str) -> str:
        return value.upper()

mapper.add_config(
    MappingConfig(
        from_type=Source,
        to_type=Target,
        schema={"name": "upper(first_name)"},
        custom_functions=MyFunctions(),
    )
)

Batch Mapping

results: list[Target] = mapper.map_many(source_list, Target)

Error Hierarchy

SpaghettimapMapperError
├── ConfigurationError   – invalid config (bad types, missing keys, unregistered pair)
└── MappingError         – runtime mapping failure
    └── FieldMappingError – failure for a specific field (has .field attribute)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

spaghettimap-0.6.0.tar.gz (6.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

spaghettimap-0.6.0-py3-none-any.whl (8.4 kB view details)

Uploaded Python 3

File details

Details for the file spaghettimap-0.6.0.tar.gz.

File metadata

  • Download URL: spaghettimap-0.6.0.tar.gz
  • Upload date:
  • Size: 6.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for spaghettimap-0.6.0.tar.gz
Algorithm Hash digest
SHA256 f95ed7bf830d448abebc728625c8cd6a9f414090c9371c33fab612570179802d
MD5 1bc40f3563270ac32d0acedce500990d
BLAKE2b-256 041eab765d1840281c35a712403257d7ab4a22c844e0dca9c0dbd43f68b857c2

See more details on using hashes here.

Provenance

The following attestation bundles were made for spaghettimap-0.6.0.tar.gz:

Publisher: ci-cd.yml on mfowlerrr/spaghettimap

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file spaghettimap-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: spaghettimap-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 8.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for spaghettimap-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a2cda7dbd0fa8e983257374c8d6a0ba7c0d2bfbf9714be0c10daa1104d3f1b40
MD5 0392e13bc17464d9e33391c0a19c6af8
BLAKE2b-256 6d492f4757aee03ca84f654a051358aa3a76f1831e6db487f1e2cd639f68b85e

See more details on using hashes here.

Provenance

The following attestation bundles were made for spaghettimap-0.6.0-py3-none-any.whl:

Publisher: ci-cd.yml on mfowlerrr/spaghettimap

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page