Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ pypi: clean
check: clean
uv run pytest tests

lint:
uv run ruff check

clean:
rm -rf __pycache__ .pytest_cache dist

Expand Down
23 changes: 11 additions & 12 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ def _(rq):

@app.cell(hide_code=True)
def _():
from typing import Literal

from instructor.batch import BatchJob
from pydantic import BaseModel, Field
from typing import Literal

class EmojiDescription(BaseModel):
terms: list[str] = Field(..., description="List of words/phrases that could fit the emoji. List can be long, around 10 examples.")
Expand Down Expand Up @@ -74,7 +75,7 @@ def _():

@app.cell
def _(cache):
import polars as pl
import polars as pl
from lazylines import LazyLines

pl.DataFrame(
Expand All @@ -92,10 +93,11 @@ def _(cache):
@app.cell(hide_code=True)
def _(mo):
import asyncio
import random
import logging
import random
from typing import Any, Callable, Dict, List, Optional

import tqdm
from typing import List, Dict, Any, Callable, Optional

async def process_with_retry(
func,
Expand Down Expand Up @@ -279,12 +281,13 @@ async def main():
@app.cell
def _():
import inspect
import json
import llm
from typing import TypeVar, get_type_hints
import json
from functools import wraps
from jinja2 import Template
from typing import TypeVar, get_type_hints

import llm
from diskcache import Cache
from jinja2 import Template
return Cache, Template, TypeVar, get_type_hints, inspect, json, llm, wraps


Expand Down Expand Up @@ -318,8 +321,6 @@ def wrapper(*args, **kwargs):
if type_hints.get('return', None):
assert issubclass(type_hints.get('return', None), BaseModel), "Output type must be Pydantic class"

# Create a dictionary of parameter types
param_types = {name: param.default for name, param in signature.parameters.items()}
bound_args = signature.bind(*args, **kwargs)
bound_args.apply_defaults() # Apply default values for missing parameters
all_kwargs = bound_args.arguments
Expand Down Expand Up @@ -383,8 +384,6 @@ async def wrapper(*args, **kwargs):
if type_hints.get('return', None):
assert issubclass(type_hints.get('return', None), BaseModel), "Output type must be Pydantic class"

# Create a dictionary of parameter types
param_types = {name: param.default for name, param in signature.parameters.items()}
bound_args = signature.bind(*args, **kwargs)
bound_args.apply_defaults() # Apply default values for missing parameters
all_kwargs = bound_args.arguments
Expand Down
7 changes: 4 additions & 3 deletions demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ def _(mo):

@app.cell
def _():
from smartfunc import backend
from openai import OpenAI
from dotenv import load_dotenv
from pydantic import BaseModel
from openai import OpenAI
from pydantic import BaseModel

from smartfunc import backend

load_dotenv(".env")

Expand Down
7 changes: 7 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ dependencies = [
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.ruff]
target-version = "py310"
line-length = 88

[tool.ruff.lint]
select = ["F", "I"]

[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
Expand Down
5 changes: 3 additions & 2 deletions smartfunc/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from functools import wraps
from typing import Any, Callable, Optional, Type, Union, List, Dict
from typing import Any, Callable, Optional, Type

from openai import AsyncOpenAI, OpenAI
from pydantic import BaseModel
from openai import OpenAI, AsyncOpenAI


def _disallow_additional_properties(schema: Any) -> Any:
Expand Down
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Pytest fixtures and mock clients for smartfunc tests."""


import pytest
from typing import Optional


class MockMessage:
Expand Down
11 changes: 6 additions & 5 deletions tests/test_basic.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pytest
from pydantic import BaseModel
from smartfunc import backend, async_backend

from smartfunc import async_backend, backend


class Summary(BaseModel):
Expand Down Expand Up @@ -59,7 +60,7 @@ def test_system_prompt(mock_client_factory):
def generate(prompt: str) -> str:
return prompt

result = generate("test")
generate("test")

assert len(client.calls[0]["messages"]) == 2
assert client.calls[0]["messages"][0]["role"] == "system"
Expand All @@ -75,7 +76,7 @@ def test_extra_kwargs(mock_client_factory):
def generate(prompt: str) -> str:
return prompt

result = generate("test")
generate("test")

assert client.calls[0]["temperature"] == 0.7
assert client.calls[0]["max_tokens"] == 100
Expand Down Expand Up @@ -166,7 +167,7 @@ def test_multiple_arguments(mock_client_factory):
def generate(topic: str, style: str, length: int) -> str:
return f"Write a {length} word {style} piece about {topic}"

result = generate("AI", "formal", 500)
generate("AI", "formal", 500)

content = client.calls[0]["messages"][0]["content"]
assert "Write a 500 word formal piece about AI" in content
Expand All @@ -187,7 +188,7 @@ def smart_generate(items: list[str], include_summary: bool) -> str:

return prompt

result = smart_generate(["apple", "banana"], True)
smart_generate(["apple", "banana"], True)

content = client.calls[0]["messages"][0]["content"]
assert "1. apple" in content
Expand Down
5 changes: 3 additions & 2 deletions tests/test_messages.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pytest
from pydantic import BaseModel
from smartfunc import backend, async_backend

from smartfunc import async_backend, backend


class Summary(BaseModel):
Expand Down Expand Up @@ -46,7 +47,7 @@ def chat() -> list:
{"role": "user", "content": "Hello"},
]

result = chat()
chat()

messages = client.calls[0]["messages"]
assert len(messages) == 2
Expand Down