Skip to content

Commit d1b9c50

Browse files
authored
Merge pull request #29 from SimVascular/pure-python-install
Pure python install
2 parents 6954157 + f85acc2 commit d1b9c50

File tree

26 files changed

+1618
-184
lines changed

26 files changed

+1618
-184
lines changed

.github/workflows/test-upload.yml

Lines changed: 69 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,39 +13,28 @@ on:
1313
- "false"
1414

1515
jobs:
16-
build_wheels:
17-
# We'll build on a matrix of OSes and Python versions.
18-
runs-on: ${{ matrix.os }}
19-
strategy:
20-
matrix:
21-
os: [macOS-latest, ubuntu-latest, windows-latest]
22-
env:
23-
CIBW_BUILD: "cp39-* cp310-* cp311-* cp312-*"
24-
CIBW_ENVIRONMENT: "PIP_NO_CACHE_DIR=1"
25-
CIBW_BUILD_VERBOSITY: 3
26-
16+
build_base_wheel:
17+
# Build the pure-Python wheel once (no platform matrix needed)
18+
runs-on: ubuntu-latest
2719
steps:
2820
- name: Check out code
2921
uses: actions/checkout@v4
3022

3123
- name: Install build dependencies
3224
run: |
33-
pip install --upgrade pip && pip install cibuildwheel twine
25+
pip install --upgrade pip && pip install build
3426
35-
- name: Upgrade pip, setuptools, wheel
36-
run: python -m pip install --upgrade setuptools wheel
27+
- name: Build base wheel (pure-Python svv)
28+
run: python -m build --wheel --outdir dist
3729

