Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@
f-string upgrades, `object` base class removal) and removed it from the
ruff exclude list. `tests/test_subject/` also removed from the ruff exclude
list as it already passed all checks.
- Testing: Fixed pyright (standard-mode) type errors in `tests/test_scheduler/`:
corrected `@classmethod` overrides of `VirtualTimeScheduler.add`,
fixed `[None]`-typed list variables, updated optional-import suppression
comments (`# type: ignore[import-untyped]`), narrowed callback parameter
types, and aligned `ScheduledItemTestScheduler` method signatures with the
`Scheduler` base class.
- CI: Standardised `actions/setup-python` to `@v5` across all workflow jobs.

## 2.0.0-alpha
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ asyncio_mode = "strict"
include = ["reactivex", "tests"]
exclude = [
# Stage 1 complete, Stage 2 partial (test_integration complete)
# test_subject and test_scheduler now pass ruff and pyright (run separately)
# keeping them excluded until strict-mode pyright issues are resolved
# test_subject and test_scheduler now pass ruff and pyright in standard mode
# keeping them excluded until type annotations are added to all callbacks (strict mode)
"tests/test_subject",
"tests/test_scheduler",
"tests/test_observable",
Expand Down
8 changes: 6 additions & 2 deletions tests/test_scheduler/test_catchscheduler.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import unittest
from datetime import timedelta

from reactivex import typing as rx_typing
from reactivex.scheduler import CatchScheduler, VirtualTimeScheduler


Expand All @@ -13,8 +14,11 @@ def __init__(self, initial_clock=0.0):
super().__init__(initial_clock)
self.exc = None

def add(self, absolute, relative):
return absolute + relative
@classmethod
def add(
cls, absolute: rx_typing.AbsoluteTime, relative: rx_typing.RelativeTime
) -> rx_typing.AbsoluteTime:
return absolute + relative # type: ignore[operator]

def _wrap(self, action):
def _action(scheduler, state=None):
Expand Down
2 changes: 1 addition & 1 deletion tests/test_scheduler/test_currentthreadscheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def test_currentthread_singleton(self):
assert scheduler[1] is scheduler[2]

gate = [threading.Semaphore(0), threading.Semaphore(0)]
scheduler = [None, None]
scheduler: list[CurrentThreadScheduler | None] = [None, None]

def run(idx):
scheduler[idx] = CurrentThreadScheduler.singleton()
Expand Down
3 changes: 2 additions & 1 deletion tests/test_scheduler/test_eventloop/test_asyncioscheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import pytest

from reactivex import abc
from reactivex.scheduler.eventloop import AsyncIOScheduler

CI = os.getenv("CI") is not None
Expand Down Expand Up @@ -49,7 +50,7 @@ async def go():
scheduler = AsyncIOScheduler(loop)
ran = False

def action(scheduler: AsyncIOScheduler, state: Any):
def action(scheduler: abc.SchedulerBase, state: Any):
nonlocal ran
ran = True

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from reactivex.scheduler.eventloop import IOLoopScheduler

tornado = pytest.importorskip("tornado")
from tornado import ioloop # noqa: E402
from tornado import ioloop # noqa: E402 # type: ignore[import-untyped]


class TestIOLoopScheduler(unittest.TestCase):
Expand Down
7 changes: 5 additions & 2 deletions tests/test_scheduler/test_eventloop/test_twistedscheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
from reactivex.scheduler.eventloop import TwistedScheduler

twisted = pytest.importorskip("twisted")
from twisted.internet import defer, reactor # noqa: E402
from twisted.trial import unittest # noqa: E402
from twisted.internet import ( # noqa: E402 # type: ignore[import-untyped]
defer,
reactor,
)
from twisted.trial import unittest # noqa: E402 # type: ignore[import-untyped]


class TestTwistedScheduler(unittest.TestCase):
Expand Down
12 changes: 7 additions & 5 deletions tests/test_scheduler/test_eventloopscheduler.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os
import threading
import unittest
from datetime import timedelta
from datetime import datetime, timedelta
from time import sleep

import pytest
Expand Down Expand Up @@ -132,7 +132,7 @@ def test_event_loop_schedule_action_relative_due(self):
scheduler = EventLoopScheduler(exit_if_empty=True)
gate = threading.Semaphore(0)
starttime = default_now()
endtime = None
endtime: datetime | None = None

def action(scheduler, state):
nonlocal endtime
Expand All @@ -144,6 +144,7 @@ def action(scheduler, state):
# There is no guarantee that the event-loop thread ends before the
# test thread is re-scheduled, give it some time to always run.
sleep(0.1)
assert endtime is not None
diff = endtime - starttime
assert diff > timedelta(milliseconds=180)
assert scheduler._has_thread() is False
Expand All @@ -152,7 +153,7 @@ def test_event_loop_schedule_action_absolute_due(self):
scheduler = EventLoopScheduler(exit_if_empty=True)
gate = threading.Semaphore(0)
starttime = default_now()
endtime = None
endtime: datetime | None = None

def action(scheduler, state):
nonlocal endtime
Expand All @@ -164,6 +165,7 @@ def action(scheduler, state):
# There is no guarantee that the event-loop thread ends before the
# test thread is re-scheduled, give it some time to always run.
sleep(0.1)
assert endtime is not None
diff = endtime - starttime
assert diff < timedelta(milliseconds=180)
assert scheduler._has_thread() is False
Expand Down Expand Up @@ -241,12 +243,12 @@ def test_eventloop_schedule_periodic_dispose_error(self):

ran = False

def action(scheduler, state):
def action(state: None) -> None:
nonlocal ran
ran = True

with pytest.raises(DisposedException):
scheduler.schedule_periodic(0.1, action)
scheduler.schedule_periodic(0.1, action) # type: ignore[arg-type]

assert ran is False
assert scheduler._has_thread() is False
2 changes: 1 addition & 1 deletion tests/test_scheduler/test_immediatescheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def test_immediate_singleton(self):
assert scheduler[0] is scheduler[1]

gate = [threading.Semaphore(0), threading.Semaphore(0)]
scheduler = [None, None]
scheduler: list[ImmediateScheduler | None] = [None, None]

def run(idx):
scheduler[idx] = ImmediateScheduler()
Expand Down
2 changes: 1 addition & 1 deletion tests/test_scheduler/test_mainloop/test_gtkscheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from reactivex.scheduler.mainloop import GtkScheduler

gi = pytest.importorskip("gi")
from gi.repository import GLib, Gtk # noqa: E402, I001
from gi.repository import GLib, Gtk # noqa: E402, I001 # type: ignore[import-untyped]


gi.require_version("Gtk", "3.0")
Expand Down
6 changes: 4 additions & 2 deletions tests/test_scheduler/test_newthreadscheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,14 @@ def test_new_thread_schedule_periodic(self):
period = 0.05
counter = 3

def action(state: int):
def action(state: int | None) -> int | None:
nonlocal counter
if state:
counter -= 1
return state - 1
if counter == 0:
gate.release()
return None

scheduler.schedule_periodic(period, action, counter)
gate.acquire()
Expand All @@ -92,11 +93,12 @@ def test_new_thread_schedule_periodic_cancel(self):
period = 0.1
counter = 4

def action(state: int):
def action(state: int | None) -> int | None:
nonlocal counter
if state:
counter -= 1
return state - 1
return None

disp = scheduler.schedule_periodic(period, action, counter)
sleep(0.4)
Expand Down
47 changes: 34 additions & 13 deletions tests/test_scheduler/test_scheduleditem.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import unittest
from datetime import timedelta
from typing import Any

from reactivex import abc
from reactivex import typing as rx_typing
from reactivex.disposable import Disposable
from reactivex.internal.basic import default_now
from reactivex.scheduler.scheduleditem import ScheduledItem
Expand All @@ -10,24 +13,42 @@
class ScheduledItemTestScheduler(Scheduler):
def __init__(self):
super()
self.action = None
self.state = None
self.disposable = None

def invoke_action(self, action, state):
self.action: Any = None
self.state: Any = None
self.disposable: abc.DisposableBase | None = None

def invoke_action(
self,
action: abc.ScheduledAction[Any],
state: Any = None,
) -> abc.DisposableBase:
self.action = action
self.state = state
self.disposable = super().invoke_action(action, state)
return self.disposable

def schedule(self, action, state):
pass

def schedule_relative(self, duetime, action, state):
pass

def schedule_absolute(self, duetime, action, state):
pass
def schedule(
self,
action: abc.ScheduledAction[Any],
state: Any = None,
) -> abc.DisposableBase:
return Disposable()

def schedule_relative(
self,
duetime: rx_typing.RelativeTime,
action: abc.ScheduledAction[Any],
state: Any = None,
) -> abc.DisposableBase:
return Disposable()

def schedule_absolute(
self,
duetime: rx_typing.AbsoluteTime,
action: abc.ScheduledAction[Any],
state: Any = None,
) -> abc.DisposableBase:
return Disposable()


class TestScheduledItem(unittest.TestCase):
Expand Down
2 changes: 1 addition & 1 deletion tests/test_scheduler/test_timeoutscheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def test_timeout_singleton(self):
assert scheduler[0] is scheduler[1]

gate = [threading.Semaphore(0), threading.Semaphore(0)]
scheduler = [None, None]
scheduler: list[TimeoutScheduler | None] = [None, None]

def run(idx):
scheduler[idx] = TimeoutScheduler()
Expand Down
12 changes: 8 additions & 4 deletions tests/test_scheduler/test_virtualtimescheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@

import pytest

from reactivex import typing as rx_typing
from reactivex.internal import ArgumentOutOfRangeException
from reactivex.internal.constants import DELTA_ZERO, UTC_ZERO
from reactivex.scheduler import VirtualTimeScheduler


class VirtualSchedulerTestScheduler(VirtualTimeScheduler):
def add(self, absolute, relative):
return absolute + relative
@classmethod
def add(
cls, absolute: rx_typing.AbsoluteTime, relative: rx_typing.RelativeTime
) -> rx_typing.AbsoluteTime:
return absolute + relative # type: ignore[operator]


class TestVirtualTimeScheduler(unittest.TestCase):
Expand All @@ -24,7 +28,7 @@ def test_virtual_now_float(self):
assert scheduler.now == UTC_ZERO

def test_virtual_now_timedelta(self):
scheduler = VirtualSchedulerTestScheduler(DELTA_ZERO)
scheduler = VirtualSchedulerTestScheduler(DELTA_ZERO) # type: ignore[arg-type]
assert scheduler.clock == DELTA_ZERO
assert scheduler.now == UTC_ZERO

Expand Down Expand Up @@ -69,4 +73,4 @@ def test_virtual_schedule_advance_clock_error(self):
scheduler = VirtualSchedulerTestScheduler()

with pytest.raises(ArgumentOutOfRangeException):
scheduler.advance_to(scheduler._clock - 1)
scheduler.advance_to(scheduler._clock - 1) # type: ignore[operator]
Loading