Skip to content

Commit de0aea9

Browse files
authored
Fix failing builds and drop Py36 and 37 support (#1163)
1 parent 74a759b commit de0aea9

20 files changed

+74
-443
lines changed

.github/workflows/continuous_integration.yml

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,18 @@ on:
99
- cron: "0 0 1 * *"
1010

1111
jobs:
12-
test:
12+
unit-tests:
1313
name: ${{ matrix.os }} (${{ matrix.python-version }})
1414
runs-on: ${{ matrix.os }}
1515
strategy:
1616
fail-fast: false
1717
matrix:
18-
python-version: ["pypy-3.7", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"]
18+
python-version: ["pypy-3.9", "3.8", "3.9", "3.10", "3.11", "3.12-dev"]
1919
os: [ubuntu-latest, macos-latest, windows-latest]
2020
exclude:
2121
# pypy3 randomly fails on Windows builds
2222
- os: windows-latest
23-
python-version: "pypy-3.7"
23+
python-version: "pypy-3.9"
2424
include:
2525
- os: ubuntu-latest
2626
path: ~/.cache/pip
@@ -51,26 +51,25 @@ jobs:
5151
with:
5252
file: coverage.xml
5353

54-
lint:
54+
linting:
55+
name: Linting
5556
runs-on: ubuntu-latest
5657
steps:
5758
- uses: actions/checkout@v3
58-
- name: Set up Python 3.10
59-
uses: actions/setup-python@v4
60-
with:
61-
python-version: "3.10"
62-
- name: Cache pip
63-
uses: actions/cache@v3
59+
- uses: actions/cache@v3
6460
with:
6561
path: ~/.cache/pip
6662
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }}
6763
restore-keys: ${{ runner.os }}-pip-
68-
- name: Cache pre-commit
69-
uses: actions/cache@v3
64+
- uses: actions/cache@v3
7065
with:
7166
path: ~/.cache/pre-commit
7267
key: ${{ runner.os }}-pre-commit-${{ hashFiles('**/.pre-commit-config.yaml') }}
7368
restore-keys: ${{ runner.os }}-pre-commit-
69+
- name: Set up Python ${{ runner.python-version }}
70+
uses: actions/setup-python@v4
71+
with:
72+
python-version: "3.11"
7473
- name: Install dependencies
7574
run: |
7675
pip install -U pip setuptools wheel

.pre-commit-config.yaml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ default_language_version:
22
python: python3
33
repos:
44
- repo: https://github.com/pre-commit/pre-commit-hooks
5-
rev: v4.3.0
5+
rev: v4.4.0
66
hooks:
77
- id: check-ast
88
- id: check-yaml
@@ -18,16 +18,16 @@ repos:
1818
args: [requirements/requirements.txt, requirements/requirements-docs.txt, requirements/requirements-tests.txt]
1919
- id: trailing-whitespace
2020
- repo: https://github.com/timothycrosley/isort
21-
rev: 5.10.1
21+
rev: 5.12.0
2222
hooks:
2323
- id: isort
2424
- repo: https://github.com/asottile/pyupgrade
25-
rev: v3.2.0
25+
rev: v3.10.1
2626
hooks:
2727
- id: pyupgrade
2828
args: [--py36-plus]
2929
- repo: https://github.com/pre-commit/pygrep-hooks
30-
rev: v1.9.0
30+
rev: v1.10.0
3131
hooks:
3232
- id: python-no-eval
3333
- id: python-check-blanket-noqa
@@ -38,17 +38,17 @@ repos:
3838
- id: rst-inline-touching-normal
3939
- id: text-unicode-replacement-char
4040
- repo: https://github.com/psf/black
41-
rev: 22.10.0
41+
rev: 23.9.1
4242
hooks:
4343
- id: black
4444
args: [--safe, --quiet, --target-version=py36]
4545
- repo: https://github.com/pycqa/flake8
46-
rev: 5.0.4
46+
rev: 6.1.0
4747
hooks:
4848
- id: flake8
4949
additional_dependencies: [flake8-bugbear,flake8-annotations]
5050
- repo: https://github.com/pre-commit/mirrors-mypy
51-
rev: v0.982
51+
rev: v1.5.1
5252
hooks:
5353
- id: mypy
5454
additional_dependencies: [types-python-dateutil]

.readthedocs.yaml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Read the Docs configuration file for Sphinx projects
2+
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
3+
4+
version: 2
5+
6+
build:
7+
os: ubuntu-22.04
8+
tools:
9+
python: "3.11"
10+
11+
# Build documentation in the "docs/" directory with Sphinx
12+
sphinx:
13+
configuration: docs/conf.py
14+
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
15+
# builder: "dirhtml"
16+
# Fail on all warnings to avoid broken references
17+
# fail_on_warning: true
18+
19+
# Optionally build your docs in additional formats such as PDF and ePub
20+
# formats:
21+
# - pdf
22+
# - epub
23+
24+
# Optional but recommended, declare the Python requirements required
25+
# to build your documentation
26+
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
27+
python:
28+
install:
29+
- requirements: requirements/requirements-docs.txt

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@
186186
same "printed page" as the copyright notice for easier
187187
identification within third-party archives.
188188

