venv added, updated
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
from .asyncioscheduler import AsyncIOScheduler
|
||||
from .asynciothreadsafescheduler import AsyncIOThreadSafeScheduler
|
||||
from .eventletscheduler import EventletScheduler
|
||||
from .geventscheduler import GEventScheduler
|
||||
from .ioloopscheduler import IOLoopScheduler
|
||||
from .twistedscheduler import TwistedScheduler
|
||||
|
||||
__all__ = [
|
||||
"AsyncIOScheduler",
|
||||
"AsyncIOThreadSafeScheduler",
|
||||
"EventletScheduler",
|
||||
"GEventScheduler",
|
||||
"IOLoopScheduler",
|
||||
"TwistedScheduler",
|
||||
]
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,123 @@
|
||||
import asyncio
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Optional, TypeVar
|
||||
|
||||
from reactivex import abc, typing
|
||||
from reactivex.disposable import (
|
||||
CompositeDisposable,
|
||||
Disposable,
|
||||
SingleAssignmentDisposable,
|
||||
)
|
||||
|
||||
from ..periodicscheduler import PeriodicScheduler
|
||||
|
||||
_TState = TypeVar("_TState")
|
||||
log = logging.getLogger("Rx")
|
||||
|
||||
|
||||
class AsyncIOScheduler(PeriodicScheduler):
|
||||
"""A scheduler that schedules work via the asyncio mainloop. This class
|
||||
does not use the asyncio threadsafe methods, if you need those please use
|
||||
the AsyncIOThreadSafeScheduler class."""
|
||||
|
||||
def __init__(self, loop: asyncio.AbstractEventLoop) -> None:
|
||||
"""Create a new AsyncIOScheduler.
|
||||
|
||||
Args:
|
||||
loop: Instance of asyncio event loop to use; typically, you would
|
||||
get this by asyncio.get_event_loop()
|
||||
"""
|
||||
super().__init__()
|
||||
self._loop: asyncio.AbstractEventLoop = loop
|
||||
|
||||
def schedule(
|
||||
self, action: typing.ScheduledAction[_TState], state: Optional[_TState] = None
|
||||
) -> abc.DisposableBase:
|
||||
"""Schedules an action to be executed.
|
||||
|
||||
Args:
|
||||
action: Action to be executed.
|
||||
state: [Optional] state to be given to the action function.
|
||||
|
||||
Returns:
|
||||
The disposable object used to cancel the scheduled action
|
||||
(best effort).
|
||||
"""
|
||||
sad = SingleAssignmentDisposable()
|
||||
|
||||
def interval() -> None:
|
||||
sad.disposable = self.invoke_action(action, state=state)
|
||||
|
||||
handle = self._loop.call_soon(interval)
|
||||
|
||||
def dispose() -> None:
|
||||
handle.cancel()
|
||||
|
||||
return CompositeDisposable(sad, Disposable(dispose))
|
||||
|
||||
def schedule_relative(
|
||||
self,
|
||||
duetime: typing.RelativeTime,
|
||||
action: typing.ScheduledAction[_TState],
|
||||
state: Optional[_TState] = None,
|
||||
) -> abc.DisposableBase:
|
||||
"""Schedules an action to be executed after duetime.
|
||||
|
||||
Args:
|
||||
duetime: Relative time after which to execute the action.
|
||||
action: Action to be executed.
|
||||
state: [Optional] state to be given to the action function.
|
||||
|
||||
Returns:
|
||||
The disposable object used to cancel the scheduled action
|
||||
(best effort).
|
||||
"""
|
||||
seconds = self.to_seconds(duetime)
|
||||
if seconds <= 0:
|
||||
return self.schedule(action, state)
|
||||
|
||||
sad = SingleAssignmentDisposable()
|
||||
|
||||
def interval() -> None:
|
||||
sad.disposable = self.invoke_action(action, state=state)
|
||||
|
||||
handle = self._loop.call_later(seconds, interval)
|
||||
|
||||
def dispose() -> None:
|
||||
handle.cancel()
|
||||
|
||||
return CompositeDisposable(sad, Disposable(dispose))
|
||||
|
||||
def schedule_absolute(
|
||||
self,
|
||||
duetime: typing.AbsoluteTime,
|
||||
action: typing.ScheduledAction[_TState],
|
||||
state: Optional[_TState] = None,
|
||||
) -> abc.DisposableBase:
|
||||
"""Schedules an action to be executed at duetime.
|
||||
|
||||
Args:
|
||||
duetime: Absolute time at which to execute the action.
|
||||
action: Action to be executed.
|
||||
state: [Optional] state to be given to the action function.
|
||||
|
||||
Returns:
|
||||
The disposable object used to cancel the scheduled action
|
||||
(best effort).
|
||||
"""
|
||||
|
||||
duetime = self.to_datetime(duetime)
|
||||
return self.schedule_relative(duetime - self.now, action, state=state)
|
||||
|
||||
@property
|
||||
def now(self) -> datetime:
|
||||
"""Represents a notion of time for this scheduler. Tasks being
|
||||
scheduled on a scheduler will adhere to the time denoted by this
|
||||
property.
|
||||
|
||||
Returns:
|
||||
The scheduler's current time, as a datetime instance.
|
||||
"""
|
||||
|
||||
return self.to_datetime(self._loop.time())
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
import asyncio
|
||||
import logging
|
||||
from concurrent.futures import Future
|
||||
from typing import List, Optional, TypeVar
|
||||
|
||||
from reactivex import abc, typing
|
||||
from reactivex.disposable import (
|
||||
CompositeDisposable,
|
||||
Disposable,
|
||||
SingleAssignmentDisposable,
|
||||
)
|
||||
|
||||
from .asyncioscheduler import AsyncIOScheduler
|
||||
|
||||
_TState = TypeVar("_TState")
|
||||
|
||||
log = logging.getLogger("Rx")
|
||||
|
||||
|
||||
class AsyncIOThreadSafeScheduler(AsyncIOScheduler):
|
||||
"""A scheduler that schedules work via the asyncio mainloop. This is a
|
||||
subclass of AsyncIOScheduler which uses the threadsafe asyncio methods.
|
||||
"""
|
||||
|
||||
def schedule(
|
||||
self, action: typing.ScheduledAction[_TState], state: Optional[_TState] = None
|
||||
) -> abc.DisposableBase:
|
||||
"""Schedules an action to be executed.
|
||||
|
||||
Args:
|
||||
action: Action to be executed.
|
||||
state: [Optional] state to be given to the action function.
|
||||
|
||||
Returns:
|
||||
The disposable object used to cancel the scheduled action
|
||||
(best effort).
|
||||
"""
|
||||
sad = SingleAssignmentDisposable()
|
||||
|
||||
def interval() -> None:
|
||||
sad.disposable = self.invoke_action(action, state=state)
|
||||
|
||||
handle = self._loop.call_soon_threadsafe(interval)
|
||||
|
||||
def dispose() -> None:
|
||||
if self._on_self_loop_or_not_running():
|
||||
handle.cancel()
|
||||
return
|
||||
|
||||
future: "Future[int]" = Future()
|
||||
|
||||
def cancel_handle() -> None:
|
||||
handle.cancel()
|
||||
future.set_result(0)
|
||||
|
||||
self._loop.call_soon_threadsafe(cancel_handle)
|
||||
future.result()
|
||||
|
||||
return CompositeDisposable(sad, Disposable(dispose))
|
||||
|
||||
def schedule_relative(
|
||||
self,
|
||||
duetime: typing.RelativeTime,
|
||||
action: typing.ScheduledAction[_TState],
|
||||
state: Optional[_TState] = None,
|
||||
) -> abc.DisposableBase:
|
||||
"""Schedules an action to be executed after duetime.
|
||||
|
||||
Args:
|
||||
duetime: Relative time after which to execute the action.
|
||||
action: Action to be executed.
|
||||
state: [Optional] state to be given to the action function.
|
||||
|
||||
Returns:
|
||||
The disposable object used to cancel the scheduled action
|
||||
(best effort).
|
||||
"""
|
||||
seconds = self.to_seconds(duetime)
|
||||
if seconds <= 0:
|
||||
return self.schedule(action, state=state)
|
||||
|
||||
sad = SingleAssignmentDisposable()
|
||||
|
||||
def interval() -> None:
|
||||
sad.disposable = self.invoke_action(action, state=state)
|
||||
|
||||
# the operations on the list used here are atomic, so there is no
|
||||
# need to protect its access with a lock
|
||||
handle: List[asyncio.Handle] = []
|
||||
|
||||
def stage2() -> None:
|
||||
handle.append(self._loop.call_later(seconds, interval))
|
||||
|
||||
handle.append(self._loop.call_soon_threadsafe(stage2))
|
||||
|
||||
def dispose() -> None:
|
||||
def do_cancel_handles() -> None:
|
||||
try:
|
||||
handle.pop().cancel()
|
||||
handle.pop().cancel()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if self._on_self_loop_or_not_running():
|
||||
do_cancel_handles()
|
||||
return
|
||||
|
||||
future: "Future[int]" = Future()
|
||||
|
||||
def cancel_handle() -> None:
|
||||
do_cancel_handles()
|
||||
future.set_result(0)
|
||||
|
||||
self._loop.call_soon_threadsafe(cancel_handle)
|
||||
future.result()
|
||||
|
||||
return CompositeDisposable(sad, Disposable(dispose))
|
||||
|
||||
def schedule_absolute(
|
||||
self,
|
||||
duetime: typing.AbsoluteTime,
|
||||
action: typing.ScheduledAction[_TState],
|
||||
state: Optional[_TState] = None,
|
||||
) -> abc.DisposableBase:
|
||||
"""Schedules an action to be executed at duetime.
|
||||
|
||||
Args:
|
||||
duetime: Absolute time at which to execute the action.
|
||||
action: Action to be executed.
|
||||
state: [Optional] state to be given to the action function.
|
||||
|
||||
Returns:
|
||||
The disposable object used to cancel the scheduled action
|
||||
(best effort).
|
||||
"""
|
||||
|
||||
duetime = self.to_datetime(duetime)
|
||||
return self.schedule_relative(duetime - self.now, action, state=state)
|
||||
|
||||
def _on_self_loop_or_not_running(self) -> bool:
|
||||
"""
|
||||
Returns True if either self._loop is not running, or we're currently
|
||||
executing on self._loop. In both cases, waiting for a future to be
|
||||
resolved on the loop would result in a deadlock.
|
||||
"""
|
||||
if not self._loop.is_running():
|
||||
return True
|
||||
current_loop = None
|
||||
try:
|
||||
# In python 3.7 there asyncio.get_running_loop() is prefered.
|
||||
current_loop = asyncio.get_event_loop()
|
||||
except RuntimeError:
|
||||
# If there is no loop in current thread at all, and it is not main
|
||||
# thread, we get error like:
|
||||
# RuntimeError: There is no current event loop in thread 'Thread-1'
|
||||
pass
|
||||
return self._loop == current_loop
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Any, Optional, TypeVar
|
||||
|
||||
from reactivex import abc, typing
|
||||
from reactivex.disposable import (
|
||||
CompositeDisposable,
|
||||
Disposable,
|
||||
SingleAssignmentDisposable,
|
||||
)
|
||||
|
||||
from ..periodicscheduler import PeriodicScheduler
|
||||
|
||||
_TState = TypeVar("_TState")
|
||||
log = logging.getLogger("Rx")
|
||||
|
||||
|
||||
class EventletScheduler(PeriodicScheduler):
|
||||
"""A scheduler that schedules work via the eventlet event loop.
|
||||
|
||||
http://eventlet.net/
|
||||
"""
|
||||
|
||||
def __init__(self, eventlet: Any) -> None:
|
||||
"""Create a new EventletScheduler.
|
||||
|
||||
Args:
|
||||
eventlet: The eventlet module to use; typically, you would get this
|
||||
by import eventlet
|
||||
"""
|
||||
|
||||
super().__init__()
|
||||
self._eventlet = eventlet
|
||||
|
||||
def schedule(
|
||||
self, action: typing.ScheduledAction[_TState], state: Optional[_TState] = None
|
||||
) -> abc.DisposableBase:
|
||||
"""Schedules an action to be executed.
|
||||
|
||||
Args:
|
||||
action: Action to be executed.
|
||||
state: [Optional] state to be given to the action function.
|
||||
|
||||
Returns:
|
||||
The disposable object used to cancel the scheduled action
|
||||
(best effort).
|
||||
"""
|
||||
|
||||
sad = SingleAssignmentDisposable()
|
||||
|
||||
def interval() -> None:
|
||||
sad.disposable = self.invoke_action(action, state=state)
|
||||
|
||||
timer = self._eventlet.spawn(interval)
|
||||
|
||||
def dispose() -> None:
|
||||
timer.kill()
|
||||
|
||||
return CompositeDisposable(sad, Disposable(dispose))
|
||||
|
||||
def schedule_relative(
|
||||
self,
|
||||
duetime: typing.RelativeTime,
|
||||
action: typing.ScheduledAction[_TState],
|
||||
state: Optional[_TState] = None,
|
||||
) -> abc.DisposableBase:
|
||||
"""Schedules an action to be executed after duetime.
|
||||
|
||||
Args:
|
||||
duetime: Relative time after which to execute the action.
|
||||
action: Action to be executed.
|
||||
state: [Optional] state to be given to the action function.
|
||||
|
||||
Returns:
|
||||
The disposable object used to cancel the scheduled action
|
||||
(best effort).
|
||||
"""
|
||||
|
||||
seconds = self.to_seconds(duetime)
|
||||
if seconds <= 0.0:
|
||||
return self.schedule(action, state=state)
|
||||
|
||||
sad = SingleAssignmentDisposable()
|
||||
|
||||
def interval() -> None:
|
||||
sad.disposable = self.invoke_action(action, state=state)
|
||||
|
||||
timer = self._eventlet.spawn_after(seconds, interval)
|
||||
|
||||
def dispose() -> None:
|
||||
timer.kill()
|
||||
|
||||
return CompositeDisposable(sad, Disposable(dispose))
|
||||
|
||||
def schedule_absolute(
|
||||
self,
|
||||
duetime: typing.AbsoluteTime,
|
||||
action: typing.ScheduledAction[_TState],
|
||||
state: Optional[_TState] = None,
|
||||
) -> abc.DisposableBase:
|
||||
"""Schedules an action to be executed at duetime.
|
||||
|
||||
Args:
|
||||
duetime: Absolute time at which to execute the action.
|
||||
action: Action to be executed.
|
||||
state: [Optional] state to be given to the action function.
|
||||
|
||||
Returns:
|
||||
The disposable object used to cancel the scheduled action
|
||||
(best effort).
|
||||
"""
|
||||
|
||||
duetime = self.to_datetime(duetime)
|
||||
return self.schedule_relative(duetime - self.now, action, state=state)
|
||||
|
||||
@property
|
||||
def now(self) -> datetime:
|
||||
"""Represents a notion of time for this scheduler. Tasks being
|
||||
scheduled on a scheduler will adhere to the time denoted by this
|
||||
property.
|
||||
|
||||
Returns:
|
||||
The scheduler's current time, as a datetime instance.
|
||||
"""
|
||||
|
||||
return self.to_datetime(self._eventlet.hubs.get_hub().clock())
|
||||
@@ -0,0 +1,127 @@
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Any, Optional, TypeVar
|
||||
|
||||
from reactivex import abc, typing
|
||||
from reactivex.disposable import (
|
||||
CompositeDisposable,
|
||||
Disposable,
|
||||
SingleAssignmentDisposable,
|
||||
)
|
||||
|
||||
from ..periodicscheduler import PeriodicScheduler
|
||||
|
||||
_TState = TypeVar("_TState")
|
||||
log = logging.getLogger("Rx")
|
||||
|
||||
|
||||
class GEventScheduler(PeriodicScheduler):
|
||||
"""A scheduler that schedules work via the GEvent event loop.
|
||||
|
||||
http://www.gevent.org/
|
||||
"""
|
||||
|
||||
def __init__(self, gevent: Any) -> None:
|
||||
"""Create a new GEventScheduler.
|
||||
|
||||
Args:
|
||||
gevent: The gevent module to use; typically ,you would get this by
|
||||
import gevent
|
||||
"""
|
||||
|
||||
super().__init__()
|
||||
self._gevent = gevent
|
||||
|
||||
def schedule(
|
||||
self, action: typing.ScheduledAction[_TState], state: Optional[_TState] = None
|
||||
) -> abc.DisposableBase:
|
||||
"""Schedules an action to be executed.
|
||||
|
||||
Args:
|
||||
action: Action to be executed.
|
||||
state: [Optional] state to be given to the action function.
|
||||
|
||||
Returns:
|
||||
The disposable object used to cancel the scheduled action
|
||||
(best effort).
|
||||
"""
|
||||
|
||||
sad = SingleAssignmentDisposable()
|
||||
|
||||
def interval() -> None:
|
||||
sad.disposable = self.invoke_action(action, state=state)
|
||||
|
||||
timer = self._gevent.spawn(interval)
|
||||
|
||||
def dispose() -> None:
|
||||
timer.kill(block=False)
|
||||
|
||||
return CompositeDisposable(sad, Disposable(dispose))
|
||||
|
||||
def schedule_relative(
|
||||
self,
|
||||
duetime: typing.RelativeTime,
|
||||
action: typing.ScheduledAction[_TState],
|
||||
state: Optional[_TState] = None,
|
||||
) -> abc.DisposableBase:
|
||||
"""Schedules an action to be executed after duetime.
|
||||
|
||||
Args:
|
||||
duetime: Relative time after which to execute the action.
|
||||
action: Action to be executed.
|
||||
state: [Optional] state to be given to the action function.
|
||||
|
||||
Returns:
|
||||
The disposable object used to cancel the scheduled action
|
||||
(best effort).
|
||||
"""
|
||||
|
||||
seconds = self.to_seconds(duetime)
|
||||
if seconds <= 0.0:
|
||||
return self.schedule(action, state=state)
|
||||
|
||||
sad = SingleAssignmentDisposable()
|
||||
|
||||
def interval() -> None:
|
||||
sad.disposable = self.invoke_action(action, state=state)
|
||||
|
||||
log.debug("timeout: %s", seconds)
|
||||
timer = self._gevent.spawn_later(seconds, interval)
|
||||
|
||||
def dispose() -> None:
|
||||
timer.kill(block=False)
|
||||
|
||||
return CompositeDisposable(sad, Disposable(dispose))
|
||||
|
||||
def schedule_absolute(
|
||||
self,
|
||||
duetime: typing.AbsoluteTime,
|
||||
action: typing.ScheduledAction[_TState],
|
||||
state: Optional[_TState] = None,
|
||||
) -> abc.DisposableBase:
|
||||
"""Schedules an action to be executed at duetime.
|
||||
|
||||
Args:
|
||||
duetime: Absolute time at which to execute the action.
|
||||
action: Action to be executed.
|
||||
state: [Optional] state to be given to the action function.
|
||||
|
||||
Returns:
|
||||
The disposable object used to cancel the scheduled action
|
||||
(best effort).
|
||||
"""
|
||||
|
||||
duetime = self.to_datetime(duetime)
|
||||
return self.schedule_relative(duetime - self.now, action, state=state)
|
||||
|
||||
@property
|
||||
def now(self) -> datetime:
|
||||
"""Represents a notion of time for this scheduler. Tasks being
|
||||
scheduled on a scheduler will adhere to the time denoted by this
|
||||
property.
|
||||
|
||||
Returns:
|
||||
The scheduler's current time, as a datetime instance.
|
||||
"""
|
||||
|
||||
return self.to_datetime(self._gevent.get_hub().loop.now())
|
||||
@@ -0,0 +1,132 @@
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Any, Optional, TypeVar
|
||||
|
||||
from reactivex import abc, typing
|
||||
from reactivex.disposable import (
|
||||
CompositeDisposable,
|
||||
Disposable,
|
||||
SingleAssignmentDisposable,
|
||||
)
|
||||
|
||||
from ..periodicscheduler import PeriodicScheduler
|
||||
|
||||
_TState = TypeVar("_TState")
|
||||
log = logging.getLogger("Rx")
|
||||
|
||||
|
||||
class IOLoopScheduler(PeriodicScheduler):
|
||||
"""A scheduler that schedules work via the Tornado I/O main event loop.
|
||||
|
||||
Note, as of Tornado 6, this is just a wrapper around the asyncio loop.
|
||||
|
||||
http://tornado.readthedocs.org/en/latest/ioloop.html"""
|
||||
|
||||
def __init__(self, loop: Any) -> None:
|
||||
"""Create a new IOLoopScheduler.
|
||||
|
||||
Args:
|
||||
loop: The ioloop to use; typically, you would get this by
|
||||
tornado import ioloop; ioloop.IOLoop.current()
|
||||
"""
|
||||
|
||||
super().__init__()
|
||||
self._loop = loop
|
||||
|
||||
def schedule(
|
||||
self, action: typing.ScheduledAction[_TState], state: Optional[_TState] = None
|
||||
) -> abc.DisposableBase:
|
||||
"""Schedules an action to be executed.
|
||||
|
||||
Args:
|
||||
action: Action to be executed.
|
||||
state: [Optional] state to be given to the action function.
|
||||
|
||||
Returns:
|
||||
The disposable object used to cancel the scheduled action
|
||||
(best effort).
|
||||
"""
|
||||
|
||||
sad = SingleAssignmentDisposable()
|
||||
disposed = False
|
||||
|
||||
def interval() -> None:
|
||||
if not disposed:
|
||||
sad.disposable = self.invoke_action(action, state=state)
|
||||
|
||||
self._loop.add_callback(interval)
|
||||
|
||||
def dispose() -> None:
|
||||
nonlocal disposed
|
||||
disposed = True
|
||||
|
||||
return CompositeDisposable(sad, Disposable(dispose))
|
||||
|
||||
def schedule_relative(
|
||||
self,
|
||||
duetime: typing.RelativeTime,
|
||||
action: typing.ScheduledAction[_TState],
|
||||
state: Optional[_TState] = None,
|
||||
) -> abc.DisposableBase:
|
||||
"""Schedules an action to be executed after duetime.
|
||||
|
||||
Args:
|
||||
duetime: Relative time after which to execute the action.
|
||||
action: Action to be executed.
|
||||
state: [Optional] state to be given to the action function.
|
||||
|
||||
Returns:
|
||||
The disposable object used to cancel the scheduled action
|
||||
(best effort).
|
||||
"""
|
||||
|
||||
seconds = self.to_seconds(duetime)
|
||||
if seconds <= 0.0:
|
||||
return self.schedule(action, state=state)
|
||||
|
||||
sad = SingleAssignmentDisposable()
|
||||
|
||||
def interval() -> None:
|
||||
sad.disposable = self.invoke_action(action, state=state)
|
||||
|
||||
log.debug("timeout: %s", seconds)
|
||||
timer = self._loop.call_later(seconds, interval)
|
||||
|
||||
def dispose() -> None:
|
||||
self._loop.remove_timeout(timer)
|
||||
self._loop.remove_timeout(timer)
|
||||
|
||||
return CompositeDisposable(sad, Disposable(dispose))
|
||||
|
||||
def schedule_absolute(
|
||||
self,
|
||||
duetime: typing.AbsoluteTime,
|
||||
action: typing.ScheduledAction[_TState],
|
||||
state: Optional[_TState] = None,
|
||||
) -> abc.DisposableBase:
|
||||
"""Schedules an action to be executed at duetime.
|
||||
|
||||
Args:
|
||||
duetime: Absolute time at which to execute the action.
|
||||
action: Action to be executed.
|
||||
state: [Optional] state to be given to the action function.
|
||||
|
||||
Returns:
|
||||
The disposable object used to cancel the scheduled action
|
||||
(best effort).
|
||||
"""
|
||||
|
||||
duetime = self.to_datetime(duetime)
|
||||
return self.schedule_relative(duetime - self.now, action, state=state)
|
||||
|
||||
@property
|
||||
def now(self) -> datetime:
|
||||
"""Represents a notion of time for this scheduler. Tasks being
|
||||
scheduled on a scheduler will adhere to the time denoted by this
|
||||
property.
|
||||
|
||||
Returns:
|
||||
The scheduler's current time, as a datetime instance.
|
||||
"""
|
||||
|
||||
return self.to_datetime(self._loop.time())
|
||||
@@ -0,0 +1,113 @@
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Any, Optional, TypeVar
|
||||
|
||||
from reactivex import abc, typing
|
||||
from reactivex.disposable import (
|
||||
CompositeDisposable,
|
||||
Disposable,
|
||||
SingleAssignmentDisposable,
|
||||
)
|
||||
|
||||
from ..periodicscheduler import PeriodicScheduler
|
||||
|
||||
_TState = TypeVar("_TState")
|
||||
log = logging.getLogger("Rx")
|
||||
|
||||
|
||||
class TwistedScheduler(PeriodicScheduler):
|
||||
"""A scheduler that schedules work via the Twisted reactor mainloop."""
|
||||
|
||||
def __init__(self, reactor: Any) -> None:
|
||||
"""Create a new TwistedScheduler.
|
||||
|
||||
Args:
|
||||
reactor: The reactor to use; typically, you would get this
|
||||
by from twisted.internet import reactor
|
||||
"""
|
||||
|
||||
super().__init__()
|
||||
self._reactor = reactor
|
||||
|
||||
def schedule(
|
||||
self, action: typing.ScheduledAction[_TState], state: Optional[_TState] = None
|
||||
) -> abc.DisposableBase:
|
||||
"""Schedules an action to be executed.
|
||||
|
||||
Args:
|
||||
action: Action to be executed.
|
||||
state: [Optional] state to be given to the action function.
|
||||
|
||||
Returns:
|
||||
The disposable object used to cancel the scheduled action
|
||||
(best effort).
|
||||
"""
|
||||
|
||||
return self.schedule_relative(0.0, action, state=state)
|
||||
|
||||
def schedule_relative(
|
||||
self,
|
||||
duetime: typing.RelativeTime,
|
||||
action: typing.ScheduledAction[_TState],
|
||||
state: Optional[_TState] = None,
|
||||
) -> abc.DisposableBase:
|
||||
"""Schedules an action to be executed after duetime.
|
||||
|
||||
Args:
|
||||
duetime: Relative time after which to execute the action.
|
||||
action: Action to be executed.
|
||||
state: [Optional] state to be given to the action function.
|
||||
|
||||
Returns:
|
||||
The disposable object used to cancel the scheduled action
|
||||
(best effort).
|
||||
"""
|
||||
|
||||
seconds = max(0.0, self.to_seconds(duetime))
|
||||
|
||||
sad = SingleAssignmentDisposable()
|
||||
|
||||
def interval() -> None:
|
||||
sad.disposable = action(self, state)
|
||||
|
||||
log.debug("timeout: %s", seconds)
|
||||
timer = self._reactor.callLater(seconds, interval)
|
||||
|
||||
def dispose() -> None:
|
||||
if not timer.called:
|
||||
timer.cancel()
|
||||
|
||||
return CompositeDisposable(sad, Disposable(dispose))
|
||||
|
||||
def schedule_absolute(
|
||||
self,
|
||||
duetime: typing.AbsoluteTime,
|
||||
action: typing.ScheduledAction[_TState],
|
||||
state: Optional[_TState] = None,
|
||||
) -> abc.DisposableBase:
|
||||
"""Schedules an action to be executed at duetime.
|
||||
|
||||
Args:
|
||||
duetime: Absolute time at which to execute the action.
|
||||
action: Action to be executed.
|
||||
state: [Optional] state to be given to the action function.
|
||||
|
||||
Returns:
|
||||
The disposable object used to cancel the scheduled action
|
||||
(best effort).
|
||||
"""
|
||||
|
||||
duetime = self.to_datetime(duetime)
|
||||
return self.schedule_relative(duetime - self.now, action, state=state)
|
||||
|
||||
@property
|
||||
def now(self) -> datetime:
|
||||
"""Represents a notion of time for this scheduler. Tasks being
|
||||
scheduled on a scheduler will adhere to the time denoted by this
|
||||
property.
|
||||
|
||||
Returns:
|
||||
The scheduler's current time, as a datetime instance.
|
||||
"""
|
||||
|
||||
return self.to_datetime(float(self._reactor.seconds()))
|
||||
Reference in New Issue
Block a user