Skip to main content

embody

Structural Object Embodiment for Python - Transform skeletal templates into fully realized, type-safe objects through recursive hydration.

Documentation PyPI version Python

What is Embody?

Embody is a powerful library for templated object generation that goes beyond simple string formatting. It provides structural embodiment - the recursive hydration of nested data structures with type preservation, cycle detection, and intelligent traversal strategies.

Key Features

  • 🎯 Type Preservation: Variables like ${count} preserve their types (int, bool, list, dict) instead of converting everything to strings
  • 🔄 Multiple Strategies: Choose between recursive visitor, compiled path, or iterative stack traversal
  • 🎨 Multiple Syntaxes: Support for ${var}, {var}, and [[var]] template syntaxes
  • 🛡️ Cycle Detection: Automatically detect and prevent circular references
  • 📍 Path Addressing: Access nested data via JSON Pointer, dot notation, or tuple paths
  • 🗺️ Mapping Interfaces: Uniform interfaces for attribute access, flattening, and path-based operations
  • ⚡ Performance: Auto-selects optimal strategy based on template complexity
  • 🔒 Type Safety: Full integration with Pydantic and other validation libraries

Installation

pip install embody

Quick Start

Basic Usage

from embody import embody

# Simple template embodiment
template = {"name": "${name}", "age": "${age}", "greeting": "Hello ${name}!"}

result = embody(template, {"name": "Alice", "age": 30})
# {'name': 'Alice', 'age': 30, 'greeting': 'Hello Alice!'}

Type Preservation

Unlike traditional templating, embody preserves types:

template = {
    "count": "${num}",  # Will be int, not string!
    "active": "${flag}",  # Will be bool
    "items": "${list}",  # Will be list
    "message": "Count: ${num}",  # Will be string (interpolation)
}

result = embody(template, {"num": 42, "flag": True, "list": [1, 2, 3]})

assert isinstance(result["count"], int)  # True - type preserved!
assert isinstance(result["active"], bool)  # True
assert isinstance(result["items"], list)  # True

Nested Structures

Embody handles deep nesting naturally:

template = {
    "user": {
        "profile": {
            "name": "${name}",
            "settings": {"theme": "${theme}", "notifications": "${notify}"},
        }
    }
}

result = embody(template, {"name": "Bob", "theme": "dark", "notify": True})

Advanced Features

Context with Resolvers

from embody import Context
import datetime

ctx = Context({"now": lambda: datetime.datetime.now(), "user": "Alice"})

# Callables are invoked on access
print(ctx["now"])  # Current time
print(ctx["user"])  # 'Alice'

Mapping Interfaces

from embody.mappings import AttributeMapping, PathMapping

# Attribute access (Box pattern)
attr_map = AttributeMapping({"user": {"name": "Alice"}})
print(attr_map.user.name)  # 'Alice'

# Path-based access
path_map = PathMapping({"a": {"b": {"c": 42}}})
print(path_map["a.b.c"])  # Dot notation
print(path_map["/a/b/c"])  # JSON Pointer
print(path_map[("a", "b", "c")])  # Tuple path

Path Addressing

from embody.paths import JSONPointer, resolve_path

data = {"users": [{"name": "Alice"}, {"name": "Bob"}]}

# JSON Pointer (RFC 6901)
ptr = JSONPointer("/users/0/name")
print(ptr.resolve(data))  # 'Alice'

# Convenience function
print(resolve_path(data, "users.0.name"))  # 'Alice'

Traversal Strategies

from embody import Embodier

template = {"data": "${value}"}

# Recursive visitor (default, best for one-off templates)
embodier1 = Embodier(template, strategy="recursive")

# Compiled path (best for repeated embodiment)
embodier2 = Embodier(template, strategy="compiled")

# Auto-select based on template complexity
embodier3 = Embodier(template, strategy="auto")

result = embodier1({"value": 42})

Examples

Configuration Management

from embody import embody
import os

config_template = {
    "database": {"host": "${db_host}", "port": "${db_port}", "name": "${db_name}"},
    "api": {"base_url": "${api_url}", "timeout": "${timeout}"},
}

config = embody(
    config_template,
    {
        "db_host": os.getenv("DB_HOST", "localhost"),
        "db_port": int(os.getenv("DB_PORT", "5432")),
        "db_name": "myapp",
        "api_url": "https://api.example.com",
        "timeout": 30,
    },
)

API Response Templates

from embody import Embodier

response_template = {
    "status": "success",
    "data": {"user_id": "${id}", "name": "${name}", "timestamp": "${ts}"},
}

embodier = Embodier(response_template, strategy="compiled")

# Efficiently generate many responses
for user in users:
    response = embodier({"id": user.id, "name": user.name, "ts": datetime.now()})

Backwards Compatibility

The original Templater API is fully preserved:

from embody.templater import Templater

template = {"hello": "{name}", "how are you": ["{verb}", 2, "{name} and {verb} again"]}

g = Templater.template_func(template=template)
result = g(name="NAME", verb="VERB")
# {'hello': 'NAME', 'how are you': ['VERB', 2, 'NAME and VERB again']}

Documentation

Contributing

Contributions are welcome! Please see our contributing guidelines.

License

Apache License 2.0 - see LICENSE file for details.

Download files

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

Source Distribution

embody-0.1.10.tar.gz (365.6 kB view details)

Uploaded Source

Built Distribution

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

embody-0.1.10-py3-none-any.whl (45.5 kB view details)

Uploaded Python 3

File details

Details for the file embody-0.1.10.tar.gz.

File metadata

  • Download URL: embody-0.1.10.tar.gz
  • Upload date:
  • Size: 365.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for embody-0.1.10.tar.gz
Algorithm Hash digest
SHA256 119d166edc6321972125678950cb56587bbe73d32e9357065ea78b9802a37cac
MD5 a22580230fa94cb810dcd6be356c3ce8
BLAKE2b-256 5f3910aa4465872af7993444a17b865a66c3046edfc8daee6c127088e8f82e64

See more details on using hashes here.

File details

Details for the file embody-0.1.10-py3-none-any.whl.

File metadata

  • Download URL: embody-0.1.10-py3-none-any.whl
  • Upload date:
  • Size: 45.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for embody-0.1.10-py3-none-any.whl
Algorithm Hash digest
SHA256 5d7485a05d3f392920e69ee17442f8b90f80e2e1d9321756afa858a72674f07c
MD5 2b8248c194d86e9e6fb4bb113e5a144c
BLAKE2b-256 adb1a5d8e06a112a4aee71d2dc82e6a7f44e963b285fcb2dc2d16589e166af01

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.10 This release

2 files

0.1.9

2 files

0.1.8

2 files

0.1.7

2 files

0.1.6

2 files

0.1.5

1 file

0.1.4

1 file

0.1.3

1 file

0.1.2

1 file

0.1.1

1 file

0.1.0

1 file

0.0.2

2 files

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