Skip to content
Merged
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
49 changes: 34 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,15 +155,11 @@ jobs:
needs: [ci-scope]
if: needs.ci-scope.outputs.ci_required == 'true'
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.python-version == '3.15' }}
strategy:
# fail-fast: true — matrix dimension is Python version only.
# sqlspec failures are typically version-agnostic library bugs, so the
# other 4 jobs running to completion after one fails wastes ~60 min of
# billed runner time. test-build.yml gates package builds behind these
# checks before spending runner minutes on wheel matrices.
fail-fast: true
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
python-version: ["3.11", "3.12", "3.13", "3.14", "3.15"]
timeout-minutes: 15
steps:
- name: Check out repository
Expand All @@ -189,12 +185,22 @@ jobs:
venv-unit-${{ runner.os }}-py${{ matrix.python-version }}-

- name: Install dependencies
id: install-deps
continue-on-error: ${{ matrix.python-version == '3.15' }}
# tests/unit/ imports every adapter module, so the install set is
# the same as integration. Speed comes from skipping Docker
# pre-pull and running only tests/unit/, not from a lighter sync.
run: uv sync --all-extras --dev
run: |
if [ "${{ matrix.python-version }}" = "3.15" ]; then
uv sync --all-extras --dev || uv sync --all-extras --no-extra mssql-python --dev
else
uv sync --all-extras --dev
fi

- name: Test
id: pytest
if: steps.install-deps.outcome == 'success'
continue-on-error: ${{ matrix.python-version == '3.15' }}
# covdefaults sets fail_under=100 globally; the per-tier run only
# covers a slice of sqlspec, so override to 0 here. The combined
# view in Codecov is the source of truth.
Expand All @@ -205,7 +211,7 @@ jobs:
--cov-fail-under=0

- name: Upload coverage to Codecov
if: always()
if: always() && steps.pytest.outcome == 'success'
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
with:
files: coverage-unit.xml
Expand Down Expand Up @@ -250,10 +256,11 @@ jobs:
needs: [ci-scope, test-unit]
if: needs.ci-scope.outputs.ci_required == 'true'
runs-on: ubuntu-24.04
continue-on-error: ${{ matrix.python-version == '3.15' }}
strategy:
fail-fast: true
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
python-version: ["3.11", "3.12", "3.13", "3.14", "3.15"]
timeout-minutes: 60
steps:
- name: Check out repository
Expand All @@ -279,9 +286,17 @@ jobs:
venv-integration-${{ runner.os }}-py${{ matrix.python-version }}-

- name: Install dependencies
run: uv sync --all-extras --dev
id: install-deps
continue-on-error: ${{ matrix.python-version == '3.15' }}
run: |
if [ "${{ matrix.python-version }}" = "3.15" ]; then
uv sync --all-extras --dev || uv sync --all-extras --no-extra mssql-python --dev
else
uv sync --all-extras --dev
fi

- name: Free runner disk before docker work
if: steps.install-deps.outcome == 'success'
run: |
set -eu
df -h /
Expand All @@ -305,6 +320,7 @@ jobs:
df -h /

- name: Install SQL Server ODBC driver
if: steps.install-deps.outcome == 'success'
run: |
set -eu
key_url="https://packages.microsoft.com/keys/microsoft.asc"
Expand Down Expand Up @@ -339,19 +355,20 @@ jobs:

- name: Cache docker images
id: docker-image-cache
if: steps.install-deps.outcome == 'success'
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: /tmp/docker-images
key: docker-images-v2-${{ hashFiles('.github/workflows/ci.yml') }}

- name: Load cached docker images
if: steps.docker-image-cache.outputs.cache-hit == 'true'
if: steps.install-deps.outcome == 'success' && steps.docker-image-cache.outputs.cache-hit == 'true'
run: |
docker load -i /tmp/docker-images/sqlspec-test-images.tar
rm -f /tmp/docker-images/sqlspec-test-images.tar

