Skip to content

Commit

Permalink
Merge branch 'master' into fix-farsi-months
Browse files Browse the repository at this point in the history
  • Loading branch information
jadchaar authored Oct 24, 2024
2 parents ab1ff62 + 540182a commit 9610acd
Show file tree
Hide file tree
Showing 23 changed files with 200 additions and 102 deletions.
6 changes: 6 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
18 changes: 9 additions & 9 deletions .github/workflows/continuous_integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["pypy-3.9", "3.8", "3.9", "3.10", "3.11", "3.12-dev"]
python-version: ["pypy-3.9", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
os: [ubuntu-latest, macos-latest, windows-latest]
exclude:
# pypy3 randomly fails on Windows builds
Expand All @@ -29,15 +29,15 @@ jobs:
- os: windows-latest
path: ~\AppData\Local\pip\Cache
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Cache pip
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ${{ matrix.path }}
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }}
restore-keys: ${{ runner.os }}-pip-
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
Expand All @@ -47,27 +47,27 @@ jobs:
- name: Test with tox
run: tox
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
with:
file: coverage.xml

linting:
name: Linting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }}
restore-keys: ${{ runner.os }}-pip-
- uses: actions/cache@v3
- uses: actions/cache@v4
with:
path: ~/.cache/pre-commit
key: ${{ runner.os }}-pre-commit-${{ hashFiles('**/.pre-commit-config.yaml') }}
restore-keys: ${{ runner.os }}-pre-commit-
- name: Set up Python ${{ runner.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ jobs:
release-to-pypi:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }}
restore-keys: ${{ runner.os }}-pip-
- uses: actions/setup-python@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
Expand Down
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ default_language_version:
python: python3
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v4.5.0
hooks:
- id: check-ast
- id: check-yaml
Expand All @@ -18,11 +18,11 @@ repos:
args: [requirements/requirements.txt, requirements/requirements-docs.txt, requirements/requirements-tests.txt]
- id: trailing-whitespace
- repo: https://github.com/timothycrosley/isort
rev: 5.12.0
rev: 5.13.2
hooks:
- id: isort
- repo: https://github.com/asottile/pyupgrade
rev: v3.13.0
rev: v3.16.0
hooks:
- id: pyupgrade
args: [--py36-plus]
Expand All @@ -48,7 +48,7 @@ repos:
- id: flake8
additional_dependencies: [flake8-bugbear,flake8-annotations]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.5.1
rev: v1.10.0
hooks:
- id: mypy
additional_dependencies: [types-python-dateutil]
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ build39: PYTHON_VER = python3.9
build310: PYTHON_VER = python3.10
build311: PYTHON_VER = python3.11
build312: PYTHON_VER = python3.12
build313: PYTHON_VER = python3.13

build36 build37 build38 build39 build310 build311 build312: clean
build36 build37 build38 build39 build310 build311 build312 build313: clean
$(PYTHON_VER) -m venv venv
. venv/bin/activate; \
pip install -U pip setuptools wheel; \
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Features
--------

- Fully-implemented, drop-in replacement for datetime
- Support for Python 3.6+
- Support for Python 3.8+
- Timezone-aware and UTC by default
- Super-simple creation options for many common input scenarios
- ``shift`` method with support for relative offsets, including weeks
Expand Down
40 changes: 22 additions & 18 deletions arrow/arrow.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,24 @@
"""


import calendar
import re
import sys
from datetime import date
from datetime import datetime as dt_datetime
from datetime import time as dt_time
from datetime import timedelta
from datetime import timedelta, timezone
from datetime import tzinfo as dt_tzinfo
from math import trunc
from time import struct_time
from typing import (
Any,
ClassVar,
Final,
Generator,
Iterable,
List,
Literal,
Mapping,
Optional,
Tuple,
Expand All @@ -36,12 +37,6 @@
from arrow.constants import DEFAULT_LOCALE, DEHUMANIZE_LOCALES
from arrow.locales import TimeFrameLiteral

if sys.version_info < (3, 8): # pragma: no cover
from typing_extensions import Final, Literal
else:
from typing import Final, Literal # pragma: no cover


TZ_EXPR = Union[dt_tzinfo, str]

_T_FRAMES = Literal[
Expand Down Expand Up @@ -496,7 +491,7 @@ def range(

values = [getattr(current, f) for f in cls._ATTRS]
current = cls(*values, tzinfo=tzinfo).shift( # type: ignore[misc]
**{frame_relative: relative_steps}
check_imaginary=True, **{frame_relative: relative_steps}
)

if frame in ["month", "quarter", "year"] and current.day < original_day:
Expand Down Expand Up @@ -587,7 +582,9 @@ def span(
elif frame_absolute == "quarter":
floor = floor.shift(months=-((self.month - 1) % 3))

ceil = floor.shift(**{frame_relative: count * relative_steps})
ceil = floor.shift(
check_imaginary=True, **{frame_relative: count * relative_steps}
)

if bounds[0] == "(":
floor = floor.shift(microseconds=+1)
Expand Down Expand Up @@ -802,15 +799,15 @@ def __hash__(self) -> int:

# attributes and properties

def __getattr__(self, name: str) -> int:
def __getattr__(self, name: str) -> Any:
if name == "week":
return self.isocalendar()[1]

if name == "quarter":
return int((self.month - 1) / self._MONTHS_PER_QUARTER) + 1

if not name.startswith("_"):
value: Optional[int] = getattr(self._datetime, name, None)
value: Optional[Any] = getattr(self._datetime, name, None)

if value is not None:
return value
Expand Down Expand Up @@ -985,10 +982,15 @@ def replace(self, **kwargs: Any) -> "Arrow":

return self.fromdatetime(current)

def shift(self, **kwargs: Any) -> "Arrow":
def shift(self, check_imaginary: bool = True, **kwargs: Any) -> "Arrow":
"""Returns a new :class:`Arrow <arrow.arrow.Arrow>` object with attributes updated
according to inputs.
Parameters:
check_imaginary (bool): If True (default), will check for and resolve
imaginary times (like during DST transitions). If False, skips this check.
Use pluralized property names to relatively shift their current value:
>>> import arrow
Expand Down Expand Up @@ -1035,7 +1037,8 @@ def shift(self, **kwargs: Any) -> "Arrow":

