aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/apscheduler/job.py
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/apscheduler/job.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are hereHEADmaster
Diffstat (limited to '.venv/lib/python3.12/site-packages/apscheduler/job.py')
-rw-r--r--.venv/lib/python3.12/site-packages/apscheduler/job.py330
1 files changed, 330 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/apscheduler/job.py b/.venv/lib/python3.12/site-packages/apscheduler/job.py
new file mode 100644
index 00000000..35e83700
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/apscheduler/job.py
@@ -0,0 +1,330 @@
+from collections.abc import Iterable, Mapping
+from inspect import isclass, ismethod
+from uuid import uuid4
+
+from apscheduler.triggers.base import BaseTrigger
+from apscheduler.util import (
+ check_callable_args,
+ convert_to_datetime,
+ datetime_repr,
+ get_callable_name,
+ obj_to_ref,
+ ref_to_obj,
+)
+
+
+class Job:
+ """
+ Contains the options given when scheduling callables and its current schedule and other state.
+ This class should never be instantiated by the user.
+
+ :var str id: the unique identifier of this job
+ :var str name: the description of this job
+ :var func: the callable to execute
+ :var tuple|list args: positional arguments to the callable
+ :var dict kwargs: keyword arguments to the callable
+ :var bool coalesce: whether to only run the job once when several run times are due
+ :var trigger: the trigger object that controls the schedule of this job
+ :var str executor: the name of the executor that will run this job
+ :var int misfire_grace_time: the time (in seconds) how much this job's execution is allowed to
+ be late (``None`` means "allow the job to run no matter how late it is")
+ :var int max_instances: the maximum number of concurrently executing instances allowed for this
+ job
+ :var datetime.datetime next_run_time: the next scheduled run time of this job
+
+ .. note::
+ The ``misfire_grace_time`` has some non-obvious effects on job execution. See the
+ :ref:`missed-job-executions` section in the documentation for an in-depth explanation.
+ """
+
+ __slots__ = (
+ "_scheduler",
+ "_jobstore_alias",
+ "id",
+ "trigger",
+ "executor",
+ "func",
+ "func_ref",
+ "args",
+ "kwargs",
+ "name",
+ "misfire_grace_time",
+ "coalesce",
+ "max_instances",
+ "next_run_time",
+ "__weakref__",
+ )
+
+ def __init__(self, scheduler, id=None, **kwargs):
+ super().__init__()
+ self._scheduler = scheduler
+ self._jobstore_alias = None
+ self._modify(id=id or uuid4().hex, **kwargs)
+
+ def modify(self, **changes):
+ """
+ Makes the given changes to this job and saves it in the associated job store.
+
+ Accepted keyword arguments are the same as the variables on this class.
+
+ .. seealso:: :meth:`~apscheduler.schedulers.base.BaseScheduler.modify_job`
+
+ :return Job: this job instance
+
+ """
+ self._scheduler.modify_job(self.id, self._jobstore_alias, **changes)
+ return self
+
+ def reschedule(self, trigger, **trigger_args):
+ """
+ Shortcut for switching the trigger on this job.
+
+ .. seealso:: :meth:`~apscheduler.schedulers.base.BaseScheduler.reschedule_job`
+
+ :return Job: this job instance
+
+ """
+ self._scheduler.reschedule_job(
+ self.id, self._jobstore_alias, trigger, **trigger_args
+ )
+ return self
+
+ def pause(self):
+ """
+ Temporarily suspend the execution of this job.
+
+ .. seealso:: :meth:`~apscheduler.schedulers.base.BaseScheduler.pause_job`
+
+ :return Job: this job instance
+
+ """
+ self._scheduler.pause_job(self.id, self._jobstore_alias)
+ return self
+
+ def resume(self):
+ """
+ Resume the schedule of this job if previously paused.
+
+ .. seealso:: :meth:`~apscheduler.schedulers.base.BaseScheduler.resume_job`
+
+ :return Job: this job instance
+
+ """
+ self._scheduler.resume_job(self.id, self._jobstore_alias)
+ return self
+
+ def remove(self):
+ """
+ Unschedules this job and removes it from its associated job store.
+
+ .. seealso:: :meth:`~apscheduler.schedulers.base.BaseScheduler.remove_job`
+
+ """
+ self._scheduler.remove_job(self.id, self._jobstore_alias)
+
+ @property
+ def pending(self):
+ """
+ Returns ``True`` if the referenced job is still waiting to be added to its designated job
+ store.
+
+ """
+ return self._jobstore_alias is None
+
+ #
+ # Private API
+ #
+
+ def _get_run_times(self, now):
+ """
+ Computes the scheduled run times between ``next_run_time`` and ``now`` (inclusive).
+
+ :type now: datetime.datetime
+ :rtype: list[datetime.datetime]
+
+ """
+ run_times = []
+ next_run_time = self.next_run_time
+ while next_run_time and next_run_time <= now:
+ run_times.append(next_run_time)
+ next_run_time = self.trigger.get_next_fire_time(next_run_time, now)
+
+ return run_times
+
+ def _modify(self, **changes):
+ """
+ Validates the changes to the Job and makes the modifications if and only if all of them
+ validate.
+
+ """
+ approved = {}
+
+ if "id" in changes:
+ value = changes.pop("id")
+ if not isinstance(value, str):
+ raise TypeError("id must be a nonempty string")
+ if hasattr(self, "id"):
+ raise ValueError("The job ID may not be changed")
+ approved["id"] = value
+
+ if "func" in changes or "args" in changes or "kwargs" in changes:
+ func = changes.pop("func") if "func" in changes else self.func
+ args = changes.pop("args") if "args" in changes else self.args
+ kwargs = changes.pop("kwargs") if "kwargs" in changes else self.kwargs
+
+ if isinstance(func, str):
+ func_ref = func
+ func = ref_to_obj(func)
+ elif callable(func):
+ try:
+ func_ref = obj_to_ref(func)
+ except ValueError:
+ # If this happens, this Job won't be serializable
+ func_ref = None
+ else:
+ raise TypeError("func must be a callable or a textual reference to one")
+
+ if not hasattr(self, "name") and changes.get("name", None) is None:
+ changes["name"] = get_callable_name(func)
+
+ if isinstance(args, str) or not isinstance(args, Iterable):
+ raise TypeError("args must be a non-string iterable")
+ if isinstance(kwargs, str) or not isinstance(kwargs, Mapping):
+ raise TypeError("kwargs must be a dict-like object")
+
+ check_callable_args(func, args, kwargs)
+
+ approved["func"] = func
+ approved["func_ref"] = func_ref
+ approved["args"] = args
+ approved["kwargs"] = kwargs
+
+ if "name" in changes:
+ value = changes.pop("name")
+ if not value or not isinstance(value, str):
+ raise TypeError("name must be a nonempty string")
+ approved["name"] = value
+
+ if "misfire_grace_time" in changes:
+ value = changes.pop("misfire_grace_time")
+ if value is not None and (not isinstance(value, int) or value <= 0):
+ raise TypeError(
+ "misfire_grace_time must be either None or a positive integer"
+ )
+ approved["misfire_grace_time"] = value
+
+ if "coalesce" in changes:
+ value = bool(changes.pop("coalesce"))
+ approved["coalesce"] = value
+
+ if "max_instances" in changes:
+ value = changes.pop("max_instances")
+ if not isinstance(value, int) or value <= 0:
+ raise TypeError("max_instances must be a positive integer")
+ approved["max_instances"] = value
+
+ if "trigger" in changes:
+ trigger = changes.pop("trigger")
+ if not isinstance(trigger, BaseTrigger):
+ raise TypeError(
+ f"Expected a trigger instance, got {trigger.__class__.__name__} instead"
+ )
+
+ approved["trigger"] = trigger
+
+ if "executor" in changes:
+ value = changes.pop("executor")
+ if not isinstance(value, str):
+ raise TypeError("executor must be a string")
+ approved["executor"] = value
+
+ if "next_run_time" in changes:
+ value = changes.pop("next_run_time")
+ approved["next_run_time"] = convert_to_datetime(
+ value, self._scheduler.timezone, "next_run_time"
+ )
+
+ if changes:
+ raise AttributeError(
+ "The following are not modifiable attributes of Job: {}".format(
+ ", ".join(changes)
+ )
+ )
+
+ for key, value in approved.items():
+ setattr(self, key, value)
+
+ def __getstate__(self):
+ # Don't allow this Job to be serialized if the function reference could not be determined
+ if not self.func_ref:
+ raise ValueError(
+ f"This Job cannot be serialized since the reference to its callable ({self.func!r}) could not "
+ "be determined. Consider giving a textual reference (module:function name) "
+ "instead."
+ )
+
+ # Instance methods cannot survive serialization as-is, so store the "self" argument
+ # explicitly
+ func = self.func
+ if (
+ ismethod(func)
+ and not isclass(func.__self__)
+ and obj_to_ref(func) == self.func_ref
+ ):
+ args = (func.__self__,) + tuple(self.args)
+ else:
+ args = self.args
+
+ return {
+ "version": 1,
+ "id": self.id,
+ "func": self.func_ref,
+ "trigger": self.trigger,
+ "executor": self.executor,
+ "args": args,
+ "kwargs": self.kwargs,
+ "name": self.name,
+ "misfire_grace_time": self.misfire_grace_time,
+ "coalesce": self.coalesce,
+ "max_instances": self.max_instances,
+ "next_run_time": self.next_run_time,
+ }
+
+ def __setstate__(self, state):
+ if state.get("version", 1) > 1:
+ raise ValueError(
+ f"Job has version {state['version']}, but only version 1 can be handled"
+ )
+
+ self.id = state["id"]
+ self.func_ref = state["func"]
+ self.func = ref_to_obj(self.func_ref)
+ self.trigger = state["trigger"]
+ self.executor = state["executor"]
+ self.args = state["args"]
+ self.kwargs = state["kwargs"]
+ self.name = state["name"]
+ self.misfire_grace_time = state["misfire_grace_time"]
+ self.coalesce = state["coalesce"]
+ self.max_instances = state["max_instances"]
+ self.next_run_time = state["next_run_time"]
+
+ def __eq__(self, other):
+ if isinstance(other, Job):
+ return self.id == other.id
+ return NotImplemented
+
+ def __repr__(self):
+ return f"<Job (id={self.id} name={self.name})>"
+
+ def __str__(self):
+ if hasattr(self, "next_run_time"):
+ status = (
+ "next run at: " + datetime_repr(self.next_run_time)
+ if self.next_run_time
+ else "paused"
+ )
+ else:
+ status = "pending"
+
+ return f"{self.name} (trigger: {self.trigger}, {status})"