- name: Pre-pull docker images
if: steps.docker-image-cache.outputs.cache-hit != 'true'
if: steps.install-deps.outcome == 'success' && steps.docker-image-cache.outputs.cache-hit != 'true'
run: |
set -eu
images=(
Expand Down Expand Up @@ -386,6 +403,8 @@ jobs:

- name: Test
id: pytest
if: steps.install-deps.outcome == 'success'
continue-on-error: ${{ matrix.python-version == '3.15' }}
env:
PYTHONFAULTHANDLER: "1"
PYTEST_ADDOPTS: "--max-worker-restart=0"
Expand Down Expand Up @@ -446,7 +465,7 @@ jobs:
exit $rc

- name: Upload coverage to Codecov
if: always() && steps.pytest.outcome != 'skipped'
if: always() && steps.pytest.outcome == 'success'
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
with:
files: coverage-integration.xml
Expand Down
8 changes: 5 additions & 3 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,12 @@ jobs:
build-wheels-mypyc:
name: Build MyPyC wheels (${{ matrix.os }} py${{ matrix.python-version }})
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.python-version == '3.15' }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, ubuntu-24.04-arm, macos-latest, windows-latest]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
python-version: ["3.11", "3.12", "3.13", "3.14", "3.15"]
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand Down Expand Up @@ -116,7 +117,7 @@ jobs:
- name: Build wheels with cibuildwheel
run: python -m cibuildwheel --output-dir wheelhouse
env:
CIBW_BUILD: "cp${{ matrix.python-version == '3.10' && '310' || matrix.python-version == '3.11' && '311' || matrix.python-version == '3.12' && '312' || matrix.python-version == '3.13' && '313' || matrix.python-version == '3.14' && '314' }}-*"
CIBW_BUILD: "cp${{ matrix.python-version == '3.11' && '311' || matrix.python-version == '3.12' && '312' || matrix.python-version == '3.13' && '313' || matrix.python-version == '3.14' && '314' || matrix.python-version == '3.15' && '315' }}-*"
CIBW_BUILD_VERBOSITY: 1

# Native host arch only — Linux aarch64 builds on ubuntu-24.04-arm,
Expand Down Expand Up @@ -187,11 +188,12 @@ jobs:
test-wheels:
name: Test ${{ matrix.os }} py${{ matrix.python-version }}
needs: [build-wheels-standard, build-wheels-mypyc]
continue-on-error: ${{ matrix.python-version == '3.15' }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-latest]
python-version: ["3.10", "3.12", "3.14"]
python-version: ["3.11", "3.13", "3.14", "3.15"]

runs-on: ${{ matrix.os }}
steps:
Expand Down
11 changes: 6 additions & 5 deletions .github/workflows/test-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ on:
default: '3.12'
type: choice
options:
- '3.10'
- '3.11'
- '3.12'
- '3.13'
- '3.14'
- '3.15'
pull_request:
paths:
- '.github/workflows/test-build.yml'
Expand Down Expand Up @@ -105,7 +105,6 @@ jobs:
REPOSITORY: ${{ github.repository }}
REQUIRED_CHECKS: |
quality
test-unit (3.10)
test-unit (3.11)
test-unit (3.12)
test-unit (3.13)
Expand Down Expand Up @@ -231,8 +230,9 @@ jobs:
name: Build MyPyC wheels (${{ matrix.os }} py${{ matrix.python-version }})
runs-on: ${{ matrix.os }}
needs: [detect-mode, wait-for-cheap-ci]
continue-on-error: ${{ matrix.python-version == '3.15' }}
strategy:
fail-fast: true
fail-fast: false
matrix:
os: ${{ needs.detect-mode.outputs.matrix_mode == 'full' && fromJSON('["ubuntu-latest", "macos-latest", "windows-latest"]') || fromJSON('["ubuntu-latest"]') }}
python-version:
Expand Down Expand Up @@ -299,7 +299,7 @@ jobs:
- name: Build wheels with cibuildwheel
run: python -m cibuildwheel --output-dir wheelhouse
env:
CIBW_BUILD: "cp${{ matrix.python-version == '3.10' && '310' || matrix.python-version == '3.11' && '311' || matrix.python-version == '3.12' && '312' || matrix.python-version == '3.13' && '313' || matrix.python-version == '3.14' && '314' }}-*"
CIBW_BUILD: "cp${{ matrix.python-version == '3.11' && '311' || matrix.python-version == '3.12' && '312' || matrix.python-version == '3.13' && '313' || matrix.python-version == '3.14' && '314' || matrix.python-version == '3.15' && '315' }}-*"
CIBW_BUILD_VERBOSITY: 1

