Skip to content

Commit

Permalink
Fix failing builds and drop Py36 and 37 support (#1163)
Browse files Browse the repository at this point in the history
  • Loading branch information
jadchaar committed Sep 12, 2023
1 parent 74a759b commit de0aea9
Show file tree
Hide file tree
Showing 20 changed files with 74 additions and 443 deletions.
23 changes: 11 additions & 12 deletions .github/workflows/continuous_integration.yml
Expand Up @@ -9,18 +9,18 @@ on:
- cron: "0 0 1 * *"

jobs:
test:
unit-tests:
name: ${{ matrix.os }} (${{ matrix.python-version }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
python-version: ["pypy-3.7", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"]
python-version: ["pypy-3.9", "3.8", "3.9", "3.10", "3.11", "3.12-dev"]
os: [ubuntu-latest, macos-latest, windows-latest]
exclude:
# pypy3 randomly fails on Windows builds
- os: windows-latest
python-version: "pypy-3.7"
python-version: "pypy-3.9"
include:
- os: ubuntu-latest
path: ~/.cache/pip
Expand Down Expand Up @@ -51,26 +51,25 @@ jobs:
with:
file: coverage.xml

lint:
linting:
name: Linting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10
uses: actions/setup-python@v4
with:
python-version: "3.10"
- name: Cache pip
uses: actions/cache@v3
- uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }}
restore-keys: ${{ runner.os }}-pip-
- name: Cache pre-commit
uses: actions/cache@v3
- uses: actions/cache@v3
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
with:
python-version: "3.11"
- name: Install dependencies
run: |
pip install -U pip setuptools wheel
Expand Down
14 changes: 7 additions & 7 deletions .pre-commit-config.yaml
Expand Up @@ -2,7 +2,7 @@ default_language_version:
python: python3
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
rev: v4.4.0
hooks:
- id: check-ast
- id: check-yaml
Expand All @@ -18,16 +18,16 @@ repos:
args: [requirements/requirements.txt, requirements/requirements-docs.txt, requirements/requirements-tests.txt]
- id: trailing-whitespace
- repo: https://github.com/timothycrosley/isort
rev: 5.10.1
rev: 5.12.0
hooks:
- id: isort
- repo: https://github.com/asottile/pyupgrade
rev: v3.2.0
rev: v3.10.1
hooks:
- id: pyupgrade
args: [--py36-plus]
- repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.9.0
rev: v1.10.0
hooks:
- id: python-no-eval
- id: python-check-blanket-noqa
Expand All @@ -38,17 +38,17 @@ repos:
- id: rst-inline-touching-normal
- id: text-unicode-replacement-char
- repo: https://github.com/psf/black
rev: 22.10.0
rev: 23.9.1
hooks:
- id: black
args: [--safe, --quiet, --target-version=py36]
- repo: https://github.com/pycqa/flake8
rev: 5.0.4
rev: 6.1.0
hooks:
- id: flake8
additional_dependencies: [flake8-bugbear,flake8-annotations]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.982
rev: v1.5.1
hooks:
- id: mypy
additional_dependencies: [types-python-dateutil]
29 changes: 29 additions & 0 deletions .readthedocs.yaml
@@ -0,0 +1,29 @@
# Read the Docs configuration file for Sphinx projects
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

version: 2

build:
os: ubuntu-22.04
tools:
python: "3.11"

# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/conf.py
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
# builder: "dirhtml"
# Fail on all warnings to avoid broken references
# fail_on_warning: true

# Optionally build your docs in additional formats such as PDF and ePub
# formats:
# - pdf
# - epub

# Optional but recommended, declare the Python requirements required
# to build your documentation
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: requirements/requirements-docs.txt
2 changes: 1 addition & 1 deletion LICENSE
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright 2021 Chris Smith
Copyright 2023 Chris Smith

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
7 changes: 3 additions & 4 deletions Makefile
@@ -1,15 +1,14 @@
.PHONY: auto test docs clean

auto: build310
auto: build311

build36: PYTHON_VER = python3.6
build37: PYTHON_VER = python3.7
build38: PYTHON_VER = python3.8
build39: PYTHON_VER = python3.9
build310: PYTHON_VER = python3.10
build311: PYTHON_VER = python3.11
build312: PYTHON_VER = python3.12

build36 build37 build38 build39 build310: clean
build36 build37 build38 build39 build310 build311 build312: clean
$(PYTHON_VER) -m venv venv
. venv/bin/activate; \
pip install -U pip setuptools wheel; \
Expand Down
21 changes: 2 additions & 19 deletions arrow/arrow.py
Expand Up @@ -168,9 +168,9 @@ def __init__(
isinstance(tzinfo, dt_tzinfo)
and hasattr(tzinfo, "localize")
and hasattr(tzinfo, "zone")
and tzinfo.zone # type: ignore[attr-defined]
and tzinfo.zone
):
tzinfo = parser.TzinfoParser.parse(tzinfo.zone) # type: ignore[attr-defined]
tzinfo = parser.TzinfoParser.parse(tzinfo.zone)
elif isinstance(tzinfo, str):
tzinfo = parser.TzinfoParser.parse(tzinfo)

Expand Down Expand Up @@ -792,7 +792,6 @@ def __str__(self) -> str:
return self._datetime.isoformat()

def __format__(self, formatstr: str) -> str:

if len(formatstr) > 0:
return self.format(formatstr)

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

def __getattr__(self, name: str) -> int:

if name == "week":
return self.isocalendar()[1]

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

for key, value in kwargs.items():

if key in self._ATTRS:
absolute_kwargs[key] = value
elif key in ["week", "quarter"]:
Expand Down Expand Up @@ -1022,7 +1019,6 @@ def shift(self, **kwargs: Any) -> "Arrow":
additional_attrs = ["weeks", "quarters", "weekday"]

for key, value in kwargs.items():

if key in self._ATTRS_PLURAL or key in additional_attrs:
relative_kwargs[key] = value
else:
Expand Down Expand Up @@ -1263,7 +1259,6 @@ def humanize(
return locale.describe(granularity, delta, only_distance=only_distance)

else:

if not granularity:
raise ValueError(
"Empty granularity list provided. "
Expand Down Expand Up @@ -1367,7 +1362,6 @@ def dehumanize(self, input_string: str, locale: str = "en_us") -> "Arrow":

# Search input string for each time unit within locale
for unit, unit_object in locale_obj.timeframes.items():

# Need to check the type of unit_object to create the correct dictionary
if isinstance(unit_object, Mapping):
strings_to_search = unit_object
Expand All @@ -1378,7 +1372,6 @@ def dehumanize(self, input_string: str, locale: str = "en_us") -> "Arrow":
# Needs to cycle all through strings as some locales have strings that
# could overlap in a regex match, since input validation isn't being performed.
for time_delta, time_string in strings_to_search.items():

# Replace {0} with regex \d representing digits
search_string = str(time_string)
search_string = search_string.format(r"\d+")
Expand Down Expand Up @@ -1718,7 +1711,6 @@ def for_json(self) -> str:
# math

def __add__(self, other: Any) -> "Arrow":

if isinstance(other, (timedelta, relativedelta)):
return self.fromdatetime(self._datetime + other, self._datetime.tzinfo)

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

def __sub__(self, other: Any) -> Union[timedelta, "Arrow"]:

if isinstance(other, (timedelta, relativedelta)):
return self.fromdatetime(self._datetime - other, self._datetime.tzinfo)

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

def __rsub__(self, other: Any) -> timedelta:

if isinstance(other, dt_datetime):
return other - self._datetime

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

def __eq__(self, other: Any) -> bool:

if not isinstance(other, (Arrow, dt_datetime)):
return False

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

def __ne__(self, other: Any) -> bool:

if not isinstance(other, (Arrow, dt_datetime)):
return True

return not self.__eq__(other)

def __gt__(self, other: Any) -> bool:

if not isinstance(other, (Arrow, dt_datetime)):
return NotImplemented

return self._datetime > self._get_datetime(other)

def __ge__(self, other: Any) -> bool:

if not isinstance(other, (Arrow, dt_datetime)):
return NotImplemented

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

def __lt__(self, other: Any) -> bool:

if not isinstance(other, (Arrow, dt_datetime)):
return NotImplemented

return self._datetime < self._get_datetime(other)

def __le__(self, other: Any) -> bool:

if not isinstance(other, (Arrow, dt_datetime)):
return NotImplemented

Expand Down Expand Up @@ -1865,7 +1849,6 @@ def _get_frames(cls, name: _T_FRAMES) -> Tuple[str, str, int]:
def _get_iteration_params(cls, end: Any, limit: Optional[int]) -> Tuple[Any, int]:
"""Sets default end and limit values for range method."""
if end is None:

if limit is None:
raise ValueError("One of 'end' or 'limit' is required.")

Expand Down
3 changes: 0 additions & 3 deletions arrow/factory.py
Expand Up @@ -267,11 +267,9 @@ def get(self, *args: Any, **kwargs: Any) -> Arrow:
raise TypeError(f"Cannot parse single argument of type {type(arg)!r}.")

elif arg_count == 2:

arg_1, arg_2 = args[0], args[1]

if isinstance(arg_1, datetime):

# (datetime, tzinfo/str) -> fromdatetime @ tzinfo
if isinstance(arg_2, (dt_tzinfo, str)):
return self.type.fromdatetime(arg_1, tzinfo=arg_2)
Expand All @@ -281,7 +279,6 @@ def get(self, *args: Any, **kwargs: Any) -> Arrow:
)

elif isinstance(arg_1, date):

# (date, tzinfo/str) -> fromdate @ tzinfo
if isinstance(arg_2, (dt_tzinfo, str)):
return self.type.fromdate(arg_1, tzinfo=arg_2)
Expand Down
4 changes: 0 additions & 4 deletions arrow/formatter.py
Expand Up @@ -29,7 +29,6 @@


class DateTimeFormatter:

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

def __init__(self, locale: str = DEFAULT_LOCALE) -> None:

self.locale = locales.get_locale(locale)

def format(cls, dt: datetime, fmt: str) -> str:

# FIXME: _format_token() is nullable
return cls._FORMAT_RE.sub(
lambda m: cast(str, cls._format_token(dt, m.group(0))), fmt
)

def _format_token(self, dt: datetime, token: Optional[str]) -> Optional[str]:

if token and token.startswith("[") and token.endswith("]"):
return token[1:-1]

Expand Down

0 comments on commit de0aea9

Please sign in to comment.