Skip to content

Commit 9d9c6f4

Browse files
authored
chore: modernize dev setup with uv and simplified makefile (#366)
* chore: switch to uv * fix: import for tests * docs: add a note on python version * feedback
1 parent be24c77 commit 9d9c6f4

23 files changed

+1303
-190
lines changed

.github/workflows/CI.yml

Lines changed: 54 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ on:
1010
env:
1111
MIN_PYTHON_VERSION: "3.9"
1212

13-
1413
defaults:
1514
run:
1615
# Prevents windows runners from running on powershell
@@ -20,27 +19,23 @@ jobs:
2019
lint:
2120
runs-on: ubuntu-latest
2221
steps:
23-
- uses: actions/checkout@v5
24-
- name: Set up Python
25-
uses: actions/setup-python@v5
26-
with:
27-
python-version: "${{ env.MIN_PYTHON_VERSION }}"
28-
- name: Set up rust toolchain
29-
uses: dtolnay/rust-toolchain@stable
30-
- name: Set up rustfmt
31-
run: rustup component add rustfmt
22+
- uses: actions/checkout@v5
23+
- name: Set up Python
24+
uses: actions/setup-python@v5
25+
with:
26+
python-version: "${{ env.MIN_PYTHON_VERSION }}"
27+
- name: Set up rust toolchain
28+
uses: dtolnay/rust-toolchain@stable
29+
- name: Set up rustfmt
30+
run: rustup component add rustfmt
3231

33-
# Maturin requires a venv to be activated, that's why we have to create one here
34-
- name: Create virtualenv
35-
run: |
36-
python -m venv .venv
37-
source .venv/bin/activate
38-
make install-test-requirements
32+
- name: install uv
33+
uses: astral-sh/setup-uv@v6
3934

40-
- name: Lint
41-
run: |
42-
source .venv/bin/activate
43-
make lint
35+
- name: Install dependencies and lint
36+
run: |
37+
make install
38+
make lint
4439
4540
check-docs:
4641
runs-on: ubuntu-latest
@@ -52,18 +47,11 @@ jobs:
5247
python-version: "3.11"
5348
- name: Set up rust toolchain
5449
uses: dtolnay/rust-toolchain@stable
55-
- run: |
56-
git config user.name github-actions
57-
git config user.email github-actions@github.com
58-
59-
# venv required by maturin
60-
python3 -m venv .venv
61-
source .venv/bin/activate
62-
63-
make install-test-requirements
64-
make install-doc-requirements
65-
# Required for pdoc to be able to import the sources
66-
make dev-install
50+
- name: install uv
51+
uses: astral-sh/setup-uv@v6
52+
- name: Check documentation
53+
run: |
54+
make install
6755
make doc
6856
6957
# GitHub provides only x86_64 runners, so we cannot test on arm architecture
@@ -74,29 +62,21 @@ jobs:
7462
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
7563
os: ["ubuntu-latest", "macos-14", "windows-latest"]
7664
steps:
77-
- uses: actions/checkout@v5
78-
- name: Set up Python
79-
uses: actions/setup-python@v5
80-
with:
81-
python-version: ${{ matrix.python-version }}
82-
- name: Set up rust toolchain
83-
uses: dtolnay/rust-toolchain@stable
84-
85-
# Maturin requires a venv to be activated, that's why we have to create one here
86-
- name: Create virtualenv
87-
env:
88-
BIN: ${{ matrix.os == 'windows-latest' && 'Scripts' || 'bin' }}
89-
run: |
90-
python -m venv .venv
91-
echo "${{ github.workspace }}/.venv/${{ env.BIN }}" >> $GITHUB_PATH
65+
- uses: actions/checkout@v5
66+
- name: Set up Python
67+
uses: actions/setup-python@v5
68+
with:
69+
python-version: ${{ matrix.python-version }}
70+
- name: Set up rust toolchain
71+
uses: dtolnay/rust-toolchain@stable
9272

93-
- name: Install dependencies
94-
run: |
95-
echo "PATH IS $PATH"
96-
make install-test-requirements
73+
- name: install uv
74+
uses: astral-sh/setup-uv@v6
9775

98-
- name: Test
99-
run: make test-ci
76+
- name: Install dependencies and test
77+
run: |
78+
make install
79+
make test
10080
10181
check-wheel-build:
10282
runs-on: ${{ matrix.os }}
@@ -111,28 +91,28 @@ jobs:
11191
- os: windows-latest
11292
architecture: aarch64
11393
steps:
114-
- uses: actions/checkout@v5
115-
- uses: dtolnay/rust-toolchain@stable
116-
- name: Set Rust target
117-
id: target
118-
if: matrix.os != 'windows-latest'
119-
run: |
120-
TARGET=${{ matrix.os == 'macos-14' && (matrix.architecture == 'aarch64' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin') || (matrix.architecture == 'aarch64' && 'aarch64-unknown-linux-gnu' || null) }}
121-
echo "target=$TARGET" >> $GITHUB_OUTPUT
122-
123-
- name: build (fast)
124-
uses: PyO3/maturin-action@v1
125-
with:
126-
manylinux: auto
127-
command: build
128-
args: "-o dist"
129-
target: ${{ steps.target.outputs.target }}
94+
- uses: actions/checkout@v5
95+
- uses: dtolnay/rust-toolchain@stable
96+
- name: Set Rust target
97+
id: target
98+
if: matrix.os != 'windows-latest'
99+
run: |
100+
TARGET=${{ matrix.os == 'macos-14' && (matrix.architecture == 'aarch64' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin') || (matrix.architecture == 'aarch64' && 'aarch64-unknown-linux-gnu' || null) }}
101+
echo "target=$TARGET" >> $GITHUB_OUTPUT
102+
103+
- name: build (fast)
104+
uses: PyO3/maturin-action@v1
105+
with:
106+
manylinux: auto
107+
command: build
108+
args: "-o dist"
109+
target: ${{ steps.target.outputs.target }}
130110

131-
- name: Upload wheels
132-
uses: actions/upload-artifact@v4
133-
with:
134-
name: "wheels-${{ matrix.os }}-python-${{ matrix.python-version }}-${{ matrix.architecture }}"
135-
path: dist
111+
- name: Upload wheels
112+
uses: actions/upload-artifact@v4
113+
with:
114+
name: "wheels-${{ matrix.os }}-python-${{ matrix.python-version }}-${{ matrix.architecture }}"
115+
path: dist
136116

137117
check-sdist-build:
138118
runs-on: "ubuntu-latest"

.github/workflows/docs.yml

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ jobs:
1818
python-version: "3.11"
1919
- name: Set up rust toolchain
2020
uses: dtolnay/rust-toolchain@stable
21+
- name: install uv
22+
uses: astral-sh/setup-uv@v6
2123
- run: |
2224
git config user.name github-actions
2325
git config user.email github-actions@github.com
@@ -26,14 +28,8 @@ jobs:
2628
git checkout gh-pages
2729
git merge -m 'Merge main' main
2830
29-
# venv required by maturin
30-
python3 -m venv .venv
31-
source .venv/bin/activate
32-
33-
make install-test-requirements
34-
make install-doc-requirements
35-
# Required for pdoc to be able to import the sources
36-
make dev-install
31+
# Install dependencies and build docs
32+
make install
3733
make doc
3834
3935
git add -f docs

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,5 @@ docs
1414
.vscode
1515
.idea
1616
.benchmarks
17-
uv.lock
1817
notebooks
1918
/python/tests/fixtures/~$*.xlsx

Makefile

Lines changed: 95 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,113 @@
1-
.PHONY: lint format dev-setup dev-install prod-install test install-test-requirements benchmarks
2-
3-
# Commands
4-
## Python
5-
ruff = ruff check python/ *.py
6-
format = ruff format python/ *.py
7-
mypy = mypy python/ *.py
8-
pytest = pytest -v
9-
## Rust
10-
clippy = cargo clippy
11-
fmt = cargo fmt
12-
cargo-test = cargo test --no-default-features --features tests
13-
## Docs
14-
pdoc = pdoc -o docs python/fastexcel
1+
.DEFAULT_GOAL := all
2+
sources = python/fastexcel python/tests
153

16-
lint-python:
17-
$(ruff)
18-
$(format) --check --diff
19-
$(mypy)
4+
export CARGO_TERM_COLOR=$(shell (test -t 0 && echo "always") || echo "auto")
205

21-
lint-rust:
22-
$(clippy)
6+
.PHONY: .uv ## Check that uv is installed
7+
.uv:
8+
@uv -V || echo 'Please install uv: https://docs.astral.sh/uv/getting-started/installation/'
239

24-
lint: lint-rust lint-python
10+
.PHONY: install ## Install the package & dependencies with debug build
11+
install: .uv
12+
uv sync --frozen --group all
13+
uv run maturin develop --uv -E pandas,polars
2514

26-
format-python:
27-
$(ruff) --fix
28-
$(format)
15+
.PHONY: install-prod ## Install the package & dependencies with release build
16+
install-prod: .uv
17+
uv sync --frozen --group all
18+
uv run maturin develop --uv --release -E pandas,polars
2919

30-
format-rust:
31-
$(fmt)
32-
$(clippy) --fix --lib -p fastexcel --allow-dirty --allow-staged
20+
.PHONY: setup-dev ## First-time setup: install + pre-commit hooks
21+
setup-dev: install
22+
uv run pre-commit install --install-hooks
3323

34-
format: format-rust format-python
24+
.PHONY: rebuild-lockfiles ## Rebuild lockfiles from scratch, updating all dependencies
25+
rebuild-lockfiles: .uv
26+
uv lock --upgrade
27+
cargo update
3528

36-
install-build-requirements:
37-
pip install -U -r build-requirements.txt
29+
.PHONY: build-dev ## Build the development version of the package
30+
build-dev:
31+
uv run maturin develop --uv -E pandas,polars
3832

39-
install-test-requirements: install-build-requirements
40-
uv pip install -U -r test-requirements.txt
33+
.PHONY: build-wheel ## Build production wheel and install it
34+
build-wheel:
35+
@rm -rf target/wheels/
36+
uv run maturin build --release
37+
@wheel=$$(ls target/wheels/*.whl); uv pip install --force-reinstall "$$wheel[pandas,polars]"
4138

42-
install-doc-requirements: install-build-requirements
43-
uv pip install -r doc-requirements.txt
39+
.PHONY: lint-python ## Lint python source files
40+
lint-python:
41+
uv run ruff check $(sources)
42+
uv run ruff format --check $(sources)
43+
uv run mypy $(sources)
4444

45-
dev-setup: install-test-requirements install-doc-requirements
46-
pre-commit install
45+
.PHONY: lint-rust ## Lint rust source files
46+
lint-rust:
47+
cargo fmt --all -- --check
48+
cargo clippy
4749

48-
dev-install:
49-
maturin develop --uv -E pandas,polars
50+
.PHONY: lint ## Lint rust and python source files
51+
lint: lint-python lint-rust
5052

51-
prod-install:
52-
./prod_install.sh
53+
.PHONY: format-python ## Auto-format python source files
54+
format-python:
55+
uv run ruff check --fix $(sources)
56+
uv run ruff format $(sources)
5357

54-
test-rust:
55-
$(cargo-test)
58+
.PHONY: format-rust ## Auto-format rust source files
59+
format-rust:
60+
cargo fmt
61+
cargo clippy --fix --lib -p fastexcel --allow-dirty --allow-staged
5662

57-
test-python:
58-
$(pytest)
63+
.PHONY: format ## Auto-format python and rust source files
64+
format: format-rust format-python
5965

60-
test: test-rust test-python
66+
.PHONY: test-python ## Run python tests
67+
test-python: build-dev
68+
uv run pytest
6169

62-
doc:
63-
$(pdoc)
70+
.PHONY: test-rust ## Run rust tests
71+
test-rust:
72+
cargo test --no-default-features --features tests
6473

65-
test-ci: dev-install test
74+
.PHONY: test ## Run all tests
75+
test: test-rust test-python
6676

67-
benchmarks: prod-install
68-
pytest ./python/tests/benchmarks/speed.py
77+
.PHONY: doc-serve ## Serve documentation with live reload
78+
doc-serve: build-dev
79+
uv run pdoc python/fastexcel
80+
81+
.PHONY: doc ## Build documentation
82+
doc: build-dev
83+
uv run pdoc -o docs python/fastexcel
84+
85+
.PHONY: all ## Run the standard set of checks performed in CI
86+
all: format build-dev lint test
87+
88+
.PHONY: benchmarks ## Run benchmarks
89+
benchmarks: build-wheel
90+
uv run pytest ./python/tests/benchmarks/speed.py
91+
92+
.PHONY: clean ## Clear local caches and build artifacts
93+
clean:
94+
rm -rf `find . -name __pycache__`
95+
rm -f `find . -type f -name '*.py[co]' `
96+
rm -f `find . -type f -name '*~' `
97+
rm -f `find . -type f -name '.*~' `
98+
rm -rf .cache
99+
rm -rf htmlcov
100+
rm -rf .pytest_cache
101+
rm -rf *.egg-info
102+
rm -f .coverage
103+
rm -f .coverage.*
104+
rm -rf build
105+
rm -rf perf.data*
106+
rm -rf python/fastexcel/*.so
107+
108+
.PHONY: help ## Display this message
109+
help:
110+
@grep -E \
111+
'^.PHONY: .*?## .*$$' $(MAKEFILE_LIST) | \
112+
sort | \
113+
awk 'BEGIN {FS = ".PHONY: |## "}; {printf "\033[36m%-19s\033[0m %s\n", $$2, $$3}'

0 commit comments

Comments
 (0)