189-
Copyright 2021 Chris Smith
189+
Copyright 2023 Chris Smith
190190

191191
Licensed under the Apache License, Version 2.0 (the "License");
192192
you may not use this file except in compliance with the License.

Makefile

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
.PHONY: auto test docs clean
22

3-
auto: build310
3+
auto: build311
44

5-
build36: PYTHON_VER = python3.6
6-
build37: PYTHON_VER = python3.7
75
build38: PYTHON_VER = python3.8
86
build39: PYTHON_VER = python3.9
97
build310: PYTHON_VER = python3.10
108
build311: PYTHON_VER = python3.11
9+
build312: PYTHON_VER = python3.12
1110

12-
build36 build37 build38 build39 build310: clean
11+
build36 build37 build38 build39 build310 build311 build312: clean
1312
$(PYTHON_VER) -m venv venv
1413
. venv/bin/activate; \
1514
pip install -U pip setuptools wheel; \

arrow/arrow.py

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,9 @@ def __init__(
168168
isinstance(tzinfo, dt_tzinfo)
169169
and hasattr(tzinfo, "localize")
170170
and hasattr(tzinfo, "zone")
171-
and tzinfo.zone # type: ignore[attr-defined]
171+
and tzinfo.zone
172172
):
173-
tzinfo = parser.TzinfoParser.parse(tzinfo.zone) # type: ignore[attr-defined]
173+
tzinfo = parser.TzinfoParser.parse(tzinfo.zone)
174174
elif isinstance(tzinfo, str):
175175
tzinfo = parser.TzinfoParser.parse(tzinfo)
176176

@@ -792,7 +792,6 @@ def __str__(self) -> str:
792792
return self._datetime.isoformat()
793793

794794
def __format__(self, formatstr: str) -> str:
795-
796795
if len(formatstr) > 0:
797796
return self.format(formatstr)
798797

@@ -804,7 +803,6 @@ def __hash__(self) -> int:
804803
# attributes and properties
805804

806805
def __getattr__(self, name: str) -> int:
807-
808806
if name == "week":
809807
return self.isocalendar()[1]
810808

@@ -965,7 +963,6 @@ def replace(self, **kwargs: Any) -> "Arrow":
965963
absolute_kwargs = {}
966964

967965
for key, value in kwargs.items():
968-
969966
if key in self._ATTRS:
970967
absolute_kwargs[key] = value
971968
elif key in ["week", "quarter"]:
@@ -1022,7 +1019,6 @@ def shift(self, **kwargs: Any) -> "Arrow":
10221019
additional_attrs = ["weeks", "quarters", "weekday"]
10231020