# PR validation builds host arch only — release covers full cross-arch matrix.
Expand Down Expand Up @@ -358,8 +358,9 @@ jobs:
test-wheels:
name: Test ${{ matrix.os }} py${{ matrix.python-version }}
needs: [build-wheels-standard, build-wheels-mypyc, detect-mode]
continue-on-error: ${{ matrix.python-version == '3.15' }}
strategy:
fail-fast: true
fail-fast: false
matrix:
os: ${{ needs.detect-mode.outputs.matrix_mode == 'full' && fromJSON('["ubuntu-latest", "windows-latest", "macos-latest"]') || fromJSON('["ubuntu-latest"]') }}
python-version:
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@ install-uv: ## Install latest version of
.PHONY: install
install: destroy clean ## Install the project and dependencies
@echo "${INFO} Starting fresh installation..."
@uv python pin 3.10 >/dev/null 2>&1
@uv python pin 3.11 >/dev/null 2>&1
@uv venv >/dev/null 2>&1
@uv sync --all-extras --no-extra mypyc --dev
@echo "${OK} Installation complete! 🎉"

.PHONY: install-compiled
install-compiled: destroy clean ## Install with mypyc compilation for performance
@echo "${INFO} Starting fresh installation with mypyc compilation..."
@uv python pin 3.10 >/dev/null 2>&1
@uv python pin 3.11 >/dev/null 2>&1
@uv venv >/dev/null 2>&1
@echo "${INFO} Installing in editable mode with mypyc compilation..."
@uv sync --all-extras --dev
Expand Down
4 changes: 2 additions & 2 deletions docs/examples/extensions/adk/memory_store.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from datetime import datetime, timezone
from datetime import UTC, datetime
from typing import TYPE_CHECKING

import anyio
Expand Down Expand Up @@ -37,7 +37,7 @@ async def _run() -> "list[StoredEvent]":
invocation_id="inv_1",
author="user",
content=types.Content(parts=[types.Part(text="Hello")]),
timestamp=datetime.now(timezone.utc).timestamp(),
timestamp=datetime.now(UTC).timestamp(),
)
event_record = event_to_record(event, session["app_name"], session["user_id"], session["id"])
await store.append_event(event_record)
Expand Down
6 changes: 3 additions & 3 deletions docs/examples/extensions/adk/tool_integration.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from datetime import datetime, timezone
from datetime import UTC, datetime

import anyio
import pytest
Expand Down Expand Up @@ -30,11 +30,11 @@ async def _run() -> int:
"scope": "user",
"event_id": "evt_1",
"author": "tool",
"timestamp": datetime.now(timezone.utc),
"timestamp": datetime.now(UTC),
"content_json": {"tool": "search", "query": "sqlspec"},
"content_text": "tool:search query=sqlspec",
"metadata_json": None,
"inserted_at": datetime.now(timezone.utc),
"inserted_at": datetime.now(UTC),
"embedding": None,
}
await store.insert_memory_entries([record])
Expand Down
2 changes: 1 addition & 1 deletion docs/releases.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ CI/CD Publishing Pipeline
When a GitHub Release is published, ``.github/workflows/publish.yml`` automatically executes:

1. **Standard Distributions**: Builds standard source distribution (``sdist``) and pure Python wheel packages.
2. **Compiled Mypyc Wheels**: Compiles high-performance C-extensions via `hatch-mypyc` across a matrix of operating systems (Linux, macOS, Windows) and Python versions (3.10 through 3.14).
2. **Compiled Mypyc Wheels**: Compiles high-performance C-extensions via `hatch-mypyc` across a matrix of operating systems (Linux, macOS, Windows) and Python versions (3.11 through 3.14, with experimental 3.15 builds).
3. **Profile-Guided Optimization (PGO)**: Compiles Linux binary wheels using execution profile data (GCC) to optimize critical statement translation and dispatch paths. macOS and Windows use standard mypyc C-extension compilation.
4. **Smoke Testing**: Validates binary wheel imports across supported architectures before publishing to `PyPI <https://pypi.org/project/sqlspec/>`_.

