ENH: Backport #6026 — PEP 688 buffer protocol and np.asarray() lifetime safety#6042
Open
hjmjohnson wants to merge 1 commit intoInsightSoftwareConsortium:release-5.4from
Open
Conversation
Add zero-copy data export to all wrapped itk.Image types via three
protocols, ensuring the exported array remains valid even after
the source image is deleted:
image = itk.imread("brain.nii.gz")
arr = np.asarray(image)
del image
print(arr[1,1,1]) # safe -- no crash
Protocol dispatch by Python version:
3.12+: np.asarray -> __buffer__ (PEP 688, zero-copy, memoryview
pins self via NDArrayITKBase intermediary)
3.10-11: np.asarray -> __array_interface__ (zero-copy, NumPy sets
arr.base = self, preventing image GC)
All versions: image.__array__() returns NDArrayITKBase with
.itk_base = image for explicit __array__ calls.
Changes to pyBase.i:
- Add __buffer__() implementing PEP 688 buffer export with shaped
memoryview. Uses NDArrayITKBase as intermediary to hold a Python
reference to the image, preventing GC while any derived
memoryview/array exists. flags parameter accepted for PEP 688
compliance but not inspected (ITK buffers always writable).
- Add __array_interface__ property returning NumPy v3 array
interface dict. NumPy sets arr.base = self when creating arrays
from this interface, providing correct lifetime on 3.10-3.11.
- Simplify __array__() to always return zero-copy view via
array_view_from_image(). Supports NumPy 2.0 copy= parameter.
copy=True returns a plain ndarray so image can be GCd.
Changes to PyBuffer.i.init:
- Add _BUFFER_FORMAT_MAP constant (before function definition)
- Add _get_buffer_formatstring() with descriptive KeyError
- Add _NUMPY_PIXELID_MAP and _get_numpy_pixelid()
- Remove LD (long double) mapping (silent corruption)
Tested: Python 3.10-3.14, all pass (0 failures).
Supersedes InsightSoftwareConsortium#6020, InsightSoftwareConsortium#6018, InsightSoftwareConsortium#5673, InsightSoftwareConsortium#5665.
Addresses @thewtex (del image crash), @blowekamp (ref pinning).
Co-Authored-By: Hans J. Johnson <hans-johnson@uiowa.edu>
(cherry picked from commit 45a5096)
2 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Backport of #6026 (merged as
45a50960daon main) torelease-5.4.Cherry-picks the PEP 688 buffer protocol implementation and
np.asarray()zero-copy lifetime safety fix onto the v5.4.x branch so that downstream consumers pinning to ITK 5.4 get the correctdel image; arr[1,1,1]behavior without needing to wait for the ITK 6.x release.What's in the cherry-pick
Modules/Bridge/NumPy/wrapping/PyBuffer.i.init— adds_BUFFER_FORMAT_MAP,_NUMPY_PIXELID_MAP, and the helper accessors; removes the long-double (LD) mapping that caused silent data corruption.Wrapping/Generators/Python/PyBase/pyBase.i— adds__buffer__()(PEP 688),__array_interface__property for NumPy v3, and simplifies__array__()to always return a zero-copy view viaNDArrayITKBase(which pins the source image to prevent GC while any derived memoryview/array exists). Supports NumPy 2.0'scopy=parameter.Cherry-picked cleanly (one auto-merge in
pyBase.i, no hand resolution needed).Test plan
Dependency note
The companion follow-up backport of #6027 (comprehensive tests for this feature) is stacked on top of this branch. It is intentionally a separate PR so the fix can be reviewed and merged independently. Please merge this PR before the #6027 backport.
🤖 Generated with Claude Code