Browse Source

Revert "[tasks] Add support for explicit time parameter when running."

This reverts commit 9f822a1e6d.
pull/2428/head
Rapptz 5 years ago
parent
commit
071c5b89e0
  1. 106
      discord/ext/tasks/__init__.py

106
discord/ext/tasks/__init__.py

@ -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:
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: def loop(*, seconds=0, minutes=0, hours=0, count=None, reconnect=True, loop=None):
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…
Cancel
Save