streamable 2.1.0b1__tar.gz → 2.1.0b2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. streamable-2.1.0b2/MANIFEST.in +1 -0
  2. {streamable-2.1.0b1 → streamable-2.1.0b2}/PKG-INFO +17 -2
  3. {streamable-2.1.0b1 → streamable-2.1.0b2}/pyproject.toml +18 -1
  4. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/__init__.py +1 -1
  5. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable.egg-info/PKG-INFO +17 -2
  6. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable.egg-info/SOURCES.txt +2 -20
  7. streamable-2.1.0b1/tests/test_buffer.py +0 -91
  8. streamable-2.1.0b1/tests/test_catch.py +0 -269
  9. streamable-2.1.0b1/tests/test_closing.py +0 -829
  10. streamable-2.1.0b1/tests/test_do.py +0 -31
  11. streamable-2.1.0b1/tests/test_eq.py +0 -146
  12. streamable-2.1.0b1/tests/test_filter.py +0 -23
  13. streamable-2.1.0b1/tests/test_flatten.py +0 -140
  14. streamable-2.1.0b1/tests/test_group.py +0 -310
  15. streamable-2.1.0b1/tests/test_map.py +0 -204
  16. streamable-2.1.0b1/tests/test_observe.py +0 -360
  17. streamable-2.1.0b1/tests/test_other.py +0 -525
  18. streamable-2.1.0b1/tests/test_readme.py +0 -383
  19. streamable-2.1.0b1/tests/test_ref_cycles.py +0 -199
  20. streamable-2.1.0b1/tests/test_repr.py +0 -126
  21. streamable-2.1.0b1/tests/test_skip.py +0 -53
  22. streamable-2.1.0b1/tests/test_take.py +0 -86
  23. streamable-2.1.0b1/tests/test_throttle.py +0 -73
  24. streamable-2.1.0b1/tests/test_tools.py +0 -98
  25. streamable-2.1.0b1/tests/test_visitor.py +0 -52
  26. {streamable-2.1.0b1 → streamable-2.1.0b2}/LICENSE +0 -0
  27. {streamable-2.1.0b1 → streamable-2.1.0b2}/README.md +0 -0
  28. {streamable-2.1.0b1 → streamable-2.1.0b2}/setup.cfg +0 -0
  29. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/_afunctions.py +0 -0
  30. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/_aiterators.py +0 -0
  31. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/_functions.py +0 -0
  32. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/_iterators.py +0 -0
  33. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/_stream.py +0 -0
  34. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/_tools/__init__.py +0 -0
  35. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/_tools/_afuture.py +0 -0
  36. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/_tools/_async.py +0 -0
  37. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/_tools/_context.py +0 -0
  38. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/_tools/_error.py +0 -0
  39. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/_tools/_func.py +0 -0
  40. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/_tools/_future.py +0 -0
  41. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/_tools/_iter.py +0 -0
  42. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/_tools/_logging.py +0 -0
  43. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/_tools/_observation.py +0 -0
  44. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/_tools/_sentinel.py +0 -0
  45. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/_tools/_star.py +0 -0
  46. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/_tools/_validation.py +0 -0
  47. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/py.typed +0 -0
  48. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/visitors/__init__.py +0 -0
  49. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/visitors/_aiter.py +0 -0
  50. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/visitors/_base.py +0 -0
  51. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/visitors/_eq.py +0 -0
  52. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/visitors/_involves_async.py +0 -0
  53. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/visitors/_iter.py +0 -0
  54. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable/visitors/_repr.py +0 -0
  55. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable.egg-info/dependency_links.txt +0 -0
  56. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable.egg-info/requires.txt +0 -0
  57. {streamable-2.1.0b1 → streamable-2.1.0b2}/streamable.egg-info/top_level.txt +0 -0
