diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3ec3be2a..967b5988 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,15 +11,11 @@ repos: exclude: ^tests/.*/fixtures/.* - id: debug-statements - - repo: https://github.com/psf/black - rev: 23.7.0 - hooks: - - id: black - - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.0.291 + rev: v0.8.0 hooks: - - id: ruff + - id: ruff + - id: ruff-format - repo: local hooks: diff --git a/pyproject.toml b/pyproject.toml index 8f03b3cc..aeb524e6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -85,47 +85,52 @@ test = ["time-machine"] [tool.maturin] module-name = "pendulum._pendulum" - [tool.ruff] fix = true -unfixable = [ - "ERA", # do not autoremove commented out code -] -target-version = "py39" line-length = 88 +target-version = "py39" +extend-exclude = [ + # External to the project's coding standards: + "docs/*", + # Machine-generated, too many false-positives + "src/pendulum/locales/*", + # ruff disagrees with black when it comes to formatting + "*.pyi", +] + +[tool.ruff.lint] extend-select = [ - "B", # flake8-bugbear - "C4", # flake8-comprehensions + "B", # flake8-bugbear + "C4", # flake8-comprehensions "ERA", # flake8-eradicate/eradicate - "I", # isort - "N", # pep8-naming + "I", # isort + "N", # pep8-naming "PIE", # flake8-pie "PGH", # pygrep "RUF", # ruff checks "SIM", # flake8-simplify + "T20", # flake8-print "TCH", # flake8-type-checking "TID", # flake8-tidy-imports - "UP", # pyupgrade + "UP", # pyupgrade ] ignore = [ "B904", # use 'raise ... from err' "B905", # use explicit 'strict=' parameter with 'zip()' - "N818", # Exception name should be named with an Error suffix - "RUF001", + "N818", + "RUF001" ] -extend-exclude = [ - # External to the project's coding standards: - "docs/*", - # Machine-generated, too many false-positives - "src/pendulum/locales/*", - # ruff disagrees with black when it comes to formatting - "*.pyi", +extend-safe-fixes = [ + "TCH", # move import from and to TYPE_CHECKING blocks +] +unfixable = [ + "ERA", # do not autoremove commented out code ] -[tool.ruff.flake8-tidy-imports] +[tool.ruff.lint.flake8-tidy-imports] ban-relative-imports = "all" -[tool.ruff.isort] +[tool.ruff.lint.isort] force-single-line = true lines-between-types = 1 lines-after-imports = 2 diff --git a/src/pendulum/__init__.py b/src/pendulum/__init__.py index 16e7b367..c6bfe081 100644 --- a/src/pendulum/__init__.py +++ b/src/pendulum/__init__.py @@ -59,18 +59,15 @@ @overload -def timezone(name: int) -> FixedTimezone: - ... +def timezone(name: int) -> FixedTimezone: ... @overload -def timezone(name: str) -> Timezone: - ... +def timezone(name: str) -> Timezone: ... @overload -def timezone(name: str | int) -> Timezone | FixedTimezone: - ... +def timezone(name: str | int) -> Timezone | FixedTimezone: ... def timezone(name: str | int) -> Timezone | FixedTimezone: @@ -205,24 +202,21 @@ def time(hour: int, minute: int = 0, second: int = 0, microsecond: int = 0) -> T def instance( obj: _datetime.datetime, tz: str | Timezone | FixedTimezone | _datetime.tzinfo | None = UTC, -) -> DateTime: - ... +) -> DateTime: ... @overload def instance( obj: _datetime.date, tz: str | Timezone | FixedTimezone | _datetime.tzinfo | None = UTC, -) -> Date: - ... +) -> Date: ... @overload def instance( obj: _datetime.time, tz: str | Timezone | FixedTimezone | _datetime.tzinfo | None = UTC, -) -> Time: - ... +) -> Time: ... def instance( @@ -350,7 +344,6 @@ def interval( travel_back = _traveller.travel_back __all__ = [ - "__version__", "DAYS_PER_WEEK", "HOURS_PER_DAY", "MINUTES_PER_HOUR", @@ -358,14 +351,20 @@ def interval( "SECONDS_PER_DAY", "SECONDS_PER_HOUR", "SECONDS_PER_MINUTE", + "UTC", "WEEKS_PER_YEAR", "YEARS_PER_CENTURY", "YEARS_PER_DECADE", "Date", "DateTime", "Duration", + "FixedTimezone", "Formatter", + "Interval", + "Time", + "Timezone", "WeekDay", + "__version__", "date", "datetime", "duration", @@ -377,18 +376,13 @@ def interval( "instance", "interval", "local", + "local_timezone", "locale", "naive", "now", - "set_locale", - "week_ends_at", - "week_starts_at", "parse", - "Interval", - "Time", - "UTC", - "local_timezone", "set_local_timezone", + "set_locale", "test_local_timezone", "time", "timezone", @@ -398,7 +392,7 @@ def interval( "travel", "travel_back", "travel_to", - "FixedTimezone", - "Timezone", + "week_ends_at", + "week_starts_at", "yesterday", ] diff --git a/src/pendulum/_helpers.py b/src/pendulum/_helpers.py index 3eb85439..fddd0021 100644 --- a/src/pendulum/_helpers.py +++ b/src/pendulum/_helpers.py @@ -175,10 +175,10 @@ def precise_diff( ) if ( - tzinfo1 is None - and tzinfo2 is not None - or tzinfo2 is None - and tzinfo1 is not None + (tzinfo1 is None + and tzinfo2 is not None) + or (tzinfo2 is None + and tzinfo1 is not None) ): raise ValueError( "Comparison between naive and aware datetimes is not supported" diff --git a/src/pendulum/date.py b/src/pendulum/date.py index 633bb6da..50554f43 100644 --- a/src/pendulum/date.py +++ b/src/pendulum/date.py @@ -257,16 +257,13 @@ def __add__(self, other: timedelta) -> Self: return self._add_timedelta(other) @overload # type: ignore[override] # this is only needed because of Python 3.7 - def __sub__(self, __delta: timedelta) -> Self: - ... + def __sub__(self, __delta: timedelta) -> Self: ... @overload - def __sub__(self, __dt: datetime) -> NoReturn: - ... + def __sub__(self, __dt: datetime) -> NoReturn: ... @overload - def __sub__(self, __dt: Self) -> Interval[Date]: - ... + def __sub__(self, __dt: Self) -> Interval[Date]: ... def __sub__(self, other: timedelta | date) -> Self | Interval[Date]: if isinstance(other, timedelta): diff --git a/src/pendulum/datetime.py b/src/pendulum/datetime.py index c1babbf8..44aef330 100644 --- a/src/pendulum/datetime.py +++ b/src/pendulum/datetime.py @@ -146,13 +146,11 @@ def instance( @overload @classmethod - def now(cls, tz: datetime.tzinfo | None = None) -> Self: - ... + def now(cls, tz: datetime.tzinfo | None = None) -> Self: ... @overload @classmethod - def now(cls, tz: str | Timezone | FixedTimezone | None = None) -> Self: - ... + def now(cls, tz: str | Timezone | FixedTimezone | None = None) -> Self: ... @classmethod def now( @@ -1186,12 +1184,10 @@ def average( # type: ignore[override] ) @overload # type: ignore[override] - def __sub__(self, other: datetime.timedelta) -> Self: - ... + def __sub__(self, other: datetime.timedelta) -> Self: ... @overload - def __sub__(self, other: DateTime) -> Interval[datetime.datetime]: - ... + def __sub__(self, other: DateTime) -> Interval[datetime.datetime]: ... def __sub__( self, other: datetime.datetime | datetime.timedelta diff --git a/src/pendulum/duration.py b/src/pendulum/duration.py index a4875fca..214adc3f 100644 --- a/src/pendulum/duration.py +++ b/src/pendulum/duration.py @@ -37,7 +37,7 @@ def _divide_and_round(a: float, b: float) -> int: # positive, 2 * r < b if b negative. r *= 2 greater_than_half = r > b if b > 0 else r < b - if greater_than_half or r == b and q % 2 == 1: + if greater_than_half or (r == b and q % 2 == 1): q += 1 return q @@ -375,12 +375,10 @@ def __mul__(self, other: int | float) -> Self: __rmul__ = __mul__ @overload - def __floordiv__(self, other: timedelta) -> int: - ... + def __floordiv__(self, other: timedelta) -> int: ... @overload - def __floordiv__(self, other: int) -> Self: - ... + def __floordiv__(self, other: int) -> Self: ... def __floordiv__(self, other: int | timedelta) -> int | Duration: if not isinstance(other, (int, timedelta)): @@ -389,7 +387,8 @@ def __floordiv__(self, other: int | timedelta) -> int | Duration: usec = self._to_microseconds() if isinstance(other, timedelta): return cast( - int, usec // other._to_microseconds() # type: ignore[attr-defined] + int, + usec // other._to_microseconds(), # type: ignore[attr-defined] ) if isinstance(other, int): @@ -402,12 +401,10 @@ def __floordiv__(self, other: int | timedelta) -> int | Duration: ) @overload - def __truediv__(self, other: timedelta) -> float: - ... + def __truediv__(self, other: timedelta) -> float: ... @overload - def __truediv__(self, other: float) -> Self: - ... + def __truediv__(self, other: float) -> Self: ... def __truediv__(self, other: int | float | timedelta) -> Self | float: if not isinstance(other, (int, float, timedelta)): @@ -416,7 +413,8 @@ def __truediv__(self, other: int | float | timedelta) -> Self | float: usec = self._to_microseconds() if isinstance(other, timedelta): return cast( - float, usec / other._to_microseconds() # type: ignore[attr-defined] + float, + usec / other._to_microseconds(), # type: ignore[attr-defined] ) if isinstance(other, int): @@ -443,7 +441,7 @@ def __truediv__(self, other: int | float | timedelta) -> Self | float: def __mod__(self, other: timedelta) -> Self: if isinstance(other, timedelta): - r = self._to_microseconds() % other._to_microseconds() # type: ignore[attr-defined] # noqa: E501 + r = self._to_microseconds() % other._to_microseconds() # type: ignore[attr-defined] return self.__class__(0, 0, r) diff --git a/src/pendulum/formatting/formatter.py b/src/pendulum/formatting/formatter.py index 8735ecc4..a95f99d4 100644 --- a/src/pendulum/formatting/formatter.py +++ b/src/pendulum/formatting/formatter.py @@ -38,7 +38,7 @@ _MATCH_TIMESTAMP = r"[+-]?\d+(\.\d{1,6})?" _MATCH_WORD = ( "(?i)[0-9]*" - "['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+" + "['a-z\u00a0-\u05ff\u0700-\ud7ff\uf900-\ufdcf\ufdf0-\uffef]+" r"|[\u0600-\u06FF/]+(\s*?[\u0600-\u06FF]+){1,2}" ) _MATCH_TIMEZONE = "[A-Za-z0-9-+]+(/[A-Za-z0-9-+_]+)?" diff --git a/src/pendulum/helpers.py b/src/pendulum/helpers.py index 5d5fe8e5..e9424d90 100644 --- a/src/pendulum/helpers.py +++ b/src/pendulum/helpers.py @@ -62,8 +62,7 @@ def add_duration( minutes: int = 0, seconds: float = 0, microseconds: int = 0, -) -> _DT: - ... +) -> _DT: ... @overload @@ -205,17 +204,17 @@ def week_ends_at(wday: WeekDay) -> None: __all__ = [ "PreciseDiff", + "add_duration", "days_in_year", + "format_diff", + "get_locale", "is_leap", "is_long_year", "local_time", - "precise_diff", - "week_day", - "add_duration", - "format_diff", "locale", + "precise_diff", "set_locale", - "get_locale", - "week_starts_at", + "week_day", "week_ends_at", + "week_starts_at", ] diff --git a/src/pendulum/interval.py b/src/pendulum/interval.py index 345a160e..31491f67 100644 --- a/src/pendulum/interval.py +++ b/src/pendulum/interval.py @@ -38,10 +38,10 @@ class Interval(Duration, Generic[_T]): def __new__(cls, start: _T, end: _T, absolute: bool = False) -> Self: if ( - isinstance(start, datetime) - and not isinstance(end, datetime) - or not isinstance(start, datetime) - and isinstance(end, datetime) + (isinstance(start, datetime) + and not isinstance(end, datetime)) + or (not isinstance(start, datetime) + and isinstance(end, datetime)) ): raise ValueError( "Both start and end of an Interval must have the same type" @@ -51,10 +51,10 @@ def __new__(cls, start: _T, end: _T, absolute: bool = False) -> Self: isinstance(start, datetime) and isinstance(end, datetime) and ( - start.tzinfo is None - and end.tzinfo is not None - or start.tzinfo is not None - and end.tzinfo is None + (start.tzinfo is None + and end.tzinfo is not None) + or (start.tzinfo is not None + and end.tzinfo is None) ) ): raise TypeError("can't compare offset-naive and offset-aware datetimes") @@ -336,12 +336,10 @@ def __mul__(self, other: int | float) -> Duration: # type: ignore[override] __rmul__ = __mul__ # type: ignore[assignment] @overload # type: ignore[override] - def __floordiv__(self, other: timedelta) -> int: - ... + def __floordiv__(self, other: timedelta) -> int: ... @overload - def __floordiv__(self, other: int) -> Duration: - ... + def __floordiv__(self, other: int) -> Duration: ... def __floordiv__(self, other: int | timedelta) -> int | Duration: return self.as_duration().__floordiv__(other) @@ -349,12 +347,10 @@ def __floordiv__(self, other: int | timedelta) -> int | Duration: __div__ = __floordiv__ # type: ignore[assignment] @overload # type: ignore[override] - def __truediv__(self, other: timedelta) -> float: - ... + def __truediv__(self, other: timedelta) -> float: ... @overload - def __truediv__(self, other: float) -> Duration: - ... + def __truediv__(self, other: float) -> Duration: ... def __truediv__(self, other: float | timedelta) -> Duration | float: return self.as_duration().__truediv__(other) diff --git a/src/pendulum/parsing/__init__.py b/src/pendulum/parsing/__init__.py index 60b232bf..865bb4f9 100644 --- a/src/pendulum/parsing/__init__.py +++ b/src/pendulum/parsing/__init__.py @@ -44,7 +44,8 @@ " )" ")?" # Time (optional) # noqa: ERA001 - "(?P