diff --git a/lib/apscheduler/executors/asyncio.py b/lib/apscheduler/executors/asyncio.py index 06fc7f96..7d45d6c1 100644 --- a/lib/apscheduler/executors/asyncio.py +++ b/lib/apscheduler/executors/asyncio.py @@ -3,13 +3,9 @@ from __future__ import absolute_import import sys from apscheduler.executors.base import BaseExecutor, run_job +from apscheduler.executors.base_py3 import run_coroutine_job from apscheduler.util import iscoroutinefunction_partial -try: - from apscheduler.executors.base_py3 import run_coroutine_job -except ImportError: - run_coroutine_job = None - class AsyncIOExecutor(BaseExecutor): """ @@ -46,11 +42,8 @@ class AsyncIOExecutor(BaseExecutor): self._run_job_success(job.id, events) if iscoroutinefunction_partial(job.func): - if run_coroutine_job is not None: - coro = run_coroutine_job(job, job._jobstore_alias, run_times, self._logger.name) - f = self._eventloop.create_task(coro) - else: - raise Exception('Executing coroutine based jobs is not supported with Trollius') + coro = run_coroutine_job(job, job._jobstore_alias, run_times, self._logger.name) + f = self._eventloop.create_task(coro) else: f = self._eventloop.run_in_executor(None, run_job, job, job._jobstore_alias, run_times, self._logger.name) diff --git a/lib/apscheduler/jobstores/sqlalchemy.py b/lib/apscheduler/jobstores/sqlalchemy.py index dcfd3e56..716549bc 100644 --- a/lib/apscheduler/jobstores/sqlalchemy.py +++ b/lib/apscheduler/jobstores/sqlalchemy.py @@ -57,7 +57,7 @@ class SQLAlchemyJobStore(BaseJobStore): # 25 = precision that translates to an 8-byte float self.jobs_t = Table( tablename, metadata, - Column('id', Unicode(191, _warn_on_bytestring=False), primary_key=True), + Column('id', Unicode(191), primary_key=True), Column('next_run_time', Float(25), index=True), Column('job_state', LargeBinary, nullable=False), schema=tableschema @@ -68,20 +68,22 @@ class SQLAlchemyJobStore(BaseJobStore): self.jobs_t.create(self.engine, True) def lookup_job(self, job_id): - selectable = select([self.jobs_t.c.job_state]).where(self.jobs_t.c.id == job_id) - job_state = self.engine.execute(selectable).scalar() - return self._reconstitute_job(job_state) if job_state else None + selectable = select(self.jobs_t.c.job_state).where(self.jobs_t.c.id == job_id) + with self.engine.begin() as connection: + job_state = connection.execute(selectable).scalar() + return self._reconstitute_job(job_state) if job_state else None def get_due_jobs(self, now): timestamp = datetime_to_utc_timestamp(now) return self._get_jobs(self.jobs_t.c.next_run_time <= timestamp) def get_next_run_time(self): - selectable = select([self.jobs_t.c.next_run_time]).\ + selectable = select(self.jobs_t.c.next_run_time).\ where(self.jobs_t.c.next_run_time != null()).\ order_by(self.jobs_t.c.next_run_time).limit(1) - next_run_time = self.engine.execute(selectable).scalar() - return utc_timestamp_to_datetime(next_run_time) + with self.engine.begin() as connection: + next_run_time = connection.execute(selectable).scalar() + return utc_timestamp_to_datetime(next_run_time) def get_all_jobs(self): jobs = self._get_jobs() @@ -94,29 +96,33 @@ class SQLAlchemyJobStore(BaseJobStore): 'next_run_time': datetime_to_utc_timestamp(job.next_run_time), 'job_state': pickle.dumps(job.__getstate__(), self.pickle_protocol) }) - try: - self.engine.execute(insert) - except IntegrityError: - raise ConflictingIdError(job.id) + with self.engine.begin() as connection: + try: + connection.execute(insert) + except IntegrityError: + raise ConflictingIdError(job.id) def update_job(self, job): update = self.jobs_t.update().values(**{ 'next_run_time': datetime_to_utc_timestamp(job.next_run_time), 'job_state': pickle.dumps(job.__getstate__(), self.pickle_protocol) }).where(self.jobs_t.c.id == job.id) - result = self.engine.execute(update) - if result.rowcount == 0: - raise JobLookupError(job.id) + with self.engine.begin() as connection: + result = connection.execute(update) + if result.rowcount == 0: + raise JobLookupError(job.id) def remove_job(self, job_id): delete = self.jobs_t.delete().where(self.jobs_t.c.id == job_id) - result = self.engine.execute(delete) - if result.rowcount == 0: - raise JobLookupError(job_id) + with self.engine.begin() as connection: + result = connection.execute(delete) + if result.rowcount == 0: + raise JobLookupError(job_id) def remove_all_jobs(self): delete = self.jobs_t.delete() - self.engine.execute(delete) + with self.engine.begin() as connection: + connection.execute(delete) def shutdown(self): self.engine.dispose() @@ -132,21 +138,22 @@ class SQLAlchemyJobStore(BaseJobStore): def _get_jobs(self, *conditions): jobs = [] - selectable = select([self.jobs_t.c.id, self.jobs_t.c.job_state]).\ + selectable = select(self.jobs_t.c.id, self.jobs_t.c.job_state).\ order_by(self.jobs_t.c.next_run_time) selectable = selectable.where(and_(*conditions)) if conditions else selectable failed_job_ids = set() - for row in self.engine.execute(selectable): - try: - jobs.append(self._reconstitute_job(row.job_state)) - except BaseException: - self._logger.exception('Unable to restore job "%s" -- removing it', row.id) - failed_job_ids.add(row.id) + with self.engine.begin() as connection: + for row in connection.execute(selectable): + try: + jobs.append(self._reconstitute_job(row.job_state)) + except BaseException: + self._logger.exception('Unable to restore job "%s" -- removing it', row.id) + failed_job_ids.add(row.id) - # Remove all the jobs we failed to restore - if failed_job_ids: - delete = self.jobs_t.delete().where(self.jobs_t.c.id.in_(failed_job_ids)) - self.engine.execute(delete) + # Remove all the jobs we failed to restore + if failed_job_ids: + delete = self.jobs_t.delete().where(self.jobs_t.c.id.in_(failed_job_ids)) + connection.execute(delete) return jobs diff --git a/lib/apscheduler/schedulers/asyncio.py b/lib/apscheduler/schedulers/asyncio.py index 70ebedeb..8bcdfdaf 100644 --- a/lib/apscheduler/schedulers/asyncio.py +++ b/lib/apscheduler/schedulers/asyncio.py @@ -1,18 +1,10 @@ from __future__ import absolute_import +import asyncio from functools import wraps, partial from apscheduler.schedulers.base import BaseScheduler from apscheduler.util import maybe_ref -try: - import asyncio -except ImportError: # pragma: nocover - try: - import trollius as asyncio - except ImportError: - raise ImportError( - 'AsyncIOScheduler requires either Python 3.4 or the asyncio package installed') - def run_in_event_loop(func): @wraps(func) diff --git a/lib/apscheduler/util.py b/lib/apscheduler/util.py index d929a482..64b27d7b 100644 --- a/lib/apscheduler/util.py +++ b/lib/apscheduler/util.py @@ -2,6 +2,7 @@ from __future__ import division +from asyncio import iscoroutinefunction from datetime import date, datetime, time, timedelta, tzinfo from calendar import timegm from functools import partial @@ -22,15 +23,6 @@ try: except ImportError: TIMEOUT_MAX = 4294967 # Maximum value accepted by Event.wait() on Windows -try: - from asyncio import iscoroutinefunction -except ImportError: - try: - from trollius import iscoroutinefunction - except ImportError: - def iscoroutinefunction(func): - return False - __all__ = ('asint', 'asbool', 'astimezone', 'convert_to_datetime', 'datetime_to_utc_timestamp', 'utc_timestamp_to_datetime', 'timedelta_seconds', 'datetime_ceil', 'get_callable_name', 'obj_to_ref', 'ref_to_obj', 'maybe_ref', 'repr_escape', 'check_callable_args', diff --git a/package/requirements-package.txt b/package/requirements-package.txt index bbd322c3..27f69c35 100644 --- a/package/requirements-package.txt +++ b/package/requirements-package.txt @@ -1,4 +1,4 @@ -apscheduler==3.9.1.post1 +apscheduler==3.10.0 importlib-metadata==6.0.0 importlib-resources==5.12.0 pyinstaller==5.7.0 diff --git a/requirements.txt b/requirements.txt index 799b09b2..050b9add 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ appdirs==1.4.4 -apscheduler==3.9.1.post1 +apscheduler==3.10.0 arrow==1.2.3 backports.csv==1.0.7 backports.functools-lru-cache==1.6.4