Skip to main content

Object-oriented prompting for Python

This project has been archived.

The maintainers of this project have marked this project as archived. No new releases are expected.

Project description

Proompt

Object-oriented prompt engineering for LLMs

Stop wrestling with string templates. Build composable, testable, and maintainable prompts using object-oriented design patterns.

# Instead of this messy string concatenation...
prompt = f"""
Analyze this data:
{open('data.csv').read()}

Using these functions:
{str(my_functions)}
"""

# Write clean, composable prompts like this:
from proompt.data import (
    CsvDataProvider,
    FileDataProvider,
    SqliteProvider,
)
from proompt.base.context import ToolContext

section = PromptSection(
    context=ToolContext(my_function),
    CsvDataProvider("data.csv"),
    FileDataProvider("file.txt"),
    SqliteProvider("data.db"),
)

Project Overview

Proompt is organized into a clean, modular structure:

proompt/
├── src/proompt/
│   ├── base/              # Abstract base classes
│   │   ├── context.py
│   │   ├── prompt.py
│   │   └── provider.py
│   └── data.py            # Concrete data provider examples
├── examples/              # Complete usage examples
│   ├── 01-simple_quarterly_review.py
│   ├── 02-intermediate_quarterly_review.py
│   └── 03-advanced_quarterly_review.py
└── tests/                 # Unit tests

Key Components:

  • Base classes define contracts for providers, contexts, and prompts
  • Data providers concrete examples of how to extend DataProviders
  • Examples show real-world implementations from simple to advanced
  • Tests ensure reliability and demonstrate usage patterns

Why Proompt?

Traditional string-based prompts are painful:

  • 🔥 Hard to compose and maintain large prompts
  • 🐛 No separation between data and prompt logic
  • 🚫 Difficult to test individual components
  • 🔄 Can't reuse prompt components across projects
  • ⚠️ No type safety or validation

Proompt solves this with:

  • Composable objects - Build prompts from reusable components
  • Data providers - Clean separation of data sources and prompt logic
  • Type safety - Abstract base classes enforce contracts
  • Testable - Unit test each component independently
  • Extensible - Easy to create custom providers and contexts
  • Async ready - Support for both sync and async operations

Quick Start

uv pip install proompt
from proompt.data import FileDataProvider

# Read a file and inject it into your prompt
provider = FileDataProvider("data.txt")
content = provider.run()  # Returns file contents as string

print(f"Analyze the data:\n{content}")

Core Concepts

A few example classes for extending the DataProvider class can be found in the proompt.data module.

🔌 Providers - Inject Data from Any Source

Providers fetch data from external sources and format it for LLM consumption:

from proompt.data import CsvDataProvider, SqliteProvider

# CSV data as markdown tables
csv_provider = CsvDataProvider("sales_data.csv")
print(csv_provider.run())
# | Product | Sales | Region |
# | ------- | ----- | ------ |
# | Widget  | 1000  | North  |

# Database queries as markdown tables
db_provider = SqliteProvider(
    "company.db",
    'SELECT * FROM employees WHERE department = "Engineering"'
)
print(db_provider.run())
# | name  | role      | salary |
# | ----- | --------- | ------ |
# | Alice | Developer | 85000  |

🛠️ Tool Context - Document Functions for LLMs

Automatically generate function documentation that LLMs can understand:

from proompt.base.context import ToolContext

def calculate_tax(income: float, rate: float = 0.25) -> float:
    """Calculate tax owed on income."""
    return income * rate

tool_ctx = ToolContext(calculate_tax)
print(tool_ctx.render())
# Name: calculate_tax
# Description: Calculate tax owed on income.
# Arguments: income: float, rate: float = 0.25
# Returns: float
# Usage: Reference description for usage.

📝 Prompt Sections - Compose Complex Prompts

Combine providers, tools, and context into reusable sections:

from textwrap import dedent
from proompt.base.prompt import PromptSection

class DataAnalysisSection(PromptSection):

    def formatter(self, instruction: str) -> str:
        data = "\n\n".join(p.run() for p in self.providers)
        tools = "\n\n".join(str(t) for t in self.tools)

        return dedent(f"""
        {instruction}

        Available Data Providers:
        {data}

        Available Tools:
        {tools}
        """)

    def render(self) -> str:
        return self.formatter("Analyze the provided data")

# Use it
section = DataAnalysisSection(
    context=context,  # Use Context to pass dynamic info
    tools=[ToolContext(calculate_tax)],
    CsvDataProvider("metrics.csv"),  # accepts any number of Providers
)

prompt = str(section)  # Ready for your LLM

Data Providers

File Provider

from proompt.data import FileDataProvider

# Read any text file
provider = FileDataProvider("config.yaml")
content = provider.run().  # raw string content

NOTE: for structured YAML parsing, extend DataProvider to create YamlProvider class

