Skip to content

Commit

Permalink
Improve docstrings and IDE autocomplete
Browse files Browse the repository at this point in the history
  • Loading branch information
ariebovenberg committed Oct 26, 2024
1 parent 978affa commit 37e340b
Show file tree
Hide file tree
Showing 9 changed files with 625 additions and 153 deletions.
1 change: 1 addition & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- [ ] Build runs successfully
- [ ] Type stubs updated
- [ ] Docs updated
- [ ] If docstrings were affected, check if they appear correctly in the docs as well as autocomplete

# Release checklist (maintainers only)

Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
🚀 Changelog
============

0.6.10 (2024-10-??)
-------------------

**Improved**

- Improve method documentation and IDE autocomplete support (#172, #173, #176)

**Fixed**

- Remove lingering undocumented ``offset`` on ``Instant``
- Fix incorrect ``LocalDateTime.difference`` return type annotation

0.6.9 (2024-09-12)
------------------

Expand Down
9 changes: 8 additions & 1 deletion docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,20 @@ Concrete classes

.. autoclass:: whenever.Instant
:members:
from_utc,
format_rfc3339,
parse_rfc3339,
format_rfc2822,
parse_rfc2822,
add,
subtract
subtract,
:special-members: __add__, __sub__
:member-order: bysource
:show-inheritance:

.. autoattribute:: MIN
.. autoattribute:: MAX

.. autoclass:: whenever.LocalDateTime
:members:
assume_utc,
Expand All @@ -63,6 +67,9 @@ Concrete classes
:member-order: bysource
:show-inheritance:

.. autoattribute:: MIN
.. autoattribute:: MAX

.. autoclass:: whenever.OffsetDateTime
:members:
format_rfc3339,
Expand Down
14 changes: 14 additions & 0 deletions docs/faq.rst
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,17 @@ Additional advantages of ``pyo3_ffi`` are:
- Its API is more stable than PyO3's, which is still evolving.
- It allows support for per-interpreter GIL, and free-threaded Python,
which are not yet supported by PyO3.

Why can't I subclass Whenever classes?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Whenever classes aren't meant to be subclassed.
There's no plan to change this due to the following reasons:

1. The benefits of subclassing are limited.
If you want to extend the classes, composition is a better way to do it.
Alternatively, you can use Python's dynamic features to create
something that "quacks" like a subclass.
2. For a class to support subclassing properly, a lot of extra work is needed.
It also adds many subtle ways to misuse the API, that are hard to control.
3. Enabling subclassing would undo some performance optimizations.
6 changes: 3 additions & 3 deletions docs/overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -361,8 +361,8 @@ Ambiguity in timezones

In timezones, local clocks are often moved backwards and forwards
due to Daylight Saving Time (DST) or political decisions.
This creates two types of situations for the :class:`~whenever.ZonedDateTime`
and :class:`~whenever.SystemDateTime` types:
This makes it complicated to map a local datetime to a point on the timeline.
Two common situations arise:

- When the clock moves backwards, there is a period of time that repeats.
For example, Sunday October 29th 2023 2:30am occurred twice in Paris.
Expand All @@ -374,7 +374,7 @@ and :class:`~whenever.SystemDateTime` types:
Common approaches are to extrapolate the time forward or backwards
to 1:30am or 3:30am.

.. important::
.. note::

You may wonder why skipped time is "extrapolated" like this,
and not truncated. Why turn 2:30am into 3:30am and not cut
Expand Down
7 changes: 5 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ name = "whenever"
authors = [
{name = "Arie Bovenberg", email = "a.c.bovenberg@gmail.com"},
]
maintainers = [
{name = "Arie Bovenberg", email = "a.c.bovenberg@gmail.com"},
]
readme = "README.md"
version = "0.6.9"
description = "Modern datetime library for Python, written in Rust"
version = "0.6.10"
description = "Modern datetime library for Python"
requires-python = ">=3.9"
classifiers = [
"Development Status :: 4 - Beta",
Expand Down
103 changes: 72 additions & 31 deletions pysrc/whenever/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ __all__ = [
"SUNDAY",
]

Disambiguate = Literal["raise", "earlier", "later", "compatible"]

@final
class Date:
def __init__(self, year: int, month: int, day: int) -> None: ...
Expand Down Expand Up @@ -257,15 +255,7 @@ Delta = DateTimeDelta | TimeDelta | DateDelta

_T = TypeVar("_T")

class _BasicConversions(ABC):
@classmethod
def from_py_datetime(cls: type[_T], d: _datetime, /) -> _T: ...
def py_datetime(self) -> _datetime: ...
def format_common_iso(self) -> str: ...
@classmethod
def parse_common_iso(cls: type[_T], s: str, /) -> _T: ...

class _KnowsLocal(_BasicConversions, ABC):
class _KnowsLocal(ABC):
@property
def year(self) -> int: ...
@property
Expand All @@ -283,7 +273,7 @@ class _KnowsLocal(_BasicConversions, ABC):
def date(self) -> Date: ...
def time(self) -> Time: ...

class _KnowsInstant(_BasicConversions, ABC):
class _KnowsInstant(ABC):
def timestamp(self) -> int: ...
def timestamp_millis(self) -> int: ...
def timestamp_nanos(self) -> int: ...
Expand Down Expand Up @@ -333,6 +323,7 @@ class Instant(_KnowsInstant):
def from_timestamp_nanos(cls, i: int, /) -> Instant: ...
@classmethod
def from_py_datetime(cls, d: _datetime, /) -> Instant: ...
def py_datetime(self) -> _datetime: ...
def format_rfc2822(self) -> str: ...
@classmethod
def parse_rfc2822(cls, s: str, /) -> Instant: ...
Expand Down Expand Up @@ -406,11 +397,13 @@ class OffsetDateTime(_KnowsInstantAndLocal):
) -> OffsetDateTime: ...
@classmethod
def from_py_datetime(cls, d: _datetime, /) -> OffsetDateTime: ...
def py_datetime(self) -> _datetime: ...
@classmethod
def strptime(cls, s: str, fmt: str, /) -> OffsetDateTime: ...
def format_rfc2822(self) -> str: ...
@classmethod
def parse_rfc2822(cls, s: str, /) -> OffsetDateTime: ...
def format_common_iso(self) -> str: ...
def format_rfc3339(self) -> str: ...
@classmethod
def parse_rfc3339(cls, s: str, /) -> OffsetDateTime: ...
Expand Down Expand Up @@ -491,7 +484,9 @@ class ZonedDateTime(_KnowsInstantAndLocal):
*,
nanosecond: int = 0,
tz: str,
disambiguate: Disambiguate = "raise",
disambiguate: Literal[
"compatible", "raise", "earlier", "later"
] = "raise",
) -> None: ...
@property
def tz(self) -> str: ...
Expand All @@ -500,6 +495,7 @@ class ZonedDateTime(_KnowsInstantAndLocal):
def now(cls, tz: str, /) -> ZonedDateTime: ...
@classmethod
def from_py_datetime(cls, d: _datetime, /) -> ZonedDateTime: ...
def py_datetime(self) -> _datetime: ...
@classmethod
def from_timestamp(
cls, i: int | float, /, *, tz: str
Expand All @@ -508,6 +504,7 @@ class ZonedDateTime(_KnowsInstantAndLocal):
def from_timestamp_millis(cls, i: int, /, *, tz: str) -> ZonedDateTime: ...
@classmethod
def from_timestamp_nanos(cls, i: int, /, *, tz: str) -> ZonedDateTime: ...
def format_common_iso(self) -> str: ...
@classmethod
def parse_common_iso(cls, s: str, /) -> ZonedDateTime: ...
def exact_eq(self, other: ZonedDateTime, /) -> bool: ...
Expand All @@ -522,13 +519,21 @@ class ZonedDateTime(_KnowsInstantAndLocal):
second: int = ...,
nanosecond: int = ...,
tz: str = ...,
disambiguate: Disambiguate,
disambiguate: Literal["compatible", "raise", "earlier", "later"],
) -> ZonedDateTime: ...
def replace_date(
self, d: Date, /, *, disambiguate: Disambiguate
self,
d: Date,
/,
*,
disambiguate: Literal["compatible", "raise", "earlier", "later"],
) -> ZonedDateTime: ...
def replace_time(
self, t: Time, /, *, disambiguate: Disambiguate
self,
t: Time,
/,
*,
disambiguate: Literal["compatible", "raise", "earlier", "later"],
) -> ZonedDateTime: ...
@overload
def add(
Expand All @@ -544,7 +549,7 @@ class ZonedDateTime(_KnowsInstantAndLocal):
milliseconds: float = 0,
microseconds: float = 0,
nanoseconds: int = 0,
disambiguate: Disambiguate,
disambiguate: Literal["compatible", "raise", "earlier", "later"],
) -> ZonedDateTime: ...
@overload
def add(
Expand All @@ -561,7 +566,11 @@ class ZonedDateTime(_KnowsInstantAndLocal):
def add(self, d: TimeDelta, /) -> ZonedDateTime: ...
@overload
def add(
self, d: DateDelta | DateTimeDelta, /, *, disambiguate: Disambiguate
self,
d: DateDelta | DateTimeDelta,
/,
*,
disambiguate: Literal["compatible", "raise", "earlier", "later"],
) -> ZonedDateTime: ...
@overload
def subtract(
Expand All @@ -577,7 +586,7 @@ class ZonedDateTime(_KnowsInstantAndLocal):
milliseconds: float = 0,
microseconds: float = 0,
nanoseconds: int = 0,
disambiguate: Disambiguate,
disambiguate: Literal["compatible", "raise", "earlier", "later"],
) -> ZonedDateTime: ...
@overload
def subtract(
Expand All @@ -594,7 +603,11 @@ class ZonedDateTime(_KnowsInstantAndLocal):
def subtract(self, d: TimeDelta, /) -> ZonedDateTime: ...
@overload
def subtract(
self, d: DateDelta | DateTimeDelta, /, *, disambiguate: Disambiguate
self,
d: DateDelta | DateTimeDelta,
/,
*,
disambiguate: Literal["compatible", "raise", "earlier", "later"],
) -> ZonedDateTime: ...
def __add__(self, delta: TimeDelta) -> ZonedDateTime: ...
@overload
Expand All @@ -614,7 +627,9 @@ class SystemDateTime(_KnowsInstantAndLocal):
second: int = 0,
*,
nanosecond: int = 0,
disambiguate: Disambiguate = "raise",
disambiguate: Literal[
"compatible", "raise", "earlier", "later"
] = "raise",
) -> None: ...
@classmethod
def now(cls) -> SystemDateTime: ...
Expand All @@ -626,8 +641,10 @@ class SystemDateTime(_KnowsInstantAndLocal):
def from_timestamp_nanos(cls, i: int, /) -> SystemDateTime: ...
@classmethod
def from_py_datetime(cls, d: _datetime, /) -> SystemDateTime: ...
def py_datetime(self) -> _datetime: ...
@classmethod
def parse_common_iso(cls, s: str, /) -> SystemDateTime: ...
def format_common_iso(self) -> str: ...
def exact_eq(self, other: SystemDateTime, /) -> bool: ...
def replace(
self,
Expand All @@ -639,13 +656,21 @@ class SystemDateTime(_KnowsInstantAndLocal):
minute: int = ...,
second: int = ...,
nanosecond: int = ...,
disambiguate: Disambiguate,
disambiguate: Literal["compatible", "raise", "earlier", "later"],
) -> SystemDateTime: ...
def replace_date(
self, d: Date, /, *, disambiguate: Disambiguate
self,
d: Date,
/,
*,
disambiguate: Literal["compatible", "raise", "earlier", "later"],
) -> SystemDateTime: ...
def replace_time(
self, t: Time, /, *, disambiguate: Disambiguate
self,
t: Time,
/,
*,
disambiguate: Literal["compatible", "raise", "earlier", "later"],
) -> SystemDateTime: ...
@overload
def add(
Expand All @@ -661,7 +686,7 @@ class SystemDateTime(_KnowsInstantAndLocal):
milliseconds: float = 0,
microseconds: float = 0,
nanoseconds: int = 0,
disambiguate: Disambiguate,
disambiguate: Literal["compatible", "raise", "earlier", "later"],
) -> SystemDateTime: ...
@overload
def add(
Expand All @@ -678,7 +703,11 @@ class SystemDateTime(_KnowsInstantAndLocal):
def add(self, d: TimeDelta, /) -> SystemDateTime: ...
@overload
def add(
self, d: DateDelta | DateTimeDelta, /, *, disambiguate: Disambiguate
self,
d: DateDelta | DateTimeDelta,
/,
*,
disambiguate: Literal["compatible", "raise", "earlier", "later"],
) -> SystemDateTime: ...
@overload
def subtract(
Expand All @@ -694,7 +723,7 @@ class SystemDateTime(_KnowsInstantAndLocal):
milliseconds: float = 0,
microseconds: float = 0,
nanoseconds: int = 0,
disambiguate: Disambiguate,
disambiguate: Literal["compatible", "raise", "earlier", "later"],
) -> SystemDateTime: ...
@overload
def subtract(
Expand All @@ -711,7 +740,11 @@ class SystemDateTime(_KnowsInstantAndLocal):
def subtract(self, d: TimeDelta, /) -> SystemDateTime: ...
@overload
def subtract(
self, d: DateDelta | DateTimeDelta, /, *, disambiguate: Disambiguate
self,
d: DateDelta | DateTimeDelta,
/,
*,
disambiguate: Literal["compatible", "raise", "earlier", "later"],
) -> SystemDateTime: ...
def __add__(self, delta: TimeDelta) -> SystemDateTime: ...
@overload
Expand Down Expand Up @@ -739,15 +772,23 @@ class LocalDateTime(_KnowsLocal):
self, offset: int | TimeDelta, /
) -> OffsetDateTime: ...
def assume_tz(
self, tz: str, /, *, disambiguate: Disambiguate
self,
tz: str,
/,
*,
disambiguate: Literal["compatible", "raise", "earlier", "later"],
) -> ZonedDateTime: ...
def assume_system_tz(
self, *, disambiguate: Disambiguate
self,
*,
disambiguate: Literal["compatible", "raise", "earlier", "later"],
) -> SystemDateTime: ...
@classmethod
def from_py_datetime(cls, d: _datetime, /) -> LocalDateTime: ...
def py_datetime(self) -> _datetime: ...
@classmethod
def parse_common_iso(cls, s: str, /) -> LocalDateTime: ...
def format_common_iso(self) -> str: ...
@classmethod
def strptime(cls, s: str, fmt: str, /) -> LocalDateTime: ...
def replace(
Expand Down Expand Up @@ -817,7 +858,7 @@ class LocalDateTime(_KnowsLocal):
) -> LocalDateTime: ...
def difference(
self, other: LocalDateTime, /, *, ignore_dst: Literal[True]
) -> DateTimeDelta: ...
) -> TimeDelta: ...
def __add__(self, delta: DateDelta) -> LocalDateTime: ...
def __sub__(self, other: DateDelta) -> LocalDateTime: ...
def __lt__(self, other: LocalDateTime) -> bool: ...
Expand Down
Loading

0 comments on commit 37e340b

Please sign in to comment.