Skip to content

Commit

Permalink
add pydantic_ai_examples to sdist and wheel, and examples CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelcolvin committed Nov 3, 2024
1 parent 566678a commit 48be7f4
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 33 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
enable-cache: true

- name: Install dependencies
run: uv sync --python 3.12 --frozen --group examples
run: uv sync --python 3.12 --frozen --all-extras

- uses: pre-commit/action@v3.0.0
with:
Expand Down
5 changes: 4 additions & 1 deletion pydantic_ai/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from importlib.metadata import version

from .agent import Agent
from .shared import AgentError, CallContext, ModelRetry, UnexpectedModelBehaviour, UserError

__all__ = 'Agent', 'AgentError', 'CallContext', 'ModelRetry', 'UnexpectedModelBehaviour', 'UserError'
__all__ = 'Agent', 'AgentError', 'CallContext', 'ModelRetry', 'UnexpectedModelBehaviour', 'UserError', '__version__'
__version__ = version('pydantic_ai')
38 changes: 28 additions & 10 deletions examples/README.md → pydantic_ai_examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,28 @@ Examples of how to use Pydantic AI and what it can do.

## Usage

These examples are distributed with `pydantic-ai` so you can run them either by cloning the [pydantic-ai repo](https://github.com/pydantic/pydantic-ai) or by simply installing `pydantic-ai` from PyPI with `pip` or `uv`.

Either way you'll need to install extra dependencies to run some examples, you just need to install the `examples` optional dependency group.

If you've cloned the repo, add the extra dependencies with:

```bash
uv sync --extra examples
```

If you've installed `pydantic-ai` via pip/uv, you can install the extra dependencies with:

```bash
pip install 'pydantic-ai[examples]'
# of if you're using uv
uv add 'pydantic-ai[examples]'
```

To run the examples, run:

```bash
uv run -m examples.<example_module_name>
uv run -m pydantic_ai_examples.<example_module_name>
```

## Examples
Expand All @@ -19,17 +37,17 @@ uv run -m examples.<example_module_name>
Simple example of using Pydantic AI to construct a Pydantic model from a text input.

```bash
uv run --group examples -m examples.pydantic_model
uv run --extra examples -m pydantic_ai_examples.pydantic_model
```

This examples uses `openai:gpt-4o` by default but it works well with other models, e.g. you can run it
This examples uses `openai:gpt-4o` by default, but it works well with other models, e.g. you can run it
with Gemini using:

```bash
PYDANTIC_AI_MODEL=gemini-1.5-pro uv run --group examples -m examples.pydantic_model
PYDANTIC_AI_MODEL=gemini-1.5-pro uv run --extra examples -m pydantic_ai_examples.pydantic_model
```

(or `PYDANTIC_AI_MODEL=gemini-1.5-flash...`)
(or `PYDANTIC_AI_MODEL=gemini-1.5-flash ...`)

### `sql_gen.py`

Expand All @@ -38,13 +56,13 @@ PYDANTIC_AI_MODEL=gemini-1.5-pro uv run --group examples -m examples.pydantic_mo
Example demonstrating how to use Pydantic AI to generate SQL queries based on user input.

```bash
uv run --group examples -m examples.sql_gen
uv run --extra examples -m pydantic_ai_examples.sql_gen
```

or to use a custom prompt:

```bash
uv run --group examples -m examples.sql_gen "find me whatever"
uv run --extra examples -m pydantic_ai_examples.sql_gen "find me whatever"
```

This model uses `gemini-1.5-flash` by default since Gemini is good at single shot queries.
Expand All @@ -66,7 +84,7 @@ To run this example properly, you'll need two extra API keys:
**(Note if either key is missing, the code will fall back to dummy data.)**

```bash
uv run --group examples -m examples.weather
uv run --extra examples -m pydantic_ai_examples.weather
```

This example uses `openai:gpt-4o` by default. Gemini seems to be unable to handle the multiple tool
Expand Down Expand Up @@ -97,13 +115,13 @@ We also mount the postgresql `data` directory locally to persist the data if you
With that running, we can build the search database with (**WARNING**: this requires the `OPENAI_API_KEY` env variable and will calling the OpenAI embedding API around 300 times to generate embeddings for each section of the documentation):

```bash
uv run --group examples -m examples.rag build
uv run --extra examples -m pydantic_ai_examples.rag build
```

(Note building the database doesn't use Pydantic AI right now, instead it uses the OpenAI SDK directly.)

You can then ask the agent a question with:

```bash
uv run --group examples -m examples.rag search "How do I configure logfire to work with FastAPI?"
uv run --extra examples -m pydantic_ai_examples.rag search "How do I configure logfire to work with FastAPI?"
```
69 changes: 69 additions & 0 deletions pydantic_ai_examples/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"""Very simply CLI to aid in running the examples, and for copying examples code to a new directory."""
import argparse
import os
import re
import sys
from pathlib import Path


def cli():
this_dir = Path(__file__).parent

parser = argparse.ArgumentParser(prog='pydantic_ai_examples', description=get_description(this_dir), formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('-v', '--version', action='store_true', help='show the version and exit')
parser.add_argument('--copy-to', dest='DEST', help='Copy all examples to a new directory')

args = parser.parse_args()
if args.version:
from pydantic_ai import __version__

print(f'pydantic_ai v{__version__}')
elif args.DEST:
copy_to(this_dir, Path(args.DEST))
else:
parser.print_help()


def get_description(this_dir: Path) -> str:
description = f"""\
{__doc__}
The following examples are available:
(you might need to prefix the command you run with `uv run` or similar depending on your environment)
"""
for file in this_dir.glob('*.py'):
if file.name == '__main__.py':
continue
file_descr = re.match(r'"""(.+)', file.read_text())
if file_descr:
description += f"""
## {file.name}
{file_descr.group(1).strip()}
python -m {this_dir.name}.{file.stem}
"""

return description


def copy_to(this_dir: Path, dst: Path):
if dst.exists():
print(f'Error: destination path "{dst}" already exists', file=sys.stderr)
sys.exit(1)

dst.mkdir(parents=True)

count = 0
for file in this_dir.glob('*.*'):
with open(file, 'rb') as src:
with open(dst / file.name, 'wb') as dst:
dst.write(src.read())
count += 1

print(f'Copied {count} example files to "{dst}"')


if __name__ == '__main__':
cli()
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Run with:
uv run --group examples -m examples.pydantic_model
uv run -m pydantic_ai_examples.pydantic_model
"""

import os
Expand Down
8 changes: 4 additions & 4 deletions examples/rag.py → pydantic_ai_examples/rag.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""RAG example with pydantic-ai.
"""RAG example with pydantic-ai — using vector search to augment a chat agent.
Run pgvector with:
Expand All @@ -10,11 +10,11 @@
Build the search DB with:
uv run --group examples -m examples.rag build
uv run -m pydantic_ai_examples.rag build
Ask the agent a question with:
uv run --group examples -m examples.rag search "How do I configure logfire to work with FastAPI?"
uv run -m pydantic_ai_examples.rag search "How do I configure logfire to work with FastAPI?"
"""

from __future__ import annotations as _annotations
Expand Down Expand Up @@ -226,5 +226,5 @@ def slugify(value: str, separator: str, unicode: bool = False) -> str:
q = 'How do I configure logfire to work with FastAPI?'
asyncio.run(run_agent(q))
else:
print('uv run --group examples -m examples.rag build|search', file=sys.stderr)
print('uv run --extra examples -m pydantic_ai_examples.rag build|search', file=sys.stderr)
sys.exit(1)
2 changes: 1 addition & 1 deletion examples/sql_gen.py → pydantic_ai_examples/sql_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Run with:
uv run --group examples -m examples.sql_gen "show me logs from yesterday, with level 'error'"
uv run -m pydantic_ai_examples.sql_gen "show me logs from yesterday, with level 'error'"
"""

import asyncio
Expand Down
2 changes: 1 addition & 1 deletion examples/weather.py → pydantic_ai_examples/weather.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
Run with:
uv run --group examples -m examples.weather
uv run -m pydantic_ai_examples.weather
"""

from __future__ import annotations as _annotations
Expand Down
12 changes: 6 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ dependencies = [
logfire = [
"logfire>=1.2.0",
]
examples = [
"asyncpg>=0.30.0",
"logfire[asyncpg]>=1.2.0",
]

[dependency-groups]
dev = [
Expand All @@ -60,16 +64,12 @@ dev = [
"devtools>=0.12.2",
"anyio>=4.5.0",
]
examples = [
"asyncpg>=0.30.0",
"logfire[asyncpg]>=1.2.0",
]

[tool.hatch.build.targets.wheel]
packages = ["pydantic_ai"]
packages = ["pydantic_ai", "pydantic_ai_examples"]

[tool.hatch.build.targets.sdist]
include = ["/README.md", "/Makefile", "/pydantic_ai", "/tests"]
include = ["/README.md", "/Makefile", "/pydantic_ai", "/pydantic_ai_examples", "/tests"]

[tool.ruff]
line-length = 120
Expand Down
14 changes: 6 additions & 8 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 48be7f4

Please sign in to comment.