Example #1
0
 def check_timing_tzinfo(
     job_type: JobType,
     timing: TimingJobUnion,
     tzinfo: Optional[dt.tzinfo],
 ):
     """Raise if `timing` incompatible with `tzinfo` for `job_type`."""
     if job_type is JobType.WEEKLY:
         for weekday in cast(list[Weekday], timing):
             if bool(weekday.time.tzinfo) ^ bool(tzinfo):
                 raise SchedulerError(TZ_ERROR_MSG)
     elif job_type in (JobType.MINUTELY, JobType.HOURLY, JobType.DAILY):
         for time in cast(list[dt.time], timing):
             if bool(time.tzinfo) ^ bool(tzinfo):
                 raise SchedulerError(TZ_ERROR_MSG)
Example #2
0
    def sane_timing_types(job_type: JobType, timing: TimingJobUnion) -> None:
        """
        Determine if the `JobType` is fulfilled by the type of the specified `timing`.

        Parameters
        ----------
        job_type : JobType
            :class:`~scheduler.job.JobType` to test agains.
        timing : TimingJobUnion
            The `timing` object to be tested.

        Raises
        ------
        TypeError
            If the `timing` object has the wrong `Type` for a specific `JobType`.
        """
        try:
            tg.check_type("timing", timing,
                          JOB_TIMING_TYPE_MAPPING[job_type]["type"])
            if job_type == JobType.CYCLIC:
                if not len(timing) == 1:
                    raise TypeError
        except TypeError as err:
            raise SchedulerError(
                JOB_TIMING_TYPE_MAPPING[job_type]["err"]) from err
Example #3
0
    def once(
        self,
        timing: TimingOnceUnion,
        handle: Callable[..., None],
        args: tuple[Any] = None,
        kwargs: Optional[dict[str, Any]] = None,
        tags: Optional[list[str]] = None,
        weight: float = 1,
    ):
        r"""
        Schedule a oneshot `Job`.

        Parameters
        ----------
        timing : TimingOnceUnion
            Desired execution time.
        handle : Callable[..., None]
            Handle to a callback function.
        args : tuple[Any]
            Positional argument payload for the function handle within a |Job|.
        kwargs : Optional[dict[str, Any]]
            Keyword arguments payload for the function handle within a |Job|.
        tags : Optional[set[str]]
            The tags of the |Job|.
        weight : float
            Relative weight against other |Job|\ s.

        Returns
        -------
        Job
            Instance of a scheduled |Job|.
        """
        try:
            tg.check_type("timing", timing, TimingOnceUnion)
        except TypeError as err:
            raise SchedulerError(ONCE_TYPE_ERROR_MSG) from err
        if isinstance(timing, dt.datetime):
            return self.__schedule(
                job_type=JobType.CYCLIC,
                timing=dt.timedelta(),
                handle=handle,
                args=args,
                kwargs=kwargs,
                max_attempts=1,
                tags=tags,
                weight=weight,
                delay=False,
                start=timing,
            )
        return self.__schedule(
            job_type=JOB_TYPE_MAPPING[type(timing)],
            timing=timing,
            handle=handle,
            args=args,
            kwargs=kwargs,
            max_attempts=1,
            tags=tags,
            weight=weight,
        )
Example #4
0
 def check_duplicate_effective_timings(
     job_type: JobType,
     timing: TimingJobUnion,
     tzinfo: Optional[dt.tzinfo],
 ):
     """Raise given timings are not effectively duplicates."""
     if job_type is JobType.WEEKLY:
         if not are_weekday_times_unique(cast(list[Weekday], timing),
                                         tzinfo):
             raise SchedulerError(DUPLICATE_EFFECTIVE_TIME)
     elif job_type in (
             JobType.MINUTELY,
             JobType.HOURLY,
             JobType.DAILY,
     ):
         if not are_times_unique(cast(list[dt.time], timing)):
             raise SchedulerError(DUPLICATE_EFFECTIVE_TIME)
Example #5
0
    def set_start_check_stop_tzinfo(
        start: Optional[dt.datetime],
        stop: Optional[dt.datetime],
        tzinfo: Optional[dt.tzinfo],
    ) -> dt.datetime:
        """Raise if `start`, `stop` and `tzinfo` incompatible; Make start."""
        if start:
            if bool(start.tzinfo) ^ bool(tzinfo):
                raise SchedulerError(_TZ_ERROR_MSG.format("start"))
        else:
            start = dt.datetime.now(tzinfo)

        if stop:
            if bool(stop.tzinfo) ^ bool(tzinfo):
                raise SchedulerError(_TZ_ERROR_MSG.format("stop"))

        if stop is not None:
            if start >= stop:
                raise SchedulerError(START_STOP_ERROR)
        return start