@@ -0,0 +1 @@
1
+ prune tests
@@ -1,10 +1,25 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: streamable
3
- Version: 2.1.0b1
3
+ Version: 2.1.0b2
4
4
  Summary: sync/async iterable streams for Python
5
5
  Author-email: ebonnal <bonnal.enzo.dev@gmail.com>
6
- License: Apache 2.
6
+ License: Apache-2.0
7
7
  Project-URL: Homepage, https://github.com/ebonnal/streamable
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: Framework :: AsyncIO
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3 :: Only
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Programming Language :: Python :: 3.15
22
+ Classifier: Typing :: Typed
8
23
  Requires-Python: >=3.8
9
24
  Description-Content-Type: text/markdown
10
25
  License-File: LICENSE
@@ -7,10 +7,27 @@ name = "streamable"
7
7
  dynamic = ["version"]
8
8
  description = "sync/async iterable streams for Python"
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
- license = { text = "Apache 2." }
10
+ license = { text = "Apache-2.0" }
11
11
  authors = [{ name = "ebonnal", email = "bonnal.enzo.dev@gmail.com" }]
12
12
  urls = { Homepage = "https://github.com/ebonnal/streamable" }
13
13
  requires-python = ">=3.8"
14
+ classifiers = [
15
+ "Development Status :: 5 - Production/Stable",
16
+ "Framework :: AsyncIO",
17
+ "Intended Audience :: Developers",
18
+ "Operating System :: OS Independent",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3 :: Only",
21
+ "Programming Language :: Python :: 3.8",
22
+ "Programming Language :: Python :: 3.9",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Programming Language :: Python :: 3.13",
27
+ "Programming Language :: Python :: 3.14",
28
+ "Programming Language :: Python :: 3.15",
29
+ "Typing :: Typed",
30
+ ]
14
31
  dependencies = []
15
32
 
16
33
  [project.optional-dependencies]
@@ -12,4 +12,4 @@ ClosableAsyncIterator.__module__ = __name__
12
12
 
13
13
  __all__ = ["stream", "star", "Observation", "ClosableAsyncIterator"]
14
14
 
15
- __version__ = "2.1.0b1"
15
+ __version__ = "2.1.0b2"
@@ -1,10 +1,25 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: streamable
3
- Version: 2.1.0b1
3
+ Version: 2.1.0b2
4
4
  Summary: sync/async iterable streams for Python
5
5
  Author-email: ebonnal <bonnal.enzo.dev@gmail.com>
6
- License: Apache 2.
6
+ License: Apache-2.0
7
7
  Project-URL: Homepage, https://github.com/ebonnal/streamable
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: Framework :: AsyncIO
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3 :: Only
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Programming Language :: Python :: 3.15
22
+ Classifier: Typing :: Typed
8
23
  Requires-Python: >=3.8
9
24
  Description-Content-Type: text/markdown
10
25
  License-File: LICENSE
@@ -1,4 +1,5 @@
1
1
  LICENSE
2
+ MANIFEST.in
2
3
  README.md
3
4
  pyproject.toml
4
5
  streamable/__init__.py
@@ -32,23 +33,4 @@ streamable/visitors/_base.py
32
33
  streamable/visitors/_eq.py
33
34
  streamable/visitors/_involves_async.py
34
35
  streamable/visitors/_iter.py
