prompt-template


Nameprompt-template JSON
Version 1.2.0 PyPI version JSON
download
home_pageNone
SummaryA robust zero-dependency library for creating prompt templates
upload_time2025-02-12 18:55:45
maintainerNone
docs_urlNone
authorNone
requires_python>=3.9
licenseMIT
keywords ai llm prompt-engineering prompt-template templating
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Prompt Template

A lightweight, zero-dependency Python library for managing LLM prompt templates. Built on the design principles of
`string.Template` but with enhanced features specifically designed for LLM prompt engineering.

## Features

- Strong template validation with detailed error messages
- Support for nested braces and complex JSON structures
- Automatic value serialization for common Python types
- Default value support with deep copying for mutable types
- Incremental template population with value inheritance
- Type hints for enhanced IDE support
- Zero dependencies - just pure Python
- 100% test coverage

## Installation

```bash
pip install prompt-template
```

## Usage

The library is intentionally very simple to use.
The idea is to keep it simple, have validation and serialization builtin, and make debugging simple.

### Simple Templates

```python
from prompt_template import PromptTemplate

# Create a template
template = PromptTemplate("Hello ${name}! Welcome to ${location}.")

# Render with values
result = template.to_string(name="Alice", location="Wonderland")
print(result)  # Hello Alice! Welcome to Wonderland.
```

### Default Values

```python
# Set default values that can be overridden later
template = PromptTemplate("Hello ${name}! Your settings are: ${settings}")

# Set default values - they're safely deep copied
template.set_default(
    name="Guest",
    settings={"theme": "light", "language": "en"}
)

# Use with defaults
print(template.to_string())
# Hello Guest! Your settings are: {"theme": "light", "language": "en"}

# Override specific values
print(template.to_string(name="Alice"))
# Hello Alice! Your settings are: {"theme": "light", "language": "en"}

# Override everything
print(template.to_string(
    name="Bob",
    settings={"theme": "dark", "language": "fr"}
))
# Hello Bob! Your settings are: {"theme": "dark", "language": "fr"}
```

### Named Templates

Adding a name to your template enhances error messages with context. Templates with the same name and content are considered equal:

```python
# Create named templates
template1 = PromptTemplate(
    name="user_greeting",
    template="Hello ${name}! Welcome to ${location}."
)

# Templates can be compared and used as dictionary keys
template2 = PromptTemplate(
    name="user_greeting",
    template="Hello ${name}! Welcome to ${location}."
)
assert template1 == template2

# Templates have a readable string representation
print(template1)  # PromptTemplate [user_greeting]:\n\nHello ${name}! Welcome to ${location}.
```

### Complex JSON Templates

The library handles nested structures elegantly:

```python
template = PromptTemplate("""
{
    "user": {
        "name": "${username}",
        "role": "${role}"
    },
    "settings": {
        "theme": "${theme}",
        "notifications": ${notifications},
        "preferences": ${preferences}
    }
}
""")

# Values are automatically serialized
result = template.to_string(
    username="john_doe",
    role="admin",
    theme="dark",
    notifications={"email": True, "push": False},
    preferences=["daily_digest", "weekly_report"]
)
```

### Template Methods

The library provides two main methods for populating templates:

```python
# to_string(): Validates inputs, uses defaults, and serializes values
template = PromptTemplate("Hello ${name}!")
template.set_default(name="Guest")
result = template.to_string()  # Uses default
result = template.to_string(name="Alice")  # Overrides default

# substitute(): Lower-level method for partial population
base = PromptTemplate("${greeting} ${name}!")
partial = base.substitute(greeting="Hello")  # Returns a string
final = PromptTemplate(partial).to_string(name="Alice")
```

### Nested Templates

Templates can be nested within other templates:

```python
# Create nested templates
inner = PromptTemplate("My name is ${name}")
inner.set_default(name="Alice")

outer = PromptTemplate("""
User message:
${message}
""")

# Combine templates
result = outer.to_string(message=inner.to_string())
print(result)
# User message:
# My name is Alice
```

### Type Handling and Automatic Serialization

The library automatically handles various Python types:

