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.5.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.5.0-py3-none-any.whl (8.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: spaghettimap-0.5.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.5.0.tar.gz
Algorithm Hash digest
SHA256 df4f9905ac9392b3b7228925f540daf75066332c618a1cecc371f13948380662
MD5 2dc9eac57ba6da633d28d61311078af7
BLAKE2b-256 f46b8e849f7dd7626cad6894380a4b6e87b8f220d10e7d2df835b263a0ae4b56

See more details on using hashes here.

Provenance

The following attestation bundles were made for spaghettimap-0.5.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.5.0-py3-none-any.whl.

File metadata

  • Download URL: spaghettimap-0.5.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.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8537b40bec659fc36a390d7b7e425c88d6b2f8a0c401a4bd7a0e804f8505e522
MD5 08d4fc2f3f357f942edd7e58a23722d3
BLAKE2b-256 6976f1f5365b87386ae1949b00895dcf9cb5db5880be821397fc63332e7639e3

See more details on using hashes here.

Provenance

The following attestation bundles were made for spaghettimap-0.5.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