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
15 changes: 11 additions & 4 deletions cid/set.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""CID Set operations for managing collections of unique CIDs."""

from collections.abc import Callable
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
from .cid import CIDv0, CIDv1
Expand Down Expand Up @@ -77,15 +77,22 @@ def visit(self, cid: "CIDv0 | CIDv1") -> bool:
return True
return False

def for_each(self, func: Callable[["CIDv0 | CIDv1"], None]) -> None:
def for_each(self, func: Callable[["CIDv0 | CIDv1"], "Any"]) -> "Exception | None":
"""
Call function for each CID in set.
Call function for each CID in set. Stop and return error if func raises or returns an error.

:param func: Function to call for each CID
:type func: callable
:return: Exception if an error occurred, None otherwise
"""
for cid in self._set:
func(cid)
try:
result = func(cid)
if result is not None and isinstance(result, Exception):
return result
except Exception as e:
return e
return None

def __iter__(self):
"""Make set iterable."""
Expand Down
1 change: 1 addition & 0 deletions newsfragments/69.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Update `CIDSet.for_each()` to stop iteration and return the error if the callback function raises an exception or returns an exception.
20 changes: 20 additions & 0 deletions tests/test_new_features.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,26 @@ def collect(cid):
assert cidv0 in collected
assert cidv1 in collected

def test_cid_set_for_each_error_propagation(self, cidv0, cidv1):
"""CIDSet.for_each: stops and propagates error"""
cid_set = CIDSet()
cid_set.add(cidv0)
cid_set.add(cidv1)

def failing_func(cid):
raise ValueError("test error")

result = cid_set.for_each(failing_func)
assert isinstance(result, ValueError)
assert str(result) == "test error"

def returning_func(cid):
return TypeError("return error")

result2 = cid_set.for_each(returning_func)
assert isinstance(result2, TypeError)
assert str(result2) == "return error"

def test_cid_set_contains(self, cidv0):
"""CIDSet.__contains__: supports 'in' operator"""
cid_set = CIDSet()
Expand Down
Loading