Skip to content

Commit f500d31

Browse files
committed
Merge branch 'main' into pr/amalia-k510/141
2 parents 572948e + 63192a5 commit f500d31

26 files changed

Lines changed: 596 additions & 275 deletions

.github/workflows/publish.yml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,9 @@ jobs:
1111
permissions:
1212
id-token: write # to authenticate as Trusted Publisher to pypi.org
1313
steps:
14-
- uses: actions/checkout@v5
15-
- uses: actions/setup-python@v6
14+
- uses: actions/checkout@v7
15+
- uses: astral-sh/setup-uv@v9.0.0
1616
with:
17-
python-version: "3.x"
18-
cache: pip
19-
- run: pip install build
20-
- run: python -m build
17+
enable-cache: false
18+
- run: uv build
2119
- uses: pypa/gh-action-pypi-publish@release/v1

.github/workflows/pytest.yml

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,48 +13,53 @@ jobs:
1313
python-version: ["3.10", "3.14"]
1414
runs-on: ubuntu-latest
1515
timeout-minutes: 60
16+
env:
17+
UV_PYTHON: ${{ matrix.python-version }}
1618
steps:
17-
- name: Checkout
18-
uses: actions/checkout@v5
19+
- &clone
20+
uses: actions/checkout@v7
1921
with:
2022
filter: blob:none
2123
fetch-depth: 0
2224

23-
- name: Setup Python
24-
uses: actions/setup-python@v6
25+
- &uv
26+
uses: astral-sh/setup-uv@v9.0.0
2527
with:
26-
python-version: ${{ matrix.python-version }}
27-
cache: pip
28+
enable-cache: true
2829

29-
- name: Install project and dependencies
30-
run: pip install .[annlibs,tests] 'hannoy @ git+https://github.com/nnethercott/hannoy.git'
30+
- &hatch
31+
name: Install Hatch
32+
# https://github.com/pypa/hatch/pull/2351
33+
run: uv tool install git+https://github.com/pypa/hatch.git@af5339a1a5bb8e6d4b659c4c1bfff8e7e37cdaff
3134

3235
- name: Run test suite
33-
run: pytest -v --color=yes
36+
run: hatch test -py ${{ matrix.python-version }} -v --color=yes
37+
38+
types:
39+
runs-on: ubuntu-latest
40+
steps:
41+
- *clone
42+
- *uv
43+
- *hatch
44+
- name: Type check
45+
run: hatch check types
3446

