fix(ci): constrain vtk on Python 3.9 and run dev deps in PR workflow - #137
Conversation
vtk 9.7.0 (2026-08-15) is the first release without a cp39 wheel, and vtk publishes no requires-python metadata, so Poetry cannot exclude it automatically -- it selects the newest version and then finds all 27 wheels ABI-incompatible. With no committed lockfile, every CI run re-resolves, so the post-merge 3.9 job broke the day that release shipped. Split the vtk constraint by Python version: <9.7 (last cp39 release is 9.6.2) below 3.10, unconstrained from 3.10 on. The PR workflow installed with `pip install -e .`, which skips the dev group where vtk lives, while the push-to-main workflow uses `poetry install`. That is why the PR was green and main failed. Align tests_mr.yml with tests.yml so PRs exercise the dev group too. Verified on Python 3.9: `poetry install` succeeds (vtk 9.6.2) and `poetry run pytest` reports 462 passed, 6 skipped. Python 3.10 still resolves to vtk 9.7.0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Benchmark comparisonSpeed (wall time per call)baseline Showing the 5 most-changed measurements per case; the rest are collapsed. Rows with a baseline below 3 ms are tagged
|
| Measurement | baseline ms (median ±½·range) | head ms (median ±½·range) | Δ % | p |
|---|---|---|---|---|
nii_rescale |
41.91 ±0.45 | 39.71 ±0.11 | -5.2% | 0.001 |
nii_resample_from_to |
43.64 ±0.08 | 41.74 ±0.06 | -4.3% | 0.000 |
nii_filter_connected_components |
4.14 ±0.03 | 4.31 ±0.14 | +4.0% | 0.044 |
nii_fill_holes |
4.58 ±0.03 | 4.68 ±0.05 | +2.2% | 0.003 |
nii_dilate_msk |
119.29 ±0.41 | 121.35 ±0.54 | +1.7% | 0.000 |
… 31 more measurements
| Measurement | baseline ms (median ±½·range) | head ms (median ±½·range) | Δ % | p |
|---|---|---|---|---|
poi_calc_centroids_nocrop |
4.28 ±0.03 | 4.33 ±0.04 | +1.4% | 0.028 |
nii_erode_msk |
6.00 ±0.05 | 6.07 ±0.03 | +1.3% | 0.034 |
poi_calc_poi_from_subreg_vert |
11.36 ±0.10 | 11.42 ±0.05 | +0.5% | 0.504 |
nii_save |
11.48 ±0.16 | 11.45 ±0.04 | -0.3% | 0.256 |
nii_rescale_seg |
3.05 ±0.03 | 3.05 ±0.01 | -0.3% | 0.829 |
nii_load_img |
11.64 ±0.05 | 11.62 ±0.11 | -0.2% | 0.989 |
metric_voxels |
250463.00 ±0.00 | 250463.00 ±0.00 | +0.0% | — |
metric_labels |
3.00 ±0.00 | 3.00 ±0.00 | +0.0% | — |
metric_foreground_pct |
14.51 ±0.00 | 14.51 ±0.00 | +0.0% | — |
poi_rescale |
0.19 ±0.02 | 0.17 ±0.01 | -12.4% (noise) | 0.317 |
poi_map_labels |
0.15 ±0.01 | 0.14 ±0.01 | -5.8% (noise) | 0.336 |
nii_set_dtype |
0.38 ±0.01 | 0.36 ±0.01 | -5.2% (noise) | 0.042 |
nii_compute_crop |
0.29 ±0.02 | 0.28 ±0.01 | -3.5% (noise) | 0.166 |
poi_calc_centroids |
2.38 ±0.04 | 2.45 ±0.09 | +2.9% (noise) | 0.164 |
nii_pad_to |
0.53 ±0.01 | 0.54 ±0.03 | +2.2% (noise) | 0.393 |
nii_unique |
0.57 ±0.01 | 0.58 ±0.01 | +2.1% (noise) | 0.016 |
nii_get_array |
0.04 ±0.00 | 0.04 ±0.00 | -1.8% (noise) | 0.292 |
poi_save |
0.35 ±0.01 | 0.36 ±0.01 | +1.7% (noise) | 0.508 |
nii_get_connected_components |
1.96 ±0.01 | 1.99 ±0.04 | +1.4% (noise) | 0.099 |
poi_reorient |
0.32 ±0.01 | 0.32 ±0.02 | +1.4% (noise) | 0.373 |
nii_reorient |
0.65 ±0.01 | 0.66 ±0.04 | +1.4% (noise) | 0.960 |
nii_apply_crop |
0.51 ±0.02 | 0.52 ±0.01 | +1.2% (noise) | 0.842 |
nii_extract_label |
0.33 ±0.02 | 0.32 ±0.01 | -1.1% (noise) | 0.984 |
nii_load_seg |
2.60 ±0.05 | 2.62 ±0.02 | +0.8% (noise) | 0.845 |
poi_to_global |
0.16 ±0.01 | 0.15 ±0.01 | -0.7% (noise) | 0.803 |
nii_volumes |
1.89 ±0.01 | 1.88 ±0.02 | -0.5% (noise) | 0.163 |
poi_load |
0.86 ±0.02 | 0.86 ±0.03 | +0.4% (noise) | 0.702 |
nii_center_of_masses |
1.80 ±0.02 | 1.80 ±0.01 | -0.4% (noise) | 0.619 |
nii_map_labels |
0.79 ±0.03 | 0.79 ±0.02 | -0.3% (noise) | 0.795 |
poi_local_to_global_arr |
0.24 ±0.01 | 0.24 ±0.01 | +0.2% (noise) | 0.612 |
poi_resample_from_to |
0.54 ±0.01 | 0.54 ±0.01 | +0.1% (noise) | 0.849 |
ct_2d — shape (73, 47, 1)
| Measurement | baseline ms (median ±½·range) | head ms (median ±½·range) | Δ % | p |
|---|---|---|---|---|
nii_rescale |
5.43 ±0.13 | 5.32 ±0.04 | -2.2% | 0.100 |
nii_dilate_msk |
13.86 ±0.10 | 13.91 ±0.32 | +0.4% | 0.390 |
nii_resample_from_to |
7.15 ±0.08 | 7.17 ±0.09 | +0.2% | 0.509 |
metric_voxels |
3431.00 ±0.00 | 3431.00 ±0.00 | +0.0% | — |
metric_labels |
3.00 ±0.00 | 3.00 ±0.00 | +0.0% | — |
… 30 more measurements
| Measurement | baseline ms (median ±½·range) | head ms (median ±½·range) | Δ % | p |
|---|---|---|---|---|
metric_foreground_pct |
37.60 ±0.00 | 37.60 ±0.00 | +0.0% | — |
nii_compute_crop |
0.14 ±0.01 | 0.16 ±0.00 | +16.4% (noise) | 0.015 |
nii_set_dtype |
0.37 ±0.01 | 0.42 ±0.04 | +12.1% (noise) | 0.050 |
nii_erode_msk |
0.90 ±0.02 | 1.01 ±0.03 | +11.4% (noise) | 0.001 |
nii_map_labels |
0.45 ±0.02 | 0.49 ±0.02 | +8.6% (noise) | 0.023 |
nii_pad_to |
0.52 ±0.01 | 0.57 ±0.01 | +8.4% (noise) | 0.000 |
nii_get_array |
0.02 ±0.00 | 0.02 ±0.00 | +7.9% (noise) | 0.082 |
nii_fill_holes |
0.78 ±0.01 | 0.84 ±0.04 | +7.6% (noise) | 0.010 |
poi_local_to_global_arr |
0.27 ±0.01 | 0.29 ±0.01 | +6.7% (noise) | 0.010 |
nii_apply_crop |
0.66 ±0.01 | 0.70 ±0.02 | +6.7% (noise) | 0.001 |
poi_save |
0.48 ±0.01 | 0.51 ±0.02 | +6.4% (noise) | 0.043 |
nii_extract_label |
0.40 ±0.01 | 0.43 ±0.01 | +6.1% (noise) | 0.002 |
nii_volumes |
0.28 ±0.01 | 0.29 ±0.01 | +5.6% (noise) | 0.066 |
nii_rescale_seg |
0.72 ±0.03 | 0.76 ±0.01 | +5.2% (noise) | 0.021 |
nii_reorient |
0.76 ±0.02 | 0.79 ±0.02 | +5.2% (noise) | 0.026 |
nii_load_seg |
1.54 ±0.01 | 1.60 ±0.02 | +4.3% (noise) | 0.001 |
nii_get_connected_components |
0.62 ±0.05 | 0.64 ±0.01 | +3.7% (noise) | 0.826 |
poi_reorient |
0.46 ±0.01 | 0.44 ±0.01 | -3.6% (noise) | 0.020 |
poi_to_global |
0.24 ±0.01 | 0.23 ±0.01 | -3.2% (noise) | 0.519 |
nii_filter_connected_components |
0.80 ±0.02 | 0.82 ±0.03 | +2.8% (noise) | 0.127 |
poi_map_labels |
0.20 ±0.01 | 0.21 ±0.01 | +2.8% (noise) | 0.253 |
nii_load_img |
1.40 ±0.02 | 1.44 ±0.02 | +2.5% (noise) | 0.019 |
nii_save |
1.29 ±0.02 | 1.32 ±0.02 | +2.3% (noise) | 0.043 |
poi_load |
0.96 ±0.02 | 0.98 ±0.00 | +2.1% (noise) | 0.411 |
poi_calc_centroids_nocrop |
1.04 ±0.03 | 1.07 ±0.01 | +2.1% (noise) | 0.145 |
poi_calc_centroids |
0.88 ±0.01 | 0.89 ±0.01 | +1.6% (noise) | 0.258 |
poi_rescale |
0.26 ±0.01 | 0.26 ±0.02 | -1.4% (noise) | 0.866 |
nii_center_of_masses |
0.21 ±0.02 | 0.21 ±0.01 | -1.1% (noise) | 0.818 |
poi_resample_from_to |
0.70 ±0.02 | 0.70 ±0.03 | +1.1% (noise) | 0.178 |
nii_unique |
0.12 ±0.01 | 0.12 ±0.01 | -0.1% (noise) | 0.770 |
mri_3d — shape (68, 52, 67)
| Measurement | baseline ms (median ±½·range) | head ms (median ±½·range) | Δ % | p |
|---|---|---|---|---|
nii_rescale |
39.41 ±0.21 | 37.13 ±0.07 | -5.8% | 0.000 |
nii_resample_from_to |
41.07 ±0.19 | 39.16 ±0.18 | -4.6% | 0.000 |
poi_calc_centroids_nocrop |
8.97 ±0.05 | 9.15 ±0.07 | +2.1% | 0.001 |
nii_rescale_seg |
3.03 ±0.02 | 3.07 ±0.02 | +1.2% | 0.014 |
poi_calc_poi_from_subreg_vert |
10.73 ±0.05 | 10.82 ±0.08 | +0.9% | 0.132 |
… 31 more measurements
| Measurement | baseline ms (median ±½·range) | head ms (median ±½·range) | Δ % | p |
|---|---|---|---|---|
nii_filter_connected_components |
4.60 ±0.08 | 4.64 ±0.14 | +0.8% | 0.192 |
nii_dilate_msk |
153.18 ±0.62 | 154.20 ±0.87 | +0.7% | 0.052 |
nii_erode_msk |
7.60 ±0.11 | 7.56 ±0.07 | -0.5% | 0.331 |
nii_fill_holes |
5.48 ±0.02 | 5.51 ±0.02 | +0.5% | 0.090 |
nii_load_img |
9.43 ±0.03 | 9.43 ±0.02 | +0.0% | 0.801 |
nii_save |
9.45 ±0.06 | 9.45 ±0.05 | +0.0% | 0.296 |
metric_voxels |
236912.00 ±0.00 | 236912.00 ±0.00 | +0.0% | — |
metric_labels |
8.00 ±0.00 | 8.00 ±0.00 | +0.0% | — |
metric_foreground_pct |
18.21 ±0.00 | 18.21 ±0.00 | +0.0% | — |
nii_get_array |
0.04 ±0.00 | 0.05 ±0.00 | +29.4% (noise) | 0.000 |
poi_save |
0.52 ±0.02 | 0.56 ±0.02 | +7.6% (noise) | 0.010 |
nii_apply_crop |
0.67 ±0.01 | 0.71 ±0.02 | +5.9% (noise) | 0.015 |
nii_pad_to |
0.67 ±0.01 | 0.71 ±0.02 | +5.8% (noise) | 0.002 |
nii_extract_label |
0.44 ±0.02 | 0.46 ±0.01 | +4.8% (noise) | 0.181 |
nii_set_dtype |
0.50 ±0.01 | 0.53 ±0.03 | +4.7% (noise) | 0.030 |
nii_compute_crop |
0.34 ±0.01 | 0.33 ±0.01 | -4.4% (noise) | 0.083 |
poi_map_labels |
0.24 ±0.01 | 0.25 ±0.02 | +4.2% (noise) | 0.383 |
poi_to_global |
0.27 ±0.01 | 0.28 ±0.01 | +3.7% (noise) | 0.025 |
poi_resample_from_to |
0.73 ±0.01 | 0.75 ±0.02 | +3.5% (noise) | 0.065 |
poi_rescale |
0.29 ±0.01 | 0.29 ±0.01 | +3.1% (noise) | 0.479 |
nii_reorient |
0.82 ±0.03 | 0.84 ±0.02 | +2.7% (noise) | 0.442 |
poi_load |
2.06 ±0.02 | 2.11 ±0.04 | +2.6% (noise) | 0.066 |
nii_load_seg |
2.70 ±0.02 | 2.77 ±0.03 | +2.5% (noise) | 0.004 |
nii_unique |
0.59 ±0.01 | 0.61 ±0.01 | +2.4% (noise) | 0.043 |
poi_reorient |
0.48 ±0.03 | 0.49 ±0.02 | +2.3% (noise) | 0.124 |
nii_get_connected_components |
2.03 ±0.03 | 2.07 ±0.25 | +1.7% (noise) | 0.277 |
nii_volumes |
2.02 ±0.04 | 2.05 ±0.02 | +1.4% (noise) | 0.468 |
nii_center_of_masses |
2.06 ±0.01 | 2.08 ±0.01 | +1.1% (noise) | 0.000 |
nii_map_labels |
0.97 ±0.02 | 0.98 ±0.01 | +0.5% (noise) | 0.312 |
poi_calc_centroids |
2.82 ±0.02 | 2.83 ±0.04 | +0.4% (noise) | 0.600 |
poi_local_to_global_arr |
0.29 ±0.01 | 0.29 ±0.01 | -0.1% (noise) | 0.432 |
mri_2d — shape (68, 52, 1)
| Measurement | baseline ms (median ±½·range) | head ms (median ±½·range) | Δ % | p |
|---|---|---|---|---|
nii_rescale |
5.46 ±0.07 | 5.35 ±0.07 | -2.1% | 0.258 |
nii_resample_from_to |
7.14 ±0.08 | 7.09 ±0.03 | -0.7% | 0.067 |
nii_dilate_msk |
18.20 ±0.14 | 18.22 ±0.07 | +0.1% | 0.964 |
metric_voxels |
3536.00 ±0.00 | 3536.00 ±0.00 | +0.0% | — |
metric_labels |
7.00 ±0.00 | 7.00 ±0.00 | +0.0% | — |
… 30 more measurements
| Measurement | baseline ms (median ±½·range) | head ms (median ±½·range) | Δ % | p |
|---|---|---|---|---|
metric_foreground_pct |
50.17 ±0.00 | 50.17 ±0.00 | +0.0% | — |
nii_get_array |
0.01 ±0.00 | 0.02 ±0.00 | +27.1% (noise) | 0.481 |
nii_unique |
0.12 ±0.02 | 0.13 ±0.01 | +8.9% (noise) | 0.386 |
nii_get_connected_components |
0.60 ±0.03 | 0.64 ±0.08 | +7.3% (noise) | 0.129 |
nii_center_of_masses |
0.39 ±0.01 | 0.41 ±0.02 | +6.3% (noise) | 0.231 |
nii_set_dtype |
0.38 ±0.01 | 0.40 ±0.01 | +5.7% (noise) | 0.014 |
nii_pad_to |
0.51 ±0.02 | 0.54 ±0.02 | +5.1% (noise) | 0.034 |
nii_compute_crop |
0.14 ±0.01 | 0.15 ±0.01 | +4.9% (noise) | 0.174 |
nii_map_labels |
0.47 ±0.01 | 0.49 ±0.00 | +4.8% (noise) | 0.004 |
poi_to_global |
0.27 ±0.01 | 0.26 ±0.01 | -4.1% (noise) | 0.330 |
nii_filter_connected_components |
0.80 ±0.03 | 0.84 ±0.02 | +4.1% (noise) | 0.074 |
nii_save |
1.28 ±0.03 | 1.33 ±0.02 | +4.0% (noise) | 0.020 |
nii_apply_crop |
0.63 ±0.01 | 0.65 ±0.01 | +3.5% (noise) | 0.003 |
nii_volumes |
0.44 ±0.01 | 0.46 ±0.01 | +3.2% (noise) | 0.021 |
nii_extract_label |
0.41 ±0.01 | 0.42 ±0.01 | +2.7% (noise) | 0.069 |
nii_load_img |
1.40 ±0.02 | 1.44 ±0.02 | +2.7% (noise) | 0.006 |
poi_calc_centroids_nocrop |
1.26 ±0.03 | 1.30 ±0.02 | +2.6% (noise) | 0.087 |
poi_calc_centroids |
1.06 ±0.02 | 1.08 ±0.03 | +2.5% (noise) | 0.021 |
nii_rescale_seg |
0.73 ±0.02 | 0.75 ±0.02 | +2.5% (noise) | 0.189 |
nii_erode_msk |
1.12 ±0.04 | 1.15 ±0.01 | +2.4% (noise) | 0.253 |
nii_load_seg |
1.53 ±0.01 | 1.56 ±0.03 | +1.7% (noise) | 0.313 |
poi_local_to_global_arr |
0.28 ±0.02 | 0.29 ±0.01 | +1.7% (noise) | 0.612 |
nii_fill_holes |
0.98 ±0.01 | 1.00 ±0.03 | +1.6% (noise) | 0.122 |
poi_resample_from_to |
0.71 ±0.03 | 0.72 ±0.01 | +1.5% (noise) | 0.371 |
poi_map_labels |
0.23 ±0.01 | 0.23 ±0.01 | +1.4% (noise) | 0.716 |
nii_reorient |
0.78 ±0.03 | 0.79 ±0.02 | +1.3% (noise) | 0.198 |
poi_load |
1.84 ±0.03 | 1.86 ±0.01 | +1.1% (noise) | 0.599 |
poi_save |
0.53 ±0.01 | 0.54 ±0.01 | +1.0% (noise) | 0.725 |
poi_reorient |
0.47 ±0.02 | 0.47 ±0.02 | +0.3% (noise) | 0.578 |
poi_rescale |
0.28 ±0.01 | 0.28 ±0.01 | +0.0% (noise) | 0.870 |
Gate: a measurement fails when the baseline is ≥ 1 ms, the median grows by ≥ 50%, and Welch's t-test gives p < 0.05. metric_* rows are context only.
Memory (peak RSS growth per call)
baseline 73e7fea vs head 73e7fea · python 3.11.16 · 5 repeats + 1 warmup · sampler proc-status, isolation fork · measurement floor ≈ 0.90 MiB
Showing the 5 most-changed measurements per case; the rest are collapsed. Rows with a baseline below 3 MiB are tagged (noise) — runner jitter on those swamps any real change.
ct_3d — shape (73, 47, 73)
| Measurement | baseline MiB (median ±½·range) | head MiB (median ±½·range) | Δ % | p |
|---|---|---|---|---|
nii_set_dtype |
5.25 ±0.00 | 5.21 ±0.00 | -0.7% | — |
poi_resample_from_to |
5.28 ±0.00 | 5.24 ±0.00 | -0.7% | — |
nii_pad_to |
5.43 ±0.00 | 5.39 ±0.00 | -0.7% | — |
nii_extract_label |
5.43 ±0.00 | 5.39 ±0.00 | -0.7% | — |
nii_load_seg |
6.02 ±0.00 | 5.97 ±0.00 | -0.7% | — |
… 31 more measurements
| Measurement | baseline MiB (median ±½·range) | head MiB (median ±½·range) | Δ % | p |
|---|---|---|---|---|
nii_map_labels |
5.50 ±0.00 | 5.46 ±0.00 | -0.7% | — |
nii_apply_crop |
5.87 ±0.00 | 5.83 ±0.00 | -0.7% | — |
nii_reorient |
5.91 ±0.00 | 5.87 ±0.00 | -0.7% | — |
poi_calc_centroids_nocrop |
5.93 ±0.00 | 5.89 ±0.00 | -0.7% | — |
nii_dilate_msk |
5.93 ±0.00 | 5.89 ±0.00 | -0.7% | — |
nii_erode_msk |
5.95 ±0.00 | 5.91 ±0.00 | -0.7% | — |
poi_calc_centroids |
6.06 ±0.00 | 6.02 ±0.00 | -0.6% | — |
nii_fill_holes |
6.29 ±0.00 | 6.25 ±0.00 | -0.6% | — |
nii_get_connected_components |
6.62 ±0.00 | 6.58 ±0.00 | -0.6% | — |
nii_filter_connected_components |
6.87 ±0.00 | 6.83 ±0.00 | -0.6% | — |
poi_calc_poi_from_subreg_vert |
7.11 ±0.00 | 7.07 ±0.00 | -0.5% | 0.000 |
nii_load_img |
3.57 ±0.00 | 3.57 ±0.00 | -0.1% | — |
nii_save |
3.71 ±0.00 | 3.71 ±0.00 | +0.0% | — |
nii_rescale |
6.18 ±0.00 | 6.18 ±0.00 | +0.0% | — |
nii_rescale_seg |
5.95 ±0.00 | 5.95 ±0.00 | +0.0% | — |
nii_resample_from_to |
6.30 ±0.00 | 6.30 ±0.00 | +0.0% | — |
nii_volumes |
3.53 ±0.00 | 3.53 ±0.00 | +0.0% | — |
nii_center_of_masses |
3.28 ±0.00 | 3.28 ±0.00 | +0.0% | — |
poi_reorient |
3.84 ±0.00 | 3.84 ±0.00 | +0.0% | — |
poi_to_global |
3.09 ±0.00 | 3.09 ±0.00 | +0.0% | — |
metric_voxels |
250463.00 ±0.00 | 250463.00 ±0.00 | +0.0% | — |
metric_labels |
3.00 ±0.00 | 3.00 ±0.00 | +0.0% | — |
metric_foreground_pct |
14.51 ±0.00 | 14.51 ±0.00 | +0.0% | — |
nii_get_array |
1.65 ±0.00 | 1.65 ±0.00 | +0.0% (noise) | — |
nii_compute_crop |
2.90 ±0.00 | 2.90 ±0.00 | +0.0% (noise) | — |
nii_unique |
2.96 ±0.00 | 2.96 ±0.00 | +0.0% (noise) | — |
poi_rescale |
2.61 ±0.00 | 2.61 ±0.00 | +0.0% (noise) | — |
poi_local_to_global_arr |
2.96 ±0.00 | 2.96 ±0.00 | +0.0% (noise) | — |
poi_save |
1.41 ±0.00 | 1.41 ±0.00 | +0.0% (noise) | — |
poi_map_labels |
1.78 ±0.00 | 1.78 ±0.00 | +0.0% (noise) | — |
poi_load |
1.62 ±0.00 | 1.62 ±0.00 | +0.0% (noise) | — |
ct_2d — shape (73, 47, 1)
| Measurement | baseline MiB (median ±½·range) | head MiB (median ±½·range) | Δ % | p |
|---|---|---|---|---|
nii_set_dtype |
5.18 ±0.00 | 5.14 ±0.00 | -0.8% | — |
poi_resample_from_to |
5.21 ±0.00 | 5.18 ±0.00 | -0.7% | — |
nii_pad_to |
5.36 ±0.00 | 5.32 ±0.00 | -0.7% | — |
nii_extract_label |
5.37 ±0.00 | 5.33 ±0.00 | -0.7% | — |
nii_map_labels |
5.43 ±0.00 | 5.39 ±0.00 | -0.7% | — |
… 30 more measurements
| Measurement | baseline MiB (median ±½·range) | head MiB (median ±½·range) | Δ % | p |
|---|---|---|---|---|
nii_apply_crop |
5.80 ±0.00 | 5.77 ±0.00 | -0.7% | — |
nii_reorient |
5.84 ±0.00 | 5.80 ±0.00 | -0.7% | — |
nii_dilate_msk |
5.87 ±0.00 | 5.83 ±0.00 | -0.7% | — |
nii_erode_msk |
5.88 ±0.00 | 5.84 ±0.00 | -0.7% | — |
poi_calc_centroids_nocrop |
5.93 ±0.00 | 5.89 ±0.00 | -0.7% | — |
nii_load_seg |
5.95 ±0.00 | 5.91 ±0.00 | -0.7% | — |
poi_calc_centroids |
5.99 ±0.00 | 5.95 ±0.00 | -0.7% | — |
nii_fill_holes |
6.22 ±0.00 | 6.18 ±0.00 | -0.6% | — |
nii_get_connected_components |
6.55 ±0.00 | 6.52 ±0.00 | -0.6% | — |
nii_filter_connected_components |
6.80 ±0.00 | 6.77 ±0.00 | -0.6% | — |
nii_load_img |
3.50 ±0.00 | 3.50 ±0.00 | +0.0% | — |
nii_save |
3.65 ±0.00 | 3.65 ±0.00 | +0.0% | — |
nii_rescale |
6.11 ±0.00 | 6.11 ±0.00 | +0.0% | — |
nii_rescale_seg |
5.88 ±0.00 | 5.88 ±0.00 | +0.0% | — |
nii_resample_from_to |
6.23 ±0.00 | 6.23 ±0.00 | +0.0% | — |
nii_volumes |
3.46 ±0.00 | 3.46 ±0.00 | +0.0% | — |
nii_center_of_masses |
3.21 ±0.00 | 3.21 ±0.00 | +0.0% | — |
poi_reorient |
3.77 ±0.00 | 3.77 ±0.00 | +0.0% | — |
poi_to_global |
3.02 ±0.00 | 3.02 ±0.00 | +0.0% | — |
metric_voxels |
3431.00 ±0.00 | 3431.00 ±0.00 | +0.0% | — |
metric_labels |
3.00 ±0.00 | 3.00 ±0.00 | +0.0% | — |
metric_foreground_pct |
37.60 ±0.00 | 37.60 ±0.00 | +0.0% | — |
nii_get_array |
1.59 ±0.00 | 1.59 ±0.00 | +0.0% (noise) | — |
nii_compute_crop |
2.84 ±0.00 | 2.84 ±0.00 | +0.0% (noise) | — |
nii_unique |
2.90 ±0.00 | 2.90 ±0.00 | +0.0% (noise) | — |
poi_rescale |
2.54 ±0.00 | 2.54 ±0.00 | +0.0% (noise) | — |
poi_local_to_global_arr |
2.89 ±0.00 | 2.89 ±0.00 | +0.0% (noise) | — |
poi_save |
1.34 ±0.00 | 1.34 ±0.00 | +0.0% (noise) | — |
poi_map_labels |
1.71 ±0.00 | 1.71 ±0.00 | +0.0% (noise) | — |
poi_load |
1.55 ±0.00 | 1.55 ±0.00 | +0.0% (noise) | — |
mri_3d — shape (68, 52, 67)
| Measurement | baseline MiB (median ±½·range) | head MiB (median ±½·range) | Δ % | p |
|---|---|---|---|---|
poi_resample_from_to |
5.21 ±0.00 | 5.18 ±0.00 | -0.7% | — |
nii_set_dtype |
5.24 ±0.00 | 5.20 ±0.00 | -0.7% | — |
nii_pad_to |
5.36 ±0.00 | 5.32 ±0.00 | -0.7% | — |
nii_extract_label |
5.37 ±0.00 | 5.33 ±0.00 | -0.7% | — |
nii_map_labels |
5.43 ±0.00 | 5.39 ±0.00 | -0.7% | — |
… 31 more measurements
| Measurement | baseline MiB (median ±½·range) | head MiB (median ±½·range) | Δ % | p |
|---|---|---|---|---|
nii_apply_crop |
5.80 ±0.00 | 5.77 ±0.00 | -0.7% | — |
nii_reorient |
5.84 ±0.00 | 5.80 ±0.00 | -0.7% | — |
poi_calc_centroids_nocrop |
5.86 ±0.00 | 5.82 ±0.00 | -0.7% | — |
nii_dilate_msk |
5.87 ±0.00 | 5.83 ±0.00 | -0.7% | — |
nii_erode_msk |
5.88 ±0.00 | 5.84 ±0.00 | -0.7% | — |
nii_load_seg |
5.95 ±0.00 | 5.91 ±0.00 | -0.7% | — |
poi_calc_centroids |
5.99 ±0.00 | 5.95 ±0.00 | -0.7% | — |
nii_fill_holes |
6.22 ±0.00 | 6.18 ±0.00 | -0.6% | — |
nii_get_connected_components |
6.55 ±0.00 | 6.52 ±0.00 | -0.6% | — |
nii_filter_connected_components |
6.80 ±0.00 | 6.77 ±0.00 | -0.6% | — |
poi_calc_poi_from_subreg_vert |
7.11 ±0.00 | 7.07 ±0.00 | -0.5% | — |
nii_load_img |
3.56 ±0.00 | 3.56 ±0.00 | +0.0% | — |
nii_save |
3.65 ±0.00 | 3.65 ±0.00 | +0.0% | — |
nii_rescale |
6.11 ±0.00 | 6.11 ±0.00 | +0.0% | — |
nii_rescale_seg |
5.88 ±0.00 | 5.88 ±0.00 | +0.0% | — |
nii_resample_from_to |
6.23 ±0.00 | 6.23 ±0.00 | +0.0% | — |
nii_volumes |
3.46 ±0.00 | 3.46 ±0.00 | +0.0% | — |
nii_center_of_masses |
3.21 ±0.00 | 3.21 ±0.00 | +0.0% | — |
poi_reorient |
3.77 ±0.00 | 3.77 ±0.00 | +0.0% | — |
poi_to_global |
3.02 ±0.00 | 3.02 ±0.00 | +0.0% | — |
metric_voxels |
236912.00 ±0.00 | 236912.00 ±0.00 | +0.0% | — |
metric_labels |
8.00 ±0.00 | 8.00 ±0.00 | +0.0% | — |
metric_foreground_pct |
18.21 ±0.00 | 18.21 ±0.00 | +0.0% | — |
nii_get_array |
1.59 ±0.00 | 1.59 ±0.00 | +0.0% (noise) | — |
nii_compute_crop |
2.84 ±0.00 | 2.84 ±0.00 | +0.0% (noise) | — |
nii_unique |
2.90 ±0.00 | 2.90 ±0.00 | +0.0% (noise) | — |
poi_rescale |
2.54 ±0.00 | 2.54 ±0.00 | +0.0% (noise) | — |
poi_local_to_global_arr |
2.89 ±0.00 | 2.89 ±0.00 | +0.0% (noise) | — |
poi_save |
1.40 ±0.00 | 1.40 ±0.00 | +0.0% (noise) | — |
poi_map_labels |
1.71 ±0.00 | 1.71 ±0.00 | +0.0% (noise) | — |
poi_load |
1.55 ±0.00 | 1.55 ±0.00 | +0.0% (noise) | — |
mri_2d — shape (68, 52, 1)
| Measurement | baseline MiB (median ±½·range) | head MiB (median ±½·range) | Δ % | p |
|---|---|---|---|---|
poi_resample_from_to |
5.21 ±0.00 | 5.18 ±0.00 | -0.7% | — |
nii_set_dtype |
5.24 ±0.00 | 5.20 ±0.00 | -0.7% | — |
nii_pad_to |
5.36 ±0.00 | 5.32 ±0.00 | -0.7% | — |
nii_extract_label |
5.37 ±0.00 | 5.33 ±0.00 | -0.7% | — |
nii_map_labels |
5.43 ±0.00 | 5.39 ±0.00 | -0.7% | — |
… 30 more measurements
| Measurement | baseline MiB (median ±½·range) | head MiB (median ±½·range) | Δ % | p |
|---|---|---|---|---|
nii_apply_crop |
5.80 ±0.00 | 5.77 ±0.00 | -0.7% | — |
nii_reorient |
5.84 ±0.00 | 5.80 ±0.00 | -0.7% | — |
nii_dilate_msk |
5.87 ±0.00 | 5.83 ±0.00 | -0.7% | — |
nii_erode_msk |
5.88 ±0.00 | 5.84 ±0.00 | -0.7% | — |
poi_calc_centroids_nocrop |
5.93 ±0.00 | 5.89 ±0.00 | -0.7% | — |
nii_load_seg |
5.95 ±0.00 | 5.91 ±0.00 | -0.7% | — |
poi_calc_centroids |
5.99 ±0.00 | 5.95 ±0.00 | -0.7% | — |
nii_fill_holes |
6.22 ±0.00 | 6.18 ±0.00 | -0.6% | — |
nii_get_connected_components |
6.55 ±0.00 | 6.52 ±0.00 | -0.6% | — |
nii_filter_connected_components |
6.80 ±0.00 | 6.77 ±0.00 | -0.6% | — |
nii_load_img |
3.56 ±0.00 | 3.56 ±0.00 | +0.0% | — |
nii_save |
3.65 ±0.00 | 3.65 ±0.00 | +0.0% | — |
nii_rescale |
6.11 ±0.00 | 6.11 ±0.00 | +0.0% | — |
nii_rescale_seg |
5.88 ±0.00 | 5.88 ±0.00 | +0.0% | — |
nii_resample_from_to |
6.23 ±0.00 | 6.23 ±0.00 | +0.0% | — |
nii_volumes |
3.46 ±0.00 | 3.46 ±0.00 | +0.0% | — |
nii_center_of_masses |
3.21 ±0.00 | 3.21 ±0.00 | +0.0% | — |
poi_reorient |
3.77 ±0.00 | 3.77 ±0.00 | +0.0% | — |
poi_to_global |
3.02 ±0.00 | 3.02 ±0.00 | +0.0% | — |
metric_voxels |
3536.00 ±0.00 | 3536.00 ±0.00 | +0.0% | — |
metric_labels |
7.00 ±0.00 | 7.00 ±0.00 | +0.0% | — |
metric_foreground_pct |
50.17 ±0.00 | 50.17 ±0.00 | +0.0% | — |
nii_get_array |
1.59 ±0.00 | 1.59 ±0.00 | +0.0% (noise) | — |
nii_compute_crop |
2.84 ±0.00 | 2.84 ±0.00 | +0.0% (noise) | — |
nii_unique |
2.90 ±0.00 | 2.90 ±0.00 | +0.0% (noise) | — |
poi_rescale |
2.54 ±0.00 | 2.54 ±0.00 | +0.0% (noise) | — |
poi_local_to_global_arr |
2.89 ±0.00 | 2.89 ±0.00 | +0.0% (noise) | — |
poi_save |
1.40 ±0.00 | 1.40 ±0.00 | +0.0% (noise) | — |
poi_map_labels |
1.71 ±0.00 | 1.71 ±0.00 | +0.0% (noise) | — |
poi_load |
1.55 ±0.00 | 1.55 ±0.00 | +0.0% (noise) | — |
Gate: a measurement fails when the baseline is ≥ 1 MiB, the median grows by ≥ 50%, and Welch's t-test gives p < 0.05. metric_* rows are context only.
Problem
The post-merge
testsjob fails onubuntu-latest/ Python 3.9:Root cause:
vtk9.7.0 (published 2026-08-15) is the first release with nocp39wheel — 9.6.2 was the last one. vtk also publishes norequires-pythonmetadata at all, so Poetry cannot auto-exclude it: it picks the newest version, then finds every wheel ABI-incompatible.Because
poetry.lockis gitignored (.gitignore:160), every CI run re-resolves from scratch, somainbroke the moment that release landed. No code change was involved.Why the PR checks were green but main failed
The two workflows installed differently:
tests_mr.ymlpull_requestpip install -e .tests.ymlpushtomainpython -m poetry installvtklives only in[tool.poetry.group.dev.dependencies], so the PR job never installed it. Only the post-merge job did.Changes
1.
pyproject.toml— split the vtk constraint by Python version2.
.github/workflows/tests_mr.yml— install via Poetry, matchingtests.ymlSplit into
Configure python(pip, poetry, flake8, pytest) andInstall dependencies(python -m poetry install); tests now run throughpython -m poetry run pytestso they execute inside the Poetry venv. flake8 still runs from the ambient interpreter, as intests.yml.This closes the gap that let the breakage through: PRs now exercise the dev group.
Verification
Run locally against this branch, reproducing the new PR-workflow sequence:
poetry installexits 0, resolvesvtk 9.6.2, installs the root project;poetry run pytest→ 462 passed, 6 skipped in 43s.vtk 9.7.0; no regression for the modern matrix entries.Follow-ups not included here
poetry.lockis gitignored, so CI re-resolves on every run. The new PR job catches this class of break at review time rather than preventing it; committing the lock would prevent it outright — a bigger workflow decision.pyvistais already frozen at^0.43.2because 0.44+ requires >=3.10 (current is 0.48.4), and vtk has now followed. 3.9 reached EOL in October 2025; dropping it would remove this category of pin entirely.🤖 Generated with Claude Code