Align Behavior Of JobQueue.run_daily With cron (#3046)

This commit is contained in:
James Carl Necio 2022-05-25 16:02:00 +08:00 committed by GitHub
parent 5e24765bbc
commit 349baa0202
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 43 additions and 3 deletions

View file

@ -28,6 +28,7 @@ from apscheduler.job import Job as APSJob
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from telegram._utils.types import JSONDict
from telegram._utils.warnings import warn
from telegram.ext._extbot import ExtBot
from telegram.ext._utils.types import JobCallback
@ -50,6 +51,7 @@ class JobQueue:
"""
__slots__ = ("_application", "scheduler", "_executor")
_CRON_MAPPING = ("sun", "mon", "tue", "wed", "thu", "fri", "sat")
def __init__(self) -> None:
self._application: "Optional[weakref.ReferenceType[Application]]" = None
@ -419,7 +421,11 @@ class JobQueue:
(:obj:`datetime.time.tzinfo`) is :obj:`None`, the default timezone of the bot will
be used.
days (Tuple[:obj:`int`], optional): Defines on which days of the week the job should
run (where ``0-6`` correspond to monday - sunday). Defaults to ``EVERY_DAY``
run (where ``0-6`` correspond to sunday - saturday). By default, the job will run
every day.
.. versionchanged:: 20.0
Changed day of the week mapping of 0-6 from monday-sunday to sunday-saturday.
data (:obj:`object`, optional): Additional data needed for the callback function.
Can be accessed through :attr:`Job.data` in the callback. Defaults to
:obj:`None`.
@ -447,6 +453,12 @@ class JobQueue:
queue.
"""
# TODO: After v20.0, we should remove the this warning.
warn(
"Prior to v20.0 the `days` parameter was not aligned to that of cron's weekday scheme."
"We recommend double checking if the passed value is correct.",
stacklevel=2,
)
if not job_kwargs:
job_kwargs = {}
@ -458,7 +470,7 @@ class JobQueue:
name=name,
args=(self.application,),
trigger="cron",
day_of_week=",".join([str(d) for d in days]),
day_of_week=",".join([self._CRON_MAPPING[d] for d in days]),
hour=time.hour,
minute=time.minute,
second=time.second,

View file

@ -303,7 +303,11 @@ class TestJobQueue:
scheduled_time = job_queue.jobs()[0].next_t.timestamp()
assert scheduled_time == pytest.approx(expected_time)
async def test_run_daily(self, job_queue):
async def test_run_daily(self, job_queue, recwarn):
expected_warning = (
"Prior to v20.0 the `days` parameter was not aligned to that of cron's weekday scheme."
"We recommend double checking if the passed value is correct."
)
delta, now = 1, dtm.datetime.now(pytz.utc)
time_of_day = (now + dtm.timedelta(seconds=delta)).time()
expected_reschedule_time = (now + dtm.timedelta(seconds=delta, days=1)).timestamp()
@ -313,6 +317,30 @@ class TestJobQueue:
assert self.result == 1
scheduled_time = job_queue.jobs()[0].next_t.timestamp()
assert scheduled_time == pytest.approx(expected_reschedule_time)
assert len(recwarn) == 1
assert str(recwarn[0].message) == expected_warning
assert recwarn[0].filename == __file__, "wrong stacklevel"
@pytest.mark.parametrize("weekday", (0, 1, 2, 3, 4, 5, 6))
async def test_run_daily_days_of_week(self, job_queue, recwarn, weekday):
expected_warning = (
"Prior to v20.0 the `days` parameter was not aligned to that of cron's weekday scheme."
"We recommend double checking if the passed value is correct."
)
delta, now = 1, dtm.datetime.now(pytz.utc)
time_of_day = (now + dtm.timedelta(seconds=delta)).time()
# offset in days until next weekday
offset = (weekday + 6 - now.weekday()) % 7
offset = offset if offset > 0 else 7
expected_reschedule_time = (now + dtm.timedelta(seconds=delta, days=offset)).timestamp()
job_queue.run_daily(self.job_run_once, time_of_day, days=[weekday])
await asyncio.sleep(delta + 0.1)
scheduled_time = job_queue.jobs()[0].next_t.timestamp()
assert scheduled_time == pytest.approx(expected_reschedule_time)
assert len(recwarn) == 1
assert str(recwarn[0].message) == expected_warning
assert recwarn[0].filename == __file__, "wrong stacklevel"
async def test_run_monthly(self, job_queue, timezone):
delta, now = 1, dtm.datetime.now(timezone)