Skip to content

Commit 2b44bbd

Browse files
authored
Merge pull request #640 from sdispater/refactor/typing
Improve and fix typing
2 parents d87ad91 + 8732968 commit 2b44bbd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1413
-1141
lines changed

.pre-commit-config.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ repos:
1515
rev: v2.1.1
1616
hooks:
1717
- id: pycln
18-
args: [--all]
18+
args: [ --all ]
1919

2020
- repo: https://github.com/psf/black
2121
rev: 22.6.0
@@ -26,7 +26,7 @@ repos:
2626
rev: 5.10.1
2727
hooks:
2828
- id: isort
29-
args: [--add-import, from __future__ import annotations]
29+
args: [ --add-import, from __future__ import annotations, --lines-after-imports, "-1" ]
3030

3131
- repo: https://github.com/pycqa/flake8
3232
rev: 5.0.4
@@ -67,3 +67,5 @@ repos:
6767
exclude: ^build\.py$
6868
additional_dependencies:
6969
- pytest>=7.1.2
70+
- types-backports
71+
- types-python-dateutil

pendulum/__init__.py

Lines changed: 93 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
import datetime as _datetime
44

5-
from typing import Optional
65
from typing import Union
6+
from typing import cast
77

88
from pendulum.__version__ import __version__
99
from pendulum.constants import DAYS_PER_WEEK
@@ -40,9 +40,6 @@
4040
from pendulum.parser import parse
4141
from pendulum.period import Period
4242
from pendulum.time import Time
43-
from pendulum.tz import POST_TRANSITION
44-
from pendulum.tz import PRE_TRANSITION
45-
from pendulum.tz import TRANSITION_ERROR
4643
from pendulum.tz import UTC
4744
from pendulum.tz import local_timezone
4845
from pendulum.tz import set_local_timezone
@@ -52,7 +49,6 @@
5249
from pendulum.tz.timezone import FixedTimezone
5350
from pendulum.tz.timezone import Timezone
5451

55-
5652
_TEST_NOW: DateTime | None = None
5753
_LOCALE = "en"
5854
_WEEK_STARTS_AT = MONDAY
@@ -61,7 +57,10 @@
6157
_formatter = Formatter()
6258

6359

