Skip to content

Update croniter to 6.0.0 #13548

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion stubs/croniter/METADATA.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version = "5.0.1"
version = "6.0.0"
upstream_repository = "https://github.com/pallets-eco/croniter"
11 changes: 11 additions & 0 deletions stubs/croniter/croniter/__init__.pyi
Original file line number Diff line number Diff line change
@@ -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
204 changes: 158 additions & 46 deletions stubs/croniter/croniter/croniter.pyi
Original file line number Diff line number Diff line change
@@ -1,22 +1,46 @@
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

_RetType: TypeAlias = type[float | datetime.datetime]
_R_co = TypeVar("_R_co", float, datetime.datetime, default=float, covariant=True)
_R2_co = TypeVar("_R2_co", float, datetime.datetime, covariant=True)
_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]]

Expand All @@ -26,26 +50,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): ...
Expand All @@ -54,9 +70,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[
Expand Down Expand Up @@ -102,8 +116,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.
Expand All @@ -113,13 +127,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,
Expand All @@ -128,44 +185,74 @@ 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: ...
@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: 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
) -> 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: 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: ...
@overload
def 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
def all_next(
self,
ret_type: _RetType | None = None,
start_time: float | datetime.datetime | None = None,
update_current: bool | None = None,
) -> Iterator[Any]: ...
def all_prev(
) -> _R2_co: ...
@overload
def next(
self,
ret_type: _RetType | None = None,
ret_type: None = None,
start_time: float | datetime.datetime | None = None,
is_prev: bool | 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: ...
) -> _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
Expand Down Expand Up @@ -198,17 +285,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
Expand Down