Expand Down
2 changes: 1 addition & 1 deletion docs/usage/frameworks/litestar/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ Install SQLSpec with the Litestar extra and a database adapter.
Requirements
------------

- **Python 3.10+**
- **Python 3.11+**
- **Litestar 2.23+**
- A compatible database adapter (async recommended for web request concurrency)

Expand Down
15 changes: 7 additions & 8 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ authors = [{ name = "Cody Fincher", email = "cody@litestar.dev" }]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3.15",
"Programming Language :: Python :: 3 :: Only",
"Typing :: Typed",
]
Expand All @@ -16,14 +16,13 @@ dependencies = [
"sqlglot>=30.13.0",
"mypy-extensions",
"rich-click>=1.9.0",
"tomli>=2.0.0; python_version < '3.11'",
]
description = "SQL Experiments in Python"
license = "MIT"
maintainers = [{ name = "Litestar Developers", email = "hello@litestar.dev" }]
name = "sqlspec"
readme = "README.md"
requires-python = ">=3.10, <4.0"
requires-python = ">=3.11, <4.0"
version = "0.66.0"

[project.urls]
Expand Down Expand Up @@ -131,7 +130,6 @@ lint = [
"asyncpg-stubs",
"pyarrow-stubs",
"pandas-stubs<3",
"tomli>=2.0.0",
"types-PyMySQL",
]
test = [
Expand Down Expand Up @@ -500,7 +498,7 @@ allow_redefinition = false
exclude = ["tmp/", ".tmp/", ".bugs/"]
local_partial_types = true
packages = ["sqlspec", "tests"]
python_version = "3.10"
python_version = "3.11"
strict_bytes = true

disallow_any_generics = false
Expand Down Expand Up @@ -561,7 +559,7 @@ module = "tests.*"
disableBytesTypePromotions = true
exclude = ["**/node_modules", "**/__pycache__", ".venv", "tools", "docs", "tmp", ".tmp", ".bugs", "**/.*"]
include = ["sqlspec", "tests"]
pythonVersion = "3.10"
pythonVersion = "3.11"
reportMissingTypeStubs = false
reportPrivateImportUsage = false
reportPrivateUsage = false
Expand All @@ -577,7 +575,7 @@ strict-imports = false
exclude = [".venv", "node_modules", "tmp", ".tmp", ".bugs"]
line-length = 120
src = ["sqlspec", "tests", "docs/examples", "tools"]
target-version = "py310"
target-version = "py311"

[tool.ruff.format]
docstring-code-format = true
Expand Down Expand Up @@ -648,6 +646,7 @@ ignore = [
"PLW0108", # Replace lambda expression with a def
"RUF067", # ruff - init should only have import statements
"PLW0717", # too many statements in try block
"ASYNC109", # async function definition with a `timeout` parameter
]
preview = true
select = ["ALL"]
Expand Down Expand Up @@ -719,4 +718,4 @@ split-on-trailing-comma = false
ban-relative-imports = "all"

[tool.ruff.lint.flake8-tidy-imports.banned-api]
"__future__.annotations" = { msg = "Use Python 3.10+ PEP 604 annotations instead of from __future__ import annotations" }
"__future__.annotations" = { msg = "Use Python 3.11+ PEP 604 annotations instead of from __future__ import annotations" }
4 changes: 2 additions & 2 deletions sqlspec/_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
from collections.abc import Iterable, Mapping
from dataclasses import dataclass
from enum import Enum
from typing import TYPE_CHECKING, Any, ClassVar, Final, Literal, Protocol, cast, runtime_checkable
from typing import TYPE_CHECKING, Any, ClassVar, Final, Literal, Protocol, Self, cast, runtime_checkable

from typing_extensions import Self, TypeVar, dataclass_transform
from typing_extensions import TypeVar, dataclass_transform

from sqlspec.utils.module_loader import (
dependency_flag,
Expand Down
Loading
Loading