diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 1d7308c8..00000000 --- a/.flake8 +++ /dev/null @@ -1,29 +0,0 @@ -[flake8] -max-line-length = 88 -per-file-ignores = - # F401: Module imported but unused - # TC001: Move import into type checking block - __init__.py:F401, TC001 - pendulum/date.py:E800 - # F811: Redefinition of unused name from line n - pendulum/tz/timezone.py:F811, E800 -min_python_version = 3.7.0 -ban-relative-imports = true -# flake8-use-fstring: https://github.com/MichaelKim0407/flake8-use-fstring#--percent-greedy-and---format-greedy -format-greedy = 1 -inline-quotes = double -enable-extensions = TC, TC1 -type-checking-exempt-modules = typing, typing-extensions -eradicate-whitelist-extend = ^-.*; -extend-ignore = - # E501: Line too long - E501, - # E203: Whitespace before ':' - E203, - # SIM106: Handle error-cases first - SIM106, -extend-exclude = - # External to the project's coding standards: - docs/*, - # Machine-generated, too many false-positives - pendulum/locales/*, diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2ee2fd44..2974fac7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ ci: repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 + rev: v4.4.0 hooks: - id: trailing-whitespace exclude: ^tests/.*/fixtures/.* @@ -11,50 +11,12 @@ repos: exclude: ^tests/.*/fixtures/.* - id: debug-statements - - repo: https://github.com/hadialqattan/pycln - rev: v2.1.1 - hooks: - - id: pycln - args: [ --all ] - - repo: https://github.com/psf/black - rev: 22.10.0 + rev: 23.3.0 hooks: - id: black - - repo: https://github.com/pycqa/isort - rev: 5.12.0 - hooks: - - id: isort - args: [ --add-import, from __future__ import annotations, --lines-after-imports, "-1" ] - - - repo: https://github.com/pycqa/flake8 - rev: 5.0.4 - hooks: - - id: flake8 - additional_dependencies: &flake8_deps - - flake8-broken-line==0.5.0 - - flake8-bugbear==22.7.1 - - flake8-comprehensions==3.10.0 - - flake8-eradicate==1.3.0 - - flake8-quotes==3.3.1 - - flake8-simplify==0.19.2 - - flake8-tidy-imports==4.8.0 - - flake8-type-checking==2.1.2 - - flake8-typing-imports==1.12.0 - - flake8-use-fstring==1.3 - - pep8-naming==0.13.1 - - - repo: https://github.com/asottile/yesqa - rev: v1.4.0 - hooks: - - id: yesqa - additional_dependencies: *flake8_deps - - - repo: https://github.com/asottile/pyupgrade - rev: v3.2.0 + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: v0.0.270 hooks: - - id: pyupgrade - exclude: ^build\.py$ - args: - - --py37-plus + - id: ruff diff --git a/build.py b/build.py index 95e63e10..8a72beb9 100644 --- a/build.py +++ b/build.py @@ -4,7 +4,7 @@ def meson(*args): - subprocess.call(["meson"] + list(args)) + subprocess.call(["meson", *list(args)]) def _build(): diff --git a/clock b/clock index 17f35a32..3c21a160 100755 --- a/clock +++ b/clock @@ -47,7 +47,6 @@ class _LambdaCompiler(_GettextCompiler): class LocaleCreate(Command): - name = "locale create" description = "Creates locale translations." @@ -229,7 +228,6 @@ translations = {{}} class LocaleRecreate(Command): - name = "locale recreate" description = "Recreate existing locales." @@ -244,7 +242,6 @@ class LocaleRecreate(Command): class WindowsTzDump(Command): - name = "windows dump-timezones" description = "Dumps the mapping of Windows timezones to IANA timezones." diff --git a/pendulum/__init__.py b/pendulum/__init__.py index 72f19eaf..f8e2651a 100644 --- a/pendulum/__init__.py +++ b/pendulum/__init__.py @@ -47,6 +47,7 @@ from pendulum.tz.timezone import FixedTimezone from pendulum.tz.timezone import Timezone + _TEST_NOW: DateTime | None = None _LOCALE = "en" _WEEK_STARTS_AT = MONDAY @@ -105,7 +106,7 @@ def _safe_timezone( obj = obj.key # pytz elif hasattr(obj, "localize"): - obj = obj.zone # type: ignore + obj = obj.zone # type: ignore[attr-defined] elif obj.tzname(None) == "UTC": return UTC else: diff --git a/pendulum/__version__.py b/pendulum/__version__.py index 29e86a85..0f8ddaa1 100644 --- a/pendulum/__version__.py +++ b/pendulum/__version__.py @@ -1 +1,4 @@ +from __future__ import annotations + + __version__ = "3.0.0a" diff --git a/pendulum/_extensions/helpers.py b/pendulum/_extensions/helpers.py index e0b16a33..4dd4c726 100644 --- a/pendulum/_extensions/helpers.py +++ b/pendulum/_extensions/helpers.py @@ -354,6 +354,6 @@ def _get_tzinfo_name(tzinfo: datetime.tzinfo | None) -> str | None: return cast(Timezone, tzinfo).name elif hasattr(tzinfo, "zone"): # pytz timezone - return tzinfo.zone # type: ignore + return tzinfo.zone # type: ignore[no-any-return] return None diff --git a/pendulum/constants.py b/pendulum/constants.py index a3d2a18e..c7b3876a 100644 --- a/pendulum/constants.py +++ b/pendulum/constants.py @@ -1,6 +1,7 @@ # The day constants from __future__ import annotations + SUNDAY = 0 MONDAY = 1 TUESDAY = 2 diff --git a/pendulum/date.py b/pendulum/date.py index 0d8382a4..0fe776ce 100644 --- a/pendulum/date.py +++ b/pendulum/date.py @@ -30,6 +30,7 @@ from pendulum.interval import Interval from pendulum.mixins.default import FormattableMixin + if TYPE_CHECKING: from typing_extensions import Self from typing_extensions import SupportsIndex @@ -187,8 +188,9 @@ def is_anniversary(self, dt: date | None = None) -> bool: return (self.month, self.day) == (instance.month, instance.day) # the additional method for checking if today is the anniversary day - # the alias is provided to start using a new name and keep the backward compatibility - # the old name can be completely replaced with the new in one of the future versions + # the alias is provided to start using a new name and keep the backward + # compatibility the old name can be completely replaced with the new in + # one of the future versions is_birthday = is_anniversary # ADDITIONS AND SUBTRACTIONS @@ -516,7 +518,8 @@ def first_of(self, unit: str, day_of_week: int | None = None) -> Self: Returns an instance set to the first occurrence of a given day of the week in the current unit. If no day_of_week is provided, modify to the first day of the unit. - Use the supplied consts to indicate the desired day_of_week, ex. pendulum.MONDAY. + Use the supplied consts to indicate the desired day_of_week, + ex. pendulum.MONDAY. Supported units are month, quarter and year. @@ -533,7 +536,8 @@ def last_of(self, unit: str, day_of_week: int | None = None) -> Self: Returns an instance set to the last occurrence of a given day of the week in the current unit. If no day_of_week is provided, modify to the last day of the unit. - Use the supplied consts to indicate the desired day_of_week, ex. pendulum.MONDAY. + Use the supplied consts to indicate the desired day_of_week, + ex. pendulum.MONDAY. Supported units are month, quarter and year. diff --git a/pendulum/datetime.py b/pendulum/datetime.py index d265aece..93f0ade6 100644 --- a/pendulum/datetime.py +++ b/pendulum/datetime.py @@ -41,6 +41,7 @@ from pendulum.tz.timezone import FixedTimezone from pendulum.tz.timezone import Timezone + if TYPE_CHECKING: from typing_extensions import Literal from typing_extensions import Self @@ -913,10 +914,7 @@ def next(self, day_of_week: int | None = None, keep_time: bool = False) -> Self: if day_of_week < SUNDAY or day_of_week > SATURDAY: raise ValueError("Invalid day of week") - if keep_time: - dt = self - else: - dt = self.start_of("day") + dt = self if keep_time else self.start_of("day") dt = dt.add(days=1) while dt.day_of_week != day_of_week: @@ -937,10 +935,7 @@ def previous(self, day_of_week: int | None = None, keep_time: bool = False) -> S if day_of_week < SUNDAY or day_of_week > SATURDAY: raise ValueError("Invalid day of week") - if keep_time: - dt = self - else: - dt = self.start_of("day") + dt = self if keep_time else self.start_of("day") dt = dt.subtract(days=1) while dt.day_of_week != day_of_week: @@ -953,7 +948,8 @@ def first_of(self, unit: str, day_of_week: int | None = None) -> Self: Returns an instance set to the first occurrence of a given day of the week in the current unit. If no day_of_week is provided, modify to the first day of the unit. - Use the supplied consts to indicate the desired day_of_week, ex. DateTime.MONDAY. + Use the supplied consts to indicate the desired day_of_week, + ex. DateTime.MONDAY. Supported units are month, quarter and year. """ @@ -967,7 +963,8 @@ def last_of(self, unit: str, day_of_week: int | None = None) -> Self: Returns an instance set to the last occurrence of a given day of the week in the current unit. If no day_of_week is provided, modify to the last day of the unit. - Use the supplied consts to indicate the desired day_of_week, ex. DateTime.MONDAY. + Use the supplied consts to indicate the desired day_of_week, + ex. DateTime.MONDAY. Supported units are month, quarter and year. """ diff --git a/pendulum/duration.py b/pendulum/duration.py index 2e9daf2d..a07c9c79 100644 --- a/pendulum/duration.py +++ b/pendulum/duration.py @@ -13,6 +13,7 @@ from pendulum.constants import US_PER_SECOND from pendulum.utils._compat import PYPY + if TYPE_CHECKING: from typing_extensions import Self @@ -376,7 +377,9 @@ 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] + return cast( + int, usec // other._to_microseconds() # type: ignore[attr-defined] + ) if isinstance(other, int): return self.__class__( @@ -401,7 +404,9 @@ 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] + return cast( + float, usec / other._to_microseconds() # type: ignore[attr-defined] + ) if isinstance(other, int): return self.__class__( @@ -427,7 +432,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] + r = self._to_microseconds() % other._to_microseconds() # type: ignore[attr-defined] # noqa: E501 return self.__class__(0, 0, r) @@ -435,7 +440,7 @@ def __mod__(self, other: timedelta) -> Self: def __divmod__(self, other: timedelta) -> tuple[int, Duration]: if isinstance(other, timedelta): - q, r = divmod(self._to_microseconds(), other._to_microseconds()) # type: ignore[attr-defined] + q, r = divmod(self._to_microseconds(), other._to_microseconds()) # type: ignore[attr-defined] # noqa: E501 return q, self.__class__(0, 0, r) diff --git a/pendulum/exceptions.py b/pendulum/exceptions.py index 3ab4db91..16872119 100644 --- a/pendulum/exceptions.py +++ b/pendulum/exceptions.py @@ -1,8 +1,13 @@ from __future__ import annotations -from .parsing.exceptions import ParserError # noqa +from pendulum.parsing.exceptions import ParserError class PendulumException(Exception): - pass + + +__all__ = [ + "ParserError", + "PendulumException", +] diff --git a/pendulum/formatting/__init__.py b/pendulum/formatting/__init__.py index 975c409a..0c6e725d 100644 --- a/pendulum/formatting/__init__.py +++ b/pendulum/formatting/__init__.py @@ -2,4 +2,5 @@ from pendulum.formatting.formatter import Formatter + __all__ = ["Formatter"] diff --git a/pendulum/formatting/difference_formatter.py b/pendulum/formatting/difference_formatter.py index dad219dd..588c0727 100644 --- a/pendulum/formatting/difference_formatter.py +++ b/pendulum/formatting/difference_formatter.py @@ -4,6 +4,7 @@ from pendulum.locales.locale import Locale + if t.TYPE_CHECKING: from pendulum import Duration @@ -31,10 +32,7 @@ def format( :param absolute: Whether it's an absolute difference or not :param locale: The locale to use """ - if locale is None: - locale = self._locale - else: - locale = Locale.load(locale) + locale = self._locale if locale is None else Locale.load(locale) if diff.years > 0: unit = "year" diff --git a/pendulum/formatting/formatter.py b/pendulum/formatting/formatter.py index 032daaaa..d1bbab76 100644 --- a/pendulum/formatting/formatter.py +++ b/pendulum/formatting/formatter.py @@ -14,6 +14,7 @@ from pendulum.locales.locale import Locale + if TYPE_CHECKING: from pendulum import Timezone @@ -287,10 +288,7 @@ def _format_token(self, dt: pendulum.DateTime, token: str, locale: Locale) -> st offset = dt.utcoffset() or datetime.timedelta() minutes = offset.total_seconds() / 60 - if minutes >= 0: - sign = "+" - else: - sign = "-" + sign = "+" if minutes >= 0 else "-" hour, minute = divmod(abs(int(minutes)), 60) @@ -395,9 +393,8 @@ def parse( if not re.search("^" + pattern + "$", time): raise ValueError(f"String does not match format {fmt}") - _get_parsed_values: Callable[ - [Match[str]], Any - ] = lambda m: self._get_parsed_values(m, parsed, loaded_locale, now) + def _get_parsed_values(m: Match[str]) -> Any: + return self._get_parsed_values(m, parsed, loaded_locale, now) re.sub(pattern, _get_parsed_values, time) @@ -502,9 +499,9 @@ def _check_parsed( raise ValueError("Invalid date") pm = parsed["meridiem"] == "pm" - validated["hour"] %= 12 # type: ignore + validated["hour"] %= 12 # type: ignore[operator] if pm: - validated["hour"] += 12 # type: ignore + validated["hour"] += 12 # type: ignore[operator] if validated["month"] is None: if parsed["year"] is not None: diff --git a/pendulum/helpers.py b/pendulum/helpers.py index 72c527db..6b62fe77 100644 --- a/pendulum/helpers.py +++ b/pendulum/helpers.py @@ -17,6 +17,7 @@ from pendulum.formatting.difference_formatter import DifferenceFormatter from pendulum.locales.locale import Locale + if TYPE_CHECKING: # Prevent import cycles from pendulum.duration import Duration @@ -27,7 +28,6 @@ _D = TypeVar("_D", bound=date) try: - # nopycln: file # noqa: E800 if not with_extensions or struct.calcsize("P") == 4: raise ImportError() diff --git a/pendulum/interval.py b/pendulum/interval.py index ed2cfe63..0c773058 100644 --- a/pendulum/interval.py +++ b/pendulum/interval.py @@ -17,12 +17,13 @@ from pendulum.duration import Duration from pendulum.helpers import precise_diff + if TYPE_CHECKING: from typing_extensions import Self from typing_extensions import SupportsIndex from pendulum.helpers import PreciseDiff - from pendulum.locales.locale import Locale # noqa + from pendulum.locales.locale import Locale class Interval(Duration): @@ -264,7 +265,7 @@ def in_words(self, locale: str | None = None, separator: str = " ") -> str: :param locale: The locale to use. Defaults to current locale. :param separator: The separator to use between each unit """ - from pendulum.locales.locale import Locale # noqa + from pendulum.locales.locale import Locale periods = [ ("year", self.years), diff --git a/pendulum/mixins/default.py b/pendulum/mixins/default.py index 59f985e5..6444b2a8 100644 --- a/pendulum/mixins/default.py +++ b/pendulum/mixins/default.py @@ -2,6 +2,7 @@ from pendulum.formatting import Formatter + _formatter = Formatter() diff --git a/pendulum/parser.py b/pendulum/parser.py index 1b050621..d39842f6 100644 --- a/pendulum/parser.py +++ b/pendulum/parser.py @@ -9,6 +9,7 @@ from pendulum.parsing import parse as base_parse from pendulum.tz.timezone import UTC + if t.TYPE_CHECKING: from pendulum.date import Date from pendulum.datetime import DateTime diff --git a/pendulum/parsing/__init__.py b/pendulum/parsing/__init__.py index ca465926..3b64994a 100644 --- a/pendulum/parsing/__init__.py +++ b/pendulum/parsing/__init__.py @@ -17,6 +17,7 @@ from pendulum.parsing.exceptions import ParserError + with_extensions = os.getenv("PENDULUM_EXTENSIONS", "1") == "1" try: @@ -30,7 +31,7 @@ from pendulum.parsing.iso8601 import parse_iso8601 # type: ignore[assignment] COMMON = re.compile( - # Date (optional) # noqa: E800 + # Date (optional) # noqa: ERA001 "^" "(?P" " (?P" # Classic date (YYYY-MM-DD) @@ -41,10 +42,10 @@ " )?" " )" ")?" - # Time (optional) # noqa: E800 - "(?P