Skip to main content

EBlock (Easy Block Builder)

A flexible, schema-driven library for building dynamic, context-aware content blocks with variable substitution, nested composition, validation, and asynchronous rendering.

Designed for use in page builders, CMS backends, or dynamic UI generation systems where content is defined as structured JSON, rendered with context variables, and validated via Pydantic models.


Installation

pip install eblock

or with uv:

uv add eblock

Core Concepts

Context

A container for variables and metadata used during block rendering.

  • Variables are case-normalized to uppercase.
  • Supports deep copying for safety.
  • Allows dynamic assignment via ctx["key"] = value.
  • Stores:
    • vars: dictionary of scalar or structured values (strings, numbers, lists, dicts, etc.)
    • extra: arbitrary metadata (not used in substitution)

BaseBlock

Abstract base class for all content blocks.

Each block: - Accepts properties (dict) on initialization. - Optionally validates input/output using Pydantic models. - Recursively resolves {{ variable }} placeholders from Context. - Supports nesting inside dicts, lists, tuples, and sets. - Exposes an async build() method returning (result_dict, output_schema). - Allows custom output transformation via prepare_output().


Block Registration Mechanism

EBlock uses an automatic class-based registration system powered by the BlockMeta metaclass.

How It Works

Every subclass of BaseBlock that defines a _type attribute is automatically registered on import.

class TextBlock(BaseBlock):
    _type = "text"

When Python loads this class:

  • BlockMeta.__new__ is triggered.
  • If _type is not "base" and not private (_SomethingBlock), the block is added to the global registry.
  • Duplicate _type values produce a warning and are ignored.

Accessing Registered Blocks

You can list all registered block types:

from eblock import get_registered_block_types

print(get_registered_block_types())
# ["text", "score_card", ...]

Creating Blocks Dynamically

Use the factory function:

from eblock import create_block

block = create_block("text", {"content": "Hello"})

Building Blocks from JSON-like Config

The library supports nested block trees:

from eblock import create_blocks_from_config

blocks = create_blocks_from_config([
    {"type": "text", "properties": {"content": "Hi"}},
    {"type": "score_card", "properties": {"title": "Test", "score": 95}},
])

Nested blocks inside dicts/lists are resolved recursively.

Why Use Automatic Registration?

  • No need for manual registries.
  • Blocks register themselves as soon as they are imported.
  • Decoupled plugins/modules can define their own block types.
  • Ensures consistency when building from JSON configs.

Features

✅ Variable substitution
Placeholders like {{ user_name }} are replaced with values from context.

✅ Recursive structure support
Handles dicts, lists, tuples, sets, and nested BaseBlock instances.

✅ Input/Output validation
Define _input_schema and _output_schema using Pydantic models.

✅ Computed fields
Override prepare_output() to modify or add fields before output validation.

✅ Static dependency analysis
Use .get_vars() to extract all required variables, including in nested blocks.

✅ Async-first design
Full async/await support throughout the rendering pipeline.

✅ Structured logging
Blocks and context instances log operations through hierarchical loggers.


Usage Examples

Basic Block

from eblock import BaseBlock, Context

class TextBlock(BaseBlock):
    _type = "text"

ctx = Context(vars={"name": "Alice"})
block = TextBlock({"content": "Hello, {{ name }}!"})
result, _ = await block.build(ctx)
# result == {"content": "Hello, Alice!"}

Validated Block with Computed Output

from pydantic import BaseModel
from eblock import BaseBlock

class Input(BaseModel):
    title: str
    score: int

class Output(BaseModel):
    title: str
    score: int
    badge: str

class ScoreCard(BaseBlock):
    _type = "score_card"
    _input_schema = Input
    _output_schema = Output

    async def prepare_output(self, result, ctx):
        result["badge"] = "🏆" if result["score"] >= 90 else "📝"
        return result

Nested Blocks

header = TextBlock({"text": "Welcome, {{ user }}!"})
page = PageBlock({"header": header, "theme": "{{ theme }}"})
# Both variables will be resolved from context

Variable Inspection

block = TextBlock({"msg": "Hi {{ first }}, {{ last }}!"})
print(block.get_vars())  # {"FIRST", "LAST"}

API Reference

class Context

  • __init__(self, vars: dict | None = None, **extra)
  • __getitem__(key)
  • __setitem__(key, value)
  • Properties:
    • vars --- deep copy of stored variables\
    • extra --- shallow copy of extra data

class BaseBlock

  • __init__(self, properties: dict)
  • async build(self, ctx: Context) -> tuple[dict, Type[BaseModel] | None]
  • async prepare_output(self, result: dict, ctx: Context) -> dict
  • get_vars(self) -> set[str]
  • Property: type --- block identifier

Define in subclasses

  • _type: str --- identifier (required)
  • _input_schema: Type[BaseModel] | None
  • _output_schema: Type[BaseModel] | None

Registry Helpers

  • create_block(type, properties)
  • create_blocks_from_config(config)
  • get_registered_block_types()

Requirements

  • Python ≥ 3.10
  • Pydantic ≥ 2.0

Notes

  • Placeholders must use double curly braces: {{ var_name }}.
  • Whitespace is trimmed: {{ user }} → user.
  • Missing variables resolve to empty string and produce a warning.
  • Blocks should be treated as stateless and recreated when reused.

Metadata

Release files for eblock 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for eblock 0.3.0
File Size Uploaded
eblock-0.3.0.tar.gz 20.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for eblock 0.3.0
File Interpreter ABI Platform
eblock-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 33.5 kB

Release files / eblock-0.3.0.tar.gz

Download URL eblock-0.3.0.tar.gz
Size 20.3 kB
Tags Source
SHA-256 checksum
How to use checksums
206f83b6b02cc0938527ef693fedb69fb44fdc6d031d2117b49a872f9f33d889
BLAKE2b-256 checksum
How to use checksums
1f62c7b4ca5a7217ae70e809d493a5f4262f1ee4b610b6b25f26fc9b77210288
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Dec 7, 2025.

Transparency log

Release files / eblock-0.3.0-py3-none-any.whl

Download URL eblock-0.3.0-py3-none-any.whl
Size 13.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
acd48586b56dc6ba79b79a218867b46bdd9a37aad8b4e78f58a22582972d788a
BLAKE2b-256 checksum
How to use checksums
ffed80ace570de9d5928e7a0992a97ceb137b6d679a722486b233c492df79973
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Dec 7, 2025.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release 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