From e092f32944e67f9fa79590c71a52e341b6f85849 Mon Sep 17 00:00:00 2001 From: Arsalan Shakil Date: Thu, 18 Jun 2026 16:18:06 +0300 Subject: [PATCH] Fix #1169: correct NumPy skip conditions for DLPack host writes Writing into a host-accessible array obtained via np.from_dlpack requires NumPy 2.2.5+, because earlier versions return a read-only array (numpy GH #28632). Several tests and examples guarded these writes at NumPy 2.1.0, so on NumPy 2.1.0-2.2.4 they would error instead of skip. Audit all NumPy version guards in cuda_core and bump the write-into-DLPack sites to 2.2.5 with a consistent reason matching the existing correct guard in test_launcher.py. Guards that only read DLPack arrays (e.g. strided_memory_view_constructors.py) or skip for an unrelated NumPy fix (test_utils.py, numpy#26501) are left at 2.1. Also fix examples/memory_ops.py, which used a plain string comparison (np.__version__ < "2.1.0") that is unreliable for multi-digit versions; replace it with np.lib.NumpyVersion to match the other examples, and standardize test_graph_builder.py off a hand-rolled tuple skipif onto requires_module. Update affected PEP 723 dependency pins to numpy>=2.2.5. Signed-off-by: Arsalan Shakil --- cuda_core/examples/graph_update.py | 9 ++++++--- cuda_core/examples/memory_ops.py | 11 ++++++----- cuda_core/examples/memory_pool_resources.py | 9 ++++++--- cuda_core/tests/graph/test_device_launch.py | 4 ++-- cuda_core/tests/graph/test_graph_builder.py | 4 ++-- .../tests/graph/test_graph_builder_conditional.py | 8 ++++---- .../tests/graph/test_graph_definition_mutation.py | 4 ++-- cuda_core/tests/graph/test_graph_update.py | 4 ++-- cuda_core/tests/test_launcher.py | 4 ++-- 9 files changed, 32 insertions(+), 25 deletions(-) diff --git a/cuda_core/examples/graph_update.py b/cuda_core/examples/graph_update.py index c4918877b55..7b3dc5c26b2 100644 --- a/cuda_core/examples/graph_update.py +++ b/cuda_core/examples/graph_update.py @@ -10,7 +10,7 @@ # ################################################################################ # /// script -# dependencies = ["cuda_bindings", "cuda_core", "nvidia-cuda-nvrtc", "numpy>=2.1"] +# dependencies = ["cuda_bindings", "cuda_core", "nvidia-cuda-nvrtc", "numpy>=2.2.5"] # /// import sys @@ -44,8 +44,11 @@ def build_increment_graph(device, kernel, target_ptr): def main(): - if np.lib.NumpyVersion(np.__version__) < "2.1.0": - print("This example requires NumPy 2.1.0 or later", file=sys.stderr) + # Writing into the pinned host array imported via DLPack requires NumPy + # 2.2.5+ (np.from_dlpack returns a read-only array on earlier versions; + # see numpy GH #28632). + if np.lib.NumpyVersion(np.__version__) < "2.2.5": + print("This example requires NumPy 2.2.5 or later", file=sys.stderr) sys.exit(1) device = Device() diff --git a/cuda_core/examples/memory_ops.py b/cuda_core/examples/memory_ops.py index 549686b466a..8b845821c7c 100644 --- a/cuda_core/examples/memory_ops.py +++ b/cuda_core/examples/memory_ops.py @@ -5,13 +5,14 @@ # ################################################################################ # # This example demonstrates memory resources for allocation and management, -# copying data between device and pinned memory, and DLPack interop. Requires -# NumPy 2.1.0+. +# copying data between device and pinned memory, and DLPack interop. Writing +# into the pinned host array imported via DLPack requires NumPy 2.2.5+ (arrays +# from np.from_dlpack are read-only on earlier versions; see numpy GH #28632). # # ################################################################################ # /// script -# dependencies = ["cuda_bindings", "cuda_core", "nvidia-cuda-nvrtc", "cupy-cuda13x"] +# dependencies = ["cuda_bindings", "cuda_core", "nvidia-cuda-nvrtc", "cupy-cuda13x", "numpy>=2.2.5"] # /// import sys @@ -47,8 +48,8 @@ def main(): - if np.__version__ < "2.1.0": - print("This example requires NumPy 2.1.0 or later", file=sys.stderr) + if np.lib.NumpyVersion(np.__version__) < "2.2.5": + print("This example requires NumPy 2.2.5 or later", file=sys.stderr) sys.exit(1) dev = Device() diff --git a/cuda_core/examples/memory_pool_resources.py b/cuda_core/examples/memory_pool_resources.py index cc992fc6c29..aa322ecc206 100644 --- a/cuda_core/examples/memory_pool_resources.py +++ b/cuda_core/examples/memory_pool_resources.py @@ -11,7 +11,7 @@ # ################################################################################ # /// script -# dependencies = ["cuda_bindings", "cuda_core", "nvidia-cuda-nvrtc", "numpy>=2.1"] +# dependencies = ["cuda_bindings", "cuda_core", "nvidia-cuda-nvrtc", "numpy>=2.2.5"] # /// import sys @@ -43,8 +43,11 @@ def main(): - if np.lib.NumpyVersion(np.__version__) < "2.1.0": - print("This example requires NumPy 2.1.0 or later", file=sys.stderr) + # Writing into the managed/pinned host arrays imported via DLPack requires + # NumPy 2.2.5+ (np.from_dlpack returns a read-only array on earlier + # versions; see numpy GH #28632). + if np.lib.NumpyVersion(np.__version__) < "2.2.5": + print("This example requires NumPy 2.2.5 or later", file=sys.stderr) sys.exit(1) device = Device() diff --git a/cuda_core/tests/graph/test_device_launch.py b/cuda_core/tests/graph/test_device_launch.py index 0e9367077da..221b09bd815 100644 --- a/cuda_core/tests/graph/test_device_launch.py +++ b/cuda_core/tests/graph/test_device_launch.py @@ -76,7 +76,7 @@ def _compile_device_launcher_kernel(): Device().compute_capability.major < 9, reason="Device-side graph launch requires Hopper (sm_90+) architecture", ) -@requires_module(np, "2.1") +@requires_module(np, "2.2.5", reason="need numpy 2.2.5+ (numpy GH #28632)") def test_device_launch_basic(init_cuda): """Test basic device-side graph launch functionality. @@ -128,7 +128,7 @@ def test_device_launch_basic(init_cuda): Device().compute_capability.major < 9, reason="Device-side graph launch requires Hopper (sm_90+) architecture", ) -@requires_module(np, "2.1") +@requires_module(np, "2.2.5", reason="need numpy 2.2.5+ (numpy GH #28632)") def test_device_launch_multiple(init_cuda): """Test that device-side graph launch can be executed multiple times. diff --git a/cuda_core/tests/graph/test_graph_builder.py b/cuda_core/tests/graph/test_graph_builder.py index e0e3fd9a51c..43866132967 100644 --- a/cuda_core/tests/graph/test_graph_builder.py +++ b/cuda_core/tests/graph/test_graph_builder.py @@ -118,7 +118,7 @@ def test_graph_is_join_required(init_cuda): gb.end_building().complete() -@requires_module(np, "2.1") +@requires_module(np, "2.2.5", reason="need numpy 2.2.5+ (numpy GH #28632)") def test_graph_repeat_capture(init_cuda): mod = compile_common_kernels() add_one = mod.get_kernel("add_one") @@ -209,7 +209,7 @@ def read_byte(data): assert result[0] == 0xAB -@pytest.mark.skipif(tuple(int(i) for i in np.__version__.split(".")[:2]) < (2, 1), reason="need numpy 2.1.0+") +@requires_module(np, "2.2.5", reason="need numpy 2.2.5+ (numpy GH #28632)") def test_graph_child_graph(init_cuda): mod = compile_common_kernels() add_one = mod.get_kernel("add_one") diff --git a/cuda_core/tests/graph/test_graph_builder_conditional.py b/cuda_core/tests/graph/test_graph_builder_conditional.py index 69956cf0f21..e50b061e6f9 100644 --- a/cuda_core/tests/graph/test_graph_builder_conditional.py +++ b/cuda_core/tests/graph/test_graph_builder_conditional.py @@ -17,7 +17,7 @@ @pytest.mark.parametrize( "condition_value", [True, False, ctypes.c_bool(True), ctypes.c_bool(False), np.bool_(True), np.bool_(False), 1, 0] ) -@requires_module(np, "2.1") +@requires_module(np, "2.2.5", reason="need numpy 2.2.5+ (numpy GH #28632)") def test_graph_conditional_if(init_cuda, condition_value): mod = compile_conditional_kernels(type(condition_value)) add_one = mod.get_kernel("add_one") @@ -81,7 +81,7 @@ def test_graph_conditional_if(init_cuda, condition_value): @pytest.mark.parametrize( "condition_value", [True, False, ctypes.c_bool(True), ctypes.c_bool(False), np.bool_(True), np.bool_(False), 1, 0] ) -@requires_module(np, "2.1") +@requires_module(np, "2.2.5", reason="need numpy 2.2.5+ (numpy GH #28632)") def test_graph_conditional_if_else(init_cuda, condition_value): mod = compile_conditional_kernels(type(condition_value)) add_one = mod.get_kernel("add_one") @@ -153,7 +153,7 @@ def test_graph_conditional_if_else(init_cuda, condition_value): @pytest.mark.parametrize("condition_value", [0, 1, 2, 3]) -@requires_module(np, "2.1") +@requires_module(np, "2.2.5", reason="need numpy 2.2.5+ (numpy GH #28632)") def test_graph_conditional_switch(init_cuda, condition_value): mod = compile_conditional_kernels(type(condition_value)) add_one = mod.get_kernel("add_one") @@ -244,7 +244,7 @@ def test_graph_conditional_switch(init_cuda, condition_value): @pytest.mark.parametrize("condition_value", [True, False, 1, 0]) -@requires_module(np, "2.1") +@requires_module(np, "2.2.5", reason="need numpy 2.2.5+ (numpy GH #28632)") def test_graph_conditional_while(init_cuda, condition_value): mod = compile_conditional_kernels(type(condition_value)) add_one = mod.get_kernel("add_one") diff --git a/cuda_core/tests/graph/test_graph_definition_mutation.py b/cuda_core/tests/graph/test_graph_definition_mutation.py index 1db1089f825..7ac3a9e9853 100644 --- a/cuda_core/tests/graph/test_graph_definition_mutation.py +++ b/cuda_core/tests/graph/test_graph_definition_mutation.py @@ -139,7 +139,7 @@ def close(self): self._buf.close() -@requires_module(np, "2.1") +@requires_module(np, "2.2.5", reason="need numpy 2.2.5+ (numpy GH #28632)") class TestMutateYRig: """Tests that mutate the Y-shaped graph built by YRig.""" @@ -335,7 +335,7 @@ def test_self_edge(init_cuda): node.succ.add(node) -@requires_module(np, "2.1") +@requires_module(np, "2.2.5", reason="need numpy 2.2.5+ (numpy GH #28632)") def test_convert_linear_to_fan_in(init_cuda): """Chain four computations sequentially, then rewire so all pairs run in parallel feeding into a reduce node. diff --git a/cuda_core/tests/graph/test_graph_update.py b/cuda_core/tests/graph/test_graph_update.py index 206fabcd587..556c187aeef 100644 --- a/cuda_core/tests/graph/test_graph_update.py +++ b/cuda_core/tests/graph/test_graph_update.py @@ -14,7 +14,7 @@ @pytest.mark.parametrize("builder", ["GraphBuilder", "GraphDefinition"]) -@requires_module(np, "2.1") +@requires_module(np, "2.2.5", reason="need numpy 2.2.5+ (numpy GH #28632)") def test_graph_update_kernel_args(init_cuda, builder): """Update redirects a kernel to write to a different pointer.""" mod = compile_common_kernels() @@ -60,7 +60,7 @@ def build(ptr): b.close() -@requires_module(np, "2.1") +@requires_module(np, "2.2.5", reason="need numpy 2.2.5+ (numpy GH #28632)") def test_graph_update_conditional(init_cuda): """Update swaps conditional switch graphs with matching topology.""" mod = compile_conditional_kernels(int) diff --git a/cuda_core/tests/test_launcher.py b/cuda_core/tests/test_launcher.py index 15a2108e411..942952d29b8 100644 --- a/cuda_core/tests/test_launcher.py +++ b/cuda_core/tests/test_launcher.py @@ -320,7 +320,7 @@ def test_launch_invalid_values(init_cuda): @pytest.mark.parametrize("python_type, cpp_type, init_value", PARAMS) -@requires_module(np, "2.1") +@requires_module(np, "2.2.5", reason="need numpy 2.2.5+ (numpy GH #28632)") def test_launch_scalar_argument(python_type, cpp_type, init_value): dev = Device() dev.set_current() @@ -536,7 +536,7 @@ class MyBool(ctypes.c_bool): assert holder.ptr != 0 -@requires_module(np, "2.1") +@requires_module(np, "2.2.5", reason="need numpy 2.2.5+ (numpy GH #28632)") @pytest.mark.parametrize( ("scalar_kind", "np_dtype", "cpp_type", "raw_value"), [