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 providersContext- Abstract base for prompt contextsToolContext- Documents functions for LLM consumptionPromptSection- Composable prompt sectionsBasePrompt- Full prompt composition
Concrete Providers
FileDataProvider- Read text filesCsvDataProvider- Read CSV files as markdown tablesSqliteProvider- Execute SQL queries as markdown tables
Utilities
TableData- Convert various formats to markdown tablesto_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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8d4a56e487fa390f39cf578ed775413fc2c13bc17a4ac58d935b95ee8b409ec5
|
|
| MD5 |
1bdf7118a5a737c6f188a1bc375581dd
|
|
| BLAKE2b-256 |
9a5767601426ca2d6da381dcffcb734ab219f37a07b61a512b64338ae034fe94
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7f7c224b842ccd8ece49ea4429023e052776a0734073ccf2fc9d72a9eed24360
|
|
| MD5 |
ff2df67fc054617e39d15cc1a0598906
|
|
| BLAKE2b-256 |
092961b5f722601d6751c9c5390509c514716f52c4a04dcf63e0580721a9931e
|