current = self._datetime + relativedelta(**relative_kwargs)

if not dateutil_tz.datetime_exists(current):
# If check_imaginary is True, perform the check for imaginary times (DST transitions)
if check_imaginary and not dateutil_tz.datetime_exists(current):
current = dateutil_tz.resolve_imaginary(current)

return self.fromdatetime(current)
Expand Down Expand Up @@ -1092,7 +1095,8 @@ def format(
self, fmt: str = "YYYY-MM-DD HH:mm:ssZZ", locale: str = DEFAULT_LOCALE
) -> str:
"""Returns a string representation of the :class:`Arrow <arrow.arrow.Arrow>` object,
formatted according to the provided format string.
formatted according to the provided format string. For a list of formatting values,
see :ref:`supported-tokens`
:param fmt: the format string.
:param locale: the locale to format.
Expand Down Expand Up @@ -1147,7 +1151,7 @@ def humanize(
locale = locales.get_locale(locale)

if other is None:
utc = dt_datetime.utcnow().replace(tzinfo=dateutil_tz.tzutc())
utc = dt_datetime.now(timezone.utc).replace(tzinfo=dateutil_tz.tzutc())
dt = utc.astimezone(self._datetime.tzinfo)

elif isinstance(other, Arrow):
Expand Down Expand Up @@ -1444,7 +1448,7 @@ def dehumanize(self, input_string: str, locale: str = "en_us") -> "Arrow":

time_changes = {k: sign_val * v for k, v in time_object_info.items()}

return current_time.shift(**time_changes)
return current_time.shift(check_imaginary=True, **time_changes)

# query functions

Expand Down Expand Up @@ -1862,7 +1866,7 @@ def _get_iteration_params(cls, end: Any, limit: Optional[int]) -> Tuple[Any, int
@staticmethod
def _is_last_day_of_month(date: "Arrow") -> bool:
"""Returns a boolean indicating whether the datetime is the last day of the month."""
return date.day == calendar.monthrange(date.year, date.month)[1]
return cast(int, date.day) == calendar.monthrange(date.year, date.month)[1]


Arrow.min = Arrow.fromdatetime(dt_datetime.min)
Expand Down
6 changes: 1 addition & 5 deletions arrow/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@

import sys
from datetime import datetime

if sys.version_info < (3, 8): # pragma: no cover
from typing_extensions import Final
else:
from typing import Final # pragma: no cover
from typing import Final

# datetime.max.timestamp() errors on Windows, so we must hardcode
# the highest possible datetime value that can output a timestamp.
Expand Down
1 change: 0 additions & 1 deletion arrow/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"""


import calendar
from datetime import date, datetime
from datetime import tzinfo as dt_tzinfo
Expand Down
9 changes: 1 addition & 8 deletions arrow/formatter.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
"""Provides the :class:`Arrow <arrow.formatter.DateTimeFormatter>` class, an improved formatter for datetimes."""

import re
import sys
from datetime import datetime, timedelta
from typing import Optional, Pattern, cast
from typing import Final, Optional, Pattern, cast

from dateutil import tz as dateutil_tz

from arrow import locales
from arrow.constants import DEFAULT_LOCALE

if sys.version_info < (3, 8): # pragma: no cover
from typing_extensions import Final
else:
from typing import Final # pragma: no cover


FORMAT_ATOM: Final[str] = "YYYY-MM-DD HH:mm:ssZZ"
FORMAT_COOKIE: Final[str] = "dddd, DD-MMM-YYYY HH:mm:ss ZZZ"
FORMAT_RFC822: Final[str] = "ddd, DD MMM YY HH:mm:ss Z"
Expand Down
Loading

0 comments on commit 9610acd

Please sign in to comment.