From 889e65f44cea6550070a7593c28a59f5a1973cc2 Mon Sep 17 00:00:00 2001 From: Brock Date: Sun, 14 Mar 2021 11:15:58 -0700 Subject: [PATCH 1/2] TYP: stubs for tslibs --- pandas/_libs/tslibs/ccalendar.pyi | 13 ++++++++ pandas/_libs/tslibs/strptime.pyi | 11 +++++++ pandas/_libs/tslibs/strptime.pyx | 3 +- pandas/_libs/tslibs/timezones.pyi | 32 +++++++++++++++++++ pandas/_libs/tslibs/timezones.pyx | 5 +++ pandas/_libs/tslibs/tzconversion.pyi | 25 +++++++++++++++ pandas/_libs/tslibs/vectorized.pyi | 47 ++++++++++++++++++++++++++++ pandas/core/tools/datetimes.py | 6 ++-- 8 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 pandas/_libs/tslibs/ccalendar.pyi create mode 100644 pandas/_libs/tslibs/strptime.pyi create mode 100644 pandas/_libs/tslibs/timezones.pyi create mode 100644 pandas/_libs/tslibs/tzconversion.pyi create mode 100644 pandas/_libs/tslibs/vectorized.pyi diff --git a/pandas/_libs/tslibs/ccalendar.pyi b/pandas/_libs/tslibs/ccalendar.pyi new file mode 100644 index 0000000000000..500a0423bc9cf --- /dev/null +++ b/pandas/_libs/tslibs/ccalendar.pyi @@ -0,0 +1,13 @@ + +DAYS: list[str] +MONTH_ALIASES: dict[int, str] +MONTH_NUMBERS: dict[str, int] +MONTHS: list[str] +int_to_weekday: dict[int, str] + +def get_firstbday(year: int, month: int) -> int: ... +def get_lastbday(year: int, month: int) -> int: ... +def get_day_of_year(year: int, month: int, day: int) -> int: ... +def get_iso_calendar(year: int, month: int, day: int) -> tuple[int, int, int]: ... +def get_week_of_year(year: int, month: int, day: int) -> int: ... +def get_days_in_month(year: int, month: int) -> int: ... diff --git a/pandas/_libs/tslibs/strptime.pyi b/pandas/_libs/tslibs/strptime.pyi new file mode 100644 index 0000000000000..3748c169bb1c6 --- /dev/null +++ b/pandas/_libs/tslibs/strptime.pyi @@ -0,0 +1,11 @@ +from typing import Optional + +import numpy as np + +def array_strptime( + values: np.ndarray, # np.ndarray[object] + fmt: Optional[str], + exact: bool = True, + errors: str = "raise" +) -> tuple[np.ndarray, np.ndarray]: ... +# first ndarray is M8[ns], second is object ndarray of Optional[tzinfo] diff --git a/pandas/_libs/tslibs/strptime.pyx b/pandas/_libs/tslibs/strptime.pyx index ffa29b44a366a..14c3a90dbd19b 100644 --- a/pandas/_libs/tslibs/strptime.pyx +++ b/pandas/_libs/tslibs/strptime.pyx @@ -78,11 +78,12 @@ def array_strptime(ndarray[object] values, object fmt, bint exact=True, errors=' int week_of_year, week_of_year_start, parse_code, ordinal int iso_week, iso_year int64_t us, ns - object val, group_key, ampm, found, timezone + object val, group_key, ampm, found dict found_key bint is_raise = errors=='raise' bint is_ignore = errors=='ignore' bint is_coerce = errors=='coerce' + tzinfo timezone assert is_raise or is_ignore or is_coerce diff --git a/pandas/_libs/tslibs/timezones.pyi b/pandas/_libs/tslibs/timezones.pyi new file mode 100644 index 0000000000000..04a1b391dc30a --- /dev/null +++ b/pandas/_libs/tslibs/timezones.pyi @@ -0,0 +1,32 @@ +from datetime import ( + datetime, + tzinfo, +) +from typing import ( + Callable, + Optional, + Union, +) + +import numpy as np + +# imported from dateutil.tz +dateutil_gettz: Callable[[str], tzinfo] + + +def tz_standardize(tz: tzinfo) -> tzinfo: ... + +def tz_compare(start: Optional[tzinfo], end: Optional[tzinfo]) -> bool: ... + +def infer_tzinfo( + start: Optional[datetime], end: Optional[datetime], +) -> Optional[tzinfo]: ... + +# ndarrays returned are both int64_t +def get_dst_info(tz: tzinfo) -> tuple[np.ndarray, np.ndarray, str]: ... + +def maybe_get_tz(tz: Optional[Union[str, int, np.int64, tzinfo]]) -> Optional[tzinfo]: ... + +def get_timezone(tz: tzinfo) -> Union[tzinfo, str]: ... + +def is_utc(tz: Optional[tzinfo]) -> bool: ... diff --git a/pandas/_libs/tslibs/timezones.pyx b/pandas/_libs/tslibs/timezones.pyx index 92065e1c3d4c5..0809033b02934 100644 --- a/pandas/_libs/tslibs/timezones.pyx +++ b/pandas/_libs/tslibs/timezones.pyx @@ -67,6 +67,7 @@ cdef inline bint treat_tz_as_dateutil(tzinfo tz): return hasattr(tz, '_trans_list') and hasattr(tz, '_trans_idx') +# Returns str or tzinfo object cpdef inline object get_timezone(tzinfo tz): """ We need to do several things here: @@ -80,6 +81,8 @@ cpdef inline object get_timezone(tzinfo tz): the tz name. It needs to be a string so that we can serialize it with UJSON/pytables. maybe_get_tz (below) is the inverse of this process. """ + if tz is None: + raise TypeError("tz argument cannot be None") if is_utc(tz): return tz else: @@ -364,6 +367,8 @@ cpdef bint tz_compare(tzinfo start, tzinfo end): elif is_utc(end): # Ensure we don't treat tzlocal as equal to UTC when running in UTC return False + elif start is None or end is None: + return start is None and end is None return get_timezone(start) == get_timezone(end) diff --git a/pandas/_libs/tslibs/tzconversion.pyi b/pandas/_libs/tslibs/tzconversion.pyi new file mode 100644 index 0000000000000..f47885a2e3306 --- /dev/null +++ b/pandas/_libs/tslibs/tzconversion.pyi @@ -0,0 +1,25 @@ +from datetime import ( + timedelta, + tzinfo, +) +from typing import ( + Iterable, + Optional, + Union, +) + +import numpy as np + +def tz_convert_from_utc( + vals: np.ndarray, # const int64_t[:] + tz: tzinfo, +) -> np.ndarray: ... # np.ndarray[np.int64] + +def tz_convert_from_utc_single(val: np.int64, tz: tzinfo) -> np.int64: ... + +def tz_localize_to_utc( + vals: np.ndarray, # np.ndarray[np.int64] + tz: Optional[tzinfo], + ambiguous: Optional[Union[str, bool, Iterable[bool]]] = None, + nonexistent: Optional[Union[str, timedelta, np.timedelta64]] = None, +) -> np.ndarray: ... # np.ndarray[np.int64] diff --git a/pandas/_libs/tslibs/vectorized.pyi b/pandas/_libs/tslibs/vectorized.pyi new file mode 100644 index 0000000000000..6ed1e10ef2353 --- /dev/null +++ b/pandas/_libs/tslibs/vectorized.pyi @@ -0,0 +1,47 @@ +""" +For cython types that cannot be represented precisely, closest-available +python equivalents are used, and the precise types kept as adjacent comments. +""" +from datetime import tzinfo +from typing import ( + Optional, + Union, +) + +import numpy as np + +from pandas._libs.tslibs.dtypes import Resolution +from pandas._libs.tslibs.offsets import BaseOffset + +def dt64arr_to_periodarr( + stamps: np.ndarray, # const int64_t[:] + freq: int, + tz: Optional[tzinfo], +) -> np.ndarray: ... # np.ndarray[np.int64, ndim=1] + + +def is_date_array_normalized( + stamps: np.ndarray, # const int64_t[:] + tz: Optional[tzinfo] = None, +) -> bool: ... + + +def normalize_i8_timestamps( + stamps: np.ndarray, # const int64_t[:] + tz: Optional[tzinfo], +) -> np.ndarray: ... # np.ndarray[np.int64] + + +def get_resolution( + stamps: np.ndarray, # const int64_t[:] + tz: Optional[tzinfo] = None, +) -> Resolution: ... + + +def ints_to_pydatetime( + arr: np.ndarray, # const int64_t[:}] + tz: Optional[tzinfo] = None, + freq: Optional[Union[str, BaseOffset]] = None, + fold: bool = False, + box: str = "datetime", +) -> np.ndarray: ... # np.ndarray[object] diff --git a/pandas/core/tools/datetimes.py b/pandas/core/tools/datetimes.py index 9822356d11d7c..ba238e2b789f0 100644 --- a/pandas/core/tools/datetimes.py +++ b/pandas/core/tools/datetimes.py @@ -285,7 +285,7 @@ def _convert_listlike_datetimes( name: Hashable = None, tz: Optional[Timezone] = None, unit: Optional[str] = None, - errors: Optional[str] = None, + errors: str = "raise", infer_datetime_format: bool = False, dayfirst: Optional[bool] = None, yearfirst: Optional[bool] = None, @@ -428,7 +428,7 @@ def _array_strptime_with_fallback( tz, fmt: str, exact: bool, - errors: Optional[str], + errors: str, infer_datetime_format: bool, ) -> Optional[Index]: """ @@ -476,7 +476,7 @@ def _to_datetime_with_format( tz, fmt: str, exact: bool, - errors: Optional[str], + errors: str, infer_datetime_format: bool, ) -> Optional[Index]: """ From 229a13a1b16d876b447d031eb5a862d6670e1c65 Mon Sep 17 00:00:00 2001 From: Brock Date: Sun, 14 Mar 2021 12:39:16 -0700 Subject: [PATCH 2/2] revert strptime --- pandas/_libs/tslibs/strptime.pyx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pandas/_libs/tslibs/strptime.pyx b/pandas/_libs/tslibs/strptime.pyx index 14c3a90dbd19b..ffa29b44a366a 100644 --- a/pandas/_libs/tslibs/strptime.pyx +++ b/pandas/_libs/tslibs/strptime.pyx @@ -78,12 +78,11 @@ def array_strptime(ndarray[object] values, object fmt, bint exact=True, errors=' int week_of_year, week_of_year_start, parse_code, ordinal int iso_week, iso_year int64_t us, ns - object val, group_key, ampm, found + object val, group_key, ampm, found, timezone dict found_key bint is_raise = errors=='raise' bint is_ignore = errors=='ignore' bint is_coerce = errors=='coerce' - tzinfo timezone assert is_raise or is_ignore or is_coerce