Skip to content

Commit ba351a0

Browse files
github-actions[bot]Copilotdbrattli
authored
test: fix pyright strict-mode errors in tests/test_observable (batch 2) (#782)
* test: fix pyright strict-mode errors in test_observable (batch 2) Fix pyright strict-mode type errors in 30 files under tests/test_observable/, continuing the incremental cleanup of the pyright exclusion list. Error patterns fixed: - _raise("string") → _raise(Exception("string")) - def action(): → def action(_): for on_next callbacks (OnNext[T] requires a param) - Notification union-attr access annotated with # type: ignore[union-attr] - subscribe(scheduler="not_set") → subscribe(scheduler=None) for proper typing - mapper/generate iterate lambdas annotated with # type: ignore[arg-type] - do_action callback removing spurious return value - factory(ex: Exception) → factory(ex: Exception | None) for on_error_resume_next - return lambda: None → return None in subscribe functions - Hoisted variables to avoid unbound-var errors inside assertRaises blocks - Various other minor fixes (arg-type, call-arg, misc type: ignore) 260 tests pass. Part of ongoing effort to clean up pyright exclusions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor(tests): replace type:ignore comments with proper type annotations Builds on PR #782 to replace the `# type: ignore` suppressions with real type annotations and structural fixes: - Use `isinstance(value, OnError|OnNext)` to narrow `Recorded.value` instead of `# type: ignore[union-attr]` (test_average, test_elementat, test_reduce, test_toiterable). - Properly annotate test-local `subscribe` functions with `ObserverBase[T] / SchedulerBase | None / DisposableBase` and return `Disposable()` so `reactivex.create(...)` accepts them without `# type: ignore[misc]/[arg-type]` (test_concat, test_observeon, test_map, test_skipuntil, test_while_do). - Type `xs` as `list[ColdObservable[int] | None]` in test_defer instead of bare `[None]`, and add `assert xs[0] is not None` narrowing. - Annotate `_raise` as `NoReturn` in test_map, test_retry, test_generate so the surrounding code type-checks without trailing dummy returns. - Use a typed module-level seed in test_generate to widen `Literal[0]` to `int` so `lambda x: x + 1` matches `Mapper[int, int]`. - `cast(Observable[int], s)` in test_tofuture instead of `# type: ignore`. Also widens two clearly-incorrect public type signatures (the implementation already supports the wider input): - `delay()` and `delay_()` now accept `AbsoluteOrRelativeTime` instead of only `RelativeTime`. The implementation already branches on `isinstance(duetime, datetime)`, so this just makes the signature match reality and removes 5 `# type: ignore[arg-type]` in test_delay. - `from_callback()` now returns `Callable[..., Observable[Any]]` instead of `Callable[[], Observable[Any]]`. The inner `function(*args)` already accepts arbitrary args, so this matches reality and removes 2 `# type: ignore[call-arg]` in test_fromcallback. Only `test_of.py:51` keeps a `# type: ignore[call-arg]` — it's in a test that never runs (typo `teest_` in the name) and intentionally calls `reactivex.of()` with a kwarg that doesn't exist; fixing it is out of scope. Pyright strict: 0 errors. All 1494 tests pass. --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Dag Brattli <dag@brattli.net>
1 parent d78df7d commit ba351a0

32 files changed

Lines changed: 158 additions & 80 deletions

reactivex/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ def from_callable(
469469
def from_callback(
470470
func: Callable[..., Callable[..., None]],
471471
mapper: typing.Mapper[Any, Any] | None = None,
472-
) -> Callable[[], Observable[Any]]:
472+
) -> Callable[..., Observable[Any]]:
473473
"""Converts a callback function to an observable sequence.
474474
475475
Args:

reactivex/observable/fromcallback.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
def from_callback_(
99
func: Callable[..., Callable[..., None]],
1010
mapper: typing.Mapper[Any, Any] | None = None,
11-
) -> Callable[[], Observable[Any]]:
11+
) -> Callable[..., Observable[Any]]:
1212
"""Converts a callback function to an observable sequence.
1313
1414
Args:

reactivex/operators/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,8 @@ def dematerialize() -> Callable[[Observable[Notification[_T]]], Observable[_T]]:
707707

708708

709709
def delay(
710-
duetime: typing.RelativeTime, scheduler: abc.SchedulerBase | None = None
710+
duetime: typing.AbsoluteOrRelativeTime,
711+
scheduler: abc.SchedulerBase | None = None,
711712
) -> Callable[[Observable[_T]], Observable[_T]]:
712713
"""The delay operator.
713714

reactivex/operators/_delay.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
def observable_delay_timespan(
2222
source: Observable[_T],
23-
duetime: typing.RelativeTime,
23+
duetime: typing.AbsoluteOrRelativeTime,
2424
scheduler: abc.SchedulerBase | None = None,
2525
) -> Observable[_T]:
2626
def subscribe(
@@ -119,7 +119,7 @@ def action(scheduler: abc.SchedulerBase, state: Any = None):
119119
@curry_flip
120120
def delay_(
121121
source: Observable[_T],
122-
duetime: typing.RelativeTime,
122+
duetime: typing.AbsoluteOrRelativeTime,
123123
scheduler: abc.SchedulerBase | None = None,
124124
) -> Observable[_T]:
125125
"""Time shifts the observable sequence.

tests/test_observable/test_amb.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def test_amb_regular_should_dispose_loser(self):
6868
source_not_disposed = [False]
6969
o1 = scheduler.create_hot_observable(msgs1)
7070

71-
def action():
71+
def action(_):
7272
source_not_disposed[0] = True
7373

7474
o2 = scheduler.create_hot_observable(msgs2).pipe(
@@ -91,7 +91,7 @@ def test_amb_winner_throws(self):
9191
source_not_disposed = [False]
9292
o1 = scheduler.create_hot_observable(msgs1)
9393

94-
def action():
94+
def action(_):
9595
source_not_disposed[0] = True
9696

9797
o2 = scheduler.create_hot_observable(msgs2).pipe(
@@ -112,7 +112,7 @@ def test_amb_loser_throws(self):
112112
msgs2 = [on_next(150, 1), on_next(210, 3), on_completed(250)]
113113
source_not_disposed = [False]
114114

115-
def action():
115+
def action(_):
116116
source_not_disposed[0] = True
117117

118118
o1 = scheduler.create_hot_observable(msgs1).pipe(
@@ -136,7 +136,7 @@ def test_amb_throws_before_election(self):
136136
source_not_disposed = [False]
137137
o1 = scheduler.create_hot_observable(msgs1)
138138

139-
def action():
139+
def action(_):
140140
source_not_disposed[0] = True
141141

142142
o2 = scheduler.create_hot_observable(msgs2).pipe(

tests/test_observable/test_average.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import unittest
22

33
from reactivex import operators as _
4+
from reactivex.notification import OnError
45
from reactivex.testing import ReactiveTest, TestScheduler
56

67
on_next = ReactiveTest.on_next
@@ -20,7 +21,7 @@ def test_average_int32_empty(self):
2021
res = scheduler.start(create=lambda: xs.pipe(_.average())).messages
2122

2223
assert len(res) == 1
23-
assert res[0].value.kind == "E" and res[0].value.exception is not None
24+
assert isinstance(res[0].value, OnError) and res[0].value.exception is not None
2425
assert res[0].time == 250
2526

2627
def test_average_int32_return(self):

tests/test_observable/test_combinelatest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ def create():
472472
]
473473

474474
def test_combine_latest_mapper_throws(self):
475-
ex = "ex"
475+
ex = Exception("ex")
476476
scheduler = TestScheduler()
477477
msgs1 = [on_next(150, 1), on_next(215, 2), on_completed(230)]
478478
msgs2 = [on_next(150, 1), on_next(220, 3), on_completed(240)]

tests/test_observable/test_concat.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import unittest
22

33
import reactivex
4+
from reactivex import abc
45
from reactivex import operators as ops
6+
from reactivex.disposable import Disposable
57
from reactivex.testing import ReactiveTest, TestScheduler
68

79
on_next = ReactiveTest.on_next
@@ -225,15 +227,23 @@ def create():
225227

226228
def test_concat_forward_scheduler(self):
227229
scheduler = TestScheduler()
228-
subscribe_schedulers = {"e1": "unknown", "e2": "unknown"}
230+
subscribe_schedulers: dict[str, object] = {"e1": "unknown", "e2": "unknown"}
229231

230-
def subscribe_e1(observer, scheduler="not_set"):
232+
def subscribe_e1(
233+
observer: abc.ObserverBase[int],
234+
scheduler: abc.SchedulerBase | None = None,
235+
) -> abc.DisposableBase:
231236
subscribe_schedulers["e1"] = scheduler
232237
observer.on_completed()
238+
return Disposable()
233239

234-
def subscribe_e2(observer, scheduler="not_set"):
240+
def subscribe_e2(
241+
observer: abc.ObserverBase[int],
242+
scheduler: abc.SchedulerBase | None = None,
243+
) -> abc.DisposableBase:
235244
subscribe_schedulers["e2"] = scheduler
236245
observer.on_completed()
246+
return Disposable()
237247

238248
e1 = reactivex.create(subscribe_e1)
239249
e2 = reactivex.create(subscribe_e2)
@@ -245,15 +255,23 @@ def subscribe_e2(observer, scheduler="not_set"):
245255
assert subscribe_schedulers["e2"] is scheduler
246256

247257
def test_concat_forward_none_scheduler(self):
248-
subscribe_schedulers = {"e1": "unknown", "e2": "unknown"}
258+
subscribe_schedulers: dict[str, object] = {"e1": "unknown", "e2": "unknown"}
249259

250-
def subscribe_e1(observer, scheduler="not_set"):
260+
def subscribe_e1(
261+
observer: abc.ObserverBase[int],
262+
scheduler: abc.SchedulerBase | None = None,
263+
) -> abc.DisposableBase:
251264
subscribe_schedulers["e1"] = scheduler
252265
observer.on_completed()
266+
return Disposable()
253267

254-
def subscribe_e2(observer, scheduler="not_set"):
268+
def subscribe_e2(
269+
observer: abc.ObserverBase[int],
270+
scheduler: abc.SchedulerBase | None = None,
271+
) -> abc.DisposableBase:
255272
subscribe_schedulers["e2"] = scheduler
256273
observer.on_completed()
274+
return Disposable()
257275

258276
e1 = reactivex.create(subscribe_e1)
259277
e2 = reactivex.create(subscribe_e2)

tests/test_observable/test_debounce.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ def mapper(x):
359359
assert xs.subscriptions == [subscribe(200, 460)]
360360

361361
def test_debounce_duration_mapper_throws(self):
362-
ex = "ex"
362+
ex = Exception("ex")
363363
scheduler = TestScheduler()
364364
xs = scheduler.create_hot_observable(
365365
on_next(150, 1),
@@ -376,7 +376,7 @@ def mapper(x):
376376
on_next(x * 10, "Ignore"), on_next(x * 10 + 5, "Aargh!")
377377
)
378378
else:
379-
_raise(ex)
379+
raise ex
380380

381381
return xs.pipe(_.throttle_with_mapper(mapper))
382382

tests/test_observable/test_defer.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import reactivex
44
from reactivex.testing import ReactiveTest, TestScheduler
5+
from reactivex.testing.coldobservable import ColdObservable
56

67
on_next = ReactiveTest.on_next
78
on_completed = ReactiveTest.on_completed
@@ -23,7 +24,7 @@ def _raise(ex):
2324

2425
class TestDefer(unittest.TestCase):
2526
def test_defer_complete(self):
26-
xs = [None]
27+
xs: list[ColdObservable[int] | None] = [None]
2728
invoked = [0]
2829
scheduler = TestScheduler()
2930

@@ -40,12 +41,13 @@ def defer(scheduler):
4041
results = scheduler.start(create)
4142
assert results.messages == [on_next(300, 200), on_completed(400)]
4243
assert 1 == invoked[0]
44+
assert xs[0] is not None
4345
assert xs[0].subscriptions == [subscribe(200, 400)]
4446

4547
def test_defer_error(self):
4648
scheduler = TestScheduler()
4749
invoked = [0]
48-
xs = [None]
50+
xs: list[ColdObservable[int] | None] = [None]
4951
ex = "ex"
5052

5153
def create():
@@ -62,12 +64,13 @@ def defer(scheduler):
6264

6365
assert results.messages == [on_next(300, 200), on_error(400, ex)]
6466
assert 1 == invoked[0]
67+
assert xs[0] is not None
6568
assert xs[0].subscriptions == [subscribe(200, 400)]
6669

6770
def test_defer_dispose(self):
6871
scheduler = TestScheduler()
6972
invoked = [0]
70-
xs = [None]
73+
xs: list[ColdObservable[int] | None] = [None]
7174

7275
def create():
7376
def defer(scheduler):
@@ -84,6 +87,7 @@ def defer(scheduler):
8487
results = scheduler.start(create)
8588
assert results.messages == [on_next(300, 200), on_next(400, 1)]
8689
assert 1 == invoked[0]
90+
assert xs[0] is not None
8791
assert xs[0].subscriptions == [subscribe(200, 1000)]
8892

8993
def test_defer_on_error(self):

0 commit comments

Comments
 (0)