Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature - enabling a time to execution property on Routines #416

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
6 changes: 4 additions & 2 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
:orphan:
orphan:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Directive should be :orphan:, no?


Master
======
- TwitchIO
- Bug fixes
- Fix IndexError when getting prefix when empty message is sent in a reply.

- Additioons
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Additioons
- Additions

- Added :attr:`~twitchio.ext.routines.Routine.time_until_next_execution` and :attr:`~twitchio.ext.routines.Routine.next_event_time` for monitoring

2.7.0
======
Expand All @@ -24,6 +25,7 @@ Master
- Added :func:`~twitchio.Client.fetch_content_classification_labels` along with :class:`~twitchio.ContentClassificationLabel`
- Added :attr:`~twitchio.ChannelInfo.content_classification_labels` and :attr:`~twitchio.ChannelInfo.is_branded_content` to :class:`~twitchio.ChannelInfo`
- Added new parameters to :func:`~twitchio.PartialUser.modify_stream` for ``is_branded_content`` and ``content_classification_labels``

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this newline added? Did it cause an issue in the building of the documentation?


- Bug fixes
- Fix :func:`~twitchio.Client.search_categories` due to :attr:`~twitchio.Game.igdb_id` being added to :class:`~twitchio.Game`
Expand Down
32 changes: 29 additions & 3 deletions twitchio/ext/routines/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,10 @@ def __init__(

self._instance = None

self._args: tuple | None = None
self._kwargs: dict | None = None
self._args: Optional[tuple] = None
self._kwargs: Optional[dict] = None

self.next_event_time: Optional[datetime.datetime] = None

def __get__(self, instance, owner):
if instance is None:
Expand Down Expand Up @@ -174,6 +176,8 @@ def cancel(self) -> None:
Consider using :meth:`stop` if a graceful stop, which will complete the current iteration, is desired.
"""
if self._can_be_cancelled():
self.next_event_time = None

self._task.cancel()

if not self._restarting:
Expand Down Expand Up @@ -211,7 +215,6 @@ def restart_when_over(fut, *, args=args, kwargs=kwargs):

if self._can_be_cancelled():
self._task.add_done_callback(restart_when_over)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this newline removed?

if force:
self._task.cancel()
else:
Expand Down Expand Up @@ -320,6 +323,20 @@ def remaining_iterations(self) -> Optional[int]:
"""A count of remaining iterations."""
return self._remaining_iterations

@property
def time_until_next_execution(self) -> Optional[datetime.timedelta]:
"""Return the time left as a datetime object before the next execution.

None will be returned if the routine is not scheduled
"""

if self.next_event_time is None:
return None

return max(
self.next_event_time - datetime.datetime.now(self.next_event_time.tzinfo), datetime.timedelta(seconds=0)
)

@property
def start_time(self) -> Optional[datetime.datetime]:
"""The time the routine was started.
Expand Down Expand Up @@ -351,10 +368,14 @@ async def _routine(self, *args, **kwargs) -> None:
return self.cancel()

if self._time:
self.next_event_time = self._time
wait = compute_timedelta(self._time)
await asyncio.sleep(wait)

if self._wait_first and not self._time:
self.next_event_time = datetime.timedelta(seconds=self._delta) + datetime.datetime.now(
datetime.timezone.utc
)
await asyncio.sleep(self._delta)

if self._remaining_iterations == 0:
Expand Down Expand Up @@ -382,10 +403,12 @@ async def _routine(self, *args, **kwargs) -> None:
pass
else:
if self._remaining_iterations == 0:
self.next_event_time = None
break

if self._stop_set:
self._stop_set = False
self.next_event_time = None
break

if self._time:
Expand All @@ -394,6 +417,9 @@ async def _routine(self, *args, **kwargs) -> None:
sleep = max((start - datetime.datetime.now(datetime.timezone.utc)).total_seconds() + self._delta, 0)

self._completed_loops += 1

self.next_event_time = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(seconds=sleep)

await asyncio.sleep(sleep)

try:
Expand Down