From 92c65142998d9c01edf5fd344427f6bcda74d1d3 Mon Sep 17 00:00:00 2001 From: donBarbos Date: Sun, 22 Jun 2025 23:00:49 +0400 Subject: [PATCH 1/4] [python-dateutil] Add missing stubs * Fix and improve few stubs --- .../@tests/stubtest_allowlist.txt | 2 - .../@tests/stubtest_allowlist_darwin.txt | 3 + .../@tests/stubtest_allowlist_linux.txt | 3 + stubs/python-dateutil/METADATA.toml | 4 - stubs/python-dateutil/dateutil/__init__.pyi | 5 + stubs/python-dateutil/dateutil/_version.pyi | 6 + stubs/python-dateutil/dateutil/easter.pyi | 10 +- .../dateutil/parser/__init__.pyi | 76 ++-------- .../dateutil/parser/_parser.pyi | 134 ++++++++++++++++++ .../dateutil/parser/isoparser.pyi | 2 + .../dateutil/relativedelta.pyi | 2 + stubs/python-dateutil/dateutil/rrule.pyi | 127 ++++++++++++----- .../python-dateutil/dateutil/tz/__init__.pyi | 30 ++++ stubs/python-dateutil/dateutil/tz/_common.pyi | 4 + stubs/python-dateutil/dateutil/tz/tz.pyi | 78 ++++++---- stubs/python-dateutil/dateutil/tz/win.pyi | 46 ++++++ stubs/python-dateutil/dateutil/tzwin.pyi | 4 + stubs/python-dateutil/dateutil/utils.pyi | 6 +- .../dateutil/zoneinfo/__init__.pyi | 41 +++++- .../dateutil/zoneinfo/rebuild.pyi | 7 +- 20 files changed, 436 insertions(+), 154 deletions(-) create mode 100644 stubs/python-dateutil/@tests/stubtest_allowlist_darwin.txt create mode 100644 stubs/python-dateutil/@tests/stubtest_allowlist_linux.txt create mode 100644 stubs/python-dateutil/dateutil/_version.pyi create mode 100644 stubs/python-dateutil/dateutil/parser/_parser.pyi create mode 100644 stubs/python-dateutil/dateutil/tz/win.pyi create mode 100644 stubs/python-dateutil/dateutil/tzwin.pyi diff --git a/stubs/python-dateutil/@tests/stubtest_allowlist.txt b/stubs/python-dateutil/@tests/stubtest_allowlist.txt index 852c593a1288..a0c201aa1cac 100644 --- a/stubs/python-dateutil/@tests/stubtest_allowlist.txt +++ b/stubs/python-dateutil/@tests/stubtest_allowlist.txt @@ -1,5 +1,3 @@ -dateutil.parser._tzparser.__init__ -dateutil.parser.parserinfo.convertyear dateutil.rrule.weekday.__init__ dateutil.tz.tz.tzoffset.instance dateutil.tz.tz.tzstr.instance diff --git a/stubs/python-dateutil/@tests/stubtest_allowlist_darwin.txt b/stubs/python-dateutil/@tests/stubtest_allowlist_darwin.txt new file mode 100644 index 000000000000..b667fc149971 --- /dev/null +++ b/stubs/python-dateutil/@tests/stubtest_allowlist_darwin.txt @@ -0,0 +1,3 @@ +# Cannot import these Windows packages at stubtest runtime: +dateutil.tzwin +dateutil.tz.win diff --git a/stubs/python-dateutil/@tests/stubtest_allowlist_linux.txt b/stubs/python-dateutil/@tests/stubtest_allowlist_linux.txt new file mode 100644 index 000000000000..b667fc149971 --- /dev/null +++ b/stubs/python-dateutil/@tests/stubtest_allowlist_linux.txt @@ -0,0 +1,3 @@ +# Cannot import these Windows packages at stubtest runtime: +dateutil.tzwin +dateutil.tz.win diff --git a/stubs/python-dateutil/METADATA.toml b/stubs/python-dateutil/METADATA.toml index 5f2be1e4ef5b..9aa35b672cc2 100644 --- a/stubs/python-dateutil/METADATA.toml +++ b/stubs/python-dateutil/METADATA.toml @@ -1,6 +1,2 @@ version = "2.9.*" upstream_repository = "https://github.com/dateutil/dateutil" -partial_stub = true - -[tool.stubtest] -ignore_missing_stub = true diff --git a/stubs/python-dateutil/dateutil/__init__.pyi b/stubs/python-dateutil/dateutil/__init__.pyi index e69de29bb2d1..9fb5d4b1fe59 100644 --- a/stubs/python-dateutil/dateutil/__init__.pyi +++ b/stubs/python-dateutil/dateutil/__init__.pyi @@ -0,0 +1,5 @@ +from dateutil import easter, parser, relativedelta, rrule, tz, utils, zoneinfo + +__all__ = ["easter", "parser", "relativedelta", "rrule", "tz", "utils", "zoneinfo"] + +def __dir__() -> list[str]: ... diff --git a/stubs/python-dateutil/dateutil/_version.pyi b/stubs/python-dateutil/dateutil/_version.pyi new file mode 100644 index 000000000000..840633ef6e91 --- /dev/null +++ b/stubs/python-dateutil/dateutil/_version.pyi @@ -0,0 +1,6 @@ +from typing import Final + +__version__: Final[str] +version: Final[str] +__version_tuple__: Final[tuple[int, int, int]] +version_tuple: Final[tuple[int, int, int]] diff --git a/stubs/python-dateutil/dateutil/easter.pyi b/stubs/python-dateutil/dateutil/easter.pyi index 952d119142e5..695faa222541 100644 --- a/stubs/python-dateutil/dateutil/easter.pyi +++ b/stubs/python-dateutil/dateutil/easter.pyi @@ -1,8 +1,10 @@ from datetime import date -from typing import Literal +from typing import Final, Literal -EASTER_JULIAN: Literal[1] -EASTER_ORTHODOX: Literal[2] -EASTER_WESTERN: Literal[3] +__all__ = ["easter", "EASTER_JULIAN", "EASTER_ORTHODOX", "EASTER_WESTERN"] + +EASTER_JULIAN: Final = 1 +EASTER_ORTHODOX: Final = 2 +EASTER_WESTERN: Final = 3 def easter(year: int, method: Literal[1, 2, 3] = 3) -> date: ... diff --git a/stubs/python-dateutil/dateutil/parser/__init__.pyi b/stubs/python-dateutil/dateutil/parser/__init__.pyi index 68f96ff238b8..1041c050d7a7 100644 --- a/stubs/python-dateutil/dateutil/parser/__init__.pyi +++ b/stubs/python-dateutil/dateutil/parser/__init__.pyi @@ -1,68 +1,12 @@ -from collections.abc import Callable, Mapping -from datetime import datetime, tzinfo -from typing import IO, Any -from typing_extensions import TypeAlias - +from ._parser import ( + DEFAULTPARSER as DEFAULTPARSER, + DEFAULTTZPARSER as DEFAULTTZPARSER, + ParserError as ParserError, + UnknownTimezoneWarning as UnknownTimezoneWarning, + parse as parse, + parser as parser, + parserinfo as parserinfo, +) from .isoparser import isoparse as isoparse, isoparser as isoparser -_FileOrStr: TypeAlias = bytes | str | IO[str] | IO[Any] -_TzData: TypeAlias = tzinfo | int | str | None -_TzInfo: TypeAlias = Mapping[str, _TzData] | Callable[[str, int], _TzData] - -class parserinfo: - JUMP: list[str] - WEEKDAYS: list[tuple[str, ...]] - MONTHS: list[tuple[str, ...]] - HMS: list[tuple[str, str, str]] - AMPM: list[tuple[str, str]] - UTCZONE: list[str] - PERTAIN: list[str] - TZOFFSET: dict[str, int] - def __init__(self, dayfirst: bool = False, yearfirst: bool = False) -> None: ... - def jump(self, name: str) -> bool: ... - def weekday(self, name: str) -> int | None: ... - def month(self, name: str) -> int | None: ... - def hms(self, name: str) -> int | None: ... - def ampm(self, name: str) -> int | None: ... - def pertain(self, name: str) -> bool: ... - def utczone(self, name: str) -> bool: ... - def tzoffset(self, name: str) -> int | None: ... - def convertyear(self, year: int) -> int: ... - def validate(self, res: datetime) -> bool: ... - -class parser: - def __init__(self, info: parserinfo | None = None) -> None: ... - def parse( - self, - timestr: _FileOrStr, - default: datetime | None = None, - ignoretz: bool = False, - tzinfos: _TzInfo | None = None, - *, - dayfirst: bool | None = ..., - yearfirst: bool | None = ..., - fuzzy: bool = ..., - fuzzy_with_tokens: bool = ..., - ) -> datetime: ... - -DEFAULTPARSER: parser - -def parse( - timestr: _FileOrStr, - parserinfo: parserinfo | None = None, - *, - dayfirst: bool | None = ..., - yearfirst: bool | None = ..., - ignoretz: bool = ..., - fuzzy: bool = ..., - fuzzy_with_tokens: bool = ..., - default: datetime | None = ..., - tzinfos: _TzInfo | None = ..., -) -> datetime: ... - -class _tzparser: ... - -DEFAULTTZPARSER: _tzparser - -class ParserError(ValueError): ... -class UnknownTimezoneWarning(RuntimeWarning): ... +__all__ = ["parse", "parser", "parserinfo", "isoparse", "isoparser", "ParserError", "UnknownTimezoneWarning"] diff --git a/stubs/python-dateutil/dateutil/parser/_parser.pyi b/stubs/python-dateutil/dateutil/parser/_parser.pyi new file mode 100644 index 000000000000..cceea934a514 --- /dev/null +++ b/stubs/python-dateutil/dateutil/parser/_parser.pyi @@ -0,0 +1,134 @@ +import re +from _typeshed import SupportsRead +from collections.abc import Callable, Mapping +from datetime import _TzInfo, datetime +from io import StringIO +from typing import IO, Any +from typing_extensions import Self, TypeAlias + +_FileOrStr: TypeAlias = bytes | str | IO[str] | IO[Any] +_TzData: TypeAlias = _TzInfo | int | str | None +_TzInfos: TypeAlias = Mapping[str, _TzData] | Callable[[str, int], _TzData] + +__all__ = ["parse", "parserinfo", "ParserError"] + +class _timelex: + _split_decimal: re.Pattern[str] + instream: StringIO | SupportsRead + charstack: list[str] + tokenstack: list[str] + eof: bool + def __init__(self, instream: str | bytes | bytearray | SupportsRead) -> None: ... + def get_token(self) -> str | None: ... + def __iter__(self) -> Self: ... + def __next__(self) -> str: ... + def next(self) -> str: ... + @classmethod + def split(cls, s: str) -> list[str]: ... + @classmethod + def isword(cls, nextchar: str) -> bool: ... + @classmethod + def isnum(cls, nextchar: str) -> bool: ... + @classmethod + def isspace(cls, nextchar: str) -> bool: ... + +class _resultbase: + def __init__(self) -> None: ... + def _repr(self, classname: str) -> str: ... + def __len__(self) -> int: ... + +class parserinfo: + JUMP: list[str] + WEEKDAYS: list[tuple[str, str]] + MONTHS: list[tuple[str, str] | tuple[str, str, str]] + HMS: list[tuple[str, str, str]] + AMPM: list[tuple[str, str]] + UTCZONE: list[str] + PERTAIN: list[str] + TZOFFSET: dict[str, int] + def __init__(self, dayfirst: bool = False, yearfirst: bool = False) -> None: ... + def jump(self, name: str) -> bool: ... + def weekday(self, name: str) -> int | None: ... + def month(self, name: str) -> int | None: ... + def hms(self, name: str) -> int | None: ... + def ampm(self, name: str) -> int | None: ... + def pertain(self, name: str) -> bool: ... + def utczone(self, name: str) -> bool: ... + def tzoffset(self, name: str) -> int | None: ... + def convertyear(self, year: int, century_specified: bool = False) -> int: ... + def validate(self, res: datetime) -> bool: ... + +class _ymd(list): + century_specified: bool + dstridx: int | None + mstridx: int | None + ystridx: int | None + def __init__(self, *args, **kwargs) -> None: ... + @property + def has_year(self) -> bool: ... + @property + def has_month(self) -> bool: ... + @property + def has_day(self) -> bool: ... + def could_be_day(self, value): ... + def append(self, val, label=None): ... + def _resolve_from_stridxs(self, strids): ... + def resolve_ymd(self, yearfirst: bool | None, dayfirst: bool | None): ... + +class parser: + info: parserinfo + def __init__(self, info: parserinfo | None = None) -> None: ... + def parse( + self, + timestr: _FileOrStr, + default: datetime | None = None, + ignoretz: bool = False, + tzinfos: _TzInfos | None = None, + *, + dayfirst: bool | None = ..., + yearfirst: bool | None = ..., + fuzzy: bool = ..., + fuzzy_with_tokens: bool = ..., + ) -> datetime: ... + +DEFAULTPARSER: parser + +def parse( + timestr: _FileOrStr, + parserinfo: parserinfo | None = None, + *, + dayfirst: bool | None = ..., + yearfirst: bool | None = ..., + ignoretz: bool = ..., + fuzzy: bool = ..., + fuzzy_with_tokens: bool = ..., + default: datetime | None = ..., + tzinfos: _TzInfos | None = ..., +) -> datetime: ... + +class _tzparser: + class _result(_resultbase): + stdabbr: str | None + stdoffset: int | None + dstabbr: str | None + dstoffset: int | None + start: _attr + end: _attr + + class _attr(_resultbase): + month: int | None + week: int | None + weekday: int | None + yday: int | None + jyday: int | None + day: int | None + time: int | None + + def __init__(self): ... + + def parse(self, tzstr: str | re.Pattern[str]) -> _result | None: ... + +DEFAULTTZPARSER: _tzparser + +class ParserError(ValueError): ... +class UnknownTimezoneWarning(RuntimeWarning): ... diff --git a/stubs/python-dateutil/dateutil/parser/isoparser.pyi b/stubs/python-dateutil/dateutil/parser/isoparser.pyi index fc5e46d97e50..51a9c153af81 100644 --- a/stubs/python-dateutil/dateutil/parser/isoparser.pyi +++ b/stubs/python-dateutil/dateutil/parser/isoparser.pyi @@ -5,6 +5,8 @@ from typing_extensions import TypeAlias _Readable: TypeAlias = SupportsRead[str | bytes] _TakesAscii: TypeAlias = str | bytes | _Readable +__all__ = ["isoparse", "isoparser"] + class isoparser: def __init__(self, sep: str | bytes | None = None): ... def isoparse(self, dt_str: _TakesAscii) -> datetime: ... diff --git a/stubs/python-dateutil/dateutil/relativedelta.pyi b/stubs/python-dateutil/dateutil/relativedelta.pyi index 9de928158249..90f155f70717 100644 --- a/stubs/python-dateutil/dateutil/relativedelta.pyi +++ b/stubs/python-dateutil/dateutil/relativedelta.pyi @@ -17,6 +17,8 @@ FR: weekday SA: weekday SU: weekday +__all__ = ["relativedelta", "MO", "TU", "WE", "TH", "FR", "SA", "SU"] + class relativedelta: years: int months: int diff --git a/stubs/python-dateutil/dateutil/rrule.pyi b/stubs/python-dateutil/dateutil/rrule.pyi index 22b7c983505c..75aaefd34e88 100644 --- a/stubs/python-dateutil/dateutil/rrule.pyi +++ b/stubs/python-dateutil/dateutil/rrule.pyi @@ -1,17 +1,48 @@ import datetime from _typeshed import Incomplete -from collections.abc import Iterable, Iterator, Sequence -from typing_extensions import TypeAlias +from collections.abc import Generator, Iterable, Iterator, Sequence +from typing import Final, Literal +from typing_extensions import Self, TypeAlias from ._common import weekday as weekdaybase -YEARLY: int -MONTHLY: int -WEEKLY: int -DAILY: int -HOURLY: int -MINUTELY: int -SECONDLY: int +__all__ = [ + "rrule", + "rruleset", + "rrulestr", + "YEARLY", + "MONTHLY", + "WEEKLY", + "DAILY", + "HOURLY", + "MINUTELY", + "SECONDLY", + "MO", + "TU", + "WE", + "TH", + "FR", + "SA", + "SU", +] + +M366MASK: Final[tuple[int, ...]] +MDAY366MASK: Final[tuple[int, ...]] +MDAY365MASK: Final[tuple[int, ...]] +NMDAY366MASK: Final[tuple[int, ...]] +NMDAY365MASK: Final[list[int]] +M366RANGE: Final[tuple[int, ...]] +M365RANGE: Final[tuple[int, ...]] +WDAYMASK: Final[list[int]] +M365MASK: Final[tuple[int, ...]] +FREQNAMES: Final[list[str]] +YEARLY: Final = 0 +MONTHLY: Final = 1 +WEEKLY: Final = 2 +DAILY: Final = 3 +HOURLY: Final = 4 +MINUTELY: Final = 5 +SECONDLY: Final = 6 class weekday(weekdaybase): ... @@ -25,21 +56,21 @@ SA: weekday SU: weekday class rrulebase: - def __init__(self, cache: bool = False) -> None: ... + def __init__(self, cache: bool | None = False) -> None: ... def __iter__(self) -> Iterator[datetime.datetime]: ... def __getitem__(self, item): ... - def __contains__(self, item): ... - def count(self): ... + def __contains__(self, item) -> bool: ... + def count(self) -> int | None: ... def before(self, dt, inc: bool = False): ... def after(self, dt, inc: bool = False): ... - def xafter(self, dt, count=None, inc: bool = False): ... - def between(self, after, before, inc: bool = False, count: int = 1): ... + def xafter(self, dt, count=None, inc: bool = False) -> Generator[Incomplete]: ... + def between(self, after, before, inc: bool = False, count: int = 1) -> list[Incomplete]: ... class rrule(rrulebase): def __init__( self, - freq, - dtstart: datetime.date | None = None, + freq: Literal[0, 1, 2, 3, 4, 5, 6], + dtstart: datetime.datetime | None = None, interval: int = 1, wkst: weekday | int | None = None, count: int | None = None, @@ -54,9 +85,29 @@ class rrule(rrulebase): byhour: int | Iterable[int] | None = None, byminute: int | Iterable[int] | None = None, bysecond: int | Iterable[int] | None = None, - cache: bool = False, + cache: bool | None = False, ) -> None: ... - def replace(self, **kwargs): ... + def replace( + self, + *, + freq: Literal[0, 1, 2, 3, 4, 5, 6] = ..., + dtstart: datetime.datetime | None = ..., + interval: int = ..., + wkst: weekday | int | None = ..., + count: int | None = ..., + until: datetime.date | int | None = ..., + bysetpos: int | Iterable[int] | None = None, + bymonth: int | Iterable[int] | None = None, + bymonthday: int | Iterable[int] | None = None, + byyearday: int | Iterable[int] | None = None, + byeaster: int | Iterable[int] | None = None, + byweekno: int | Iterable[int] | None = None, + byweekday: int | weekday | Iterable[int] | Iterable[weekday] | None = None, + byhour: int | Iterable[int] | None = None, + byminute: int | Iterable[int] | None = None, + bysecond: int | Iterable[int] | None = None, + cache: bool | None = ..., + ) -> Self: ... _RRule: TypeAlias = rrule @@ -77,14 +128,14 @@ class _iterinfo: eastermask: Sequence[int] | None lastyear: int | None lastmonth: int | None - def rebuild(self, year, month): ... - def ydayset(self, year, month, day): ... - def mdayset(self, year, month, day): ... - def wdayset(self, year, month, day): ... - def ddayset(self, year, month, day): ... - def htimeset(self, hour, minute, second): ... - def mtimeset(self, hour, minute, second): ... - def stimeset(self, hour, minute, second): ... + def rebuild(self, year: int, month: int) -> None: ... + def ydayset(self, year: int, month: int, day: int) -> tuple[Iterable[int | None], int, int]: ... + def mdayset(self, year: int, month: int, day: int) -> tuple[Iterable[int | None], int, int]: ... + def wdayset(self, year: int, month: int, day: int) -> tuple[Iterable[int | None], int, int]: ... + def ddayset(self, year: int, month: int, day: int) -> tuple[Iterable[int | None], int, int]: ... + def htimeset(self, hour: int, minute: int, second: int) -> list[datetime.time]: ... + def mtimeset(self, hour: int, minute: int, second: int) -> list[datetime.time]: ... + def stimeset(self, hour: int, minute: int, second: int) -> tuple[datetime.time, ...]: ... class rruleset(rrulebase): class _genitem: @@ -99,13 +150,25 @@ class rruleset(rrulebase): def __eq__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... - def __init__(self, cache: bool = False) -> None: ... - def rrule(self, rrule: _RRule): ... - def rdate(self, rdate): ... - def exrule(self, exrule): ... - def exdate(self, exdate): ... + def __init__(self, cache: bool | None = False) -> None: ... + def rrule(self, rrule: _RRule) -> None: ... + def rdate(self, rdate) -> None: ... + def exrule(self, exrule) -> None: ... + def exdate(self, exdate) -> None: ... class _rrulestr: - def __call__(self, s, **kwargs) -> rrule | rruleset: ... + def __call__( + self, + s: str, + *, + dtstart: datetime.datetime | None = None, + cache: bool | None = False, + unfold: bool = False, + forceset: bool = False, + compatible: bool = False, + ignoretz: bool = False, + tzids=None, + tzinfos=None, + ) -> rrule | rruleset: ... rrulestr: _rrulestr diff --git a/stubs/python-dateutil/dateutil/tz/__init__.pyi b/stubs/python-dateutil/dateutil/tz/__init__.pyi index 334ca4825094..bc525e706b56 100644 --- a/stubs/python-dateutil/dateutil/tz/__init__.pyi +++ b/stubs/python-dateutil/dateutil/tz/__init__.pyi @@ -1,6 +1,9 @@ +import sys + from .tz import ( datetime_ambiguous as datetime_ambiguous, datetime_exists as datetime_exists, + enfold as enfold, gettz as gettz, resolve_imaginary as resolve_imaginary, tzfile as tzfile, @@ -12,4 +15,31 @@ from .tz import ( tzutc as tzutc, ) +if sys.platform == "win32": + from .win import tzwin as tzwin, tzwinlocal as tzwinlocal +else: + tzwin: None + tzwinlocal: None + UTC: tzutc + +__all__ = [ + "tzutc", + "tzoffset", + "tzlocal", + "tzfile", + "tzrange", + "tzstr", + "tzical", + "tzwin", + "tzwinlocal", + "gettz", + "enfold", + "datetime_ambiguous", + "datetime_exists", + "resolve_imaginary", + "UTC", + "DeprecatedTzFormatWarning", +] + +class DeprecatedTzFormatWarning(Warning): ... diff --git a/stubs/python-dateutil/dateutil/tz/_common.pyi b/stubs/python-dateutil/dateutil/tz/_common.pyi index 4e64822fa09c..327cbc8f9359 100644 --- a/stubs/python-dateutil/dateutil/tz/_common.pyi +++ b/stubs/python-dateutil/dateutil/tz/_common.pyi @@ -2,6 +2,10 @@ import abc from datetime import datetime, timedelta, tzinfo from typing import ClassVar +ZERO: timedelta + +__all__ = ["tzname_in_python2", "enfold"] + def tzname_in_python2(namefunc): ... def enfold(dt: datetime, fold: int = 1): ... diff --git a/stubs/python-dateutil/dateutil/tz/tz.pyi b/stubs/python-dateutil/dateutil/tz/tz.pyi index c129277343c1..45703de89761 100644 --- a/stubs/python-dateutil/dateutil/tz/tz.pyi +++ b/stubs/python-dateutil/dateutil/tz/tz.pyi @@ -1,32 +1,41 @@ -import datetime +import sys +from datetime import datetime, timedelta, tzinfo from typing import ClassVar, Literal, Protocol, TypeVar from ..relativedelta import relativedelta -from ._common import _tzinfo as _tzinfo, enfold as enfold, tzname_in_python2 as tzname_in_python2, tzrangebase as tzrangebase +from ._common import _tzinfo, enfold as enfold, tzrangebase -_DT = TypeVar("_DT", bound=datetime.datetime) +if sys.platform == "win32": + from .win import tzwin as tzwin, tzwinlocal as tzwinlocal +else: + tzwin: None + tzwinlocal: None -ZERO: datetime.timedelta -EPOCH: datetime.datetime +_DT = TypeVar("_DT", bound=datetime) + +ZERO: timedelta +EPOCH: datetime EPOCHORDINAL: int -class tzutc(datetime.tzinfo): - def utcoffset(self, dt: datetime.datetime | None) -> datetime.timedelta | None: ... - def dst(self, dt: datetime.datetime | None) -> datetime.timedelta | None: ... - def tzname(self, dt: datetime.datetime | None) -> str: ... - def is_ambiguous(self, dt: datetime.datetime | None) -> bool: ... +class tzutc(tzinfo): + def utcoffset(self, dt: datetime | None) -> timedelta | None: ... + def dst(self, dt: datetime | None) -> timedelta | None: ... + def tzname(self, dt: datetime | None) -> str: ... + def is_ambiguous(self, dt: datetime | None) -> bool: ... def fromutc(self, dt: _DT) -> _DT: ... def __eq__(self, other): ... __hash__: ClassVar[None] # type: ignore[assignment] def __ne__(self, other): ... __reduce__ = object.__reduce__ -class tzoffset(datetime.tzinfo): +UTC: tzutc + +class tzoffset(tzinfo): def __init__(self, name, offset) -> None: ... - def utcoffset(self, dt: datetime.datetime | None) -> datetime.timedelta | None: ... - def dst(self, dt: datetime.datetime | None) -> datetime.timedelta | None: ... - def is_ambiguous(self, dt: datetime.datetime | None) -> bool: ... - def tzname(self, dt: datetime.datetime | None) -> str: ... + def utcoffset(self, dt: datetime | None) -> timedelta | None: ... + def dst(self, dt: datetime | None) -> timedelta | None: ... + def is_ambiguous(self, dt: datetime | None) -> bool: ... + def tzname(self, dt: datetime | None) -> str: ... def fromutc(self, dt: _DT) -> _DT: ... def __eq__(self, other): ... __hash__: ClassVar[None] # type: ignore[assignment] @@ -37,16 +46,23 @@ class tzoffset(datetime.tzinfo): class tzlocal(_tzinfo): def __init__(self) -> None: ... - def utcoffset(self, dt: datetime.datetime | None) -> datetime.timedelta | None: ... - def dst(self, dt: datetime.datetime | None) -> datetime.timedelta | None: ... - def tzname(self, dt: datetime.datetime | None) -> str: ... - def is_ambiguous(self, dt: datetime.datetime | None) -> bool: ... + def utcoffset(self, dt: datetime | None) -> timedelta | None: ... + def dst(self, dt: datetime | None) -> timedelta | None: ... + def tzname(self, dt: datetime | None) -> str: ... + def is_ambiguous(self, dt: datetime | None) -> bool: ... def __eq__(self, other): ... __hash__: ClassVar[None] # type: ignore[assignment] def __ne__(self, other): ... __reduce__ = object.__reduce__ class _ttinfo: + offset: float + delta: timedelta + isdst: bool + abbr: str + isstd: bool + isgmt: bool + dstoffset: timedelta def __init__(self) -> None: ... def __eq__(self, other): ... __hash__: ClassVar[None] # type: ignore[assignment] @@ -60,10 +76,10 @@ class _TZFileReader(Protocol): class tzfile(_tzinfo): def __init__(self, fileobj: str | _TZFileReader, filename: str | None = None) -> None: ... - def is_ambiguous(self, dt: datetime.datetime | None, idx: int | None = None) -> bool: ... - def utcoffset(self, dt: datetime.datetime | None) -> datetime.timedelta | None: ... - def dst(self, dt: datetime.datetime | None) -> datetime.timedelta | None: ... - def tzname(self, dt: datetime.datetime | None) -> str: ... + def is_ambiguous(self, dt: datetime | None, idx: int | None = None) -> bool: ... + def utcoffset(self, dt: datetime | None) -> timedelta | None: ... + def dst(self, dt: datetime | None) -> timedelta | None: ... + def tzname(self, dt: datetime | None) -> str: ... def __eq__(self, other): ... __hash__: ClassVar[None] # type: ignore[assignment] def __ne__(self, other): ... @@ -75,13 +91,13 @@ class tzrange(tzrangebase): def __init__( self, stdabbr: str, - stdoffset: int | datetime.timedelta | None = None, + stdoffset: int | timedelta | None = None, dstabbr: str | None = None, - dstoffset: int | datetime.timedelta | None = None, + dstoffset: int | timedelta | None = None, start: relativedelta | None = None, end: relativedelta | None = None, ) -> None: ... - def transitions(self, year: int) -> tuple[datetime.datetime, datetime.datetime]: ... + def transitions(self, year: int) -> tuple[datetime, datetime]: ... def __eq__(self, other): ... class tzstr(tzrange): @@ -103,12 +119,12 @@ class tzical: TZFILES: list[str] TZPATHS: list[str] -def datetime_exists(dt: datetime.datetime, tz: datetime.tzinfo | None = None) -> bool: ... -def datetime_ambiguous(dt: datetime.datetime, tz: datetime.tzinfo | None = None) -> bool: ... -def resolve_imaginary(dt: datetime.datetime) -> datetime.datetime: ... +def datetime_exists(dt: datetime, tz: tzinfo | None = None) -> bool: ... +def datetime_ambiguous(dt: datetime, tz: tzinfo | None = None) -> bool: ... +def resolve_imaginary(dt: datetime) -> datetime: ... class _GetTZ: - def __call__(self, name: str | None = ...) -> datetime.tzinfo | None: ... - def nocache(self, name: str | None) -> datetime.tzinfo | None: ... + def __call__(self, name: str | None = ...) -> tzinfo | None: ... + def nocache(self, name: str | None) -> tzinfo | None: ... gettz: _GetTZ diff --git a/stubs/python-dateutil/dateutil/tz/win.pyi b/stubs/python-dateutil/dateutil/tz/win.pyi new file mode 100644 index 000000000000..1f6a81839b57 --- /dev/null +++ b/stubs/python-dateutil/dateutil/tz/win.pyi @@ -0,0 +1,46 @@ +import sys +import winreg +from ctypes import _Pointer, c_wchar +from datetime import datetime, timedelta +from typing import Any, ClassVar, Final +from typing_extensions import Self + +from ._common import tzrangebase + +if sys.platform == "win32": + __all__ = ["tzwin", "tzwinlocal", "tzres"] + + ONEWEEK: timedelta + TZKEYNAMENT: Final[str] + TZKEYNAME9X: Final[str] + TZLOCALKEYNAME: Final[str] + TZKEYNAME: Final[str] + + class tzres: + p_wchar: ClassVar[type[_Pointer[c_wchar]]] + def __init__(self, tzres_loc="tzres.dll"): ... + def load_name(self, offset): ... + def name_from_string(self, tzname_str: str): ... + + class tzwinbase(tzrangebase): + hasdst: bool + def __eq__(self, other: tzwinbase) -> bool: ... + @staticmethod + def list() -> list[str]: ... + def display(self) -> str | None: ... + def transitions(self, year: int) -> tuple[datetime, datetime] | None: ... + + class tzwin(tzwinbase): + hasdst: bool + def __init__(self, name: str) -> None: ... + def __reduce__(self) -> tuple[type[Self], tuple[str, ...]]: ... + + class tzwinlocal(tzwinbase): + hasdst: bool + def __init__(self) -> None: ... + def __reduce__(self) -> tuple[type[Self], tuple[str, ...]]: ... + + def picknthweekday(year: int, month: int, dayofweek: int, hour: int, minute: int, whichweek: int) -> datetime: ... + def valuestodict( + key: winreg._KeyType, + ) -> dict[str, Any]: ... # keys and values in dict are results of winreg.EnumValue() function diff --git a/stubs/python-dateutil/dateutil/tzwin.pyi b/stubs/python-dateutil/dateutil/tzwin.pyi new file mode 100644 index 000000000000..f021d35938e6 --- /dev/null +++ b/stubs/python-dateutil/dateutil/tzwin.pyi @@ -0,0 +1,4 @@ +import sys + +if sys.platform == "win32": + from .tz.win import tzres as tzres, tzwin as tzwin, tzwinlocal as tzwinlocal diff --git a/stubs/python-dateutil/dateutil/utils.pyi b/stubs/python-dateutil/dateutil/utils.pyi index 8c9f5e44a294..512c241832c9 100644 --- a/stubs/python-dateutil/dateutil/utils.pyi +++ b/stubs/python-dateutil/dateutil/utils.pyi @@ -1,5 +1,5 @@ -from datetime import datetime, timedelta, tzinfo +from datetime import _TzInfo, datetime, timedelta -def default_tzinfo(dt: datetime, tzinfo: tzinfo) -> datetime: ... -def today(tzinfo: tzinfo | None = None) -> datetime: ... +def today(tzinfo: _TzInfo | None = None) -> datetime: ... +def default_tzinfo(dt: datetime, tzinfo: _TzInfo) -> datetime: ... def within_delta(dt1: datetime, dt2: datetime, delta: timedelta) -> bool: ... diff --git a/stubs/python-dateutil/dateutil/zoneinfo/__init__.pyi b/stubs/python-dateutil/dateutil/zoneinfo/__init__.pyi index 423e003dc095..3be08148bf08 100644 --- a/stubs/python-dateutil/dateutil/zoneinfo/__init__.pyi +++ b/stubs/python-dateutil/dateutil/zoneinfo/__init__.pyi @@ -1,17 +1,44 @@ from _typeshed import Incomplete -from typing import IO -from typing_extensions import TypeAlias +from collections.abc import Callable +from io import BytesIO +from tarfile import _Fileobj +from typing import Final, TypeVar, overload +from typing_extensions import Self, TypeAlias, deprecated -__all__ = ["get_zonefile_instance", "gettz", "gettz_db_metadata"] +from dateutil.tz import tzfile as _tzfile +_T = TypeVar("_T") _MetadataType: TypeAlias = dict[str, Incomplete] +__all__ = ["get_zonefile_instance", "gettz", "gettz_db_metadata"] + +ZONEFILENAME: Final[str] +METADATA_FN: Final[str] + +class tzfile(_tzfile): + def __reduce__(self) -> tuple[Callable[[str], Self], tuple[str, ...]]: ... + +def getzoneinfofile_stream() -> BytesIO | None: ... + class ZoneInfoFile: - zones: dict[Incomplete, Incomplete] + zones: dict[str, _tzfile] metadata: _MetadataType | None - def __init__(self, zonefile_stream: IO[bytes] | None = None) -> None: ... - def get(self, name, default=None): ... + def __init__(self, zonefile_stream: _Fileobj | None = None) -> None: ... + @overload + def get(self, name: str, default: None = None) -> _tzfile | None: ... + @overload + def get(self, name: str, default: _tzfile) -> _tzfile: ... + @overload + def get(self, name: str, default: _T) -> _tzfile | _T: ... def get_zonefile_instance(new_instance: bool = False) -> ZoneInfoFile: ... -def gettz(name): ... +@deprecated( + "zoneinfo.gettz() will be removed in future versions, to use the dateutil-provided " + "zoneinfo files, instantiate a ZoneInfoFile object and use ZoneInfoFile.zones.get() instead." +) +def gettz(name: str) -> _tzfile: ... +@deprecated( + "zoneinfo.gettz_db_metadata() will be removed in future versions, to use the " + "dateutil-provided zoneinfo files, ZoneInfoFile object and query the 'metadata' attribute instead." +) def gettz_db_metadata() -> _MetadataType: ... diff --git a/stubs/python-dateutil/dateutil/zoneinfo/rebuild.pyi b/stubs/python-dateutil/dateutil/zoneinfo/rebuild.pyi index 18e2d1c50b2d..9aae2bdcba44 100644 --- a/stubs/python-dateutil/dateutil/zoneinfo/rebuild.pyi +++ b/stubs/python-dateutil/dateutil/zoneinfo/rebuild.pyi @@ -1,7 +1,4 @@ from _typeshed import StrOrBytesPath -from collections.abc import Sequence -from tarfile import TarInfo +from collections.abc import Iterable -def rebuild( - filename: StrOrBytesPath, tag=None, format: str = "gz", zonegroups: Sequence[str | TarInfo] = [], metadata=None -) -> None: ... +def rebuild(filename: StrOrBytesPath, tag=None, format: str = "gz", zonegroups: Iterable[str] = [], metadata=None) -> None: ... From a7dfa263a5cfde342fc64217970b4459646d6160 Mon Sep 17 00:00:00 2001 From: donBarbos Date: Sun, 22 Jun 2025 23:16:58 +0400 Subject: [PATCH 2/4] Fix __eq__ override on win --- stubs/python-dateutil/dateutil/tz/win.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stubs/python-dateutil/dateutil/tz/win.pyi b/stubs/python-dateutil/dateutil/tz/win.pyi index 1f6a81839b57..1d81282b0156 100644 --- a/stubs/python-dateutil/dateutil/tz/win.pyi +++ b/stubs/python-dateutil/dateutil/tz/win.pyi @@ -24,7 +24,7 @@ if sys.platform == "win32": class tzwinbase(tzrangebase): hasdst: bool - def __eq__(self, other: tzwinbase) -> bool: ... + def __eq__(self, other: tzwinbase) -> bool: ... # type: ignore[override] @staticmethod def list() -> list[str]: ... def display(self) -> str | None: ... From 72a0266989cf96be220d3945875f6bc552862e73 Mon Sep 17 00:00:00 2001 From: donBarbos Date: Mon, 23 Jun 2025 20:30:49 +0400 Subject: [PATCH 3/4] Fix __reduce__ override issues --- stubs/python-dateutil/dateutil/tz/win.pyi | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/stubs/python-dateutil/dateutil/tz/win.pyi b/stubs/python-dateutil/dateutil/tz/win.pyi index 1d81282b0156..65d8e69d63a5 100644 --- a/stubs/python-dateutil/dateutil/tz/win.pyi +++ b/stubs/python-dateutil/dateutil/tz/win.pyi @@ -1,5 +1,4 @@ import sys -import winreg from ctypes import _Pointer, c_wchar from datetime import datetime, timedelta from typing import Any, ClassVar, Final @@ -8,6 +7,8 @@ from typing_extensions import Self from ._common import tzrangebase if sys.platform == "win32": + from winreg import _KeyType + __all__ = ["tzwin", "tzwinlocal", "tzres"] ONEWEEK: timedelta @@ -33,14 +34,12 @@ if sys.platform == "win32": class tzwin(tzwinbase): hasdst: bool def __init__(self, name: str) -> None: ... - def __reduce__(self) -> tuple[type[Self], tuple[str, ...]]: ... + def __reduce__(self) -> tuple[type[Self], tuple[str, ...]]: ... # type: ignore[override] class tzwinlocal(tzwinbase): hasdst: bool def __init__(self) -> None: ... - def __reduce__(self) -> tuple[type[Self], tuple[str, ...]]: ... + def __reduce__(self) -> tuple[type[Self], tuple[str, ...]]: ... # type: ignore[override] def picknthweekday(year: int, month: int, dayofweek: int, hour: int, minute: int, whichweek: int) -> datetime: ... - def valuestodict( - key: winreg._KeyType, - ) -> dict[str, Any]: ... # keys and values in dict are results of winreg.EnumValue() function + def valuestodict(key: _KeyType) -> dict[str, Any]: ... # keys and values in dict are results of winreg.EnumValue() function From 0f653aa485ad72a5eec7307873a6df2419e37b2d Mon Sep 17 00:00:00 2001 From: donBarbos Date: Mon, 23 Jun 2025 20:39:56 +0400 Subject: [PATCH 4/4] Fix import issues --- .../python-dateutil/dateutil/tz/__init__.pyi | 24 ++++++++++++++++++- stubs/python-dateutil/dateutil/tz/win.pyi | 21 +--------------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/stubs/python-dateutil/dateutil/tz/__init__.pyi b/stubs/python-dateutil/dateutil/tz/__init__.pyi index bc525e706b56..3dbbe3199855 100644 --- a/stubs/python-dateutil/dateutil/tz/__init__.pyi +++ b/stubs/python-dateutil/dateutil/tz/__init__.pyi @@ -1,5 +1,8 @@ import sys +from datetime import datetime +from typing_extensions import Self +from ._common import tzrangebase from .tz import ( datetime_ambiguous as datetime_ambiguous, datetime_exists as datetime_exists, @@ -15,8 +18,27 @@ from .tz import ( tzutc as tzutc, ) +# UTC, tzwin, tzwinlocal are defined in this class +# otherwise pyright complains about unknown import symbol: if sys.platform == "win32": - from .win import tzwin as tzwin, tzwinlocal as tzwinlocal + class tzwinbase(tzrangebase): + hasdst: bool + def __eq__(self, other: tzwinbase) -> bool: ... # type: ignore[override] + @staticmethod + def list() -> list[str]: ... + def display(self) -> str | None: ... + def transitions(self, year: int) -> tuple[datetime, datetime] | None: ... + + class tzwin(tzwinbase): + hasdst: bool + def __init__(self, name: str) -> None: ... + def __reduce__(self) -> tuple[type[Self], tuple[str, ...]]: ... # type: ignore[override] + + class tzwinlocal(tzwinbase): + hasdst: bool + def __init__(self) -> None: ... + def __reduce__(self) -> tuple[type[Self], tuple[str, ...]]: ... # type: ignore[override] + else: tzwin: None tzwinlocal: None diff --git a/stubs/python-dateutil/dateutil/tz/win.pyi b/stubs/python-dateutil/dateutil/tz/win.pyi index 65d8e69d63a5..bae9c4e9956a 100644 --- a/stubs/python-dateutil/dateutil/tz/win.pyi +++ b/stubs/python-dateutil/dateutil/tz/win.pyi @@ -2,9 +2,8 @@ import sys from ctypes import _Pointer, c_wchar from datetime import datetime, timedelta from typing import Any, ClassVar, Final -from typing_extensions import Self -from ._common import tzrangebase +from dateutil.tz import tzwin as tzwin, tzwinlocal as tzwinlocal if sys.platform == "win32": from winreg import _KeyType @@ -23,23 +22,5 @@ if sys.platform == "win32": def load_name(self, offset): ... def name_from_string(self, tzname_str: str): ... - class tzwinbase(tzrangebase): - hasdst: bool - def __eq__(self, other: tzwinbase) -> bool: ... # type: ignore[override] - @staticmethod - def list() -> list[str]: ... - def display(self) -> str | None: ... - def transitions(self, year: int) -> tuple[datetime, datetime] | None: ... - - class tzwin(tzwinbase): - hasdst: bool - def __init__(self, name: str) -> None: ... - def __reduce__(self) -> tuple[type[Self], tuple[str, ...]]: ... # type: ignore[override] - - class tzwinlocal(tzwinbase): - hasdst: bool - def __init__(self) -> None: ... - def __reduce__(self) -> tuple[type[Self], tuple[str, ...]]: ... # type: ignore[override] - def picknthweekday(year: int, month: int, dayofweek: int, hour: int, minute: int, whichweek: int) -> datetime: ... def valuestodict(key: _KeyType) -> dict[str, Any]: ... # keys and values in dict are results of winreg.EnumValue() function