This document covers the Python implementation of the dotprompt system, including package structure, core APIs, Pydantic-based type system, and Rust FFI integration. The Python implementation (version 0.1.4) provides both synchronous and asynchronous interfaces with type-safe Pydantic models for prompt templating in Generative AI applications.
For information about other language implementations, see JavaScript Implementation and Go Implementation. For shared concepts across all implementations, see Core Concepts. For testing strategies specific to Python, see Language-Specific Testing.
The Python implementation uses a uv-based workspace containing two primary packages:
Sources: python/pyproject.toml1-190 python/dotpromptz/pyproject.toml1-73
The dotpromptz package declares the following core dependencies:
| Dependency | Version | Purpose |
|---|---|---|
dotpromptz-handlebars | >=0.1.3 | Rust-based Handlebars template engine via PyO3 |
pydantic[email] | >=2.10.6 | Runtime type validation and data models |
pyyaml | >=6.0.2 | YAML frontmatter parsing |
anyio | >=4.9.0 | Async/sync compatibility layer |
aiofiles | >=24.1.0 | Async file I/O operations |
structlog | >=25.2.0 | Structured logging |
Sources: python/dotpromptz/pyproject.toml36-46
The Python implementation uses:
Sources: python/dotpromptz/pyproject.toml54-59 python/pyproject.toml67-75
The Dotprompt class in python/dotpromptz/src/dotpromptz/dotprompt.py184-591 is the main entry point for the Python implementation. It extends the Handlebars template engine for use with Generative AI prompts.
Sources: python/dotpromptz/src/dotpromptz/dotprompt.py187-232
The Dotprompt.__init__() method accepts the following parameters:
| Parameter | Type | Description |
|---|---|---|
default_model | str | None | Default model when not specified in template |
model_configs | dict[str, Any] | None | Model-specific configuration defaults |
helpers | dict[str, HelperFn] | None | Custom Handlebars helper functions |
partials | dict[str, str] | None | Pre-registered partial templates |
tools | dict[str, ToolDefinition] | None | Static tool definition mappings |
tool_resolver | ToolResolver | None | Dynamic tool name resolution function |
schemas | dict[str, JsonSchema] | None | Static schema mappings |
schema_resolver | SchemaResolver | None | Dynamic schema name resolution function |
partial_resolver | PartialResolver | None | Dynamic partial name resolution function |
escape_fn | EscapeFunction | HTML escaping strategy (default: NO_ESCAPE) |
Sources: python/dotpromptz/src/dotpromptz/dotprompt.py187-213
Parses a .prompt file string into a ParsedPrompt object by extracting YAML frontmatter and template body.
Sources: python/dotpromptz/src/dotpromptz/dotprompt.py274-283
Compiles a prompt template into a reusable PromptFunction. This method:
RenderFunc callable that holds the compiled stateSources: python/dotpromptz/src/dotpromptz/dotprompt.py301-322
One-shot method that combines compile() and execution. Parses, compiles, and renders a template with the provided data.
Sources: python/dotpromptz/src/dotpromptz/dotprompt.py285-299
Resolves and merges all metadata without rendering the template. This includes:
ToolDefinition objectsSources: python/dotpromptz/src/dotpromptz/dotprompt.py324-355
The registration methods (define_helper, define_partial, define_tool) all return self, enabling fluent API usage:
Sources: python/dotpromptz/src/dotpromptz/dotprompt.py234-272 python/dotpromptz/tests/dotpromptz/dotprompt_test.py161-184
The Python implementation uses Pydantic V2 models for runtime type validation. All models are defined in python/dotpromptz/src/dotpromptz/typing.py1-863
Sources: python/dotpromptz/src/dotpromptz/typing.py179-554
The Python implementation uses three primary generic type variables:
| TypeVar | Bound | Purpose |
|---|---|---|
ModelConfigT | None | Model-specific configuration structure (e.g., temperature, top_p) |
VariablesT | dict[str, Any] | Input variables passed to template rendering |
InputT / OutputT | None | Tool request/response payload types |
Sources: python/dotpromptz/src/dotpromptz/typing.py166-176
Generic container for prompt configuration and metadata:
Sources: python/dotpromptz/src/dotpromptz/typing.py271-308
Extends PromptMetadata with the template string:
Sources: python/dotpromptz/src/dotpromptz/typing.py311-318
Messages represent conversation turns with role and content:
Sources: python/dotpromptz/src/dotpromptz/typing.py497-507 python/dotpromptz/src/dotpromptz/typing.py476
Runtime data provided during rendering:
Sources: python/dotpromptz/src/dotpromptz/typing.py521-534
The document parsing system in python/dotpromptz/src/dotpromptz/parse.py1-546 transforms raw .prompt files into structured messages.
Sources: python/dotpromptz/src/dotpromptz/parse.py199-284 python/dotpromptz/src/dotpromptz/parse.py287-344
The parse_document() function in python/dotpromptz/src/dotpromptz/parse.py216-284 performs frontmatter extraction and metadata parsing:
FRONTMATTER_AND_BODY_REGEX to split YAML from template bodyyaml.safe_load() on frontmatterRESERVED_METADATA_KEYWORDS listgenkit.input) into nested objectsSources: python/dotpromptz/src/dotpromptz/parse.py216-284
The following frontmatter keys receive special handling:
config, description, ext, input, model, name, output,
raw, toolDefs, tools, variant, version
Keys containing dots (e.g., genkit.input) are automatically converted to nested structures in the ext field.
Sources: python/dotpromptz/src/dotpromptz/parse.py105-119
The to_messages() function in python/dotpromptz/src/dotpromptz/parse.py287-344 converts rendered template strings into structured Message objects:
Sources: python/dotpromptz/src/dotpromptz/parse.py287-344
The parsing system recognizes special markers inserted by helper functions:
| Marker Pattern | Regex | Purpose |
|---|---|---|
<<<dotprompt:role:xxx>>> | ROLE_AND_HISTORY_MARKER_REGEX | Separates messages by role (user, model, tool, system) |
<<<dotprompt:history>>> | ROLE_AND_HISTORY_MARKER_REGEX | Inserts conversation history |
<<<dotprompt:media:url>>> | MEDIA_AND_SECTION_MARKER_REGEX | Embeds media content (image, audio, video) |
<<<dotprompt:section xxx>>> | MEDIA_AND_SECTION_MARKER_REGEX | Creates pending sections for special purposes |
Sources: python/dotpromptz/src/dotpromptz/parse.py68-101
The to_parts() function in python/dotpromptz/src/dotpromptz/parse.py447-458 converts message content into typed Part objects:
<<<dotprompt:media:url content_type>>> markers<<<dotprompt:section type>>> markersSources: python/dotpromptz/src/dotpromptz/parse.py447-545
The Python implementation leverages native Rust performance through the handlebarrz package, which exposes the handlebars-rust library via PyO3 bindings.
Sources: python/dotpromptz/src/dotpromptz/dotprompt.py67 python/dotpromptz/src/dotpromptz/dotprompt.py214
The Handlebars class from the handlebarrz package provides the following interface:
| Method | Signature | Purpose |
|---|---|---|
__init__ | (escape_fn: EscapeFunction) | Creates Handlebars instance with escaping strategy |
register_helper | (name: str, fn: HelperFn) | Registers custom helper function |
register_partial | (name: str, source: str) | Registers partial template |
has_partial | (name: str) -> bool | Checks if partial is registered |
compile | (source: str) -> Callable | Compiles template into callable render function |
Sources: python/dotpromptz/src/dotpromptz/dotprompt.py67 python/dotpromptz/src/dotpromptz/dotprompt.py214 python/dotpromptz/src/dotpromptz/dotprompt.py245-260
The handlebarrz package provides three escaping strategies:
EscapeFunction.NO_ESCAPE: No HTML escaping (default for AI prompts)EscapeFunction.HTML: Standard HTML entity escapingEscapeFunction.JSON: JSON string escapingSources: python/dotpromptz/src/dotpromptz/dotprompt.py198
Custom helpers must match this signature:
Where HelperOptions provides:
params: Positional parametershash: Named parametersdata: Context data stackblock: Block content for block helpersSources: python/dotpromptz/src/dotpromptz/dotprompt.py67
The Rust backend provides:
The Python implementation uses async-capable resolver functions to lazily load external resources. Resolvers enable separation between prompt definition and resource location.
Sources: python/dotpromptz/src/dotpromptz/typing.py537-544 python/dotpromptz/src/dotpromptz/dotprompt.py446-511
The ToolResolver type alias in python/dotpromptz/src/dotpromptz/typing.py540 allows both sync and async resolution:
Tool resolution occurs in Dotprompt._resolve_tools() at python/dotpromptz/src/dotpromptz/dotprompt.py446-511:
Dotprompt._tools static mappingtool_resolver is set, call resolveranyio.create_task_group()PromptMetadata.tool_defs with resolved definitionsPromptMetadata.toolsSources: python/dotpromptz/src/dotpromptz/dotprompt.py446-511
The SchemaResolver type alias in python/dotpromptz/src/dotpromptz/typing.py537 enables dynamic schema loading:
Schema resolution occurs in Dotprompt._wrapped_schema_resolver() at python/dotpromptz/src/dotpromptz/dotprompt.py428-444:
Dotprompt._schemas static mappingschema_resolver is set, call resolverSchemas are resolved during Picoschema expansion in _render_picoschema().
Sources: python/dotpromptz/src/dotpromptz/dotprompt.py428-444 python/dotpromptz/src/dotpromptz/dotprompt.py387-426
The PartialResolver type alias in python/dotpromptz/src/dotpromptz/typing.py543 enables dynamic partial template loading:
Partial resolution occurs in Dotprompt._resolve_partials() at python/dotpromptz/src/dotpromptz/dotprompt.py513-558:
_identify_partials() (regex-based)handlebarrz.Handlebarspartial_resolver if availabledefine_partial()Sources: python/dotpromptz/src/dotpromptz/dotprompt.py513-558 python/dotpromptz/src/dotpromptz/dotprompt.py108-117
Since the Rust-based handlebars library doesn't expose AST visitors, partial references are detected using a regular expression:
This pattern matches Handlebars partial syntax: {{> partialName}}
Sources: python/dotpromptz/src/dotpromptz/dotprompt.py74
The PromptFunction protocol in python/dotpromptz/src/dotpromptz/typing.py557-582 defines the interface for compiled prompt callables:
Sources: python/dotpromptz/src/dotpromptz/typing.py557-582
The RenderFunc class in python/dotpromptz/src/dotpromptz/dotprompt.py120-182 implements the PromptFunction protocol:
Sources: python/dotpromptz/src/dotpromptz/dotprompt.py120-182
When a RenderFunc is called at python/dotpromptz/src/dotpromptz/dotprompt.py142-181:
render_metadata() to merge all configurationdata.inputRuntimeOptions with data.context_handlebars.compile() to get render functionto_messages() to structure outputRenderedPrompt with metadata and messagesSources: python/dotpromptz/src/dotpromptz/dotprompt.py142-181
The RenderFunc object holds compiled template state, enabling efficient reuse:
The expensive compilation step (parsing, partial resolution, Rust template compilation) occurs only once.
Sources: python/dotpromptz/src/dotpromptz/dotprompt.py120-182
The Python implementation provides built-in helpers defined in dotpromptz.helpers.BUILTIN_HELPERS that are automatically registered during Dotprompt initialization.
Sources: python/dotpromptz/src/dotpromptz/dotprompt.py228-231 python/dotpromptz/src/dotpromptz/dotprompt.py560-580
| Helper Name | Purpose | Example Usage |
|---|---|---|
role | Inserts role marker to separate messages | {{role "user"}} |
history | Inserts conversation history placeholder | {{history}} |
section | Creates pending part with purpose metadata | {{section "thinking"}} |
media | Embeds media content (image, audio, video) | {{media url contentType}} |
json | Serializes object to JSON string | {{json myObject}} |
ifEquals | Conditional block if values equal | {{#ifEquals role "user"}}...{{/ifEquals}} |
unlessEquals | Inverted conditional block | {{#unlessEquals role "user"}}...{{/unlessEquals}} |
Sources: python/dotpromptz/src/dotpromptz/helpers.py (referenced but not included in provided files)
Python tests are organized in python/dotpromptz/tests/dotpromptz/:
tests/
├── dotpromptz/
│ ├── dotprompt_test.py # Dotprompt class unit tests
│ ├── models_test.py # Model utility tests
│ ├── parse_test.py # Document parsing tests
│ ├── picoschema_test.py # Picoschema conversion tests
│ ├── resolvers_test.py # Resolver function tests
│ └── spec_test.py # Cross-language spec tests
Sources: python/dotpromptz/tests/dotpromptz/dotprompt_test.py1-564 python/dotpromptz/tests/dotpromptz/models_test.py1-43
The workspace uses pytest with the following configuration from python/pyproject.toml53-64:
| Setting | Value | Purpose |
|---|---|---|
asyncio_mode | "strict" | Enforces explicit async fixture/test marking |
asyncio_default_fixture_loop_scope | "function" | Creates new event loop per test |
log_cli | true | Enables console logging during tests |
python_files | ["**/*_test.py"] | Test file naming pattern |
Sources: python/pyproject.toml53-64
The workspace enforces 85% minimum code coverage:
Sources: python/pyproject.toml63-64
The test suite uses pytest-asyncio for async testing:
Sources: python/dotpromptz/tests/dotpromptz/dotprompt_test.py271-323
Tests extensively use unittest.mock for isolating dependencies:
Sources: python/dotpromptz/tests/dotpromptz/dotprompt_test.py147-158
Cross-language behavioral consistency is verified through YAML-based specification tests. The Python implementation generates dynamic test cases from spec/**/*.yaml files.
For details on the specification test system, see Shared Specification Suite.
Sources: python/dotpromptz/tests/dotpromptz/dotprompt_test.py1-28
The Python implementation provides a type-safe, async-capable prompt templating system with the following key characteristics:
The implementation maintains API consistency with the JavaScript reference implementation while leveraging Python-specific features like type hints, async context managers, and Pydantic validation.
Refresh this wiki
This wiki was recently refreshed. Please wait 5 days to refresh again.