Skip to content

Commit d543f27

Browse files
committed
Add change_interval method to Routine.
1 parent f111e67 commit d543f27

File tree

2 files changed

+73
-0
lines changed

2 files changed

+73
-0
lines changed

docs/changelog.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ Master
1818
- Fix USERSTATE parsing incorrect user
1919
- Fix errors when event loop is started using `run_until_complete` to call methods prior to :func:`~twitchio.Client.run`
2020

21+
- ext.routines
22+
- Additions
23+
- Added the :func:`~twitchio.ext.routines.Routine.change_interval` method.
24+
2125
- ext.commands
2226
- Bug fixes
2327
- Make sure double-quotes are properly tokenized for bot commands

twitchio/ext/routines/__init__.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ def __init__(
9797

9898
self._instance = None
9999

100+
self._args: tuple | None = None
101+
self._kwargs: dict | None = None
102+
100103
def __get__(self, instance, owner):
101104
if instance is None:
102105
return self
@@ -143,6 +146,8 @@ def start(self, *args, **kwargs) -> asyncio.Task:
143146
if self._task is not None and not self._task.done() and not self._restarting:
144147
raise RuntimeError(f"Routine {self._coro.__name__!r} is already running and is not done.")
145148

149+
self._args, self._kwargs = args, kwargs
150+
146151
self._restarting = False
147152
self._task = self._loop.create_task(self._routine(*args, **kwargs))
148153

@@ -226,6 +231,70 @@ def after_routine(self, coro: Callable) -> None:
226231

227232
self._after = coro
228233

234+
def change_interval(
235+
self,
236+
*,
237+
seconds: Optional[float] = 0,
238+
minutes: Optional[float] = 0,
239+
hours: Optional[float] = 0,
240+
time: Optional[datetime.datetime] = None,
241+
wait_first: Optional[bool] = False,
242+
) -> None:
243+
"""Method which schedules the running interval of the task to change.
244+
245+
Parameters
246+
----------
247+
seconds: Optional[float]
248+
The seconds to wait before the next iteration of the routine.
249+
minutes: Optional[float]
250+
The minutes to wait before the next iteration of the routine.
251+
hours: Optional[float]
252+
The hours to wait before the next iteration of the routine.
253+
time: Optional[datetime.datetime]
254+
A specific time to run this routine at. If a naive datetime is passed, your system local time will be used.
255+
wait_first: Optional[bool]
256+
Whether to wait the specified time before running the first iteration at the new interval.
257+
Defaults to False.
258+
259+
Raises
260+
------
261+
RuntimeError
262+
Raised when the time argument and any hours, minutes or seconds is passed together.
263+
264+
265+
.. warning::
266+
267+
The time argument can not be passed in conjunction with hours, minutes or seconds.
268+
This behaviour is intended as it allows the time to be exact every day.
269+
"""
270+
time_ = time
271+
272+
if any((seconds, minutes, hours)) and time_:
273+
raise RuntimeError(
274+
"Argument <time> can not be used in conjunction with any <seconds>, <minutes> or <hours> argument(s)."
275+
)
276+
277+
if not time_:
278+
delta = compute_timedelta(
279+
datetime.datetime.now(datetime.timezone.utc)
280+
+ datetime.timedelta(seconds=seconds, minutes=minutes, hours=hours)
281+
)
282+
283+
self._delta = delta
284+
else:
285+
now = datetime.datetime.now(time_.tzinfo)
286+
if time_ < now:
287+
time_ = datetime.datetime.combine(now.date(), time_.time())
288+
if time_ < now:
289+
time_ = time_ + datetime.timedelta(days=1)
290+
291+
self._time = time_
292+
293+
kwargs: dict = self._kwargs
294+
kwargs['force'] = not wait_first
295+
296+
self.restart(*self._args, **kwargs)
297+
229298
def error(self, coro: Callable):
230299
"""A decorator to assign a coroutine as the error handler for this routine.
231300

0 commit comments

Comments
 (0)