64-
def _safe_timezone(obj: str | float | _datetime.tzinfo | Timezone | None) -> Timezone:
60+
def _safe_timezone(
61+
obj: str | float | _datetime.tzinfo | Timezone | FixedTimezone | None,
62+
dt: _datetime.datetime | None = None,
63+
) -> Timezone | FixedTimezone:
6564
"""
6665
Creates a timezone instance
6766
from a string, Timezone, TimezoneInfo or integer offset.
@@ -75,19 +74,24 @@ def _safe_timezone(obj: str | float | _datetime.tzinfo | Timezone | None) -> Tim
7574
if isinstance(obj, (int, float)):
7675
obj = int(obj * 60 * 60)
7776
elif isinstance(obj, _datetime.tzinfo):
77+
# zoneinfo
78+
if hasattr(obj, "key"):
79+
obj = obj.key # type: ignore
7880
# pytz
79-
if hasattr(obj, "localize"):
80-
obj = obj.zone
81+
elif hasattr(obj, "localize"):
82+
obj = obj.zone # type: ignore
8183
elif obj.tzname(None) == "UTC":
8284
return UTC
8385
else:
84-
offset = obj.utcoffset(None)
86+
offset = obj.utcoffset(dt)
8587

8688
if offset is None:
8789
offset = _datetime.timedelta(0)
8890

8991
obj = int(offset.total_seconds())
9092

93+
obj = cast(Union[str, int], obj)
94+
9195
return timezone(obj)
9296

9397

@@ -100,8 +104,8 @@ def datetime(
100104
minute: int = 0,
101105
second: int = 0,
102106
microsecond: int = 0,
103-
tz: str | float | Timezone | None = UTC,
104-
fold: int | None = 1,
107+
tz: str | float | Timezone | FixedTimezone | _datetime.tzinfo | None = UTC,
108+
fold: int = 1,
105109
raise_on_unknown_times: bool = False,
106110
) -> DateTime:
107111
"""
@@ -146,7 +150,7 @@ def naive(
146150
minute: int = 0,
147151
second: int = 0,
148152
microsecond: int = 0,
149-
fold: int | None = 1,
153+
fold: int = 1,
150154
) -> DateTime:
151155
"""
152156
Return a naive DateTime.
@@ -168,7 +172,10 @@ def time(hour: int, minute: int = 0, second: int = 0, microsecond: int = 0) -> T
168172
return Time(hour, minute, second, microsecond)
169173

170174

171-
def instance(dt: _datetime.datetime, tz: str | Timezone | None = UTC) -> DateTime:
175+
def instance(
176+
dt: _datetime.datetime,
177+
tz: str | Timezone | FixedTimezone | _datetime.tzinfo | None = UTC,
178+
) -> DateTime:
172179
"""
173180
Create a DateTime instance from a datetime one.
174181
"""
@@ -180,19 +187,18 @@ def instance(dt: _datetime.datetime, tz: str | Timezone | None = UTC) -> DateTim
180187

181188
tz = dt.tzinfo or tz
182189

183-
# Checking for pytz/tzinfo
184-
if isinstance(tz, _datetime.tzinfo) and not isinstance(tz, Timezone):
185-
# pytz
186-
if hasattr(tz, "localize") and tz.zone:
187-
tz = tz.zone
188-
else:
189-
# We have no sure way to figure out
190-
# the timezone name, we fallback
191-
# on a fixed offset
192-
tz = tz.utcoffset(dt).total_seconds() / 3600
190+
if tz is not None:
191+
tz = _safe_timezone(tz, dt=dt)
193192

194193
return datetime(
195-
dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond, tz=tz
194+
dt.year,
195+
dt.month,
196+
dt.day,
197+
dt.hour,
198+
dt.minute,
199+
dt.second,
200+
dt.microsecond,
201+
tz=cast(Union[str, int, Timezone, FixedTimezone, None], tz),
196202
)
197203

198204

@@ -228,12 +234,13 @@ def from_format(
228234
string: str,
229235
fmt: str,
230236
tz: str | Timezone = UTC,
231-
locale: str | None = None, # noqa
237+
locale: str | None = None,
232238
) -> DateTime:
233239
"""
234240
Creates a DateTime instance from a specific format.
235241
"""
236242
parts = _formatter.parse(string, fmt, now(), locale=locale)
243+
237244
if parts["tz"] is None:
238245
parts["tz"] = tz
239246

@@ -288,3 +295,64 @@ def period(start: DateTime, end: DateTime, absolute: bool = False) -> Period:
288295
Create a Period instance.
289296
"""
290297
return Period(start, end, absolute=absolute)
298+
299+
300+
__all__ = [
301+
"__version__",
302+
"DAYS_PER_WEEK",
303+
"FRIDAY",
304+
"HOURS_PER_DAY",
305+
"MINUTES_PER_HOUR",
306+
"MONDAY",
307+
"MONTHS_PER_YEAR",
308+
"SATURDAY",
309+
"SECONDS_PER_DAY",
310+
"SECONDS_PER_HOUR",
311+
"SECONDS_PER_MINUTE",
312+
"SUNDAY",
313+
"THURSDAY",
314+
"TUESDAY",
315+
"WEDNESDAY",
316+
"WEEKS_PER_YEAR",
317+
"YEARS_PER_CENTURY",
318+
"YEARS_PER_DECADE",
319+
"Date",
320+
"DateTime",
321+
"Duration",
322+
"Formatter",
323+
"date",
324+
"datetime",
325+
"duration",
326+
"format_diff",
327+
"from_format",
328+
"from_timestamp",
329+
"get_locale",
330+
"get_test_now",
331+
"has_test_now",
332+
"instance",
333+
"local",
334+
"locale",
335+
"naive",
336+
"now",
337+
"period",
338+
"set_locale",
339+
"set_test_now",
340+
"test",
341+
"week_ends_at",
342+
"week_starts_at",
343+
"parse",
344+
"Period",
345+
"Time",
346+
"UTC",
347+
"local_timezone",
348+
"set_local_timezone",
349+
"test_local_timezone",
350+
"time",
351+
"timezone",
352+
"timezones",
353+
"today",
354+
"tomorrow",
355+
"FixedTimezone",
356+
"Timezone",
357+
"yesterday",
358+
]

pendulum/_extensions/_helpers.pyi

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from __future__ import annotations
2+
3+
from collections import namedtuple
4+
from datetime import date
5+
from datetime import datetime
6+
7+
def days_in_year(year: int) -> int: ...
8+
def is_leap(year: int) -> bool: ...
9+
def is_long_year(year: int) -> bool: ...
10+
def local_time(
11+
unix_time: int, utc_offset: int, microseconds: int
12+
) -> tuple[int, int, int, int, int, int, int]: ...
13+
14+
class PreciseDiff(
15+
namedtuple(
16+
"PreciseDiff",
17+
"years months days " "hours minutes seconds microseconds " "total_days",
18+
)
19+
):
20+
years: int
21+
months: int
22+
days: int
23+
hours: int
24+
minutes: int
25+
seconds: int
26+
microseconds: int
27+
total_days: int
28+
29+
def precise_diff(d1: datetime | date, d2: datetime | date) -> PreciseDiff: ...
30+
def timestamp(dt: datetime) -> int: ...
31+
def week_day(year: int, month: int, day: int) -> int: ...

0 commit comments

Comments
 (0)