38-
- name: Build wheels
39-
run: cibuildwheel --output-dir dist
40-
41-
- name: Upload artifacts
30+
- name: Upload base wheel artifact
4231
uses: actions/upload-artifact@v4
4332
with:
44-
name: cibw-wheels-${{ matrix.os }}
45-
path: dist
33+
name: base-wheel
34+
path: dist/*.whl
4635

4736
build_sdist:
48-
needs: [build_wheels]
37+
needs: [build_base_wheel]
4938
runs-on: ubuntu-latest
5039
steps:
5140
- uses: actions/checkout@v4
@@ -62,23 +51,70 @@ jobs:
6251
name: cibw-sdist
6352
path: dist/*.tar.gz
6453

65-
upload_testpypi:
66-
needs: [build_wheels, build_sdist]
54+
55+
build_wheels_accelerated:
56+
runs-on: ${{ matrix.os }}
57+
strategy:
58+
matrix:
59+
os: [macOS-latest, ubuntu-latest, windows-latest]
60+
env:
61+
CIBW_BUILD: "cp39-* cp310-* cp311-* cp312-*"
62+
CIBW_BUILD_VERBOSITY: 3
63+
# Install build deps before building each wheel (use python -m pip for Windows compatibility)
64+
CIBW_BEFORE_BUILD: "python -m pip install -U pip setuptools wheel cython numpy cmake"
65+
# Tell setup.py to build the companion 'svv-accelerated' distribution
66+
CIBW_ENVIRONMENT: "PIP_NO_CACHE_DIR=1 SVV_ACCEL_COMPANION=1"
67+
steps:
68+
- name: Check out code
69+
uses: actions/checkout@v4
70+
71+
- name: Install cibuildwheel
72+
run: pip install --upgrade pip && pip install cibuildwheel
73+
74+
- name: Build wheels (svv-accelerated)
75+
run: cibuildwheel --output-dir dist
76+
77+
- name: Upload artifacts
78+
uses: actions/upload-artifact@v4
79+
with:
80+
name: cibw-wheels-accelerated-${{ matrix.os }}
81+
path: dist
82+
83+
upload_testpypi_all:
84+
needs: [build_base_wheel, build_wheels_accelerated, build_sdist]
6785
runs-on: ubuntu-latest
68-
steps:
86+
steps:
6987
- uses: actions/download-artifact@v4
7088
with:
71-
# unpacks all CIBW artifacts into dist/
72-
pattern: cibw-*
89+
# download all artifacts from previous jobs (base wheel, sdist, accelerated wheels)
90+
pattern: '*'
7391
path: dist
7492
merge-multiple: true
75-
76-
- name: Install build dependencies
93+
- name: Install twine
94+
run: pip install --upgrade pip && pip install twine
95+
- name: Validate TestPyPI token (svv)
96+
if: ${{ hashFiles('dist/svv-*-py3-none-any.whl') != '' || hashFiles('dist/svv-*.tar.gz') != '' }}
7797
run: |
78-
pip install --upgrade pip && pip install twine
79-
80-
- name: Upload to TestPyPI
81-
run: twine upload --repository testpypi dist/*
98+
if [ -z "${{ secrets.TEST_PYPI_PASSWORD_SVV }}" ]; then
99+
echo "::error title=Missing secret::The repository secret 'TEST_PYPI_PASSWORD_SVV' is not configured. Set it to a TestPyPI API token with access to the 'svv' project.";
100+
exit 1;
101+
fi
102+
- name: Upload base package (svv) to TestPyPI
103+
if: ${{ hashFiles('dist/svv-*-py3-none-any.whl') != '' || hashFiles('dist/svv-*.tar.gz') != '' }}
104+
run: twine upload --non-interactive --skip-existing --verbose --repository testpypi dist/svv-*-py3-none-any.whl dist/svv-*.tar.gz
105+
env:
106+
TWINE_USERNAME: __token__
107+
TWINE_PASSWORD: ${{ secrets.TEST_PYPI_PASSWORD_SVV }}
108+
- name: Validate TestPyPI token (svv-accelerated)
109+
if: ${{ hashFiles('dist/svv-accelerated-*.whl') != '' }}
110+
run: |
111+
if [ -z "${{ secrets.TEST_PYPI_PASSWORD_ACCEL }}" ]; then
112+
echo "::error title=Missing secret::The repository secret 'TEST_PYPI_PASSWORD_ACCEL' is not configured. Set it to a TestPyPI API token with access to the 'svv-accelerated' project.";
113+
exit 1;
114+
fi
115+
- name: Upload accelerated wheels (svv-accelerated) to TestPyPI
116+
if: ${{ hashFiles('dist/svv-accelerated-*.whl') != '' }}
117+
run: twine upload --non-interactive --skip-existing --verbose --repository testpypi dist/svv-accelerated-*.whl
82118
env:
83119
TWINE_USERNAME: __token__
84-
TWINE_PASSWORD: ${{ secrets.TEST_PYPI_PASSWORD }}
120+
TWINE_PASSWORD: ${{ secrets.TEST_PYPI_PASSWORD_ACCEL }}

.github/workflows/upload.yml

Lines changed: 96 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,39 +13,57 @@ on:
1313
- "false"
1414

1515
jobs:
16-
build_wheels:
17-
# We'll build on a matrix of OSes and Python versions.
16+
build_base_wheel:
17+
# Build the pure-Python wheel once (no platform matrix needed)
18+
runs-on: ubuntu-latest
19+
steps:
20+
- name: Check out code
21+
uses: actions/checkout@v4
22+
23+
- name: Install build dependencies
24+
run: |
25+
pip install --upgrade pip && pip install build
26+
27+
- name: Build base wheel (pure-Python svv)
28+
run: python -m build --wheel --outdir dist
29+
30+
- name: Upload base wheel artifact
31+
uses: actions/upload-artifact@v4
32+
with:
33+
name: base-wheel
34+
path: dist/*.whl
35+
36+
build_wheels_accelerated:
1837
runs-on: ${{ matrix.os }}
1938
strategy:
2039
matrix:
2140
os: [macOS-latest, ubuntu-latest, windows-latest]
2241
env:
2342
CIBW_BUILD: "cp39-* cp310-* cp311-* cp312-*"
24-
CIBW_ENVIRONMENT: "PIP_NO_CACHE_DIR=1"
2543
CIBW_BUILD_VERBOSITY: 3
44+
# Install build deps before building each wheel (use python -m pip for Windows compatibility)
45+
CIBW_BEFORE_BUILD: "python -m pip install -U pip setuptools wheel cython numpy cmake"
46+
# Tell setup.py to build the companion 'svv-accelerated' distribution
47+
CIBW_ENVIRONMENT: "PIP_NO_CACHE_DIR=1 SVV_ACCEL_COMPANION=1"
2648

2749
steps:
2850
- name: Check out code
2951
uses: actions/checkout@v4
3052

31-
- name: Install build dependencies
32-
run: |
33-
pip install --upgrade pip && pip install cibuildwheel twine
34-
35-
- name: Upgrade pip, setuptools, wheel
36-
run: python -m pip install --upgrade setuptools wheel
53+
- name: Install cibuildwheel
54+
run: pip install --upgrade pip && pip install cibuildwheel
3755

38-
- name: Build wheels
56+
- name: Build wheels (svv-accelerated)
3957
run: cibuildwheel --output-dir dist
4058

4159
- name: Upload artifacts
4260
uses: actions/upload-artifact@v4
4361
with:
44-
name: cibw-wheels-${{ matrix.os }}
62+
name: cibw-wheels-accelerated-${{ matrix.os }}
4563
path: dist
4664

4765
build_sdist:
48-
needs: [build_wheels]
66+
needs: [build_base_wheel]
4967
runs-on: ubuntu-latest
5068
steps:
5169
- uses: actions/checkout@v4
@@ -63,22 +81,82 @@ jobs:
6381
path: dist/*.tar.gz
6482

6583
upload_pypi:
66-
needs: [build_wheels, build_sdist]
84+
needs: [build_base_wheel, build_wheels_accelerated, build_sdist]
6785
runs-on: ubuntu-latest
86+
permissions:
87+
contents: write
6888
steps:
6989
- uses: actions/download-artifact@v4
7090
with:
71-
# unpacks all CIBW artifacts into dist/
72-
pattern: cibw-*
91+
# download all artifacts from previous jobs (base wheels, sdist, accelerated wheels)
92+
pattern: '*'
7393
path: dist
7494
merge-multiple: true
7595

7696
- name: Install build dependencies
7797
run: |
7898
pip install --upgrade pip && pip install twine
7999
80-
- name: Upload to PyPI
81-
run: twine upload --repository pypi dist/*
100+
- name: Upload base package (svv) to PyPI
101+
run: |
102+
set -euo pipefail
103+
files=$(ls dist/svv-*.whl dist/svv-*.tar.gz 2>/dev/null | grep -v 'svv-accelerated' || true)
104+
if [ -z "$files" ]; then
105+
echo "No base svv artifacts found; skipping upload."
106+
exit 0
107+
fi
108+
if [ -z "${{ secrets.PYPI_PASSWORD_SVV }}" ]; then
109+
echo "::error title=Missing secret::The repository secret 'PYPI_PASSWORD_SVV' is not configured. Set it to a PyPI API token with access to the 'svv' project.";
110+
exit 1
111+
fi
112+
twine upload --non-interactive --skip-existing --verbose --repository pypi $files
113+
env:
114+
TWINE_USERNAME: __token__
115+
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD_SVV }}
116+
117+
- name: Upload accelerated wheels (svv-accelerated) to PyPI
118+
run: |
119+
set -euo pipefail
120+
files=$(ls dist/svv-accelerated-*.whl 2>/dev/null || true)
121+
if [ -z "$files" ]; then
122+
echo "No svv-accelerated artifacts found; skipping upload."
123+
exit 0
124+
fi
125+
if [ -z "${{ secrets.PYPI_PASSWORD_ACCEL }}" ]; then
126+
echo "::error title=Missing secret::The repository secret 'PYPI_PASSWORD_ACCEL' is not configured. Set it to a PyPI API token with access to the 'svv-accelerated' project.";
127+
exit 1
128+
fi
129+
twine upload --non-interactive --skip-existing --verbose --repository pypi $files
82130
env:
83131
TWINE_USERNAME: __token__
84-
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
132+
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD_ACCEL }}
133+
134+
- name: Extract version from artifacts
135+
id: extract_version
136+
run: |
137+
set -euo pipefail
138+
file=$(ls dist/svv-*-py3-none-any.whl 2>/dev/null || true)
139+
if [ -z "$file" ]; then
140+
file=$(ls dist/svv-*.tar.gz 2>/dev/null | head -n1 || true)
141+
fi
142+
if [ -z "$file" ]; then
143+
echo "::error title=Version detection failed::No base svv artifact found to determine version."; exit 1
144+
fi
145+
base=$(basename "$file")
146+
# Extract version after 'svv-' up to next '-'
147+
version=$(echo "$base" | sed -E 's/^svv-([^\-]+).*/\1/')
148+
echo "Detected version: $version"
149+
echo "version=$version" >> "$GITHUB_OUTPUT"
150+
151+
- name: Create GitHub Release and upload artifacts
152+
uses: softprops/action-gh-release@v2
153+
with:
154+
tag_name: ${{ steps.extract_version.outputs.version }}
155+
name: svv ${{ steps.extract_version.outputs.version }}
156+
generate_release_notes: true
157+
draft: false
158+
prerelease: false
159+
files: |
160+
dist/svv-*.whl
161+
dist/svv-*.tar.gz
162+
dist/svv-accelerated-*.whl