CSV Provider

from proompt.data import CsvDataProvider

# Automatically converts CSV to markdown tables
provider = CsvDataProvider("data.csv")
table = provider.run()  # Returns formatted markdown table

See proompt.data.TableData and proompt.data.to_markdown_table() for conversion.

SQLite Provider

from proompt.data import SqliteProvider

# Execute SQL queries, get markdown tables
provider = SqliteProvider(
    database_path="app.db",
    query="SELECT name, email FROM users WHERE active = 1",
    table_name="users"  # Optional, for better context
)

# Async support; NOTE the async only runs sync method .run()
result = await provider.arun()

NOTE: A true asynchronous method would need to be defined when extending the DataProvider class.

Advanced Usage

Custom Providers

Creating custom providers is straightforward:

from proompt.base.provider import BaseProvider
import requests

class ApiProvider(BaseProvider, str):

    def __init__(self, url: str, api_key: str):
        self.url = url
        self.api_key = api_key

    @property
    def name(self) -> str:
        return f"API Provider for {self.url}"

    @property
    def provider_ctx(self) -> str:
        return f"Fetches data from REST API at {self.url}"
        # NOTE: would be useful to include available endpoints

    def run(self, endpoint: str) -> str:
        response = requests.get(
            f"{self.url}/{endpoint}",
            headers={"Authorization": f"Bearer {self.api_key}"}
        )
        return response.json()

# Use your custom provider
api = ApiProvider("https://api.example.com", "your-key")
data = api.run("users")

Data Transformation

Convert any data format to LLM-friendly markdown:

from proompt.data import TableData

# From dictionaries
data = [
    {"name": "Alice", "role": "Engineer", "salary": 85000},
    {"name": "Bob", "role": "Designer", "salary": 75000}
]

table = TableData.from_dicts(data)
markdown = table.to_md()
print(markdown)
# | name  | role     | salary |
# | ----- | -------- | ------ |
# | Alice | Engineer | 85000  |
# | Bob   | Designer | 75000  |

API Reference

Core Classes

  • BaseProvider - Abstract base for all data providers
  • Context - Abstract base for prompt contexts
  • ToolContext - Documents functions for LLM consumption
  • PromptSection - Composable prompt sections
  • BasePrompt - Full prompt composition

Concrete Providers

  • FileDataProvider - Read text files
  • CsvDataProvider - Read CSV files as markdown tables
  • SqliteProvider - Execute SQL queries as markdown tables

Utilities

  • TableData - Convert various formats to markdown tables
  • to_markdown_table() - Low-level table formatting

Why Object-Oriented Prompts?

Better Organization

# Instead of managing giant prompt strings
SYSTEM_PROMPT = """You are an assistant..."""
DATA_SECTION = """Here is the data: {data}"""
TOOL_SECTION = """Available tools: {tools}"""

# Compose from organized, testable objects
prompt = ChatPrompt(
    SystemSection("You are an assistant..."),
    DataSection(providers=[csv_provider, db_provider]),
    ToolSection(tools=[calculator, parser])
)

Easier Testing

# Test individual components
def test_csv_provider():
    provider = CsvDataProvider("test.csv")
    result = provider.run()
    assert "| Name |" in result

def test_tool_context():
    ctx = ToolContext(my_function)
    assert "my_function" in ctx.render()

Reusable Components

# Define once, use everywhere
analysis_section = DataAnalysisSection(
    providers=[CsvDataProvider("metrics.csv")]
)

# Reuse in different prompts
customer_prompt = CustomerPrompt(analysis_section, ...)
admin_prompt = AdminPrompt(analysis_section, ...)

Contributing

Coming soon

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

proommpt-0.1.0.tar.gz (15.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

proommpt-0.1.0-py3-none-any.whl (13.3 kB view details)

Uploaded Python 3

File details

Details for the file proommpt-0.1.0.tar.gz.

File metadata

  • Download URL: proommpt-0.1.0.tar.gz
  • Upload date:
  • Size: 15.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.13

File hashes

Hashes for proommpt-0.1.0.tar.gz
Algorithm Hash digest
SHA256 8d4a56e487fa390f39cf578ed775413fc2c13bc17a4ac58d935b95ee8b409ec5
MD5 1bdf7118a5a737c6f188a1bc375581dd
BLAKE2b-256 9a5767601426ca2d6da381dcffcb734ab219f37a07b61a512b64338ae034fe94

See more details on using hashes here.

File details

Details for the file proommpt-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: proommpt-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 13.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.13

File hashes

Hashes for proommpt-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7f7c224b842ccd8ece49ea4429023e052776a0734073ccf2fc9d72a9eed24360
MD5 ff2df67fc054617e39d15cc1a0598906
BLAKE2b-256 092961b5f722601d6751c9c5390509c514716f52c4a04dcf63e0580721a9931e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page