Skip to content

Commit d91cfdf

Browse files
BrianPughclaude
andcommitted
Migrate from Poetry to uv
Replace Poetry/poetry-dynamic-versioning with uv as the package manager and setuptools + setuptools-scm + Cython as the build backend: - pyproject.toml: PEP 621 [project] metadata, PEP 735 [dependency-groups], and [tool.uv] cache-keys so `uv sync` rebuilds the Cython extension whenever its sources change. - build.py -> setup.py (same extension config); add MANIFEST.in for sdists. - Version derived from git tags via setuptools-scm, exposed at runtime through importlib.metadata. - bootstrap installs uv instead of Poetry; Cython support is now wired by default and stripped when declined. - CI: astral-sh/setup-uv with locked syncs; lint/docs split out of the test matrix with cancel-in-progress concurrency; PyPI Trusted Publishing (OIDC) replaces PYPI_TOKEN; wheel builds gated to compiled-code changes on PRs; native ubuntu-24.04-arm runners replace QEMU for aarch64 wheels; lightweight pre-commit hooks move to pre-commit.ci. - Support window bumped to Python 3.10-3.14 (cibuildwheel v3.2). - Dependabot: uv + github-actions ecosystems with grouped minor/patch PRs. - Dockerfile/ReadTheDocs converted to uv; .dockerignore no longer ships the local venv and build artifacts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UarJmE1ctKM1J5U8oSMVEY
1 parent d9edd2d commit d91cfdf

20 files changed

Lines changed: 1721 additions & 2048 deletions

.dockerignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,16 @@
55
.github
66
.gitignore
77
.pre-commit-config.yaml
8+
.pytest_cache
89
.readthedocs.yaml
10+
.ruff_cache
11+
.venv
912
assets
13+
build
14+
dist
1015
docs
1116
tests
17+
wheelhouse
18+
**/__pycache__
19+
*.so
20+
*.pyd

.github/contributing.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
## Environment Setup
22

