From 87e90cc170f23288ae295605df33f545b8c67af5 Mon Sep 17 00:00:00 2001 From: ed cuss Date: Fri, 24 Jul 2026 21:24:27 +0100 Subject: [PATCH 1/3] fix: handle when provided par_collect workers would be 0 --- src/danom/_stream.py | 2 ++ tests/test_stream.py | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/danom/_stream.py b/src/danom/_stream.py index 66e3898..223255a 100644 --- a/src/danom/_stream.py +++ b/src/danom/_stream.py @@ -472,6 +472,8 @@ def par_collect(self, workers: int = 4, *, use_threads: bool = False) -> tuple[U if workers == -1: workers = (os.cpu_count() or 5) - 1 + workers = max(workers, 1) + executor_cls = ThreadPoolExecutor if use_threads else ProcessPoolExecutor batches = [ diff --git a/tests/test_stream.py b/tests/test_stream.py index 6a56247..d531f02 100644 --- a/tests/test_stream.py +++ b/tests/test_stream.py @@ -34,6 +34,9 @@ def _get_attr_collect(stream: Stream, collect_fn: str, kwargs: dict) -> tuple: pytest.param("collect", {}, id="simple `collect`"), pytest.param("par_collect", {"workers": 4}, id="`par_collect` with workers passed in"), pytest.param("par_collect", {"workers": -1}, id="`par_collect` with n-1 workers"), + pytest.param( + "par_collect", {"workers": 0}, id="`par_collect` with 0 workers falls back to 1 worker" + ), pytest.param("par_collect", {"use_threads": True}, id="`par_collect` with threads True"), ], ) From e545874ec3728d1c9032fe9d7a20bda811fc0d2f Mon Sep 17 00:00:00 2001 From: ed cuss Date: Fri, 24 Jul 2026 21:28:46 +0100 Subject: [PATCH 2/3] fix: propagate traceback and input args on map_err --- src/danom/_result.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/danom/_result.py b/src/danom/_result.py index f8b431d..69d8d63 100644 --- a/src/danom/_result.py +++ b/src/danom/_result.py @@ -264,7 +264,9 @@ def map[**P](self, func: Mappable, *args: P.args, **kwargs: P.kwargs) -> Self: return self def map_err[**P](self, func: Mappable, *args: P.args, **kwargs: P.kwargs) -> Err[E_co]: - return Err(func(self.error, *args, **kwargs)) + return Err( + func(self.error, *args, **kwargs), input_args=self.input_args, traceback=self.traceback + ) def and_then[**P](self, func: Bindable, *args: P.args, **kwargs: P.kwargs) -> Self: # noqa: ARG002 return self From 1b4af7487b5619fc84f819cb59c808b19ece8f5e Mon Sep 17 00:00:00 2001 From: ed cuss Date: Fri, 24 Jul 2026 21:31:12 +0100 Subject: [PATCH 3/3] docs: don't promise true immutability --- src/danom/_stream.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/danom/_stream.py b/src/danom/_stream.py index 223255a..92ca9e6 100644 --- a/src/danom/_stream.py +++ b/src/danom/_stream.py @@ -89,7 +89,7 @@ def __bool__(self) -> bool: @attrs.define(frozen=True) class Stream[T](_BaseStream): - """An immutable lazy iterator with functional operations. + """A lazy iterator with functional operations. Why bother? -----------