Coverage for tests / __main__.py: 95%
463 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-17 08:56 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-17 08:56 +0000
1# Licensed under the EUPL-1.2 or later.
2# You may obtain a copy of the licence in all the official languages of the
3# European Union at https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
4# pylint: disable=too-many-lines
6"""The tests for the Stream."""
8from __future__ import annotations
10import doctest
11import importlib
12import operator
13import sys
14import traceback
15import types
16from collections import Counter
17from collections.abc import Callable
18from functools import partial
19from numbers import Number, Real
20from operator import add
21from pathlib import Path
22from types import EllipsisType
23from typing import Any
25from typed_stream import (
26 BinaryFileStream,
27 FileStream,
28 Stream,
29 StreamableSequence,
30 StreamEmptyError,
31 StreamFinishedError,
32 StreamIndexError,
33 _impl,
34)
35from typed_stream._impl._iteration_utils import (
36 IterWithCleanUp,
37 Peeker,
38 sliding_window,
39)
40from typed_stream._impl._lazy_file_iterators import (
41 LazyFileIteratorRemovingEndsBytes,
42)
43from typed_stream._impl._typing import assert_type
44from typed_stream._impl._utils import IndexValueTuple
45from typed_stream._impl.functions import method_partial
46from typed_stream.functions import is_even, is_odd
48from .test_functions import (
49 is_bool,
50 is_complex,
51 is_float,
52 is_int,
53 is_none,
54 is_not_none,
55 is_number,
56 is_real_number,
57 is_str,
58 noop,
59)
61for export in Stream(_impl.__all__).map(partial(getattr, _impl)): # noqa: F405
62 # pylint: disable-next=protected-access
63 assert export._module() == "typed_stream", f"{export!r}" # nosec: B101
64 del export
67def testmod(
68 mod: types.ModuleType,
69 optionflags: int = doctest.DONT_ACCEPT_TRUE_FOR_1,
70) -> tuple[int, int]:
71 """Test modules.
73 Like doctest.testmod, but smaller.
74 """
75 runner = doctest.DocTestRunner(optionflags=optionflags)
77 for test in doctest.DocTestFinder().find(mod, mod.__name__, mod):
78 runner.run(test)
80 return runner.failures, runner.tries
83def run_doc_tests() -> None: # noqa: C901
84 """Run the doctests in the typed_stream package."""
85 dir_ = Path(__file__).resolve().parent.parent / "typed_stream"
86 acc_fails, acc_tests = 0, 0
87 for mod in sorted(
88 Stream(dir_.rglob("*.py"))
89 .map(lambda p: p.relative_to(dir_).as_posix())
90 .map(str.removesuffix, "/__init__.py")
91 .map(str.removesuffix, ".py")
92 .map(str.replace, "/", "."),
93 key=lambda s: (s.count("."), len(s)),
94 reverse=True,
95 ):
96 full_mod = f"typed_stream.{mod}" if mod else "typed_stream"
97 fails, tests = testmod(importlib.import_module(full_mod))
98 acc_fails += fails
99 acc_tests += tests
100 if tests:
101 print(
102 f"{full_mod}: {tests - fails} / {tests} doctests successful",
103 file=sys.stderr,
104 )
106 print(
107 f"SUMMARY: {acc_tests - acc_fails} / {acc_tests} doctests successful",
108 file=sys.stderr,
109 )
110 if acc_fails == 1 and sys.implementation.name == "rustpython":
111 print("ignoring 1 failure", file=sys.stderr)
112 elif acc_fails:
113 sys.exit(1)
116run_doc_tests()
119def typed_nwise_stuff() -> None:
120 """Test whether the Stream.nwise overloads work."""
121 one: Stream[tuple[str]] = Stream("abc").nwise(1)
122 assert one.map("".join).collect("".join) == "abc"
124 two: Stream[tuple[str, str]] = Stream("abc").nwise(2)
125 assert two.map("".join).collect("".join) == "abbc"
127 three: Stream[tuple[str, ...]] = Stream("abcd").nwise(3)
128 assert three.map("".join).collect("".join) == "abcbcd"
131typed_nwise_stuff()
134# pylint: disable=unnecessary-lambda, protected-access
137def assert_raises(exc: type[BaseException], fun: Callable[[], object]) -> None:
138 """Assert that fun raises exc."""
139 try:
140 val = fun()
141 except exc:
142 return
143 except BaseException: # pragma: no cover
144 print(f"{fun} did not raise {exc}", file=sys.stderr)
145 raise
146 raise AssertionError(
147 f"{fun} did not raise {exc} and instead returned {val}"
148 )
151assert_raises(AssertionError, lambda: assert_raises(Exception, lambda: None))
152assert_raises(TypeError, lambda: hash(Stream(...)))
153assert_raises(TypeError, lambda: hash(Stream([0, 1])))
155assert_raises(ValueError, lambda: sliding_window([], -1))
156assert_raises(ValueError, lambda: sliding_window((), 0))
157assert_raises(ValueError, lambda: Stream([]).nwise(0))
158assert_raises(ValueError, lambda: Stream(()).nwise(-1))
160assert_raises(ValueError, Stream("1a2b3c4d5").map(int).sum)
161assert_raises(ValueError, Stream("1a2b3c4d5").map(int).catch(TypeError).sum)
162assert_raises(ValueError, lambda: Stream(()).catch(StopIteration))
163assert_raises(ValueError, lambda: Stream(()).catch(StopIteration, TypeError))
164assert_raises(ValueError, lambda: Stream(()).catch(ValueError, StopIteration))
165assert (
166 assert_type(
167 Stream("1a2b3c4d5e6f7g8h9").map(int).catch(ValueError).sum(), int
168 )
169 == 45
170)
171assert (
172 assert_type(
173 Stream("1a2b3c4d5e6f7g8h9").map(int).catch(Exception).sum(), int
174 )
175 == 45
176)
178assert assert_type(Stream("abbccc122333").collect(Counter), Counter[str]) == {
179 "a": 1,
180 "b": 2,
181 "c": 3,
182 "1": 1,
183 "2": 2,
184 "3": 3,
185}
187assert Stream.range(10).conditional_map(
188 is_even, lambda x: x, lambda x: -x
189).collect() == (0, -1, 2, -3, 4, -5, 6, -7, 8, -9)
190assert assert_type(
191 Stream.range(10)
192 .conditional_map(is_even, lambda x: x * 2, lambda x: -x)
193 .collect(),
194 StreamableSequence[int],
195) == (0, -1, 4, -3, 8, -5, 12, -7, 16, -9)
196assert assert_type(
197 Stream.range(10).conditional_map(is_odd, lambda x: -x, lambda x: x * 2),
198 Stream[int],
199).collect() == (0, -1, 4, -3, 8, -5, 12, -7, 16, -9)
200assert (
201 assert_type(
202 Stream.range(10)
203 .conditional_map(is_even, lambda _: ..., lambda x: None)
204 .collect(),
205 StreamableSequence[None | EllipsisType],
206 )
207 == (..., None) * 5
208)
209assert assert_type(
210 Stream.range(10).conditional_map(is_odd, lambda x: -x), Stream[int]
211).collect() == (
212 -1,
213 -3,
214 -5,
215 -7,
216 -9,
217)
218assert (
219 assert_type(
220 Stream.range(10).conditional_map(is_even, lambda _: ...).collect(),
221 StreamableSequence[EllipsisType],
222 )
223 == (...,) * 5
224)
227def raise_exceptions(number: int) -> int:
228 """Raise different exceptions."""
229 if number == 1:
230 raise ValueError("1")
231 if number == 3:
232 raise TypeError("3")
233 if number == 5:
234 raise ZeroDivisionError("5")
235 return number
238assert assert_type(
239 Stream.range(6)
240 .map(raise_exceptions)
241 .catch(ValueError, TypeError, ZeroDivisionError, default=lambda: -1)
242 .collect(),
243 StreamableSequence[int],
244) == (0, -1, 2, -1, 4, -1)
246assert assert_type(
247 Stream.range(6)
248 .map(raise_exceptions)
249 .catch(ValueError, TypeError, ZeroDivisionError)
250 .collect(),
251 StreamableSequence[int],
252) == (0, 2, 4)
254assert assert_type(
255 Stream.range(6)
256 .map(raise_exceptions)
257 .map(str)
258 .catch(
259 ValueError,
260 TypeError,
261 ZeroDivisionError,
262 default=lambda _: f"E{_.args[0]}",
263 )
264 .collect(),
265 StreamableSequence[str],
266) == ("0", "E1", "2", "E3", "4", "E5")
268assert (
269 assert_type(
270 Stream.range(20)
271 .map(raise_exceptions)
272 .catch(ValueError, TypeError, ZeroDivisionError)
273 .sum(),
274 int,
275 )
276 == sum(range(20)) - 1 - 3 - 5
277)
278assert (
279 assert_type(
280 Stream.range(20)
281 .map(raise_exceptions)
282 .catch(ValueError, TypeError, ZeroDivisionError, default=lambda: 0)
283 .sum(),
284 int,
285 )
286 == sum(range(20)) - 1 - 3 - 5
287)
288assert (
289 assert_type(
290 Stream.range(20)
291 .map(raise_exceptions)
292 .catch(ValueError, TypeError, ZeroDivisionError, default=lambda _: 0)
293 .sum(),
294 int,
295 )
296 == sum(range(20)) - 1 - 3 - 5
297)
300errors: list[ValueError] = []
301assert (
302 assert_type(
303 Stream("1a2b3c4d5e6f7g8h9")
304 .map(int)
305 .catch(ValueError, handler=errors.append, default=lambda: 100)
306 .sum(),
307 int,
308 )
309 == 845
310)
311assert (
312 assert_type(Stream(errors).map(type).collect(list), list[type])
313 == [ValueError] * 8
314)
315errors = []
316assert (
317 assert_type(
318 Stream("1x2x3x4x5x6x7x8x9")
319 .map(int)
320 .catch(
321 ValueError,
322 handler=errors.append,
323 default=lambda _: len(_.args) * 1000,
324 )
325 .sum(),
326 int,
327 )
328 == 8045
329)
330value_error: ValueError
331try:
332 int("x")
333except ValueError as _:
334 value_error = _
335else:
336 raise AssertionError("x is int")
337assert Stream(errors).map(type).collect(list) == [ValueError] * 8
338assert (
339 Stream(errors).flat_map(lambda _: _.args).distinct().collect()
340 == value_error.args
341)
343optional_float_list: list[float | None] = list(
344 Stream.range(3)
345 .map((5).__truediv__)
346 .catch(ZeroDivisionError, default=lambda: None)
347)
348assert optional_float_list == [None, 5.0, 2.5]
350assert (
351 Stream.range(69).collect()
352 == Stream.range(69).nwise(1).sum()
353 == Stream.range(69).map(lambda x: (x,)).sum()
354 == Stream.range(69).nwise(1).flat_map(lambda x: x).collect(tuple)
355 == Stream.range(69).map(lambda x: (x,)).flat_map(lambda x: x).collect(tuple)
356)
357assert (
358 Stream.range(69).collect(list)
359 == Stream.range(69).map(lambda x: [x]).sum()
360 == Stream.range(69).map(lambda x: [x]).flat_map(lambda x: x).collect(list)
361)
362assert Stream.range(10).enumerate(-10).sum() == Stream.range(10).enumerate(
363 -10
364).flat_map(lambda x: x).collect(tuple)
366assert " ".join(Stream("ABCDEFG").nwise(1).map("".join)) == "A B C D E F G"
367assert Stream("ABCDEFG").nwise(1).collect() == (
368 ("A",),
369 ("B",),
370 ("C",),
371 ("D",),
372 ("E",),
373 ("F",),
374 ("G",),
375)
377assert " ".join(Stream("ABCDEFG").nwise(2).map("".join)) == "AB BC CD DE EF FG"
378assert Stream("ABCDEFG").nwise(2).collect() == (
379 ("A", "B"),
380 ("B", "C"),
381 ("C", "D"),
382 ("D", "E"),
383 ("E", "F"),
384 ("F", "G"),
385)
386assert (
387 " ".join(Stream("ABCDEFG").nwise(3).map("".join)) == "ABC BCD CDE DEF EFG"
388)
389assert Stream("ABCDEFG").nwise(3).collect() == (
390 ("A", "B", "C"),
391 ("B", "C", "D"),
392 ("C", "D", "E"),
393 ("D", "E", "F"),
394 ("E", "F", "G"),
395)
396assert (
397 " ".join(Stream("ABCDEFG").nwise(4).map("".join)) == "ABCD BCDE CDEF DEFG"
398)
399assert Stream("ABCDEFG").nwise(4).collect() == (
400 ("A", "B", "C", "D"),
401 ("B", "C", "D", "E"),
402 ("C", "D", "E", "F"),
403 ("D", "E", "F", "G"),
404)
405assert " ".join(Stream("ABCDEFG").nwise(5).map("".join)) == "ABCDE BCDEF CDEFG"
406assert Stream("ABCDEFG").nwise(5).collect() == (
407 ("A", "B", "C", "D", "E"),
408 ("B", "C", "D", "E", "F"),
409 ("C", "D", "E", "F", "G"),
410)
411assert " ".join(Stream("ABCDEFG").nwise(6).map("".join)) == "ABCDEF BCDEFG"
412assert Stream("ABCDEFG").nwise(6).collect() == (
413 ("A", "B", "C", "D", "E", "F"),
414 ("B", "C", "D", "E", "F", "G"),
415)
416assert " ".join(Stream("ABCDEFG").nwise(7).map("".join)) == "ABCDEFG"
417assert Stream("ABCDEFG").nwise(7).collect() == (
418 ("A", "B", "C", "D", "E", "F", "G"),
419)
420assert Stream("").nwise(1).collect() == ()
421assert Stream("A").nwise(2).collect() == ()
422assert Stream("AB").nwise(3).collect() == ()
423assert Stream("ABC").nwise(4).collect() == ()
424assert Stream("ABCDEFG").nwise(8).collect() == ()
426assert 0 in Stream.counting()
427assert 1 in Stream([1])
428assert 2 not in Stream.range(1, 100, 2)
429assert 3 not in Stream.range(3)
431assert "0" in Stream.counting().map(str)
432assert "1" in Stream([1]).map(str)
433assert "2" not in Stream.range(1, 100, 2).map(str)
434assert "3" not in Stream.range(3).map(str)
436assert assert_type("".join(reversed(Stream("abc"))), str) == "cba"
437assert tuple(reversed(Stream([1, 2, 3, 4]))) == (4, 3, 2, 1)
439assert assert_type(Stream([1, 2, 3]).collect(tuple), tuple[int, ...]) == (
440 1,
441 2,
442 3,
443)
444assert assert_type(Stream([1, 2, 3]).collect(set), set[int]) == {1, 2, 3}
445mapping: dict[int, str] = (
446 Stream([1, 2, 3]).map(lambda x: (x, str(x))).collect(dict)
447)
448assert mapping == {1: "1", 2: "2", 3: "3"}
450assert assert_type(Stream([1, 2, 3]).sum(), int) == 6
451assert assert_type(Stream([1, 2, 3]).max(), int) == 3
452assert assert_type(Stream([1, 2, 3]).min(), int) == 1
453assert assert_type(Stream([1, 2, 3]).min(default=0), int) == 1
455assert assert_type(Stream(["1", "2", "3"]).max(), str) == "3"
456assert assert_type(Stream(["1", "2", "3"]).min(), str) == "1"
457assert assert_type(Stream(["1", "2", "3"]).min(default="a"), str) == "1"
459_stream1 = Stream.from_value(69).enumerate().nwise(3).catch()
460assert isinstance(
461 _stream2 := eval( # pylint: disable=eval-used
462 repr(_stream1),
463 {
464 "typed_stream": __import__("typed_stream"),
465 "repeat": __import__("itertools").repeat,
466 },
467 ),
468 Stream,
469)
470assert _stream1.limit(1000).collect() == _stream2.limit(1000).collect()
471assert (
472 repr(iter(Stream.from_value(69)))
473 == "typed_stream._impl._iteration_utils.IterWithCleanUp"
474 + "(<bound method StreamABC.close of typed_stream.Stream"
475 + "(repeat(69))>,repeat(69))"
476)
477assert (
478 repr(Peeker(print))
479 == "typed_stream._impl._iteration_utils.Peeker(<built-in function print>)"
480)
482assert str(Stream(...)) == "typed_stream.Stream(...)"
483assert repr(Stream(...)) == "typed_stream.Stream(...)"
484assert repr(FileStream(...)) == "typed_stream.FileStream(...)"
486assert_raises(StreamFinishedError, lambda: Stream(...)._data)
487assert_raises(StreamFinishedError, lambda: BinaryFileStream(...)._data)
488assert_raises(StreamFinishedError, lambda: FileStream(...)._data)
490assert assert_type(
491 Stream.range(5).map(str).enumerate(), Stream[IndexValueTuple[str]]
492).collect(tuple) == (
493 (0, "0"),
494 (1, "1"),
495 (2, "2"),
496 (3, "3"),
497 (4, "4"),
498)
501assert assert_type(
502 Stream.range(5).map(str).enumerate().map(lambda x: x.idx).collect(list),
503 list[int],
504) == list(range(5))
505enumeration_stream = assert_type(
506 Stream.range(5).map(str).enumerate(), Stream[IndexValueTuple[str]]
507)
508assert assert_type(
509 enumeration_stream.map(lambda x: x.val).collect(list), list[str]
510) == list(map(str, range(5)))
511assert assert_type(
512 Stream.range(5).map(str).enumerate().map(lambda x: x.val).collect(list),
513 list[str],
514) == list(map(str, range(5)))
515assert assert_type(
516 Stream.range(5).map(str).enumerate().collect(dict), dict[int, str]
517) == {0: "0", 1: "1", 2: "2", 3: "3", 4: "4"}
519assert assert_type(
520 list(Stream.range(999).enumerate().starmap(int.__eq__).distinct()),
521 list[bool],
522) == [True]
523assert assert_type(
524 list(Stream.range(999).enumerate().starmap(operator.eq).distinct()),
525 list[Any],
526) == [True]
527assert (
528 assert_type(Stream.range(10).nwise(1).starmap(str).sum(), str)
529 == "0123456789"
530)
531assert (
532 assert_type(Stream.range(6).nwise(2).starmap(int.__mul__).sum(), int) == 40
533)
534assert (
535 assert_type(Stream.range(6).nwise(2).starmap(operator.mul).sum(), Any) == 40
536)
538STRING = "pjwa nsvoidnvifbp s,cpvmodo nngfibogfmjv in"
539assert (
540 assert_type(Stream(STRING).distinct().collect("".join), str)
541 == "pjwa nsvoidfb,cmg"
542)
543assert (
544 assert_type(Stream(STRING).distinct(use_set=False).sum(), str)
545 == "pjwa nsvoidfb,cmg"
546)
549def create_int_stream() -> Stream[int]:
550 """Create an int stream."""
551 return Stream.range(10_000).map(operator.pow, 2)
554assert (
555 333283335000
556 == assert_type(sum(create_int_stream()), int)
557 == assert_type(create_int_stream().reduce(lambda x, y: x + y), int)
558 == assert_type(create_int_stream().reduce(int.__add__), int)
559 == assert_type(create_int_stream().reduce(add, 0), int)
560 == assert_type(create_int_stream().reduce(add), int)
561 == assert_type(create_int_stream().sum(), int)
562 == assert_type(create_int_stream().collect(lambda x: sum(x)), int)
563 == assert_type(create_int_stream().collect(sum), int)
564)
566assert assert_type(Stream([1, 2, 3, -1]).max(), int) == 3
567assert assert_type(
568 Stream([{0, 1}, {2}, {3, 4, 5}, {6}]).max(key=len), set[int]
569) == {3, 4, 5}
570assert assert_type(Stream([1, 2, -1, 3]).min(), int) == -1
571assert assert_type(
572 Stream([{0, 1}, {2}, {3, 4, 5}, {6}]).min(key=len), set[int]
573) == {2}
575assert assert_type(Stream([1, 2, 3]).max(default=None), None | int) == 3
576assert not assert_type(Stream([1]).limit(0).max(default=None), None | int)
577assert assert_type(Stream([1, 2, 3]).first(default=None), None | int) == 1
578assert not assert_type(Stream([1]).limit(0).first(default=None), None | int)
579assert assert_type(Stream([1, 2, 3]).min(default=None), None | int) == 1
580assert not assert_type(Stream([1]).limit(0).min(default=None), None | int)
582assert assert_type(Stream([1, 2, 3]).max(default="None"), str | int) == 3
583assert (
584 assert_type(Stream([1]).limit(0).max(default="None"), str | int) == "None"
585)
586assert assert_type(Stream([1, 2, 3]).first(default="None"), str | int) == 1
587assert (
588 assert_type(Stream([1]).limit(0).first(default="None"), str | int) == "None"
589)
590assert assert_type(Stream([1, 2, 3]).min(default="None"), str | int) == 1
591assert (
592 assert_type(Stream([1]).limit(0).min(default="None"), str | int) == "None"
593)
595assert Stream((1,)).drop(100).reduce(add, 1) == 1
596assert Stream("").reduce(add, "x") == "x"
597assert_raises(StreamEmptyError, Stream("").sum)
599assert tuple(Stream([1, 2, 2, 2, 3]).distinct()) == (1, 2, 3)
600assert tuple(Stream([1, 2, 1, 1, 2, 1, 2, 3, 3, 3, 2, 2, 1]).distinct()) == (
601 1,
602 2,
603 3,
604)
606assert Stream([1, 4, 7]).flat_map(lambda x: [x, x + 1, x + 2]).collect(
607 list
608) == [1, 2, 3, 4, 5, 6, 7, 8, 9]
609assert Stream([1, 2, 3, 4, 5]).limit(3).collect(list) == [1, 2, 3]
610assert not Stream([]).limit(3).collect(list)
611assert Stream([1]).limit(3).collect(list) == [1]
612assert Stream([1, 2, 3, 4, 5]).count() == 5
613assert Stream([1, 4, 5]).last() == 5
614assert Stream([1, 4, 5]).first() == 1
615assert Stream([True, True, True]).all()
616assert Stream([]).empty()
617assert not Stream([1]).empty()
619assert Stream([1, 2, 3]).chain([4, 5, 6]).collect(tuple) == (1, 2, 3, 4, 5, 6)
620assert Stream.range(25).chunk(5).map(lambda x: list(x)).collect(tuple) == (
621 [0, 1, 2, 3, 4],
622 [5, 6, 7, 8, 9],
623 [10, 11, 12, 13, 14],
624 [15, 16, 17, 18, 19],
625 [20, 21, 22, 23, 24],
626)
627assert_raises(ValueError, lambda: Stream(()).chunk(0))
629int_list: list[int] = Stream([None, 1, 2, 3, 4, 0, 23]).filter().collect(list)
630assert int_list == [1, 2, 3, 4, 23]
631int_list = Stream([None, 1, 2, 3, None]).filter(is_not_none).collect(list)
632assert int_list == [1, 2, 3]
633int_list = Stream([None, 1, 2, 3, None]).exclude(is_none).collect(list)
634assert int_list == [1, 2, 3]
635int_list = []
636Stream([None, 1, 2, 3, None]).exclude(is_none).for_each(int_list.append)
637assert int_list == [1, 2, 3]
639assert len(Stream.from_value("x").limit(1000).tail(10)) == 10
641assert not Stream("").count()
642assert Stream.range(10_000).chunk(100).count() == 100
643assert list(Stream.range(10_000).chunk(100).map(len).distinct()) == [100]
645assert Stream.counting().take_while((100).__gt__).count() == 100
646assert list(Stream.counting().take_while((5).__gt__)) == [0, 1, 2, 3, 4]
647assert list(Stream.range(10).drop_while((5).__gt__)) == [5, 6, 7, 8, 9]
648assert Stream.range(10).tail(5) == (5, 6, 7, 8, 9)
651str_stream: Stream[str] = Stream([None, "1", "2", "3", 4, 0, 23]).filter(is_str)
652assert str_stream.collect(list) == ["1", "2", "3"]
654assert (
655 repr(FileStream("file.txt", "Utf-8", False))
656 == "typed_stream.FileStream('file.txt','Utf-8',False)"
657)
658assert (
659 repr(FileStream("file.txt", "Utf-8", True))
660 == "typed_stream.FileStream('file.txt','Utf-8',True)"
661)
663INPUT_TXT = Path(__file__).parent / "input.txt"
665assert (
666 FileStream(INPUT_TXT)
667 .filter(lambda string: string and not string.startswith("#"))
668 .map(int)
669 .sum()
670 == 7
671)
672assert (
673 FileStream(INPUT_TXT)
674 .filter()
675 .exclude(method_partial(str.startswith, "#"))
676 .map(int)
677 .sum()
678 == 7
679)
680assert FileStream(INPUT_TXT).map(int).catch(ValueError).sum() == 7
682assert FileStream(INPUT_TXT, keep_line_ends=True).map(
683 lambda x: x[-1]
684).distinct().collect(tuple) == ("\n",)
686fs = FileStream(INPUT_TXT)
687assert fs.chain(" ").last() == " "
688assert fs._file_iterator is None
689fs.close() # closing twice shouldn't fail
690assert fs._file_iterator is None
692fs = FileStream(INPUT_TXT, keep_line_ends=True)
693for line in fs:
694 assert line.endswith("\n")
696assert fs._file_iterator is None
697fs = FileStream(INPUT_TXT)
698for line in fs:
699 assert not line.endswith("\n")
701assert fs._file_iterator is None
703fs = FileStream(INPUT_TXT)
704assert fs.map(lambda _: ...).limit(1).collect(list) == [...]
705assert fs._file_iterator is None
707fs = FileStream(INPUT_TXT)
708assert (
709 fs.limit(10).map(repr).map(len).peek(lambda _: ...).map((1).__add__).count()
710 == 10
711)
712assert fs._file_iterator is None
714with FileStream(INPUT_TXT) as fs:
715 assert isinstance(next(iter(fs)), str)
716assert fs._file_iterator is None
718fs = FileStream(INPUT_TXT)
719assert fs.take_while(len).count() == 4
720assert fs._file_iterator is None
723assert BinaryFileStream(INPUT_TXT, keep_line_ends=True).map(
724 lambda x: x[-1]
725).distinct().collect(tuple) == (b"\n"[0],)
727bfs: BinaryFileStream = BinaryFileStream(INPUT_TXT)
728assert bfs.chain([b" "]).last() == b" "
729assert bfs._file_iterator is None
731bfs = BinaryFileStream(INPUT_TXT)
732assert list(bfs.map(lambda _: ...).limit(1)) == [...]
733assert bfs._file_iterator is None
735bfs = BinaryFileStream(INPUT_TXT)
736assert (
737 bfs.limit(10)
738 .map(repr)
739 .map(len)
740 .peek(lambda _: ...)
741 .map((1).__add__)
742 .count()
743 == 10
744)
745assert bfs._file_iterator is None
747bfs = BinaryFileStream(INPUT_TXT)
748assert bfs.take_while(len).count() == 4
749assert bfs._file_iterator is None
751bfs = BinaryFileStream(INPUT_TXT)
752first = bfs.first()
753assert bfs._file_iterator is None
755with BinaryFileStream(INPUT_TXT) as bfs:
756 assert first == next(iter(bfs))
757assert bfs._file_iterator is None
759with LazyFileIteratorRemovingEndsBytes(INPUT_TXT) as lfireb:
760 assert first == next(lfireb)
761assert not lfireb._file_object
762lfireb.close()
763assert not lfireb._file_object
764lfireb = LazyFileIteratorRemovingEndsBytes(INPUT_TXT)
765assert next(lfireb) == first
766assert lfireb._file_object
767lfireb.close()
768assert lfireb._file_object is None
770bfs = BinaryFileStream(INPUT_TXT) # type: ignore[unreachable]
771fs = FileStream(INPUT_TXT)
772assert tuple(bfs) == tuple(fs.map(str.encode, "UTF-8").collect(tuple))
773assert bfs._file_iterator is None
774assert fs._file_iterator is None
776int_list_begin: list[int] = []
777int_list_end: list[int] = []
778int_stream: Stream[int] = (
779 Stream.range(10_000)
780 .peek(int_list_begin.append)
781 .limit(1000)
782 .drop_while(lambda x: x < 500)
783 .exclude(lambda x: x % 2)
784 .flat_map(range)
785 .filter(lambda x: x % 2)
786 .map(operator.pow, 2)
787 .peek(int_list_end.append)
788)
789assert not int_list_begin # the above code did nothing
790assert not int_list_end
791assert list(int_stream) == int_list_end
792assert int_list_end # list(int_stream) consumed the stream
793assert len(int_list_begin) == 1000
795assert repr(int_stream) == "typed_stream.Stream(...)"
797assert Stream(["abc", "def", "ghijk"]).flat_map(str.encode, "ASCII").map(
798 operator.sub, 97
799).collect(tuple) == (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
801stream = (
802 Stream.range(10000000000000000000000000000000000000000000000000000000000000)
803 .peek(noop)
804 .map(str)
805 .flat_map(str.encode, "ASCII")
806 .map(operator.sub, ord("0"))
807 .limit(100)
808 .map(operator.mul, 10)
809 .drop_while((10).__gt__)
810 .take_while((90).__gt__)
811 .filter(operator.truth)
812 .exclude(operator.not_)
813)
815for i in range(100):
816 assert Stream.range(10_000)[i] == i
817 assert Stream.range(10_000).nth(i) == i
818 if not i:
819 continue
820 assert Stream.range(10_000)[-i] == 10_000 - i
821 assert Stream.range(10_000).nth(-i) == 10_000 - i
824for name in dir(Stream(...)): # noqa: C901 # pylint: disable=too-complex
825 if name in {
826 "__class__",
827 "__class_getitem__",
828 "__del__",
829 "__delattr__",
830 "__dir__",
831 "__enter__",
832 "__eq__",
833 "__exit__",
834 "__format__",
835 "__ge__",
836 "__getattribute__",
837 "__getstate__",
838 "__gt__",
839 "__init__",
840 "__init_subclass__",
841 "__le__",
842 "__lt__",
843 "__ne__",
844 "__new__",
845 "__reduce__",
846 "__reduce_ex__",
847 "__repr__",
848 "__setattr__",
849 "__sizeof__",
850 "__str__",
851 "__subclasshook__",
852 "_close_source",
853 "_data",
854 "_finish",
855 "_full_class_name",
856 "_get_args",
857 "_module",
858 "_StreamABC__data",
859 "close",
860 "collect_and_await_all",
861 "collect_async_to_awaited_tasks",
862 "counting",
863 "from_value",
864 "range",
865 }:
866 continue
867 if (
868 sys.implementation.name == "rustpython"
869 and getattr(Stream(...), name, None) is None
870 ):
871 print(f"ignoring Stream.{name}")
872 continue
873 if isinstance(method := getattr(Stream(...), name), Callable):
874 args: tuple[Any, ...]
875 if name == "chain":
876 args = ([],)
877 elif name in {
878 "chunk",
879 "drop",
880 "limit",
881 "nth",
882 "nwise",
883 "tail",
884 "__contains__",
885 "__getitem__",
886 }:
887 args = (2,)
888 elif name in {
889 "concurrent_map",
890 "drop_while",
891 "exclude",
892 "flat_map",
893 "map",
894 "peek",
895 "reduce",
896 "starcollect",
897 "starmap",
898 "take_while",
899 }:
900 args = (lambda: ...,)
901 elif name == "catch":
902 args = (Exception,)
903 elif name == "conditional_map":
904 args = (lambda _: ..., lambda _: ..., lambda _: ...)
905 else:
906 args = ()
907 try:
908 assert_raises(StreamFinishedError, partial(method, *args))
909 except NotImplementedError:
910 if sys.implementation.name == "rustpython":
911 traceback.print_exc()
912 else:
913 raise
916assert_raises(StreamIndexError, lambda: Stream.range(10)[10])
917assert_raises(StreamIndexError, lambda: Stream.range(10)[-11])
918assert_raises(StreamIndexError, lambda: Stream(())[-1])
919assert_raises(StreamIndexError, lambda: Stream(())[0])
920assert_raises(StreamIndexError, lambda: Stream(())[1])
921assert_raises(StreamIndexError, lambda: Stream(()).nth(-1))
922assert_raises(StreamIndexError, lambda: Stream(()).nth(0))
923assert_raises(StreamIndexError, lambda: Stream(()).nth(1))
925assert_raises(StreamEmptyError, lambda: Stream(()).first())
926assert_raises(StreamEmptyError, lambda: Stream([]).first())
927assert_raises(StreamEmptyError, lambda: Stream(()).last())
928assert_raises(StreamEmptyError, lambda: Stream([]).last())
931assert Stream.range(100).nth(1_000, default=None) is None
932assert Stream.range(100).nth(-1_000, default=None) is None
933assert Stream(()).nth(1, default=None) is None
934assert Stream(()).nth(-1, default=None) is None
936assert Stream.range(100)[:10] == tuple(range(10))
937assert Stream.range(100)[90:] == tuple(range(90, 100))
938assert Stream.range(1000)[90:100] == tuple(range(90, 100))
939assert Stream.range(1000)[90:100:2] == tuple(range(90, 100, 2))
941assert Stream.range(1000)[20:44:5] == tuple(range(20, 44, 5))
943assert list(Stream.range(10)) == list(range(10))
944assert list(Stream.range(stop=10)) == list(range(10))
945assert list(Stream.range(0, 20)) == list(range(0, 20))
946assert list(Stream.range(0, stop=20)) == list(range(0, 20))
947assert list(Stream.range(start=0, stop=20)) == list(range(0, 20))
948assert list(Stream.range(0, 20, 3)) == list(range(0, 20, 3))
949assert list(Stream.range(0, 20, step=3)) == list(range(0, 20, 3))
950assert list(Stream.range(0, stop=20, step=3)) == list(range(0, 20, 3))
951assert list(Stream.range(start=0, stop=20, step=3)) == list(range(0, 20, 3))
954# ints_and_strs: list[int | str] = [1, "2", 3, "4"]
955# str_list: list[str] = list(Stream(ints_and_strs).exclude(is_int))
956# assert str_list == ["2", "4"]
957# int_list: list[str] = list(Stream(ints_and_strs).exclude(is_str))
958# assert int_list == [1, 3]
961source: list[str | int | float | complex | bool | None] = [
962 None,
963 True,
964 "2",
965 3,
966 4.2,
967 5j,
968]
969assert assert_type(Stream(source).filter(is_str).collect(list), list[str]) == [
970 "2"
971]
972assert assert_type(Stream(source).filter(is_int).collect(list), list[int]) == [
973 True,
974 3,
975]
976assert assert_type(
977 Stream(source).filter(is_float).collect(list), list[float]
978) == [4.2]
979assert assert_type(
980 Stream(source).filter(is_complex).collect(list), list[complex]
981) == [5j]
982assert assert_type(
983 Stream(source).filter(is_bool).collect(list), list[bool]
984) == [True]
985assert assert_type(
986 Stream(source).filter(is_number).collect(list), list[Number]
987) == [True, 3, 4.2, 5j]
988assert assert_type(
989 Stream(source).filter(is_real_number).collect(list), list[Real]
990) == [True, 3, 4.2]
991assert assert_type(
992 Stream(source).filter(is_none).collect(list), list[None]
993) == [None]
994assert assert_type(
995 Stream(source).filter(is_not_none).collect(list),
996 list[str | int | float | complex | bool],
997) == [True, "2", 3, 4.2, 5j]
1000assert assert_type(
1001 Stream(source).exclude(is_str).collect(list),
1002 list[int | float | complex | bool | None],
1003) == [None, True, 3, 4.2, 5j]
1004assert assert_type(
1005 Stream(source).exclude(is_int).collect(list),
1006 list[str | float | complex | bool | None],
1007) == [None, "2", 4.2, 5j]
1008assert assert_type(
1009 Stream(source).exclude(is_float).collect(list),
1010 list[str | int | complex | bool | None],
1011) == [None, True, "2", 3, 5j]
1012assert assert_type(
1013 Stream(source).exclude(is_complex).collect(list),
1014 list[str | int | float | bool | None],
1015) == [None, True, "2", 3, 4.2]
1016assert assert_type(
1017 Stream(source).exclude(is_bool).collect(list),
1018 list[str | int | float | complex | None],
1019) == [None, "2", 3, 4.2, 5j]
1020assert assert_type(
1021 Stream(source).exclude(is_number).collect(list), list[str | None]
1022) == [None, "2"]
1023assert assert_type(
1024 Stream(source).exclude(is_real_number).collect(list),
1025 list[str | None | complex],
1026) == [None, "2", 5j]
1027assert assert_type(
1028 Stream(source).exclude(is_none).collect(list),
1029 list[str | int | float | complex | bool],
1030) == [True, "2", 3, 4.2, 5j]
1031assert assert_type(
1032 Stream(source).exclude(is_not_none).collect(list), list[None]
1033) == [None]
1035assert not Stream(()).count()
1036assert Stream(range(100)).drop(10).count() == 90
1037assert Stream(range(100)).drop(10).collect() == tuple(range(10, 100))
1038assert Stream("abc").drop(2).collect() == ("c",)
1039assert Stream("abc")[::] == ("a", "b", "c") == tuple("abc")[::]
1040assert Stream("abc")[-2::] == ("b", "c") == tuple("abc")[-2::]
1041assert Stream("abc")[::-1] == ("c", "b", "a") == tuple("abc")[::-1]
1042assert Stream("abc")[::2] == ("a", "c") == tuple("abc")[::2]
1043assert Stream("abc")[:2:] == ("a", "b") == tuple("abc")[:2:]
1044assert Stream("abc")[:-1:] == ("a", "b") == tuple("abc")[:-1:]
1045assert Stream("abc")[-1:-1:-1] == () == tuple("abc")[-1:-1:-1]
1046assert Stream("abc")[-2:-1:-1] == () == tuple("abc")[-2:-1:-1]
1047assert Stream("abc")[-1:-2:-1] == ("c",) == tuple("abc")[-1:-2:-1]
1048assert Stream("abc")[-1:-3:-1] == ("c", "b") == tuple("abc")[-1:-3:-1]
1049assert Stream("abc")[-1:] == ("c",) == tuple("abc")[-1:]
1050assert Stream("abc")[-2:] == ("b", "c") == tuple("abc")[-2:]
1051assert Stream("abc")[-3:] == ("a", "b", "c") == tuple("abc")[-3:]
1052assert Stream("abc")[-2:None:None] == ("b", "c") == tuple("abc")[-2:None:None]
1055assert isinstance(StreamableSequence() * 4, StreamableSequence)
1056assert isinstance(4 * StreamableSequence(), StreamableSequence)
1057assert isinstance(() + StreamableSequence(), tuple)
1058assert isinstance(StreamableSequence() + (), StreamableSequence)
1059assert isinstance(
1060 StreamableSequence() + StreamableSequence(), StreamableSequence
1061)
1062assert isinstance(StreamableSequence()[::], StreamableSequence)
1063assert StreamableSequence("a")[0] == "a"
1065assert StreamableSequence("ab") + ("c", "d") == ("a", "b", "c", "d")
1066assert ("c", "d") + StreamableSequence("ab") == ("c", "d", "a", "b")
1068str_stream = Stream("abc")
1069assert str_stream.last() == "c"
1070assert_raises(StreamFinishedError, str_stream.collect)
1071str_stream = Stream(())
1072assert_raises(StreamEmptyError, str_stream.first)
1074try:
1075 assert (
1076 Stream("abc").map(str.upper).sum()
1077 == Stream("abc").concurrent_map(str.upper).sum()
1078 == "ABC"
1079 )
1080except NotImplementedError:
1081 if sys.implementation.name == "rustpython":
1082 traceback.print_exc()
1083 else:
1084 raise
1086assert_raises(StreamEmptyError, lambda: Stream(()).sum())
1088int_list = []
1089assert (
1090 assert_type(
1091 Stream.counting(-100)
1092 .drop(100)
1093 .drop_while((1000).__gt__)
1094 .take_while((100_000).__gt__)
1095 .filter(is_odd)
1096 .map(operator.pow, 3)
1097 .peek(int_list.append)
1098 .enumerate()
1099 .flat_map(operator.mul, 2)
1100 .exclude(is_even)
1101 .limit(10_000)
1102 .distinct()
1103 .chunk(30)
1104 .map(sum)
1105 .sum(),
1106 int,
1107 )
1108 == 432028881523605
1109)
1110assert sum(int_list) == 432028878744716
1111assert len(int_list) - 1 == 3333
1113try: # pylint: disable=too-many-try-statements
1114 int_list.clear()
1115 assert (
1116 assert_type(
1117 Stream.counting(-100)
1118 .drop(100)
1119 .drop_while((1000).__gt__)
1120 .take_while((100_000).__gt__)
1121 .filter(is_odd)
1122 .map(operator.pow, 3)
1123 .peek(int_list.append)
1124 .enumerate()
1125 .flat_map(operator.mul, 2)
1126 .exclude(is_even)
1127 .limit(10_000)
1128 .distinct()
1129 .chunk(30)
1130 .concurrent_map(sum)
1131 .sum(),
1132 int,
1133 )
1134 == 432028881523605
1135 )
1136 assert sum(int_list) == 432028878744716
1137 assert len(int_list) - 1 == 3333
1138except NotImplementedError:
1139 if sys.implementation.name == "rustpython":
1140 traceback.print_exc()
1141 else:
1142 raise
1144assert Stream("abc").starcollect(lambda *args: args) == ("a", "b", "c")
1146try: # pylint: disable=too-many-try-statements
1147 int_list = []
1148 it_w_cl: IterWithCleanUp[int] = IterWithCleanUp(
1149 Stream.counting(1), lambda: int_list.append(1)
1150 )
1151 assert next(it_w_cl) == 1
1152 assert not int_list
1153 with it_w_cl as _it:
1154 assert next(_it) == 2
1155 assert not int_list
1156 assert int_list == [1]
1158 with it_w_cl as _it:
1159 assert not next(_it, None)
1160 assert int_list == [1]
1162 assert int_list == [1]
1163except TypeError:
1164 if sys.implementation.name == "rustpython":
1165 traceback.print_exc()
1166 else:
1167 raise