Coverage for tests / __main__.py: 95%

463 statements  

« 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 

5 

6"""The tests for the Stream.""" 

7 

8from __future__ import annotations 

9 

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 

24 

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 

47 

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) 

60 

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 

65 

66 

67def testmod( 

68 mod: types.ModuleType, 

69 optionflags: int = doctest.DONT_ACCEPT_TRUE_FOR_1, 

70) -> tuple[int, int]: 

71 """Test modules. 

72 

73 Like doctest.testmod, but smaller. 

74 """ 

75 runner = doctest.DocTestRunner(optionflags=optionflags) 

76 

77 for test in doctest.DocTestFinder().find(mod, mod.__name__, mod): 

78 runner.run(test) 

79 

80 return runner.failures, runner.tries 

81 

82 

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 ) 

105 

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) 

114 

115 

116run_doc_tests() 

117 

118 

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" 

123 

124 two: Stream[tuple[str, str]] = Stream("abc").nwise(2) 

125 assert two.map("".join).collect("".join) == "abbc" 

126 

127 three: Stream[tuple[str, ...]] = Stream("abcd").nwise(3) 

128 assert three.map("".join).collect("".join) == "abcbcd" 

129 

130 

131typed_nwise_stuff() 

132 

133 

134# pylint: disable=unnecessary-lambda, protected-access 

135 

136 

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 ) 

149 

150 

151assert_raises(AssertionError, lambda: assert_raises(Exception, lambda: None)) 

152assert_raises(TypeError, lambda: hash(Stream(...))) 

153assert_raises(TypeError, lambda: hash(Stream([0, 1]))) 

154 

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)) 

159 

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) 

177 

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} 

186 

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) 

225 

226 

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 

236 

237 

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) 

245 

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) 

253 

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") 

267 

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) 

298 

299 

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) 

342 

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] 

349 

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) 

365 

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) 

376 

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() == () 

425 

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) 

430 

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) 

435 

436assert assert_type("".join(reversed(Stream("abc"))), str) == "cba" 

437assert tuple(reversed(Stream([1, 2, 3, 4]))) == (4, 3, 2, 1) 

438 

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"} 

449 

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 

454 

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" 

458 

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) 

481 

482assert str(Stream(...)) == "typed_stream.Stream(...)" 

483assert repr(Stream(...)) == "typed_stream.Stream(...)" 

484assert repr(FileStream(...)) == "typed_stream.FileStream(...)" 

485 

486assert_raises(StreamFinishedError, lambda: Stream(...)._data) 

487assert_raises(StreamFinishedError, lambda: BinaryFileStream(...)._data) 

488assert_raises(StreamFinishedError, lambda: FileStream(...)._data) 

489 

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) 

499 

500 

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"} 

518 

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) 

537 

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) 

547 

548 

549def create_int_stream() -> Stream[int]: 

550 """Create an int stream.""" 

551 return Stream.range(10_000).map(operator.pow, 2) 

552 

553 

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) 

565 

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} 

574 

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) 

581 

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) 

594 

595assert Stream((1,)).drop(100).reduce(add, 1) == 1 

596assert Stream("").reduce(add, "x") == "x" 

597assert_raises(StreamEmptyError, Stream("").sum) 

598 

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) 

605 

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() 

618 

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)) 

628 

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] 

638 

639assert len(Stream.from_value("x").limit(1000).tail(10)) == 10 

640 

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] 

644 

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) 

649 

650 

651str_stream: Stream[str] = Stream([None, "1", "2", "3", 4, 0, 23]).filter(is_str) 

652assert str_stream.collect(list) == ["1", "2", "3"] 

653 

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) 

662 

663INPUT_TXT = Path(__file__).parent / "input.txt" 

664 

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 

681 

682assert FileStream(INPUT_TXT, keep_line_ends=True).map( 

683 lambda x: x[-1] 

684).distinct().collect(tuple) == ("\n",) 

685 

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 

691 

692fs = FileStream(INPUT_TXT, keep_line_ends=True) 

693for line in fs: 

694 assert line.endswith("\n") 

695 

696assert fs._file_iterator is None 

697fs = FileStream(INPUT_TXT) 

698for line in fs: 

699 assert not line.endswith("\n") 

700 

701assert fs._file_iterator is None 

702 

703fs = FileStream(INPUT_TXT) 

704assert fs.map(lambda _: ...).limit(1).collect(list) == [...] 

705assert fs._file_iterator is None 

706 

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 

713 

714with FileStream(INPUT_TXT) as fs: 

715 assert isinstance(next(iter(fs)), str) 

716assert fs._file_iterator is None 

717 

718fs = FileStream(INPUT_TXT) 

719assert fs.take_while(len).count() == 4 

720assert fs._file_iterator is None 

721 

722 

723assert BinaryFileStream(INPUT_TXT, keep_line_ends=True).map( 

724 lambda x: x[-1] 

725).distinct().collect(tuple) == (b"\n"[0],) 

726 

727bfs: BinaryFileStream = BinaryFileStream(INPUT_TXT) 

728assert bfs.chain([b" "]).last() == b" " 

729assert bfs._file_iterator is None 

730 

731bfs = BinaryFileStream(INPUT_TXT) 

732assert list(bfs.map(lambda _: ...).limit(1)) == [...] 

733assert bfs._file_iterator is None 

734 

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 

746 

747bfs = BinaryFileStream(INPUT_TXT) 

748assert bfs.take_while(len).count() == 4 

749assert bfs._file_iterator is None 

750 

751bfs = BinaryFileStream(INPUT_TXT) 

752first = bfs.first() 

753assert bfs._file_iterator is None 

754 

755with BinaryFileStream(INPUT_TXT) as bfs: 

756 assert first == next(iter(bfs)) 

757assert bfs._file_iterator is None 

758 

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 

769 

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 

775 

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 

794 

795assert repr(int_stream) == "typed_stream.Stream(...)" 

796 

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) 

800 

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) 

814 

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 

822 

823 

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 

914 

915 

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)) 

924 

925assert_raises(StreamEmptyError, lambda: Stream(()).first()) 

926assert_raises(StreamEmptyError, lambda: Stream([]).first()) 

927assert_raises(StreamEmptyError, lambda: Stream(()).last()) 

928assert_raises(StreamEmptyError, lambda: Stream([]).last()) 

929 

930 

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 

935 

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)) 

940 

941assert Stream.range(1000)[20:44:5] == tuple(range(20, 44, 5)) 

942 

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)) 

952 

953 

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] 

959 

960 

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] 

998 

999 

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] 

1034 

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] 

1053 

1054 

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" 

1064 

1065assert StreamableSequence("ab") + ("c", "d") == ("a", "b", "c", "d") 

1066assert ("c", "d") + StreamableSequence("ab") == ("c", "d", "a", "b") 

1067 

1068str_stream = Stream("abc") 

1069assert str_stream.last() == "c" 

1070assert_raises(StreamFinishedError, str_stream.collect) 

1071str_stream = Stream(()) 

1072assert_raises(StreamEmptyError, str_stream.first) 

1073 

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 

1085 

1086assert_raises(StreamEmptyError, lambda: Stream(()).sum()) 

1087 

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 

1112 

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 

1143 

1144assert Stream("abc").starcollect(lambda *args: args) == ("a", "b", "c") 

1145 

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] 

1157 

1158 with it_w_cl as _it: 

1159 assert not next(_it, None) 

1160 assert int_list == [1] 

1161 

1162 assert int_list == [1] 

1163except TypeError: 

1164 if sys.implementation.name == "rustpython": 

1165 traceback.print_exc() 

1166 else: 

1167 raise