Skip to content

Commit b593dd4

Browse files
authored
feat: add comprehensive tests, examples, and documentation (#2)
- Add examples directory with practical usage examples: - basic_usage.py: Loading packs, templates, and formatting - tools_example.py: Tool conversion and LangChain integration - validation_example.py: Output validation with various validators - Example PromptPack JSON files (customer-support, sales-assistant) - Add comprehensive unit tests: - test_multimodal.py: 19 tests for multimodal content conversion - Enhanced test_template.py: Model overrides, defaults, async support - Enhanced test_validators.py: Multiple validators, edge cases - Update CI pipeline (.github/workflows/ci.yml): - Add Python 3.13 to test matrix - Add linting for examples directory - Add coverage reporting with Codecov - Add examples verification job - Update documentation (Astro/Starlight): - Add Examples section with 4 detailed guides - Update quickstart with validation examples - Add Output Validation feature card - Configure ruff to allow print statements in examples Test count: 131 tests (60 promptpack + 71 promptpack-langchain)
1 parent f641808 commit b593dd4

18 files changed

Lines changed: 2183 additions & 60 deletions

File tree

.github/workflows/ci.yml

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,53 @@ on:
77
branches: [main]
88

99
jobs:
10+
lint:
11+
name: Lint
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
- name: Set up Python
17+
uses: actions/setup-python@v5
18+
with:
19+
python-version: "3.12"
20+
21+
- name: Install linting tools
22+
run: |
23+
python -m pip install --upgrade pip
24+
pip install ruff mypy
25+
26+
- name: Install packages for type checking
27+
run: |
28+
pip install pydantic langchain-core
29+
cd packages/promptpack && pip install -e .
30+
cd ../promptpack-langchain && pip install -e .
31+
32+
- name: Run ruff linter on packages
33+
run: ruff check packages/
34+
35+
- name: Run ruff linter on examples
36+
run: ruff check examples/
37+
38+
- name: Run ruff formatter check on packages
39+
run: ruff format --check packages/
40+
41+
- name: Run ruff formatter check on examples
42+
run: ruff format --check examples/
43+
44+
- name: Run mypy on promptpack
45+
run: mypy packages/promptpack/src/promptpack --ignore-missing-imports
46+
47+
- name: Run mypy on promptpack-langchain
48+
run: mypy packages/promptpack-langchain/src/promptpack_langchain --ignore-missing-imports
49+
1050
test:
51+
name: Test (Python ${{ matrix.python-version }})
1152
runs-on: ubuntu-latest
1253
strategy:
1354
fail-fast: false
1455
matrix:
15-
python-version: ["3.10", "3.11", "3.12"]
56+
python-version: ["3.10", "3.11", "3.12", "3.13"]
1657

1758
steps:
1859
- uses: actions/checkout@v4
@@ -25,7 +66,7 @@ jobs:
2566
- name: Install dependencies
2667
run: |
2768
python -m pip install --upgrade pip
28-
pip install hatch
69+
pip install pytest pytest-asyncio pytest-cov
2970
3071
- name: Install promptpack package
3172
run: |
@@ -40,14 +81,22 @@ jobs:
4081
- name: Run promptpack tests
4182
run: |
4283
cd packages/promptpack
43-
pytest tests/ -v --tb=short
84+
pytest tests/ -v --tb=short --cov=src/promptpack --cov-report=xml:coverage-promptpack.xml
4485
4586
- name: Run promptpack-langchain tests
4687
run: |
4788
cd packages/promptpack-langchain
48-
pytest tests/ -v --tb=short
89+
pytest tests/ -v --tb=short --cov=src/promptpack_langchain --cov-report=xml:coverage-langchain.xml
4990
50-
lint:
91+
- name: Upload coverage reports
92+
uses: codecov/codecov-action@v4
93+
if: matrix.python-version == '3.12'
94+
with:
95+
files: packages/promptpack/coverage-promptpack.xml,packages/promptpack-langchain/coverage-langchain.xml
96+
fail_ci_if_error: false
97+
98+
examples:
99+
name: Verify Examples
51100
runs-on: ubuntu-latest
52101
steps:
53102
- uses: actions/checkout@v4
@@ -57,25 +106,21 @@ jobs:
57106
with:
58107
python-version: "3.12"
59108

60-
- name: Install linting tools
109+
- name: Install dependencies
61110
run: |
62111
python -m pip install --upgrade pip
63-
pip install ruff mypy
112+
pip install pytest
64113
65-
- name: Install packages for type checking
114+
- name: Install packages
66115
run: |
67-
pip install pydantic langchain-core
68116
cd packages/promptpack && pip install -e .
69117
cd ../promptpack-langchain && pip install -e .
70118
71-
- name: Run ruff linter
72-
run: ruff check packages/
73-
74-
- name: Run ruff formatter check
75-
run: ruff format --check packages/
119+
- name: Run basic_usage example
120+
run: python examples/basic_usage.py
76121

77-
- name: Run mypy on promptpack
78-
run: mypy packages/promptpack/src/promptpack --ignore-missing-imports
122+
- name: Run tools_example
123+
run: python examples/tools_example.py
79124

80-
- name: Run mypy on promptpack-langchain
81-
run: mypy packages/promptpack-langchain/src/promptpack_langchain --ignore-missing-imports
125+
- name: Run validation_example
126+
run: python examples/validation_example.py

docs/astro.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export default defineConfig({
2323
sidebar: [
2424
{ label: 'Getting Started', autogenerate: { directory: 'getting-started' } },
2525
{ label: 'Packages', autogenerate: { directory: 'packages' } },
26+
{ label: 'Examples', autogenerate: { directory: 'examples' } },
2627
{ label: 'API Reference', autogenerate: { directory: 'api' } },
2728
{ label: 'Contributors', autogenerate: { directory: 'contributors' } },
2829
],
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
---
2+
title: Basic Usage
3+
description: Getting started with PromptPack Python
4+
sidebar:
5+
order: 2
6+
---
7+
8+
This example demonstrates the core PromptPack workflow: loading packs, creating templates, and formatting prompts.
9+
10+
## Loading a PromptPack
11+
12+
```python
13+
from pathlib import Path
14+
from promptpack import parse_promptpack
15+
16+
# Load from a file
17+
pack = parse_promptpack("path/to/pack.json")
18+
19+
# Or parse from a string
20+
from promptpack import parse_promptpack_string
21+
22+
pack_json = '{"id": "my-pack", ...}'
23+
pack = parse_promptpack_string(pack_json)
24+
```
25+
26+
## Creating Templates
27+
28+
Use `PromptPackTemplate` to create LangChain-compatible templates:
29+
30+
```python
31+
from promptpack_langchain import PromptPackTemplate
32+
33+
# Create a template from a specific prompt in the pack
34+
template = PromptPackTemplate.from_promptpack(pack, "support")
35+
36+
# Check input variables
37+
print(template.input_variables) # ['role', 'company']
38+
39+
# Get LLM parameters
40+
params = template.get_parameters()
41+
print(params) # {'temperature': 0.7, 'max_tokens': 1500}
42+
```
43+
44+
## Formatting Prompts
45+
46+
Format the template with your variables:
47+
48+
```python
49+
# Format with variables
50+
formatted = template.format(
51+
role="customer support agent",
52+
issue_type="billing"
53+
)
54+
55+
print(formatted)
56+
```
57+
58+
Output:
59+
```
60+
You are a customer support agent assistant for TechCorp.
61+
62+
# Company Context
63+
TechCorp provides cloud infrastructure, SaaS products, and enterprise solutions.
64+
65+
# Your Role
66+
Handle billing customer inquiries effectively.
67+
68+
# Guidelines
69+
Maintain a professional yet friendly tone. Be concise and solution-oriented.
70+
```
71+
72+
## Using Fragments
73+
74+
PromptPacks support reusable fragments that are automatically resolved:
75+
76+
```json
77+
{
78+
"fragments": {
79+
"company_context": "TechCorp provides cloud infrastructure...",
80+
"tone_guidelines": "Maintain a professional yet friendly tone..."
81+
},
82+
"prompts": {
83+
"support": {
84+
"system_template": "{{fragment:company_context}}\n\n{{fragment:tone_guidelines}}"
85+
}
86+
}
87+
}
88+
```
89+
90+
Fragments are resolved automatically when you call `template.format()`.
91+
92+
## Model Overrides
93+
94+
Templates can have model-specific configurations:
95+
96+
```python
97+
# Create template with model-specific overrides
98+
template = PromptPackTemplate.from_promptpack(
99+
pack,
100+
"support",
101+
model_name="gpt-4"
102+
)
103+
104+
# The template and parameters will use GPT-4 specific settings
105+
params = template.get_parameters()
106+
```
107+
108+
## Using with LangChain
109+
110+
Convert to a ChatPromptTemplate for use with LangChain:
111+
112+
```python
113+
from langchain_openai import ChatOpenAI
114+
115+
# Create chat template
116+
chat_template = template.to_chat_prompt_template(
117+
role="support agent",
118+
company="Acme Corp"
119+
)
120+
121+
# Create chain
122+
model = ChatOpenAI(
123+
model="gpt-4o-mini",
124+
temperature=template.get_parameters().get("temperature", 0.7)
125+
)
126+
127+
chain = chat_template | model
128+
129+
# Invoke
130+
response = chain.invoke({
131+
"messages": [("human", "I was charged twice for my subscription")]
132+
})
133+
134+
print(response.content)
135+
```
136+
137+
## Complete Example
138+
139+
Here's the complete `basic_usage.py` example:
140+
141+
```python
142+
#!/usr/bin/env python3
143+
from pathlib import Path
144+
145+
from promptpack import parse_promptpack
146+
from promptpack_langchain import PromptPackTemplate
147+
148+
149+
def main():
150+
# Load PromptPack
151+
pack_path = Path(__file__).parent / "packs" / "customer-support.json"
152+
pack = parse_promptpack(pack_path)
153+
154+
print(f"Loaded pack: {pack.name} (v{pack.version})")
155+
print(f"Available prompts: {list(pack.prompts.keys())}")
156+
157+
# Create template
158+
template = PromptPackTemplate.from_promptpack(pack, "support")
159+
print(f"Input variables: {template.input_variables}")
160+
print(f"Parameters: {template.get_parameters()}")
161+
162+
# Format
163+
formatted = template.format(
164+
role="customer support agent",
165+
issue_type="billing"
166+
)
167+
print(formatted)
168+
169+
170+
if __name__ == "__main__":
171+
main()
172+
```
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
---
2+
title: Examples Overview
3+
description: Learn how to use PromptPack Python through practical examples
4+
sidebar:
5+
order: 1
6+
---
7+
8+
This section contains practical examples demonstrating how to use PromptPack Python in real-world scenarios.
9+
10+
## Available Examples
11+
12+
### [Basic Usage](/promptpack-python/examples/basic-usage/)
13+
Learn the fundamentals of loading PromptPacks, creating templates, and formatting prompts with variables and fragments.
14+
15+
### [Tools Integration](/promptpack-python/examples/tools/)
16+
Discover how to convert PromptPack tools to LangChain format, bind custom handlers, and use tools with agents.
17+
18+
### [Validation](/promptpack-python/examples/validation/)
19+
Explore the validation system including banned words, length limits, and regex pattern matching.
20+
21+
## Running the Examples
22+
23+
All examples are located in the `examples/` directory of the repository. To run them:
24+
25+
```bash
26+
# Clone the repository
27+
git clone https://github.com/AltairaLabs/promptpack-python.git
28+
cd promptpack-python
29+
30+
# Install dependencies
31+
pip install -e packages/promptpack
32+
pip install -e packages/promptpack-langchain
33+
34+
# Run an example
35+
python examples/basic_usage.py
36+
python examples/tools_example.py
37+
python examples/validation_example.py
38+
```
39+
40+
## Example Packs
41+
42+
The examples use PromptPack JSON files located in `examples/packs/`:
43+
44+
- **customer-support.json** - Customer support prompts with fragments, validators, and multiple prompt types
45+
- **sales-assistant.json** - Sales assistant with CRM tools (customer lookup, inventory, orders)

0 commit comments

Comments
 (0)