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.8.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.8-py3-none-any.whl (45.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: embody-0.1.8.tar.gz
  • Upload date:
  • Size: 365.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","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.8.tar.gz
Algorithm Hash digest
SHA256 02cad239735fc8b51d5f8227a5d308138d50ddb150ccd27f0a660a1f3a18ae4e
MD5 4ceb1dcb32d08b39912e13fb030f7d72
BLAKE2b-256 db3469e40660498be1f88a8b66af0b193fdaa7cb8fe94f0f05f29e28a72eff86

See more details on using hashes here.

File details

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

File metadata

  • Download URL: embody-0.1.8-py3-none-any.whl
  • Upload date:
  • Size: 45.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","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.8-py3-none-any.whl
Algorithm Hash digest
SHA256 cd3db2223474f138c0e7999980ce135a30b0b2345ea272dfe0c04a36168f5ecd
MD5 d20053655e435b3773fc43438e2c1197
BLAKE2b-256 784fbdf9def88c3ec9052165bebdfe6683d09e65469edd1d31e1e61f53a7f57d

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