3547
build:
3648
runs-on: ubuntu-latest
3749
steps:
38-
- uses: actions/checkout@v5
39-
with:
40-
filter: blob:none
41-
fetch-depth: 0
42-
- uses: actions/setup-python@v6
43-
with:
44-
python-version: "3.x"
45-
cache: pip
46-
- name: Install tools
47-
run: pip install twine build
50+
- *clone
51+
- *uv
4852
- name: Build and check
4953
run: |
50-
python -m build
51-
twine check dist/*.whl
54+
uv build
55+
uvx twine check dist/*.whl
5256
5357
check:
5458
if: always()
5559
needs:
5660
- build
5761
- test
62+
- types
5863
runs-on: ubuntu-latest
5964
steps:
6065
# https://github.com/marketplace/actions/alls-green#why

.pre-commit-config.yaml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
ci:
2+
skip: [mypy] # needs hatch to build an env with the ANN libs
13
repos:
24
- repo: https://github.com/pre-commit/pre-commit-hooks
35
rev: v6.0.0
@@ -15,9 +17,19 @@ repos:
1517
- repo: https://github.com/astral-sh/ruff-pre-commit
1618
rev: v0.16.1
1719
hooks:
18-
- id: ruff
20+
- id: ruff-check
1921
args: ["--fix"]
2022
- id: ruff-format
23+
- repo: local
24+
hooks:
25+
- id: mypy
26+
name: mypy
27+
entry: hatch check types
28+
language: system
29+
types: [python]
30+
files: ^(src|tests)/
31+
require_serial: true
32+
pass_filenames: false
2133
- repo: https://github.com/pre-commit/mirrors-prettier
2234
rev: v4.0.0-alpha.8
2335
hooks:

.readthedocs.yaml

Lines changed: 0 additions & 19 deletions
This file was deleted.

.readthedocs.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# https://docs.readthedocs.io/en/stable/config-file/v2.html
2+
version: 2
3+
build:
4+
os: ubuntu-26.04
5+
tools:
6+
python: "3.14"
7+
jobs:
8+
post_checkout:
9+
# unshallow so version can be derived from tag
10+
- git fetch --unshallow || true
11+
create_environment:
12+
- asdf plugin add uv
13+
- asdf install uv latest
14+
- asdf global uv latest
15+
# https://github.com/pypa/hatch/pull/2351
16+
- UV_TOOL_BIN_DIR=$HOME/.asdf/bin uv tool install git+https://github.com/pypa/hatch.git@af5339a1a5bb8e6d4b659c4c1bfff8e7e37cdaff
17+
build:
18+
html:
19+
- hatch run docs:build
20+
- mv docs/_build $READTHEDOCS_OUTPUT

docs/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# This file only contains a selection of the most common options. For a full
44
# list see the documentation:
55
# https://www.sphinx-doc.org/en/master/usage/configuration.html
6+
from __future__ import annotations
67

78
import os
89

examples/rnn_dbscan_big.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,38 @@
77
88
"""
99

10+
from __future__ import annotations
11+
12+
from typing import TYPE_CHECKING
13+
1014
import numpy as np
1115
from joblib import Memory
1216
from sklearn import metrics
1317
from sklearn.datasets import fetch_openml
1418

1519
from sklearn_ann.cluster.rnn_dbscan import simple_rnn_dbscan_pipeline
1620

21+
if TYPE_CHECKING:
22+
from collections.abc import Callable
23+
from typing import Any
24+
1725

1826
# #############################################################################
1927
# Generate sample data
20-
def fetch_mnist():
28+
def fetch_mnist() -> tuple[Any, Any]:
2129
print("Downloading mnist_784")
22-
mnist = fetch_openml("mnist_784")
23-
return mnist.data / 255, mnist.target
30+
data, target = fetch_openml("mnist_784", return_X_y=True)
31+
return data / 255, target
2432

2533

2634
memory = Memory("./mnist")
2735

2836
X, y = memory.cache(fetch_mnist)()
2937

3038

31-
def run_rnn_dbscan(neighbor_transformer, n_neighbors, **kwargs):
39+
def run_rnn_dbscan(
40+
neighbor_transformer: Callable[..., Any], n_neighbors: int, **kwargs: Any
41+
) -> None:
3242
# #############################################################################
3343
# Compute RnnDBSCAN
3444

examples/rnn_dbscan_simple.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
1010
"""
1111

12+
from __future__ import annotations
13+
1214
import numpy as np
1315
from sklearn import metrics
1416
from sklearn.datasets import make_blobs
@@ -34,7 +36,7 @@
3436

3537
# Number of clusters in labels, ignoring noise if present.
3638
n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0)
37-
n_noise_ = list(labels).count(-1)
39+
n_noise_ = int((labels == -1).sum())
3840

3941
print(f"""\
4042
Estimated number of clusters: {n_clusters_}

pyproject.toml

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,6 @@ dependencies = [
1616
]
1717

1818
[project.optional-dependencies]
19-
tests = [
20-
"pytest>=6.2.1",
21-
"pytest-cov>=2.10.1",
22-
]
23-
docs = [
24-
"sphinx>=7",
25-
"sphinx-gallery>=0.8.2",
26-
"sphinx-book-theme>=1.1.0",
27-
"sphinx-issues>=1.2.0",
28-
"numpydoc>=1.1.0",
29-
"matplotlib>=3.3.3",
30-
"scanpydoc",
31-
]
3219
annoy = [
3320
"annoy>=1.17.0,<2.0.0",
3421
]
@@ -49,6 +36,26 @@ annlibs = [
4936
"sklearn-ann[annoy,faiss,hannoy,pynndescent,nmslib]",
5037
]
5138

39+
[dependency-groups]
40+
docs = [
41+
"sphinx>=7",
42+
"sphinx-gallery>=0.8.2",
43+
"sphinx-book-theme>=1.1.0",
44+
"sphinx-issues>=1.2.0",
45+
"numpydoc>=1.1.0",
46+
"matplotlib>=3.3.3",
47+
"scanpydoc",
48+
]
49+
tests = [
50+
"pytest>=6.2.1",
51+
"pytest-cov>=2.10.1",
52+
]
53+
typing = [
54+
"mypy",
55+
"matplotlib", # examples are type checked, too
56+
"scipy-stubs",
57+
]
58+
5259
[tool.hatch.version]
5360
source = "vcs"
5461

@@ -77,6 +84,7 @@ select = [
7784
"PTH", # Pathlib
7885
"RUF", # Ruff’s own rules
7986
"T20", # print statements
87+
"TC", # type checking
8088
]
8189
ignore = [
8290
# Don’t complain about “confusables”
@@ -87,19 +95,51 @@ ignore = [
8795
"tests/*.py" = ["T20"]
8896
[tool.ruff.lint.isort]
8997
known-first-party = ["sklearn_ann"]
98+
required-imports = ["from __future__ import annotations"]
99+
[tool.ruff.lint.flake8-type-checking]
100+
exempt-modules = []
101+
strict = true
90102

91103
[tool.hatch.envs.docs]
92104
installer = "uv"
93-
features = ["docs", "annlibs"]
105+
features = ["annlibs"]
106+
dependency-groups = ["docs"]
94107
scripts.build = "sphinx-build -M html docs docs/_build"
95108

109+
[tool.hatch.envs.hatch-check-types]
110+
features = ["annlibs"]
111+
dependency-groups = ["tests", "typing"]
112+
scripts.check = "mypy {args:.}"
113+
96114
[tool.hatch.envs.hatch-test]
97115
default-args = []
98-
features = ["tests", "annlibs"]
116+
features = ["annlibs"]
117+
dependency-groups = ["tests"]
99118

100119
[tool.hatch.build.targets.wheel]
101120
packages = ["src/sklearn_ann"]
102121

122+
[tool.mypy]
123+
python_version = "3.12"
124+
mypy_path = ["src", "tests"]
125+
strict = true
126+
explicit_package_bases = true # pytest doesn’t do __init__.py
127+
no_implicit_optional = true
128+
disallow_untyped_decorators = false # e.g. pytest.mark.parametrize
129+
follow_untyped_imports = true
130+
# follow_untyped_imports makes these readable, but not annotated
131+
untyped_calls_exclude = ["sklearn", "joblib", "pynndescent"]
132+
133+
[[tool.mypy.overrides]]
134+
# pynndescent has no __all__, so its re-exports are implicit
135+
module = ["pynndescent"]
136+
no_implicit_reexport = false
137+
138+
[[tool.mypy.overrides]]
139+
# nmslib is a compiled extension module without stubs
140+
module = ["nmslib"]
141+
ignore_missing_imports = true
142+
103143
[tool.uv.sources]
104144
hannoy.git = "https://github.com/nnethercott/hannoy.git" # TODO: remove once 0.1.4/0.2 is released
105145

0 commit comments

Comments
 (0)