10241021
for key, value in kwargs.items():
1025-
10261022
if key in self._ATTRS_PLURAL or key in additional_attrs:
10271023
relative_kwargs[key] = value
10281024
else:
@@ -1263,7 +1259,6 @@ def humanize(
12631259
return locale.describe(granularity, delta, only_distance=only_distance)
12641260

12651261
else:
1266-
12671262
if not granularity:
12681263
raise ValueError(
12691264
"Empty granularity list provided. "
@@ -1367,7 +1362,6 @@ def dehumanize(self, input_string: str, locale: str = "en_us") -> "Arrow":
13671362

13681363
# Search input string for each time unit within locale
13691364
for unit, unit_object in locale_obj.timeframes.items():
1370-
13711365
# Need to check the type of unit_object to create the correct dictionary
13721366
if isinstance(unit_object, Mapping):
13731367
strings_to_search = unit_object
@@ -1378,7 +1372,6 @@ def dehumanize(self, input_string: str, locale: str = "en_us") -> "Arrow":
13781372
# Needs to cycle all through strings as some locales have strings that
13791373
# could overlap in a regex match, since input validation isn't being performed.
13801374
for time_delta, time_string in strings_to_search.items():
1381-
13821375
# Replace {0} with regex \d representing digits
13831376
search_string = str(time_string)
13841377
search_string = search_string.format(r"\d+")
@@ -1718,7 +1711,6 @@ def for_json(self) -> str:
17181711
# math
17191712

17201713
def __add__(self, other: Any) -> "Arrow":
1721-
17221714
if isinstance(other, (timedelta, relativedelta)):
17231715
return self.fromdatetime(self._datetime + other, self._datetime.tzinfo)
17241716

@@ -1736,7 +1728,6 @@ def __sub__(self, other: Union[dt_datetime, "Arrow"]) -> timedelta:
17361728
pass # pragma: no cover
17371729

17381730
def __sub__(self, other: Any) -> Union[timedelta, "Arrow"]:
1739-
17401731
if isinstance(other, (timedelta, relativedelta)):
17411732
return self.fromdatetime(self._datetime - other, self._datetime.tzinfo)
17421733

@@ -1749,7 +1740,6 @@ def __sub__(self, other: Any) -> Union[timedelta, "Arrow"]:
17491740
return NotImplemented
17501741

17511742
def __rsub__(self, other: Any) -> timedelta:
1752-
17531743
if isinstance(other, dt_datetime):
17541744
return other - self._datetime
17551745

@@ -1758,42 +1748,36 @@ def __rsub__(self, other: Any) -> timedelta:
17581748
# comparisons
17591749

17601750
def __eq__(self, other: Any) -> bool:
1761-
17621751
if not isinstance(other, (Arrow, dt_datetime)):
17631752
return False
17641753

17651754
return self._datetime == self._get_datetime(other)
17661755

17671756
def __ne__(self, other: Any) -> bool:
1768-
17691757
if not isinstance(other, (Arrow, dt_datetime)):
17701758
return True
17711759

17721760
return not self.__eq__(other)
17731761

17741762
def __gt__(self, other: Any) -> bool:
1775-
17761763
if not isinstance(other, (Arrow, dt_datetime)):
17771764
return NotImplemented
17781765

17791766
return self._datetime > self._get_datetime(other)
17801767

17811768
def __ge__(self, other: Any) -> bool:
1782-
17831769
if not isinstance(other, (Arrow, dt_datetime)):
17841770
return NotImplemented
17851771

17861772
return self._datetime >= self._get_datetime(other)
17871773

17881774
def __lt__(self, other: Any) -> bool:
1789-
17901775
if not isinstance(other, (Arrow, dt_datetime)):
17911776
return NotImplemented
17921777

17931778
return self._datetime < self._get_datetime(other)
17941779

17951780
def __le__(self, other: Any) -> bool:
1796-
17971781
if not isinstance(other, (Arrow, dt_datetime)):
17981782
return NotImplemented
17991783

@@ -1865,7 +1849,6 @@ def _get_frames(cls, name: _T_FRAMES) -> Tuple[str, str, int]:
18651849
def _get_iteration_params(cls, end: Any, limit: Optional[int]) -> Tuple[Any, int]:
18661850
"""Sets default end and limit values for range method."""
18671851
if end is None:
1868-
18691852
if limit is None:
18701853
raise ValueError("One of 'end' or 'limit' is required.")
18711854

arrow/factory.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -267,11 +267,9 @@ def get(self, *args: Any, **kwargs: Any) -> Arrow:
267267
raise TypeError(f"Cannot parse single argument of type {type(arg)!r}.")
268268

269269
elif arg_count == 2:
270-
271270
arg_1, arg_2 = args[0], args[1]
272271

273272
if isinstance(arg_1, datetime):
274-
275273
# (datetime, tzinfo/str) -> fromdatetime @ tzinfo
276274
if isinstance(arg_2, (dt_tzinfo, str)):
277275
return self.type.fromdatetime(arg_1, tzinfo=arg_2)
@@ -281,7 +279,6 @@ def get(self, *args: Any, **kwargs: Any) -> Arrow:
281279
)
282280

283281
elif isinstance(arg_1, date):
284-
285282
# (date, tzinfo/str) -> fromdate @ tzinfo
286283
if isinstance(arg_2, (dt_tzinfo, str)):
287284
return self.type.fromdate(arg_1, tzinfo=arg_2)

arrow/formatter.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929

3030

3131
class DateTimeFormatter:
32-
3332
# This pattern matches characters enclosed in square brackets are matched as
3433
# an atomic group. For more info on atomic groups and how to they are
3534
# emulated in Python's re library, see https://stackoverflow.com/a/13577411/2701578
@@ -41,18 +40,15 @@ class DateTimeFormatter:
4140
locale: locales.Locale
4241

4342
def __init__(self, locale: str = DEFAULT_LOCALE) -> None:
44-
4543
self.locale = locales.get_locale(locale)
4644

4745
def format(cls, dt: datetime, fmt: str) -> str:
48-
4946
# FIXME: _format_token() is nullable
5047
return cls._FORMAT_RE.sub(
5148
lambda m: cast(str, cls._format_token(dt, m.group(0))), fmt
5249
)
5350

5451
def _format_token(self, dt: datetime, token: Optional[str]) -> Optional[str]:
55-
5652
if token and token.startswith("[") and token.endswith("]"):
5753
return token[1:-1]
5854

0 commit comments

Comments
 (0)