Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions cuda_core/cuda/core/_event.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -330,9 +330,11 @@ cdef class IPCEventDescriptor:
self._is_blocking_sync = is_blocking_sync
return self

def __eq__(self, IPCEventDescriptor rhs):
def __eq__(self, other) -> bool:
if not isinstance(other, IPCEventDescriptor):
return NotImplemented
# No need to check self._is_blocking_sync.
return self._reserved == rhs._reserved
return self._reserved == (<IPCEventDescriptor>other)._reserved

def __reduce__(self):
return IPCEventDescriptor._init, (self._reserved, self._is_blocking_sync)
Expand Down
11 changes: 9 additions & 2 deletions cuda_core/cuda/core/_layout.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,15 @@ cdef class _StridedLayout:
f"_StridedLayout(shape={self.shape}, strides={self.strides}, itemsize={self.itemsize}, _slice_offset={self.slice_offset})"
)

def __eq__(self : _StridedLayout, other : _StridedLayout) -> bool:
return self.itemsize == other.itemsize and self.slice_offset == other.slice_offset and _base_layout_equal(self.base, other.base)
def __eq__(self, other):
if not isinstance(other, _StridedLayout):
return NotImplemented
cdef _StridedLayout _other = <_StridedLayout>other
return (
self.itemsize == _other.itemsize
and self.slice_offset == _other.slice_offset
and _base_layout_equal(self.base, _other.base)
)

@property
def ndim(self : _StridedLayout):
Expand Down
37 changes: 37 additions & 0 deletions cuda_core/tests/test_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,43 @@ def test_ipc_event_descriptor_direct_init():
_event_module.IPCEventDescriptor()


@pytest.mark.parametrize(
"other",
[None, "string", 42, 3.14, (b"\x00" * 64,), object()],
ids=["None", "str", "int", "float", "tuple", "object"],
)
def test_ipc_event_descriptor_eq_other_type(other):
"""IPCEventDescriptor.__eq__ returns NotImplemented for unrelated types.

Regression test for https://github.com/NVIDIA/cuda-python/issues/2050: comparing
an IPCEventDescriptor to objects of unrelated types must not raise TypeError /
AttributeError; it must follow Python's rich-comparison protocol and yield False.
"""
import cuda.core._event as _event_module

desc = _event_module.IPCEventDescriptor._init(b"\x00" * 64, True)
assert desc != other
assert not (desc == other) # noqa: SIM201
assert other != desc
assert desc.__eq__(other) is NotImplemented


def test_ipc_event_descriptor_eq_same_value():
"""Two IPCEventDescriptors with the same _reserved compare equal."""
import cuda.core._event as _event_module

reserved = b"\x01" * 64
a = _event_module.IPCEventDescriptor._init(reserved, True)
b = _event_module.IPCEventDescriptor._init(reserved, True)
c = _event_module.IPCEventDescriptor._init(b"\x02" * 64, True)
assert a == a
assert a == b
assert a != c
# _is_blocking_sync is intentionally ignored by __eq__.
d = _event_module.IPCEventDescriptor._init(reserved, False)
assert a == d


# ============================================================================
# Event Hash Tests
# ============================================================================
Expand Down
40 changes: 39 additions & 1 deletion cuda_core/tests/test_strided_layout.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# SPDX-License-Identifier: Apache-2.0

Expand Down Expand Up @@ -927,3 +927,41 @@ def test_to_dense(layout_spec, new_stride_order):
assert dense.is_dense
assert dense.required_size_in_bytes() == np_ref.size * layout.itemsize
assert dense.offset_bounds == (0, np_ref.size - 1)


@pytest.mark.parametrize(
"other",
[
None,
"string",
42,
3.14,
(3, 4),
[1, 2, 3],
object(),
],
ids=["None", "str", "int", "float", "tuple", "list", "object"],
)
def test_eq_returns_not_implemented_for_other_types(other):
"""_StridedLayout.__eq__ returns False (via NotImplemented) for unrelated types.

Regression test for https://github.com/NVIDIA/cuda-python/issues/2050: comparing
a _StridedLayout to objects of unrelated types must not raise AttributeError /
TypeError; it must follow Python's rich-comparison protocol and yield False.
"""
layout = _StridedLayout.dense((5, 3, 7), 4)
assert layout != other
assert not (layout == other) # noqa: SIM201
assert other != layout
# Direct check of the protocol contract.
assert layout.__eq__(other) is NotImplemented


def test_eq_reflexive_and_value_equality():
"""_StridedLayout equality is reflexive and compares by value, not identity."""
a = _StridedLayout.dense((5, 3, 7), 4)
b = _StridedLayout.dense((5, 3, 7), 4)
c = _StridedLayout.dense((5, 3, 8), 4)
assert a == a
assert a == b
assert a != c
Loading