```python
from uuid import UUID
from decimal import Decimal
from datetime import datetime

template = PromptTemplate("""
{
    "id": "${id}",
    "amount": "${amount}",
    "metadata": ${metadata}
}
""")

result = template.to_string(
    id=UUID("550e8400-e29b-41d4-a716-446655440000"),
    amount=Decimal("45.67"),
    metadata={
        "timestamp": datetime.now(),  # Serialized via JSON
        "values": [1, 2, 3]
    }
)
```

### Custom Serialization

Extend the base class to customize value serialization with proper error handling:

```python
from typing import Any
from datetime import datetime
from decimal import Decimal
from prompt_template import PromptTemplate as BasePromptTemplate
import orjson


class PromptTemplate(BasePromptTemplate):
    @staticmethod
    def serializer(value: Any) -> str:
        """Custom serializer with orjson for better performance.

        Handles special cases and provides detailed error messages.
        """
        try:
            # Handle special types first
            if isinstance(value, (datetime, Decimal)):
                return str(value)

            # Use orjson for everything else
            return orjson.dumps(value).decode('utf-8')
        except (TypeError, ValueError) as e:
            raise TypeError(
                f"Failed to serialize value of type {type(value).__name__}: {e}"
            ) from e
```

The custom serializer will be used automatically:

```python
template = PromptTemplate("""
{
    "timestamp": "${time}",
    "amount": "${price}",
    "data": ${complex_data}
}
""")

result = template.to_string(
    time=datetime.now(),
    price=Decimal("45.67"),
    complex_data={"nested": [1, 2, 3]}
)
```

## Error Handling

The library provides specific extensive errors:

### Missing Values

```python
from prompt_template import MissingTemplateValuesError

template = PromptTemplate("Hello ${name}!")
try:
    template.to_string()  # No values provided
except MissingTemplateValuesError as e:
    print(f"Missing values: {e.missing_values}")  # {'name'}
```

### Invalid Keys

```python
from prompt_template import InvalidTemplateKeysError

template = PromptTemplate("Hello ${name}!")
try:
    template.to_string(name="World", invalid_key="value")
except InvalidTemplateKeysError as e:
    print(f"Invalid keys: {e.invalid_keys}")  # ['invalid_key']
    print(f"Valid keys: {e.valid_keys}")  # {'name'}
```

### Serialization Errors

```python
from prompt_template import TemplateSerializationError

template = PromptTemplate("Value: ${value}")
try:
    template.to_string(value=object())  # Non-serializable object
except TemplateSerializationError as e:
    print(f"Failed to serialize key '{e.key}': {e.original_error}")
```

## License