3-
1. We use [Poetry](https://python-poetry.org/docs/#installation) for managing virtual environments and dependencies.
4-
Once Poetry is installed, run `poetry install` in this repo to get started.
3+
1. We use [uv](https://docs.astral.sh/uv/getting-started/installation/) for managing virtual environments and dependencies.
4+
Once uv is installed, run `uv sync` in this repo to get started.
55
2. For managing linters, static-analysis, and other tools, we use [pre-commit](https://pre-commit.com/#installation).
66
Once Pre-commit is installed, run `pre-commit install` in this repo to install the hooks.
77
Using pre-commit ensures PRs match the linting requirements of the codebase.
88

99
## Documentation
1010
Whenever possible, please add docstrings to your code!
1111
We use [numpy-style napoleon docstrings](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/#google-vs-numpy).
12-
To confirm docstrings are valid, build the docs by running `poetry run make html` in the `docs/` folder.
12+
To confirm docstrings are valid, build the docs by running `uv run make html` in the `docs/` folder.
1313

1414
I typically write dosctrings first, it will act as a guide to limit scope and encourage unit-testable code.
1515
Good docstrings include information like:

.github/dependabot.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,19 @@
55

66
version: 2
77
updates:
8-
- package-ecosystem: "pip" # See documentation for possible values
8+
- package-ecosystem: "uv" # See documentation for possible values
99
directory: "/" # Location of package manifests
1010
schedule:
1111
interval: "weekly"
12+
groups:
13+
# Batch minor/patch bumps into a single weekly PR; majors stay separate.
14+
python-dependencies:
15+
patterns: ["*"]
16+
update-types: ["minor", "patch"]
17+
- package-ecosystem: "github-actions"
18+
directory: "/"
19+
schedule:
20+
interval: "weekly"
21+
groups:
22+
github-actions:
23+
patterns: ["*"]

.github/workflows/build_wheels.yaml

Lines changed: 43 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -3,54 +3,41 @@ name: Build Wheels
33
on:
44
workflow_dispatch:
55
pull_request:
6+
# Only build wheels on PRs when compiled code (or the build itself) changes.
7+
paths:
8+
- "**.pyx"
9+
- "**.pxd"
10+
- "pythontemplate/_c_src/**"
11+
- "setup.py"
12+
- "MANIFEST.in"
13+
- "pyproject.toml"
14+
- ".github/workflows/build_wheels.yaml"
615
push:
716
tags:
817
- "v*.*.*"
918

19+
concurrency:
20+
group: ${{ github.workflow }}-${{ github.ref }}
21+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
22+
1023
jobs:
1124
build_sdist:
1225
name: "sdist"
1326
runs-on: ubuntu-latest
14-
env:
15-
PYTHON: 3.12
16-
POETRY_HOME: "~/poetry"
1727

1828
steps:
1929
- name: Check out repository
20-
uses: actions/checkout@v4
30+
uses: actions/checkout@v5
2131
with:
2232
fetch-depth: 0
2333

24-
- name: Set up python ${{ env.PYTHON }}
25-
id: setup-python
26-
uses: actions/setup-python@v5
27-
with:
28-
python-version: ${{ env.PYTHON }}
29-
30-
- name: Cache Poetry Install
31-
uses: actions/cache@v4
32-
id: cached-poetry
34+
- name: Install uv
35+
uses: astral-sh/setup-uv@v6
3336
with:
34-
path: ${{ env.POETRY_HOME }}
35-
key: poetry-cache-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('.github/workflows/build_wheels.yaml') }}
36-
37-
- name: Install poetry
38-
if: steps.cached-poetry.outputs.cache-hit != 'true'
39-
uses: snok/install-poetry@v1
40-
41-
- name: Add Poetry to PATH # Needs to be separate from install-poetry because cache.
42-
run: |
43-
echo "$POETRY_HOME/bin" >> $GITHUB_PATH
44-
45-
- name: Configure Poetry # Needs to be separate from install-poetry because cache.
46-
run: |
47-
poetry self add poetry-dynamic-versioning[plugin]
48-
poetry config virtualenvs.create true
49-
poetry config virtualenvs.in-project true
37+
python-version: "3.13"
5038

5139
- name: Build sdist
52-
run: |
53-
poetry build --format=sdist
40+
run: uv build --sdist
5441

5542
- uses: actions/upload-artifact@v4
5643
with:
@@ -64,13 +51,8 @@ jobs:
6451
fail-fast: false
6552
matrix:
6653
os: [windows-latest]
67-
cibw_build: ["cp39-*", "cp310-*", "cp311-*", "cp312-*", "cp313-*"]
68-
cibw_archs: ["AMD64", "x86", "ARM64"]
69-
exclude:
70-
- os: windows-latest
71-
cibw_archs: "ARM64"
72-
env:
73-
PYTHON: 3.12
54+
cibw_build: ["cp310-*", "cp311-*", "cp312-*", "cp313-*", "cp314-*"]
55+
cibw_archs: ["AMD64"]
7456

7557
steps:
7658
- name: "Set environment variables (Windows)"
@@ -84,22 +66,15 @@ jobs:
8466
shell: bash
8567

8668
- name: Check out repository
87-
uses: actions/checkout@v4
69+
uses: actions/checkout@v5
8870
with:
8971
fetch-depth: 0
9072

91-
- name: Set up python ${{ env.PYTHON }}
92-
uses: actions/setup-python@v5
93-
id: setup-python
94-
with:
95-
python-version: ${{ env.PYTHON }}
96-
9773
- name: Build wheels
98-
uses: pypa/cibuildwheel@v2.16.5
74+
uses: pypa/cibuildwheel@v3.2
9975
env:
10076
CIBW_ARCHS: ${{ matrix.cibw_archs }}
10177
CIBW_BUILD: ${{ matrix.cibw_build }}
102-
CIBW_TEST_SKIP: "*-win_arm64"
10378
CIBW_TEST_REQUIRES: pytest
10479
CIBW_TEST_COMMAND: pytest {package}/tests
10580

@@ -109,20 +84,18 @@ jobs:
10984
path: wheelhouse/*.whl
11085

11186
build_wheels_linux:
112-
name: "${{ matrix.os }} ${{ matrix.cibw_archs }} ${{ matrix.cibw_build }}"
87+
name: "${{ matrix.os }} ${{ matrix.cibw_build }}"
11388
runs-on: ${{ matrix.os }}
11489
strategy:
11590
fail-fast: false
11691
matrix:
117-
os: [ubuntu-latest]
118-
cibw_build: ["cp39-*", "cp310-*", "cp311-*", "cp312-*", "cp313-*"]
119-
cibw_archs: ["x86_64", "i686", "aarch64", "ppc64le"]
120-
env:
121-
PYTHON: 3.12
92+
# ubuntu-24.04-arm builds aarch64 wheels natively (much faster than QEMU).
93+
os: [ubuntu-latest, ubuntu-24.04-arm]
94+
cibw_build: ["cp310-*", "cp311-*", "cp312-*", "cp313-*", "cp314-*"]
12295

12396
steps:
12497
- name: Check out repository
125-
uses: actions/checkout@v4
98+
uses: actions/checkout@v5
12699
with:
127100
fetch-depth: 0
128101

@@ -131,29 +104,16 @@ jobs:
131104
run: echo "CIBW_BUILD_SANITIZED=$(echo '${{ matrix.cibw_build }}' | sed 's/\*/_/g')" >> $GITHUB_ENV
132105
shell: bash
133106

134-
- name: Set up QEMU
135-
if: matrix.cibw_archs != 'x86_64'
136-
uses: docker/setup-qemu-action@v3
137-
with:
138-
platforms: all
139-
140-
- name: Set up python ${{ env.PYTHON }}
141-
uses: actions/setup-python@v5
142-
id: setup-python
143-
with:
144-
python-version: ${{ env.PYTHON }}
145-
146107
- name: Build wheels
147-
uses: pypa/cibuildwheel@v2.16.5
108+
uses: pypa/cibuildwheel@v3.2
148109
env:
149-
CIBW_ARCHS: ${{ matrix.cibw_archs }}
150110
CIBW_BUILD: ${{ matrix.cibw_build }}
151111
CIBW_TEST_REQUIRES: pytest
152112
CIBW_TEST_COMMAND: pytest {package}/tests
153113

154114
- uses: actions/upload-artifact@v4
155115
with:
156-
name: wheels-${{ matrix.os }}-${{ env.CIBW_BUILD_SANITIZED }}-${{ matrix.cibw_archs }}
116+
name: wheels-${{ matrix.os }}-${{ env.CIBW_BUILD_SANITIZED }}
157117
path: wheelhouse/*.whl
158118

159119
build_wheels_macos:
@@ -162,15 +122,13 @@ jobs:
162122
strategy:
163123
fail-fast: false
164124
matrix:
165-
os: [macos-13]
166-
cibw_build: ["cp39-*", "cp310-*", "cp311-*", "cp312-*", "cp313-*"]
167-
cibw_archs: ["x86_64"]
168-
env:
169-
PYTHON: 3.12
170-
SYSTEM_VERSION_COMPAT: 0 # https://github.com/actions/setup-python/issues/469#issuecomment-1192522949
125+
os: [macos-latest]
126+
cibw_build: ["cp310-*", "cp311-*", "cp312-*", "cp313-*", "cp314-*"]
127+
cibw_archs: ["arm64", "x86_64"]
128+
171129
steps:
172130
- name: Check out repository
173-
uses: actions/checkout@v4
131+
uses: actions/checkout@v5
174132
with:
175133
fetch-depth: 0
176134

@@ -179,17 +137,13 @@ jobs:
179137
run: echo "CIBW_BUILD_SANITIZED=$(echo '${{ matrix.cibw_build }}' | sed 's/\*/_/g')" >> $GITHUB_ENV
180138
shell: bash
181139

182-
- name: Set up python ${{ env.PYTHON }}
183-
uses: actions/setup-python@v5
184-
id: setup-python
185-
with:
186-
python-version: ${{ env.PYTHON }}
187-
188140
- name: Build wheels
189-
uses: pypa/cibuildwheel@v2.16.5
141+
uses: pypa/cibuildwheel@v3.2
190142
env:
191143
CIBW_ARCHS: ${{ matrix.cibw_archs }}
192144
CIBW_BUILD: ${{ matrix.cibw_build }}
145+
# x86_64 wheels are cross-compiled on arm64 runners; their tests can't run natively.
146+
CIBW_TEST_SKIP: "*-macosx_x86_64"
193147
CIBW_TEST_REQUIRES: pytest
194148
CIBW_TEST_COMMAND: pytest {package}/tests
195149

@@ -198,62 +152,6 @@ jobs:
198152
name: wheels-${{ matrix.os }}-${{ env.CIBW_BUILD_SANITIZED }}-${{ matrix.cibw_archs }}
199153
path: wheelhouse/*.whl
200154

201-
build_wheels_macos_arm64:
202-
name: "${{ matrix.os }} ${{ matrix.cibw_archs }} ${{ matrix.cibw_build }}"
203-
runs-on: ${{ matrix.os }}
204-
strategy:
205-
matrix:
206-
os: [macos-13]
207-
cibw_build: ["cp39-*", "cp310-*", "cp311-*", "cp312-*", "cp313-*"]
208-
cibw_archs: ["arm64"]
209-
210-
steps:
211-
- name: Check out repository
212-
uses: actions/checkout@v4
213-
with:
214-
fetch-depth: 0
215-
216-
- uses: actions/setup-python@v5
217-
id: setup-python
218-
with:
219-
python-version: "3.12"
220-
221-
- name: Build wheels
222-
uses: pypa/cibuildwheel@v2.16.5
223-
env:
224-
CIBW_BUILD: ${{ matrix.cibw_build }}
225-
CIBW_ARCHS: ${{ matrix.cibw_archs }}
226-
CIBW_TEST_SKIP: "*-macosx_arm64"
227-
CIBW_TEST_REQUIRES: pytest
228-
CIBW_TEST_COMMAND: pytest {package}/tests
229-
CIBW_REPAIR_WHEEL_COMMAND: |
230-
echo "Target delocate archs: {delocate_archs}"
231-
232-
ORIGINAL_WHEEL={wheel}
233-
234-
echo "Running delocate-listdeps to list linked original wheel dependencies"
235-
delocate-listdeps --all $ORIGINAL_WHEEL
236-
237-
echo "Renaming .whl file when architecture is 'macosx_arm64'"
238-
RENAMED_WHEEL=${ORIGINAL_WHEEL//x86_64/arm64}
239-
240-
echo "Wheel will be renamed to $RENAMED_WHEEL"
241-
mv $ORIGINAL_WHEEL $RENAMED_WHEEL
242-
243-
echo "Running delocate-wheel command on $RENAMED_WHEEL"
244-
delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v $RENAMED_WHEEL
245-
246-
echo "Running delocate-listdeps to list linked wheel dependencies"
247-
WHEEL_SIMPLE_FILENAME="${RENAMED_WHEEL##*/}"
248-
delocate-listdeps --all {dest_dir}/$WHEEL_SIMPLE_FILENAME
249-
250-
echo "DONE."
251-
252-
- uses: actions/upload-artifact@v4
253-
with:
254-
name: wheels-${{ matrix.os }}-${{ matrix.cibw_build }}-${{ matrix.cibw_archs }}
255-
path: ./wheelhouse/*.whl
256-
257155
upload_to_pypi:
258156
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/v')
259157
needs:
@@ -262,9 +160,12 @@ jobs:
262160
"build_wheels_windows",
263161
"build_wheels_linux",
264162
"build_wheels_macos",
265-
"build_wheels_macos_arm64",
266163
]
267164
runs-on: ubuntu-latest
165+
environment: pypi
166+
permissions:
167+
# Required for PyPI Trusted Publishing (OIDC); no API token needed.
168+
id-token: write
268169
steps:
269170
- uses: actions/download-artifact@v4
270171
with:
@@ -274,6 +175,5 @@ jobs:
274175

275176
- uses: pypa/gh-action-pypi-publish@release/v1
276177
with:
277-
password: ${{ secrets.PYPI_TOKEN }}
278-
packages_dir: wheels/
279-
skip_existing: true
178+
packages-dir: wheels/
179+
skip-existing: true

0 commit comments

Comments
 (0)