MANIFEST.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,6 @@ recursive-include svv/bin *
1919
include svv/utils/remeshing/Windows/mmg2d_O3.exe
2020
include svv/utils/remeshing/Windows/mmg3d_O3.exe
2121
include svv/utils/remeshing/Windows/mmgs_O3.exe
22+
23+
# Exclude any compiled extension artifacts from source distribution
24+
global-exclude *.so *.pyd *.dylib *.dll

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ biomanufacturing applications or computational fluid dynamic (CFD) analysis.
1818

1919
* **Website:** https://simvascular.github.io/svVascularize/
2020
* **PyPi:** https://pypi.org/project/svv/
21-
* **Source code:** https://github.com/zasexton/svVascularize
21+
* **Source code:** https://github.com/SimVascular/svVascularize

docs/install.html

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,39 @@ <h2>Installing with <code>pip</code></h2>
120120
<code>svv</code> and other python packages you might already use
121121
or need later.
122122
</div>
123+
124+
<h3>Choose pure‑Python or accelerated</h3>
125+
<p>svVascularize runs entirely in pure Python, but ships optional C/Cython
126+
accelerators for heavier routines. You can select either experience at
127+
install time:</p>
128+
<ul>
129+
<li><strong>Pure‑Python (default):</strong>
130+
<pre data-copy><code class="language-shell">pip install svv</code></pre>
131+
<em>No compiler required.</em> All performance‑critical paths have
132+
Python fallbacks.</li>
133+
<li><strong>Accelerated (prebuilt extensions):</strong>
134+
<pre data-copy><code class="language-shell">pip install "svv[accel]"</code></pre>
135+
The <code>[accel]</code> extra pulls in a small companion wheel,
136+
<code>svv-accelerated</code>, which contains compiled accelerators.
137+
When present, <code>svv</code> automatically prefers those modules.
138+
</li>
139+
</ul>
140+
141+
<div class="callout info">
142+
<strong>Advanced (optional):</strong> To force a local from‑source build
143+
of extensions instead of using the companion wheel, set the env var
144+
and ask pip to build from source:
145+
<pre data-copy><code class="language-shell">SVV_BUILD_EXTENSIONS=1 pip install --no-binary svv "svv[accel]"</code></pre>
146+
This requires a C++17 tool‑chain, CMake, Cython, and NumPy headers.
147+
</div>
148+
149+
<h3>Verify which backend is active</h3>
150+
<pre data-copy><code class="language-python">import importlib
151+
m = importlib.import_module('svv.tree.utils.c_local_optimize')
152+
print(getattr(m, '__file__', '&lt;builtin&gt;'))
153+
</code></pre>
154+
<p>If you see a <code>.so</code>/<code>.pyd</code> path, the accelerated backend
155+
is active. A <code>.py</code> path indicates the pure‑Python fallback.</p>
123156
</section>
124157

125158
<!-- CONDA -->

pyproject.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
requires = [
33
"setuptools>=45.0",
44
"wheel>=0.36; python_version < '3.12' ",
5-
"cython>=3.0.7",
6-
"numpy",
7-
"cmake>=3.15"
5+
# Ensure PEP 517 build environments have the headers/tools needed to compile extensions
6+
"Cython>=3.0.7",
7+
"numpy>=1.22"
88
]
99

1010
build-backend = "setuptools.build_meta"

requirements.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ usearch
66
scikit-image
77
tetgen
88
trimesh[all]
9-
hnswlib
109
pyvista~=0.44.2
1110
scikit-learn
1211
tqdm

0 commit comments

Comments
 (0)