Skip to content

Commit 57ceac4

Browse files
authored
preparing for v1.0.0 pypi release (#90)
This PR prepares OceanMesh for its v1.0.0 PyPI release by introducing comprehensive CI/CD infrastructure for wheel building and publishing, refactoring build configuration to support multiple platforms, and improving code maintainability through function extraction and test simplification. Key Changes: Introduces automated wheel building and PyPI publishing workflows for macOS (including Apple Silicon support) Refactors build system to use environment-based dependency detection instead of hardcoded paths Extracts large monolithic functions into smaller helper functions for better maintainability
1 parent b9bc6a9 commit 57ceac4

File tree

16 files changed

+1990
-803
lines changed

16 files changed

+1990
-803
lines changed

.github/workflows/ci.yml

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
name: ci
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- master
8+
tags-ignore:
9+
- "v*"
10+
- "test-v*"
11+
12+
jobs:
13+
tox_tests:
14+
name: Tox tests (ubuntu, py${{ matrix.py }})
15+
runs-on: ubuntu-latest
16+
env:
17+
OCEANMESH_REQUIRE_INPOLY_ACCEL: "1"
18+
OCEANMESH_INPOLY_ACCEL_DEBUG: "1"
19+
OCEANMESH_INPOLY_ACCEL: "1"
20+
OCEANMESH_INPOLY_METHOD: ""
21+
strategy:
22+
fail-fast: false
23+
matrix:
24+
include:
25+
- py: "310"
26+
python-version: "3.10"
27+
toxenv: "py310"
28+
- py: "311"
29+
python-version: "3.11"
30+
toxenv: "py311"
31+
- py: "312"
32+
python-version: "3.12"
33+
toxenv: "py312"
34+
- py: "313"
35+
python-version: "3.13"
36+
toxenv: "py313"
37+
38+
steps:
39+
- uses: actions/checkout@v4
40+
41+
- name: Set up Python
42+
uses: actions/setup-python@v5
43+
with:
44+
python-version: ${{ matrix.python-version }}
45+
46+
- name: Install system build deps
47+
run: |
48+
sudo apt-get update
49+
sudo apt-get install -y \
50+
libgmp-dev \
51+
libmpfr-dev \
52+
libcgal-dev \
53+
libopenmpi3 \
54+
libopenmpi-dev \
55+
openmpi-bin \
56+
libhdf5-dev
57+
58+
- name: Install Python build dependencies
59+
run: |
60+
python -m pip install --upgrade pip
61+
python -m pip install Cython numpy
62+
63+
- name: Verify Cython inpoly kernel is available
64+
env:
65+
OCEANMESH_INPOLY_ACCEL: "1"
66+
run: |
67+
python -m pip install -e .
68+
python - << 'PY'
69+
import os, importlib
70+
from oceanmesh.geometry import point_in_polygon as pip
71+
72+
os.environ.pop("OCEANMESH_INPOLY_METHOD", None)
73+
os.environ["OCEANMESH_INPOLY_ACCEL"] = "1"
74+
pip = importlib.reload(pip)
75+
76+
if not getattr(pip, "_COMPILED_KERNEL_AVAILABLE", False):
77+
raise SystemExit("Cython inpoly2 kernel not available in CI environment")
78+
79+
print("_COMPILED_KERNEL_AVAILABLE =", pip._COMPILED_KERNEL_AVAILABLE)
80+
from oceanmesh.geometry.point_in_polygon_ import inpoly2_fast
81+
print("inpoly2_fast:", inpoly2_fast)
82+
PY
83+
84+
- name: Install tox
85+
run: |
86+
python -m pip install tox
87+
88+
- name: Run tests
89+
run: |
90+
tox -e "${{ matrix.toxenv }}" -- -q
91+
92+
build_wheels:
93+
name: Build wheels (${{ matrix.os }})
94+
runs-on: ${{ matrix.os }}
95+
strategy:
96+
fail-fast: false
97+
matrix:
98+
os: [macos-latest]
99+
100+
steps:
101+
- uses: actions/checkout@v4
102+
103+
- name: Set up Python
104+
uses: actions/setup-python@v5
105+
with:
106+
python-version: "3.12"
107+
108+
- name: Install build tooling
109+
run: |
110+
python -m pip install --upgrade pip
111+
python -m pip install cibuildwheel==2.*
112+
113+
# Build dependencies (CGAL headers + GMP/MPFR libs) into a local prefix via micromamba.
114+
# The wheel build will link against these, and repair tools will bundle the runtime libs.
115+
- name: Install micromamba (Unix)
116+
if: runner.os != 'Windows'
117+
shell: bash
118+
run: |
119+
set -euxo pipefail
120+
if [ "${RUNNER_OS}" = "macOS" ]; then
121+
if [ "$(uname -m)" = "arm64" ]; then
122+
MAMBA_PLATFORM="osx-arm64"
123+
else
124+
MAMBA_PLATFORM="osx-64"
125+
fi
126+
else
127+
MAMBA_PLATFORM="linux-64"
128+
fi
129+
130+
curl -Ls "https://micro.mamba.pm/api/micromamba/${MAMBA_PLATFORM}/latest" -o micromamba.tar.bz2
131+
tar -xjf micromamba.tar.bz2 bin/micromamba
132+
sudo mv bin/micromamba /usr/local/bin/micromamba
133+
134+
- name: Install micromamba (Windows)
135+
if: runner.os == 'Windows'
136+
shell: pwsh
137+
run: |
138+
Invoke-WebRequest -Uri "https://micro.mamba.pm/api/micromamba/win-64/latest" -OutFile micromamba.tar.bz2
139+
tar -xjf micromamba.tar.bz2
140+
echo "${PWD}\\Library\\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
141+
142+
- name: Build wheels
143+
env:
144+
# Use a local prefix so setup.py can find include/lib without relying on system installs.
145+
# cibuildwheel will run these on the build machine (and inside manylinux containers on Linux).
146+
CIBW_MANYLINUX_X86_64_IMAGE: quay.io/pypa/manylinux_2_34_x86_64:2025.04.19-1
147+
CIBW_ENVIRONMENT: "OCEANMESH_PREFIX=/opt/om"
148+
CIBW_ENVIRONMENT_MACOS: "OCEANMESH_PREFIX=$HOME/om"
149+
CIBW_REPAIR_WHEEL_COMMAND_LINUX: "auditwheel -v show {wheel} && auditwheel repair -w {dest_dir} {wheel}"
150+
CIBW_BEFORE_ALL_LINUX: |
151+
set -eux
152+
curl -Ls https://micro.mamba.pm/api/micromamba/linux-64/latest -o micromamba.tar.bz2
153+
tar -xjf micromamba.tar.bz2 bin/micromamba
154+
mv bin/micromamba /usr/local/bin/micromamba
155+
micromamba create -y -p /opt/om -c conda-forge \
156+
cgal boost-cpp gmp mpfr eigen
157+
CIBW_BEFORE_ALL_MACOS: |
158+
set -eux
159+
micromamba create -y -p "$HOME/om" -c conda-forge \
160+
cgal boost-cpp gmp mpfr eigen
161+
CIBW_BEFORE_ALL_WINDOWS: |
162+
micromamba create -y -p C:\\om -c conda-forge cgal boost-cpp gmp mpfr eigen
163+
CIBW_ENVIRONMENT_WINDOWS: "OCEANMESH_PREFIX=C:\\om"
164+
# Repair wheels to bundle shared libs.
165+
CIBW_REPAIR_WHEEL_COMMAND_MACOS: "python -m pip install delocate && delocate-wheel -w {dest_dir} -v {wheel}"
166+
CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "python -m pip install delvewheel && delvewheel repair -w {dest_dir} {wheel}"
167+
run: |
168+
python -m cibuildwheel --output-dir dist
169+
170+
- name: Upload wheel artifacts
171+
uses: actions/upload-artifact@v4
172+
with:
173+
name: wheels-${{ matrix.os }}
174+
path: dist/*.whl
175+
176+
build_sdist:
177+
name: Build sdist
178+
runs-on: ubuntu-latest
179+
steps:
180+
- uses: actions/checkout@v4
181+
- uses: actions/setup-python@v5
182+
with:
183+
python-version: "3.12"
184+
- name: Build sdist
185+
run: |
186+
python -m pip install --upgrade pip
187+
python -m pip install build
188+
python -m build --sdist
189+
- name: Upload sdist artifact
190+
uses: actions/upload-artifact@v4
191+
with:
192+
name: sdist
193+
path: dist/*.tar.gz
194+
195+
smoke_test:
196+
name: Smoke test install (${{ matrix.os }})
197+
needs: [build_wheels]
198+
runs-on: ${{ matrix.os }}
199+
strategy:
200+
fail-fast: false
201+
matrix:
202+
os: [macos-latest]
203+
204+
steps:
205+
- name: Set up Python
206+
uses: actions/setup-python@v5
207+
with:
208+
python-version: "3.12"
209+
210+
- name: Download wheel artifacts
211+
uses: actions/download-artifact@v4
212+
with:
213+
name: wheels-${{ matrix.os }}
214+
path: dist
215+
216+
- name: Install wheel into fresh venv and import
217+
shell: bash
218+
run: |
219+
set -euxo pipefail
220+
python -m venv .venv
221+
if [ -f .venv/bin/activate ]; then
222+
source .venv/bin/activate
223+
else
224+
source .venv/Scripts/activate
225+
fi
226+
227+
python -m pip install --upgrade pip packaging
228+
229+
python - <<'PY'
230+
import glob
231+
import os
232+
import sys
233+
import subprocess
234+
235+
from packaging import tags
236+
from packaging.utils import parse_wheel_filename
237+
238+
wheels = sorted(glob.glob(os.path.join("dist", "*.whl")))
239+
if not wheels:
240+
raise SystemExit("No wheels found in dist/")
241+
242+
supported = set(tags.sys_tags())
243+
244+
def is_compatible(wheel_path: str) -> bool:
245+
_, _, _, wheel_tags = parse_wheel_filename(os.path.basename(wheel_path))
246+
return any(t in supported for t in wheel_tags)
247+
248+
selected = next((w for w in wheels if is_compatible(w)), None)
249+
if not selected:
250+
raise SystemExit(f"No compatible wheel found. Found wheels: {wheels}")
251+
252+
print(f"Selected wheel: {selected}")
253+
subprocess.check_call([sys.executable, "-m", "pip", "install", selected])
254+
PY
255+
256+
python -c "import oceanmesh; print(oceanmesh.__version__)"
257+
python -c "import oceanmesh; oceanmesh.Region((0, 1, 0, 1), 'EPSG:4326'); print('ok')"

0 commit comments

Comments
 (0)