Skip to content

Commit dcdee05

Browse files
skarndevSergey Shumakovclaude
authored
Migrate to uv & ruff, remove black and isort (#290)
## Summary This PR migrates the project's tooling from pip/black/isort/flake8 to uv/ruff, and renames `master` → `main` in CI. ### CI changes - **uv**: replaced pip with uv for all package management in CI; `uv venv` + `uv pip install` for virtual environment setup and dependency installation - **ruff**: replaced black (formatter) + isort (import sorter) + flake8 (linter) with a single `ruff` invocation; added a new `check` job that runs `ruff format --diff`, `ruff check --select I,RUF022 --diff` (isort), and `ruff check` - **Branch rename**: updated CI trigger and publish step to target `main` instead of `master` ### Script changes (`tests/`) - `install-demo-module.sh`: replaced `pip install` with `uv pip install --python <exe>` to install into the active venv without requiring pip to be present (uv venv doesn't include pip by default) - `check-demo-stubs-generation.sh`: replaced `black` + `isort` with `ruff format` + `ruff check --select I,RUF022 --fix`; added dynamic `--target-version` to handle PEP 695 syntax in Python 3.12+ stubs; removed `--diff` flag from the fix step (diffs are shown later by `git diff --exit-code`) - `check-demo-errors-generation.sh`: removed `uv run` wrapper (not compatible with tox's virtual env activation) ### tox changes - Removed `requirements-dev.txt` dependency (replaced with inline `deps` in tox.ini) - Fixed parallel run: `PYTHON_TAG_FILE` now uses `{envtmpdir}` (per-env) instead of a shared path under `{toxinidir}/tmp/` - Added `cmeel-eigen` to `deps` so it's available during `commands_pre` (cmake build) ### Reference stubs - Reformatted all reference stubs under `tests/stubs/` with ruff (import ordering and style differ slightly from isort+black) - Updated `requirements.txt` files: removed `black` and `isort`, added `ruff>=0.14.14` ### pyproject.toml - Added `exclude = ["tests/stubs"]` to `[tool.ruff]` to prevent ruff from parsing PEP 695 stub syntax (e.g. `def f[T](...)`) with a `py310` target version 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Sergey Shumakov <skarn@Sergeys-MacBook-Pro.local> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 80a777e commit dcdee05

81 files changed

Lines changed: 753 additions & 548 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 61 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,58 +5,60 @@ on:
55
pull_request:
66
push:
77
branches:
8-
- master
8+
- main
99
tags:
1010
- "v*"
1111

1212
jobs:
13+
check:
14+
name: Check
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Setup Python 3.13
18+
uses: actions/setup-python@v5
19+
with:
20+
python-version: "3.13"
21+
- uses: astral-sh/setup-uv@v7
22+
- name: Checkout
23+
uses: actions/checkout@v5
24+
- name: Install requirements
25+
run: |
26+
uv lock --check
27+
uv sync
28+
- name: Run Ruff as isort
29+
run: uv run ruff check --select I,RUF022 --fix --diff ./pybind11_stubgen
30+
if: ${{ failure() || success() }}
31+
- name: Run Ruff format
32+
run: uv run ruff format --diff ./pybind11_stubgen
33+
if: ${{ failure() || success() }}
34+
- name: Run Ruff
35+
run: |
36+
uv run ruff check --ignore F401,F821 .
37+
if: ${{ failure() || success() }}
38+
1339
build:
1440
name: Build wheel
1541
runs-on: ubuntu-latest
42+
needs: [check]
1643
steps:
1744
- uses: actions/checkout@v5
1845
- uses: actions/setup-python@v5
1946
with:
2047
python-version: "3.13"
2148

22-
- name: Install build
23-
run: python -m pip --disable-pip-version-check install build
49+
- uses: astral-sh/setup-uv@v7
2450

2551
- name: Build sdist + wheel
26-
run: python -m build
52+
run: |
53+
uv lock --check
54+
uv build
2755
2856
- name: Upload build artifacts
2957
uses: actions/upload-artifact@v6
3058
with:
3159
name: dist
3260
path: dist
3361

34-
format:
35-
name: Format code
36-
runs-on: ubuntu-latest
37-
steps:
38-
- name: Setup Python 3.13
39-
uses: actions/setup-python@v5
40-
with:
41-
python-version: "3.13"
42-
- name: Checkout
43-
uses: actions/checkout@v5
44-
- name: Install requirements
45-
run: pip install -r requirements-dev.txt
46-
- name: Run isort
47-
run: isort --check --profile=black --diff ./pybind11_stubgen
48-
if: ${{ failure() || success() }}
49-
- name: Run black
50-
run: black --diff ./pybind11_stubgen
51-
if: ${{ failure() || success() }}
52-
- name: Run flake8
53-
run: |
54-
flake8 \
55-
--max-line-length=88 \
56-
--extend-ignore=E203 \
57-
--extend-exclude=venv/,.pytest_cache/,.ipynb_checkpoints/,tests/,tmp/,build/
58-
if: ${{ failure() || success() }}
59-
6062
tests:
6163
name: "Test 🐍 ${{ matrix.config.python }} • pybind-${{ matrix.config.pybind11-branch }} • ${{ matrix.config.numpy-format }}"
6264
runs-on: ubuntu-latest
@@ -159,31 +161,40 @@ jobs:
159161
with:
160162
python-version: ${{ matrix.config.python }}
161163

164+
- uses: astral-sh/setup-uv@v7
165+
162166
- name: Update CMake
163167
uses: jwlawson/actions-setup-cmake@v2
164168
with:
165-
# https://github.com/pybind/pybind11/blob/914c06fb252b6cc3727d0eedab6736e88a3fcb01/CMakeLists.txt#L13C34-L13C38
166169
cmake-version: ${{ matrix.config.cmake-version }}
167170

171+
- name: Create UV venv
172+
run: |
173+
uv venv .venv
174+
168175
- name: Setup annotations on Linux
169176
if: runner.os == 'Linux'
170-
run: python -m pip install pytest-github-actions-annotate-failures
177+
run: uv pip install pytest-github-actions-annotate-failures
171178

172179
- name: Install requirements
173-
run: pip install -r "./tests/stubs/python-${{ matrix.config.python }}/requirements.txt"
180+
run: uv sync --group dev --no-install-project
174181

175182
- name: Install
176183
shell: bash
177184
working-directory: dist
178-
run: python -m pip --disable-pip-version-check install *.whl
185+
run: uv pip install --disable-pip-version-check *.whl
179186

180187
- name: Install demo module
181188
shell: bash
182-
run: ./tests/install-demo-module.sh --pybind11-branch "${{ matrix.config.pybind11-branch }}"
189+
run: |
190+
source .venv/bin/activate
191+
./tests/install-demo-module.sh --pybind11-branch "${{ matrix.config.pybind11-branch }}"
183192
184193
- name: Check stubs generation
185194
shell: bash
186-
run: ./tests/check-demo-stubs-generation.sh --stubs-sub-dir "stubs/python-${{ matrix.config.python }}/pybind11-${{ matrix.config.pybind11-branch }}/${{ matrix.config.numpy-format }}" --${{ matrix.config.numpy-format }}
195+
run: |
196+
source .venv/bin/activate
197+
./tests/check-demo-stubs-generation.sh --stubs-sub-dir "stubs/python-${{ matrix.config.python }}/pybind11-${{ matrix.config.pybind11-branch }}/${{ matrix.config.numpy-format }}" --${{ matrix.config.numpy-format }}
187198
188199
- name: Archive patch
189200
uses: actions/upload-artifact@v6
@@ -196,7 +207,9 @@ jobs:
196207

197208
- name: Check error generation
198209
shell: bash
199-
run: ./tests/check-demo-errors-generation.sh "pybind11-${{ matrix.config.pybind11-branch }}"
210+
run: |
211+
source .venv/bin/activate
212+
./tests/check-demo-errors-generation.sh "pybind11-${{ matrix.config.pybind11-branch }}"
200213
201214
test-cli-options:
202215
name: "Runs on 🐍 ${{ matrix.python }} • ${{ matrix.test-package }}"
@@ -219,28 +232,35 @@ jobs:
219232
with:
220233
python-version: ${{ matrix.python }}
221234

235+
- uses: astral-sh/setup-uv@v7
236+
222237
- name: Download build artifacts
223238
uses: actions/download-artifact@v6
224239
with:
225240
name: dist
226241
path: dist
227242

243+
- name: Create UV venv
244+
run: |
245+
uv venv .venv
246+
228247
- name: Setup annotations on Linux
229248
if: runner.os == 'Linux'
230-
run: python -m pip install pytest-github-actions-annotate-failures
249+
run: uv pip install pytest-github-actions-annotate-failures
231250

232251
- name: Install
233252
shell: bash
234253
working-directory: dist
235-
run: python -m pip --disable-pip-version-check install *.whl
254+
run: uv pip install --disable-pip-version-check *.whl
236255

237256
- name: "Install ${{ matrix.test-package }}"
238257
shell: bash
239-
run: pip install "${{ matrix.test-package }}"
258+
run: uv pip install "${{ matrix.test-package }}"
240259

241260
- name: Generate stubs
242261
shell: bash
243262
run: |
263+
source .venv/bin/activate
244264
pybind11-stubgen "${{ matrix.test-package }}" -o flavour-1 --numpy-array-wrap-with-annotated
245265
pybind11-stubgen "${{ matrix.test-package }}" -o flavour-2 --numpy-array-remove-parameters
246266
pybind11-stubgen "${{ matrix.test-package }}" -o flavour-3 --print-invalid-expressions-as-is
@@ -249,7 +269,7 @@ jobs:
249269
250270
publish:
251271
name: Publish distribution
252-
needs: [build, format, tests, test-cli-options]
272+
needs: [check, build, tests, test-cli-options]
253273
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
254274
runs-on: ubuntu-latest
255275
permissions:

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,9 @@ cython_debug/
210210
# VS Code
211211
.vscode/
212212

213+
# Zed
214+
.zed/
215+
213216
tmp
214217
*.patch
215218
*.zip

pyproject.toml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,18 @@ dynamic = ["readme"]
1818
Repository = "https://github.com/pybind/pybind11-stubgen"
1919
Issues = "https://github.com/pybind/pybind11-stubgen/issues"
2020

21+
[dependency-groups]
22+
dev = [
23+
"cmeel==0.59.0",
24+
"cmeel-eigen==3.4.0.2",
25+
"numpy~=1.20",
26+
"pip",
27+
"scipy~=1.0",
28+
"typing_extensions>=4,<5",
29+
"mypy>=1.19.1",
30+
"ruff>=0.14.14",
31+
]
32+
2133
[tool.setuptools.packages]
2234
find = {}
2335

@@ -26,3 +38,18 @@ readme = {file = ["README.md"], content-type = "text/markdown"}
2638

2739
[project.entry-points.console_scripts]
2840
pybind11-stubgen = "pybind11_stubgen.__init__:main"
41+
42+
[tool.ruff]
43+
target-version = "py310"
44+
line-length = 88
45+
exclude = ["tests/stubs"]
46+
47+
[tool.ruff.lint]
48+
ignore = ["F403"] # undefined names imported (triggered by native extensions)
49+
50+
[tool.ruff.format]
51+
quote-style = "double"
52+
indent-style = "space"
53+
54+
[tool.ruff.lint.pycodestyle]
55+
max-line-length = 88

requirements-dev.txt

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

tests/check-demo-stubs-generation.sh

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
set -e
44

5-
PYTHON_EXECUTABLE=$(python -c 'import sys; print(sys.executable)')
6-
75
resolve_path() {
86
local path="$1"
97

@@ -55,7 +53,7 @@ remove_stubs() {
5553
}
5654

5755
run_stubgen() {
58-
${PYTHON_EXECUTABLE} -m pybind11_stubgen \
56+
pybind11-stubgen \
5957
demo \
6058
--output-dir=${STUBS_DIR} \
6159
${NUMPY_FORMAT} \
@@ -69,8 +67,9 @@ run_stubgen() {
6967
format_stubs() {
7068
(
7169
cd "${STUBS_DIR}" ;
72-
black . ;
73-
isort --profile=black . ;
70+
PYTHON_TARGET=$(python -c "import sys; print(f'py{sys.version_info.major}{sys.version_info.minor}')")
71+
ruff format --target-version "${PYTHON_TARGET}" .
72+
ruff check --select I,RUF022 --fix --target-version "${PYTHON_TARGET}" .
7473
)
7574
}
7675

tests/install-demo-module.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ resolve_path() {
1818
fi
1919
}
2020

21+
2122
function parse_args() {
2223

2324
CLEAR='\033[0m'
@@ -84,7 +85,7 @@ install_pydemo() {
8485
(
8586
export CMAKE_PREFIX_PATH="$(resolve_path "${INSTALL_PREFIX}"):$(cmeel cmake)";
8687
rm -rf ${TESTS_ROOT}/py-demo/build
87-
${PYTHON_EXECUTABLE} -m pip install --force-reinstall "${TESTS_ROOT}/py-demo"
88+
uv pip install --python "${PYTHON_EXECUTABLE}" --force-reinstall "${TESTS_ROOT}/py-demo"
8889
)
8990
}
9091

tests/stubs/python-3.10/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/aliases/__init__.pyi

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@ from __future__ import annotations
22

33
import typing
44

5-
import numpy
6-
from numpy import random
7-
85
import demo._bindings.enum
6+
import numpy
97
from demo._bindings.aliases.foreign_method_arg import Bar2 as foreign_type_alias
108
from demo._bindings.aliases.foreign_return import get_foo as foreign_class_alias
9+
from numpy import random
1110

1211
from . import (
1312
foreign_arg,

tests/stubs/python-3.10/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/eigen.pyi

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,12 @@ def four_col_matrix_r(
6161
def four_row_matrix_r(
6262
arg0: typing.Annotated[numpy.typing.ArrayLike, numpy.float32, "[4, n]"],
6363
) -> typing.Annotated[numpy.typing.NDArray[numpy.float32], "[4, n]"]: ...
64-
def get_matrix_int() -> (
65-
typing.Annotated[numpy.typing.NDArray[numpy.int32], "[3, 3]"]
66-
): ...
67-
def get_vector_float64() -> (
68-
typing.Annotated[numpy.typing.NDArray[numpy.float64], "[3, 1]"]
69-
): ...
64+
def get_matrix_int() -> typing.Annotated[
65+
numpy.typing.NDArray[numpy.int32], "[3, 3]"
66+
]: ...
67+
def get_vector_float64() -> typing.Annotated[
68+
numpy.typing.NDArray[numpy.float64], "[3, 1]"
69+
]: ...
7070
def sparse_matrix_c(
7171
arg0: typing.Annotated[scipy.sparse.csc_matrix, numpy.float32],
7272
) -> typing.Annotated[scipy.sparse.csc_matrix, numpy.float32]: ...

tests/stubs/python-3.10/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/issues.pyi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import typing
44

55
__all__: list[str] = [
66
"backslashes_should_be_escaped",
7-
"issue_274_docstring_leading_newline",
87
"issue_51_catastrophic_regex",
98
"issue_73_utf8_doc_chars",
9+
"issue_274_docstring_leading_newline",
1010
]
1111

1212
def backslashes_should_be_escaped() -> None:

tests/stubs/python-3.10/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/properties.pyi

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,27 +43,23 @@ class WithPropDoc:
4343
"""
4444
prop doc token
4545
"""
46-
4746
@def_property.setter
4847
def def_property(self, arg1: typing.SupportsInt | typing.SupportsIndex) -> None: ...
4948
@property
5049
def def_property_readonly(self) -> int:
5150
"""
5251
prop doc token
5352
"""
54-
5553
@property
5654
def def_readonly(self) -> int:
5755
"""
5856
prop doc token
5957
"""
60-
6158
@property
6259
def def_readwrite(self) -> int:
6360
"""
6461
prop doc token
6562
"""
66-
6763
@def_readwrite.setter
6864
def def_readwrite(
6965
self, arg0: typing.SupportsInt | typing.SupportsIndex
@@ -81,13 +77,11 @@ class WithGetterSetterDoc:
8177
"""
8278
getter doc token
8379
"""
84-
8580
@def_property.setter
8681
def def_property(self, arg1: typing.SupportsInt | typing.SupportsIndex) -> None:
8782
"""
8883
setter doc token
8984
"""
90-
9185
@property
9286
def def_property_readonly(self) -> int:
9387
"""
@@ -106,7 +100,6 @@ class WithPropAndGetterSetterDoc:
106100
"""
107101
prop doc token
108102
"""
109-
110103
@def_property.setter
111104
def def_property(self, arg1: typing.SupportsInt | typing.SupportsIndex) -> None: ...
112105
@property

0 commit comments

Comments
 (0)