From da12c07494b3b982741eed8852145c185966c776 Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Wed, 26 Feb 2025 18:43:56 +0100 Subject: [PATCH 1/3] Update croniter to 6.0.0 Make class `croniter` generic over `ret_type` and tighten return types for some methods. --- stubs/croniter/METADATA.toml | 2 +- stubs/croniter/croniter/__init__.pyi | 11 ++ stubs/croniter/croniter/croniter.pyi | 217 +++++++++++++++++++++------ 3 files changed, 186 insertions(+), 44 deletions(-) diff --git a/stubs/croniter/METADATA.toml b/stubs/croniter/METADATA.toml index 238b0e38b807..997f1dd88a30 100644 --- a/stubs/croniter/METADATA.toml +++ b/stubs/croniter/METADATA.toml @@ -1,2 +1,2 @@ -version = "5.0.1" +version = "6.0.0" upstream_repository = "https://github.com/kiorky/croniter" diff --git a/stubs/croniter/croniter/__init__.pyi b/stubs/croniter/croniter/__init__.pyi index f9bdbea7d109..97fa561af5c4 100644 --- a/stubs/croniter/croniter/__init__.pyi +++ b/stubs/croniter/croniter/__init__.pyi @@ -1,11 +1,22 @@ +from . import croniter as croniter_m from .croniter import ( + DAY_FIELD as DAY_FIELD, + HOUR_FIELD as HOUR_FIELD, + MINUTE_FIELD as MINUTE_FIELD, + MONTH_FIELD as MONTH_FIELD, OVERFLOW32B_MODE as OVERFLOW32B_MODE, + SECOND_FIELD as SECOND_FIELD, + UTC_DT as UTC_DT, + YEAR_FIELD as YEAR_FIELD, CroniterBadCronError as CroniterBadCronError, CroniterBadDateError as CroniterBadDateError, CroniterBadTypeRangeError as CroniterBadTypeRangeError, + CroniterError as CroniterError, CroniterNotAlphaError as CroniterNotAlphaError, CroniterUnsupportedSyntaxError as CroniterUnsupportedSyntaxError, croniter as croniter, croniter_range as croniter_range, datetime_to_timestamp as datetime_to_timestamp, ) + +cron_m = croniter_m diff --git a/stubs/croniter/croniter/croniter.pyi b/stubs/croniter/croniter/croniter.pyi index e92a633debeb..94fcd641b524 100644 --- a/stubs/croniter/croniter/croniter.pyi +++ b/stubs/croniter/croniter/croniter.pyi @@ -1,22 +1,53 @@ import datetime from _typeshed import Unused from collections import OrderedDict -from collections.abc import Iterator +from collections.abc import Generator from re import Match, Pattern -from typing import Any, Final, Literal, overload +from typing import Any, Final, Generic, Literal, Protocol, TypeVar, overload from typing_extensions import Never, Self, TypeAlias +_R_co = TypeVar("_R_co", float, datetime.datetime, default=float, covariant=True) +_R2_co = TypeVar("_R2_co", float, datetime.datetime, covariant=True) _RetType: TypeAlias = type[float | datetime.datetime] _Expressions: TypeAlias = list[str] # fixed-length list of 5 or 6 strings +class _AllIter(Protocol[_R_co]): + @overload + def __call__( + self, + ret_type: type[_R2_co], + start_time: float | datetime.datetime | None = None, + update_current: bool | None = None, + ) -> Generator[_R2_co]: ... + @overload + def __call__( + self, + ret_type: None = None, + start_time: float | datetime.datetime | None = None, + update_current: bool | None = None, + ) -> Generator[_R_co]: ... + def is_32bit() -> bool: ... OVERFLOW32B_MODE: Final[bool] +UTC_DT: Final[datetime.timezone] EPOCH: Final[datetime.datetime] M_ALPHAS: Final[dict[str, int]] DOW_ALPHAS: Final[dict[str, int]] -ALPHAS: Final[dict[str, int]] + +MINUTE_FIELD: Final = 0 +HOUR_FIELD: Final = 1 +DAY_FIELD: Final = 2 +MONTH_FIELD: Final = 3 +DOW_FIELD: Final = 4 +SECOND_FIELD: Final = 5 +YEAR_FIELD: Final = 6 + +UNIX_FIELDS: Final[tuple[int, int, int, int, int]] +SECOND_FIELDS: Final[tuple[int, int, int, int, int, int]] +YEAR_FIELDS: Final[tuple[int, int, int, int, int, int, int]] + step_search_re: Final[Pattern[str]] only_int_re: Final[Pattern[str]] @@ -26,26 +57,18 @@ star_or_int_re: Final[Pattern[str]] special_dow_re: Final[Pattern[str]] re_star: Final[Pattern[str]] hash_expression_re: Final[Pattern[str]] -MINUTE_FIELD: Final = 0 -HOUR_FIELD: Final = 1 -DAY_FIELD: Final = 2 -MONTH_FIELD: Final = 3 -DOW_FIELD: Final = 4 -SECOND_FIELD: Final = 5 + +CRON_FIELDS: Final[dict[str | int, tuple[int, ...]]] UNIX_CRON_LEN: Final = 5 -YEAR_FIELD: Final = 6 SECOND_CRON_LEN: Final = 6 YEAR_CRON_LEN: Final = 7 -SECOND_FIELDS: Final[tuple[int, int, int, int, int, int]] -UNIX_FIELDS: Final[tuple[int, int, int, int, int]] -YEAR_FIELDS: Final[tuple[int, int, int, int, int, int, int]] -CRON_FIELDS: Final[dict[str | int, tuple[int, ...]]] VALID_LEN_EXPRESSION: Final[set[int]] +TIMESTAMP_TO_DT_CACHE: Final[dict[tuple[float, str], datetime.datetime]] EXPRESSIONS: dict[tuple[str, bytes], _Expressions] - -UTC_DT: Final[datetime.timezone] +MARKER: object def timedelta_to_seconds(td: datetime.timedelta) -> float: ... +def datetime_to_timestamp(d: datetime.datetime) -> float: ... class CroniterError(ValueError): ... class CroniterBadTypeRangeError(TypeError): ... @@ -54,9 +77,7 @@ class CroniterUnsupportedSyntaxError(CroniterBadCronError): ... class CroniterBadDateError(CroniterError): ... class CroniterNotAlphaError(CroniterError): ... -def datetime_to_timestamp(d: datetime.datetime) -> float: ... - -class croniter(Iterator[Any]): +class croniter(Generic[_R_co]): MONTHS_IN_YEAR: Final = 12 RANGES: Final[ tuple[ @@ -102,8 +123,8 @@ class croniter(Iterator[Any]): ] ] LEN_MEANS_ALL: Final[tuple[int, int, int, int, int, int, int]] - bad_length: Final[str] + second_at_beginning: bool tzinfo: datetime.tzinfo | None # Initialized to None, but immediately set to a float. @@ -113,13 +134,56 @@ class croniter(Iterator[Any]): expanded: list[list[str]] nth_weekday_of_month: dict[str, set[int]] + fields: tuple[int, ...] expressions: _Expressions + @overload + def __new__( + cls, + expr_format: str, + start_time: float | datetime.datetime | None = None, + ret_type: type[float] = ..., + day_or: bool = True, + max_years_between_matches: int | None = None, + is_prev: bool = False, + hash_id: str | bytes | None = None, + implement_cron_bug: bool = False, + second_at_beginning: bool | None = None, + expand_from_start_time: bool = False, + ) -> croniter[float]: ... + @overload + def __new__( + cls, + expr_format: str, + start_time: float | datetime.datetime | None, + ret_type: type[datetime.datetime], + day_or: bool = True, + max_years_between_matches: int | None = None, + is_prev: bool = False, + hash_id: str | bytes | None = None, + implement_cron_bug: bool = False, + second_at_beginning: bool | None = None, + expand_from_start_time: bool = False, + ) -> croniter[datetime.datetime]: ... + @overload + def __new__( + cls, + expr_format: str, + *, + ret_type: type[datetime.datetime], + day_or: bool = True, + max_years_between_matches: int | None = None, + is_prev: bool = False, + hash_id: str | bytes | None = None, + implement_cron_bug: bool = False, + second_at_beginning: bool | None = None, + expand_from_start_time: bool = False, + ) -> croniter[datetime.datetime]: ... def __init__( self, expr_format: str, start_time: float | datetime.datetime | None = None, - ret_type: _RetType | None = ..., + ret_type: type[_R_co] = ..., day_or: bool = True, max_years_between_matches: int | None = None, is_prev: bool = False, @@ -128,44 +192,86 @@ class croniter(Iterator[Any]): second_at_beginning: bool | None = None, expand_from_start_time: bool = False, ) -> None: ... - # Most return value depend on ret_type, which can be passed in both as a method argument and as - # a constructor argument. + @overload + def get_next( + self, ret_type: type[_R2_co], start_time: float | datetime.datetime | None = None, update_current: bool = True + ) -> _R_co: ... + @overload def get_next( - self, ret_type: _RetType | None = None, start_time: float | datetime.datetime | None = None, update_current: bool = True - ) -> Any: ... + self, ret_type: None = None, start_time: float | datetime.datetime | None = None, update_current: bool = True + ) -> _R_co: ... + @overload + def get_prev( + self, ret_type: type[_R2_co], start_time: float | datetime.datetime | None = None, update_current: bool = True + ) -> _R2_co: ... + @overload def get_prev( - self, ret_type: _RetType | None = None, start_time: float | datetime.datetime | None = None, update_current: bool = True - ) -> Any: ... - def get_current(self, ret_type: _RetType | None = None) -> Any: ... + self, ret_type: None = None, start_time: float | datetime.datetime | None = None, update_current: bool = True + ) -> _R_co: ... + @overload + def get_current(self, ret_type: type[_R2_co]) -> _R2_co: ... + @overload + def get_current(self, ret_type: None = None) -> _R_co: ... def set_current(self, start_time: float | datetime.datetime | None, force: bool = True) -> float: ... - def __iter__(self) -> Self: ... - def next( + @staticmethod + def datetime_to_timestamp(d: datetime.datetime) -> float: ... + def timestamp_to_datetime(self, timestamp: float, tzinfo: datetime.tzinfo | None = ...) -> datetime.datetime: ... + @staticmethod + def timedelta_to_seconds(td: datetime.timedelta) -> float: ... + @overload + def all_next( self, - ret_type: _RetType | None = None, + ret_type: type[_R2_co], start_time: float | datetime.datetime | None = None, - is_prev: bool | None = None, update_current: bool | None = None, - ) -> Any: ... - __next__ = next + ) -> Generator[_R2_co]: ... + @overload def all_next( self, - ret_type: _RetType | None = None, + ret_type: None = None, start_time: float | datetime.datetime | None = None, update_current: bool | None = None, - ) -> Iterator[Any]: ... + ) -> Generator[_R_co]: ... + @overload + def all_prev( + self, + ret_type: type[_R2_co], + start_time: float | datetime.datetime | None = None, + update_current: bool | None = None, + ) -> Generator[_R2_co]: ... + @overload def all_prev( self, - ret_type: _RetType | None = None, + ret_type: None = None, start_time: float | datetime.datetime | None = None, update_current: bool | None = None, - ) -> Iterator[Any]: ... - def iter(self, ret_type: _RetType | None = ...) -> Iterator[Any]: ... - def is_leap(self, year: int) -> bool: ... + ) -> Generator[_R_co]: ... + def iter(self, *args: Unused, **kwargs: Unused) -> _AllIter[_R_co]: ... + def __iter__(self) -> Self: ... + @overload + def next( + self, + ret_type: type[_R2_co], + start_time: float | datetime.datetime | None = None, + is_prev: bool | None = None, + update_current: bool | None = None, + ) -> _R2_co: ... + @overload + def next( + self, + ret_type: None = None, + start_time: float | datetime.datetime | None = None, + is_prev: bool | None = None, + update_current: bool | None = None, + ) -> _R_co: ... + __next__ = next + @staticmethod + def is_leap(year: int) -> bool: ... @classmethod def value_alias( cls, val: int, - field: Literal[0, 1, 2, 3, 4, 5, 6], + field_index: Literal[0, 1, 2, 3, 4, 5, 6], len_expressions: int | list[Any] | dict[Any, Any] | tuple[Any, ...] | set[Any] = 5, ) -> int: ... @classmethod @@ -198,17 +304,42 @@ class croniter(Iterator[Any]): second_at_beginning: bool = False, ) -> bool: ... +@overload def croniter_range( start: float | datetime.datetime, stop: float | datetime.datetime, expr_format: str, - ret_type: _RetType | None = None, + ret_type: type[_R2_co], + day_or: bool = True, + exclude_ends: bool = False, + _croniter: type[croniter] | None = None, + second_at_beginning: bool = False, + expand_from_start_time: bool = False, +) -> Generator[_R2_co, None, None]: ... +@overload +def croniter_range( + start: float, + stop: float | datetime.datetime, + expr_format: str, + ret_type: None = None, + day_or: bool = True, + exclude_ends: bool = False, + _croniter: type[croniter] | None = None, + second_at_beginning: bool = False, + expand_from_start_time: bool = False, +) -> Generator[float, None, None]: ... +@overload +def croniter_range( + start: datetime.datetime, + stop: float | datetime.datetime, + expr_format: str, + ret_type: None = None, day_or: bool = True, exclude_ends: bool = False, _croniter: type[croniter] | None = None, second_at_beginning: bool = False, expand_from_start_time: bool = False, -) -> Iterator[Any]: ... +) -> Generator[datetime.datetime, None, None]: ... class HashExpander: cron: croniter From 7bb60b12570c8fff0f1adc538a020c3388a2f495 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 26 Feb 2025 17:46:08 +0000 Subject: [PATCH 2/3] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stubs/croniter/croniter/croniter.pyi | 30 ++++++---------------------- 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/stubs/croniter/croniter/croniter.pyi b/stubs/croniter/croniter/croniter.pyi index 94fcd641b524..f2c579c370d3 100644 --- a/stubs/croniter/croniter/croniter.pyi +++ b/stubs/croniter/croniter/croniter.pyi @@ -14,17 +14,11 @@ _Expressions: TypeAlias = list[str] # fixed-length list of 5 or 6 strings class _AllIter(Protocol[_R_co]): @overload def __call__( - self, - ret_type: type[_R2_co], - start_time: float | datetime.datetime | None = None, - update_current: bool | None = None, + self, ret_type: type[_R2_co], start_time: float | datetime.datetime | None = None, update_current: bool | None = None ) -> Generator[_R2_co]: ... @overload def __call__( - self, - ret_type: None = None, - start_time: float | datetime.datetime | None = None, - update_current: bool | None = None, + self, ret_type: None = None, start_time: float | datetime.datetime | None = None, update_current: bool | None = None ) -> Generator[_R_co]: ... def is_32bit() -> bool: ... @@ -220,31 +214,19 @@ class croniter(Generic[_R_co]): def timedelta_to_seconds(td: datetime.timedelta) -> float: ... @overload def all_next( - self, - ret_type: type[_R2_co], - start_time: float | datetime.datetime | None = None, - update_current: bool | None = None, + self, ret_type: type[_R2_co], start_time: float | datetime.datetime | None = None, update_current: bool | None = None ) -> Generator[_R2_co]: ... @overload def all_next( - self, - ret_type: None = None, - start_time: float | datetime.datetime | None = None, - update_current: bool | None = None, + self, ret_type: None = None, start_time: float | datetime.datetime | None = None, update_current: bool | None = None ) -> Generator[_R_co]: ... @overload def all_prev( - self, - ret_type: type[_R2_co], - start_time: float | datetime.datetime | None = None, - update_current: bool | None = None, + self, ret_type: type[_R2_co], start_time: float | datetime.datetime | None = None, update_current: bool | None = None ) -> Generator[_R2_co]: ... @overload def all_prev( - self, - ret_type: None = None, - start_time: float | datetime.datetime | None = None, - update_current: bool | None = None, + self, ret_type: None = None, start_time: float | datetime.datetime | None = None, update_current: bool | None = None ) -> Generator[_R_co]: ... def iter(self, *args: Unused, **kwargs: Unused) -> _AllIter[_R_co]: ... def __iter__(self) -> Self: ... From 21288975e4fd95e8c35828dbebd55cab1dae7ff4 Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Wed, 26 Feb 2025 18:50:48 +0100 Subject: [PATCH 3/3] Remove _RetType --- stubs/croniter/croniter/croniter.pyi | 1 - 1 file changed, 1 deletion(-) diff --git a/stubs/croniter/croniter/croniter.pyi b/stubs/croniter/croniter/croniter.pyi index f2c579c370d3..9d9dfe102bd2 100644 --- a/stubs/croniter/croniter/croniter.pyi +++ b/stubs/croniter/croniter/croniter.pyi @@ -8,7 +8,6 @@ from typing_extensions import Never, Self, TypeAlias _R_co = TypeVar("_R_co", float, datetime.datetime, default=float, covariant=True) _R2_co = TypeVar("_R2_co", float, datetime.datetime, covariant=True) -_RetType: TypeAlias = type[float | datetime.datetime] _Expressions: TypeAlias = list[str] # fixed-length list of 5 or 6 strings class _AllIter(Protocol[_R_co]):