Add JobQueue.scheduler_configuration and Corresponding Warnings (#3913)

This commit is contained in:
Bibo-Joshi 2023-10-16 20:25:25 +02:00 committed by GitHub
parent af130ef5e7
commit f67e8c0804
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 64 additions and 10 deletions

View file

@ -76,6 +76,17 @@ class JobQueue(Generic[CCT]):
Attributes:
scheduler (:class:`apscheduler.schedulers.asyncio.AsyncIOScheduler`): The scheduler.
Warning:
This scheduler is configured by :meth:`set_application`. Additional configuration
settings can be made by users. However, calling
:meth:`~apscheduler.schedulers.base.BaseScheduler.configure` will delete any
previous configuration settings. Therefore, please make sure to pass the values
returned by :attr:`scheduler_configuration` to the method call in addition to your
custom values.
Alternatively, you can also use methods like
:meth:`~apscheduler.schedulers.base.BaseScheduler.add_jobstore` to avoid using
:meth:`~apscheduler.schedulers.base.BaseScheduler.configure` altogether.
.. versionchanged:: 20.0
Uses :class:`~apscheduler.schedulers.asyncio.AsyncIOScheduler` instead of
:class:`~apscheduler.schedulers.background.BackgroundScheduler`
@ -94,9 +105,7 @@ class JobQueue(Generic[CCT]):
self._application: Optional[weakref.ReferenceType[Application]] = None
self._executor = AsyncIOExecutor()
self.scheduler: AsyncIOScheduler = AsyncIOScheduler(
timezone=pytz.utc, executors={"default": self._executor}
)
self.scheduler: AsyncIOScheduler = AsyncIOScheduler(**self.scheduler_configuration)
def __repr__(self) -> str:
"""Give a string representation of the JobQueue in the form ``JobQueue[application=...]``.
@ -119,6 +128,43 @@ class JobQueue(Generic[CCT]):
return application
raise RuntimeError("The application instance is no longer alive.")
@property
def scheduler_configuration(self) -> JSONDict:
"""Provides configuration values that are used by :class:`JobQueue` for :attr:`scheduler`.
Tip:
Since calling
:meth:`scheduler.configure() <apscheduler.schedulers.base.BaseScheduler.configure>`
deletes any previous setting, please make sure to pass these values to the method call
in addition to your custom values:
.. code-block:: python
scheduler.configure(..., **job_queue.scheduler_configuration)
Alternatively, you can also use methods like
:meth:`~apscheduler.schedulers.base.BaseScheduler.add_jobstore` to avoid using
:meth:`~apscheduler.schedulers.base.BaseScheduler.configure` altogether.
.. versionadded:: NEXT.VERSION
Returns:
Dict[:obj:`str`, :obj:`object`]: The configuration values as dictionary.
"""
timezone: object = pytz.utc
if (
self._application
and isinstance(self.application.bot, ExtBot)
and self.application.bot.defaults
):
timezone = self.application.bot.defaults.tzinfo or pytz.utc
return {
"timezone": timezone,
"executors": {"default": self._executor},
}
def _tz_now(self) -> datetime.datetime:
return datetime.datetime.now(self.scheduler.timezone)
@ -166,11 +212,7 @@ class JobQueue(Generic[CCT]):
"""
self._application = weakref.ref(application)
if isinstance(application.bot, ExtBot) and application.bot.defaults:
self.scheduler.configure(
timezone=application.bot.defaults.tzinfo or pytz.utc,
executors={"default": self._executor},
)
self.scheduler.configure(**self.scheduler_configuration)
@staticmethod
async def job_callback(job_queue: "JobQueue[CCT]", job: "Job[CCT]") -> None:

View file

@ -25,7 +25,7 @@ import time
import pytest
from telegram.ext import ApplicationBuilder, CallbackContext, ContextTypes, Job, JobQueue
from telegram.ext import ApplicationBuilder, CallbackContext, ContextTypes, Defaults, Job, JobQueue
from telegram.warnings import PTBUserWarning
from tests.auxil.envvars import GITHUB_ACTION, TEST_WITH_OPT_DEPS
from tests.auxil.pytest_classes import make_bot
@ -106,6 +106,15 @@ class TestJobQueue:
self.job_time = 0
self.received_error = None
def test_scheduler_configuration(self, job_queue, timezone, bot):
# Unfortunately, we can't really test the executor setting explicitly without relying
# on protected attributes. However, this should be tested enough implicitly via all the
# other tests in here
assert job_queue.scheduler_configuration["timezone"] is UTC
tz_app = ApplicationBuilder().defaults(Defaults(tzinfo=timezone)).token(bot.token).build()
assert tz_app.job_queue.scheduler_configuration["timezone"] is timezone
async def job_run_once(self, context):
if (
isinstance(context, CallbackContext)
@ -578,7 +587,7 @@ class TestJobQueue:
assert rec.name == "telegram.ext.Application"
assert "No error handlers are registered" in rec.getMessage()
async def test_custom_context(self, bot, job_queue):
async def test_custom_context(self, bot):
application = (
ApplicationBuilder()
.token(bot.token)
@ -589,6 +598,7 @@ class TestJobQueue:
)
.build()
)
job_queue = JobQueue()
job_queue.set_application(application)
async def callback(context):
@ -599,9 +609,11 @@ class TestJobQueue:
type(context.bot_data),
)
await job_queue.start()
job_queue.run_once(callback, 0.1)
await asyncio.sleep(0.15)
assert self.result == (CustomContext, None, None, int)
await job_queue.stop()
async def test_attribute_error(self):
job = Job(self.job_run_once)