Example #6
0
    def hourly(self, timing: TimingDailyUnion, handle: Callable[..., None],
               **kwargs):
        r"""
        Schedule an hourly `Job`.

        Use a `datetime.time` object or a `list` of `datetime.time` objects
        to schedule a |Job| every hour.

        Notes
        -----
        If given a `datetime.time` object with a non zero hour property, this information
        will be ignored.

        Parameters
        ----------
        timing : TimingDailyUnion
            Desired execution time(s).
        handle : Callable[..., None]
            Handle to a callback function.

        Returns
        -------
        Job
            Instance of a scheduled |Job|.

        Other Parameters
        ----------------
        **kwargs
            |Job| properties, optional

            `kwargs` are used to specify |Job| properties.

            Here is a list of available |Job| properties:

            .. include:: ../_assets/kwargs.rst
        """
        try:
            tg.check_type("timing", timing, TimingDailyUnion)
        except TypeError as err:
            raise SchedulerError(HOURLY_TYPE_ERROR_MSG) from err
        return self.__schedule(job_type=JobType.HOURLY,
                               timing=timing,
                               handle=handle,
                               **kwargs)
Example #7
0
    def weekly(self, timing: TimingWeeklyUnion, handle: Callable[..., None],
               **kwargs):
        r"""
        Schedule a weekly `Job`.

        Use a `tuple` of a `Weekday` and a `datetime.time` object to define a weekly
        recuring |Job|. Combine multiple desired `tuples` in
        a `list`. If the planed execution time is `00:00` the `datetime.time` object
        can be ingored, just pass a `Weekday` without a `tuple`.

        Parameters
        ----------
        timing : TimingWeeklyUnion
            Desired execution time(s).
        handle : Callable[..., None]
            Handle to a callback function.

        Returns
        -------
        Job
            Instance of a scheduled |Job|.

        Other Parameters
        ----------------
        **kwargs
            |Job| properties, optional

            `kwargs` are used to specify |Job| properties.

            Here is a list of available |Job| properties:

            .. include:: ../_assets/kwargs.rst
        """
        try:
            tg.check_type("timing", timing, TimingWeeklyUnion)
        except TypeError as err:
            raise SchedulerError(WEEKLY_TYPE_ERROR_MSG) from err
        return self.__schedule(job_type=JobType.WEEKLY,
                               timing=timing,
                               handle=handle,
                               **kwargs)
Example #8
0
    def cyclic(self, timing: TimingCyclic, handle: Callable[..., None],
               **kwargs):
        r"""
        Schedule a cyclic `Job`.

        Use a `datetime.timedelta` object or a `list` of `datetime.timedelta` objects
        to schedule a cyclic |Job|.

        Parameters
        ----------
        timing : TimingTypeCyclic
            Desired execution time.
        handle : Callable[..., None]
            Handle to a callback function.

        Returns
        -------
        Job
            Instance of a scheduled |Job|.

        Other Parameters
        ----------------
        **kwargs
            |Job| properties, optional

            `kwargs` are used to specify |Job| properties.

            Here is a list of available |Job| properties:

            .. include:: ../_assets/kwargs.rst
        """
        try:
            tg.check_type("timing", timing, TimingCyclic)
        except TypeError as err:
            raise SchedulerError(CYCLIC_TYPE_ERROR_MSG) from err
        return self.__schedule(job_type=JobType.CYCLIC,
                               timing=timing,
                               handle=handle,
                               **kwargs)
Example #9
0
    def __init__(
        self,
        max_exec: int = 0,
        tzinfo: Optional[dt.tzinfo] = None,
        priority_function: Callable[
            [float, AbstractJob, int, int],
            float, ] = Prioritization.linear_priority_function,
        jobs: Optional[set[Job]] = None,
        n_threads: int = 1,
    ):
        self.__lock = threading.RLock()
        self.__max_exec = max_exec
        self.__tzinfo = tzinfo
        self.__priority_function = priority_function
        self.__jobs_lock = threading.RLock()
        self.__jobs: set[Job] = jobs or set()
        for job in self.__jobs:
            if job._tzinfo != self.__tzinfo:
                raise SchedulerError(TZ_ERROR_MSG)

        self.__n_threads = n_threads
        self.__tz_str = dt.datetime.now(tzinfo).tzname()