Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix failing builds and add read the docs configuration #1163

Merged
merged 1 commit into from
Sep 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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