summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/apscheduler/abc.py26
-rw-r--r--src/apscheduler/converters.py3
-rw-r--r--src/apscheduler/datastores/async_adapter.py12
-rw-r--r--src/apscheduler/datastores/async_sqlalchemy.py12
-rw-r--r--src/apscheduler/datastores/memory.py30
-rw-r--r--src/apscheduler/datastores/mongodb.py12
-rw-r--r--src/apscheduler/datastores/sqlalchemy.py16
-rw-r--r--src/apscheduler/enums.py2
-rw-r--r--src/apscheduler/eventbrokers/async_local.py2
-rw-r--r--src/apscheduler/eventbrokers/base.py12
-rw-r--r--src/apscheduler/eventbrokers/local.py6
-rw-r--r--src/apscheduler/eventbrokers/mqtt.py4
-rw-r--r--src/apscheduler/events.py11
-rw-r--r--src/apscheduler/exceptions.py2
-rw-r--r--src/apscheduler/schedulers/async_.py26
-rw-r--r--src/apscheduler/schedulers/sync.py24
-rw-r--r--src/apscheduler/serializers/pickle.py2
-rw-r--r--src/apscheduler/structures.py46
-rw-r--r--src/apscheduler/triggers/calendarinterval.py6
-rw-r--r--src/apscheduler/triggers/combining.py20
-rw-r--r--src/apscheduler/triggers/cron/__init__.py10
-rw-r--r--src/apscheduler/triggers/cron/expressions.py7
-rw-r--r--src/apscheduler/triggers/cron/fields.py6
-rw-r--r--src/apscheduler/triggers/date.py4
-rw-r--r--src/apscheduler/triggers/interval.py8
-rw-r--r--src/apscheduler/validators.py12
-rw-r--r--src/apscheduler/workers/async_.py6
-rw-r--r--src/apscheduler/workers/sync.py6
28 files changed, 168 insertions, 165 deletions
diff --git a/src/apscheduler/abc.py b/src/apscheduler/abc.py
index 58d74cd..929a8cc 100644
--- a/src/apscheduler/abc.py
+++ b/src/apscheduler/abc.py
@@ -3,7 +3,7 @@ from __future__ import annotations
from abc import ABCMeta, abstractmethod
from base64 import b64decode, b64encode
from datetime import datetime
-from typing import TYPE_CHECKING, Any, Callable, Iterable, Iterator, Optional
+from typing import TYPE_CHECKING, Any, Callable, Iterable, Iterator
from uuid import UUID
from .enums import ConflictPolicy
@@ -19,7 +19,7 @@ class Trigger(Iterator[datetime], metaclass=ABCMeta):
__slots__ = ()
@abstractmethod
- def next(self) -> Optional[datetime]:
+ def next(self) -> datetime | None:
"""
Return the next datetime to fire on.
@@ -92,7 +92,7 @@ class EventSource(metaclass=ABCMeta):
@abstractmethod
def subscribe(
self, callback: Callable[[Event], Any],
- event_types: Optional[Iterable[type[Event]]] = None,
+ event_types: Iterable[type[Event]] | None = None,
*,
one_shot: bool = False
) -> Subscription:
@@ -200,7 +200,7 @@ class DataStore:
"""
@abstractmethod
- def get_schedules(self, ids: Optional[set[str]] = None) -> list[Schedule]:
+ def get_schedules(self, ids: set[str] | None = None) -> list[Schedule]:
"""
Get schedules from the data store.
@@ -249,7 +249,7 @@ class DataStore:
"""
@abstractmethod
- def get_next_schedule_run_time(self) -> Optional[datetime]:
+ def get_next_schedule_run_time(self) -> datetime | None:
"""
Return the earliest upcoming run time of all the schedules in the store, or ``None`` if
there are no active schedules.
@@ -264,7 +264,7 @@ class DataStore:
"""
@abstractmethod
- def get_jobs(self, ids: Optional[Iterable[UUID]] = None) -> list[Job]:
+ def get_jobs(self, ids: Iterable[UUID] | None = None) -> list[Job]:
"""
Get the list of pending jobs.
@@ -273,7 +273,7 @@ class DataStore:
"""
@abstractmethod
- def acquire_jobs(self, worker_id: str, limit: Optional[int] = None) -> list[Job]:
+ def acquire_jobs(self, worker_id: str, limit: int | None = None) -> list[Job]:
"""
Acquire unclaimed jobs for execution.
@@ -296,7 +296,7 @@ class DataStore:
"""
@abstractmethod
- def get_job_result(self, job_id: UUID) -> Optional[JobResult]:
+ def get_job_result(self, job_id: UUID) -> JobResult | None:
"""
Retrieve the result of a job.
@@ -358,7 +358,7 @@ class AsyncDataStore:
"""
@abstractmethod
- async def get_schedules(self, ids: Optional[set[str]] = None) -> list[Schedule]:
+ async def get_schedules(self, ids: set[str] | None = None) -> list[Schedule]:
"""
Get schedules from the data store.
@@ -407,7 +407,7 @@ class AsyncDataStore:
"""
@abstractmethod
- async def get_next_schedule_run_time(self) -> Optional[datetime]:
+ async def get_next_schedule_run_time(self) -> datetime | None:
"""
Return the earliest upcoming run time of all the schedules in the store, or ``None`` if
there are no active schedules.
@@ -422,7 +422,7 @@ class AsyncDataStore:
"""
@abstractmethod
- async def get_jobs(self, ids: Optional[Iterable[UUID]] = None) -> list[Job]:
+ async def get_jobs(self, ids: Iterable[UUID] | None = None) -> list[Job]:
"""
Get the list of pending jobs.
@@ -431,7 +431,7 @@ class AsyncDataStore:
"""
@abstractmethod
- async def acquire_jobs(self, worker_id: str, limit: Optional[int] = None) -> list[Job]:
+ async def acquire_jobs(self, worker_id: str, limit: int | None = None) -> list[Job]:
"""
Acquire unclaimed jobs for execution.
@@ -454,7 +454,7 @@ class AsyncDataStore:
"""
@abstractmethod
- async def get_job_result(self, job_id: UUID) -> Optional[JobResult]:
+ async def get_job_result(self, job_id: UUID) -> JobResult | None:
"""
Retrieve the result of a job.
diff --git a/src/apscheduler/converters.py b/src/apscheduler/converters.py
index 103ab35..7a2680d 100644
--- a/src/apscheduler/converters.py
+++ b/src/apscheduler/converters.py
@@ -2,13 +2,12 @@ from __future__ import annotations
from datetime import datetime, timedelta
from enum import Enum
-from typing import Optional
from uuid import UUID
from . import abc
-def as_aware_datetime(value: datetime | str) -> Optional[datetime]:
+def as_aware_datetime(value: datetime | str) -> datetime | None:
"""Convert the value from a string to a timezone aware datetime."""
if isinstance(value, str):
# fromisoformat() does not handle the "Z" suffix
diff --git a/src/apscheduler/datastores/async_adapter.py b/src/apscheduler/datastores/async_adapter.py
index 3537772..945851f 100644
--- a/src/apscheduler/datastores/async_adapter.py
+++ b/src/apscheduler/datastores/async_adapter.py
@@ -3,7 +3,7 @@ from __future__ import annotations
from contextlib import AsyncExitStack
from datetime import datetime
from functools import partial
-from typing import Iterable, Optional
+from typing import Iterable
from uuid import UUID
import attrs
@@ -58,7 +58,7 @@ class AsyncDataStoreAdapter(AsyncDataStore):
async def get_tasks(self) -> list[Task]:
return await to_thread.run_sync(self.original.get_tasks)
- async def get_schedules(self, ids: Optional[set[str]] = None) -> list[Schedule]:
+ async def get_schedules(self, ids: set[str] | None = None) -> list[Schedule]:
return await to_thread.run_sync(self.original.get_schedules, ids)
async def add_schedule(self, schedule: Schedule, conflict_policy: ConflictPolicy) -> None:
@@ -73,20 +73,20 @@ class AsyncDataStoreAdapter(AsyncDataStore):
async def release_schedules(self, scheduler_id: str, schedules: list[Schedule]) -> None:
await to_thread.run_sync(self.original.release_schedules, scheduler_id, schedules)
- async def get_next_schedule_run_time(self) -> Optional[datetime]:
+ async def get_next_schedule_run_time(self) -> datetime | None:
return await to_thread.run_sync(self.original.get_next_schedule_run_time)
async def add_job(self, job: Job) -> None:
await to_thread.run_sync(self.original.add_job, job)
- async def get_jobs(self, ids: Optional[Iterable[UUID]] = None) -> list[Job]:
+ async def get_jobs(self, ids: Iterable[UUID] | None = None) -> list[Job]:
return await to_thread.run_sync(self.original.get_jobs, ids)
- async def acquire_jobs(self, worker_id: str, limit: Optional[int] = None) -> list[Job]:
+ async def acquire_jobs(self, worker_id: str, limit: int | None = None) -> list[Job]:
return await to_thread.run_sync(self.original.acquire_jobs, worker_id, limit)
async def release_job(self, worker_id: str, task_id: str, result: JobResult) -> None:
await to_thread.run_sync(self.original.release_job, worker_id, task_id, result)
- async def get_job_result(self, job_id: UUID) -> Optional[JobResult]:
+ async def get_job_result(self, job_id: UUID) -> JobResult | None:
return await to_thread.run_sync(self.original.get_job_result, job_id)
diff --git a/src/apscheduler/datastores/async_sqlalchemy.py b/src/apscheduler/datastores/async_sqlalchemy.py
index 4ad1483..ca97330 100644
--- a/src/apscheduler/datastores/async_sqlalchemy.py
+++ b/src/apscheduler/datastores/async_sqlalchemy.py
@@ -2,7 +2,7 @@ from __future__ import annotations
from collections import defaultdict
from datetime import datetime, timedelta, timezone
-from typing import Any, Iterable, Optional
+from typing import Any, Iterable
from uuid import UUID
import anyio
@@ -216,7 +216,7 @@ class AsyncSQLAlchemyDataStore(_BaseSQLAlchemyDataStore, AsyncDataStore):
for schedule_id in removed_ids:
await self._events.publish(ScheduleRemoved(schedule_id=schedule_id))
- async def get_schedules(self, ids: Optional[set[str]] = None) -> list[Schedule]:
+ async def get_schedules(self, ids: set[str] | None = None) -> list[Schedule]:
query = self.t_schedules.select().order_by(self.t_schedules.c.id)
if ids:
query = query.where(self.t_schedules.c.id.in_(ids))
@@ -321,7 +321,7 @@ class AsyncSQLAlchemyDataStore(_BaseSQLAlchemyDataStore, AsyncDataStore):
for schedule_id in finished_schedule_ids:
await self._events.publish(ScheduleRemoved(schedule_id=schedule_id))
- async def get_next_schedule_run_time(self) -> Optional[datetime]:
+ async def get_next_schedule_run_time(self) -> datetime | None:
statenent = select(self.t_schedules.c.next_fire_time).\
where(self.t_schedules.c.next_fire_time.isnot(None)).\
order_by(self.t_schedules.c.next_fire_time).\
@@ -344,7 +344,7 @@ class AsyncSQLAlchemyDataStore(_BaseSQLAlchemyDataStore, AsyncDataStore):
tags=job.tags)
await self._events.publish(event)
- async def get_jobs(self, ids: Optional[Iterable[UUID]] = None) -> list[Job]:
+ async def get_jobs(self, ids: Iterable[UUID] | None = None) -> list[Job]:
query = self.t_jobs.select().order_by(self.t_jobs.c.id)
if ids:
job_ids = [job_id for job_id in ids]
@@ -356,7 +356,7 @@ class AsyncSQLAlchemyDataStore(_BaseSQLAlchemyDataStore, AsyncDataStore):
result = await conn.execute(query)
return await self._deserialize_jobs(result)
- async def acquire_jobs(self, worker_id: str, limit: Optional[int] = None) -> list[Job]:
+ async def acquire_jobs(self, worker_id: str, limit: int | None = None) -> list[Job]:
async for attempt in self._retrying:
with attempt:
async with self.engine.begin() as conn:
@@ -444,7 +444,7 @@ class AsyncSQLAlchemyDataStore(_BaseSQLAlchemyDataStore, AsyncDataStore):
delete = self.t_jobs.delete().where(self.t_jobs.c.id == result.job_id)
await conn.execute(delete)
- async def get_job_result(self, job_id: UUID) -> Optional[JobResult]:
+ async def get_job_result(self, job_id: UUID) -> JobResult | None:
async for attempt in self._retrying:
with attempt:
async with self.engine.begin() as conn:
diff --git a/src/apscheduler/datastores/memory.py b/src/apscheduler/datastores/memory.py
index 6b8bc7b..65fad9e 100644
--- a/src/apscheduler/datastores/memory.py
+++ b/src/apscheduler/datastores/memory.py
@@ -4,7 +4,7 @@ from bisect import bisect_left, insort_right
from collections import defaultdict
from datetime import MAXYEAR, datetime, timedelta, timezone
from functools import partial
-from typing import Any, Iterable, Optional
+from typing import Any, Iterable
from uuid import UUID
import attrs
@@ -35,9 +35,9 @@ class TaskState:
@attrs.define
class ScheduleState:
schedule: Schedule
- next_fire_time: Optional[datetime] = attrs.field(init=False, eq=False)
- acquired_by: Optional[str] = attrs.field(init=False, eq=False, default=None)
- acquired_until: Optional[datetime] = attrs.field(init=False, eq=False, default=None)
+ next_fire_time: datetime | None = attrs.field(init=False, eq=False)
+ acquired_by: str | None = attrs.field(init=False, eq=False, default=None)
+ acquired_until: datetime | None = attrs.field(init=False, eq=False, default=None)
def __attrs_post_init__(self):
self.next_fire_time = self.schedule.next_fire_time
@@ -61,8 +61,8 @@ class ScheduleState:
class JobState:
job: Job = attrs.field(order=False)
created_at: datetime = attrs.field(init=False, factory=partial(datetime.now, timezone.utc))
- acquired_by: Optional[str] = attrs.field(eq=False, order=False, default=None)
- acquired_until: Optional[datetime] = attrs.field(eq=False, order=False, default=None)
+ acquired_by: str | None = attrs.field(eq=False, order=False, default=None)
+ acquired_until: datetime | None = attrs.field(eq=False, order=False, default=None)
def __eq__(self, other):
return self.job.id == other.job.id
@@ -85,12 +85,12 @@ class MemoryDataStore(DataStore):
_jobs_by_task_id: dict[str, set[JobState]] = attrs.Factory(partial(defaultdict, set))
_job_results: dict[UUID, JobResult] = attrs.Factory(dict)
- def _find_schedule_index(self, state: ScheduleState) -> Optional[int]:
+ def _find_schedule_index(self, state: ScheduleState) -> int | None:
left_index = bisect_left(self._schedules, state)
right_index = bisect_left(self._schedules, state)
return self._schedules.index(state, left_index, right_index + 1)
- def _find_job_index(self, state: JobState) -> Optional[int]:
+ def _find_job_index(self, state: JobState) -> int | None:
left_index = bisect_left(self._jobs, state)
right_index = bisect_left(self._jobs, state)
return self._jobs.index(state, left_index, right_index + 1)
@@ -106,7 +106,7 @@ class MemoryDataStore(DataStore):
def events(self) -> EventSource:
return self._events
- def get_schedules(self, ids: Optional[set[str]] = None) -> list[Schedule]:
+ def get_schedules(self, ids: set[str] | None = None) -> list[Schedule]:
return [state.schedule for state in self._schedules
if ids is None or state.schedule.id in ids]
@@ -200,7 +200,7 @@ class MemoryDataStore(DataStore):
index = self._find_schedule_index(schedule_state)
del self._schedules[index]
- # Readd the schedule to its new position
+ # Re-add the schedule to its new position
schedule_state.next_fire_time = s.next_fire_time
schedule_state.acquired_by = None
schedule_state.acquired_until = None
@@ -213,7 +213,7 @@ class MemoryDataStore(DataStore):
# Remove schedules that didn't get a new next fire time
self.remove_schedules(finished_schedule_ids)
- def get_next_schedule_run_time(self) -> Optional[datetime]:
+ def get_next_schedule_run_time(self) -> datetime | None:
return self._schedules[0].next_fire_time if self._schedules else None
def add_job(self, job: Job) -> None:
@@ -226,16 +226,16 @@ class MemoryDataStore(DataStore):
tags=job.tags)
self._events.publish(event)
- def get_jobs(self, ids: Optional[Iterable[UUID]] = None) -> list[Job]:
+ def get_jobs(self, ids: Iterable[UUID] | None = None) -> list[Job]:
if ids is not None:
ids = frozenset(ids)
return [state.job for state in self._jobs if ids is None or state.job.id in ids]
- def acquire_jobs(self, worker_id: str, limit: Optional[int] = None) -> list[Job]:
+ def acquire_jobs(self, worker_id: str, limit: int | None = None) -> list[Job]:
now = datetime.now(timezone.utc)
jobs: list[Job] = []
- for index, job_state in enumerate(self._jobs):
+ for _index, job_state in enumerate(self._jobs):
task_state = self._tasks[job_state.job.task_id]
# Skip already acquired jobs (unless the acquisition lock has expired)
@@ -288,5 +288,5 @@ class MemoryDataStore(DataStore):
JobReleased(job_id=result.job_id, worker_id=worker_id, outcome=result.outcome)
)
- def get_job_result(self, job_id: UUID) -> Optional[JobResult]:
+ def get_job_result(self, job_id: UUID) -> JobResult | None:
return self._job_results.pop(job_id, None)
diff --git a/src/apscheduler/datastores/mongodb.py b/src/apscheduler/datastores/mongodb.py
index b8c4db5..7d6fa76 100644
--- a/src/apscheduler/datastores/mongodb.py
+++ b/src/apscheduler/datastores/mongodb.py
@@ -5,7 +5,7 @@ from collections import defaultdict
from contextlib import ExitStack
from datetime import datetime, timedelta, timezone
from logging import Logger, getLogger
-from typing import Any, Callable, ClassVar, Iterable, Optional
+from typing import Any, Callable, ClassVar, Iterable
from uuid import UUID
import attrs
@@ -182,7 +182,7 @@ class MongoDBDataStore(DataStore):
return tasks
- def get_schedules(self, ids: Optional[set[str]] = None) -> list[Schedule]:
+ def get_schedules(self, ids: set[str] | None = None) -> list[Schedule]:
filters = {'_id': {'$in': list(ids)}} if ids is not None else {}
for attempt in self._retrying:
with attempt:
@@ -311,7 +311,7 @@ class MongoDBDataStore(DataStore):
for schedule_id in finished_schedule_ids:
self._events.publish(ScheduleRemoved(schedule_id=schedule_id))
- def get_next_schedule_run_time(self) -> Optional[datetime]:
+ def get_next_schedule_run_time(self) -> datetime | None:
for attempt in self._retrying:
with attempt:
document = self._schedules.find_one({'next_run_time': {'$ne': None}},
@@ -334,7 +334,7 @@ class MongoDBDataStore(DataStore):
tags=job.tags)
self._events.publish(event)
- def get_jobs(self, ids: Optional[Iterable[UUID]] = None) -> list[Job]:
+ def get_jobs(self, ids: Iterable[UUID] | None = None) -> list[Job]:
filters = {'_id': {'$in': list(ids)}} if ids is not None else {}
for attempt in self._retrying:
with attempt:
@@ -352,7 +352,7 @@ class MongoDBDataStore(DataStore):
return jobs
- def acquire_jobs(self, worker_id: str, limit: Optional[int] = None) -> list[Job]:
+ def acquire_jobs(self, worker_id: str, limit: int | None = None) -> list[Job]:
for attempt in self._retrying:
with attempt, self.client.start_session() as session:
cursor = self._jobs.find(
@@ -438,7 +438,7 @@ class MongoDBDataStore(DataStore):
JobReleased(job_id=result.job_id, worker_id=worker_id, outcome=result.outcome)
)
- def get_job_result(self, job_id: UUID) -> Optional[JobResult]:
+ def get_job_result(self, job_id: UUID) -> JobResult | None:
for attempt in self._retrying:
with attempt:
document = self._jobs_results.find_one_and_delete({'_id': job_id})
diff --git a/src/apscheduler/datastores/sqlalchemy.py b/src/apscheduler/datastores/sqlalchemy.py
index 86e8138..ee9fd34 100644
--- a/src/apscheduler/datastores/sqlalchemy.py
+++ b/src/apscheduler/datastores/sqlalchemy.py
@@ -3,7 +3,7 @@ from __future__ import annotations
from collections import defaultdict
from datetime import datetime, timedelta, timezone
from logging import Logger, getLogger
-from typing import Any, Iterable, Optional
+from typing import Any, Iterable
from uuid import UUID
import attrs
@@ -66,10 +66,10 @@ class EmulatedInterval(TypeDecorator):
@attrs.define(kw_only=True, eq=False)
class _BaseSQLAlchemyDataStore:
- schema: Optional[str] = attrs.field(default=None)
+ schema: str | None = attrs.field(default=None)
serializer: Serializer = attrs.field(factory=PickleSerializer)
lock_expiration_delay: float = attrs.field(default=30)
- max_poll_time: Optional[float] = attrs.field(default=1)
+ max_poll_time: float | None = attrs.field(default=1)
max_idle_time: float = attrs.field(default=60)
retry_settings: RetrySettings = attrs.field(default=RetrySettings())
start_from_scratch: bool = attrs.field(default=False)
@@ -342,7 +342,7 @@ class SQLAlchemyDataStore(_BaseSQLAlchemyDataStore, DataStore):
for schedule_id in removed_ids:
self._events.publish(ScheduleRemoved(schedule_id=schedule_id))
- def get_schedules(self, ids: Optional[set[str]] = None) -> list[Schedule]:
+ def get_schedules(self, ids: set[str] | None = None) -> list[Schedule]:
query = self.t_schedules.select().order_by(self.t_schedules.c.id)
if ids:
query = query.where(self.t_schedules.c.id.in_(ids))
@@ -441,7 +441,7 @@ class SQLAlchemyDataStore(_BaseSQLAlchemyDataStore, DataStore):
for schedule_id in finished_schedule_ids:
self._events.publish(ScheduleRemoved(schedule_id=schedule_id))
- def get_next_schedule_run_time(self) -> Optional[datetime]:
+ def get_next_schedule_run_time(self) -> datetime | None:
query = select(self.t_schedules.c.next_fire_time).\
where(self.t_schedules.c.next_fire_time.isnot(None)).\
order_by(self.t_schedules.c.next_fire_time).\
@@ -462,7 +462,7 @@ class SQLAlchemyDataStore(_BaseSQLAlchemyDataStore, DataStore):
tags=job.tags)
self._events.publish(event)
- def get_jobs(self, ids: Optional[Iterable[UUID]] = None) -> list[Job]:
+ def get_jobs(self, ids: Iterable[UUID] | None = None) -> list[Job]:
query = self.t_jobs.select().order_by(self.t_jobs.c.id)
if ids:
job_ids = [job_id for job_id in ids]
@@ -473,7 +473,7 @@ class SQLAlchemyDataStore(_BaseSQLAlchemyDataStore, DataStore):
result = conn.execute(query)
return self._deserialize_jobs(result)
- def acquire_jobs(self, worker_id: str, limit: Optional[int] = None) -> list[Job]:
+ def acquire_jobs(self, worker_id: str, limit: int | None = None) -> list[Job]:
for attempt in self._retrying:
with attempt, self.engine.begin() as conn:
now = datetime.now(timezone.utc)
@@ -563,7 +563,7 @@ class SQLAlchemyDataStore(_BaseSQLAlchemyDataStore, DataStore):
JobReleased(job_id=result.job_id, worker_id=worker_id, outcome=result.outcome)
)
- def get_job_result(self, job_id: UUID) -> Optional[JobResult]:
+ def get_job_result(self, job_id: UUID) -> JobResult | None:
for attempt in self._retrying:
with attempt, self.engine.begin() as conn:
# Retrieve the result
diff --git a/src/apscheduler/enums.py b/src/apscheduler/enums.py
index 5a0929c..dec6669 100644
--- a/src/apscheduler/enums.py
+++ b/src/apscheduler/enums.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from enum import Enum, auto
diff --git a/src/apscheduler/eventbrokers/async_local.py b/src/apscheduler/eventbrokers/async_local.py
index cb0fb96..753505c 100644
--- a/src/apscheduler/eventbrokers/async_local.py
+++ b/src/apscheduler/eventbrokers/async_local.py
@@ -38,7 +38,7 @@ class LocalAsyncEventBroker(AsyncEventBroker, BaseEventBroker):
async def publish_local(self, event: Event) -> None:
event_type = type(event)
one_shot_tokens: list[object] = []
- for token, subscription in self._subscriptions.items():
+ for _token, subscription in self._subscriptions.items():
if subscription.event_types is None or event_type in subscription.event_types:
self._task_group.start_soon(self._deliver_event, subscription.callback, event)
if subscription.one_shot:
diff --git a/src/apscheduler/eventbrokers/base.py b/src/apscheduler/eventbrokers/base.py
index 8ec4dcb..c917d2f 100644
--- a/src/apscheduler/eventbrokers/base.py
+++ b/src/apscheduler/eventbrokers/base.py
@@ -2,7 +2,7 @@ from __future__ import annotations
from base64 import b64decode, b64encode
from logging import Logger, getLogger
-from typing import Any, Callable, Iterable, Optional
+from typing import Any, Callable, Iterable
import attrs
@@ -15,7 +15,7 @@ from ..exceptions import DeserializationError
@attrs.define(eq=False, frozen=True)
class LocalSubscription(Subscription):
callback: Callable[[Event], Any]
- event_types: Optional[set[type[Event]]]
+ event_types: set[type[Event]] | None
one_shot: bool
token: object
_source: BaseEventBroker
@@ -33,7 +33,7 @@ class BaseEventBroker(EventBroker):
self._logger = getLogger(self.__class__.__module__)
def subscribe(self, callback: Callable[[Event], Any],
- event_types: Optional[Iterable[type[Event]]] = None, *,
+ event_types: Iterable[type[Event]] | None = None, *,
one_shot: bool = False) -> Subscription:
types = set(event_types) if event_types else None
token = object()
@@ -57,7 +57,7 @@ class DistributedEventBrokerMixin:
serialized = self.serializer.serialize(attrs.asdict(event))
return event.__class__.__name__ + ' ' + b64encode(serialized).decode('ascii')
- def _reconstitute_event(self, event_type: str, serialized: bytes) -> Optional[Event]:
+ def _reconstitute_event(self, event_type: str, serialized: bytes) -> Event | None:
try:
kwargs = self.serializer.deserialize(serialized)
except DeserializationError:
@@ -78,7 +78,7 @@ class DistributedEventBrokerMixin:
self._logger.exception('Error reconstituting event of type %s', event_type)
return None
- def reconstitute_event(self, payload: bytes) -> Optional[Event]:
+ def reconstitute_event(self, payload: bytes) -> Event | None:
try:
event_type_bytes, serialized = payload.split(b' ', 1)
except ValueError:
@@ -88,7 +88,7 @@ class DistributedEventBrokerMixin:
event_type = event_type_bytes.decode('ascii', errors='replace')
return self._reconstitute_event(event_type, serialized)
- def reconstitute_event_str(self, payload: str) -> Optional[Event]:
+ def reconstitute_event_str(self, payload: str) -> Event | None:
try:
event_type, b64_serialized = payload.split(' ', 1)
except ValueError:
diff --git a/src/apscheduler/eventbrokers/local.py b/src/apscheduler/eventbrokers/local.py
index fd345a1..f780aae 100644
--- a/src/apscheduler/eventbrokers/local.py
+++ b/src/apscheduler/eventbrokers/local.py
@@ -4,7 +4,7 @@ from asyncio import iscoroutinefunction
from concurrent.futures import ThreadPoolExecutor
from contextlib import ExitStack
from threading import Lock
-from typing import Any, Callable, Iterable, Optional
+from typing import Any, Callable, Iterable
import attrs
@@ -31,7 +31,7 @@ class LocalEventBroker(BaseEventBroker):
del self._executor
def subscribe(self, callback: Callable[[Event], Any],
- event_types: Optional[Iterable[type[Event]]] = None, *,
+ event_types: Iterable[type[Event]] | None = None, *,
one_shot: bool = False) -> Subscription:
if iscoroutinefunction(callback):
raise ValueError('Coroutine functions are not supported as callbacks on a synchronous '
@@ -51,7 +51,7 @@ class LocalEventBroker(BaseEventBroker):
event_type = type(event)
with self._subscriptions_lock:
one_shot_tokens: list[object] = []
- for token, subscription in self._subscriptions.items():
+ for _token, subscription in self._subscriptions.items():
if subscription.event_types is None or event_type in subscription.event_types:
self._executor.submit(self._deliver_event, subscription.callback, event)
if subscription.one_shot:
diff --git a/src/apscheduler/eventbrokers/mqtt.py b/src/apscheduler/eventbrokers/mqtt.py
index 60e7195..04db95d 100644
--- a/src/apscheduler/eventbrokers/mqtt.py
+++ b/src/apscheduler/eventbrokers/mqtt.py
@@ -1,7 +1,7 @@
from __future__ import annotations
from concurrent.futures import Future
-from typing import Any, Optional
+from typing import Any
import attrs
from paho.mqtt.client import Client, MQTTMessage
@@ -43,7 +43,7 @@ class MQTTEventBroker(LocalEventBroker, DistributedEventBrokerMixin):
return self
def _on_connect(self, client: Client, userdata: Any, flags: dict[str, Any],
- rc: ReasonCodes | int, properties: Optional[Properties] = None) -> None:
+ rc: ReasonCodes | int, properties: Properties | None = None) -> None:
try:
client.subscribe(self.topic, qos=self.subscribe_qos)
except Exception as exc:
diff --git a/src/apscheduler/events.py b/src/apscheduler/events.py
index 9eb1c7a..f38c12e 100644
--- a/src/apscheduler/events.py
+++ b/src/apscheduler/events.py
@@ -2,7 +2,6 @@ from __future__ import annotations
from datetime import datetime, timezone
from functools import partial
-from typing import Optional
from uuid import UUID
import attrs
@@ -45,13 +44,13 @@ class TaskRemoved(DataStoreEvent):
@attrs.define(kw_only=True, frozen=True)
class ScheduleAdded(DataStoreEvent):
schedule_id: str
- next_fire_time: Optional[datetime] = attrs.field(converter=optional(as_aware_datetime))
+ next_fire_time: datetime | None = attrs.field(converter=optional(as_aware_datetime))
@attrs.define(kw_only=True, frozen=True)
class ScheduleUpdated(DataStoreEvent):
schedule_id: str
- next_fire_time: Optional[datetime] = attrs.field(converter=optional(as_aware_datetime))
+ next_fire_time: datetime | None = attrs.field(converter=optional(as_aware_datetime))
@attrs.define(kw_only=True, frozen=True)
@@ -63,7 +62,7 @@ class ScheduleRemoved(DataStoreEvent):
class JobAdded(DataStoreEvent):
job_id: UUID = attrs.field(converter=as_uuid)
task_id: str
- schedule_id: Optional[str]
+ schedule_id: str | None
tags: frozenset[str] = attrs.field(converter=frozenset)
@@ -100,7 +99,7 @@ class SchedulerStarted(SchedulerEvent):
@attrs.define(kw_only=True, frozen=True)
class SchedulerStopped(SchedulerEvent):
- exception: Optional[BaseException] = None
+ exception: BaseException | None = None
#
@@ -119,7 +118,7 @@ class WorkerStarted(WorkerEvent):
@attrs.define(kw_only=True, frozen=True)
class WorkerStopped(WorkerEvent):
- exception: Optional[BaseException] = None
+ exception: BaseException | None = None
@attrs.define(kw_only=True, frozen=True)
diff --git a/src/apscheduler/exceptions.py b/src/apscheduler/exceptions.py
index b84e58a..64fbf6a 100644
--- a/src/apscheduler/exceptions.py
+++ b/src/apscheduler/exceptions.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from uuid import UUID
diff --git a/src/apscheduler/schedulers/async_.py b/src/apscheduler/schedulers/async_.py
index 61e2e64..6d3287f 100644
--- a/src/apscheduler/schedulers/async_.py
+++ b/src/apscheduler/schedulers/async_.py
@@ -6,7 +6,7 @@ import random
from contextlib import AsyncExitStack
from datetime import datetime, timedelta, timezone
from logging import Logger, getLogger
-from typing import Any, Callable, Iterable, Mapping, Optional
+from typing import Any, Callable, Iterable, Mapping
from uuid import UUID, uuid4
import anyio
@@ -37,11 +37,11 @@ class AsyncScheduler:
data_store: AsyncDataStore = attrs.field(converter=as_async_datastore, factory=MemoryDataStore)
identity: str = attrs.field(kw_only=True, default=None)
start_worker: bool = attrs.field(kw_only=True, default=True)
- logger: Optional[Logger] = attrs.field(kw_only=True, default=getLogger(__name__))
+ logger: Logger | None = attrs.field(kw_only=True, default=getLogger(__name__))
_state: RunState = attrs.field(init=False, default=RunState.stopped)
_wakeup_event: anyio.Event = attrs.field(init=False)
- _worker: Optional[AsyncWorker] = attrs.field(init=False, default=None)
+ _worker: AsyncWorker | None = attrs.field(init=False, default=None)
_events: LocalAsyncEventBroker = attrs.field(init=False, factory=LocalAsyncEventBroker)
_exit_stack: AsyncExitStack = attrs.field(init=False)
@@ -54,7 +54,7 @@ class AsyncScheduler:
return self._events
@property
- def worker(self) -> Optional[AsyncWorker]:
+ def worker(self) -> AsyncWorker | None:
return self._worker
async def __aenter__(self):
@@ -102,11 +102,11 @@ class AsyncScheduler:
self._wakeup_event.set()
async def add_schedule(
- self, func_or_task_id: str | Callable, trigger: Trigger, *, id: Optional[str] = None,
- args: Optional[Iterable] = None, kwargs: Optional[Mapping[str, Any]] = None,
+ self, func_or_task_id: str | Callable, trigger: Trigger, *, id: str | None = None,
+ args: Iterable | None = None, kwargs: Mapping[str, Any] | None = None,
coalesce: CoalescePolicy = CoalescePolicy.latest,
misfire_grace_time: float | timedelta | None = None,
- max_jitter: float | timedelta | None = None, tags: Optional[Iterable[str]] = None,
+ max_jitter: float | timedelta | None = None, tags: Iterable[str] | None = None,
conflict_policy: ConflictPolicy = ConflictPolicy.do_nothing
) -> str:
id = id or str(uuid4())
@@ -139,8 +139,8 @@ class AsyncScheduler:
await self.data_store.remove_schedules({schedule_id})
async def add_job(
- self, func_or_task_id: str | Callable, *, args: Optional[Iterable] = None,
- kwargs: Optional[Mapping[str, Any]] = None, tags: Optional[Iterable[str]] = None
+ self, func_or_task_id: str | Callable, *, args: Iterable | None = None,
+ kwargs: Mapping[str, Any] | None = None, tags: Iterable[str] | None = None
) -> UUID:
"""
Add a job to the data store.
@@ -192,8 +192,8 @@ class AsyncScheduler:
return result
async def run_job(
- self, func_or_task_id: str | Callable, *, args: Optional[Iterable] = None,
- kwargs: Optional[Mapping[str, Any]] = None, tags: Optional[Iterable[str]] = ()
+ self, func_or_task_id: str | Callable, *, args: Iterable | None = None,
+ kwargs: Mapping[str, Any] | None = None, tags: Iterable[str] | None = ()
) -> Any:
"""
Convenience method to add a job and then return its result (or raise its exception).
@@ -207,7 +207,7 @@ class AsyncScheduler:
if event.job_id == job_id:
job_complete_event.set()
- job_id: Optional[UUID] = None
+ job_id: UUID | None = None
with self.data_store.events.subscribe(listener, {JobReleased}):
job_id = await self.add_job(func_or_task_id, args=args, kwargs=kwargs, tags=tags)
await job_complete_event.wait()
@@ -234,7 +234,7 @@ class AsyncScheduler:
task_status.started()
await self._events.publish(SchedulerStarted())
- exception: Optional[BaseException] = None
+ exception: BaseException | None = None
try:
while self._state is RunState.started:
schedules = await self.data_store.acquire_schedules(self.identity, 100)
diff --git a/src/apscheduler/schedulers/sync.py b/src/apscheduler/schedulers/sync.py
index 22270f0..7ead9f8 100644
--- a/src/apscheduler/schedulers/sync.py
+++ b/src/apscheduler/schedulers/sync.py
@@ -8,7 +8,7 @@ from concurrent.futures import FIRST_COMPLETED, Future, ThreadPoolExecutor, wait
from contextlib import ExitStack
from datetime import datetime, timedelta, timezone
from logging import Logger, getLogger
-from typing import Any, Callable, Iterable, Mapping, Optional
+from typing import Any, Callable, Iterable, Mapping
from uuid import UUID, uuid4
import attrs
@@ -36,11 +36,11 @@ class Scheduler:
data_store: DataStore = attrs.field(factory=MemoryDataStore)
identity: str = attrs.field(kw_only=True, default=None)
start_worker: bool = attrs.field(kw_only=True, default=True)
- logger: Optional[Logger] = attrs.field(kw_only=True, default=getLogger(__name__))
+ logger: Logger | None = attrs.field(kw_only=True, default=getLogger(__name__))
_state: RunState = attrs.field(init=False, default=RunState.stopped)
_wakeup_event: threading.Event = attrs.field(init=False)
- _worker: Optional[Worker] = attrs.field(init=False, default=None)
+ _worker: Worker | None = attrs.field(init=False, default=None)
_events: LocalEventBroker = attrs.field(init=False, factory=LocalEventBroker)
_exit_stack: ExitStack = attrs.field(init=False)
@@ -57,7 +57,7 @@ class Scheduler:
return self._state
@property
- def worker(self) -> Optional[Worker]:
+ def worker(self) -> Worker | None:
return self._worker
def __enter__(self) -> Scheduler:
@@ -112,11 +112,11 @@ class Scheduler:
self._wakeup_event.set()
def add_schedule(
- self, func_or_task_id: str | Callable, trigger: Trigger, *, id: Optional[str] = None,
- args: Optional[Iterable] = None, kwargs: Optional[Mapping[str, Any]] = None,
+ self, func_or_task_id: str | Callable, trigger: Trigger, *, id: str | None = None,
+ args: Iterable | None = None, kwargs: Mapping[str, Any] | None = None,
coalesce: CoalescePolicy = CoalescePolicy.latest,
misfire_grace_time: float | timedelta | None = None,
- max_jitter: float | timedelta | None = None, tags: Optional[Iterable[str]] = None,
+ max_jitter: float | timedelta | None = None, tags: Iterable[str] | None = None,
conflict_policy: ConflictPolicy = ConflictPolicy.do_nothing
) -> str:
id = id or str(uuid4())
@@ -149,8 +149,8 @@ class Scheduler:
self.data_store.remove_schedules({schedule_id})
def add_job(
- self, func_or_task_id: str | Callable, *, args: Optional[Iterable] = None,
- kwargs: Optional[Mapping[str, Any]] = None, tags: Optional[Iterable[str]] = None
+ self, func_or_task_id: str | Callable, *, args: Iterable | None = None,
+ kwargs: Mapping[str, Any] | None = None, tags: Iterable[str] | None = None
) -> UUID:
"""
Add a job to the data store.
@@ -202,8 +202,8 @@ class Scheduler:
return result
def run_job(
- self, func_or_task_id: str | Callable, *, args: Optional[Iterable] = None,
- kwargs: Optional[Mapping[str, Any]] = None, tags: Optional[Iterable[str]] = ()
+ self, func_or_task_id: str | Callable, *, args: Iterable | None = None,
+ kwargs: Mapping[str, Any] | None = None, tags: Iterable[str] | None = ()
) -> Any:
"""
Convenience method to add a job and then return its result (or raise its exception).
@@ -217,7 +217,7 @@ class Scheduler:
if event.job_id == job_id:
job_complete_event.set()
- job_id: Optional[UUID] = None
+ job_id: UUID | None = None
with self.data_store.events.subscribe(listener, {JobReleased}):
job_id = self.add_job(func_or_task_id, args=args, kwargs=kwargs, tags=tags)
job_complete_event.wait()
diff --git a/src/apscheduler/serializers/pickle.py b/src/apscheduler/serializers/pickle.py
index d03bdc0..5edf2d0 100644
--- a/src/apscheduler/serializers/pickle.py
+++ b/src/apscheduler/serializers/pickle.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from pickle import dumps, loads
import attrs
diff --git a/src/apscheduler/structures.py b/src/apscheduler/structures.py
index 7f6457d..dd8204c 100644
--- a/src/apscheduler/structures.py
+++ b/src/apscheduler/structures.py
@@ -2,7 +2,7 @@ from __future__ import annotations
from datetime import datetime, timedelta, timezone
from functools import partial
-from typing import Any, Callable, Optional
+from typing import Any, Callable
from uuid import UUID, uuid4
import attrs
@@ -27,8 +27,8 @@ def serialize(inst, field, value):
class Task:
id: str
func: Callable = attrs.field(eq=False, order=False)
- max_running_jobs: Optional[int] = attrs.field(eq=False, order=False, default=None)
- misfire_grace_time: Optional[timedelta] = attrs.field(eq=False, order=False, default=None)
+ max_running_jobs: int | None = attrs.field(eq=False, order=False, default=None)
+ misfire_grace_time: timedelta | None = attrs.field(eq=False, order=False, default=None)
state: Any = None
def marshal(self, serializer: abc.Serializer) -> dict[str, Any]:
@@ -55,15 +55,15 @@ class Schedule:
kwargs: dict[str, Any] = attrs.field(eq=False, order=False, converter=dict, default=())
coalesce: CoalescePolicy = attrs.field(eq=False, order=False, default=CoalescePolicy.latest,
converter=as_enum(CoalescePolicy))
- misfire_grace_time: Optional[timedelta] = attrs.field(eq=False, order=False, default=None,
- converter=as_timedelta)
- max_jitter: Optional[timedelta] = attrs.field(eq=False, order=False, converter=as_timedelta,
- default=None)
+ misfire_grace_time: timedelta | None = attrs.field(eq=False, order=False, default=None,
+ converter=as_timedelta)
+ max_jitter: timedelta | None = attrs.field(eq=False, order=False, converter=as_timedelta,
+ default=None)
tags: frozenset[str] = attrs.field(eq=False, order=False, converter=frozenset, default=())
- next_fire_time: Optional[datetime] = attrs.field(eq=False, order=False, default=None)
- last_fire_time: Optional[datetime] = attrs.field(eq=False, order=False, default=None)
- acquired_by: Optional[str] = attrs.field(eq=False, order=False, default=None)
- acquired_until: Optional[datetime] = attrs.field(eq=False, order=False, default=None)
+ next_fire_time: datetime | None = attrs.field(eq=False, order=False, default=None)
+ last_fire_time: datetime | None = attrs.field(eq=False, order=False, default=None)
+ acquired_by: str | None = attrs.field(eq=False, order=False, default=None)
+ acquired_until: datetime | None = attrs.field(eq=False, order=False, default=None)
def marshal(self, serializer: abc.Serializer) -> dict[str, Any]:
marshalled = attrs.asdict(self, value_serializer=serialize)
@@ -84,7 +84,7 @@ class Schedule:
return cls(**marshalled)
@property
- def next_deadline(self) -> Optional[datetime]:
+ def next_deadline(self) -> datetime | None:
if self.next_fire_time and self.misfire_grace_time:
return self.next_fire_time + self.misfire_grace_time
@@ -97,20 +97,20 @@ class Job:
task_id: str = attrs.field(eq=False, order=False)
args: tuple = attrs.field(eq=False, order=False, converter=tuple, default=())
kwargs: dict[str, Any] = attrs.field(eq=False, order=False, converter=dict, default=())
- schedule_id: Optional[str] = attrs.field(eq=False, order=False, default=None)
- scheduled_fire_time: Optional[datetime] = attrs.field(eq=False, order=False, default=None)
+ schedule_id: str | None = attrs.field(eq=False, order=False, default=None)
+ scheduled_fire_time: datetime | None = attrs.field(eq=False, order=False, default=None)
jitter: timedelta = attrs.field(eq=False, order=False, converter=as_timedelta,
factory=timedelta)
- start_deadline: Optional[datetime] = attrs.field(eq=False, order=False, default=None)
+ start_deadline: datetime | None = attrs.field(eq=False, order=False, default=None)
tags: frozenset[str] = attrs.field(eq=False, order=False, converter=frozenset, default=())
created_at: datetime = attrs.field(eq=False, order=False,
factory=partial(datetime.now, timezone.utc))
- started_at: Optional[datetime] = attrs.field(eq=False, order=False, default=None)
- acquired_by: Optional[str] = attrs.field(eq=False, order=False, default=None)
- acquired_until: Optional[datetime] = attrs.field(eq=False, order=False, default=None)
+ started_at: datetime | None = attrs.field(eq=False, order=False, default=None)
+ acquired_by: str | None = attrs.field(eq=False, order=False, default=None)
+ acquired_until: datetime | None = attrs.field(eq=False, order=False, default=None)
@property
- def original_scheduled_time(self) -> Optional[datetime]:
+ def original_scheduled_time(self) -> datetime | None:
"""The scheduled time without any jitter included."""
if self.scheduled_fire_time is None:
return None
@@ -138,10 +138,10 @@ class Job:
class JobInfo:
job_id: UUID
task_id: str
- schedule_id: Optional[str]
- scheduled_fire_time: Optional[datetime]
+ schedule_id: str | None
+ scheduled_fire_time: datetime | None
jitter: timedelta
- start_deadline: Optional[datetime]
+ start_deadline: datetime | None
tags: frozenset[str]
@classmethod
@@ -157,7 +157,7 @@ class JobResult:
outcome: JobOutcome = attrs.field(eq=False, order=False, converter=as_enum(JobOutcome))
finished_at: datetime = attrs.field(eq=False, order=False,
factory=partial(datetime.now, timezone.utc))
- exception: Optional[BaseException] = attrs.field(eq=False, order=False, default=None)
+ exception: BaseException | None = attrs.field(eq=False, order=False, default=None)
return_value: Any = attrs.field(eq=False, order=False, default=None)
def marshal(self, serializer: abc.Serializer) -> dict[str, Any]:
diff --git a/src/apscheduler/triggers/calendarinterval.py b/src/apscheduler/triggers/calendarinterval.py
index 8d0990d..fbb5896 100644
--- a/src/apscheduler/triggers/calendarinterval.py
+++ b/src/apscheduler/triggers/calendarinterval.py
@@ -1,7 +1,7 @@
from __future__ import annotations
from datetime import date, datetime, time, timedelta, tzinfo
-from typing import Any, Optional
+from typing import Any
import attrs
@@ -67,7 +67,7 @@ class CalendarIntervalTrigger(Trigger):
end_date: date | None = attrs.field(converter=as_date, default=None)
timezone: tzinfo = attrs.field(converter=as_timezone, default='local')
_time: time = attrs.field(init=False, eq=False)
- _last_fire_date: Optional[date] = attrs.field(init=False, eq=False, default=None)
+ _last_fire_date: date | None = attrs.field(init=False, eq=False, default=None)
def __attrs_post_init__(self) -> None:
self._time = time(self.hour, self.minute, self.second, tzinfo=self.timezone)
@@ -78,7 +78,7 @@ class CalendarIntervalTrigger(Trigger):
if self.start_date and self.end_date and self.start_date > self.end_date:
raise ValueError('end_date cannot be earlier than start_date')
- def next(self) -> Optional[datetime]:
+ def next(self) -> datetime | None:
previous_date: date = self._last_fire_date
while True:
if previous_date:
diff --git a/src/apscheduler/triggers/combining.py b/src/apscheduler/triggers/combining.py
index fa0b5c9..bcee64a 100644
--- a/src/apscheduler/triggers/combining.py
+++ b/src/apscheduler/triggers/combining.py
@@ -2,7 +2,7 @@ from __future__ import annotations
from abc import abstractmethod
from datetime import datetime, timedelta
-from typing import Any, Optional
+from typing import Any
import attrs
@@ -15,7 +15,7 @@ from ..validators import as_timedelta, require_state_version
@attrs.define
class BaseCombiningTrigger(Trigger):
triggers: list[Trigger]
- _next_fire_times: list[Optional[datetime]] = attrs.field(init=False, eq=False, factory=list)
+ _next_fire_times: list[datetime | None] = attrs.field(init=False, eq=False, factory=list)
def __getstate__(self) -> dict[str, Any]:
return {
@@ -51,17 +51,17 @@ class AndTrigger(BaseCombiningTrigger):
"""
threshold: timedelta = attrs.field(converter=as_timedelta, default=1)
- max_iterations: Optional[int] = 10000
+ max_iterations: int | None = 10000
- def next(self) -> Optional[datetime]:
+ def next(self) -> datetime | None:
if not self._next_fire_times:
# Fill out the fire times on the first run
self._next_fire_times = [t.next() for t in self.triggers]
for _ in range(self.max_iterations):
# Find the earliest and latest fire times
- earliest_fire_time: Optional[datetime] = None
- latest_fire_time: Optional[datetime] = None
+ earliest_fire_time: datetime | None = None
+ latest_fire_time: datetime | None = None
for fire_time in self._next_fire_times:
# If any of the fire times is None, this trigger is finished
if fire_time is None:
@@ -74,7 +74,7 @@ class AndTrigger(BaseCombiningTrigger):
latest_fire_time = fire_time
# Replace all the fire times that were within the threshold
- for i, trigger in enumerate(self.triggers):
+ for i, _trigger in enumerate(self.triggers):
if self._next_fire_times[i] - earliest_fire_time <= self.threshold:
self._next_fire_times[i] = self.triggers[i].next()
@@ -114,14 +114,14 @@ class OrTrigger(BaseCombiningTrigger):
:param triggers: triggers to combine
"""
- def next(self) -> Optional[datetime]:
+ def next(self) -> datetime | None:
# Fill out the fire times on the first run
if not self._next_fire_times:
self._next_fire_times = [t.next() for t in self.triggers]
# Find out the earliest of the fire times
- earliest_time: Optional[datetime] = min([fire_time for fire_time in self._next_fire_times
- if fire_time is not None], default=None)
+ earliest_time: datetime | None = min((fire_time for fire_time in self._next_fire_times
+ if fire_time is not None), default=None)
if earliest_time is not None:
# Generate new fire times for the trigger(s) that generated the earliest fire time
for i, fire_time in enumerate(self._next_fire_times):
diff --git a/src/apscheduler/triggers/cron/__init__.py b/src/apscheduler/triggers/cron/__init__.py
index 1c1e582..df1f9e5 100644
--- a/src/apscheduler/triggers/cron/__init__.py
+++ b/src/apscheduler/triggers/cron/__init__.py
@@ -1,7 +1,7 @@
from __future__ import annotations
from datetime import datetime, timedelta, tzinfo
-from typing import Any, ClassVar, Optional, Sequence
+from typing import Any, ClassVar, Sequence
import attrs
from tzlocal import get_localzone
@@ -59,12 +59,12 @@ class CronTrigger(Trigger):
end_time: datetime | None = None
timezone: tzinfo | str = attrs.field(converter=as_timezone, factory=get_localzone)
_fields: list[BaseField] = attrs.field(init=False, eq=False, factory=list)
- _last_fire_time: Optional[datetime] = attrs.field(init=False, eq=False, default=None)
+ _last_fire_time: datetime | None = attrs.field(init=False, eq=False, default=None)
def __attrs_post_init__(self) -> None:
self._set_fields([self.year, self.month, self.day, self.week, self.day_of_week, self.hour,
self.minute, self.second])
- self._last_fire_time: Optional[datetime] = None
+ self._last_fire_time: datetime | None = None
def _set_fields(self, values: Sequence[int | str | None]) -> None:
self._fields = []
@@ -80,7 +80,7 @@ class CronTrigger(Trigger):
self._fields.append(field)
@classmethod
- def from_crontab(cls, expr: str, timezone: str | tzinfo = 'local') -> 'CronTrigger':
+ def from_crontab(cls, expr: str, timezone: str | tzinfo = 'local') -> CronTrigger:
"""
Create a :class:`~CronTrigger` from a standard crontab expression.
@@ -153,7 +153,7 @@ class CronTrigger(Trigger):
return datetime(**values, tzinfo=self.timezone)
- def next(self) -> Optional[datetime]:
+ def next(self) -> datetime | None:
if self._last_fire_time:
start_time = self._last_fire_time + timedelta(microseconds=1)
else:
diff --git a/src/apscheduler/triggers/cron/expressions.py b/src/apscheduler/triggers/cron/expressions.py
index e417dea..5c94afa 100644
--- a/src/apscheduler/triggers/cron/expressions.py
+++ b/src/apscheduler/triggers/cron/expressions.py
@@ -4,7 +4,6 @@ from __future__ import annotations
import re
from calendar import monthrange
from datetime import datetime
-from typing import Optional
from ...validators import as_int
@@ -35,7 +34,7 @@ class AllExpression:
raise ValueError(f'the step value ({self.step}) is higher than the total range of the '
f'expression ({value_range})')
- def get_next_value(self, dateval: datetime, field) -> Optional[int]:
+ def get_next_value(self, dateval: datetime, field) -> int | None:
start = field.get_value(dateval)
minval = field.get_min(dateval)
maxval = field.get_max(dateval)
@@ -144,7 +143,7 @@ class WeekdayRangeExpression(RangeExpression):
value_re = re.compile(r'(?P<first>[a-z]+)(?:-(?P<last>[a-z]+))?', re.IGNORECASE)
- def __init__(self, first: str, last: Optional[str] = None):
+ def __init__(self, first: str, last: str | None = None):
first_num = get_weekday_index(first)
last_num = get_weekday_index(last) if last else None
super().__init__(first_num, last_num)
@@ -171,7 +170,7 @@ class WeekdayPositionExpression(AllExpression):
except ValueError:
raise ValueError(f'Invalid weekday name {weekday_name!r}') from None
- def get_next_value(self, dateval: datetime, field) -> Optional[int]:
+ def get_next_value(self, dateval: datetime, field) -> int | None:
# Figure out the weekday of the month's first day and the number of days in that month
first_day_wday, last_day = monthrange(dateval.year, dateval.month)
diff --git a/src/apscheduler/triggers/cron/fields.py b/src/apscheduler/triggers/cron/fields.py
index d15fcd5..e68fdca 100644
--- a/src/apscheduler/triggers/cron/fields.py
+++ b/src/apscheduler/triggers/cron/fields.py
@@ -4,7 +4,7 @@ from __future__ import annotations
import re
from calendar import monthrange
from datetime import datetime
-from typing import Any, ClassVar, List, Optional, Sequence
+from typing import Any, ClassVar, Sequence
from .expressions import (
WEEKDAYS, AllExpression, LastDayOfMonthExpression, MonthRangeExpression, RangeExpression,
@@ -32,7 +32,7 @@ class BaseField:
def __init__(self, name: str, exprs: int | str):
self.name = name
- self.expressions: List = []
+ self.expressions: list = []
for expr in SEPARATOR.split(str(exprs).strip()):
self.append_expression(expr)
@@ -45,7 +45,7 @@ class BaseField:
def get_value(self, dateval: datetime) -> int:
return getattr(dateval, self.name)
- def get_next_value(self, dateval: datetime) -> Optional[int]:
+ def get_next_value(self, dateval: datetime) -> int | None:
smallest = None
for expr in self.expressions:
value = expr.get_next_value(dateval, self)
diff --git a/src/apscheduler/triggers/date.py b/src/apscheduler/triggers/date.py
index 08494c3..173c972 100644
--- a/src/apscheduler/triggers/date.py
+++ b/src/apscheduler/triggers/date.py
@@ -1,7 +1,7 @@
from __future__ import annotations
from datetime import datetime
-from typing import Any, Optional
+from typing import Any
import attrs
@@ -21,7 +21,7 @@ class DateTrigger(Trigger):
run_time: datetime = attrs.field(converter=as_aware_datetime)
_completed: bool = attrs.field(init=False, eq=False, default=False)
- def next(self) -> Optional[datetime]:
+ def next(self) -> datetime | None:
if not self._completed:
self._completed = True
return self.run_time
diff --git a/src/apscheduler/triggers/interval.py b/src/apscheduler/triggers/interval.py
index 0f85d36..629499b 100644
--- a/src/apscheduler/triggers/interval.py
+++ b/src/apscheduler/triggers/interval.py
@@ -1,7 +1,7 @@
from __future__ import annotations
from datetime import datetime, timedelta
-from typing import Any, Optional
+from typing import Any
import attrs
@@ -37,9 +37,9 @@ class IntervalTrigger(Trigger):
seconds: float = 0
microseconds: float = 0
start_time: datetime = attrs.field(converter=as_aware_datetime, factory=datetime.now)
- end_time: Optional[datetime] = attrs.field(converter=as_aware_datetime, default=None)
+ end_time: datetime | None = attrs.field(converter=as_aware_datetime, default=None)
_interval: timedelta = attrs.field(init=False, eq=False, repr=False)
- _last_fire_time: Optional[datetime] = attrs.field(init=False, eq=False, default=None)
+ _last_fire_time: datetime | None = attrs.field(init=False, eq=False, default=None)
def __attrs_post_init__(self) -> None:
self._interval = timedelta(weeks=self.weeks, days=self.days, hours=self.hours,
@@ -52,7 +52,7 @@ class IntervalTrigger(Trigger):
if self.end_time and self.end_time < self.start_time:
raise ValueError('end_time cannot be earlier than start_time')
- def next(self) -> Optional[datetime]:
+ def next(self) -> datetime | None:
if self._last_fire_time is None:
self._last_fire_time = self.start_time
else:
diff --git a/src/apscheduler/validators.py b/src/apscheduler/validators.py
index 179eabd..baa7b50 100644
--- a/src/apscheduler/validators.py
+++ b/src/apscheduler/validators.py
@@ -2,7 +2,7 @@ from __future__ import annotations
import sys
from datetime import date, datetime, timedelta, timezone, tzinfo
-from typing import Any, Optional
+from typing import Any
import attrs
from attrs import Attribute
@@ -17,7 +17,7 @@ else:
from backports.zoneinfo import ZoneInfo
-def as_int(value) -> Optional[int]:
+def as_int(value) -> int | None:
"""Convert the value into an integer."""
if value is None:
return None
@@ -49,7 +49,7 @@ def as_timezone(value: str | tzinfo | None) -> tzinfo:
f'{value.__class__.__qualname__} instead')
-def as_date(value: date | str | None) -> Optional[date]:
+def as_date(value: date | str | None) -> date | None:
"""
Convert the value to a date.
@@ -67,21 +67,21 @@ def as_date(value: date | str | None) -> Optional[date]:
raise TypeError(f'Expected string or date, got {value.__class__.__qualname__} instead')
-def as_timestamp(value: Optional[datetime]) -> Optional[float]:
+def as_timestamp(value: datetime | None) -> float | None:
if value is None:
return None
return value.timestamp()
-def as_ordinal_date(value: Optional[date]) -> Optional[int]:
+def as_ordinal_date(value: date | None) -> int | None:
if value is None:
return None
return value.toordinal()
-def as_aware_datetime(value: datetime | str | None) -> Optional[datetime]:
+def as_aware_datetime(value: datetime | str | None) -> datetime | None:
"""
Convert the value to a timezone aware datetime.
diff --git a/src/apscheduler/workers/async_.py b/src/apscheduler/workers/async_.py
index 50f76a9..c581b0e 100644
--- a/src/apscheduler/workers/async_.py
+++ b/src/apscheduler/workers/async_.py
@@ -6,7 +6,7 @@ from contextlib import AsyncExitStack
from datetime import datetime, timezone
from inspect import isawaitable
from logging import Logger, getLogger
-from typing import Callable, Optional
+from typing import Callable
from uuid import UUID
import anyio
@@ -30,7 +30,7 @@ class AsyncWorker:
data_store: AsyncDataStore = attrs.field(converter=as_async_datastore)
max_concurrent_jobs: int = attrs.field(kw_only=True, validator=positive_integer, default=100)
identity: str = attrs.field(kw_only=True, default=None)
- logger: Optional[Logger] = attrs.field(kw_only=True, default=getLogger(__name__))
+ logger: Logger | None = attrs.field(kw_only=True, default=getLogger(__name__))
_state: RunState = attrs.field(init=False, default=RunState.stopped)
_wakeup_event: anyio.Event = attrs.field(init=False, factory=anyio.Event)
@@ -92,7 +92,7 @@ class AsyncWorker:
task_status.started()
await self._events.publish(WorkerStarted())
- exception: Optional[BaseException] = None
+ exception: BaseException | None = None
try:
async with create_task_group() as tg:
while self._state is RunState.started:
diff --git a/src/apscheduler/workers/sync.py b/src/apscheduler/workers/sync.py
index 69718b5..7a6bee9 100644
--- a/src/apscheduler/workers/sync.py
+++ b/src/apscheduler/workers/sync.py
@@ -8,7 +8,7 @@ from contextlib import ExitStack
from contextvars import copy_context
from datetime import datetime, timezone
from logging import Logger, getLogger
-from typing import Callable, Optional
+from typing import Callable
from uuid import UUID
import attrs
@@ -28,7 +28,7 @@ class Worker:
data_store: DataStore
max_concurrent_jobs: int = attrs.field(kw_only=True, validator=positive_integer, default=20)
identity: str = attrs.field(kw_only=True, default=None)
- logger: Optional[Logger] = attrs.field(kw_only=True, default=getLogger(__name__))
+ logger: Logger | None = attrs.field(kw_only=True, default=getLogger(__name__))
_state: RunState = attrs.field(init=False, default=RunState.stopped)
_wakeup_event: threading.Event = attrs.field(init=False)
@@ -98,7 +98,7 @@ class Worker:
self._events.publish(WorkerStarted())
executor = ThreadPoolExecutor(max_workers=self.max_concurrent_jobs)
- exception: Optional[BaseException] = None
+ exception: BaseException | None = None
try:
while self._state is RunState.started:
available_slots = self.max_concurrent_jobs - len(self._running_jobs)