Revert "[tasks] Add support for explicit time parameter when running."
This reverts commit 9f822a1e6d904c4d7454ab77496b8a4f736073ab.
This commit is contained in:
parent
5517a42ee3
commit
071c5b89e0
@ -4,36 +4,19 @@ import websockets
|
|||||||
import discord
|
import discord
|
||||||
import inspect
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
import datetime
|
|
||||||
|
|
||||||
from collections.abc import Sequence
|
|
||||||
from discord.backoff import ExponentialBackoff
|
from discord.backoff import ExponentialBackoff
|
||||||
|
|
||||||
MAX_ASYNCIO_SECONDS = 3456000
|
MAX_ASYNCIO_SECONDS = 3456000
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
def _get_time_parameter(time, *, inst=isinstance, dt=datetime.time, utc=datetime.timezone.utc):
|
|
||||||
if inst(time, dt):
|
|
||||||
return [time if time.tzinfo is not None else time.replace(tzinfo=utc)]
|
|
||||||
if not inst(time, Sequence):
|
|
||||||
raise TypeError('time parameter must be datetime.time or a sequence of datetime.time')
|
|
||||||
if not time:
|
|
||||||
raise ValueError('time parameter must not be an empty sequence.')
|
|
||||||
|
|
||||||
ret = []
|
|
||||||
for index, t in enumerate(time):
|
|
||||||
if not inst(t, dt):
|
|
||||||
raise TypeError('index %d of time sequence expected %r not %r' % (index, dt, type(t)))
|
|
||||||
ret.append(t if t.tzinfo is not None else t.replace(tzinfo=utc))
|
|
||||||
return sorted(ret)
|
|
||||||
|
|
||||||
class Loop:
|
class Loop:
|
||||||
"""A background task helper that abstracts the loop and reconnection logic for you.
|
"""A background task helper that abstracts the loop and reconnection logic for you.
|
||||||
|
|
||||||
The main interface to create this is through :func:`loop`.
|
The main interface to create this is through :func:`loop`.
|
||||||
"""
|
"""
|
||||||
def __init__(self, coro, seconds, hours, minutes, time, count, reconnect, loop):
|
def __init__(self, coro, seconds, hours, minutes, count, reconnect, loop):
|
||||||
self.coro = coro
|
self.coro = coro
|
||||||
self.reconnect = reconnect
|
self.reconnect = reconnect
|
||||||
self.loop = loop or asyncio.get_event_loop()
|
self.loop = loop or asyncio.get_event_loop()
|
||||||
@ -62,7 +45,7 @@ class Loop:
|
|||||||
if self.count is not None and self.count <= 0:
|
if self.count is not None and self.count <= 0:
|
||||||
raise ValueError('count must be greater than 0 or None.')
|
raise ValueError('count must be greater than 0 or None.')
|
||||||
|
|
||||||
self.change_interval(seconds=seconds, minutes=minutes, hours=hours, time=time)
|
self.change_interval(seconds=seconds, minutes=minutes, hours=hours)
|
||||||
|
|
||||||
if not inspect.iscoroutinefunction(self.coro):
|
if not inspect.iscoroutinefunction(self.coro):
|
||||||
raise TypeError('Expected coroutine function, not {0.__name__!r}.'.format(type(self.coro)))
|
raise TypeError('Expected coroutine function, not {0.__name__!r}.'.format(type(self.coro)))
|
||||||
@ -81,10 +64,6 @@ class Loop:
|
|||||||
backoff = ExponentialBackoff()
|
backoff = ExponentialBackoff()
|
||||||
await self._call_loop_function('before_loop')
|
await self._call_loop_function('before_loop')
|
||||||
try:
|
try:
|
||||||
# If a specific time is needed, wait before calling the function
|
|
||||||
if self._time is not None:
|
|
||||||
await asyncio.sleep(self._get_next_sleep_time())
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
await self.coro(*args, **kwargs)
|
await self.coro(*args, **kwargs)
|
||||||
@ -99,7 +78,7 @@ class Loop:
|
|||||||
if self._current_loop == self.count:
|
if self._current_loop == self.count:
|
||||||
break
|
break
|
||||||
|
|
||||||
await asyncio.sleep(self._get_next_sleep_time())
|
await asyncio.sleep(self._sleep)
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
self._is_being_cancelled = True
|
self._is_being_cancelled = True
|
||||||
raise
|
raise
|
||||||
@ -343,38 +322,7 @@ class Loop:
|
|||||||
self._after_loop = coro
|
self._after_loop = coro
|
||||||
return coro
|
return coro
|
||||||
|
|
||||||
def _get_next_sleep_time(self):
|
def change_interval(self, *, seconds=0, minutes=0, hours=0):
|
||||||
if self._sleep is not None:
|
|
||||||
return self._sleep
|
|
||||||
|
|
||||||
# microseconds in the calculations sometimes leads to the sleep time
|
|
||||||
# being too small
|
|
||||||
now = datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0)
|
|
||||||
if self._time_index >= len(self._time):
|
|
||||||
self._time_index = 0
|
|
||||||
|
|
||||||
# note: self._time is sorted by earliest -> latest
|
|
||||||
current_time = self._time[self._time_index]
|
|
||||||
if current_time >= now.timetz():
|
|
||||||
as_dt = datetime.datetime.combine(now.date(), current_time)
|
|
||||||
else:
|
|
||||||
tomorrow = now + datetime.timedelta(days=1)
|
|
||||||
as_dt = datetime.datetime.combine(tomorrow.date(), current_time)
|
|
||||||
|
|
||||||
delta = (as_dt - now).total_seconds()
|
|
||||||
self._time_index += 1
|
|
||||||
return max(delta, 0.0)
|
|
||||||
|
|
||||||
def _prepare_index(self):
|
|
||||||
# pre-condition: self._time is set
|
|
||||||
# find the current index that we should be in
|
|
||||||
now = datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0).timetz()
|
|
||||||
for index, dt in enumerate(self._time):
|
|
||||||
if dt >= now:
|
|
||||||
self._time_index = index
|
|
||||||
break
|
|
||||||
|
|
||||||
def change_interval(self, *, seconds=0, minutes=0, hours=0, time=None):
|
|
||||||
"""Changes the interval for the sleep time.
|
"""Changes the interval for the sleep time.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
@ -392,47 +340,27 @@ class Loop:
|
|||||||
The number of minutes between every iteration.
|
The number of minutes between every iteration.
|
||||||
hours: :class:`float`
|
hours: :class:`float`
|
||||||
The number of hours between every iteration.
|
The number of hours between every iteration.
|
||||||
time: Union[Sequence[:class:`datetime.time`], :class:`datetime.time`]
|
|
||||||
The exact times to run this loop at. Either a list or a single
|
|
||||||
value of :class:`datetime.time` should be passed. Note that
|
|
||||||
this cannot be mixed with the relative time parameters.
|
|
||||||
|
|
||||||
.. versionadded:: 1.3.0
|
|
||||||
|
|
||||||
Raises
|
Raises
|
||||||
-------
|
-------
|
||||||
ValueError
|
ValueError
|
||||||
An invalid value was given.
|
An invalid value was given.
|
||||||
TypeError
|
|
||||||
Mixing ``time`` parameter with relative time parameter or
|
|
||||||
passing an improper type for the ``time`` parameter.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if any((seconds, minutes, hours)) and time is not None:
|
sleep = seconds + (minutes * 60.0) + (hours * 3600.0)
|
||||||
raise TypeError('Cannot mix relative time with explicit time.')
|
if sleep >= MAX_ASYNCIO_SECONDS:
|
||||||
|
fmt = 'Total number of seconds exceeds asyncio imposed limit of {0} seconds.'
|
||||||
|
raise ValueError(fmt.format(MAX_ASYNCIO_SECONDS))
|
||||||
|
|
||||||
|
if sleep < 0:
|
||||||
|
raise ValueError('Total number of seconds cannot be less than zero.')
|
||||||
|
|
||||||
|
self._sleep = sleep
|
||||||
self.seconds = seconds
|
self.seconds = seconds
|
||||||
self.hours = hours
|
self.hours = hours
|
||||||
self.minutes = minutes
|
self.minutes = minutes
|
||||||
self._time_index = 0
|
|
||||||
|
|
||||||
if time is None:
|
def loop(*, seconds=0, minutes=0, hours=0, count=None, reconnect=True, loop=None):
|
||||||
sleep = seconds + (minutes * 60.0) + (hours * 3600.0)
|
|
||||||
if sleep >= MAX_ASYNCIO_SECONDS:
|
|
||||||
fmt = 'Total number of seconds exceeds asyncio imposed limit of {0} seconds.'
|
|
||||||
raise ValueError(fmt.format(MAX_ASYNCIO_SECONDS))
|
|
||||||
|
|
||||||
if sleep < 0:
|
|
||||||
raise ValueError('Total number of seconds cannot be less than zero.')
|
|
||||||
|
|
||||||
self._sleep = sleep
|
|
||||||
self._time = None
|
|
||||||
else:
|
|
||||||
self._sleep = None
|
|
||||||
self._time = _get_time_parameter(time)
|
|
||||||
self._prepare_index()
|
|
||||||
|
|
||||||
def loop(*, seconds=0, minutes=0, hours=0, count=None, time=None, reconnect=True, loop=None):
|
|
||||||
"""A decorator that schedules a task in the background for you with
|
"""A decorator that schedules a task in the background for you with
|
||||||
optional reconnect logic. The decorator returns a :class:`Loop`.
|
optional reconnect logic. The decorator returns a :class:`Loop`.
|
||||||
|
|
||||||
@ -447,12 +375,6 @@ def loop(*, seconds=0, minutes=0, hours=0, count=None, time=None, reconnect=True
|
|||||||
count: Optional[:class:`int`]
|
count: Optional[:class:`int`]
|
||||||
The number of loops to do, ``None`` if it should be an
|
The number of loops to do, ``None`` if it should be an
|
||||||
infinite loop.
|
infinite loop.
|
||||||
time: Union[Sequence[:class:`datetime.time`], :class:`datetime.time`]
|
|
||||||
The exact times to run this loop at. Either a list or a single
|
|
||||||
value of :class:`datetime.time` should be passed. Note that
|
|
||||||
this cannot be mixed with the relative time parameters.
|
|
||||||
|
|
||||||
.. versionadded:: 1.3.0
|
|
||||||
reconnect: :class:`bool`
|
reconnect: :class:`bool`
|
||||||
Whether to handle errors and restart the task
|
Whether to handle errors and restart the task
|
||||||
using an exponential back-off algorithm similar to the
|
using an exponential back-off algorithm similar to the
|
||||||
@ -470,5 +392,5 @@ def loop(*, seconds=0, minutes=0, hours=0, count=None, time=None, reconnect=True
|
|||||||
"""
|
"""
|
||||||
def decorator(func):
|
def decorator(func):
|
||||||
return Loop(func, seconds=seconds, minutes=minutes, hours=hours,
|
return Loop(func, seconds=seconds, minutes=minutes, hours=hours,
|
||||||
time=time, count=count, reconnect=reconnect, loop=loop)
|
count=count, reconnect=reconnect, loop=loop)
|
||||||
return decorator
|
return decorator
|
||||||
|
Loading…
x
Reference in New Issue
Block a user