From 80a60f344972470528c4c8c18ca4ae9a78df2992 Mon Sep 17 00:00:00 2001 From: Bryan Forbes Date: Fri, 30 Nov 2018 11:02:38 -0600 Subject: [PATCH 1/2] Update typing comments and add py.typed for PEP-561 compliance --- pendulum/__init__.py | 24 ++++----- pendulum/_extensions/helpers.py | 21 +++++--- pendulum/datetime.py | 26 +++++---- pendulum/formatting/difference_formatter.py | 7 ++- pendulum/formatting/formatter.py | 26 +++++---- pendulum/helpers.py | 59 ++++++++++++++++----- pendulum/locales/locale.py | 17 +++--- pendulum/parser.py | 3 +- pendulum/py.typed | 0 pendulum/tz/__init__.py | 8 +-- pendulum/tz/local_timezone.py | 6 +-- pendulum/tz/timezone.py | 57 +++++++++++--------- pendulum/tz/zoneinfo/__init__.py | 4 +- pendulum/tz/zoneinfo/posix_timezone.py | 20 +++---- pendulum/tz/zoneinfo/reader.py | 16 +++--- pendulum/tz/zoneinfo/timezone.py | 4 +- pendulum/tz/zoneinfo/transition.py | 8 +-- pyproject.toml | 1 + 18 files changed, 186 insertions(+), 121 deletions(-) create mode 100644 pendulum/py.typed diff --git a/pendulum/__init__.py b/pendulum/__init__.py index 2dcac7ac..d38b69bc 100644 --- a/pendulum/__init__.py +++ b/pendulum/__init__.py @@ -1,7 +1,7 @@ from __future__ import absolute_import import datetime as _datetime -from typing import Union +from typing import Union, Optional from .__version__ import __version__ @@ -59,7 +59,7 @@ SECONDS_PER_DAY, ) -_TEST_NOW = None +_TEST_NOW = None # type: Optional[DateTime] _LOCALE = "en" _WEEK_STARTS_AT = MONDAY _WEEK_ENDS_AT = SUNDAY @@ -68,7 +68,7 @@ def _safe_timezone(obj): - # type: (Union[str, int, float, _datetime.tzinfo]) -> _Timezone + # type: (Optional[Union[str, float, _datetime.tzinfo, _Timezone]]) -> _Timezone """ Creates a timezone instance from a string, Timezone, TimezoneInfo or integer offset. @@ -105,7 +105,7 @@ def datetime( minute=0, # type: int second=0, # type: int microsecond=0, # type: int - tz=UTC, # type: Union[str, _Timezone] + tz=UTC, # type: Optional[Union[str, float, _Timezone]] dst_rule=POST_TRANSITION, # type: str ): # type: (...) -> DateTime """ @@ -169,8 +169,8 @@ def time(hour, minute=0, second=0, microsecond=0): # type: (int, int, int, int) def instance( - dt, tz=UTC # type: _datetime.datetime # type: Union[str, _Timezone, None] -): # type: (...) -> DateTime + dt, tz=UTC +): # type: (_datetime.datetime, Optional[Union[str, _Timezone]]) -> DateTime """ Create a DateTime instance from a datetime one. """ @@ -198,7 +198,7 @@ def instance( ) -def now(tz=None): # type: (Union[str, _Timezone, None]) -> DateTime +def now(tz=None): # type: (Optional[Union[str, _Timezone]]) -> DateTime """ Get a DateTime instance for the current date and time. """ @@ -248,7 +248,7 @@ def from_format( string, # type: str fmt, # type: str tz=UTC, # type: Union[str, _Timezone] - locale=None, # type: Union[str, None] + locale=None, # type: Optional[str] ): # type: (...) -> DateTime """ Creates a DateTime instance from a specific format. @@ -261,8 +261,8 @@ def from_format( def from_timestamp( - timestamp, tz=UTC # type: Union[int, float] # type: Union[str, _Timezone] -): # type: (...) -> DateTime + timestamp, tz=UTC +): # type: (Union[int, float], Union[str, _Timezone]) -> DateTime """ Create a DateTime instance from a timestamp. """ @@ -305,9 +305,7 @@ def duration( ) -def period( - start, end, absolute=False # type: DateTime # type: DateTime # type: bool -): # type: (...) -> Period +def period(start, end, absolute=False): # type: (DateTime, DateTime, bool) -> Period """ Create a Period instance. """ diff --git a/pendulum/_extensions/helpers.py b/pendulum/_extensions/helpers.py index 7bcf31ec..1578f97e 100644 --- a/pendulum/_extensions/helpers.py +++ b/pendulum/_extensions/helpers.py @@ -2,6 +2,7 @@ from collections import namedtuple import datetime +import typing from ..constants import ( EPOCH_YEAR, @@ -48,18 +49,18 @@ def __repr__(self): ) -def is_leap(year): +def is_leap(year): # type: (int) -> bool return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0) -def is_long_year(year): +def is_long_year(year): # type: (int) -> bool def p(y): return y + y // 4 - y // 100 + y // 400 return p(year) % 7 == 4 or p(year - 1) % 7 == 3 -def week_day(year, month, day): +def week_day(year, month, day): # type: (int, int, int) -> int if month < 3: year -= 1 @@ -78,14 +79,14 @@ def week_day(year, month, day): return w -def days_in_year(year): +def days_in_year(year): # type: (int) -> int if is_leap(year): return DAYS_PER_L_YEAR return DAYS_PER_N_YEAR -def timestamp(dt): # type: (datetime) -> int +def timestamp(dt): # type: (datetime.datetime) -> int year = dt.year result = (year - 1970) * 365 + MONTHS_OFFSETS[0][dt.month] @@ -107,7 +108,9 @@ def timestamp(dt): # type: (datetime) -> int return result -def local_time(unix_time, utc_offset, microseconds): +def local_time( + unix_time, utc_offset, microseconds +): # type: (int, int, int) -> typing.Tuple[int, int, int, int, int, int, int] """ Returns a UNIX time as a broken down time for a particular transition type. @@ -182,7 +185,9 @@ def local_time(unix_time, utc_offset, microseconds): return (year, month, day, hour, minute, second, microseconds) -def precise_diff(d1, d2): +def precise_diff( + d1, d2 +): # type: (typing.Union[datetime.datetime, datetime.date], typing.Union[datetime.datetime, datetime.date]) -> PreciseDiff """ Calculate a precise difference between two datetimes. @@ -341,7 +346,7 @@ def precise_diff(d1, d2): ) -def _day_number(year, month, day): +def _day_number(year, month, day): # type: (int, int, int) -> int month = (month + 9) % 12 year = year - month // 10 diff --git a/pendulum/datetime.py b/pendulum/datetime.py index abca24a8..945a3ec1 100644 --- a/pendulum/datetime.py +++ b/pendulum/datetime.py @@ -6,7 +6,7 @@ import datetime import pendulum -from typing import Union +from typing import Union, Optional, TypeVar from .date import Date from .time import Time @@ -37,9 +37,13 @@ W3C, ) +_D = TypeVar("_D", bound="DateTime") + class DateTime(datetime.datetime, Date): + EPOCH = None # type: DateTime + # Formats _FORMATS = { @@ -93,7 +97,7 @@ def __new__( return self @classmethod - def now(cls, tz=None): # type: (Union[str, Timezone, None]) -> DateTime + def now(cls, tz=None): # type: (Optional[Union[str, Timezone]]) -> DateTime """ Get a DateTime instance for the current date and time. """ @@ -214,21 +218,21 @@ def offset_hours(self): return self.get_offset() / SECONDS_PER_MINUTE / MINUTES_PER_HOUR @property - def timezone(self): # type: () -> Union[str, None] + def timezone(self): # type: () -> Optional[Timezone] if not isinstance(self.tzinfo, Timezone): return return self.tzinfo @property - def tz(self): # type: () -> Union[str, None] + def tz(self): # type: () -> Optional[Timezone] return self.timezone @property - def timezone_name(self): # type: () -> Union[str, None] + def timezone_name(self): # type: () -> Optional[str] tz = self.timezone - if self.timezone is None: + if tz is None: return None return tz.name @@ -255,7 +259,7 @@ def date(self): def time(self): return Time(self.hour, self.minute, self.second, self.microsecond) - def naive(self): # type: () -> DateTime + def naive(self): # type: (_D) -> _D """ Return the DateTime without timezone information. """ @@ -597,7 +601,7 @@ def add( minutes=0, seconds=0, microseconds=0, - ): # type: (int, int, int, int, int, int, int) -> DateTime + ): # type: (_D, int, int, int, int, int, int, int, int) -> _D """ Add a duration to the instance. @@ -794,10 +798,10 @@ def diff(self, dt=None, abs=True): def diff_for_humans( self, - other=None, # type: Union['DateTime', None] + other=None, # type: Optional[DateTime] absolute=False, # type: bool - locale=None, # type:Union[str, None] - ): # type: (...) -> False + locale=None, # type: Optional[str] + ): # type: (...) -> str """ Get the difference in a human readable format in the current locale. diff --git a/pendulum/formatting/difference_formatter.py b/pendulum/formatting/difference_formatter.py index 58d3876b..7ab6a73d 100644 --- a/pendulum/formatting/difference_formatter.py +++ b/pendulum/formatting/difference_formatter.py @@ -1,6 +1,9 @@ from pendulum.utils._compat import decode from ..locales.locale import Locale +from ..period import Period + +import typing class DifferenceFormatter(object): @@ -11,7 +14,9 @@ class DifferenceFormatter(object): def __init__(self, locale="en"): self._locale = Locale.load(locale) - def format(self, diff, is_now=True, absolute=False, locale=None): + def format( + self, diff, is_now=True, absolute=False, locale=None + ): # type: (Period, bool, bool, typing.Optional[str]) -> str """ Formats a difference. diff --git a/pendulum/formatting/formatter.py b/pendulum/formatting/formatter.py index b41873ca..d400c287 100644 --- a/pendulum/formatting/formatter.py +++ b/pendulum/formatting/formatter.py @@ -229,7 +229,9 @@ class Formatter: "z": str, } - def format(self, dt, fmt, locale=None): + def format( + self, dt, fmt, locale=None + ): # type: (pendulum.DateTime, str, typing.Optional[typing.Union[str, Locale]]) -> str """ Formats a DateTime instance with a given format and locale. @@ -260,7 +262,9 @@ def format(self, dt, fmt, locale=None): return decode(result) - def _format_token(self, dt, token, locale): + def _format_token( + self, dt, token, locale + ): # type: (pendulum.DateTime, str, Locale) -> str """ Formats a DateTime instance with a given token and locale. @@ -306,7 +310,9 @@ def _format_token(self, dt, token, locale): return "{}{:02d}{}{:02d}".format(sign, hour, separator, minute) - def _format_localizable_token(self, dt, token, locale): + def _format_localizable_token( + self, dt, token, locale + ): # type: (pendulum.DateTime, str, Locale) -> str """ Formats a DateTime instance with a given localizable token and locale. @@ -360,8 +366,8 @@ def parse( time, # type: str fmt, # type: str now, # type: pendulum.DateTime - locale=None, # type: typing.Union[str, None] - ): # type: (...) -> dict + locale=None, # type: typing.Optional[str] + ): # type: (...) -> typing.Dict[str, typing.Any] """ Parses a time string matching a given format as a tuple. @@ -410,7 +416,9 @@ def parse( return self._check_parsed(parsed, now) - def _check_parsed(self, parsed, now): # type: (dict, pendulum.DateTime) -> dict + def _check_parsed( + self, parsed, now + ): # type: (typing.Dict[str, typing.Any], pendulum.DateTime) -> typing.Dict[str, typing.Any] """ Checks validity of parsed elements. @@ -530,7 +538,7 @@ def _check_parsed(self, parsed, now): # type: (dict, pendulum.DateTime) -> dict def _get_parsed_values( self, m, parsed, locale, now - ): # type: (..., dict, Locale, pendulum.DateTime) -> None + ): # type: (typing.Match[str], typing.Dict[str, typing.Any], Locale, pendulum.DateTime) -> None for token, index in m.re.groupindex.items(): if token in self._LOCALIZABLE_TOKENS: self._get_parsed_locale_value(token, m.group(index), parsed, locale) @@ -539,7 +547,7 @@ def _get_parsed_values( def _get_parsed_value( self, token, value, parsed, now - ): # type: (str, str, dict, pendulum.DateTime) -> None + ): # type: (str, str, typing.Dict[str, typing.Any], pendulum.DateTime) -> None parsed_token = self._PARSE_TOKENS[token](value) if "Y" in token: @@ -599,7 +607,7 @@ def _get_parsed_value( def _get_parsed_locale_value( self, token, value, parsed, locale - ): # type: (str, str, dict, Locale) -> None + ): # type: (str, str, typing.Dict[str, typing.Any], Locale) -> None if token == "MMMM": unit = "month" match = "months.wide" diff --git a/pendulum/helpers.py b/pendulum/helpers.py index 5085a38b..dc87ce57 100644 --- a/pendulum/helpers.py +++ b/pendulum/helpers.py @@ -7,10 +7,17 @@ from math import copysign from datetime import datetime, date, timedelta from contextlib import contextmanager -from typing import Union +from typing import TYPE_CHECKING, Union, Optional, TypeVar, Iterator, overload + +if TYPE_CHECKING: + # Prevent import cycles + from .period import Period with_extensions = os.getenv("PENDULUM_EXTENSIONS", "1") == "1" +_DT = TypeVar("_DT", bound=datetime) +_D = TypeVar("_D", bound=date) + try: if not with_extensions or struct.calcsize("P") == 4: raise ImportError() @@ -43,8 +50,9 @@ difference_formatter = DifferenceFormatter() +@overload def add_duration( - dt, # type: Union[datetime, date] + dt, # type: _DT years=0, # type: int months=0, # type: int weeks=0, # type: int @@ -52,8 +60,33 @@ def add_duration( hours=0, # type: int minutes=0, # type: int seconds=0, # type: int + microseconds=0, # type: int +): # type: (...) -> _DT + ... + + +@overload +def add_duration( + dt, # type: _D + years=0, # type: int + months=0, # type: int + weeks=0, # type: int + days=0, # type: int +): # type: (...) -> _D + ... + + +def add_duration( + dt, + years=0, + months=0, + weeks=0, + days=0, + hours=0, + minutes=0, + seconds=0, microseconds=0, -): # type: (...) -> Union[datetime, date] +): """ Adds a duration to a date/datetime instance. """ @@ -122,7 +155,9 @@ def add_duration( ) -def format_diff(diff, is_now=True, absolute=False, locale=None): +def format_diff( + diff, is_now=True, absolute=False, locale=None +): # type: (Period, bool, bool, Optional[str]) -> str if locale is None: locale = get_locale() @@ -137,7 +172,7 @@ def _sign(x): @contextmanager -def test(mock): +def test(mock): # type: (pendulum.DateTime) -> Iterator[None] set_test_now(mock) yield @@ -145,11 +180,11 @@ def test(mock): set_test_now() -def set_test_now(test_now=None): +def set_test_now(test_now=None): # type: (Optional[pendulum.DateTime]) -> None pendulum._TEST_NOW = test_now -def get_test_now(): # type: () -> pendulum.DateTime +def get_test_now(): # type: () -> Optional[pendulum.DateTime] return pendulum._TEST_NOW @@ -157,28 +192,28 @@ def has_test_now(): # type: () -> bool return pendulum._TEST_NOW is not None -def locale(name): +def locale(name): # type: (str) -> Locale return Locale.load(name) -def set_locale(name): +def set_locale(name): # type: (str) -> None locale(name) pendulum._LOCALE = name -def get_locale(): +def get_locale(): # type: () -> str return pendulum._LOCALE -def week_starts_at(wday): +def week_starts_at(wday): # type: (int) -> None if wday < pendulum.SUNDAY or wday > pendulum.SATURDAY: raise ValueError("Invalid week day as start of week.") pendulum._WEEK_STARTS_AT = wday -def week_ends_at(wday): +def week_ends_at(wday): # type: (int) -> None if wday < pendulum.SUNDAY or wday > pendulum.SATURDAY: raise ValueError("Invalid week day as start of week.") diff --git a/pendulum/locales/locale.py b/pendulum/locales/locale.py index 84429112..2ce0694f 100644 --- a/pendulum/locales/locale.py +++ b/pendulum/locales/locale.py @@ -3,6 +3,7 @@ import os import re +from typing import Union, Optional, Any from importlib import import_module from pendulum.utils._compat import basestring @@ -16,13 +17,13 @@ class Locale: _cache = {} - def __init__(self, locale, data): + def __init__(self, locale, data): # type: (str, Any) -> None self._locale = locale self._data = data self._key_cache = {} @classmethod - def load(cls, locale): + def load(cls, locale): # type: (Union[str, Locale]) -> Locale if isinstance(locale, Locale): return locale @@ -46,14 +47,14 @@ def load(cls, locale): return cls._cache[locale] @classmethod - def normalize_locale(cls, locale): + def normalize_locale(cls, locale): # type: (str) -> str m = re.match("([a-z]{2})[-_]([a-z]{2})", locale, re.I) if m: return "{}_{}".format(m.group(1).lower(), m.group(2).lower()) else: return locale.lower() - def get(self, key, default=None): + def get(self, key, default=None): # type: (str, Optional[Any]) -> Any if key in self._key_cache: return self._key_cache[key] @@ -72,16 +73,16 @@ def get(self, key, default=None): return self._key_cache[key] - def translation(self, key): + def translation(self, key): # type: (str) -> Any return self.get("translations.{}".format(key)) - def plural(self, number): + def plural(self, number): # type: (int) -> str return decode(self._data["plural"](number)) - def ordinal(self, number): + def ordinal(self, number): # type: (int) -> str return decode(self._data["ordinal"](number)) - def ordinalize(self, number): + def ordinalize(self, number): # type: (int) -> str ordinal = self.get("custom.ordinal.{}".format(self.ordinal(number))) if not ordinal: diff --git a/pendulum/parser.py b/pendulum/parser.py index a19907cf..624ee577 100644 --- a/pendulum/parser.py +++ b/pendulum/parser.py @@ -2,6 +2,7 @@ import pendulum import datetime +import typing from .parsing import parse as base_parse, _Interval @@ -13,7 +14,7 @@ from .tz import UTC -def parse(text, **options): +def parse(text, **options): # type: (str, **typing.Any) -> str # Use the mock now value if it exists options["now"] = options.get("now", pendulum.get_test_now()) diff --git a/pendulum/py.typed b/pendulum/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/pendulum/tz/__init__.py b/pendulum/tz/__init__.py index 74ba7820..cf09e135 100644 --- a/pendulum/tz/__init__.py +++ b/pendulum/tz/__init__.py @@ -1,6 +1,6 @@ import pytzdata -from typing import Union +from typing import Union, Tuple from .local_timezone import get_local_timezone from .local_timezone import set_local_timezone @@ -14,13 +14,13 @@ POST_TRANSITION = "post" TRANSITION_ERROR = "error" -timezones = pytzdata.timezones +timezones = pytzdata.timezones # type: Tuple[str, ...] _tz_cache = {} -def timezone(name, extended=True): # type: (Union[str, int]) -> _Timezone +def timezone(name, extended=True): # type: (Union[str, int], bool) -> _Timezone """ Return a Timezone instance given its name. """ @@ -44,7 +44,7 @@ def fixed_timezone(offset): # type: (int) -> _FixedTimezone Return a Timezone instance given its offset in seconds. """ if offset in _tz_cache: - return _tz_cache[offset] + return _tz_cache[offset] # type: ignore tz = _FixedTimezone(offset) _tz_cache[offset] = tz diff --git a/pendulum/tz/local_timezone.py b/pendulum/tz/local_timezone.py index ca094f77..1bbbf38c 100644 --- a/pendulum/tz/local_timezone.py +++ b/pendulum/tz/local_timezone.py @@ -11,7 +11,7 @@ winreg = None from contextlib import contextmanager -from typing import Union +from typing import Optional, Union, Iterator from .timezone import Timezone, TimezoneFile from .zoneinfo.exceptions import InvalidTimezone @@ -35,14 +35,14 @@ def get_local_timezone(): # type: () -> Timezone return _local_timezone -def set_local_timezone(mock=None): # type: (Union[str, Timezone, None]) -> None +def set_local_timezone(mock=None): # type: (Optional[Union[str, Timezone]]) -> None global _mock_local_timezone _mock_local_timezone = mock @contextmanager -def test_local_timezone(mock): # type: (Timezone) -> None +def test_local_timezone(mock): # type: (Timezone) -> Iterator[None] set_local_timezone(mock) yield diff --git a/pendulum/tz/timezone.py b/pendulum/tz/timezone.py index a79242ed..e3f1406e 100644 --- a/pendulum/tz/timezone.py +++ b/pendulum/tz/timezone.py @@ -1,7 +1,7 @@ import pendulum from datetime import datetime, timedelta, tzinfo -from typing import Optional, Union +from typing import Optional, TypeVar, overload from pendulum.helpers import local_time, timestamp from pendulum.utils._compat import _HAS_FOLD @@ -15,6 +15,9 @@ PRE_TRANSITION = "pre" TRANSITION_ERROR = "error" +_datetime = datetime +_D = TypeVar("_D", bound=datetime) + class Timezone(tzinfo): """ @@ -26,7 +29,7 @@ class Timezone(tzinfo): >>> tz = Timezone('Europe/Paris') """ - def __init__(self, name, extended=True): # type: (str) -> None + def __init__(self, name, extended=True): # type: (str, bool) -> None tz = read(name, extend=extended) self._name = name @@ -37,9 +40,7 @@ def __init__(self, name, extended=True): # type: (str) -> None def name(self): # type: () -> str return self._name - def convert( - self, dt, dst_rule=None # type: datetime # type: Union[str, None] - ): # type: (...) -> datetime + def convert(self, dt, dst_rule=None): # type: (_D, Optional[str]) -> _D """ Converts a datetime in the current timezone. @@ -67,7 +68,7 @@ def convert( def datetime( self, year, month, day, hour=0, minute=0, second=0, microsecond=0 - ): # type: (int, int, int, int, int, int, int) -> datetime + ): # type: (int, int, int, int, int, int, int) -> _datetime """ Return a normalized datetime for the current timezone. """ @@ -81,9 +82,7 @@ def datetime( dst_rule=POST_TRANSITION, ) - def _normalize( - self, dt, dst_rule=None # type: datetime # type: Union[str, None] - ): # type: (...) -> datetime + def _normalize(self, dt, dst_rule=None): # type: (_D, Optional[str]) -> _D sec = timestamp(dt) fold = 0 transition = self._lookup_transition(sec) @@ -134,7 +133,7 @@ def _normalize( return dt.__class__(*local_time(sec, 0, dt.microsecond), **kwargs) - def _convert(self, dt): # type: (datetime) -> datetime + def _convert(self, dt): # type: (_D) -> _D if dt.tzinfo is self: return self._normalize(dt, dst_rule=POST_TRANSITION) @@ -176,8 +175,8 @@ def _convert(self, dt): # type: (datetime) -> datetime return dt.__class__(*local_time(stamp, 0, dt.microsecond), **kwargs) def _lookup_transition( - self, stamp, is_utc=False # type: int # type: bool - ): # type: (...) -> Transition + self, stamp, is_utc=False + ): # type: (int, bool) -> Transition lo, hi = 0, len(self._transitions) hint = self._hint[is_utc] if hint: @@ -211,9 +210,15 @@ def _lookup_transition( return self._transitions[lo] - def utcoffset( - self, dt # type: Optional[datetime] - ): # type: (...) -> Union[timedelta, None] + @overload + def utcoffset(self, dt): # type: (None) -> None + ... + + @overload + def utcoffset(self, dt): # type: (_datetime) -> timedelta + ... + + def utcoffset(self, dt): if dt is None: return @@ -222,8 +227,8 @@ def utcoffset( return transition.utcoffset() def dst( - self, dt # type: Optional[datetime] - ): # type: (...) -> Union[timedelta, None] + self, dt # type: Optional[_datetime] + ): # type: (...) -> Optional[timedelta] if dt is None: return @@ -234,7 +239,7 @@ def dst( return timedelta(seconds=transition.fix) - def tzname(self, dt): # type: Optional[datetime] # type: (...) -> Union[str, None] + def tzname(self, dt): # type: (Optional[_datetime]) -> Optional[str] if dt is None: return @@ -242,7 +247,7 @@ def tzname(self, dt): # type: Optional[datetime] # type: (...) -> Union[str, N return transition.ttype.abbreviation - def _get_transition(self, dt): # type: (datetime) -> Transition + def _get_transition(self, dt): # type: (_datetime) -> Transition if dt.tzinfo is not None and dt.tzinfo is not self: dt = dt - dt.utcoffset() @@ -266,7 +271,7 @@ def _get_transition(self, dt): # type: (datetime) -> Transition return transition - def fromutc(self, dt): # type: (datetime) -> datetime + def fromutc(self, dt): # type: (_D) -> _D stamp = timestamp(dt) transition = self._lookup_transition(stamp, is_utc=True) @@ -302,7 +307,7 @@ def __init__(self, offset, name=None): def offset(self): # type: () -> int return self._offset - def _normalize(self, dt, **_): # type: (datetime, ...) -> datetime + def _normalize(self, dt, dst_rule=None): # type: (_D, Optional[str]) -> _D if _HAS_FOLD: dt = dt.__class__( dt.year, @@ -329,22 +334,22 @@ def _normalize(self, dt, **_): # type: (datetime, ...) -> datetime return dt - def _convert(self, dt): # type: (datetime) -> datetime + def _convert(self, dt): # type: (_D) -> _D if dt.tzinfo is not self: return dt.astimezone(self) return dt - def utcoffset(self, dt): # type: Optional[datetime] # type: (...) -> timedelta + def utcoffset(self, dt): # type: (Optional[_datetime]) -> timedelta return self._utcoffset - def dst(self, dt): # type: Optional[datetime] # type: (...) -> timedelta + def dst(self, dt): # type: (Optional[_datetime]) -> timedelta return timedelta() - def fromutc(self, dt): # type: (datetime) -> datetime + def fromutc(self, dt): # type: (_D) -> _D return (dt + self._utcoffset).replace(tzinfo=self) - def tzname(self, dt): # type: Optional[datetime] # type: (...) -> Union[str, None] + def tzname(self, dt): # type: (Optional[_datetime]) -> Optional[str] return self._name def __getinitargs__(self): # type: () -> tuple diff --git a/pendulum/tz/zoneinfo/__init__.py b/pendulum/tz/zoneinfo/__init__.py index ce70e5fd..c1833650 100644 --- a/pendulum/tz/zoneinfo/__init__.py +++ b/pendulum/tz/zoneinfo/__init__.py @@ -2,14 +2,14 @@ from .timezone import Timezone -def read(name, extend=True): # type: (str) -> Timezone +def read(name, extend=True): # type: (str, bool) -> Timezone """ Read the zoneinfo structure for a given timezone name. """ return Reader(extend=extend).read_for(name) -def read_file(path, extend=True): # type: (str) -> Timezone +def read_file(path, extend=True): # type: (str, bool) -> Timezone """ Read the zoneinfo structure for a given path. """ diff --git a/pendulum/tz/zoneinfo/posix_timezone.py b/pendulum/tz/zoneinfo/posix_timezone.py index b5b0ceb2..da5e8667 100644 --- a/pendulum/tz/zoneinfo/posix_timezone.py +++ b/pendulum/tz/zoneinfo/posix_timezone.py @@ -4,7 +4,7 @@ """ import re -from typing import Union +from typing import Optional from pendulum.constants import MONTHS_OFFSETS, SECS_PER_DAY @@ -67,7 +67,7 @@ def _posix_spec(spec): # type: (str) -> PosixTimezone return PosixTimezone(std_abbr, std_offset, dst_abbr, dst_offset, dst_start, dst_end) -def _parse_abbr(text): # type: (str) -> Union[str, None] +def _parse_abbr(text): # type: (str) -> str return text.lstrip("<").rstrip(">") @@ -231,10 +231,10 @@ def __init__( self, std_abbr, # type: str std_offset, # type: int - dst_abbr, # type: Union[str, None] = None - dst_offset, # type: Union[str, None] = None - dst_start=None, # type: Union[PosixTransition, None] - dst_end=None, # type: Union[PosixTransition, None] + dst_abbr, # type: Optional[str] + dst_offset, # type: Optional[int] + dst_start=None, # type: Optional[PosixTransition] + dst_end=None, # type: Optional[PosixTransition] ): self._std_abbr = std_abbr self._std_offset = std_offset @@ -252,17 +252,17 @@ def std_offset(self): # type: () -> int return self._std_offset @property - def dst_abbr(self): # type: () -> Union[str, None] + def dst_abbr(self): # type: () -> Optional[str] return self._dst_abbr @property - def dst_offset(self): # type: () -> Union[int, None] + def dst_offset(self): # type: () -> Optional[int] return self._dst_offset @property - def dst_start(self): # type: () -> Union[PosixTransition, None] + def dst_start(self): # type: () -> Optional[PosixTransition] return self._dst_start @property - def dst_end(self): # type: () -> Union[PosixTransition, None] + def dst_end(self): # type: () -> Optional[PosixTransition] return self._dst_end diff --git a/pendulum/tz/zoneinfo/reader.py b/pendulum/tz/zoneinfo/reader.py index f494197d..21848b5c 100644 --- a/pendulum/tz/zoneinfo/reader.py +++ b/pendulum/tz/zoneinfo/reader.py @@ -3,7 +3,7 @@ from collections import namedtuple from struct import unpack -from typing import Dict, List, Optional +from typing import Dict, List, Optional, IO, Any, Tuple from pytzdata.exceptions import TimezoneNotFound @@ -155,7 +155,7 @@ def _parse_header(self, fd): # type: (...) -> header return hdr - def _parse_trans_64(self, fd, n): # type: (..., int) -> List[int] + def _parse_trans_64(self, fd, n): # type: (IO[Any], int) -> List[int] trans = [] for _ in range(n): buff = self._check_read(fd, 8) @@ -163,7 +163,7 @@ def _parse_trans_64(self, fd, n): # type: (..., int) -> List[int] return trans - def _parse_trans_32(self, fd, n): # type: (..., int) -> List[int] + def _parse_trans_32(self, fd, n): # type: (IO[Any], int) -> List[int] trans = [] for _ in range(n): buff = self._check_read(fd, 4) @@ -171,12 +171,14 @@ def _parse_trans_32(self, fd, n): # type: (..., int) -> List[int] return trans - def _parse_type_idx(self, fd, n): # type: (..., int) -> List[int] + def _parse_type_idx(self, fd, n): # type: (IO[Any], int) -> List[int] buff = self._check_read(fd, n) return list(unpack("{}B".format(n), buff)) - def _parse_types(self, fd, n): # type: (..., int) -> List[tuple] + def _parse_types( + self, fd, n + ): # type: (IO[Any], int) -> List[Tuple[Any, bool, int]] types = [] for _ in range(n): @@ -188,8 +190,8 @@ def _parse_types(self, fd, n): # type: (..., int) -> List[tuple] return types def _parse_abbrs( - self, fd, n, types # type: int # type: List[tuple] - ): # type: (...) -> Dict[int, str] + self, fd, n, types + ): # type: (IO[Any], int, List[Tuple[Any, bool, int]]) -> Dict[int, str] abbrs = {} buff = self._check_read(fd, n) diff --git a/pendulum/tz/zoneinfo/timezone.py b/pendulum/tz/zoneinfo/timezone.py index 4c19970a..cf8b126e 100644 --- a/pendulum/tz/zoneinfo/timezone.py +++ b/pendulum/tz/zoneinfo/timezone.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import List, Union +from typing import List, Optional from pendulum.constants import DAYS_PER_YEAR, SECS_PER_YEAR from pendulum.helpers import local_time, is_leap, timestamp, week_day @@ -13,7 +13,7 @@ class Timezone: def __init__( self, transitions, # type: List[Transition] - posix_rule=None, # type: Union[PosixTimezone, None] + posix_rule=None, # type: Optional[PosixTimezone] extended=True, # type: bool ): self._posix_rule = posix_rule diff --git a/pendulum/tz/zoneinfo/transition.py b/pendulum/tz/zoneinfo/transition.py index 1ba93a46..c64bcf2f 100644 --- a/pendulum/tz/zoneinfo/transition.py +++ b/pendulum/tz/zoneinfo/transition.py @@ -1,5 +1,5 @@ from datetime import timedelta -from typing import Union +from typing import Optional from .transition_type import TransitionType @@ -9,7 +9,7 @@ def __init__( self, at, # type: int ttype, # type: TransitionType - previous, # type: Union['Transition', None] + previous, # type: Optional[Transition] ): self._at = at @@ -51,7 +51,7 @@ def ttype(self): # type: () -> TransitionType return self._ttype @property - def previous(self): # type: () -> Transition + def previous(self): # type: () -> Optional[Transition] return self._previous @property @@ -67,7 +67,7 @@ def is_missing(self, stamp): # type: (int) -> bool def utcoffset(self): # type: () -> timedelta return self._utcoffset - def __contains__(self, stamp): # type: () -> bool + def __contains__(self, stamp): # type: (int) -> bool return self.previous.local <= stamp < self.local def __repr__(self): # type: () -> str diff --git a/pyproject.toml b/pyproject.toml index 34993096..944bbfd0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,6 +16,7 @@ packages = [ {include = "pendulum"}, {include = "tests", format = "sdist"}, ] +include = ["pendulum/py.typed"] [tool.poetry.dependencies] From c42734f2ab4b91ad9211ac7ce54c88cbc409f5ff Mon Sep 17 00:00:00 2001 From: Bryan Forbes Date: Fri, 30 Nov 2018 11:53:59 -0600 Subject: [PATCH 2/2] Change "..." to "pass" for Python 2 and pypy --- pendulum/helpers.py | 4 ++-- pendulum/tz/timezone.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pendulum/helpers.py b/pendulum/helpers.py index dc87ce57..fa8abed1 100644 --- a/pendulum/helpers.py +++ b/pendulum/helpers.py @@ -62,7 +62,7 @@ def add_duration( seconds=0, # type: int microseconds=0, # type: int ): # type: (...) -> _DT - ... + pass @overload @@ -73,7 +73,7 @@ def add_duration( weeks=0, # type: int days=0, # type: int ): # type: (...) -> _D - ... + pass def add_duration( diff --git a/pendulum/tz/timezone.py b/pendulum/tz/timezone.py index e3f1406e..c22a9888 100644 --- a/pendulum/tz/timezone.py +++ b/pendulum/tz/timezone.py @@ -212,11 +212,11 @@ def _lookup_transition( @overload def utcoffset(self, dt): # type: (None) -> None - ... + pass @overload def utcoffset(self, dt): # type: (_datetime) -> timedelta - ... + pass def utcoffset(self, dt): if dt is None: