From b7792e3866c546559e602441d750b9d5561666be Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Fri, 2 Oct 2026 01:28:09 -0500 Subject: [PATCH 01/10] refactor(py): make dotpromptz internal modules private and standardize root API surface - Rename dotpromptz internal modules with leading underscores (_dotprompt.py, _errors.py, _helpers.py, _models.py, _parse.py, _picoschema.py, _picoschema_reverse.py, _resolvers.py, _typing.py, _util.py, _validate.py). - Rename internal subpackages to _stores/ and _adapters/. - Standardize dotpromptz/__init__.py to re-export only the intentional public API surface (Dotprompt, DataArgument, PromptData, PromptMetadata, RenderedPrompt, Message, Role, Part, TextPart, MediaPart, DataPart, DirStore, DirStoreSync, DirStoreOptions, DotpromptError, FrontmatterError, PartialCycleError, ResolverFailedError, picoschema_to_json_schema). - Update tests and documentation to import public symbols from the root package. --- docs/api/python/dotpromptz.md | 144 ++++------- python/dotpromptz/README.md | 3 +- python/dotpromptz/src/dotpromptz/__init__.py | 226 +++++++----------- .../{adapters => _adapters}/__init__.py | 0 .../openai.py => _adapters/_openai.py} | 2 +- .../{dotprompt.py => _dotprompt.py} | 14 +- .../src/dotpromptz/{errors.py => _errors.py} | 2 +- .../dotpromptz/{helpers.py => _helpers.py} | 0 .../src/dotpromptz/{models.py => _models.py} | 0 .../src/dotpromptz/{parse.py => _parse.py} | 4 +- .../{picoschema.py => _picoschema.py} | 4 +- ...hema_reverse.py => _picoschema_reverse.py} | 4 +- .../{resolvers.py => _resolvers.py} | 4 +- .../{stores => _stores}/__init__.py | 10 +- .../{stores => _stores}/_dir_async.py | 8 +- .../{stores => _stores}/_dir_sync.py | 8 +- .../src/dotpromptz/{stores => _stores}/_io.py | 0 .../{stores => _stores}/_testutils.py | 0 .../dotpromptz/{stores => _stores}/_typing.py | 2 +- .../src/dotpromptz/{typing.py => _typing.py} | 0 .../src/dotpromptz/{util.py => _util.py} | 2 +- .../dotpromptz/{validate.py => _validate.py} | 4 +- .../tests/dotpromptz/dotprompt_test.py | 14 +- .../tests/dotpromptz/helpers_test.py | 2 +- .../tests/dotpromptz/model_selection_test.py | 2 +- .../tests/dotpromptz/models_test.py | 2 +- .../dotpromptz/tests/dotpromptz/parse_test.py | 6 +- .../dotpromptz/picoschema_reverse_test.py | 4 +- .../tests/dotpromptz/picoschema_test.py | 4 +- .../tests/dotpromptz/render_defaults_test.py | 4 +- .../tests/dotpromptz/resolvers_test.py | 6 +- .../tests/dotpromptz/runtime_context_test.py | 4 +- .../dotpromptz/tests/dotpromptz/spec_test.py | 4 +- .../tests/dotpromptz/stores/dir_async_test.py | 6 +- .../tests/dotpromptz/stores/dir_sync_test.py | 8 +- .../dotpromptz/structural_markers_test.py | 2 +- .../dotpromptz/tests/dotpromptz/util_test.py | 2 +- .../tests/dotpromptz/validate_test.py | 2 +- python/dotpromptz/tests/smoke/package_test.py | 14 +- 39 files changed, 211 insertions(+), 316 deletions(-) rename python/dotpromptz/src/dotpromptz/{adapters => _adapters}/__init__.py (100%) rename python/dotpromptz/src/dotpromptz/{adapters/openai.py => _adapters/_openai.py} (98%) rename python/dotpromptz/src/dotpromptz/{dotprompt.py => _dotprompt.py} (98%) rename python/dotpromptz/src/dotpromptz/{errors.py => _errors.py} (99%) rename python/dotpromptz/src/dotpromptz/{helpers.py => _helpers.py} (100%) rename python/dotpromptz/src/dotpromptz/{models.py => _models.py} (100%) rename python/dotpromptz/src/dotpromptz/{parse.py => _parse.py} (99%) rename python/dotpromptz/src/dotpromptz/{picoschema.py => _picoschema.py} (98%) rename python/dotpromptz/src/dotpromptz/{picoschema_reverse.py => _picoschema_reverse.py} (98%) rename python/dotpromptz/src/dotpromptz/{resolvers.py => _resolvers.py} (98%) rename python/dotpromptz/src/dotpromptz/{stores => _stores}/__init__.py (90%) rename python/dotpromptz/src/dotpromptz/{stores => _stores}/_dir_async.py (99%) rename python/dotpromptz/src/dotpromptz/{stores => _stores}/_dir_sync.py (99%) rename python/dotpromptz/src/dotpromptz/{stores => _stores}/_io.py (100%) rename python/dotpromptz/src/dotpromptz/{stores => _stores}/_testutils.py (100%) rename python/dotpromptz/src/dotpromptz/{stores => _stores}/_typing.py (97%) rename python/dotpromptz/src/dotpromptz/{typing.py => _typing.py} (100%) rename python/dotpromptz/src/dotpromptz/{util.py => _util.py} (99%) rename python/dotpromptz/src/dotpromptz/{validate.py => _validate.py} (96%) diff --git a/docs/api/python/dotpromptz.md b/docs/api/python/dotpromptz.md index 8565f77ee..aab396e53 100644 --- a/docs/api/python/dotpromptz.md +++ b/docs/api/python/dotpromptz.md @@ -6,19 +6,18 @@ format—an executable prompt template format for Generative AI. ## Installation ```bash -pip install dotpromptz +uv add dotpromptz ``` ## Quick Start ```python -from dotpromptz import Dotprompt -from dotpromptz.typing import DataArgument +from dotpromptz import DataArgument, Dotprompt -# Create a Dotprompt instance +# 1. Create a Dotprompt instance dp = Dotprompt() -# Parse and render a prompt +# 2. Parse and render a prompt source = ''' --- model: gemini-pro @@ -32,94 +31,47 @@ Hello, {{name}}! rendered = await dp.render(source, data=DataArgument(input={'name': 'World'})) ``` -## Core Classes - -### Dotprompt - -::: dotpromptz.dotprompt.Dotprompt -options: -show\_root\_heading: false -show\_source: true -members\_order: source -show\_docstring\_description: true -show\_docstring\_examples: false - -## Parsing - -::: dotpromptz.parse -options: -show\_root\_heading: false -show\_source: true -members\_order: source -show\_docstring\_description: true -show\_docstring\_examples: false - -## Picoschema - -::: dotpromptz.picoschema -options: -show\_root\_heading: false -show\_source: true -members\_order: source -show\_docstring\_description: true -show\_docstring\_examples: false - -## Helpers - -::: dotpromptz.helpers -options: -show\_root\_heading: false -show\_source: true -members\_order: source -show\_docstring\_description: true -show\_docstring\_examples: false - -## Resolvers - -::: dotpromptz.resolvers -options: -show\_root\_heading: false -show\_source: true -members\_order: source -show\_docstring\_description: true -show\_docstring\_examples: false - -## Types - -::: dotpromptz.typing -options: -show\_root\_heading: false -show\_source: true -members\_order: source -show\_docstring\_description: true -show\_docstring\_examples: false - -## Stores - -::: dotpromptz.stores -options: -show\_root\_heading: false -show\_source: true -members\_order: source -show\_docstring\_description: true -show\_docstring\_examples: false - -## Errors - -::: dotpromptz.errors -options: -show\_root\_heading: false -show\_source: true -members\_order: source -show\_docstring\_description: true -show\_docstring\_examples: false - -## Utilities - -::: dotpromptz.util -options: -show\_root\_heading: false -show\_source: true -members\_order: source -show\_docstring\_description: true -show\_docstring\_examples: false +## Module Reference + +::: dotpromptz.Dotprompt + options: + show_root_heading: true + members_order: source + heading_level: 3 + +::: dotpromptz.DataArgument + options: + show_root_heading: true + members_order: source + heading_level: 3 + +::: dotpromptz.RenderedPrompt + options: + show_root_heading: true + members_order: source + heading_level: 3 + +::: dotpromptz.Message + options: + show_root_heading: true + members_order: source + heading_level: 3 + +::: dotpromptz.Role + options: + show_root_heading: true + members_order: source + heading_level: 3 + +::: dotpromptz.DirStore + options: + show_root_heading: true + members_order: source + heading_level: 3 + +::: dotpromptz.DotpromptError + options: + show_root_heading: true + members_order: source + heading_level: 3 + diff --git a/python/dotpromptz/README.md b/python/dotpromptz/README.md index 98b724b7d..87746f14b 100644 --- a/python/dotpromptz/README.md +++ b/python/dotpromptz/README.md @@ -78,8 +78,7 @@ Prompt input and runtime context are separate namespaces. Use `{{name}}` for input and `{{@name}}` for context: ```python -from dotpromptz import Dotprompt -from dotpromptz.typing import DataArgument +from dotpromptz import DataArgument, Dotprompt prompt = Dotprompt() result = await prompt.render( diff --git a/python/dotpromptz/src/dotpromptz/__init__.py b/python/dotpromptz/src/dotpromptz/__init__.py index 95e74301c..336a5d992 100644 --- a/python/dotpromptz/src/dotpromptz/__init__.py +++ b/python/dotpromptz/src/dotpromptz/__init__.py @@ -16,143 +16,99 @@ """Dotpromptz: Executable prompt templates for Python. -Dotpromptz is the Python implementation of the Dotprompt file format—an executable -prompt template format for Generative AI. It provides a structured way to define, -manage, and render prompts with metadata, schemas, tools, and templating. - -## What is Dotprompt? - -Dotprompt files (`.prompt`) combine YAML frontmatter metadata with Handlebars -templates to create self-contained, executable prompt definitions: - -``` -+---------------------------+ -| YAML Frontmatter | <- Model config, schemas, tools -|---------------------------| -| | -| Handlebars Template | <- Dynamic prompt with variables -| | -+---------------------------+ -``` - -## Key Concepts - -| Concept | Description | -|------------------|------------------------------------------------------------------| -| **Frontmatter** | YAML metadata block at the top of `.prompt` files (model, | -| | schemas, tools, config) | -| **Template** | Handlebars template body with variables, helpers, and partials | -| **Picoschema** | Compact schema format that compiles to JSON Schema | -| **Partials** | Reusable template fragments (prefixed with `_` in filenames) | -| **Helpers** | Custom Handlebars functions (`{{role}}`, `{{media}}`, etc.) | -| **Resolvers** | Functions to dynamically resolve tools, schemas, and partials | - -## Architecture - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ Dotprompt │ -│ (Main entry point - compiles and renders prompt templates) │ -├─────────────────────────────────────────────────────────────────┤ -│ │ -│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │ -│ │ parse │ │ picoschema │ │ resolvers │ │ -│ │ (YAML + │ │ (Schema │ │ (Tools, schemas, │ │ -│ │ template) │ │ compiler) │ │ partials lookup) │ │ -│ └──────────────┘ └──────────────┘ └──────────────────────┘ │ -│ │ -│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │ -│ │ helpers │ │ stores │ │ handlebars │ │ -│ │ (Built-in │ │ (Prompt │ │ (Handlebars engine │ │ -│ │ functions) │ │ storage) │ │ for templates) │ │ -│ └──────────────┘ └──────────────┘ └──────────────────────┘ │ -│ │ -└─────────────────────────────────────────────────────────────────┘ -``` - -## Quick Start - -```python -from dotpromptz import Dotprompt -from dotpromptz.typing import DataArgument - -# Create a Dotprompt instance -dp = Dotprompt() - -# Parse and render a prompt -source = ''' ---- -model: gemini-pro -input: - schema: - name: string ---- -Hello, {{name}}! How can I help you today? -''' - -rendered = await dp.render(source, data=DataArgument(input={'name': 'Alice'})) - -# Access rendered messages -for message in rendered.messages: - print(f'{message.role}: {message.content}') -``` - -## Example `.prompt` File - -```handlebars ---- -model: googleai/gemini-2.5-pro -input: - schema: - topic: string, The topic to explain - level: string, Expertise level (beginner, intermediate, advanced) -output: - format: json - schema: - explanation: string, Clear explanation of the topic - examples(array): string, Illustrative examples ---- - -{{role "system"}} -You are an expert educator who adapts explanations to the learner's level. - -{{role "user"}} -Please explain {{topic}} for someone at the {{level}} level. -Provide clear examples to illustrate key points. -``` - -## Module Structure - -| Module | Purpose | -|-----------------|------------------------------------------------------| -| `dotprompt` | Main `Dotprompt` class for compiling/rendering | -| `parse` | YAML frontmatter extraction and message parsing | -| `picoschema` | Picoschema to JSON Schema compilation | -| `helpers` | Built-in Handlebars helpers (`role`, `media`, etc.) | -| `resolvers` | Async resolution of tools, schemas, and partials | -| `stores` | Filesystem-based prompt storage (`DirStore`) | -| `typing` | Pydantic models and type definitions | -| `errors` | Custom exception classes | - -## See Also - -- Dotprompt specification: https://github.com/google/dotprompt -- Handlebars templating: https://handlebarsjs.com -- JSON Schema: https://json-schema.org +Dotprompt combines YAML frontmatter metadata with Handlebars templating to define +self-contained, executable prompt templates for Generative AI applications. + +Example: + ```python + from dotpromptz import DataArgument, Dotprompt + + # 1. Initialize compiler + prompt = Dotprompt() + + # 2. Render prompt source with input data + rendered = await prompt.render( + '''--- + model: googleai/gemini-2.5-pro + input: + schema: + customer: string + dish: string + --- + {{role "system"}} + You are a restaurant server confirming an order. + + {{role "user"}} + Please confirm order for {{customer}}: {{dish}}. + ''', + DataArgument(input={'customer': 'Ada', 'dish': 'Smoked Salmon Tartine'}), + ) + + # 3. Inspect structured messages + print(rendered.messages[1].content[0].text) + # => Please confirm order for Ada: Smoked Salmon Tartine. + ``` """ -from .dotprompt import Dotprompt - - -def package_name() -> str: - """Return the package name for smoke testing. - - Returns: - The string 'dotpromptz'. - """ - return 'dotpromptz' - +# Primary Engine +from dotpromptz._dotprompt import Dotprompt + +# Exceptions +from dotpromptz._errors import ( + DotpromptError, + FrontmatterError, + PartialCycleError, + ResolverFailedError, +) + +# Schema Utilities +from dotpromptz._picoschema import picoschema_to_json_schema + +# Storage +from dotpromptz._stores import ( + DirStore, + DirStoreOptions, + DirStoreSync, +) + +# Runtime Data & Models +from dotpromptz._typing import ( + DataArgument, + DataPart, + MediaPart, + Message, + Part, + PromptData, + PromptMetadata, + RenderedPrompt, + Role, + TextPart, +) __all__ = [ - Dotprompt.__name__, + # Engine + 'Dotprompt', + # Runtime & Data + 'DataArgument', + 'PromptData', + 'PromptMetadata', + 'RenderedPrompt', + # Messages & Parts + 'DataPart', + 'MediaPart', + 'Message', + 'Part', + 'Role', + 'TextPart', + # Storage + 'DirStore', + 'DirStoreOptions', + 'DirStoreSync', + # Schema + 'picoschema_to_json_schema', + # Errors + 'DotpromptError', + 'FrontmatterError', + 'PartialCycleError', + 'ResolverFailedError', ] diff --git a/python/dotpromptz/src/dotpromptz/adapters/__init__.py b/python/dotpromptz/src/dotpromptz/_adapters/__init__.py similarity index 100% rename from python/dotpromptz/src/dotpromptz/adapters/__init__.py rename to python/dotpromptz/src/dotpromptz/_adapters/__init__.py diff --git a/python/dotpromptz/src/dotpromptz/adapters/openai.py b/python/dotpromptz/src/dotpromptz/_adapters/_openai.py similarity index 98% rename from python/dotpromptz/src/dotpromptz/adapters/openai.py rename to python/dotpromptz/src/dotpromptz/_adapters/_openai.py index 16fbd614b..0cd40bb45 100644 --- a/python/dotpromptz/src/dotpromptz/adapters/openai.py +++ b/python/dotpromptz/src/dotpromptz/_adapters/_openai.py @@ -21,7 +21,7 @@ from pydantic import BaseModel -from dotpromptz.typing import Role +from dotpromptz._typing import Role class DetailKind(str, Enum): diff --git a/python/dotpromptz/src/dotpromptz/dotprompt.py b/python/dotpromptz/src/dotpromptz/_dotprompt.py similarity index 98% rename from python/dotpromptz/src/dotpromptz/dotprompt.py rename to python/dotpromptz/src/dotpromptz/_dotprompt.py index 3c3854169..76c7e5c6b 100644 --- a/python/dotpromptz/src/dotpromptz/dotprompt.py +++ b/python/dotpromptz/src/dotpromptz/_dotprompt.py @@ -44,12 +44,12 @@ import anyio -from dotpromptz.errors import PartialCycleError -from dotpromptz.helpers import BUILTIN_HELPERS -from dotpromptz.parse import parse_document, to_messages -from dotpromptz.picoschema import picoschema_to_json_schema -from dotpromptz.resolvers import resolve_json_schema, resolve_partial, resolve_tool -from dotpromptz.typing import ( +from dotpromptz._errors import PartialCycleError +from dotpromptz._helpers import BUILTIN_HELPERS +from dotpromptz._parse import parse_document, to_messages +from dotpromptz._picoschema import picoschema_to_json_schema +from dotpromptz._resolvers import resolve_json_schema, resolve_partial, resolve_tool +from dotpromptz._typing import ( DataArgument, JsonSchema, ModelConfigT, @@ -64,7 +64,7 @@ ToolResolver, VariablesT, ) -from dotpromptz.util import remove_undefined_fields +from dotpromptz._util import remove_undefined_fields from dotpromptz_handlebars import Context, EscapeFunction, Handlebars, HelperFn, RuntimeOptions # Pre-compiled regex for finding partial references in handlebars templates diff --git a/python/dotpromptz/src/dotpromptz/errors.py b/python/dotpromptz/src/dotpromptz/_errors.py similarity index 99% rename from python/dotpromptz/src/dotpromptz/errors.py rename to python/dotpromptz/src/dotpromptz/_errors.py index f58ba570c..74f0e72c6 100644 --- a/python/dotpromptz/src/dotpromptz/errors.py +++ b/python/dotpromptz/src/dotpromptz/_errors.py @@ -29,7 +29,7 @@ ## Usage Example ```python -from dotpromptz.errors import ResolverFailedError +from dotpromptz._errors import ResolverFailedError try: tool = await resolve_tool('my_tool', resolver) diff --git a/python/dotpromptz/src/dotpromptz/helpers.py b/python/dotpromptz/src/dotpromptz/_helpers.py similarity index 100% rename from python/dotpromptz/src/dotpromptz/helpers.py rename to python/dotpromptz/src/dotpromptz/_helpers.py diff --git a/python/dotpromptz/src/dotpromptz/models.py b/python/dotpromptz/src/dotpromptz/_models.py similarity index 100% rename from python/dotpromptz/src/dotpromptz/models.py rename to python/dotpromptz/src/dotpromptz/_models.py diff --git a/python/dotpromptz/src/dotpromptz/parse.py b/python/dotpromptz/src/dotpromptz/_parse.py similarity index 99% rename from python/dotpromptz/src/dotpromptz/parse.py rename to python/dotpromptz/src/dotpromptz/_parse.py index 8f57b98bc..48cb28a80 100644 --- a/python/dotpromptz/src/dotpromptz/parse.py +++ b/python/dotpromptz/src/dotpromptz/_parse.py @@ -45,8 +45,8 @@ from yaml.events import AliasEvent, NodeEvent from yaml.nodes import MappingNode, Node, ScalarNode, SequenceNode -from dotpromptz.errors import FrontmatterError -from dotpromptz.typing import ( +from dotpromptz._errors import FrontmatterError +from dotpromptz._typing import ( DataArgument, MediaContent, MediaPart, diff --git a/python/dotpromptz/src/dotpromptz/picoschema.py b/python/dotpromptz/src/dotpromptz/_picoschema.py similarity index 98% rename from python/dotpromptz/src/dotpromptz/picoschema.py rename to python/dotpromptz/src/dotpromptz/_picoschema.py index 849997865..87735390e 100644 --- a/python/dotpromptz/src/dotpromptz/picoschema.py +++ b/python/dotpromptz/src/dotpromptz/_picoschema.py @@ -44,8 +44,8 @@ import re from typing import Any, cast -from dotpromptz.resolvers import resolve_json_schema -from dotpromptz.typing import JsonSchema, SchemaResolver +from dotpromptz._resolvers import resolve_json_schema +from dotpromptz._typing import JsonSchema, SchemaResolver JSON_SCHEMA_SCALAR_TYPES = [ 'any', diff --git a/python/dotpromptz/src/dotpromptz/picoschema_reverse.py b/python/dotpromptz/src/dotpromptz/_picoschema_reverse.py similarity index 98% rename from python/dotpromptz/src/dotpromptz/picoschema_reverse.py rename to python/dotpromptz/src/dotpromptz/_picoschema_reverse.py index f8667536b..67f9d3368 100644 --- a/python/dotpromptz/src/dotpromptz/picoschema_reverse.py +++ b/python/dotpromptz/src/dotpromptz/_picoschema_reverse.py @@ -24,7 +24,7 @@ Example:: - from dotpromptz.picoschema_reverse import json_schema_to_picoschema + from dotpromptz._picoschema_reverse import json_schema_to_picoschema schema = { 'type': 'object', @@ -44,7 +44,7 @@ import structlog -from dotpromptz.typing import JsonSchema +from dotpromptz._typing import JsonSchema logger = structlog.get_logger(__name__) diff --git a/python/dotpromptz/src/dotpromptz/resolvers.py b/python/dotpromptz/src/dotpromptz/_resolvers.py similarity index 98% rename from python/dotpromptz/src/dotpromptz/resolvers.py rename to python/dotpromptz/src/dotpromptz/_resolvers.py index 27b108706..cd1a80593 100644 --- a/python/dotpromptz/src/dotpromptz/resolvers.py +++ b/python/dotpromptz/src/dotpromptz/_resolvers.py @@ -44,8 +44,8 @@ from anyio.to_thread import run_sync -from dotpromptz.errors import ResolverFailedError -from dotpromptz.typing import ( +from dotpromptz._errors import ResolverFailedError +from dotpromptz._typing import ( JsonSchema, PartialResolver, SchemaResolver, diff --git a/python/dotpromptz/src/dotpromptz/stores/__init__.py b/python/dotpromptz/src/dotpromptz/_stores/__init__.py similarity index 90% rename from python/dotpromptz/src/dotpromptz/stores/__init__.py rename to python/dotpromptz/src/dotpromptz/_stores/__init__.py index 8d51335c7..cc4446ccd 100644 --- a/python/dotpromptz/src/dotpromptz/stores/__init__.py +++ b/python/dotpromptz/src/dotpromptz/_stores/__init__.py @@ -35,13 +35,13 @@ Usage Example: ```python # Using the async store -from dotpromptz.stores import DirStore, DirStoreOptions +from dotpromptz._stores import DirStore, DirStoreOptions store = DirStore(DirStoreOptions(directory='/path/to/prompts')) prompts = await store.list() # Using the sync store -from dotpromptz.stores import DirStoreSync, DirStoreOptions +from dotpromptz._stores import DirStoreSync, DirStoreOptions sync_store = DirStoreSync(DirStoreOptions(directory='/path/to/prompts')) prompts = sync_store.list() @@ -51,9 +51,3 @@ from ._dir_async import DirStore as DirStore from ._dir_sync import DirStoreSync from ._typing import DirStoreOptions - -__all__ = [ - 'DirStore', - 'DirStoreOptions', - 'DirStoreSync', -] diff --git a/python/dotpromptz/src/dotpromptz/stores/_dir_async.py b/python/dotpromptz/src/dotpromptz/_stores/_dir_async.py similarity index 99% rename from python/dotpromptz/src/dotpromptz/stores/_dir_async.py rename to python/dotpromptz/src/dotpromptz/_stores/_dir_async.py index 9c3497852..961b2cff3 100644 --- a/python/dotpromptz/src/dotpromptz/stores/_dir_async.py +++ b/python/dotpromptz/src/dotpromptz/_stores/_dir_async.py @@ -32,8 +32,8 @@ Example Usage: ```python -from dotpromptz.stores import DirStore, DirStoreOptions -from dotpromptz.typing import PromptData +from dotpromptz._stores import DirStore, DirStoreOptions +from dotpromptz._typing import PromptData # Create a store instance store = DirStore(DirStoreOptions(directory='/path/to/prompts')) @@ -61,7 +61,7 @@ import aiofiles import structlog -from dotpromptz.typing import ( +from dotpromptz._typing import ( DeletePromptOrPartialOptions, ListPartialsOptions, ListPromptsOptions, @@ -75,7 +75,7 @@ PromptRef, PromptStoreWritable, ) -from dotpromptz.util import validate_prompt_name +from dotpromptz._util import validate_prompt_name from ._io import ( calculate_version, diff --git a/python/dotpromptz/src/dotpromptz/stores/_dir_sync.py b/python/dotpromptz/src/dotpromptz/_stores/_dir_sync.py similarity index 99% rename from python/dotpromptz/src/dotpromptz/stores/_dir_sync.py rename to python/dotpromptz/src/dotpromptz/_stores/_dir_sync.py index 97dad7b59..53a1c738b 100644 --- a/python/dotpromptz/src/dotpromptz/stores/_dir_sync.py +++ b/python/dotpromptz/src/dotpromptz/_stores/_dir_sync.py @@ -32,8 +32,8 @@ Example Usage: ```python -from dotpromptz.stores import DirStoreSync, DirStoreOptions -from dotpromptz.typing import PromptData +from dotpromptz._stores import DirStoreSync, DirStoreOptions +from dotpromptz._typing import PromptData # Create a store instance store = DirStoreSync(DirStoreOptions(directory='/path/to/prompts')) @@ -59,7 +59,7 @@ import structlog -from dotpromptz.typing import ( +from dotpromptz._typing import ( DeletePromptOrPartialOptions, ListPartialsOptions, ListPromptsOptions, @@ -73,7 +73,7 @@ PromptRef, PromptStoreWritableSync, ) -from dotpromptz.util import validate_prompt_name +from dotpromptz._util import validate_prompt_name from ._io import ( calculate_version, diff --git a/python/dotpromptz/src/dotpromptz/stores/_io.py b/python/dotpromptz/src/dotpromptz/_stores/_io.py similarity index 100% rename from python/dotpromptz/src/dotpromptz/stores/_io.py rename to python/dotpromptz/src/dotpromptz/_stores/_io.py diff --git a/python/dotpromptz/src/dotpromptz/stores/_testutils.py b/python/dotpromptz/src/dotpromptz/_stores/_testutils.py similarity index 100% rename from python/dotpromptz/src/dotpromptz/stores/_testutils.py rename to python/dotpromptz/src/dotpromptz/_stores/_testutils.py diff --git a/python/dotpromptz/src/dotpromptz/stores/_typing.py b/python/dotpromptz/src/dotpromptz/_stores/_typing.py similarity index 97% rename from python/dotpromptz/src/dotpromptz/stores/_typing.py rename to python/dotpromptz/src/dotpromptz/_stores/_typing.py index 3d998f0c9..67ffcc9d3 100644 --- a/python/dotpromptz/src/dotpromptz/stores/_typing.py +++ b/python/dotpromptz/src/dotpromptz/_stores/_typing.py @@ -47,7 +47,7 @@ class DirStoreOptions: Example: ```python from pathlib import Path - from dotpromptz.stores import DirStore, DirStoreOptions + from dotpromptz._stores import DirStore, DirStoreOptions options = DirStoreOptions(directory=Path('/path/to/prompts')) store = DirStore(options) diff --git a/python/dotpromptz/src/dotpromptz/typing.py b/python/dotpromptz/src/dotpromptz/_typing.py similarity index 100% rename from python/dotpromptz/src/dotpromptz/typing.py rename to python/dotpromptz/src/dotpromptz/_typing.py diff --git a/python/dotpromptz/src/dotpromptz/util.py b/python/dotpromptz/src/dotpromptz/_util.py similarity index 99% rename from python/dotpromptz/src/dotpromptz/util.py rename to python/dotpromptz/src/dotpromptz/_util.py index fc7af1549..67c0b1b73 100644 --- a/python/dotpromptz/src/dotpromptz/util.py +++ b/python/dotpromptz/src/dotpromptz/_util.py @@ -86,7 +86,7 @@ ## Usage Example ```python -from dotpromptz.util import remove_undefined_fields, validate_prompt_name +from dotpromptz._util import remove_undefined_fields, validate_prompt_name # Clean up a metadata dict metadata = {'name': 'test', 'version': None, 'config': {'key': None}} diff --git a/python/dotpromptz/src/dotpromptz/validate.py b/python/dotpromptz/src/dotpromptz/_validate.py similarity index 96% rename from python/dotpromptz/src/dotpromptz/validate.py rename to python/dotpromptz/src/dotpromptz/_validate.py index a1a0f7bc2..d687e66d6 100644 --- a/python/dotpromptz/src/dotpromptz/validate.py +++ b/python/dotpromptz/src/dotpromptz/_validate.py @@ -22,7 +22,7 @@ Example:: - from dotpromptz.validate import validate_output + from dotpromptz._validate import validate_output schema = { 'type': 'object', @@ -40,7 +40,7 @@ import jsonschema import structlog -from dotpromptz.typing import JsonSchema +from dotpromptz._typing import JsonSchema logger = structlog.get_logger(__name__) diff --git a/python/dotpromptz/tests/dotpromptz/dotprompt_test.py b/python/dotpromptz/tests/dotpromptz/dotprompt_test.py index aa97bd15f..805c33856 100644 --- a/python/dotpromptz/tests/dotpromptz/dotprompt_test.py +++ b/python/dotpromptz/tests/dotpromptz/dotprompt_test.py @@ -38,9 +38,9 @@ import pytest -from dotpromptz.dotprompt import Dotprompt, _identify_partials -from dotpromptz.errors import FrontmatterError, PartialCycleError -from dotpromptz.typing import ( +from dotpromptz._dotprompt import Dotprompt, _identify_partials +from dotpromptz._errors import FrontmatterError, PartialCycleError +from dotpromptz._typing import ( DataArgument, ModelConfigT, ParsedPrompt, @@ -54,7 +54,7 @@ @pytest.fixture def mock_handlebars() -> Generator[Mock, None, None]: """Create a mock Handlebars instance.""" - with patch('dotpromptz.dotprompt.Handlebars') as mock_handlebars_class: + with patch('dotpromptz._dotprompt.Handlebars') as mock_handlebars_class: mock_instance = Mock() mock_handlebars_class.return_value = mock_instance yield mock_instance @@ -202,7 +202,7 @@ async def test_compile_render_mock(self) -> None: assert result == 'hello foo (bar, a@b.c)' -@patch('dotpromptz.dotprompt.parse_document') +@patch('dotpromptz._dotprompt.parse_document') def test_parse(mock_parse_document: Mock, mock_handlebars: Mock) -> None: """Test parsing a prompt.""" mock_parse_document.return_value = ParsedPrompt(template='Hello {{name}}', tool_defs=None) @@ -240,7 +240,7 @@ async def test_frontmatter_error_object_propagates_through_every_public_entry_po ) dotprompt = Dotprompt() - with patch('dotpromptz.dotprompt.parse_document', side_effect=error): + with patch('dotpromptz._dotprompt.parse_document', side_effect=error): with pytest.raises(FrontmatterError) as parse_exc: dotprompt.parse('source') assert parse_exc.value is error @@ -486,7 +486,7 @@ class TestRenderPicoSchema(IsolatedAsyncioTestCase): """Test the render_picoschema method.""" @patch( - 'dotpromptz.dotprompt.picoschema_to_json_schema', + 'dotpromptz._dotprompt.picoschema_to_json_schema', return_value={'type': 'object', 'properties': {'expanded': True}}, ) async def test_process_valid_picoschema_definition(self, _: Mock) -> None: diff --git a/python/dotpromptz/tests/dotpromptz/helpers_test.py b/python/dotpromptz/tests/dotpromptz/helpers_test.py index ad61d86c7..efd727af5 100644 --- a/python/dotpromptz/tests/dotpromptz/helpers_test.py +++ b/python/dotpromptz/tests/dotpromptz/helpers_test.py @@ -19,7 +19,7 @@ import json import unittest -from dotpromptz.helpers import ( +from dotpromptz._helpers import ( history_helper, if_equals_helper, json_helper, diff --git a/python/dotpromptz/tests/dotpromptz/model_selection_test.py b/python/dotpromptz/tests/dotpromptz/model_selection_test.py index 41594ac7d..18975a8b3 100644 --- a/python/dotpromptz/tests/dotpromptz/model_selection_test.py +++ b/python/dotpromptz/tests/dotpromptz/model_selection_test.py @@ -18,7 +18,7 @@ from typing import Any -from dotpromptz.dotprompt import _drop_blank_model, _pick_model +from dotpromptz._dotprompt import _drop_blank_model, _pick_model def test_pick_model_returns_the_first_named_layer() -> None: diff --git a/python/dotpromptz/tests/dotpromptz/models_test.py b/python/dotpromptz/tests/dotpromptz/models_test.py index f385638f5..82001195e 100644 --- a/python/dotpromptz/tests/dotpromptz/models_test.py +++ b/python/dotpromptz/tests/dotpromptz/models_test.py @@ -20,7 +20,7 @@ from pydantic import BaseModel -from dotpromptz.models import dump_models +from dotpromptz._models import dump_models class ModelForTesting(BaseModel): diff --git a/python/dotpromptz/tests/dotpromptz/parse_test.py b/python/dotpromptz/tests/dotpromptz/parse_test.py index c90d205ed..0477a7638 100644 --- a/python/dotpromptz/tests/dotpromptz/parse_test.py +++ b/python/dotpromptz/tests/dotpromptz/parse_test.py @@ -21,8 +21,8 @@ import pytest -from dotpromptz.errors import DotpromptError, FrontmatterError -from dotpromptz.parse import ( +from dotpromptz._errors import DotpromptError, FrontmatterError +from dotpromptz._parse import ( FRONTMATTER_AND_BODY_REGEX, MEDIA_AND_SECTION_MARKER_REGEX, ROLE_AND_HISTORY_MARKER_REGEX, @@ -43,7 +43,7 @@ split_by_role_and_history_markers, transform_messages_to_history, ) -from dotpromptz.typing import ( +from dotpromptz._typing import ( MediaContent, MediaPart, Message, diff --git a/python/dotpromptz/tests/dotpromptz/picoschema_reverse_test.py b/python/dotpromptz/tests/dotpromptz/picoschema_reverse_test.py index 7542613a6..709cc007d 100644 --- a/python/dotpromptz/tests/dotpromptz/picoschema_reverse_test.py +++ b/python/dotpromptz/tests/dotpromptz/picoschema_reverse_test.py @@ -20,8 +20,8 @@ import unittest -from dotpromptz.picoschema import picoschema_to_json_schema -from dotpromptz.picoschema_reverse import json_schema_to_picoschema +from dotpromptz import picoschema_to_json_schema +from dotpromptz._picoschema_reverse import json_schema_to_picoschema class TestJsonSchemaToPicoschema(unittest.TestCase): diff --git a/python/dotpromptz/tests/dotpromptz/picoschema_test.py b/python/dotpromptz/tests/dotpromptz/picoschema_test.py index b0eab23a4..e893e8596 100644 --- a/python/dotpromptz/tests/dotpromptz/picoschema_test.py +++ b/python/dotpromptz/tests/dotpromptz/picoschema_test.py @@ -19,8 +19,8 @@ import unittest from unittest import IsolatedAsyncioTestCase -from dotpromptz import picoschema -from dotpromptz.typing import JsonSchema +from dotpromptz import _picoschema as picoschema +from dotpromptz._typing import JsonSchema class TestPicoschemaParser(IsolatedAsyncioTestCase): diff --git a/python/dotpromptz/tests/dotpromptz/render_defaults_test.py b/python/dotpromptz/tests/dotpromptz/render_defaults_test.py index 15f23f581..20286271c 100644 --- a/python/dotpromptz/tests/dotpromptz/render_defaults_test.py +++ b/python/dotpromptz/tests/dotpromptz/render_defaults_test.py @@ -18,8 +18,8 @@ import pytest -from dotpromptz.dotprompt import Dotprompt -from dotpromptz.typing import DataArgument, PromptInputConfig, PromptMetadata, TextPart +from dotpromptz._dotprompt import Dotprompt +from dotpromptz._typing import DataArgument, PromptInputConfig, PromptMetadata, TextPart def rendered_text(result: Any) -> str: diff --git a/python/dotpromptz/tests/dotpromptz/resolvers_test.py b/python/dotpromptz/tests/dotpromptz/resolvers_test.py index e12f8a038..a7e4bb6e3 100644 --- a/python/dotpromptz/tests/dotpromptz/resolvers_test.py +++ b/python/dotpromptz/tests/dotpromptz/resolvers_test.py @@ -41,9 +41,9 @@ from collections.abc import Awaitable from typing import Any -from dotpromptz.errors import ResolverFailedError -from dotpromptz.resolvers import resolve, resolve_json_schema, resolve_partial, resolve_tool -from dotpromptz.typing import JsonSchema, ToolDefinition +from dotpromptz._errors import ResolverFailedError +from dotpromptz._resolvers import resolve, resolve_json_schema, resolve_partial, resolve_tool +from dotpromptz._typing import JsonSchema, ToolDefinition class MockSyncResolver: diff --git a/python/dotpromptz/tests/dotpromptz/runtime_context_test.py b/python/dotpromptz/tests/dotpromptz/runtime_context_test.py index 1f5ad2fae..82031c133 100644 --- a/python/dotpromptz/tests/dotpromptz/runtime_context_test.py +++ b/python/dotpromptz/tests/dotpromptz/runtime_context_test.py @@ -18,8 +18,8 @@ import pytest -from dotpromptz.dotprompt import Dotprompt -from dotpromptz.typing import DataArgument, TextPart +from dotpromptz._dotprompt import Dotprompt +from dotpromptz._typing import DataArgument, TextPart from dotpromptz_handlebars import HelperOptions diff --git a/python/dotpromptz/tests/dotpromptz/spec_test.py b/python/dotpromptz/tests/dotpromptz/spec_test.py index 113ec7351..ca7ddcb12 100644 --- a/python/dotpromptz/tests/dotpromptz/spec_test.py +++ b/python/dotpromptz/tests/dotpromptz/spec_test.py @@ -109,8 +109,8 @@ import yaml from pydantic import BaseModel, Field -from dotpromptz.dotprompt import Dotprompt -from dotpromptz.typing import ( +from dotpromptz._dotprompt import Dotprompt +from dotpromptz._typing import ( DataArgument, JsonSchema, Message, diff --git a/python/dotpromptz/tests/dotpromptz/stores/dir_async_test.py b/python/dotpromptz/tests/dotpromptz/stores/dir_async_test.py index 50d752bea..1ae191e51 100644 --- a/python/dotpromptz/tests/dotpromptz/stores/dir_async_test.py +++ b/python/dotpromptz/tests/dotpromptz/stores/dir_async_test.py @@ -45,9 +45,9 @@ import pytest import pytest_asyncio -from dotpromptz.stores import DirStore, DirStoreOptions -from dotpromptz.stores._io import calculate_version -from dotpromptz.typing import ( +from dotpromptz._stores import DirStore, DirStoreOptions +from dotpromptz._stores._io import calculate_version +from dotpromptz._typing import ( DeletePromptOrPartialOptions, LoadPartialOptions, LoadPromptOptions, diff --git a/python/dotpromptz/tests/dotpromptz/stores/dir_sync_test.py b/python/dotpromptz/tests/dotpromptz/stores/dir_sync_test.py index 16555d86c..ac7f6eab7 100644 --- a/python/dotpromptz/tests/dotpromptz/stores/dir_sync_test.py +++ b/python/dotpromptz/tests/dotpromptz/stores/dir_sync_test.py @@ -41,13 +41,13 @@ import pytest -from dotpromptz.stores import DirStoreOptions, DirStoreSync -from dotpromptz.stores._io import calculate_version -from dotpromptz.stores._testutils import ( +from dotpromptz._stores import DirStoreOptions, DirStoreSync +from dotpromptz._stores._io import calculate_version +from dotpromptz._stores._testutils import ( create_test_partial as create_test_partial_sync, create_test_prompt as create_test_prompt_sync, ) -from dotpromptz.typing import ( +from dotpromptz._typing import ( DeletePromptOrPartialOptions, LoadPartialOptions, LoadPromptOptions, diff --git a/python/dotpromptz/tests/dotpromptz/structural_markers_test.py b/python/dotpromptz/tests/dotpromptz/structural_markers_test.py index 532d54a5e..b221034de 100644 --- a/python/dotpromptz/tests/dotpromptz/structural_markers_test.py +++ b/python/dotpromptz/tests/dotpromptz/structural_markers_test.py @@ -23,7 +23,7 @@ import pytest from dotpromptz import Dotprompt -from dotpromptz.typing import DataArgument, Role, TextPart +from dotpromptz._typing import DataArgument, Role, TextPart from dotpromptz_handlebars import HelperOptions diff --git a/python/dotpromptz/tests/dotpromptz/util_test.py b/python/dotpromptz/tests/dotpromptz/util_test.py index 01d9ad453..1b0ab4666 100644 --- a/python/dotpromptz/tests/dotpromptz/util_test.py +++ b/python/dotpromptz/tests/dotpromptz/util_test.py @@ -18,7 +18,7 @@ import unittest -from dotpromptz.util import ( +from dotpromptz._util import ( remove_undefined_fields, unquote, validate_prompt_name, diff --git a/python/dotpromptz/tests/dotpromptz/validate_test.py b/python/dotpromptz/tests/dotpromptz/validate_test.py index f2d2bb696..c51216621 100644 --- a/python/dotpromptz/tests/dotpromptz/validate_test.py +++ b/python/dotpromptz/tests/dotpromptz/validate_test.py @@ -20,7 +20,7 @@ import unittest -from dotpromptz.validate import SchemaValidationError, validate_output +from dotpromptz._validate import SchemaValidationError, validate_output class TestValidateOutput(unittest.TestCase): diff --git a/python/dotpromptz/tests/smoke/package_test.py b/python/dotpromptz/tests/smoke/package_test.py index 87eefaa1a..19eaec090 100644 --- a/python/dotpromptz/tests/smoke/package_test.py +++ b/python/dotpromptz/tests/smoke/package_test.py @@ -16,22 +16,16 @@ """Smoke tests for package structure.""" -# TODO(#503): Replace this with proper imports once we have a proper implementation. -from dotpromptz import package_name as dotpromptz_package_name +from dotpromptz import Dotprompt def square(n: int | float) -> int | float: return n * n -def test_package_names() -> None: - assert dotpromptz_package_name() == 'dotpromptz' - - -# TODO(#503): Failing test on purpose to be removed after we complete -# this runtime and stop skipping all failures. -# def test_skip_failures() -> None: -# assert dotpromptz_package_name() == 'skip.failures' +def test_package_import() -> None: + dp = Dotprompt() + assert dp is not None def test_square() -> None: From 1b6079f386f23554bb916766b18e8bef5e9b7785 Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Fri, 2 Oct 2026 02:15:42 -0500 Subject: [PATCH 02/10] docs(py): polish code samples with numbered steps and inline return annotations --- docs/api/python/dotpromptz.md | 8 ++++++-- python/dotpromptz/README.md | 7 +++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/api/python/dotpromptz.md b/docs/api/python/dotpromptz.md index aab396e53..f3692c007 100644 --- a/docs/api/python/dotpromptz.md +++ b/docs/api/python/dotpromptz.md @@ -20,7 +20,7 @@ dp = Dotprompt() # 2. Parse and render a prompt source = ''' --- -model: gemini-pro +model: googleai/gemini-2.5-pro input: schema: name: string @@ -28,7 +28,11 @@ input: Hello, {{name}}! ''' -rendered = await dp.render(source, data=DataArgument(input={'name': 'World'})) +rendered = await dp.render(source, data=DataArgument(input={'name': 'Ada'})) + +# 3. Access rendered message +print(rendered.messages[0].content[0].text) +# => Hello, Ada! ``` ## Module Reference diff --git a/python/dotpromptz/README.md b/python/dotpromptz/README.md index 87746f14b..20d16031a 100644 --- a/python/dotpromptz/README.md +++ b/python/dotpromptz/README.md @@ -80,7 +80,10 @@ input and `{{@name}}` for context: ```python from dotpromptz import DataArgument, Dotprompt +# 1. Initialize compiler prompt = Dotprompt() + +# 2. Render prompt with isolated input and context result = await prompt.render( '{{name}} is signed in as {{@name}}', DataArgument( @@ -88,4 +91,8 @@ result = await prompt.render( context={'name': 'admin'}, ), ) + +# 3. Access rendered output +print(result.messages[0].content[0].text) +# => Ada is signed in as admin ``` From 07687d76aafea0f34820d789518d7ad0b1f0ed10 Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Fri, 2 Oct 2026 04:29:23 -0500 Subject: [PATCH 03/10] feat(py): export standard prompt models, store protocols, and tool parts --- python/dotpromptz/src/dotpromptz/__init__.py | 33 ++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/python/dotpromptz/src/dotpromptz/__init__.py b/python/dotpromptz/src/dotpromptz/__init__.py index 336a5d992..aaa082f6d 100644 --- a/python/dotpromptz/src/dotpromptz/__init__.py +++ b/python/dotpromptz/src/dotpromptz/__init__.py @@ -64,7 +64,7 @@ # Schema Utilities from dotpromptz._picoschema import picoschema_to_json_schema -# Storage +# Storage Implementations & Protocols from dotpromptz._stores import ( DirStore, DirStoreOptions, @@ -75,23 +75,41 @@ from dotpromptz._typing import ( DataArgument, DataPart, + Document, MediaPart, Message, + ParsedPrompt, Part, + PartialData, + PartialRef, + PromptBundle, PromptData, PromptMetadata, + PromptRef, + PromptStore, + PromptStoreSync, + PromptStoreWritable, + PromptStoreWritableSync, RenderedPrompt, Role, TextPart, + ToolArgument, + ToolDefinition, + ToolRequestPart, + ToolResponsePart, ) __all__ = [ # Engine 'Dotprompt', - # Runtime & Data + # Runtime & Data Models 'DataArgument', + 'Document', + 'ParsedPrompt', + 'PromptBundle', 'PromptData', 'PromptMetadata', + 'PromptRef', 'RenderedPrompt', # Messages & Parts 'DataPart', @@ -100,10 +118,21 @@ 'Part', 'Role', 'TextPart', + 'ToolArgument', + 'ToolDefinition', + 'ToolRequestPart', + 'ToolResponsePart', + # Partials + 'PartialData', + 'PartialRef', # Storage 'DirStore', 'DirStoreOptions', 'DirStoreSync', + 'PromptStore', + 'PromptStoreSync', + 'PromptStoreWritable', + 'PromptStoreWritableSync', # Schema 'picoschema_to_json_schema', # Errors From 0238c0ad97b49f662a385cc62434735ab535ddd9 Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Fri, 2 Oct 2026 04:33:27 -0500 Subject: [PATCH 04/10] feat(py): export idiomatic functions, picoschema alias, and resolver types --- python/dotpromptz/src/dotpromptz/__init__.py | 22 ++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/python/dotpromptz/src/dotpromptz/__init__.py b/python/dotpromptz/src/dotpromptz/__init__.py index aaa082f6d..d09764e4d 100644 --- a/python/dotpromptz/src/dotpromptz/__init__.py +++ b/python/dotpromptz/src/dotpromptz/__init__.py @@ -61,8 +61,10 @@ ResolverFailedError, ) -# Schema Utilities +# Parsing & Schema Functions +from dotpromptz._parse import parse_document from dotpromptz._picoschema import picoschema_to_json_schema +from dotpromptz._picoschema_reverse import json_schema_to_picoschema # Storage Implementations & Protocols from dotpromptz._stores import ( @@ -71,7 +73,7 @@ DirStoreSync, ) -# Runtime Data & Models +# Runtime Data, Models & Resolver Protocols from dotpromptz._typing import ( DataArgument, DataPart, @@ -82,6 +84,7 @@ Part, PartialData, PartialRef, + PartialResolver, PromptBundle, PromptData, PromptMetadata, @@ -92,16 +95,22 @@ PromptStoreWritableSync, RenderedPrompt, Role, + SchemaResolver, TextPart, ToolArgument, ToolDefinition, ToolRequestPart, + ToolResolver, ToolResponsePart, ) +# Shorthand alias matching JS and Go conventions +picoschema = picoschema_to_json_schema + __all__ = [ - # Engine + # Engine & Functional Parsing 'Dotprompt', + 'parse_document', # Runtime & Data Models 'DataArgument', 'Document', @@ -122,9 +131,12 @@ 'ToolDefinition', 'ToolRequestPart', 'ToolResponsePart', - # Partials + # Partials & Resolvers 'PartialData', 'PartialRef', + 'PartialResolver', + 'SchemaResolver', + 'ToolResolver', # Storage 'DirStore', 'DirStoreOptions', @@ -134,6 +146,8 @@ 'PromptStoreWritable', 'PromptStoreWritableSync', # Schema + 'json_schema_to_picoschema', + 'picoschema', 'picoschema_to_json_schema', # Errors 'DotpromptError', From 5bd66f2691a8598c0597972b7de25c9632572ef9 Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Fri, 2 Oct 2026 13:09:51 -0500 Subject: [PATCH 05/10] docs(py): target root dotpromptz module for API reference and fix store re-exports --- docs/api/python/dotpromptz.md | 42 ++----------------- .../src/dotpromptz/_picoschema_reverse.py | 6 +-- .../src/dotpromptz/_stores/__init__.py | 4 +- 3 files changed, 7 insertions(+), 45 deletions(-) diff --git a/docs/api/python/dotpromptz.md b/docs/api/python/dotpromptz.md index f3692c007..42893731e 100644 --- a/docs/api/python/dotpromptz.md +++ b/docs/api/python/dotpromptz.md @@ -35,47 +35,11 @@ print(rendered.messages[0].content[0].text) # => Hello, Ada! ``` -## Module Reference +## API Reference -::: dotpromptz.Dotprompt +::: dotpromptz options: - show_root_heading: true - members_order: source - heading_level: 3 - -::: dotpromptz.DataArgument - options: - show_root_heading: true - members_order: source - heading_level: 3 - -::: dotpromptz.RenderedPrompt - options: - show_root_heading: true - members_order: source - heading_level: 3 - -::: dotpromptz.Message - options: - show_root_heading: true - members_order: source - heading_level: 3 - -::: dotpromptz.Role - options: - show_root_heading: true - members_order: source - heading_level: 3 - -::: dotpromptz.DirStore - options: - show_root_heading: true - members_order: source - heading_level: 3 - -::: dotpromptz.DotpromptError - options: - show_root_heading: true + show_root_heading: false members_order: source heading_level: 3 diff --git a/python/dotpromptz/src/dotpromptz/_picoschema_reverse.py b/python/dotpromptz/src/dotpromptz/_picoschema_reverse.py index 67f9d3368..9c16e3684 100644 --- a/python/dotpromptz/src/dotpromptz/_picoschema_reverse.py +++ b/python/dotpromptz/src/dotpromptz/_picoschema_reverse.py @@ -82,10 +82,8 @@ def _convert_node(node: dict[str, Any], required: bool = True) -> Any: description = node.get('description') # Handle nullable types: {"type": ["string", "null"]} -> optional string - is_nullable = False if isinstance(schema_type, list): non_null = [t for t in schema_type if t != 'null'] - is_nullable = 'null' in schema_type schema_type = non_null[0] if len(non_null) == 1 else None # Enum @@ -153,8 +151,8 @@ def _convert_object(node: dict[str, Any]) -> dict[str, Any]: is_nullable = 'null' in prop_type prop_type = non_null[0] if len(non_null) == 1 else None - # Build the key: add ? suffix for optional fields - key = prop_name if is_required else f'{prop_name}?' + # Build the key: add ? suffix for optional or nullable fields + key = prop_name if is_required and not is_nullable else f'{prop_name}?' # Enum property if 'enum' in prop_schema: diff --git a/python/dotpromptz/src/dotpromptz/_stores/__init__.py b/python/dotpromptz/src/dotpromptz/_stores/__init__.py index cc4446ccd..790865952 100644 --- a/python/dotpromptz/src/dotpromptz/_stores/__init__.py +++ b/python/dotpromptz/src/dotpromptz/_stores/__init__.py @@ -49,5 +49,5 @@ """ from ._dir_async import DirStore as DirStore -from ._dir_sync import DirStoreSync -from ._typing import DirStoreOptions +from ._dir_sync import DirStoreSync as DirStoreSync +from ._typing import DirStoreOptions as DirStoreOptions From 8bdb112e37047e1e48275acd93d5040688f3226d Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Fri, 2 Oct 2026 13:14:30 -0500 Subject: [PATCH 06/10] refactor(py): remove internal package __init__.py files --- python/dotpromptz/src/dotpromptz/__init__.py | 8 ++- .../src/dotpromptz/_adapters/__init__.py | 4 -- .../src/dotpromptz/_stores/__init__.py | 53 ------------------- .../src/dotpromptz/_stores/_dir_async.py | 3 +- .../src/dotpromptz/_stores/_dir_sync.py | 3 +- .../src/dotpromptz/_stores/_typing.py | 2 +- .../tests/dotpromptz/stores/dir_async_test.py | 2 +- .../tests/dotpromptz/stores/dir_sync_test.py | 2 +- 8 files changed, 8 insertions(+), 69 deletions(-) delete mode 100644 python/dotpromptz/src/dotpromptz/_adapters/__init__.py delete mode 100644 python/dotpromptz/src/dotpromptz/_stores/__init__.py diff --git a/python/dotpromptz/src/dotpromptz/__init__.py b/python/dotpromptz/src/dotpromptz/__init__.py index d09764e4d..5272bde97 100644 --- a/python/dotpromptz/src/dotpromptz/__init__.py +++ b/python/dotpromptz/src/dotpromptz/__init__.py @@ -67,11 +67,9 @@ from dotpromptz._picoschema_reverse import json_schema_to_picoschema # Storage Implementations & Protocols -from dotpromptz._stores import ( - DirStore, - DirStoreOptions, - DirStoreSync, -) +from dotpromptz._stores._dir_async import DirStore +from dotpromptz._stores._dir_sync import DirStoreSync +from dotpromptz._stores._typing import DirStoreOptions # Runtime Data, Models & Resolver Protocols from dotpromptz._typing import ( diff --git a/python/dotpromptz/src/dotpromptz/_adapters/__init__.py b/python/dotpromptz/src/dotpromptz/_adapters/__init__.py deleted file mode 100644 index 774f4f133..000000000 --- a/python/dotpromptz/src/dotpromptz/_adapters/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright 2025 Google LLC -# SPDX-License-Identifier: Apache-2.0 - -"""Adapters for dotpromptz.""" diff --git a/python/dotpromptz/src/dotpromptz/_stores/__init__.py b/python/dotpromptz/src/dotpromptz/_stores/__init__.py deleted file mode 100644 index 790865952..000000000 --- a/python/dotpromptz/src/dotpromptz/_stores/__init__.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# SPDX-License-Identifier: Apache-2.0 - -"""Stores for prompt templates and partials. - -This module provides implementations of prompt stores for managing, retrieving, -and persisting prompt templates and partials. A prompt store is responsible for -storing and retrieving prompt templates and their associated metadata. - -Available Store Implementations: -- DirStore: Asynchronous filesystem-based store -- DirStoreSync: Synchronous filesystem-based store -- DirStoreOptions: Configuration options for directory-based stores - -Directory-based stores organize prompts using the following conventions: -- Prompts are stored as files with extension `.prompt` -- Regular prompts: `[name][.variant].prompt` -- Partial prompts: `_[name][.variant].prompt` -- Directory structure forms part of the prompt/partial name -- Versions are calculated based on content hashing - -Usage Example: -```python -# Using the async store -from dotpromptz._stores import DirStore, DirStoreOptions - -store = DirStore(DirStoreOptions(directory='/path/to/prompts')) -prompts = await store.list() - -# Using the sync store -from dotpromptz._stores import DirStoreSync, DirStoreOptions - -sync_store = DirStoreSync(DirStoreOptions(directory='/path/to/prompts')) -prompts = sync_store.list() -``` -""" - -from ._dir_async import DirStore as DirStore -from ._dir_sync import DirStoreSync as DirStoreSync -from ._typing import DirStoreOptions as DirStoreOptions diff --git a/python/dotpromptz/src/dotpromptz/_stores/_dir_async.py b/python/dotpromptz/src/dotpromptz/_stores/_dir_async.py index 961b2cff3..6150ef11c 100644 --- a/python/dotpromptz/src/dotpromptz/_stores/_dir_async.py +++ b/python/dotpromptz/src/dotpromptz/_stores/_dir_async.py @@ -32,8 +32,7 @@ Example Usage: ```python -from dotpromptz._stores import DirStore, DirStoreOptions -from dotpromptz._typing import PromptData +from dotpromptz import DirStore, DirStoreOptions, PromptData # Create a store instance store = DirStore(DirStoreOptions(directory='/path/to/prompts')) diff --git a/python/dotpromptz/src/dotpromptz/_stores/_dir_sync.py b/python/dotpromptz/src/dotpromptz/_stores/_dir_sync.py index 53a1c738b..467127ab4 100644 --- a/python/dotpromptz/src/dotpromptz/_stores/_dir_sync.py +++ b/python/dotpromptz/src/dotpromptz/_stores/_dir_sync.py @@ -32,8 +32,7 @@ Example Usage: ```python -from dotpromptz._stores import DirStoreSync, DirStoreOptions -from dotpromptz._typing import PromptData +from dotpromptz import DirStoreOptions, DirStoreSync, PromptData # Create a store instance store = DirStoreSync(DirStoreOptions(directory='/path/to/prompts')) diff --git a/python/dotpromptz/src/dotpromptz/_stores/_typing.py b/python/dotpromptz/src/dotpromptz/_stores/_typing.py index 67ffcc9d3..e1999618f 100644 --- a/python/dotpromptz/src/dotpromptz/_stores/_typing.py +++ b/python/dotpromptz/src/dotpromptz/_stores/_typing.py @@ -47,7 +47,7 @@ class DirStoreOptions: Example: ```python from pathlib import Path - from dotpromptz._stores import DirStore, DirStoreOptions + from dotpromptz import DirStore, DirStoreOptions options = DirStoreOptions(directory=Path('/path/to/prompts')) store = DirStore(options) diff --git a/python/dotpromptz/tests/dotpromptz/stores/dir_async_test.py b/python/dotpromptz/tests/dotpromptz/stores/dir_async_test.py index 1ae191e51..c42e52eee 100644 --- a/python/dotpromptz/tests/dotpromptz/stores/dir_async_test.py +++ b/python/dotpromptz/tests/dotpromptz/stores/dir_async_test.py @@ -45,7 +45,7 @@ import pytest import pytest_asyncio -from dotpromptz._stores import DirStore, DirStoreOptions +from dotpromptz import DirStore, DirStoreOptions from dotpromptz._stores._io import calculate_version from dotpromptz._typing import ( DeletePromptOrPartialOptions, diff --git a/python/dotpromptz/tests/dotpromptz/stores/dir_sync_test.py b/python/dotpromptz/tests/dotpromptz/stores/dir_sync_test.py index ac7f6eab7..0d8d4f1a1 100644 --- a/python/dotpromptz/tests/dotpromptz/stores/dir_sync_test.py +++ b/python/dotpromptz/tests/dotpromptz/stores/dir_sync_test.py @@ -41,7 +41,7 @@ import pytest -from dotpromptz._stores import DirStoreOptions, DirStoreSync +from dotpromptz import DirStoreOptions, DirStoreSync from dotpromptz._stores._io import calculate_version from dotpromptz._stores._testutils import ( create_test_partial as create_test_partial_sync, From 82108bc9f08cb2f796207791e67ebdf82bb58ea0 Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Fri, 2 Oct 2026 13:24:44 -0500 Subject: [PATCH 07/10] chore(py): remove redundant picoschema alias export --- python/dotpromptz/src/dotpromptz/__init__.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/python/dotpromptz/src/dotpromptz/__init__.py b/python/dotpromptz/src/dotpromptz/__init__.py index 5272bde97..cb461fdd4 100644 --- a/python/dotpromptz/src/dotpromptz/__init__.py +++ b/python/dotpromptz/src/dotpromptz/__init__.py @@ -102,9 +102,6 @@ ToolResponsePart, ) -# Shorthand alias matching JS and Go conventions -picoschema = picoschema_to_json_schema - __all__ = [ # Engine & Functional Parsing 'Dotprompt', @@ -145,7 +142,6 @@ 'PromptStoreWritableSync', # Schema 'json_schema_to_picoschema', - 'picoschema', 'picoschema_to_json_schema', # Errors 'DotpromptError', From 946dd6a0ce56d64fef1365e1a752eef7beb3b4bb Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Fri, 2 Oct 2026 13:30:48 -0500 Subject: [PATCH 08/10] refactor(py): remove dead is_nullable assignment without behavior change --- python/dotpromptz/src/dotpromptz/_picoschema_reverse.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/python/dotpromptz/src/dotpromptz/_picoschema_reverse.py b/python/dotpromptz/src/dotpromptz/_picoschema_reverse.py index 9c16e3684..b1359bb6f 100644 --- a/python/dotpromptz/src/dotpromptz/_picoschema_reverse.py +++ b/python/dotpromptz/src/dotpromptz/_picoschema_reverse.py @@ -144,15 +144,13 @@ def _convert_object(node: dict[str, Any]) -> dict[str, Any]: prop_type = prop_schema.get('type') description = prop_schema.get('description') - # Detect nullable from type list - is_nullable = False + # Strip null from type list to get the underlying scalar type if isinstance(prop_type, list): non_null = [t for t in prop_type if t != 'null'] - is_nullable = 'null' in prop_type prop_type = non_null[0] if len(non_null) == 1 else None - # Build the key: add ? suffix for optional or nullable fields - key = prop_name if is_required and not is_nullable else f'{prop_name}?' + # Build the key: add ? suffix for optional fields + key = prop_name if is_required else f'{prop_name}?' # Enum property if 'enum' in prop_schema: From a35d4a05db0d4f05ca24d8b3a9e9660b74f2e2d9 Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Fri, 2 Oct 2026 17:52:38 -0500 Subject: [PATCH 09/10] fix(py): keep published genkit imports working on dotpromptz --- docs/api/python/dotpromptz.md | 2 +- python/dotpromptz/README.md | 4 +-- python/dotpromptz/src/dotpromptz/__init__.py | 12 ++++++- .../src/dotpromptz/dotprompt/__init__.py | 27 ++++++++++++++++ .../src/dotpromptz/errors/__init__.py | 27 ++++++++++++++++ .../src/dotpromptz/helpers/__init__.py | 27 ++++++++++++++++ .../src/dotpromptz/parse/__init__.py | 27 ++++++++++++++++ .../src/dotpromptz/picoschema/__init__.py | 27 ++++++++++++++++ .../src/dotpromptz/resolvers/__init__.py | 27 ++++++++++++++++ .../src/dotpromptz/stores/__init__.py | 31 +++++++++++++++++++ .../src/dotpromptz/typing/__init__.py | 27 ++++++++++++++++ .../src/dotpromptz/util/__init__.py | 27 ++++++++++++++++ 12 files changed, 261 insertions(+), 4 deletions(-) create mode 100644 python/dotpromptz/src/dotpromptz/dotprompt/__init__.py create mode 100644 python/dotpromptz/src/dotpromptz/errors/__init__.py create mode 100644 python/dotpromptz/src/dotpromptz/helpers/__init__.py create mode 100644 python/dotpromptz/src/dotpromptz/parse/__init__.py create mode 100644 python/dotpromptz/src/dotpromptz/picoschema/__init__.py create mode 100644 python/dotpromptz/src/dotpromptz/resolvers/__init__.py create mode 100644 python/dotpromptz/src/dotpromptz/stores/__init__.py create mode 100644 python/dotpromptz/src/dotpromptz/typing/__init__.py create mode 100644 python/dotpromptz/src/dotpromptz/util/__init__.py diff --git a/docs/api/python/dotpromptz.md b/docs/api/python/dotpromptz.md index 42893731e..134a3bb25 100644 --- a/docs/api/python/dotpromptz.md +++ b/docs/api/python/dotpromptz.md @@ -20,7 +20,7 @@ dp = Dotprompt() # 2. Parse and render a prompt source = ''' --- -model: googleai/gemini-2.5-pro +model: googleai/gemini-flash-latest input: schema: name: string diff --git a/python/dotpromptz/README.md b/python/dotpromptz/README.md index 20d16031a..8b033c1d9 100644 --- a/python/dotpromptz/README.md +++ b/python/dotpromptz/README.md @@ -44,7 +44,7 @@ Here's an example of a Dotprompt file that extracts structured data from provide ```handlebars --- -model: googleai/gemini-2.5-pro +model: googleai/gemini-flash-latest input: schema: text: string @@ -62,7 +62,7 @@ present, omit that field from the output. Text: This Dotprompt file: -1. Specifies the use of the `googleai/gemini-2.5-pro` model. +1. Specifies the use of the `googleai/gemini-flash-latest` model. 2. Defines an input schema expecting a `text` string. 3. Specifies that the output should be in JSON format. 4. Provides a schema for the expected output, including fields for name, age, and occupation. diff --git a/python/dotpromptz/src/dotpromptz/__init__.py b/python/dotpromptz/src/dotpromptz/__init__.py index cb461fdd4..deb1e070d 100644 --- a/python/dotpromptz/src/dotpromptz/__init__.py +++ b/python/dotpromptz/src/dotpromptz/__init__.py @@ -29,7 +29,7 @@ # 2. Render prompt source with input data rendered = await prompt.render( '''--- - model: googleai/gemini-2.5-pro + model: googleai/gemini-flash-latest input: schema: customer: string @@ -76,6 +76,7 @@ DataArgument, DataPart, Document, + JsonSchema, MediaPart, Message, ParsedPrompt, @@ -85,6 +86,8 @@ PartialResolver, PromptBundle, PromptData, + PromptFunction, + PromptInputConfig, PromptMetadata, PromptRef, PromptStore, @@ -101,6 +104,7 @@ ToolResolver, ToolResponsePart, ) +from dotpromptz_handlebars import EscapeFunction, HelperFn __all__ = [ # Engine & Functional Parsing @@ -111,7 +115,10 @@ 'Document', 'ParsedPrompt', 'PromptBundle', + 'JsonSchema', 'PromptData', + 'PromptFunction', + 'PromptInputConfig', 'PromptMetadata', 'PromptRef', 'RenderedPrompt', @@ -140,6 +147,9 @@ 'PromptStoreSync', 'PromptStoreWritable', 'PromptStoreWritableSync', + # Engine types used in Dotprompt's public signatures + 'EscapeFunction', + 'HelperFn', # Schema 'json_schema_to_picoschema', 'picoschema_to_json_schema', diff --git a/python/dotpromptz/src/dotpromptz/dotprompt/__init__.py b/python/dotpromptz/src/dotpromptz/dotprompt/__init__.py new file mode 100644 index 000000000..fefceef8f --- /dev/null +++ b/python/dotpromptz/src/dotpromptz/dotprompt/__init__.py @@ -0,0 +1,27 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +"""Deprecated import path. + +`genkit<=0.12.0` on PyPI depends on `dotpromptz>=0.1.5` without an upper bound +and imports `from dotpromptz.dotprompt import ...`. This shim keeps those legacy +installations working. + +Remove this shim in `dotpromptz>=0.3.0` after `genkit<=0.12.0` has aged out +and users have upgraded. +""" + +from dotpromptz._dotprompt import * # noqa: F403 diff --git a/python/dotpromptz/src/dotpromptz/errors/__init__.py b/python/dotpromptz/src/dotpromptz/errors/__init__.py new file mode 100644 index 000000000..ebc612a9f --- /dev/null +++ b/python/dotpromptz/src/dotpromptz/errors/__init__.py @@ -0,0 +1,27 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +"""Deprecated import path. + +`genkit<=0.12.0` on PyPI depends on `dotpromptz>=0.1.5` without an upper bound +and imports `from dotpromptz.errors import ...`. This shim keeps those legacy +installations working. + +Remove this shim in `dotpromptz>=0.3.0` after `genkit<=0.12.0` has aged out +and users have upgraded. +""" + +from dotpromptz._errors import * # noqa: F403 diff --git a/python/dotpromptz/src/dotpromptz/helpers/__init__.py b/python/dotpromptz/src/dotpromptz/helpers/__init__.py new file mode 100644 index 000000000..fd1257f60 --- /dev/null +++ b/python/dotpromptz/src/dotpromptz/helpers/__init__.py @@ -0,0 +1,27 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +"""Deprecated import path. + +`genkit<=0.12.0` on PyPI depends on `dotpromptz>=0.1.5` without an upper bound +and imports `from dotpromptz.helpers import ...`. This shim keeps those legacy +installations working. + +Remove this shim in `dotpromptz>=0.3.0` after `genkit<=0.12.0` has aged out +and users have upgraded. +""" + +from dotpromptz._helpers import * # noqa: F403 diff --git a/python/dotpromptz/src/dotpromptz/parse/__init__.py b/python/dotpromptz/src/dotpromptz/parse/__init__.py new file mode 100644 index 000000000..19bf5c14c --- /dev/null +++ b/python/dotpromptz/src/dotpromptz/parse/__init__.py @@ -0,0 +1,27 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +"""Deprecated import path. + +`genkit<=0.12.0` on PyPI depends on `dotpromptz>=0.1.5` without an upper bound +and imports `from dotpromptz.parse import ...`. This shim keeps those legacy +installations working. + +Remove this shim in `dotpromptz>=0.3.0` after `genkit<=0.12.0` has aged out +and users have upgraded. +""" + +from dotpromptz._parse import * # noqa: F403 diff --git a/python/dotpromptz/src/dotpromptz/picoschema/__init__.py b/python/dotpromptz/src/dotpromptz/picoschema/__init__.py new file mode 100644 index 000000000..1d7115833 --- /dev/null +++ b/python/dotpromptz/src/dotpromptz/picoschema/__init__.py @@ -0,0 +1,27 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +"""Deprecated import path. + +`genkit<=0.12.0` on PyPI depends on `dotpromptz>=0.1.5` without an upper bound +and imports `from dotpromptz.picoschema import ...`. This shim keeps those legacy +installations working. + +Remove this shim in `dotpromptz>=0.3.0` after `genkit<=0.12.0` has aged out +and users have upgraded. +""" + +from dotpromptz._picoschema import * # noqa: F403 diff --git a/python/dotpromptz/src/dotpromptz/resolvers/__init__.py b/python/dotpromptz/src/dotpromptz/resolvers/__init__.py new file mode 100644 index 000000000..a85ed1062 --- /dev/null +++ b/python/dotpromptz/src/dotpromptz/resolvers/__init__.py @@ -0,0 +1,27 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +"""Deprecated import path. + +`genkit<=0.12.0` on PyPI depends on `dotpromptz>=0.1.5` without an upper bound +and imports `from dotpromptz.resolvers import ...`. This shim keeps those legacy +installations working. + +Remove this shim in `dotpromptz>=0.3.0` after `genkit<=0.12.0` has aged out +and users have upgraded. +""" + +from dotpromptz._resolvers import * # noqa: F403 diff --git a/python/dotpromptz/src/dotpromptz/stores/__init__.py b/python/dotpromptz/src/dotpromptz/stores/__init__.py new file mode 100644 index 000000000..a0cc37161 --- /dev/null +++ b/python/dotpromptz/src/dotpromptz/stores/__init__.py @@ -0,0 +1,31 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +"""Deprecated import path. + +`genkit<=0.12.0` on PyPI depends on `dotpromptz>=0.1.5` without an upper bound +and imports `from dotpromptz.stores import ...`. This shim keeps those legacy +installations working. + +Remove this shim in `dotpromptz>=0.3.0` after `genkit<=0.12.0` has aged out +and users have upgraded. +""" + +from dotpromptz._stores._dir_async import DirStore +from dotpromptz._stores._dir_sync import DirStoreSync +from dotpromptz._stores._typing import DirStoreOptions + +__all__ = ['DirStore', 'DirStoreOptions', 'DirStoreSync'] diff --git a/python/dotpromptz/src/dotpromptz/typing/__init__.py b/python/dotpromptz/src/dotpromptz/typing/__init__.py new file mode 100644 index 000000000..a9aa494f7 --- /dev/null +++ b/python/dotpromptz/src/dotpromptz/typing/__init__.py @@ -0,0 +1,27 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +"""Deprecated import path. + +`genkit<=0.12.0` on PyPI depends on `dotpromptz>=0.1.5` without an upper bound +and imports `from dotpromptz.typing import ...`. This shim keeps those legacy +installations working. + +Remove this shim in `dotpromptz>=0.3.0` after `genkit<=0.12.0` has aged out +and users have upgraded. +""" + +from dotpromptz._typing import * # noqa: F403 diff --git a/python/dotpromptz/src/dotpromptz/util/__init__.py b/python/dotpromptz/src/dotpromptz/util/__init__.py new file mode 100644 index 000000000..3bdbf1810 --- /dev/null +++ b/python/dotpromptz/src/dotpromptz/util/__init__.py @@ -0,0 +1,27 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +"""Deprecated import path. + +`genkit<=0.12.0` on PyPI depends on `dotpromptz>=0.1.5` without an upper bound +and imports `from dotpromptz.util import ...`. This shim keeps those legacy +installations working. + +Remove this shim in `dotpromptz>=0.3.0` after `genkit<=0.12.0` has aged out +and users have upgraded. +""" + +from dotpromptz._util import * # noqa: F403 From c0a9ac22fe476c12a6fd7b4f2ab7f28dbaa7cfa7 Mon Sep 17 00:00:00 2001 From: Jeff Huang Date: Mon, 5 Oct 2026 09:39:50 -0500 Subject: [PATCH 10/10] docs(py): list removed dotpromptz submodules in changelog breaking changes --- python/dotpromptz/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python/dotpromptz/CHANGELOG.md b/python/dotpromptz/CHANGELOG.md index cf5de73c4..f7e045ef9 100644 --- a/python/dotpromptz/CHANGELOG.md +++ b/python/dotpromptz/CHANGELOG.md @@ -5,6 +5,10 @@ ### ⚠ BREAKING CHANGES * **helpers:** `{{json ...}}` in prompt templates now raises `TypeError` (standard Python `json.dumps()` behavior) instead of `ValueError` when passed non-serializable objects. +* **api:** implementation modules moved behind private `_`-prefixed names; import from the `dotpromptz` root instead ([#626](https://github.com/google/dotprompt/pull/626)). `dotprompt`, `typing`, `stores`, `errors`, `helpers`, `parse`, `picoschema`, `resolvers`, and `util` remain as compatibility re-exports and will be removed in a future release. These 0.1.6 import paths no longer resolve: + * `dotpromptz.picoschema_reverse`: use `from dotpromptz import json_schema_to_picoschema`. + * `dotpromptz.adapters`, `dotpromptz.models`, `dotpromptz.validate`: removed with no public replacement. + * `dotpromptz.package_name()`: removed. ### Features