Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
cbd7023
docs: externalise migration CLI and add psycopg literalinclude
euri10 Nov 4, 2025
31cbf31
put import in tests and correct the lines accordingly
euri10 Nov 4, 2025
5dcc426
lint
euri10 Nov 4, 2025
da7a9ad
more correct lines
euri10 Nov 4, 2025
0ff5c15
delete
euri10 Nov 4, 2025
2d28f08
Revert "delete"
euri10 Nov 4, 2025
2ca1def
add leftovers
euri10 Nov 4, 2025
a6256a6
fix tests, one not passing when using provide_session by bind_key
euri10 Nov 5, 2025
b85c152
linter issues
euri10 Nov 5, 2025
642816a
12
euri10 Nov 5, 2025
5dd81fa
one test per block
euri10 Nov 5, 2025
27364bb
Merge branch 'main' into 173_usage_configuration
euri10 Nov 5, 2025
9c7c689
wrong psygopg note, replaced by correct config
euri10 Nov 5, 2025
e0b1082
Merge branch '173_usage_configuration' of github.com:euri10/sqlspec i…
euri10 Nov 5, 2025
cdca6b3
Merge branch 'main' into 173_usage_configuration
cofin Nov 5, 2025
a65c6cb
Merge branch 'main' into 173_usage_configuration
cofin Nov 5, 2025
f6d748f
Update docs/examples/usage/test_configuration_12.py
euri10 Nov 7, 2025
fffec01
Update docs/examples/usage/test_configuration_13.py
euri10 Nov 7, 2025
91c6d0e
Update docs/examples/usage/test_configuration_19.py
euri10 Nov 7, 2025
6aec1d2
Merge branch 'main' into 173_usage_configuration
cofin Nov 10, 2025
5c5d60d
Merge branch 'main' into 173_usage_configuration
cofin Nov 10, 2025
8d2c24c
Refactor example configurations and tests
cofin Nov 10, 2025
9c75fed
docs: update usage examples and configurations for clarity and consis…
cofin Nov 10, 2025
1774197
docs: improve example clarity by adjusting indentation and adding no-…
cofin Nov 10, 2025
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
25 changes: 25 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,23 @@ When processing user input that may be incomplete or malformed, use a two-tier a

**Implementation Pattern:**

## Recent edit: Configuration examples (2025-11-04)

- Updated docs/examples/usage examples: consolidated example filenames to
docs/examples/usage/test_configuration_*.py and ensured the documentation
references match the renamed examples.
- Added an explicit :lines: range and a :dedent: directive to the
literalinclude for test_configuration_23.py so Sphinx renders the snippet
with correct indentation.
- Built the Sphinx documentation (make docs) and verified HTML output was
generated successfully. Two minor warnings were reported (dedent and a
missing stylesheet copy) but they did not prevent the build.
- Updated project TODOs to reflect completed steps.

This summary documents the small documentation and example maintenance
performed on the configuration usage guide and can be expanded into a
longer changelog entry if desired.

