61 lines
1.8 KiB
Python
61 lines
1.8 KiB
Python
from datetime import datetime
|
|
from typing import Optional, TypeVar
|
|
|
|
from reactivex import abc, typing
|
|
from reactivex.disposable import Disposable, MultipleAssignmentDisposable
|
|
|
|
from .scheduler import Scheduler
|
|
|
|
_TState = TypeVar("_TState")
|
|
|
|
|
|
class PeriodicScheduler(Scheduler, abc.PeriodicSchedulerBase):
|
|
"""Base class for the various periodic scheduler implementations in this
|
|
package as well as the mainloop sub-package.
|
|
"""
|
|
|
|
def schedule_periodic(
|
|
self,
|
|
period: typing.RelativeTime,
|
|
action: typing.ScheduledPeriodicAction[_TState],
|
|
state: Optional[_TState] = None,
|
|
) -> abc.DisposableBase:
|
|
"""Schedules a periodic piece of work.
|
|
|
|
Args:
|
|
period: Period in seconds or timedelta for running the
|
|
work periodically.
|
|
action: Action to be executed.
|
|
state: [Optional] Initial state passed to the action upon
|
|
the first iteration.
|
|
|
|
Returns:
|
|
The disposable object used to cancel the scheduled
|
|
recurring action (best effort).
|
|
"""
|
|
|
|
disp: MultipleAssignmentDisposable = MultipleAssignmentDisposable()
|
|
seconds: float = self.to_seconds(period)
|
|
|
|
def periodic(
|
|
scheduler: abc.SchedulerBase, state: Optional[_TState] = None
|
|
) -> Optional[Disposable]:
|
|
if disp.is_disposed:
|
|
return None
|
|
|
|
now: datetime = scheduler.now
|
|
|
|
try:
|
|
state = action(state)
|
|
except Exception:
|
|
disp.dispose()
|
|
raise
|
|
|
|
time = seconds - (scheduler.now - now).total_seconds()
|
|
disp.disposable = scheduler.schedule_relative(time, periodic, state=state)
|
|
|
|
return None
|
|
|
|
disp.disposable = self.schedule_relative(period, periodic, state=state)
|
|
return disp
|