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
39 changes: 36 additions & 3 deletions .github/workflows/test_pull_request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,42 @@ jobs:
- name: Run pre-commit
uses: pre-commit/action@v3.0.1
with:
# Skip the local mypy hook — it requires the project venv with
# torch/transformers installed, which we don't set up in this lint job.
extra_args: --all-files --hook-stage commit --show-diff-on-failure
env:
SKIP: mypy
SKIP: mypy # mypy runs in its own job below; see the `mypy` job

# ---------------------------------------------------------------------------
# mypy — static type checker for hf_adapters/.
#
# Runs in its own job so it can install torch+transformers (needed to resolve
# the type stubs) without bloating the pre-commit lint job, which runs on a
# plain Python install. The local pre-commit mypy hook is intentionally kept
# so developers still get feedback on commit; this job is the CI enforcement.
# ---------------------------------------------------------------------------
mypy:
name: mypy
runs-on: ubuntu-latest
defaults:
run:
working-directory: .
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install dependencies
run: |
pip install --quiet \
"torch>=2.0" \
"transformers>=5.12.1,<6.0.0" \
"mypy>=2.3.0,<3"

- name: Run mypy
run: mypy --config-file=pyproject.toml

# ===========================================================================
# Dynamic matrix generation
Expand Down Expand Up @@ -623,6 +654,7 @@ jobs:
working-directory: .
needs:
- pre-commit
- mypy
- generate-matrix
- adapter-coverage
# - cpu-tests
Expand All @@ -643,6 +675,7 @@ jobs:
# lines when restoring either job.
run: |-
if ${{ contains(needs.pre-commit.result, 'failure') || contains(needs.pre-commit.result, 'cancelled') ||
contains(needs.mypy.result, 'failure') || contains(needs.mypy.result, 'cancelled') ||
contains(needs.generate-matrix.result, 'failure') || contains(needs.generate-matrix.result, 'cancelled') ||
contains(needs.adapter-coverage.result, 'failure') || contains(needs.adapter-coverage.result, 'cancelled') ||
contains(needs.spyre-load-tests.result, 'failure') || contains(needs.spyre-load-tests.result, 'cancelled') ||
Expand Down
18 changes: 16 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,31 @@ ignore = [
]

[tool.mypy]
python_version = "3.10"
python_version = "3.11"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = false
explicit_package_bases = true
files = ["hf_adapters/**/*.py"]

# sympy ships no py.typed marker (PEP 561), so mypy refuses to analyze it.
[[tool.mypy.overrides]]
module = "sympy.*"
ignore_missing_imports = true

# deepspec is an optional private package (DSpark speculative decoding);
# it is not installed in the standard dev environment.
[[tool.mypy.overrides]]
module = "deepspec.*"
ignore_missing_imports = true

# sentence_transformers is a runtime dependency (see [project].dependencies)
# but is not installed in the CI mypy job to keep that job cheap, and it
# ships no py.typed marker either — so mypy can't resolve its stubs.
[[tool.mypy.overrides]]
module = "sentence_transformers.*"
ignore_missing_imports = true

[tool.pytest.ini_options]
testpaths = ["tests"]
pythonpath = ["."]
Expand Down Expand Up @@ -82,7 +96,7 @@ dev = [
"pre-commit>=3.5.0",
"black>=26.3.1",
"ruff>=0.15.6",
"mypy>=1.14.0,<2",
"mypy>=2.3.0,<3",
"typing-extensions",
"nicegui",
"clickhouse-connect>=1.4.1",
Expand Down
46 changes: 35 additions & 11 deletions scripts/check_uv_lock.sh
Original file line number Diff line number Diff line change
@@ -1,17 +1,41 @@
#!/usr/bin/env bash
# Pre-commit hook: if pyproject.toml is staged, uv.lock must be staged too.
# Pre-commit hook: if pyproject.toml is staged AND the change actually affects
# dependency resolution, uv.lock must be staged too.
#
# The naive "any pyproject.toml change requires a staged uv.lock" rule fires
# on tool-only edits (e.g. [tool.mypy], [tool.ruff]) that uv.lock doesn't
# track, forcing a spurious lock touch. We defer to `uv lock --check` — the
# only source of truth for whether the lockfile is stale — and only fail
# when it actually is.
#
# Run as: USE_SPYRE_CCL=0 uv lock then git add uv.lock

set -euo pipefail

if git diff --cached --name-only | grep -q "^pyproject\.toml$"; then
if ! git diff --cached --name-only | grep -q "^uv\.lock$"; then
echo ""
echo " ✗ pyproject.toml was modified but uv.lock was not updated."
echo ""
echo " Run: uv lock"
echo " Then: git add uv.lock"
echo ""
exit 1
fi
# Only care about commits that touch pyproject.toml. Other paths pass through.
if ! git diff --cached --name-only | grep -q "^pyproject\.toml$"; then
exit 0
fi

# If the lockfile is already staged, trust the developer ran `uv lock` and let
# the commit through. (`uv lock --check` would run against the working-tree
# copy, not the staged one, and could disagree if the working tree drifted
# after `git add uv.lock`.)
if git diff --cached --name-only | grep -q "^uv\.lock$"; then
exit 0
fi

# pyproject.toml staged, uv.lock not staged — is uv.lock actually stale?
if uv lock --check >/dev/null 2>&1; then
# Lockfile is up-to-date w.r.t. pyproject.toml; the staged pyproject.toml
# change is dep-neutral (tool config, metadata, etc.) so nothing to do.
exit 0
fi

echo ""
echo " ✗ pyproject.toml was modified but uv.lock was not updated."
echo ""
echo " Run: uv lock"
echo " Then: git add uv.lock"
echo ""
exit 1
Loading
Loading