```python
def parse_user_input(content: str, source: str) -> "dict[str, Result]":
"""Parse user input with two-tier error handling.
Expand Down Expand Up @@ -2025,6 +2042,14 @@ class GoodDriverFeatures(TypedDict):

### Compliance Table

### Change log: configuration examples

- Renamed documentation example references to use docs/examples/usage/test_configuration_*.py
- Added explicit :lines: ranges and :dedent: directive for the literalinclude at the top of docs/usage/configuration.rst
- Rebuilt documentation to verify the changes (make docs). Build completed with 2 warnings about dedent and a missing stylesheet; output HTML written to docs/_build/html

### Compliance Table

Current state of all adapters (as of type-cleanup branch):

| Adapter | TypedDict | Auto-Detect | enable_ Prefix | Defaults | Grade | Notes |
Expand Down
12 changes: 6 additions & 6 deletions docs/examples/quickstart/quickstart_1.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
from sqlspec import SQLSpec
from sqlspec.adapters.sqlite import SqliteConfig

__all__ = ("test_quickstart_1",)


def test_quickstart_1() -> None:
# Create SQLSpec instance and configure database
# start-example
from sqlspec import SQLSpec
from sqlspec.adapters.sqlite import SqliteConfig

db_manager = SQLSpec()
db = db_manager.add_config(SqliteConfig(pool_config={"database": ":memory:"}))

# Execute a query
with db_manager.provide_session(db) as session:
result = session.execute("SELECT 'Hello, SQLSpec!' as message")
print(result.get_first()) # {'message': 'Hello, SQLSpec!'}
print(result.get_first())
# end-example

assert result.get_first() == {"message": "Hello, SQLSpec!"}
26 changes: 12 additions & 14 deletions docs/examples/quickstart/quickstart_2.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,42 @@
from sqlspec import SQLSpec
from sqlspec.adapters.sqlite import SqliteConfig

__all__ = ("test_quickstart_2",)


def test_quickstart_2() -> None:
# start-example
from sqlspec import SQLSpec
from sqlspec.adapters.sqlite import SqliteConfig

db_manager = SQLSpec()
db = db_manager.add_config(SqliteConfig(pool_config={"database": ":memory:"}))

with db_manager.provide_session(db) as session:
# Create a table
_ = session.execute("""
_ = session.execute(
"""
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL
)
""")
"""
)

# Insert data
_ = session.execute("INSERT INTO users (name, email) VALUES (?, ?)", "Alice", "alice@example.com")

# Insert multiple rows
_ = session.execute_many(
"INSERT INTO users (name, email) VALUES (?, ?)",
[("Bob", "bob@example.com"), ("Charlie", "charlie@example.com")],
)

# Query all users
users = session.select("SELECT * FROM users")
print(f"All users: {users}")

# Query single user
alice = session.select_one("SELECT * FROM users WHERE name = ?", "Alice")
alice = session.select_one_or_none("SELECT * FROM users WHERE name = ?", "Alice")
print(f"Alice: {alice}")

# Query scalar value
count = session.select_value("SELECT COUNT(*) FROM users")
print(f"Total users: {count}")
# end-example

assert len(users) == 3 # noqa: PLR2004
assert len(users) == 3
assert alice == {"id": 1, "name": "Alice", "email": "alice@example.com"}
assert count == 3 # noqa: PLR2004
assert count == 3
38 changes: 18 additions & 20 deletions docs/examples/quickstart/quickstart_3.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,36 @@
from pydantic import BaseModel
__all__ = ("test_quickstart_3",)

from sqlspec import SQLSpec
from sqlspec.adapters.sqlite import SqliteConfig

__all__ = ("User",)

def test_quickstart_3() -> None:
# start-example
from pydantic import BaseModel

class User(BaseModel):
id: int
name: str
email: str
from sqlspec import SQLSpec
from sqlspec.adapters.sqlite import SqliteConfig

class User(BaseModel):
id: int
name: str
email: str

def test_quickstart_3() -> None:
db_manager = SQLSpec()
db = db_manager.add_config(SqliteConfig(pool_config={"database": ":memory:"}))

with db_manager.provide_session(db) as session:
# Setup
_ = session.execute("""
_ = session.execute(
"""
CREATE TABLE users (id INTEGER, name TEXT, email TEXT)
""")
"""
)
_ = session.execute("INSERT INTO users VALUES (?, ?, ?)", 1, "Alice", "alice@example.com")

# Type-safe query - returns User instance
user = session.select_one("SELECT * FROM users WHERE id = ?", 1, schema_type=User)
print(f"User: {user.name} ({user.email})")

# Now you have type hints and autocomplete!
print(f"User: {user.name} ({user.email})") # IDE knows these fields exist

# Multiple results
all_users = session.select("SELECT * FROM users", schema_type=User)
for u in all_users:
print(f"User: {u.name}") # Each item is a typed User
for typed_user in all_users:
print(f"User: {typed_user.name}")
# end-example

assert user == User(id=1, name="Alice", email="alice@example.com")
assert len(all_users) == 1
Expand Down
42 changes: 21 additions & 21 deletions docs/examples/quickstart/quickstart_4.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
from pydantic import BaseModel
"""Async quickstart example."""

from sqlspec import SQLSpec
from sqlspec.adapters.aiosqlite import AiosqliteConfig
import pytest

__all__ = ("User", "test_quickstart_4")
__all__ = ("test_quickstart_4",)


class User(BaseModel):
id: int
name: str
email: str
@pytest.mark.asyncio
async def test_quickstart_4() -> None:
"""Demonstrate async SQLSpec usage."""
# start-example
from pydantic import BaseModel

from sqlspec import SQLSpec
from sqlspec.adapters.aiosqlite import AiosqliteConfig

class User(BaseModel):
id: int
name: str
email: str

async def test_quickstart_4() -> None:
db_manager = SQLSpec()
db = db_manager.add_config(AiosqliteConfig(pool_config={"database": ":memory:"}))

async with db_manager.provide_session(db) as session:
# Create table
_ = await session.execute("""
await session.execute(
"""
CREATE TABLE users (id INTEGER, name TEXT, email TEXT)
""")

# Insert data
_ = await session.execute("INSERT INTO users VALUES (?, ?, ?)", 1, "Alice", "alice@example.com")

# Type-safe async query
"""
)
await session.execute("INSERT INTO users VALUES (?, ?, ?)", 1, "Alice", "alice@example.com")
user = await session.select_one("SELECT * FROM users WHERE id = ?", 1, schema_type=User)

print(f"User: {user.name}")
# end-example

assert user == User(id=1, name="Alice", email="alice@example.com")
assert isinstance(user, User)
assert user.name == "Alice"
assert user.email == "alice@example.com"
85 changes: 45 additions & 40 deletions docs/examples/quickstart/quickstart_5.py
Original file line number Diff line number Diff line change
@@ -1,53 +1,58 @@
import os
from typing import Any
"""Async PostgreSQL quickstart example."""

from pydantic import BaseModel
import pytest

from sqlspec import SQLSpec
from sqlspec.adapters.asyncpg import AsyncpgConfig
__all__ = ("test_quickstart_5",)

__all__ = ("User", "test_quickstart_5")


class User(BaseModel):
id: int
name: str
email: str


def _pool_config() -> "dict[str, Any]":
return {
"host": os.getenv("SQLSPEC_QUICKSTART_PG_HOST", "localhost"),
"port": int(os.getenv("SQLSPEC_QUICKSTART_PG_PORT", "5432")),
"user": os.getenv("SQLSPEC_QUICKSTART_PG_USER", "postgres"),
"password": os.getenv("SQLSPEC_QUICKSTART_PG_PASSWORD", "postgres"),
"database": os.getenv("SQLSPEC_QUICKSTART_PG_DATABASE", "mydb"),
}


async def _seed_users(session: Any) -> None:
await session.execute(
"""
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL
@pytest.mark.asyncio
async def test_quickstart_5() -> None:
"""Demonstrate async PostgreSQL usage with SQLSpec."""
# start-example
import os
from typing import Any

from pydantic import BaseModel

from sqlspec import SQLSpec
from sqlspec.adapters.asyncpg import AsyncpgConfig

class User(BaseModel):
id: int
name: str
email: str

def pool_config() -> "dict[str, Any]":
return {
"host": os.getenv("SQLSPEC_QUICKSTART_PG_HOST", "localhost"),
"port": int(os.getenv("SQLSPEC_QUICKSTART_PG_PORT", "5432")),
"user": os.getenv("SQLSPEC_QUICKSTART_PG_USER", "postgres"),
"password": os.getenv("SQLSPEC_QUICKSTART_PG_PASSWORD", "postgres"),
"database": os.getenv("SQLSPEC_QUICKSTART_PG_DATABASE", "mydb"),
}

async def seed_users(session: Any) -> None:
await session.execute(
"""
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL
)
"""
)
await session.execute("TRUNCATE TABLE users")
await session.execute(
"INSERT INTO users (id, name, email) VALUES ($1, $2, $3)", 1, "Alice", "alice@example.com"
)
"""
)
await session.execute("TRUNCATE TABLE users")
await session.execute("INSERT INTO users (id, name, email) VALUES ($1, $2, $3)", 1, "Alice", "alice@example.com")


async def test_quickstart_5() -> None:
db_manager = SQLSpec()
db = db_manager.add_config(AsyncpgConfig(pool_config=_pool_config()))
db = db_manager.add_config(AsyncpgConfig(pool_config=pool_config()))

async with db_manager.provide_session(db) as session:
await _seed_users(session)

# PostgreSQL uses $1, $2 for parameters instead of ?
await seed_users(session)
user = await session.select_one("SELECT * FROM users WHERE id = $1", 1, schema_type=User)
print(f"User: {user.name}")
# end-example

assert user == User(id=1, name="Alice", email="alice@example.com")
13 changes: 6 additions & 7 deletions docs/examples/quickstart/quickstart_6.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
from sqlspec import SQLSpec
from sqlspec.adapters.duckdb import DuckDBConfig
from sqlspec.adapters.sqlite import SqliteConfig

__all__ = ("test_quickstart_6",)


def test_quickstart_6() -> None:
db_manager = SQLSpec()
# start-example
from sqlspec import SQLSpec
from sqlspec.adapters.duckdb import DuckDBConfig
from sqlspec.adapters.sqlite import SqliteConfig

# Register multiple databases
db_manager = SQLSpec()
sqlite_db = db_manager.add_config(SqliteConfig(pool_config={"database": "app.db"}))
duckdb_db = db_manager.add_config(DuckDBConfig(pool_config={"database": "analytics.duckdb"}))

# Use different databases
with db_manager.provide_session(sqlite_db) as sqlite_session:
users = sqlite_session.select("SELECT 1")

with db_manager.provide_session(duckdb_db) as duckdb_session:
analytics = duckdb_session.select("SELECT 1")
# end-example

assert isinstance(users, list)
assert isinstance(analytics, list)
Loading