Skip to main content

Generate templated objects

Project description

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

MIT License - see LICENSE file for details.

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

embody-0.1.9.tar.gz (365.0 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.9-py3-none-any.whl (45.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: embody-0.1.9.tar.gz
  • Upload date:
  • Size: 365.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","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.9.tar.gz
Algorithm Hash digest
SHA256 b48e26db4c200262397faed6e7ef128a4831375e918d3164fcfac780ba8f3a83
MD5 aab51f3782e493daf924c8d51d690f11
BLAKE2b-256 26858ec1964127d3a16027bf5dae3c0d18f64a5af873e6507f73394cdde46346

See more details on using hashes here.

File details

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

File metadata

  • Download URL: embody-0.1.9-py3-none-any.whl
  • Upload date:
  • Size: 45.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","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.9-py3-none-any.whl
Algorithm Hash digest
SHA256 ad7ec546ee693c9d782f8dd5001af2cef2766b34268dbc09e967827acdcdb472
MD5 45a74570a5074259d075554b6d89e190
BLAKE2b-256 6c32f8dd4644a2bb0f8a88359836d33743b3d9fefadd0e7752a06bb00910a53a

See more details on using hashes here.

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