35
- streamable/visitors/_repr.py
36
- tests/test_buffer.py
37
- tests/test_catch.py
38
- tests/test_closing.py
39
- tests/test_do.py
40
- tests/test_eq.py
41
- tests/test_filter.py
42
- tests/test_flatten.py
43
- tests/test_group.py
44
- tests/test_map.py
45
- tests/test_observe.py
46
- tests/test_other.py
47
- tests/test_readme.py
48
- tests/test_ref_cycles.py
49
- tests/test_repr.py
50
- tests/test_skip.py
51
- tests/test_take.py
52
- tests/test_throttle.py
53
- tests/test_tools.py
54
- tests/test_visitor.py
36
+ streamable/visitors/_repr.py
@@ -1,91 +0,0 @@
1
- import sys
2
- from typing import Any, Callable, List
3
-
4
- import pytest
5
-
6
- from streamable import stream
7
- from tests.tools.func import async_slow_identity, slow_identity
8
- from tests.tools.iter import (
9
- ITERABLE_TYPES,
10
- IterableType,
11
- aiter_or_iter,
12
- alist_or_list,
13
- anext_or_next,
14
- stopiteration_type,
15
- )
16
- from tests.tools.source import INTEGERS, ints
17
-
18
-
19
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
20
- def test_buffer_raises_on_invalid_up_to(itype: IterableType) -> None:
21
- with pytest.raises(ValueError, match="`up_to` must be >= 1 but got: 0"):
22
- alist_or_list(stream([1]).buffer(0), itype)
23
-
24
-
25
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
26
- def test_buffer_preserves_elements(itype: IterableType) -> None:
27
- assert alist_or_list(ints.buffer(5), itype) == list(INTEGERS)
28
-
29
-
30
- @pytest.mark.parametrize("buffer_size", [1, 10, None])
31
- @pytest.mark.parametrize(
32
- "itype, slow_identity",
33
- [("sync", slow_identity), ("async", async_slow_identity)],
34
- )
35
- def test_buffer_size_is_respected(
36
- itype: IterableType, buffer_size: int, slow_identity: Callable[..., Any]
37
- ) -> None:
38
- buffered: List[int] = []
39
- buffering_ints = ints.do(buffered.append).buffer(buffer_size).map(slow_identity)
40
- buffering_ints_iter = aiter_or_iter(buffering_ints, itype)
41
- assert buffered == []
42
- assert anext_or_next(buffering_ints_iter, itype) == 0
43
- assert (
44
- buffered == list(INTEGERS)[: (buffer_size + 1) if buffer_size else sys.maxsize]
45
- )
46
- assert anext_or_next(buffering_ints_iter, itype) == 1
47
- assert (
48
- buffered == list(INTEGERS)[: (buffer_size + 2) if buffer_size else sys.maxsize]
49
- )
50
-
51
-
52
- @pytest.mark.parametrize(
53
- "itype, slow_identity",
54
- [("sync", slow_identity), ("async", async_slow_identity)],
55
- )
56
- def test_buffer_with_exceptions(
57
- itype: IterableType, slow_identity: Callable[..., Any]
58
- ) -> None:
59
- buffered: List[int] = []
60
- buffersize = 3
61
- buffering_ints = (
62
- stream("0-23--6")
63
- .map(int)
64
- .do(buffered.append)
65
- .buffer(buffersize)
66
- .map(slow_identity)
67
- )
68
- buffering_ints_iter = aiter_or_iter(buffering_ints, itype)
69
- assert buffered == []
70
- assert anext_or_next(buffering_ints_iter, itype) == 0
71
- assert buffered == [0, 2, 3]
72
- with pytest.raises(ValueError):
73
- anext_or_next(buffering_ints_iter, itype)
74
- assert anext_or_next(buffering_ints_iter, itype) == 2
75
- assert buffered == [0, 2, 3]
76
- assert anext_or_next(buffering_ints_iter, itype) == 3
77
- assert buffered == [0, 2, 3, 6]
78
- with pytest.raises(ValueError):
79
- anext_or_next(buffering_ints_iter, itype)
80
- with pytest.raises(ValueError):
81
- anext_or_next(buffering_ints_iter, itype)
82
- assert anext_or_next(buffering_ints_iter, itype) == 6
83
- assert buffered == [0, 2, 3, 6]
84
- with pytest.raises(stopiteration_type(itype)):
85
- anext_or_next(buffering_ints_iter, itype)
86
-
87
-
88
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
89
- def test_buffer_chain_of_background_task(itype: IterableType) -> None:
90
- s = stream(INTEGERS).buffer(2).buffer(2)
91
- assert alist_or_list(s, itype) == list(INTEGERS)
@@ -1,269 +0,0 @@
1
- from typing import Any, Callable, List, Union
2
-
3
- import pytest
4
-
5
- from streamable import stream
6
- from streamable._tools._func import asyncify
7
- from tests.tools.error import TestError
8
- from tests.tools.func import async_identity, identity, inverse, throw_func
9
- from tests.tools.iter import (
10
- ITERABLE_TYPES,
11
- IterableType,
12
- aiter_or_iter,
13
- alist_or_list,
14
- anext_or_next,
15
- )
16
- from tests.tools.source import INTEGERS, ints
17
-
18
-
19
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
20
- def test_catch_yields_elements_without_exceptions(itype: IterableType) -> None:
21
- s = ints.catch(Exception)
22
- assert alist_or_list(s, itype) == list(INTEGERS)
23
-
24
-
25
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
26
- def test_catch_ignores_matching_exceptions(itype: IterableType) -> None:
27
- s = stream("12-34").map(int).catch(ValueError)
28
- assert alist_or_list(s, itype) == [1, 2, 3, 4]
29
-
30
-
31
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
32
- def test_catch_raises_non_matching_exceptions(itype: IterableType) -> None:
33
- chars = "1-2034"
34
- s = stream(chars).map(int).do(inverse).catch(ValueError)
35
- stream_iter = aiter_or_iter(s, itype)
36
- assert anext_or_next(stream_iter, itype) == 1
37
- # ValueError caught for `int("-")`
38
- assert anext_or_next(stream_iter, itype) == 2
39
- with pytest.raises(ZeroDivisionError):
40
- anext_or_next(stream_iter, itype)
41
- assert anext_or_next(stream_iter, itype) == 3
42
- assert anext_or_next(stream_iter, itype) == 4
43
-
44
-
45
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
46
- def test_catch_handles_thousands_of_consecutive_exceptions(itype: IterableType) -> None:
47
- s = stream(range(2000)).map(throw_func(TestError)).catch(TestError)
48
- assert alist_or_list(s, itype) == []
49
-
50
-
51
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
52
- def test_catch_chained(itype: IterableType) -> None:
53
- chars = "1-2034"
54
- s = stream(chars).map(int).do(inverse).catch(ValueError).catch(ZeroDivisionError)
55
- assert alist_or_list(s, itype) == [1, 2, 3, 4]
56
-
57
-
58
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
59
- def test_catch_tuple(itype: IterableType) -> None:
60
- chars = "1-2034"
61
- s = stream(chars).map(int).do(inverse).catch((ValueError, ZeroDivisionError))
62
- assert alist_or_list(s, itype) == [1, 2, 3, 4]
63
-
64
-
65
- @pytest.mark.parametrize("adapt", [identity, asyncify])
66
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
67
- def test_catch_where(itype: IterableType, adapt: Callable[[Any], Any]) -> None:
68
- inputs: List[Union[str, float]] = ["0", float("nan"), "1", "-", "2"]
69
- s: stream[int] = (
70
- stream(inputs)
71
- .map(int)
72
- .catch(ValueError, where=adapt(lambda e: "cannot convert float NaN" in str(e)))
73
- )
74
- stream_iter = aiter_or_iter(s, itype)
75
- assert anext_or_next(stream_iter, itype) == 0
76
- # caught ValueError caused by `int("nan")`
77
- assert anext_or_next(stream_iter, itype) == 1
78
- # but did not catch ValueError caused by `int("-")`
79
- with pytest.raises(
80
- ValueError, match=r"invalid literal for int\(\) with base 10: '-'"
81
- ):
82
- anext_or_next(stream_iter, itype)
83
- assert anext_or_next(stream_iter, itype) == 2
84
-
85
-
86
- @pytest.mark.parametrize("adapt", [identity, asyncify])
87
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
88
- def test_catch_replace_with_none(
89
- itype: IterableType, adapt: Callable[[Any], Any]
90
- ) -> None:
91
- s = stream("1-23").map(int).catch(ValueError, replace=adapt(lambda e: None))
92
- elems: List[Union[int, None]] = alist_or_list(s, itype)
93
- assert elems == [1, None, 2, 3]
94
-
95
-
96
- @pytest.mark.parametrize("adapt", [identity, asyncify])
97
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
98
- def test_catch_do(itype: IterableType, adapt: Callable[[Any], Any]) -> None:
99
- ints = [1, 0, 2, 3]
100
- errors: List[Exception] = []
101
- s = stream(ints).do(inverse).catch(ZeroDivisionError, do=adapt(errors.append))
102
- assert alist_or_list(s, itype) == [1, 2, 3]
103
- assert len(errors) == 1
104
- assert isinstance(errors[0], ZeroDivisionError)
105
-
106
-
107
- @pytest.mark.parametrize("adapt", [identity, asyncify])
108
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
109
- def test_catch_with_do_raising(
110
- itype: IterableType, adapt: Callable[[Any], Any]
111
- ) -> None:
112
- """If `do` raises an exception, it is re-raised in place of the caught one."""
113
- ints = [0, 1, 0, 1, 0]
114
- errors: List[Exception] = []
115
- s = (
116
- stream(ints)
117
- .map(lambda n: round(1 / n, 2))
118
- .catch(ZeroDivisionError, do=throw_func(TestError))
119
- .catch(TestError, do=adapt(errors.append))
120
- )
121
- assert alist_or_list(s, itype) == [1, 1]
122
- assert len(errors) == ints.count(0)
123
-
124
-
125
- @pytest.mark.parametrize("adapt", [identity, asyncify])
126
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
127
- def test_catch_with_replace_raising(
128
- itype: IterableType, adapt: Callable[[Any], Any]
129
- ) -> None:
130
- ints = [0, 1, 0, 1, 0]
131
- s = (
132
- stream(ints)
133
- .map(lambda n: round(1 / n, 2))
134
- .catch(ZeroDivisionError, replace=throw_func(TestError))
135
- .catch(TestError, replace=adapt(lambda e: None))
136
- )
137
- assert alist_or_list(s, itype) == [None, 1, None, 1, None]
138
-
139
-
140
- @pytest.mark.parametrize("where", [identity, async_identity])
141
- @pytest.mark.parametrize("adapt_do", [identity, asyncify])
142
- @pytest.mark.parametrize("adapt_replace", [identity, asyncify])
143
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
144
- def test_catch_sync_async_params_combination(
145
- where: Callable[[Exception], Any],
146
- adapt_do: Callable[[Callable[[Any], Any]], Callable[[Any], Any]],
147
- adapt_replace: Callable[[Callable[[Any], Any]], Callable[[Any], Any]],
148
- itype: IterableType,
149
- ) -> None:
150
- """Catch supports passing a mix of regular and async functions for where, do and replace."""
151
- errors: List[Exception] = []
152
- s = (
153
- stream([0, 1, 0, 1, 0])
154
- .do(inverse)
155
- .catch(
156
- ZeroDivisionError,
157
- where=where,
158
- do=adapt_do(errors.append),
159
- replace=adapt_replace(lambda e: None),
160
- )
161
- )
162
- assert alist_or_list(s, itype) == [None, 1, None, 1, None]
163
- assert len(errors) == 3
164
-
165
-
166
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
167
- def test_catch_stop(itype: IterableType) -> None:
168
- s = stream("01-3").map(int).catch(ValueError, stop=True)
169
- assert alist_or_list(s, itype) == [0, 1]
170
-
171
-
172
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
173
- def test_catch_stop_with_falsy_where(itype: IterableType) -> None:
174
- """If `stop=True` but the exception does not satisfy `where`, the iteration should not stop."""
175
- s = (
176
- stream("01-3")
177
- .map(int)
178
- .catch(ValueError, where=lambda e: False, stop=True)
179
- .catch(ValueError)
180
- )
181
- assert alist_or_list(s, itype) == [0, 1, 3]
182
-
183
-
184
- @pytest.mark.parametrize("adapt", [identity, asyncify])
185
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
186
- def test_catch_stop_with_where_raising(
187
- itype: IterableType, adapt: Callable[[Any], Any]
188
- ) -> None:
189
- """`stop=True` does not terminate the iteration if `where` raises."""
190
- ints = [0, 1, 0, 1, 0]
191
- s = (
192
- stream(ints)
193
- .map(lambda n: round(1 / n, 2))
194
- .catch(ZeroDivisionError, where=throw_func(TestError), stop=True)
195
- .catch(TestError)
196
- )
197
- assert alist_or_list(s, itype) == [1, 1]
198
-
199
-
200
- @pytest.mark.parametrize("adapt", [identity, asyncify])
201
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
202
- def test_catch_stop_with_do_raising(
203
- itype: IterableType, adapt: Callable[[Any], Any]
204
- ) -> None:
205
- """`stop=True` terminates the iteration even if `do` raises."""
206
- ints = [1, 0, 1, 0]
207
- s = (
208
- stream(ints)
209
- .map(lambda n: round(1 / n, 2))
210
- .catch(ZeroDivisionError, do=throw_func(TestError), stop=True)
211
- .catch(TestError)
212
- )
213
- assert alist_or_list(s, itype) == [1]
214
-
215
-
216
- @pytest.mark.parametrize("adapt", [identity, asyncify])
217
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
218
- def test_catch_stop_with_replace_raising(
219
- itype: IterableType, adapt: Callable[[Any], Any]
220
- ) -> None:
221
- """`stop=True` terminates the iteration even if `replace` raises."""
222
- ints = [1, 0, 1, 0]
223
- s = (
224
- stream(ints)
225
- .map(lambda n: round(1 / n, 2))
226
- .catch(ZeroDivisionError, replace=throw_func(TestError), stop=True)
227
- .catch(TestError)
228
- )
229
- assert alist_or_list(s, itype) == [1]
230
-
231
-
232
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
233
- def test_catch_stop_with_replacement(itype: IterableType) -> None:
234
- """Test `stop` on exception, with replacement as last elem."""
235
- s = stream("01-3").map(int).catch(ValueError, stop=True, replace=lambda e: None)
236
- assert alist_or_list(s, itype) == [0, 1, None]
237
-
238
-
239
- @pytest.mark.parametrize("adapt", [identity, asyncify])
240
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
241
- def test_catch_replace_occurs_after_do(
242
- itype: IterableType, adapt: Callable[[Any], Any]
243
- ) -> None:
244
- errors: List[Exception] = []
245
- s = (
246
- stream("-")
247
- .map(int)
248
- .catch(
249
- ValueError, do=adapt(errors.append), replace=adapt(lambda e: len(errors))
250
- )
251
- )
252
- assert alist_or_list(s, itype) == [len(errors)] == [1]
253
-
254
-
255
- @pytest.mark.parametrize("adapt", [identity, asyncify])
256
- @pytest.mark.parametrize("itype", ITERABLE_TYPES)
257
- def test_catch_do_occurs_after_where(
258
- itype: IterableType, adapt: Callable[[Any], Any]
259
- ) -> None:
260
- errors: List[Exception] = []
261
- s = (
262
- stream("-")
263
- .map(int)
264
- .catch(ValueError, where=adapt(lambda e: False), do=adapt(errors.append))
265
- )
266
- with pytest.raises(ValueError):
267
- anext_or_next(aiter_or_iter(s, itype), itype)
268
-
269
- assert errors == []