odx 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- odx-0.1.1/.github/workflows/ci.yml +90 -0
- odx-0.1.1/.github/workflows/release.yml +312 -0
- odx-0.1.1/.gitignore +55 -0
- odx-0.1.1/Cargo.lock +2179 -0
- odx-0.1.1/Cargo.toml +66 -0
- odx-0.1.1/LICENSE-APACHE +209 -0
- odx-0.1.1/LICENSE-MIT +29 -0
- odx-0.1.1/LICENSE-MRTRIX +403 -0
- odx-0.1.1/LICENSE-NIBABEL +60 -0
- odx-0.1.1/PKG-INFO +102 -0
- odx-0.1.1/README.md +81 -0
- odx-0.1.1/SPECIFICATION.md +440 -0
- odx-0.1.1/TODO.md +275 -0
- odx-0.1.1/assets/dsistudio_odf8_faces.txt +1280 -0
- odx-0.1.1/assets/dsistudio_odf8_vertices.txt +642 -0
- odx-0.1.1/benches/dsistudio_io.rs +71 -0
- odx-0.1.1/benches/sphere_lookup.rs +61 -0
- odx-0.1.1/docs/cli.md +297 -0
- odx-0.1.1/docs/compare.md +221 -0
- odx-0.1.1/docs/dsistudio_mrtrix_conversion_workflows.md +171 -0
- odx-0.1.1/docs/fixel_qc.md +227 -0
- odx-0.1.1/examples/check_rotation.rs +135 -0
- odx-0.1.1/examples/convert_dsistudio.rs +31 -0
- odx-0.1.1/examples/convert_mrtrix_to_fz.rs +156 -0
- odx-0.1.1/examples/inspect_h5.rs +62 -0
- odx-0.1.1/odx/__init__.py +53 -0
- odx-0.1.1/odx/adapters/__init__.py +7 -0
- odx-0.1.1/odx/adapters/dipy.py +300 -0
- odx-0.1.1/odx/spheres.py +23 -0
- odx-0.1.1/pyproject.toml +66 -0
- odx-0.1.1/python/.cargo/config.toml +14 -0
- odx-0.1.1/python/Cargo.toml +21 -0
- odx-0.1.1/python/README.md +66 -0
- odx-0.1.1/python/src/lib.rs +1412 -0
- odx-0.1.1/python/tests/test_basic.py +218 -0
- odx-0.1.1/python/tests/test_dipy_adapter.py +120 -0
- odx-0.1.1/python/tests/test_foreign_io.py +121 -0
- odx-0.1.1/python/tests/test_peak_finder.py +100 -0
- odx-0.1.1/setting_up_cs_and_benchmarking.md +185 -0
- odx-0.1.1/src/bin/odx.rs +1127 -0
- odx-0.1.1/src/cli_support.rs +610 -0
- odx-0.1.1/src/compare.rs +728 -0
- odx-0.1.1/src/data_array.rs +133 -0
- odx-0.1.1/src/densify.rs +299 -0
- odx-0.1.1/src/descoteaux_sh.rs +876 -0
- odx-0.1.1/src/dtype.rs +152 -0
- odx-0.1.1/src/error.rs +30 -0
- odx-0.1.1/src/formats/dsistudio.rs +975 -0
- odx-0.1.1/src/formats/dsistudio_odf8.rs +65 -0
- odx-0.1.1/src/formats/mat4.rs +375 -0
- odx-0.1.1/src/formats/mif.rs +411 -0
- odx-0.1.1/src/formats/mod.rs +8 -0
- odx-0.1.1/src/formats/mrtrix.rs +1839 -0
- odx-0.1.1/src/formats/pam.rs +909 -0
- odx-0.1.1/src/formats/pam_repulsion724_hemisphere_f32.bin +0 -0
- odx-0.1.1/src/formats/pyafq_aodf.rs +300 -0
- odx-0.1.1/src/formats/tortoise_mapmri.rs +719 -0
- odx-0.1.1/src/header.rs +239 -0
- odx-0.1.1/src/interop.rs +672 -0
- odx-0.1.1/src/io/archive_edit.rs +357 -0
- odx-0.1.1/src/io/directory.rs +634 -0
- odx-0.1.1/src/io/filename.rs +90 -0
- odx-0.1.1/src/io/mod.rs +117 -0
- odx-0.1.1/src/io/zip.rs +463 -0
- odx-0.1.1/src/lib.rs +58 -0
- odx-0.1.1/src/mmap_backing.rs +71 -0
- odx-0.1.1/src/mrtrix_sh.rs +822 -0
- odx-0.1.1/src/nifti_canon.rs +374 -0
- odx-0.1.1/src/odx_file.rs +540 -0
- odx-0.1.1/src/peak_finder.rs +774 -0
- odx-0.1.1/src/qc.rs +871 -0
- odx-0.1.1/src/reference_affine.rs +376 -0
- odx-0.1.1/src/sh_basis_evaluator.rs +354 -0
- odx-0.1.1/src/sphere_lookup.rs +290 -0
- odx-0.1.1/src/stream.rs +526 -0
- odx-0.1.1/src/transform/mod.rs +142 -0
- odx-0.1.1/src/transform/resample.rs +548 -0
- odx-0.1.1/src/transform/sh_apsf.rs +302 -0
- odx-0.1.1/src/transform/source_volume.rs +214 -0
- odx-0.1.1/src/typed_view.rs +44 -0
- odx-0.1.1/src/validate.rs +286 -0
- odx-0.1.1/tests/archive_mutation.rs +161 -0
- odx-0.1.1/tests/cli.rs +675 -0
- odx-0.1.1/tests/fibgz_round_trip.rs +317 -0
- odx-0.1.1/tests/interop.rs +270 -0
- odx-0.1.1/tests/mif_reader.rs +74 -0
- odx-0.1.1/tests/mrtrix_io.rs +291 -0
- odx-0.1.1/tests/pam_io.rs +183 -0
- odx-0.1.1/tests/qc.rs +467 -0
- odx-0.1.1/tests/round_trip.rs +245 -0
- odx-0.1.1/tests/transform.rs +306 -0
- odx-0.1.1/tests/transform_mrtrix_compat.rs +264 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
# Cancel in-flight runs when a new commit is pushed to the same PR/branch.
|
|
10
|
+
concurrency:
|
|
11
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
12
|
+
cancel-in-progress: true
|
|
13
|
+
|
|
14
|
+
env:
|
|
15
|
+
CARGO_TERM_COLOR: always
|
|
16
|
+
RUST_BACKTRACE: 1
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
rust-tests:
|
|
20
|
+
name: Rust tests (${{ matrix.os }})
|
|
21
|
+
runs-on: ${{ matrix.os }}
|
|
22
|
+
strategy:
|
|
23
|
+
fail-fast: false
|
|
24
|
+
matrix:
|
|
25
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v4
|
|
28
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
29
|
+
- uses: Swatinem/rust-cache@v2
|
|
30
|
+
|
|
31
|
+
# Build only the odx-rs core here. odx-py is a Python cdylib whose
|
|
32
|
+
# link step needs `-undefined dynamic_lookup` on macOS (configured in
|
|
33
|
+
# python/.cargo/config.toml, only visible when cargo runs from
|
|
34
|
+
# python/). The actual cdylib build happens in the python-tests job
|
|
35
|
+
# via maturin, which sets the right flags. We `cargo check` it here
|
|
36
|
+
# so Rust-level errors are still caught — `check` skips codegen and
|
|
37
|
+
# linking entirely.
|
|
38
|
+
- name: cargo build (odx-rs)
|
|
39
|
+
run: cargo build -p odx-rs --all-targets
|
|
40
|
+
|
|
41
|
+
- name: cargo check (odx-py)
|
|
42
|
+
run: cargo check -p odx-py
|
|
43
|
+
|
|
44
|
+
- name: cargo test (odx-rs)
|
|
45
|
+
run: cargo test -p odx-rs --lib
|
|
46
|
+
|
|
47
|
+
- name: cargo test (integration)
|
|
48
|
+
run: cargo test -p odx-rs --tests
|
|
49
|
+
|
|
50
|
+
python-tests:
|
|
51
|
+
name: Python tests (${{ matrix.os }} / py${{ matrix.python-version }})
|
|
52
|
+
runs-on: ${{ matrix.os }}
|
|
53
|
+
strategy:
|
|
54
|
+
fail-fast: false
|
|
55
|
+
matrix:
|
|
56
|
+
os: [ubuntu-latest, macos-latest]
|
|
57
|
+
python-version: ['3.10', '3.12']
|
|
58
|
+
steps:
|
|
59
|
+
- uses: actions/checkout@v4
|
|
60
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
61
|
+
- uses: Swatinem/rust-cache@v2
|
|
62
|
+
- uses: actions/setup-python@v5
|
|
63
|
+
with:
|
|
64
|
+
python-version: ${{ matrix.python-version }}
|
|
65
|
+
cache: pip
|
|
66
|
+
|
|
67
|
+
# `maturin develop` requires an active virtualenv (it refuses to
|
|
68
|
+
# install into the system Python). Create one inside python/ and
|
|
69
|
+
# activate it for the remainder of the job by exporting VIRTUAL_ENV
|
|
70
|
+
# and prepending its bin/ directory to PATH.
|
|
71
|
+
- name: Create + activate virtualenv
|
|
72
|
+
working-directory: python
|
|
73
|
+
run: |
|
|
74
|
+
python -m venv .venv
|
|
75
|
+
echo "VIRTUAL_ENV=$PWD/.venv" >> "$GITHUB_ENV"
|
|
76
|
+
echo "$PWD/.venv/bin" >> "$GITHUB_PATH"
|
|
77
|
+
|
|
78
|
+
- name: Install build + test deps
|
|
79
|
+
working-directory: python
|
|
80
|
+
run: |
|
|
81
|
+
python -m pip install --upgrade pip
|
|
82
|
+
python -m pip install maturin pytest numpy
|
|
83
|
+
|
|
84
|
+
- name: Build + install (maturin develop)
|
|
85
|
+
working-directory: python
|
|
86
|
+
run: maturin develop --release
|
|
87
|
+
|
|
88
|
+
- name: Run odx-py tests
|
|
89
|
+
working-directory: python
|
|
90
|
+
run: pytest tests/ -v
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
name: Release wheels + PyPI
|
|
2
|
+
|
|
3
|
+
# Trigger on version tags (e.g. v0.1.0, v0.2.0-rc1) or manual dispatch.
|
|
4
|
+
on:
|
|
5
|
+
push:
|
|
6
|
+
tags:
|
|
7
|
+
- 'v*'
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
env:
|
|
14
|
+
CARGO_TERM_COLOR: always
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
# ─── Tag / version sanity check ────────────────────────────────────────────
|
|
18
|
+
#
|
|
19
|
+
# Refuses to build if the pushed tag (`vX.Y.Z`) doesn't match the version
|
|
20
|
+
# in [workspace.package] of Cargo.toml. Catches "I tagged but forgot to
|
|
21
|
+
# bump" before we waste 4× wheel build minutes on a wrong-version release.
|
|
22
|
+
# All build jobs `needs: verify-version`, so a mismatch fails the whole
|
|
23
|
+
# workflow at the first step.
|
|
24
|
+
verify-version:
|
|
25
|
+
name: Verify tag matches Cargo.toml
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
outputs:
|
|
28
|
+
version: ${{ steps.check.outputs.version }}
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@v4
|
|
31
|
+
- id: check
|
|
32
|
+
run: |
|
|
33
|
+
set -euo pipefail
|
|
34
|
+
# Extract the version from the [workspace.package] section.
|
|
35
|
+
PKG_VERSION=$(awk '
|
|
36
|
+
/^\[workspace\.package\]/ { in_section = 1; next }
|
|
37
|
+
/^\[/ { in_section = 0 }
|
|
38
|
+
in_section && /^version[[:space:]]*=/ {
|
|
39
|
+
gsub(/^version[[:space:]]*=[[:space:]]*"|"[[:space:]]*$/, "")
|
|
40
|
+
print
|
|
41
|
+
exit
|
|
42
|
+
}
|
|
43
|
+
' Cargo.toml)
|
|
44
|
+
echo "Cargo.toml: $PKG_VERSION"
|
|
45
|
+
echo "version=$PKG_VERSION" >> "$GITHUB_OUTPUT"
|
|
46
|
+
# Only enforce tag<->version match when triggered by a tag push.
|
|
47
|
+
# workflow_dispatch and re-runs without a tag fall through.
|
|
48
|
+
if [[ "$GITHUB_REF" != refs/tags/v* ]]; then
|
|
49
|
+
echo "Not a tag push; skipping tag<->version match."
|
|
50
|
+
exit 0
|
|
51
|
+
fi
|
|
52
|
+
TAG_VERSION="${GITHUB_REF#refs/tags/v}"
|
|
53
|
+
echo "Tag: $TAG_VERSION"
|
|
54
|
+
if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
|
|
55
|
+
echo "::error::Tag v$TAG_VERSION does not match [workspace.package].version = \"$PKG_VERSION\". Bump Cargo.toml or retag."
|
|
56
|
+
exit 1
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# ─── Linux wheels ───────────────────────────────────────────────────────────
|
|
60
|
+
linux:
|
|
61
|
+
name: Linux ${{ matrix.target }} (${{ matrix.libc }})
|
|
62
|
+
runs-on: ubuntu-latest
|
|
63
|
+
needs: [verify-version]
|
|
64
|
+
strategy:
|
|
65
|
+
fail-fast: false
|
|
66
|
+
matrix:
|
|
67
|
+
include:
|
|
68
|
+
- target: x86_64
|
|
69
|
+
libc: manylinux
|
|
70
|
+
- target: aarch64
|
|
71
|
+
libc: manylinux
|
|
72
|
+
- target: x86_64
|
|
73
|
+
libc: musllinux
|
|
74
|
+
- target: aarch64
|
|
75
|
+
libc: musllinux
|
|
76
|
+
steps:
|
|
77
|
+
- uses: actions/checkout@v4
|
|
78
|
+
- uses: PyO3/maturin-action@v1
|
|
79
|
+
# Set the CMAKE env var so the cmake-rs crate (used by
|
|
80
|
+
# hdf5-metno-src's build script) uses our pip-installed cmake
|
|
81
|
+
# directly, sidestepping any PATH-resolution surprises.
|
|
82
|
+
# before-script-linux populates /opt/_pipcmake/bin/cmake.
|
|
83
|
+
env:
|
|
84
|
+
CMAKE: /opt/_pipcmake/bin/cmake
|
|
85
|
+
with:
|
|
86
|
+
target: ${{ matrix.target }}
|
|
87
|
+
# abi3-py39 wheels work for all CPython >= 3.9.
|
|
88
|
+
args: --release --out dist
|
|
89
|
+
working-directory: python
|
|
90
|
+
# `2_28` (AlmaLinux 9 / glibc 2.28) instead of the older `auto`
|
|
91
|
+
# (= `2014` = manylinux_2_17, CentOS 7 / glibc 2.17). The 2014
|
|
92
|
+
# cross image ships Python 3.6, which maturin rejects (needs
|
|
93
|
+
# >=3.7) and which is below our abi3-py39 baseline. 2_28 has
|
|
94
|
+
# Python 3.9+ baked in. The compat trade-off is glibc 2.28+
|
|
95
|
+
# required at install time — i.e. RHEL/AlmaLinux 8+, Debian 10+,
|
|
96
|
+
# Ubuntu 18.10+ (essentially anything from the last ~6 years).
|
|
97
|
+
manylinux: ${{ matrix.libc == 'manylinux' && '2_28' || 'musllinux_1_2' }}
|
|
98
|
+
before-script-linux: |
|
|
99
|
+
# hdf5-metno-src builds HDF5 from source via cmake; it requires
|
|
100
|
+
# CMake >= 3.26. Both manylinux_2_17 (AlmaLinux yum cmake 3.20)
|
|
101
|
+
# and musllinux_1_2 (Alpine apk cmake 3.22) ship too-old
|
|
102
|
+
# versions, and cross-compile images from messense (used for
|
|
103
|
+
# aarch64) don't have /opt/python/ at all. Install a recent
|
|
104
|
+
# cmake via pip from whatever Python we can find, and pin its
|
|
105
|
+
# path via the CMAKE env var.
|
|
106
|
+
#
|
|
107
|
+
# `set -ex` prints every command so failures are diagnosable
|
|
108
|
+
# from the workflow log without re-running.
|
|
109
|
+
set -ex
|
|
110
|
+
|
|
111
|
+
uname -a
|
|
112
|
+
cat /etc/os-release || true
|
|
113
|
+
ls -d /opt/python 2>&1 || echo "(no /opt/python — likely a cross-compile image)"
|
|
114
|
+
|
|
115
|
+
# Install minimal build tools + a system Python if needed.
|
|
116
|
+
# The cross-compile images have package managers but often no
|
|
117
|
+
# Python preinstalled, so add it here.
|
|
118
|
+
if command -v apk >/dev/null 2>&1; then
|
|
119
|
+
apk update
|
|
120
|
+
apk add --no-cache make gcc g++ musl-dev linux-headers perl bash python3 py3-pip
|
|
121
|
+
elif command -v dnf >/dev/null 2>&1; then
|
|
122
|
+
dnf install -y make gcc gcc-c++ perl python3 python3-pip
|
|
123
|
+
elif command -v yum >/dev/null 2>&1; then
|
|
124
|
+
yum install -y make gcc gcc-c++ perl python3 python3-pip
|
|
125
|
+
elif command -v apt-get >/dev/null 2>&1; then
|
|
126
|
+
apt-get update
|
|
127
|
+
apt-get install -y make gcc g++ perl python3 python3-pip
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
# Resolve a pip we can use. Prefer the PyPA-style /opt/python
|
|
131
|
+
# bundled CPython on native images; on *cross-compile* images
|
|
132
|
+
# (messense/*-cross), /opt/python contains TARGET-arch binaries
|
|
133
|
+
# that can't execute on the build host (kernel returns ENOEXEC,
|
|
134
|
+
# bash falls back to interpreting the pip script and chokes on
|
|
135
|
+
# Python syntax). Probe each candidate by running --version
|
|
136
|
+
# before committing to it.
|
|
137
|
+
PIP_CMD=""
|
|
138
|
+
PYBIN=""
|
|
139
|
+
for cand in /opt/python/cp310-cp310/bin /opt/python/cp311-cp311/bin \
|
|
140
|
+
/opt/python/cp312-cp312/bin /opt/python/cp39-cp39/bin \
|
|
141
|
+
/opt/python/cp313-cp313/bin; do
|
|
142
|
+
if [ -d "$cand" ] && "$cand/python" --version >/dev/null 2>&1; then
|
|
143
|
+
PYBIN="$cand"
|
|
144
|
+
PIP_CMD="$cand/pip"
|
|
145
|
+
break
|
|
146
|
+
fi
|
|
147
|
+
done
|
|
148
|
+
if [ -z "$PIP_CMD" ]; then
|
|
149
|
+
if command -v pip3 >/dev/null 2>&1; then
|
|
150
|
+
PIP_CMD="pip3"
|
|
151
|
+
elif command -v python3 >/dev/null 2>&1; then
|
|
152
|
+
python3 -m ensurepip --default-pip 2>/dev/null || true
|
|
153
|
+
PIP_CMD="python3 -m pip"
|
|
154
|
+
else
|
|
155
|
+
echo "::error::No Python/pip found in build container"
|
|
156
|
+
exit 1
|
|
157
|
+
fi
|
|
158
|
+
fi
|
|
159
|
+
echo "Using PIP_CMD='$PIP_CMD' (PYBIN='${PYBIN:-system}')"
|
|
160
|
+
|
|
161
|
+
# If we found a /opt/python/cp* Python, make sure it shadows
|
|
162
|
+
# any older system python3 on PATH. maturin invokes `python3`
|
|
163
|
+
# from PATH after this script runs, and we've seen older
|
|
164
|
+
# cross-compile images leave a too-old `/usr/bin/python3` in
|
|
165
|
+
# place (e.g., 3.6 on the legacy manylinux2014 cross image).
|
|
166
|
+
if [ -n "$PYBIN" ]; then
|
|
167
|
+
ln -sf "$PYBIN/python" /usr/local/bin/python3
|
|
168
|
+
ln -sf "$PYBIN/python" /usr/local/bin/python
|
|
169
|
+
fi
|
|
170
|
+
|
|
171
|
+
# Install cmake>=3.26 from PyPI. `--break-system-packages` is
|
|
172
|
+
# for PEP 668-marked Pythons (some distros); harmless on others.
|
|
173
|
+
$PIP_CMD install --no-cache-dir --upgrade --break-system-packages "cmake>=3.26" 2>/dev/null \
|
|
174
|
+
|| $PIP_CMD install --no-cache-dir --upgrade "cmake>=3.26"
|
|
175
|
+
|
|
176
|
+
# Find where the pip-installed cmake landed. With /opt/python
|
|
177
|
+
# it's in $PYBIN/cmake; with system pip it's wherever pip puts
|
|
178
|
+
# console scripts — discoverable via `command -v cmake` after
|
|
179
|
+
# install (PATH is updated by the install).
|
|
180
|
+
INSTALLED_CMAKE=""
|
|
181
|
+
if [ -n "$PYBIN" ] && [ -x "$PYBIN/cmake" ]; then
|
|
182
|
+
INSTALLED_CMAKE="$PYBIN/cmake"
|
|
183
|
+
elif command -v cmake >/dev/null 2>&1; then
|
|
184
|
+
INSTALLED_CMAKE=$(command -v cmake)
|
|
185
|
+
else
|
|
186
|
+
# Last-ditch: ask pip where it put the script.
|
|
187
|
+
INSTALLED_CMAKE=$($PIP_CMD show -f cmake 2>/dev/null | awk '/Location:/ {loc=$2} /bin\/cmake/ {print loc"/"$1}' | head -1)
|
|
188
|
+
# That gives a path relative to site-packages; resolve to abs.
|
|
189
|
+
if [ -n "$INSTALLED_CMAKE" ]; then
|
|
190
|
+
INSTALLED_CMAKE=$(realpath "$INSTALLED_CMAKE" 2>/dev/null || echo "$INSTALLED_CMAKE")
|
|
191
|
+
fi
|
|
192
|
+
fi
|
|
193
|
+
if [ -z "$INSTALLED_CMAKE" ] || [ ! -x "$INSTALLED_CMAKE" ]; then
|
|
194
|
+
echo "::error::Could not locate pip-installed cmake binary"
|
|
195
|
+
$PIP_CMD show -f cmake || true
|
|
196
|
+
exit 1
|
|
197
|
+
fi
|
|
198
|
+
echo "Pip-installed cmake at: $INSTALLED_CMAKE"
|
|
199
|
+
|
|
200
|
+
# Pin the path to match the CMAKE env var set on the step.
|
|
201
|
+
mkdir -p /opt/_pipcmake/bin
|
|
202
|
+
ln -sf "$INSTALLED_CMAKE" /opt/_pipcmake/bin/cmake
|
|
203
|
+
|
|
204
|
+
# Shadow common system locations as a PATH fallback.
|
|
205
|
+
for target in /usr/local/bin/cmake /usr/bin/cmake; do
|
|
206
|
+
parent=$(dirname "$target")
|
|
207
|
+
[ -d "$parent" ] && ln -sf "$INSTALLED_CMAKE" "$target" || true
|
|
208
|
+
done
|
|
209
|
+
|
|
210
|
+
# Diagnostic: confirm the right cmake is found via every route.
|
|
211
|
+
echo "--- cmake versions:"
|
|
212
|
+
"$INSTALLED_CMAKE" --version
|
|
213
|
+
/opt/_pipcmake/bin/cmake --version
|
|
214
|
+
cmake --version
|
|
215
|
+
- uses: actions/upload-artifact@v4
|
|
216
|
+
with:
|
|
217
|
+
name: wheels-linux-${{ matrix.target }}-${{ matrix.libc }}
|
|
218
|
+
path: python/dist
|
|
219
|
+
|
|
220
|
+
# ─── macOS wheels (x86_64 + Apple Silicon) ─────────────────────────────────
|
|
221
|
+
#
|
|
222
|
+
# Runner mapping:
|
|
223
|
+
# - aarch64 → macos-14 (Apple Silicon, free)
|
|
224
|
+
# - x86_64 → macos-15-intel (Intel x86_64 on macOS 15; GitHub's
|
|
225
|
+
# recommended migration path for x86_64
|
|
226
|
+
# builds, supported until August 2027).
|
|
227
|
+
#
|
|
228
|
+
# The older `macos-13` runner pool is queue-pressured; `macos-15-intel`
|
|
229
|
+
# is the current Intel target with much better availability. There's no
|
|
230
|
+
# `macos-15-intel-large` etc. — Intel hardware is being retired, so
|
|
231
|
+
# macos-15-intel is the long tail.
|
|
232
|
+
macos:
|
|
233
|
+
name: macOS ${{ matrix.target }}
|
|
234
|
+
runs-on: ${{ matrix.target == 'aarch64' && 'macos-14' || 'macos-15-intel' }}
|
|
235
|
+
needs: [verify-version]
|
|
236
|
+
strategy:
|
|
237
|
+
fail-fast: false
|
|
238
|
+
matrix:
|
|
239
|
+
target: [x86_64, aarch64]
|
|
240
|
+
steps:
|
|
241
|
+
- uses: actions/checkout@v4
|
|
242
|
+
- uses: PyO3/maturin-action@v1
|
|
243
|
+
with:
|
|
244
|
+
target: ${{ matrix.target }}
|
|
245
|
+
args: --release --out dist
|
|
246
|
+
working-directory: python
|
|
247
|
+
- uses: actions/upload-artifact@v4
|
|
248
|
+
with:
|
|
249
|
+
name: wheels-macos-${{ matrix.target }}
|
|
250
|
+
path: python/dist
|
|
251
|
+
|
|
252
|
+
# ─── Windows wheels ────────────────────────────────────────────────────────
|
|
253
|
+
windows:
|
|
254
|
+
name: Windows ${{ matrix.target }}
|
|
255
|
+
runs-on: windows-latest
|
|
256
|
+
needs: [verify-version]
|
|
257
|
+
strategy:
|
|
258
|
+
fail-fast: false
|
|
259
|
+
matrix:
|
|
260
|
+
target: [x64]
|
|
261
|
+
steps:
|
|
262
|
+
- uses: actions/checkout@v4
|
|
263
|
+
- uses: PyO3/maturin-action@v1
|
|
264
|
+
with:
|
|
265
|
+
target: ${{ matrix.target }}
|
|
266
|
+
args: --release --out dist
|
|
267
|
+
working-directory: python
|
|
268
|
+
- uses: actions/upload-artifact@v4
|
|
269
|
+
with:
|
|
270
|
+
name: wheels-windows-${{ matrix.target }}
|
|
271
|
+
path: python/dist
|
|
272
|
+
|
|
273
|
+
# ─── Source distribution ───────────────────────────────────────────────────
|
|
274
|
+
sdist:
|
|
275
|
+
name: sdist
|
|
276
|
+
runs-on: ubuntu-latest
|
|
277
|
+
needs: [verify-version]
|
|
278
|
+
steps:
|
|
279
|
+
- uses: actions/checkout@v4
|
|
280
|
+
- uses: PyO3/maturin-action@v1
|
|
281
|
+
with:
|
|
282
|
+
command: sdist
|
|
283
|
+
args: --out dist
|
|
284
|
+
working-directory: python
|
|
285
|
+
- uses: actions/upload-artifact@v4
|
|
286
|
+
with:
|
|
287
|
+
name: sdist
|
|
288
|
+
path: python/dist
|
|
289
|
+
|
|
290
|
+
publish:
|
|
291
|
+
name: Publish to PyPI
|
|
292
|
+
needs: [linux, macos, windows, sdist]
|
|
293
|
+
runs-on: ubuntu-latest
|
|
294
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
295
|
+
environment:
|
|
296
|
+
name: pypi
|
|
297
|
+
url: https://pypi.org/p/odx
|
|
298
|
+
permissions:
|
|
299
|
+
id-token: write
|
|
300
|
+
steps:
|
|
301
|
+
- uses: actions/download-artifact@v4
|
|
302
|
+
with:
|
|
303
|
+
path: dist
|
|
304
|
+
merge-multiple: true
|
|
305
|
+
- name: Inspect artifacts
|
|
306
|
+
run: ls -la dist/
|
|
307
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
308
|
+
with:
|
|
309
|
+
packages-dir: dist
|
|
310
|
+
# Switch to test.pypi.org for dry-runs by uncommenting:
|
|
311
|
+
# repository-url: https://test.pypi.org/legacy/
|
|
312
|
+
skip-existing: true
|
odx-0.1.1/.gitignore
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Cargo build output (binaries, deps, incremental, criterion output, etc.)
|
|
2
|
+
/debug/
|
|
3
|
+
/target/
|
|
4
|
+
**/target/
|
|
5
|
+
|
|
6
|
+
# rustfmt
|
|
7
|
+
**/*.rs.bk
|
|
8
|
+
|
|
9
|
+
# MSVC (Windows) debug symbols
|
|
10
|
+
*.pdb
|
|
11
|
+
|
|
12
|
+
# LLVM coverage (cargo llvm-cov)
|
|
13
|
+
*.profraw
|
|
14
|
+
*.profdata
|
|
15
|
+
lcov.info
|
|
16
|
+
cobertura.xml
|
|
17
|
+
|
|
18
|
+
# Python: maturin-built extension modules (placed inside the package by
|
|
19
|
+
# `maturin develop`)
|
|
20
|
+
python/odx/_odx*.so
|
|
21
|
+
python/odx/_odx*.pyd
|
|
22
|
+
python/odx/_odx*.dylib
|
|
23
|
+
|
|
24
|
+
# Python: build / packaging artifacts
|
|
25
|
+
python/dist/
|
|
26
|
+
python/build/
|
|
27
|
+
python/wheelhouse/
|
|
28
|
+
python/*.egg-info/
|
|
29
|
+
**/*.egg-info/
|
|
30
|
+
|
|
31
|
+
# Python: bytecode + caches
|
|
32
|
+
__pycache__/
|
|
33
|
+
*.py[cod]
|
|
34
|
+
*$py.class
|
|
35
|
+
.pytest_cache/
|
|
36
|
+
.mypy_cache/
|
|
37
|
+
.ruff_cache/
|
|
38
|
+
.tox/
|
|
39
|
+
.coverage
|
|
40
|
+
.coverage.*
|
|
41
|
+
htmlcov/
|
|
42
|
+
.hypothesis/
|
|
43
|
+
|
|
44
|
+
# Python: virtualenvs occasionally left behind
|
|
45
|
+
.venv/
|
|
46
|
+
venv/
|
|
47
|
+
|
|
48
|
+
# Local env / secrets
|
|
49
|
+
.env
|
|
50
|
+
.env.*
|
|
51
|
+
!.env.example
|
|
52
|
+
|
|
53
|
+
# OS junk
|
|
54
|
+
.DS_Store
|
|
55
|
+
Thumbs.db
|