From 0c38f037542b94003518186347a1b848adf4abc2 Mon Sep 17 00:00:00 2001 From: donbarbos Date: Sun, 8 Feb 2026 15:16:50 +0400 Subject: [PATCH] [dateparser] Improve stubs * Functions with `settings` params actually accepts `Settings` (or `dict` only if has `@apply_settings` decorator) * Use `TypeVar` for date params that are used as return objects * Use `collections.abc.Set` instead of `set` since there is an `isinstance` check specifically for `collections.abc.Set` * Annotated many other parameters --- stubs/dateparser/dateparser/__init__.pyi | 18 ++-- .../dateparser/calendars/__init__.pyi | 45 ++++++--- .../dateparser/calendars/hijri_parser.pyi | 27 +++--- .../dateparser/calendars/jalali_parser.pyi | 22 ++--- stubs/dateparser/dateparser/conf.pyi | 37 ++++++- .../dateparser/data/languages_info.pyi | 2 +- stubs/dateparser/dateparser/date.pyi | 97 +++++++++++++------ .../dateparser/freshness_date_parser.pyi | 5 +- .../dateparser/languages/dictionary.pyi | 14 +-- .../dateparser/languages/locale.pyi | 21 ++-- .../dateparser/languages/validation.pyi | 3 +- stubs/dateparser/dateparser/parser.pyi | 20 ++-- .../dateparser/dateparser/search/__init__.pyi | 8 +- .../dateparser/search/detection.pyi | 30 +++--- stubs/dateparser/dateparser/search/search.pyi | 87 ++++++++++++----- .../dateparser/search/text_detection.pyi | 15 ++- .../dateparser/dateparser/timezone_parser.pyi | 12 ++- .../dateparser/dateparser/utils/__init__.pyi | 28 +++--- .../dateparser/dateparser/utils/strptime.pyi | 11 ++- .../dateparser/utils/time_spans.pyi | 27 ++---- stubs/dateparser/dateparser_data/settings.pyi | 4 +- 21 files changed, 340 insertions(+), 193 deletions(-) diff --git a/stubs/dateparser/dateparser/__init__.pyi b/stubs/dateparser/dateparser/__init__.pyi index cec3cb7b8a26..ff3ab72b686a 100644 --- a/stubs/dateparser/dateparser/__init__.pyi +++ b/stubs/dateparser/dateparser/__init__.pyi @@ -1,18 +1,16 @@ import datetime -from typing import Literal, TypedDict, type_check_only -from typing_extensions import TypeAlias +from typing import Any, Final, Literal, TypedDict, type_check_only + +from dateparser.conf import Settings from .date import DateDataParser, _DetectLanguagesFunction -__version__: str +__version__: Final[str] _default_parser: DateDataParser -_Part: TypeAlias = Literal["day", "month", "year"] -_ParserKind: TypeAlias = Literal["timestamp", "relative-time", "custom-formats", "absolute-time", "no-spaces-time"] - @type_check_only -class _Settings(TypedDict, total=False): +class _Settings(TypedDict, total=False): # noqa: Y049 DATE_ORDER: str PREFER_LOCALE_DATE_ORDER: bool TIMEZONE: str @@ -23,14 +21,14 @@ class _Settings(TypedDict, total=False): PREFER_DATES_FROM: Literal["current_period", "future", "past"] RELATIVE_BASE: datetime.datetime STRICT_PARSING: bool - REQUIRE_PARTS: list[_Part] + REQUIRE_PARTS: list[Literal["day", "month", "year"]] SKIP_TOKENS: list[str] NORMALIZE: bool RETURN_TIME_AS_PERIOD: bool RETURN_TIME_SPAN: bool DEFAULT_START_OF_WEEK: Literal["monday", "sunday"] DEFAULT_DAYS_IN_MONTH: int - PARSERS: list[_ParserKind] + PARSERS: list[Literal["timestamp", "relative-time", "custom-formats", "absolute-time", "no-spaces-time"]] DEFAULT_LANGUAGES: list[str] LANGUAGE_DETECTION_CONFIDENCE_THRESHOLD: float CACHE_SIZE_LIMIT: int @@ -41,6 +39,6 @@ def parse( languages: list[str] | tuple[str, ...] | set[str] | None = None, locales: list[str] | tuple[str, ...] | set[str] | None = None, region: str | None = None, - settings: _Settings | None = None, + settings: Settings | dict[str, Any] | None = None, detect_languages_function: _DetectLanguagesFunction | None = None, ) -> datetime.datetime | None: ... diff --git a/stubs/dateparser/dateparser/calendars/__init__.pyi b/stubs/dateparser/dateparser/calendars/__init__.pyi index 105f27431aad..13a02e9d7269 100644 --- a/stubs/dateparser/dateparser/calendars/__init__.pyi +++ b/stubs/dateparser/dateparser/calendars/__init__.pyi @@ -1,24 +1,47 @@ from _typeshed import Incomplete from abc import abstractmethod +from typing import ClassVar, Protocol, type_check_only from dateparser.conf import Settings +from dateparser.date import DateData from dateparser.parser import _parser +# Examples: `hijri_parser.hijri` class or `convertdate.persian` module +@type_check_only +class _CalendarConverter(Protocol): + @classmethod + def to_gregorian(cls, year: int, month: int, day: int) -> tuple[int, int, int]: ... + @classmethod + def from_gregorian( + cls, year: int | None = None, month: int | None = None, day: int | None = None + ) -> tuple[int, int, int]: ... + @classmethod + def month_length(cls, year: int, month: int) -> int: ... + +# Examples: `hijri_parser.HijriDate` or `jalali_parser.PersianDate` +@type_check_only +class _NonGregorianDate(Protocol): + year: int + month: int + day: int + def __init__(self, year: int, month: int, day: int) -> None: ... + def weekday(self) -> int | None: ... + class CalendarBase: - parser: Incomplete - source: Incomplete - def __init__(self, source) -> None: ... - def get_date(self): ... + parser: type[_parser] + source: str + def __init__(self, source: str) -> None: ... + def get_date(self) -> DateData | None: ... class non_gregorian_parser(_parser): - calendar_converter: Incomplete - default_year: Incomplete - default_month: Incomplete - default_day: Incomplete - non_gregorian_date_cls: Incomplete + calendar_converter: ClassVar[type[_CalendarConverter]] + default_year: ClassVar[int] + default_month: ClassVar[int] + default_day: ClassVar[int] + non_gregorian_date_cls: ClassVar[type[_NonGregorianDate]] @classmethod - def to_latin(cls, source): ... + def to_latin(cls, source: str) -> str: ... @abstractmethod def handle_two_digit_year(self, year: int) -> int: ... @classmethod - def parse(cls, datestring: str, settings: Settings) -> tuple[Incomplete, Incomplete]: ... # type: ignore[override] + def parse(cls, datestring: str, settings: Settings) -> tuple[Incomplete, str | None]: ... # type: ignore[override] diff --git a/stubs/dateparser/dateparser/calendars/hijri_parser.pyi b/stubs/dateparser/dateparser/calendars/hijri_parser.pyi index f73a18bd1a0c..13551dba93dc 100644 --- a/stubs/dateparser/dateparser/calendars/hijri_parser.pyi +++ b/stubs/dateparser/dateparser/calendars/hijri_parser.pyi @@ -1,5 +1,4 @@ -from _typeshed import Incomplete -from typing import SupportsIndex +from typing import ClassVar from dateparser.calendars import non_gregorian_parser @@ -8,22 +7,22 @@ class hijri: def to_gregorian(cls, year: int | None = None, month: int | None = None, day: int | None = None) -> tuple[int, int, int]: ... @classmethod def from_gregorian( - cls, year: SupportsIndex | None = None, month: SupportsIndex | None = None, day: SupportsIndex | None = None + cls, year: int | None = None, month: int | None = None, day: int | None = None ) -> tuple[int, int, int]: ... @classmethod - def month_length(cls, year: int, month: int) -> int: ... + def month_length(cls, year: int | None, month: int | None) -> int: ... class HijriDate: - year: Incomplete - month: Incomplete - day: Incomplete - def __init__(self, year, month, day) -> None: ... - def weekday(self): ... + year: int + month: int + day: int + def __init__(self, year: int, month: int, day: int) -> None: ... + def weekday(self) -> int | None: ... class hijri_parser(non_gregorian_parser): - calendar_converter: type[hijri] - default_year: int - default_month: int - default_day: int - non_gregorian_date_cls: type[HijriDate] + calendar_converter: ClassVar[type[hijri]] + default_year: ClassVar[int] + default_month: ClassVar[int] + default_day: ClassVar[int] + non_gregorian_date_cls: ClassVar[type[HijriDate]] def handle_two_digit_year(self, year: int) -> int: ... diff --git a/stubs/dateparser/dateparser/calendars/jalali_parser.pyi b/stubs/dateparser/dateparser/calendars/jalali_parser.pyi index d70a244cbfef..9c8064135b31 100644 --- a/stubs/dateparser/dateparser/calendars/jalali_parser.pyi +++ b/stubs/dateparser/dateparser/calendars/jalali_parser.pyi @@ -1,18 +1,18 @@ -from _typeshed import Incomplete +from typing import ClassVar from dateparser.calendars import non_gregorian_parser class PersianDate: - year: Incomplete - month: Incomplete - day: Incomplete - def __init__(self, year, month, day) -> None: ... - def weekday(self): ... + year: int + month: int + day: int + def __init__(self, year: int, month: int, day: int) -> None: ... + def weekday(self) -> int | None: ... class jalali_parser(non_gregorian_parser): - calendar_converter: Incomplete - default_year: int - default_month: int - default_day: int - non_gregorian_date_cls: type[PersianDate] + # `calendar_converter` is `convertdate.persian` module + default_year: ClassVar[int] + default_month: ClassVar[int] + default_day: ClassVar[int] + non_gregorian_date_cls: ClassVar[type[PersianDate]] def handle_two_digit_year(self, year: int) -> int: ... diff --git a/stubs/dateparser/dateparser/conf.pyi b/stubs/dateparser/dateparser/conf.pyi index 7c1f85361186..74b98a5c82c4 100644 --- a/stubs/dateparser/dateparser/conf.pyi +++ b/stubs/dateparser/dateparser/conf.pyi @@ -1,8 +1,37 @@ -from typing import Any -from typing_extensions import Self +import datetime +from collections.abc import Callable +from typing import Any, Literal, TypeVar +from typing_extensions import ParamSpec, Self + +_P = ParamSpec("_P") +_R = TypeVar("_R") class Settings: - def __new__(cls, *args, **kw) -> Self: ... + # Next attributes are optional and may be missing. + # Please keep in sync with _Settings TypedDict + DATE_ORDER: str + PREFER_LOCALE_DATE_ORDER: bool + TIMEZONE: str + TO_TIMEZONE: str + RETURN_AS_TIMEZONE_AWARE: bool + PREFER_MONTH_OF_YEAR: Literal["current", "first", "last"] + PREFER_DAY_OF_MONTH: Literal["current", "first", "last"] + PREFER_DATES_FROM: Literal["current_period", "future", "past"] + RELATIVE_BASE: datetime.datetime + STRICT_PARSING: bool + REQUIRE_PARTS: list[Literal["day", "month", "year"]] + SKIP_TOKENS: list[str] + NORMALIZE: bool + RETURN_TIME_AS_PERIOD: bool + RETURN_TIME_SPAN: bool + DEFAULT_START_OF_WEEK: Literal["monday", "sunday"] + DEFAULT_DAYS_IN_MONTH: int + PARSERS: list[Literal["timestamp", "relative-time", "custom-formats", "absolute-time", "no-spaces-time"]] + DEFAULT_LANGUAGES: list[str] + LANGUAGE_DETECTION_CONFIDENCE_THRESHOLD: float + CACHE_SIZE_LIMIT: int + + def __new__(cls, *args, **kwargs) -> Self: ... def __init__(self, settings: dict[str, Any] | None = None) -> None: ... @classmethod def get_key(cls, settings: dict[str, Any] | None = None) -> str: ... @@ -10,7 +39,7 @@ class Settings: settings: Settings -def apply_settings(f): ... +def apply_settings(f: Callable[_P, _R]) -> Callable[_P, _R]: ... class SettingValidationError(ValueError): ... diff --git a/stubs/dateparser/dateparser/data/languages_info.pyi b/stubs/dateparser/dateparser/data/languages_info.pyi index 92038f5150de..5ac61c380052 100644 --- a/stubs/dateparser/dateparser/data/languages_info.pyi +++ b/stubs/dateparser/dateparser/data/languages_info.pyi @@ -1,5 +1,5 @@ from typing import Final language_order: Final[list[str]] -language_locale_dict: Final[dict[str, str]] language_map: Final[dict[str, list[str]]] +language_locale_dict: Final[dict[str, list[str]]] diff --git a/stubs/dateparser/dateparser/date.pyi b/stubs/dateparser/dateparser/date.pyi index c26e35566218..a38d05448f15 100644 --- a/stubs/dateparser/dateparser/date.pyi +++ b/stubs/dateparser/dateparser/date.pyi @@ -1,48 +1,79 @@ -import collections -from collections.abc import Callable, Iterable, Iterator -from datetime import datetime, tzinfo -from re import Pattern -from typing import ClassVar, Final, Literal, overload +import re +from _typeshed import Incomplete +from collections import OrderedDict +from collections.abc import Callable, Iterable, Iterator, Set as AbstractSet +from datetime import date, datetime, tzinfo +from typing import Any, ClassVar, Final, Literal, NamedTuple, TypeVar, overload, type_check_only from typing_extensions import TypeAlias -from dateparser import _Settings from dateparser.conf import Settings from dateparser.languages.loader import LocaleDataLoader from dateparser.languages.locale import Locale +_DateT = TypeVar("_DateT", bound=date) + _DetectLanguagesFunction: TypeAlias = Callable[[str, float], list[str]] _Period: TypeAlias = Literal["time", "day", "week", "month", "year"] +# Work around attribute and type having the same name. +_Weekday: TypeAlias = Incomplete # Actually it's dateutil._common.weekday class + +@type_check_only +class _DateData(NamedTuple): + date_obj: datetime | None + locale: str | None + period: _Period | None APOSTROPHE_LOOK_ALIKE_CHARS: Final[list[str]] -RE_NBSP: Final[Pattern[str]] -RE_SPACES: Final[Pattern[str]] -RE_TRIM_SPACES: Final[Pattern[str]] -RE_TRIM_COLONS: Final[Pattern[str]] -RE_SANITIZE_SKIP: Final[Pattern[str]] -RE_SANITIZE_RUSSIAN: Final[Pattern[str]] -RE_SANITIZE_PERIOD: Final[Pattern[str]] -RE_SANITIZE_ON: Final[Pattern[str]] -RE_SANITIZE_APOSTROPHE: Final[Pattern[str]] -RE_SEARCH_TIMESTAMP: Final[Pattern[str]] -RE_SANITIZE_CROATIAN: Final[Pattern[str]] -RE_SEARCH_NEGATIVE_TIMESTAMP: Final[Pattern[str]] +RE_NBSP: Final[re.Pattern[str]] +RE_SPACES: Final[re.Pattern[str]] +RE_TRIM_SPACES: Final[re.Pattern[str]] +RE_TRIM_COLONS: Final[re.Pattern[str]] +RE_SANITIZE_SKIP: Final[re.Pattern[str]] +RE_SANITIZE_RUSSIAN: Final[re.Pattern[str]] +RE_SANITIZE_PERIOD: Final[re.Pattern[str]] +RE_SANITIZE_ON: Final[re.Pattern[str]] +RE_SANITIZE_APOSTROPHE: Final[re.Pattern[str]] +RE_SEARCH_TIMESTAMP: Final[re.Pattern[str]] +RE_SANITIZE_CROATIAN: Final[re.Pattern[str]] +RE_SEARCH_NEGATIVE_TIMESTAMP: Final[re.Pattern[str]] def sanitize_spaces(date_string: str) -> str: ... -def date_range(begin: datetime, end: datetime, **kwargs) -> None: ... -def get_intersecting_periods(low: datetime, high: datetime, period: str = "day") -> None: ... +def date_range( + begin: _DateT, + end: _DateT, + *, + dt1: date | None = None, + dt2: date | None = None, + years: int = 0, + months: int = 0, + days: int = 0, + leapdays: int = 0, + weeks: int = 0, + hours: int = 0, + minutes: int = 0, + seconds: int = 0, + microseconds: int = 0, + weekday: int | _Weekday | None = None, + yearday: int | None = None, + nlyearday: int | None = None, + microsecond: int | None = None, +) -> Iterator[_DateT]: ... +def get_intersecting_periods( + low: _DateT, high: _DateT, period: Literal["year", "month", "week", "day", "hour", "minute", "second", "microsecond"] = "day" +) -> Iterator[_DateT]: ... def sanitize_date(date_string: str) -> str: ... -def get_date_from_timestamp(date_string: str, settings: Settings, negative: bool = False) -> datetime | None: ... +def get_date_from_timestamp(date_string: str, settings: Settings, negative: bool | None = False) -> datetime | None: ... def parse_with_formats(date_string: str, date_formats: Iterable[str], settings: Settings) -> DateData: ... class _DateLocaleParser: locale: Locale date_string: str - date_formats: list[str] | tuple[str, ...] | set[str] | None + date_formats: list[str] | tuple[str, ...] | AbstractSet[str] | None def __init__( self, locale: Locale, date_string: str, - date_formats: list[str] | tuple[str, ...] | set[str] | None, + date_formats: list[str] | tuple[str, ...] | AbstractSet[str] | None, settings: Settings | None = None, ) -> None: ... @classmethod @@ -50,7 +81,7 @@ class _DateLocaleParser: cls, locale: Locale, date_string: str, - date_formats: list[str] | tuple[str, ...] | set[str] | None = None, + date_formats: list[str] | tuple[str, ...] | AbstractSet[str] | None = None, settings: Settings | None = None, ) -> DateData: ... def _parse(self) -> DateData | None: ... @@ -88,22 +119,26 @@ class DateDataParser: try_previous_locales: bool use_given_order: bool languages: list[str] | None - locales: list[str] | tuple[str, ...] | set[str] | None + locales: list[str] | tuple[str, ...] | AbstractSet[str] | None region: str detect_languages_function: _DetectLanguagesFunction | None - previous_locales: collections.OrderedDict[Locale, None] + previous_locales: OrderedDict[Locale, None] def __init__( self, - languages: list[str] | tuple[str, ...] | set[str] | None = None, - locales: list[str] | tuple[str, ...] | set[str] | None = None, + languages: list[str] | tuple[str, ...] | AbstractSet[str] | None = None, + locales: list[str] | tuple[str, ...] | AbstractSet[str] | None = None, region: str | None = None, try_previous_locales: bool = False, use_given_order: bool = False, - settings: _Settings | None = None, + settings: Settings | dict[str, Any] | None = None, detect_languages_function: _DetectLanguagesFunction | None = None, ) -> None: ... - def get_date_data(self, date_string: str, date_formats: list[str] | tuple[str, ...] | set[str] | None = None) -> DateData: ... - def get_date_tuple(self, date_string: str, date_formats: list[str] | tuple[str, ...] | set[str] | None = ...): ... + def get_date_data( + self, date_string: str, date_formats: list[str] | tuple[str, ...] | AbstractSet[str] | None = None + ) -> DateData: ... + def get_date_tuple( + self, date_string: str, date_formats: list[str] | tuple[str, ...] | AbstractSet[str] | None = None + ) -> _DateData: ... def _get_applicable_locales(self, date_string: str) -> Iterator[Locale]: ... def _is_applicable_locale(self, locale: Locale, date_string: str) -> bool: ... @classmethod diff --git a/stubs/dateparser/dateparser/freshness_date_parser.pyi b/stubs/dateparser/dateparser/freshness_date_parser.pyi index 32aed2d4a2f2..73cb582ba88f 100644 --- a/stubs/dateparser/dateparser/freshness_date_parser.pyi +++ b/stubs/dateparser/dateparser/freshness_date_parser.pyi @@ -3,16 +3,17 @@ from _typeshed import Incomplete from typing import Final from zoneinfo import ZoneInfo +from dateparser.conf import Settings from dateparser.date import DateData PATTERN: Final[re.Pattern[str]] class FreshnessDateDataParser: def get_local_tz(self) -> ZoneInfo: ... - def parse(self, date_string: str, settings) -> tuple[Incomplete | None, str | None]: ... + def parse(self, date_string: str, settings: Settings) -> tuple[Incomplete | None, str | None]: ... def get_kwargs( self, date_string: str ) -> tuple[dict[str, float], dict[str, Incomplete]] | dict[None, None]: ... # return empty dict if pattern not found - def get_date_data(self, date_string: str, settings=None) -> DateData: ... + def get_date_data(self, date_string: str, settings: Settings | None = None) -> DateData: ... freshness_date_parser: FreshnessDateDataParser diff --git a/stubs/dateparser/dateparser/languages/dictionary.pyi b/stubs/dateparser/dateparser/languages/dictionary.pyi index ef3abee8b304..183ed097269f 100644 --- a/stubs/dateparser/dateparser/languages/dictionary.pyi +++ b/stubs/dateparser/dateparser/languages/dictionary.pyi @@ -3,6 +3,8 @@ from _typeshed import Incomplete from itertools import chain from typing import Final, overload +from dateparser.conf import Settings + PARSER_HARDCODED_TOKENS: Final[list[str]] PARSER_KNOWN_TOKENS: Final[list[str]] ALWAYS_KEEP_TOKENS: Final[list[str]] @@ -14,11 +16,11 @@ KEEP_TOKEN_PATTERN: Final[re.Pattern[str]] class UnknownTokenError(Exception): ... class Dictionary: - info: Incomplete - def __init__(self, locale_info: dict[str, Incomplete], settings=None) -> None: ... - def __contains__(self, key): ... - def __getitem__(self, key): ... - def __iter__(self) -> chain[Incomplete]: ... + info: dict[str, Incomplete] + def __init__(self, locale_info: dict[str, Incomplete], settings: Settings | None = None) -> None: ... + def __contains__(self, key: str) -> bool: ... + def __getitem__(self, key: str): ... + def __iter__(self) -> chain[str]: ... def are_tokens_valid(self, tokens: list[str]) -> bool: ... @overload def split(self, string: None, keep_formatting: bool = False) -> None: ... @@ -26,4 +28,4 @@ class Dictionary: def split(self, string: str, keep_formatting: bool = False) -> list[str]: ... class NormalizedDictionary(Dictionary): - def __init__(self, locale_info: dict[str, Incomplete], settings=None) -> None: ... + def __init__(self, locale_info: dict[str, Incomplete], settings: Settings | None = None) -> None: ... diff --git a/stubs/dateparser/dateparser/languages/locale.pyi b/stubs/dateparser/dateparser/languages/locale.pyi index edbc1a403085..ad6ae9d283d2 100644 --- a/stubs/dateparser/dateparser/languages/locale.pyi +++ b/stubs/dateparser/dateparser/languages/locale.pyi @@ -1,18 +1,25 @@ +from _typeshed import Incomplete +from collections import OrderedDict +from collections.abc import Mapping, Sized from re import Pattern -from typing import Final +from typing import Final, TypeVar from dateparser.conf import Settings +_K = TypeVar("_K", bound=Sized) +_V = TypeVar("_V") + NUMERAL_PATTERN: Final[Pattern[str]] class Locale: shortname: str - def __init__(self, shortname: str, language_info) -> None: ... + info: OrderedDict[str, Incomplete] + def __init__(self, shortname: str, language_info: Mapping[Incomplete, Incomplete]) -> None: ... def is_applicable(self, date_string: str, strip_timezone: bool = False, settings: Settings | None = None) -> bool: ... - def count_applicability(self, text: str, strip_timezone: bool = False, settings: Settings | None = None): ... + def count_applicability(self, text: str, strip_timezone: bool = False, settings: Settings | None = None) -> list[int]: ... @staticmethod - def clean_dictionary(dictionary, threshold: int = 2): ... + def clean_dictionary(dictionary: Mapping[_K, _V], threshold: int = 2) -> Mapping[_K, _V]: ... def translate(self, date_string: str, keep_formatting: bool = False, settings: Settings | None = None) -> str: ... - def translate_search(self, search_string, settings: Settings | None = None): ... - def get_wordchars_for_detection(self, settings): ... - def to_parserinfo(self, base_cls=...): ... + def translate_search(self, search_string: str, settings: Settings | None = None) -> tuple[list[str], list[str]]: ... + def get_wordchars_for_detection(self, settings: Settings) -> set[str]: ... + def to_parserinfo(self, base_cls: type = ...): ... diff --git a/stubs/dateparser/dateparser/languages/validation.pyi b/stubs/dateparser/dateparser/languages/validation.pyi index d14701860ae8..b98ed3d6e90c 100644 --- a/stubs/dateparser/dateparser/languages/validation.pyi +++ b/stubs/dateparser/dateparser/languages/validation.pyi @@ -1,9 +1,10 @@ from _typeshed import Incomplete from logging import Logger +from typing import ClassVar class LanguageValidator: + VALID_KEYS: ClassVar[list[str]] logger: Logger | None - VALID_KEYS: list[str] @classmethod def get_logger(cls) -> Logger: ... @classmethod diff --git a/stubs/dateparser/dateparser/parser.pyi b/stubs/dateparser/dateparser/parser.pyi index 45ef89115746..39d1f3c836c3 100644 --- a/stubs/dateparser/dateparser/parser.pyi +++ b/stubs/dateparser/dateparser/parser.pyi @@ -1,10 +1,10 @@ -import collections import datetime import re from _typeshed import Incomplete -from collections.abc import Callable, Generator +from collections import OrderedDict +from collections.abc import Callable, Iterable, Iterator from io import StringIO -from typing import Any, Final, Literal, overload +from typing import Final, Literal, overload from dateparser.conf import Settings @@ -35,30 +35,30 @@ time_parser: _time_parser class _no_spaces_parser: period: dict[str, list[str]] date_formats: dict[str, list[str]] - def __init__(self, *args, **kwargs): ... + def __init__(self, *args, **kwargs) -> None: ... @classmethod def parse(cls, datestring: str, settings: Settings) -> tuple[datetime.datetime, str]: ... class _parser: - alpha_directives: collections.OrderedDict[str, list[str]] + alpha_directives: OrderedDict[str, list[str]] num_directives: dict[str, list[str]] settings: Settings tokens: list[tuple[Incomplete, Incomplete]] filtered_tokens: list[tuple[Incomplete, Incomplete, int]] - unset_tokens: list[Incomplete] + unset_tokens: list[tuple[Incomplete, Incomplete, Incomplete]] day: int | None month: int | None year: int | None time: Callable[[], datetime.time] | None auto_order: list[str] - ordered_num_directives: collections.OrderedDict[str, list[str]] - def __init__(self, tokens, settings: Settings): ... + ordered_num_directives: OrderedDict[str, list[str]] + def __init__(self, tokens: Iterable[Incomplete], settings: Settings) -> None: ... @classmethod - def parse(cls, datestring: str, settings: Settings, tz: datetime.tzinfo | None = None) -> tuple[Incomplete, Incomplete]: ... + def parse(cls, datestring: str, settings: Settings, tz: datetime.tzinfo | None = None) -> tuple[Incomplete, str | None]: ... class tokenizer: digits: Literal["0123456789:"] letters: Literal["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"] instream: StringIO def __init__(self, ds: str) -> None: ... - def tokenize(self) -> Generator[tuple[str, Literal[0, 1, 2]], Any, None]: ... + def tokenize(self) -> Iterator[tuple[str, Literal[0, 1, 2]]]: ... diff --git a/stubs/dateparser/dateparser/search/__init__.pyi b/stubs/dateparser/dateparser/search/__init__.pyi index 25afddd2b856..a30045a570c3 100644 --- a/stubs/dateparser/dateparser/search/__init__.pyi +++ b/stubs/dateparser/dateparser/search/__init__.pyi @@ -1,14 +1,16 @@ -from collections.abc import Mapping, Set as AbstractSet +from collections.abc import Set as AbstractSet from datetime import datetime from typing import Any, Literal, overload +from dateparser.conf import Settings + from ..date import _DetectLanguagesFunction @overload def search_dates( text: str, languages: list[str] | tuple[str, ...] | AbstractSet[str] | None, - settings: Mapping[Any, Any] | None, + settings: Settings | dict[str, Any] | None, add_detected_language: Literal[True], detect_languages_function: _DetectLanguagesFunction | None = None, ) -> list[tuple[str, datetime, str]]: ... @@ -16,7 +18,7 @@ def search_dates( def search_dates( text: str, languages: list[str] | tuple[str, ...] | AbstractSet[str] | None = None, - settings: Mapping[Any, Any] | None = None, + settings: Settings | dict[str, Any] | None = None, add_detected_language: Literal[False] = False, detect_languages_function: _DetectLanguagesFunction | None = None, ) -> list[tuple[str, datetime]]: ... diff --git a/stubs/dateparser/dateparser/search/detection.pyi b/stubs/dateparser/dateparser/search/detection.pyi index a9839e7e12a8..1466b18175cc 100644 --- a/stubs/dateparser/dateparser/search/detection.pyi +++ b/stubs/dateparser/dateparser/search/detection.pyi @@ -1,17 +1,25 @@ -from _typeshed import Incomplete +from collections.abc import Iterator + +from dateparser.conf import Settings +from dateparser.languages.locale import Locale class BaseLanguageDetector: - languages: Incomplete - def __init__(self, languages) -> None: ... - def iterate_applicable_languages(self, date_string, modify: bool = False, settings=None) -> None: ... + languages: list[Locale] + def __init__(self, languages: list[Locale]) -> None: ... + def iterate_applicable_languages( + self, date_string: str, modify: bool = False, settings: Settings | None = None + ) -> Iterator[Locale]: ... class AutoDetectLanguage(BaseLanguageDetector): - language_pool: Incomplete - allow_redetection: Incomplete - def __init__(self, languages, allow_redetection: bool = False) -> None: ... - languages: Incomplete - def iterate_applicable_languages(self, date_string, modify: bool = False, settings=None) -> None: ... + language_pool: list[Locale] + allow_redetection: bool + def __init__(self, languages: list[Locale], allow_redetection: bool = False) -> None: ... + def iterate_applicable_languages( + self, date_string: str, modify: bool = False, settings: Settings | None = None + ) -> Iterator[Locale]: ... class ExactLanguages(BaseLanguageDetector): - def __init__(self, languages) -> None: ... - def iterate_applicable_languages(self, date_string, modify: bool = False, settings=None) -> None: ... + def __init__(self, languages: list[Locale]) -> None: ... + def iterate_applicable_languages( + self, date_string: str, modify: bool = False, settings: Settings | None = None + ) -> Iterator[Locale]: ... diff --git a/stubs/dateparser/dateparser/search/search.pyi b/stubs/dateparser/dateparser/search/search.pyi index b2bf582f82a5..5e3c3d37dda2 100644 --- a/stubs/dateparser/dateparser/search/search.pyi +++ b/stubs/dateparser/dateparser/search/search.pyi @@ -1,39 +1,76 @@ +import datetime import re from _typeshed import Incomplete -from collections.abc import Collection -from typing import Final +from collections import OrderedDict +from collections.abc import Iterable, Sequence, Set as AbstractSet +from typing import Any, Final, TypedDict, type_check_only -from ..date import _DetectLanguagesFunction +from dateparser.conf import Settings +from dateparser.date import DateData, DateDataParser, _DetectLanguagesFunction +from dateparser.languages.loader import LocaleDataLoader +from dateparser.languages.locale import Locale +from dateparser.search.text_detection import FullTextLanguageDetector + +@type_check_only +class _SearchDates(TypedDict): + Language: str | None + Dates: list[tuple[str, datetime.datetime]] | None RELATIVE_REG: Final[re.Pattern[str]] -def date_is_relative(translation): ... +def date_is_relative(translation: str) -> bool: ... class _ExactLanguageSearch: - loader: Incomplete - language: Incomplete - def __init__(self, loader) -> None: ... - def get_current_language(self, shortname) -> None: ... - def search(self, shortname, text, settings): ... + loader: LocaleDataLoader + language: Locale | None + def __init__(self, loader: LocaleDataLoader) -> None: ... + def get_current_language(self, shortname: str) -> None: ... + def search(self, shortname: str, text: str, settings: Settings | None) -> tuple[list[str], list[str]]: ... @staticmethod - def set_relative_base(substring, already_parsed): ... - def choose_best_split(self, possible_parsed_splits, possible_substrings_splits): ... - def split_by(self, item, original, splitter): ... - def split_if_not_parsed(self, item, original): ... - def parse_item(self, parser, item, translated_item, parsed, need_relative_base): ... - def parse_found_objects(self, parser, to_parse, original, translated, settings): ... - def search_parse(self, shortname, text, settings) -> list[tuple[Incomplete, Incomplete]]: ... + def set_relative_base( + substring: str, already_parsed: list[tuple[DateData, bool]] + ) -> tuple[str, datetime.datetime | None]: ... + def choose_best_split( + self, possible_parsed_splits: list[Incomplete], possible_substrings_splits: list[Incomplete] + ) -> tuple[Incomplete, Incomplete]: ... + def split_by(self, item: str, original: str, splitter: str) -> list[list[list[str]]]: ... + def split_if_not_parsed(self, item: str, original: str) -> list[list[list[str]]]: ... + def parse_item( + self, + parser: DateDataParser, + item: str, + translated_item: str, + parsed: list[tuple[DateData, bool]], + need_relative_base: bool | None, + ) -> tuple[DateData, bool]: ... + def parse_found_objects( + self, + parser: DateDataParser, + to_parse: Iterable[str], + original: Sequence[str], + translated: Sequence[str], + settings: Settings, + ) -> tuple[list[tuple[DateData, bool]], list[str]]: ... + def search_parse(self, shortname: str, text: str, settings: Settings) -> list[tuple[str, datetime.datetime]]: ... class DateSearchWithDetection: - loader: Incomplete - available_language_map: Incomplete - search: Incomplete + loader: LocaleDataLoader + available_language_map: OrderedDict[str, Locale] + search: _ExactLanguageSearch + language_detector: FullTextLanguageDetector def __init__(self) -> None: ... - language_detector: Incomplete def detect_language( - self, text, languages, settings=None, detect_languages_function: _DetectLanguagesFunction | None = None - ): ... + self, + text: str, + languages: list[str] | tuple[str, ...] | AbstractSet[str] | None, + settings: Settings | dict[str, Any] | None = None, + detect_languages_function: _DetectLanguagesFunction | None = None, + ) -> str | None: ... def search_dates( - self, text, languages=None, settings=None, detect_languages_function: _DetectLanguagesFunction | None = None - ): ... - def preprocess_text(self, text: str, languages: Collection[str]) -> str: ... + self, + text: str, + languages: list[str] | tuple[str, ...] | AbstractSet[str] | None = None, + settings: Settings | dict[str, Any] | None = None, + detect_languages_function: _DetectLanguagesFunction | None = None, + ) -> _SearchDates: ... + def preprocess_text(self, text: str, languages: Iterable[str] | None) -> str: ... diff --git a/stubs/dateparser/dateparser/search/text_detection.pyi b/stubs/dateparser/dateparser/search/text_detection.pyi index 4bf7991a58e7..fdbe298e2c0d 100644 --- a/stubs/dateparser/dateparser/search/text_detection.pyi +++ b/stubs/dateparser/dateparser/search/text_detection.pyi @@ -1,11 +1,10 @@ -from _typeshed import Incomplete - +from dateparser.conf import Settings +from dateparser.languages.locale import Locale from dateparser.search.detection import BaseLanguageDetector class FullTextLanguageDetector(BaseLanguageDetector): - languages: Incomplete - language_unique_chars: Incomplete - language_chars: Incomplete - def __init__(self, languages) -> None: ... - def get_unique_characters(self, settings) -> None: ... - def character_check(self, date_string, settings) -> None: ... + language_unique_chars: list[set[str]] + language_chars: list[set[str]] + def __init__(self, languages: list[Locale]) -> None: ... + def get_unique_characters(self, settings: Settings) -> None: ... + def character_check(self, date_string: str, settings: Settings) -> None: ... diff --git a/stubs/dateparser/dateparser/timezone_parser.pyi b/stubs/dateparser/dateparser/timezone_parser.pyi index ff86e7810c39..aed8a14628d3 100644 --- a/stubs/dateparser/dateparser/timezone_parser.pyi +++ b/stubs/dateparser/dateparser/timezone_parser.pyi @@ -1,24 +1,26 @@ -import pathlib import re from collections.abc import Generator from datetime import datetime, timedelta, tzinfo -from typing import Final +from pathlib import Path +from typing import Final, TypeVar + +_DateTimeT = TypeVar("_DateTimeT", bound=datetime) class StaticTzInfo(tzinfo): def __init__(self, name: str, offset: timedelta) -> None: ... def tzname(self, dt) -> str: ... def utcoffset(self, dt) -> timedelta: ... def dst(self, dt) -> timedelta: ... - def localize(self, dt: datetime, is_dst: bool = False) -> datetime: ... + def localize(self, dt: _DateTimeT, is_dst: bool = False) -> _DateTimeT: ... def __getinitargs__(self) -> tuple[str, timedelta]: ... def pop_tz_offset_from_string(date_string: str, as_offset: bool = True) -> tuple[str, StaticTzInfo | str | None]: ... def word_is_tz(word: str) -> bool: ... -def convert_to_local_tz(datetime_obj: datetime, datetime_tz_offset: timedelta) -> datetime: ... +def convert_to_local_tz(datetime_obj: _DateTimeT, datetime_tz_offset: timedelta) -> _DateTimeT: ... def build_tz_offsets(search_regex_parts: list[str]) -> Generator[tuple[str, dict[str, re.Pattern[str] | timedelta]]]: ... def get_local_tz_offset() -> timedelta: ... local_tz_offset: timedelta -CACHE_PATH: Final[pathlib.Path] +CACHE_PATH: Final[Path] current_hash: int | None diff --git a/stubs/dateparser/dateparser/utils/__init__.pyi b/stubs/dateparser/dateparser/utils/__init__.pyi index 43ee4205a32a..695d51a09400 100644 --- a/stubs/dateparser/dateparser/utils/__init__.pyi +++ b/stubs/dateparser/dateparser/utils/__init__.pyi @@ -1,8 +1,14 @@ +import datetime from _typeshed import MaybeNone from collections import OrderedDict from collections.abc import Mapping from logging import Logger -from typing import Any +from typing import Any, TypeVar + +from dateparser.conf import Settings + +_DateT = TypeVar("_DateT", bound=datetime.date) +_DateTimeT = TypeVar("_DateTimeT", bound=datetime.datetime) def strip_braces(date_string: str) -> str: ... def normalize_unicode(string: str, form: str = "NFKD") -> str: ... @@ -10,16 +16,16 @@ def combine_dicts( primary_dict: Mapping[Any, Any], supplementary_dict: Mapping[Any, Any] ) -> OrderedDict[str, str | list[Any]]: ... def find_date_separator(format: str) -> str | MaybeNone | None: ... -def localize_timezone(date_time, tz_string): ... -def apply_tzdatabase_timezone(date_time, pytz_string): ... -def apply_dateparser_timezone(utc_datetime, offset_or_timezone_abb): ... -def apply_timezone(date_time, tz_string): ... -def apply_timezone_from_settings(date_obj, settings): ... -def get_last_day_of_month(year, month): ... -def get_previous_leap_year(year): ... -def get_next_leap_year(year): ... -def set_correct_day_from_settings(date_obj, settings, current_day=None): ... -def set_correct_month_from_settings(date_obj, settings, current_month=None): ... +def localize_timezone(date_time: _DateTimeT, tz_string: str) -> _DateTimeT: ... +def apply_tzdatabase_timezone(date_time: _DateTimeT, pytz_string: str) -> _DateTimeT: ... +def apply_dateparser_timezone(utc_datetime: _DateTimeT, offset_or_timezone_abb) -> _DateTimeT | None: ... +def apply_timezone(date_time: _DateTimeT, tz_string: str) -> _DateTimeT: ... +def apply_timezone_from_settings(date_obj: _DateTimeT, settings: Settings | None) -> _DateTimeT: ... +def get_last_day_of_month(year: int, month: int) -> int: ... +def get_previous_leap_year(year: int) -> int: ... +def get_next_leap_year(year: int) -> int: ... +def set_correct_day_from_settings(date_obj: _DateT, settings: Settings, current_day: int | None = None) -> _DateT: ... +def set_correct_month_from_settings(date_obj: _DateT, settings: Settings, current_month: int | None = None) -> _DateT: ... def registry(cls): ... def get_logger() -> Logger: ... def setup_logging() -> None: ... diff --git a/stubs/dateparser/dateparser/utils/strptime.pyi b/stubs/dateparser/dateparser/utils/strptime.pyi index f2171fa58873..69d630a709d0 100644 --- a/stubs/dateparser/dateparser/utils/strptime.pyi +++ b/stubs/dateparser/dateparser/utils/strptime.pyi @@ -1,9 +1,14 @@ import re from datetime import datetime -from typing import Any, Final +from time import struct_time +from typing import Final, Protocol, type_check_only TIME_MATCHER: Final[re.Pattern[str]] MS_SEARCHER: Final[re.Pattern[str]] -def patch_strptime() -> Any: ... -def strptime(date_string, format) -> datetime: ... +@type_check_only +class _strptime_time(Protocol): + def __call__(self, data_string: str, format: str = "%a %b %d %H:%M:%S %Y") -> struct_time: ... + +def patch_strptime() -> _strptime_time: ... +def strptime(date_string: str, format: str) -> datetime: ... diff --git a/stubs/dateparser/dateparser/utils/time_spans.pyi b/stubs/dateparser/dateparser/utils/time_spans.pyi index a43a4963b0ea..61726ba82839 100644 --- a/stubs/dateparser/dateparser/utils/time_spans.pyi +++ b/stubs/dateparser/dateparser/utils/time_spans.pyi @@ -1,8 +1,10 @@ -from datetime import date, datetime -from typing import TypedDict, overload, type_check_only +import datetime +from typing import TypedDict, TypeVar, type_check_only from typing_extensions import NotRequired -from dateparser import _Settings +from dateparser.conf import Settings + +_DateT = TypeVar("_DateT", bound=datetime.date) @type_check_only class _SpanInformation(TypedDict): @@ -13,20 +15,9 @@ class _SpanInformation(TypedDict): end_pos: int number: NotRequired[int] -@overload -def get_week_start(date: datetime, start_of_week: str = "monday") -> datetime: ... -@overload -def get_week_start(date: date, start_of_week: str = "monday") -> date: ... -@overload -def get_week_end(date: datetime, start_of_week: str = "monday") -> datetime: ... -@overload -def get_week_end(date: date, start_of_week: str = "monday") -> date: ... +def get_week_start(date: _DateT, start_of_week: str = "monday") -> _DateT: ... +def get_week_end(date: _DateT, start_of_week: str = "monday") -> _DateT: ... def detect_time_span(text: str) -> _SpanInformation | None: ... -@overload -def generate_time_span( - span_info: _SpanInformation, base_date: datetime | None = None, settings: _Settings | None = None -) -> tuple[datetime, datetime]: ... -@overload def generate_time_span( - span_info: _SpanInformation, base_date: date = ..., settings: _Settings | None = None -) -> tuple[date, date]: ... + span_info: _SpanInformation, base_date: _DateT | None = None, settings: Settings | None = None +) -> tuple[_DateT, _DateT]: ... diff --git a/stubs/dateparser/dateparser_data/settings.pyi b/stubs/dateparser/dateparser_data/settings.pyi index bc4d69704e4a..42d65ec2bca0 100644 --- a/stubs/dateparser/dateparser_data/settings.pyi +++ b/stubs/dateparser/dateparser_data/settings.pyi @@ -1,4 +1,6 @@ from typing import Final +from dateparser import _Settings + default_parsers: Final[list[str]] -settings: Final[dict[str, str | bool | list[str] | float | int]] +settings: Final[_Settings]