MIT License

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "prompt-template",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": "ai, llm, prompt-engineering, prompt-template, templating",
    "author": null,
    "author_email": "Na'aman Hirschfeld <nhirschfed@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/bc/3b/6918eeede245be7b22bcbb3419d85aadb2e9d7fd201c2384389ca1dc8dc8/prompt_template-1.2.0.tar.gz",
    "platform": null,
    "description": "# Prompt Template\n\nA lightweight, zero-dependency Python library for managing LLM prompt templates. Built on the design principles of\n`string.Template` but with enhanced features specifically designed for LLM prompt engineering.\n\n## Features\n\n- Strong template validation with detailed error messages\n- Support for nested braces and complex JSON structures\n- Automatic value serialization for common Python types\n- Default value support with deep copying for mutable types\n- Incremental template population with value inheritance\n- Type hints for enhanced IDE support\n- Zero dependencies - just pure Python\n- 100% test coverage\n\n## Installation\n\n```bash\npip install prompt-template\n```\n\n## Usage\n\nThe library is intentionally very simple to use.\nThe idea is to keep it simple, have validation and serialization builtin, and make debugging simple.\n\n### Simple Templates\n\n```python\nfrom prompt_template import PromptTemplate\n\n# Create a template\ntemplate = PromptTemplate(\"Hello ${name}! Welcome to ${location}.\")\n\n# Render with values\nresult = template.to_string(name=\"Alice\", location=\"Wonderland\")\nprint(result)  # Hello Alice! Welcome to Wonderland.\n```\n\n### Default Values\n\n```python\n# Set default values that can be overridden later\ntemplate = PromptTemplate(\"Hello ${name}! Your settings are: ${settings}\")\n\n# Set default values - they're safely deep copied\ntemplate.set_default(\n    name=\"Guest\",\n    settings={\"theme\": \"light\", \"language\": \"en\"}\n)\n\n# Use with defaults\nprint(template.to_string())\n# Hello Guest! Your settings are: {\"theme\": \"light\", \"language\": \"en\"}\n\n# Override specific values\nprint(template.to_string(name=\"Alice\"))\n# Hello Alice! Your settings are: {\"theme\": \"light\", \"language\": \"en\"}\n\n# Override everything\nprint(template.to_string(\n    name=\"Bob\",\n    settings={\"theme\": \"dark\", \"language\": \"fr\"}\n))\n# Hello Bob! Your settings are: {\"theme\": \"dark\", \"language\": \"fr\"}\n```\n\n### Named Templates\n\nAdding a name to your template enhances error messages with context. Templates with the same name and content are considered equal:\n\n```python\n# Create named templates\ntemplate1 = PromptTemplate(\n    name=\"user_greeting\",\n    template=\"Hello ${name}! Welcome to ${location}.\"\n)\n\n# Templates can be compared and used as dictionary keys\ntemplate2 = PromptTemplate(\n    name=\"user_greeting\",\n    template=\"Hello ${name}! Welcome to ${location}.\"\n)\nassert template1 == template2\n\n# Templates have a readable string representation\nprint(template1)  # PromptTemplate [user_greeting]:\\n\\nHello ${name}! Welcome to ${location}.\n```\n\n### Complex JSON Templates\n\nThe library handles nested structures elegantly:\n\n```python\ntemplate = PromptTemplate(\"\"\"\n{\n    \"user\": {\n        \"name\": \"${username}\",\n        \"role\": \"${role}\"\n    },\n    \"settings\": {\n        \"theme\": \"${theme}\",\n        \"notifications\": ${notifications},\n        \"preferences\": ${preferences}\n    }\n}\n\"\"\")\n\n# Values are automatically serialized\nresult = template.to_string(\n    username=\"john_doe\",\n    role=\"admin\",\n    theme=\"dark\",\n    notifications={\"email\": True, \"push\": False},\n    preferences=[\"daily_digest\", \"weekly_report\"]\n)\n```\n\n### Template Methods\n\nThe library provides two main methods for populating templates:\n\n```python\n# to_string(): Validates inputs, uses defaults, and serializes values\ntemplate = PromptTemplate(\"Hello ${name}!\")\ntemplate.set_default(name=\"Guest\")\nresult = template.to_string()  # Uses default\nresult = template.to_string(name=\"Alice\")  # Overrides default\n\n# substitute(): Lower-level method for partial population\nbase = PromptTemplate(\"${greeting} ${name}!\")\npartial = base.substitute(greeting=\"Hello\")  # Returns a string\nfinal = PromptTemplate(partial).to_string(name=\"Alice\")\n```\n\n### Nested Templates\n\nTemplates can be nested within other templates:\n\n```python\n# Create nested templates\ninner = PromptTemplate(\"My name is ${name}\")\ninner.set_default(name=\"Alice\")\n\nouter = PromptTemplate(\"\"\"\nUser message:\n${message}\n\"\"\")\n\n# Combine templates\nresult = outer.to_string(message=inner.to_string())\nprint(result)\n# User message:\n# My name is Alice\n```\n\n### Type Handling and Automatic Serialization\n\nThe library automatically handles various Python types:\n\n```python\nfrom uuid import UUID\nfrom decimal import Decimal\nfrom datetime import datetime\n\ntemplate = PromptTemplate(\"\"\"\n{\n    \"id\": \"${id}\",\n    \"amount\": \"${amount}\",\n    \"metadata\": ${metadata}\n}\n\"\"\")\n\nresult = template.to_string(\n    id=UUID(\"550e8400-e29b-41d4-a716-446655440000\"),\n    amount=Decimal(\"45.67\"),\n    metadata={\n        \"timestamp\": datetime.now(),  # Serialized via JSON\n        \"values\": [1, 2, 3]\n    }\n)\n```\n\n### Custom Serialization\n\nExtend the base class to customize value serialization with proper error handling:\n\n```python\nfrom typing import Any\nfrom datetime import datetime\nfrom decimal import Decimal\nfrom prompt_template import PromptTemplate as BasePromptTemplate\nimport orjson\n\n\nclass PromptTemplate(BasePromptTemplate):\n    @staticmethod\n    def serializer(value: Any) -> str:\n        \"\"\"Custom serializer with orjson for better performance.\n\n        Handles special cases and provides detailed error messages.\n        \"\"\"\n        try:\n            # Handle special types first\n            if isinstance(value, (datetime, Decimal)):\n                return str(value)\n\n            # Use orjson for everything else\n            return orjson.dumps(value).decode('utf-8')\n        except (TypeError, ValueError) as e:\n            raise TypeError(\n                f\"Failed to serialize value of type {type(value).__name__}: {e}\"\n            ) from e\n```\n\nThe custom serializer will be used automatically:\n\n```python\ntemplate = PromptTemplate(\"\"\"\n{\n    \"timestamp\": \"${time}\",\n    \"amount\": \"${price}\",\n    \"data\": ${complex_data}\n}\n\"\"\")\n\nresult = template.to_string(\n    time=datetime.now(),\n    price=Decimal(\"45.67\"),\n    complex_data={\"nested\": [1, 2, 3]}\n)\n```\n\n## Error Handling\n\nThe library provides specific extensive errors:\n\n### Missing Values\n\n```python\nfrom prompt_template import MissingTemplateValuesError\n\ntemplate = PromptTemplate(\"Hello ${name}!\")\ntry:\n    template.to_string()  # No values provided\nexcept MissingTemplateValuesError as e:\n    print(f\"Missing values: {e.missing_values}\")  # {'name'}\n```\n\n### Invalid Keys\n\n```python\nfrom prompt_template import InvalidTemplateKeysError\n\ntemplate = PromptTemplate(\"Hello ${name}!\")\ntry:\n    template.to_string(name=\"World\", invalid_key=\"value\")\nexcept InvalidTemplateKeysError as e:\n    print(f\"Invalid keys: {e.invalid_keys}\")  # ['invalid_key']\n    print(f\"Valid keys: {e.valid_keys}\")  # {'name'}\n```\n\n### Serialization Errors\n\n```python\nfrom prompt_template import TemplateSerializationError\n\ntemplate = PromptTemplate(\"Value: ${value}\")\ntry:\n    template.to_string(value=object())  # Non-serializable object\nexcept TemplateSerializationError as e:\n    print(f\"Failed to serialize key '{e.key}': {e.original_error}\")\n```\n\n## License\n\nMIT License\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A robust zero-dependency library for creating prompt templates",
    "version": "1.2.0",
    "project_urls": {
        "homepage": "https://github.com/Goldziher/prompt-template"
    },
    "split_keywords": [
        "ai",
        " llm",
        " prompt-engineering",
        " prompt-template",
        " templating"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "34d0ed203aabbb1d131fbea89c5fe42aa13cadb49ebc5dafc781170049e3c7f5",
                "md5": "25d1aa797f7c77ae108ea3e3bc01ab2d",
                "sha256": "96f6f0f8d3fcbddd0816aeb2cd95632b9e08d38e786963a23260abf6da45629b"
            },
            "downloads": -1,
            "filename": "prompt_template-1.2.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "25d1aa797f7c77ae108ea3e3bc01ab2d",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 8733,
            "upload_time": "2025-02-12T18:55:43",
            "upload_time_iso_8601": "2025-02-12T18:55:43.955968Z",
            "url": "https://files.pythonhosted.org/packages/34/d0/ed203aabbb1d131fbea89c5fe42aa13cadb49ebc5dafc781170049e3c7f5/prompt_template-1.2.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "bc3b6918eeede245be7b22bcbb3419d85aadb2e9d7fd201c2384389ca1dc8dc8",
                "md5": "1227357bda238b022ecb40d185ded25d",
                "sha256": "03c2099b83080d144448e12c7f94192e3503cfa5c55359f2e07a6143703d97c2"
            },
            "downloads": -1,
            "filename": "prompt_template-1.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "1227357bda238b022ecb40d185ded25d",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 39087,
            "upload_time": "2025-02-12T18:55:45",
            "upload_time_iso_8601": "2025-02-12T18:55:45.870208Z",
            "url": "https://files.pythonhosted.org/packages/bc/3b/6918eeede245be7b22bcbb3419d85aadb2e9d7fd201c2384389ca1dc8dc8/prompt_template-1.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-02-12 18:55:45",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "Goldziher",
    "github_project": "prompt-template",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "prompt-template"
}
        
Elapsed time: 0.96100s