From 774ac01303d9b6d5f0bb321b6965af10ac050ff8 Mon Sep 17 00:00:00 2001 From: Jad Chaar Date: Fri, 31 Dec 2021 18:14:02 -0500 Subject: [PATCH 1/4] Break up requirements.txt into multiple requirements files (#1080) * Break up requirements.txt into multiple requirements files. * Fix linting --- .github/workflows/continuous_integration.yml | 72 ++++--------------- .pre-commit-config.yaml | 24 ++++--- Makefile | 15 ++-- arrow/locales.py | 4 +- requirements/requirements-docs.txt | 5 ++ .../requirements-tests.txt | 11 ++- requirements/requirements.txt | 2 + tox.ini | 15 ++-- 8 files changed, 59 insertions(+), 89 deletions(-) create mode 100644 requirements/requirements-docs.txt rename requirements-dev.txt => requirements/requirements-tests.txt (51%) create mode 100644 requirements/requirements.txt diff --git a/.github/workflows/continuous_integration.yml b/.github/workflows/continuous_integration.yml index 140bf446..d60e4bd3 100644 --- a/.github/workflows/continuous_integration.yml +++ b/.github/workflows/continuous_integration.yml @@ -12,7 +12,6 @@ jobs: test: name: ${{ matrix.os }} (${{ matrix.python-version }}) runs-on: ${{ matrix.os }} - strategy: fail-fast: false matrix: @@ -22,56 +21,31 @@ jobs: # pypy3 randomly fails on Windows builds - os: windows-latest python-version: "pypy-3.7" - + include: + - os: ubuntu-latest + path: ~/.cache/pip + - os: macos-latest + path: ~/Library/Caches/pip + - os: windows-latest + path: ~\AppData\Local\pip\Cache steps: - # Check out latest code - uses: actions/checkout@v2 - - # Configure pip cache - - name: Cache pip (Linux) - uses: actions/cache@v2 - if: startsWith(runner.os, 'Linux') - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements-dev.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - - - name: Cache pip (macOS) - uses: actions/cache@v2 - if: startsWith(runner.os, 'macOS') - with: - path: ~/Library/Caches/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements-dev.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - - - name: Cache pip (Windows) + - name: Cache pip uses: actions/cache@v2 - if: startsWith(runner.os, 'Windows') with: - path: ~\AppData\Local\pip\Cache - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements-dev.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - - # Set up Python + 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@v2 with: python-version: ${{ matrix.python-version }} - - # Install dependencies - name: Install dependencies run: | pip install -U pip setuptools wheel pip install -U tox tox-gh-actions - - # Run tests - name: Test with tox run: tox - - # Upload coverage report - name: Upload coverage to Codecov uses: codecov/codecov-action@v2 with: @@ -79,45 +53,29 @@ jobs: lint: runs-on: ubuntu-latest - steps: - # Check out latest code - uses: actions/checkout@v2 - - # Set up Python - name: Set up Python 3.10 uses: actions/setup-python@v2 with: python-version: "3.10" - - # Configure pip cache - name: Cache pip uses: actions/cache@v2 with: path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements-dev.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - - # Configure pre-commit cache + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }} + restore-keys: ${{ runner.os }}-pip- - name: Cache pre-commit uses: actions/cache@v2 with: path: ~/.cache/pre-commit key: ${{ runner.os }}-pre-commit-${{ hashFiles('**/.pre-commit-config.yaml') }} - restore-keys: | - ${{ runner.os }}-pre-commit- - - # Install dependencies + restore-keys: ${{ runner.os }}-pre-commit- - name: Install dependencies run: | pip install -U pip setuptools wheel pip install -U tox - - # Lint code - name: Lint code - run: tox -e lint - - # Lint docs + run: tox -e lint -- --show-diff-on-failure - name: Lint docs run: tox -e docs diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c65b2618..28b5f8a0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,25 +2,27 @@ default_language_version: python: python3 repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.0.1 + rev: v4.1.0 hooks: - - id: trailing-whitespace - - id: end-of-file-fixer - - id: fix-encoding-pragma - args: [--remove] - - id: requirements-txt-fixer - id: check-ast - id: check-yaml - id: check-case-conflict - id: check-docstring-first - id: check-merge-conflict + - id: check-builtin-literals - id: debug-statements + - id: end-of-file-fixer + - id: fix-encoding-pragma + args: [--remove] + - id: requirements-txt-fixer + args: [requirements/requirements.txt, requirements/requirements-docs.txt, requirements/requirements-tests.txt] + - id: trailing-whitespace - repo: https://github.com/timothycrosley/isort - rev: 5.9.3 + rev: 5.10.1 hooks: - id: isort - repo: https://github.com/asottile/pyupgrade - rev: v2.29.0 + rev: v2.30.1 hooks: - id: pyupgrade args: [--py36-plus] @@ -29,12 +31,14 @@ repos: hooks: - id: python-no-eval - id: python-check-blanket-noqa + - id: python-check-mock-methods - id: python-use-type-annotations - id: rst-backticks - id: rst-directive-colons - id: rst-inline-touching-normal + - id: text-unicode-replacement-char - repo: https://github.com/psf/black - rev: 21.9b0 + rev: 21.12b0 hooks: - id: black args: [--safe, --quiet, --target-version=py36] @@ -44,7 +48,7 @@ repos: - id: flake8 additional_dependencies: [flake8-bugbear,flake8-annotations] - repo: https://github.com/pre-commit/mirrors-mypy - rev: 'v0.910-1' + rev: 'v0.930' hooks: - id: mypy additional_dependencies: [types-python-dateutil] diff --git a/Makefile b/Makefile index c473e3f1..5f885157 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ .PHONY: auto test docs clean -auto: build39 +auto: build310 build36: PYTHON_VER = python3.6 build37: PYTHON_VER = python3.7 @@ -12,7 +12,8 @@ build36 build37 build38 build39 build310: clean $(PYTHON_VER) -m venv venv . venv/bin/activate; \ pip install -U pip setuptools wheel; \ - pip install -r requirements-dev.txt; \ + pip install -r requirements/requirements-tests.txt; \ + pip install -r requirements/requirements-docs.txt; \ pre-commit install test: @@ -22,14 +23,20 @@ test: lint: . venv/bin/activate; \ - pre-commit run --all-files --show-diff-on-failure + pre-commit run --all-files -docs: +clean-docs: rm -rf docs/_build + +docs: . venv/bin/activate; \ cd docs; \ make html +live-docs: clean-docs + . venv/bin/activate; \ + sphinx-autobuild docs docs/_build/html + clean: clean-dist rm -rf venv .pytest_cache ./**/__pycache__ rm -f .coverage coverage.xml ./**/*.pyc diff --git a/arrow/locales.py b/arrow/locales.py index ddbecb77..d5044608 100644 --- a/arrow/locales.py +++ b/arrow/locales.py @@ -46,7 +46,7 @@ ] -_locale_map: Dict[str, Type["Locale"]] = dict() +_locale_map: Dict[str, Type["Locale"]] = {} def get_locale(name: str) -> "Locale": @@ -5743,7 +5743,7 @@ class SinhalaLocale(Locale): } # Sinhala: the general format to describe timeframe is different from past and future, # so we do not copy the original timeframes dictionary - timeframes_only_distance = dict() + timeframes_only_distance = {} timeframes_only_distance["second"] = "තත්පරයක්" timeframes_only_distance["seconds"] = "තත්පර {0}" timeframes_only_distance["minute"] = "මිනිත්තුවක්" diff --git a/requirements/requirements-docs.txt b/requirements/requirements-docs.txt new file mode 100644 index 00000000..de59f1a3 --- /dev/null +++ b/requirements/requirements-docs.txt @@ -0,0 +1,5 @@ +-r requirements.txt +doc8 +sphinx +sphinx-autobuild +sphinx-autodoc-typehints diff --git a/requirements-dev.txt b/requirements/requirements-tests.txt similarity index 51% rename from requirements-dev.txt rename to requirements/requirements-tests.txt index 75f44341..7e9fbe3f 100644 --- a/requirements-dev.txt +++ b/requirements/requirements-tests.txt @@ -1,11 +1,10 @@ +-r requirements.txt dateparser==1.* -pre-commit==2.* -pytest==6.* -pytest-cov==3.* -pytest-mock==3.* +pre-commit +pytest +pytest-cov +pytest-mock python-dateutil>=2.7.0 pytz==2021.1 simplejson==3.* -sphinx==4.* -sphinx-autodoc-typehints==1.* typing_extensions; python_version < '3.8' diff --git a/requirements/requirements.txt b/requirements/requirements.txt new file mode 100644 index 00000000..bcdff0e8 --- /dev/null +++ b/requirements/requirements.txt @@ -0,0 +1,2 @@ +python-dateutil>=2.7.0 +typing_extensions; python_version < '3.8' diff --git a/tox.ini b/tox.ini index b7746176..fefa3e7e 100644 --- a/tox.ini +++ b/tox.ini @@ -13,27 +13,22 @@ python = 3.10: py310 [testenv] -deps = -rrequirements-dev.txt +deps = -r requirements/requirements-tests.txt allowlist_externals = pytest commands = pytest [testenv:lint] -basepython = python3 skip_install = true deps = pre-commit -commands = - pre-commit install - pre-commit run --all-files --show-diff-on-failure +commands_pre = pre-commit install +commands = pre-commit run --all-files {posargs} [testenv:docs] -basepython = python3 skip_install = true changedir = docs deps = - doc8 - sphinx - sphinx-autodoc-typehints - python-dateutil + -r requirements/requirements-tests.txt + -r requirements/requirements-docs.txt allowlist_externals = make commands = doc8 index.rst ../README.rst --extension .rst --ignore D001 From 022845e639993dd9ccbcee01014ae7b5ea0671a6 Mon Sep 17 00:00:00 2001 From: Jad Chaar Date: Fri, 31 Dec 2021 18:28:43 -0500 Subject: [PATCH 2/4] Generate doc PDFs with xelatex, which has better support for unicode characters. --- docs/conf.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index 907d78c0..f106cb7f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -58,3 +58,7 @@ html_sidebars = { "**": ["about.html", "localtoc.html", "relations.html", "searchbox.html"] } + +# Generate PDFs with unicode characters +# https://docs.readthedocs.io/en/stable/guides/pdf-non-ascii-languages.html +latex_engine = "xelatex" From fecbada0e4cc06b52f08a9e1151045b9e056ab3d Mon Sep 17 00:00:00 2001 From: Jad Chaar Date: Fri, 31 Dec 2021 22:05:28 -0500 Subject: [PATCH 3/4] Fix requirements files in MANIFEST.in --- MANIFEST.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index 8ac191e0..9abe9773 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,4 @@ -include LICENSE CHANGELOG.rst README.rst Makefile requirements-dev.txt tox.ini +include LICENSE CHANGELOG.rst README.rst Makefile tox.ini +recursive-include requirements *.txt recursive-include tests *.py recursive-include docs *.py *.rst *.bat Makefile From 7d7926a056f820743352b9ffbb0043f49505ec2f Mon Sep 17 00:00:00 2001 From: kaiyang-code <57576013+kaiyang-code@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:11:05 -0500 Subject: [PATCH 4/4] Expand Hong Kong, ChineseCN and ChineseTW Locale Test Cases (#1076) Co-authored-by: Anish Nyayachavadi --- tests/test_locales.py | 150 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/tests/test_locales.py b/tests/test_locales.py index 54536c0a..cb2f60ff 100644 --- a/tests/test_locales.py +++ b/tests/test_locales.py @@ -2018,6 +2018,56 @@ def test_format_timeframe(self): assert self.locale._format_timeframe("year", 1) == "1年" assert self.locale._format_timeframe("years", 12) == "12年" + assert self.locale._format_timeframe("second", -1) == "1秒" + assert self.locale._format_timeframe("seconds", -30) == "30秒" + assert self.locale._format_timeframe("minute", -1) == "1分鐘" + assert self.locale._format_timeframe("minutes", -40) == "40分鐘" + assert self.locale._format_timeframe("hour", -1) == "1小時" + assert self.locale._format_timeframe("hours", -23) == "23小時" + assert self.locale._format_timeframe("day", -1) == "1天" + assert self.locale._format_timeframe("days", -12) == "12天" + assert self.locale._format_timeframe("week", -1) == "1星期" + assert self.locale._format_timeframe("weeks", -38) == "38星期" + assert self.locale._format_timeframe("month", -1) == "1個月" + assert self.locale._format_timeframe("months", -11) == "11個月" + assert self.locale._format_timeframe("year", -1) == "1年" + assert self.locale._format_timeframe("years", -12) == "12年" + + def test_format_relative_now(self): + assert self.locale._format_relative("剛才", "now", 0) == "剛才" + + def test_format_relative_past(self): + assert self.locale._format_relative("1秒", "second", 1) == "1秒後" + assert self.locale._format_relative("2秒", "seconds", 2) == "2秒後" + assert self.locale._format_relative("1分鐘", "minute", 1) == "1分鐘後" + assert self.locale._format_relative("2分鐘", "minutes", 2) == "2分鐘後" + assert self.locale._format_relative("1小時", "hour", 1) == "1小時後" + assert self.locale._format_relative("2小時", "hours", 2) == "2小時後" + assert self.locale._format_relative("1天", "day", 1) == "1天後" + assert self.locale._format_relative("2天", "days", 2) == "2天後" + assert self.locale._format_relative("1星期", "week", 1) == "1星期後" + assert self.locale._format_relative("2星期", "weeks", 2) == "2星期後" + assert self.locale._format_relative("1個月", "month", 1) == "1個月後" + assert self.locale._format_relative("2個月", "months", 2) == "2個月後" + assert self.locale._format_relative("1年", "year", 1) == "1年後" + assert self.locale._format_relative("2年", "years", 2) == "2年後" + + def test_format_relative_future(self): + assert self.locale._format_relative("1秒", "second", -1) == "1秒前" + assert self.locale._format_relative("2秒", "seconds", -2) == "2秒前" + assert self.locale._format_relative("1分鐘", "minute", -1) == "1分鐘前" + assert self.locale._format_relative("2分鐘", "minutes", -2) == "2分鐘前" + assert self.locale._format_relative("1小時", "hour", -1) == "1小時前" + assert self.locale._format_relative("2小時", "hours", -2) == "2小時前" + assert self.locale._format_relative("1天", "day", -1) == "1天前" + assert self.locale._format_relative("2天", "days", -2) == "2天前" + assert self.locale._format_relative("1星期", "week", -1) == "1星期前" + assert self.locale._format_relative("2星期", "weeks", -2) == "2星期前" + assert self.locale._format_relative("1個月", "month", -1) == "1個月前" + assert self.locale._format_relative("2個月", "months", -2) == "2個月前" + assert self.locale._format_relative("1年", "year", -1) == "1年前" + assert self.locale._format_relative("2年", "years", -2) == "2年前" + @pytest.mark.usefixtures("lang_locale") class TestChineseTWLocale: @@ -2038,6 +2088,56 @@ def test_format_timeframe(self): assert self.locale._format_timeframe("year", 1) == "1年" assert self.locale._format_timeframe("years", 12) == "12年" + assert self.locale._format_timeframe("second", -1) == "1秒" + assert self.locale._format_timeframe("seconds", -30) == "30秒" + assert self.locale._format_timeframe("minute", -1) == "1分鐘" + assert self.locale._format_timeframe("minutes", -40) == "40分鐘" + assert self.locale._format_timeframe("hour", -1) == "1小時" + assert self.locale._format_timeframe("hours", -23) == "23小時" + assert self.locale._format_timeframe("day", -1) == "1天" + assert self.locale._format_timeframe("days", -12) == "12天" + assert self.locale._format_timeframe("week", -1) == "1週" + assert self.locale._format_timeframe("weeks", -38) == "38週" + assert self.locale._format_timeframe("month", -1) == "1個月" + assert self.locale._format_timeframe("months", -11) == "11個月" + assert self.locale._format_timeframe("year", -1) == "1年" + assert self.locale._format_timeframe("years", -12) == "12年" + + def test_format_relative_now(self): + assert self.locale._format_relative("剛才", "now", 0) == "剛才" + + def test_format_relative_past(self): + assert self.locale._format_relative("1秒", "second", 1) == "1秒後" + assert self.locale._format_relative("2秒", "seconds", 2) == "2秒後" + assert self.locale._format_relative("1分鐘", "minute", 1) == "1分鐘後" + assert self.locale._format_relative("2分鐘", "minutes", 2) == "2分鐘後" + assert self.locale._format_relative("1小時", "hour", 1) == "1小時後" + assert self.locale._format_relative("2小時", "hours", 2) == "2小時後" + assert self.locale._format_relative("1天", "day", 1) == "1天後" + assert self.locale._format_relative("2天", "days", 2) == "2天後" + assert self.locale._format_relative("1週", "week", 1) == "1週後" + assert self.locale._format_relative("2週", "weeks", 2) == "2週後" + assert self.locale._format_relative("1個月", "month", 1) == "1個月後" + assert self.locale._format_relative("2個月", "months", 2) == "2個月後" + assert self.locale._format_relative("1年", "year", 1) == "1年後" + assert self.locale._format_relative("2年", "years", 2) == "2年後" + + def test_format_relative_future(self): + assert self.locale._format_relative("1秒", "second", -1) == "1秒前" + assert self.locale._format_relative("2秒", "seconds", -2) == "2秒前" + assert self.locale._format_relative("1分鐘", "minute", -1) == "1分鐘前" + assert self.locale._format_relative("2分鐘", "minutes", -2) == "2分鐘前" + assert self.locale._format_relative("1小時", "hour", -1) == "1小時前" + assert self.locale._format_relative("2小時", "hours", -2) == "2小時前" + assert self.locale._format_relative("1天", "day", -1) == "1天前" + assert self.locale._format_relative("2天", "days", -2) == "2天前" + assert self.locale._format_relative("1週", "week", -1) == "1週前" + assert self.locale._format_relative("2週", "weeks", -2) == "2週前" + assert self.locale._format_relative("1個月", "month", -1) == "1個月前" + assert self.locale._format_relative("2個月", "months", -2) == "2個月前" + assert self.locale._format_relative("1年", "year", -1) == "1年前" + assert self.locale._format_relative("2年", "years", -2) == "2年前" + @pytest.mark.usefixtures("lang_locale") class TestChineseCNLocale: @@ -2058,6 +2158,56 @@ def test_format_timeframe(self): assert self.locale._format_timeframe("year", 1) == "1年" assert self.locale._format_timeframe("years", 12) == "12年" + assert self.locale._format_timeframe("second", -1) == "1秒" + assert self.locale._format_timeframe("seconds", -30) == "30秒" + assert self.locale._format_timeframe("minute", -1) == "1分钟" + assert self.locale._format_timeframe("minutes", -40) == "40分钟" + assert self.locale._format_timeframe("hour", -1) == "1小时" + assert self.locale._format_timeframe("hours", -23) == "23小时" + assert self.locale._format_timeframe("day", -1) == "1天" + assert self.locale._format_timeframe("days", -12) == "12天" + assert self.locale._format_timeframe("week", -1) == "1周" + assert self.locale._format_timeframe("weeks", -38) == "38周" + assert self.locale._format_timeframe("month", -1) == "1个月" + assert self.locale._format_timeframe("months", -11) == "11个月" + assert self.locale._format_timeframe("year", -1) == "1年" + assert self.locale._format_timeframe("years", -12) == "12年" + + def test_format_relative_now(self): + assert self.locale._format_relative("刚才", "now", 0) == "刚才" + + def test_format_relative_past(self): + assert self.locale._format_relative("1秒", "second", 1) == "1秒后" + assert self.locale._format_relative("2秒", "seconds", 2) == "2秒后" + assert self.locale._format_relative("1分钟", "minute", 1) == "1分钟后" + assert self.locale._format_relative("2分钟", "minutes", 2) == "2分钟后" + assert self.locale._format_relative("1小时", "hour", 1) == "1小时后" + assert self.locale._format_relative("2小时", "hours", 2) == "2小时后" + assert self.locale._format_relative("1天", "day", 1) == "1天后" + assert self.locale._format_relative("2天", "days", 2) == "2天后" + assert self.locale._format_relative("1周", "week", 1) == "1周后" + assert self.locale._format_relative("2周", "weeks", 2) == "2周后" + assert self.locale._format_relative("1个月", "month", 1) == "1个月后" + assert self.locale._format_relative("2个月", "months", 2) == "2个月后" + assert self.locale._format_relative("1年", "year", 1) == "1年后" + assert self.locale._format_relative("2年", "years", 2) == "2年后" + + def test_format_relative_future(self): + assert self.locale._format_relative("1秒", "second", -1) == "1秒前" + assert self.locale._format_relative("2秒", "seconds", -2) == "2秒前" + assert self.locale._format_relative("1分钟", "minute", -1) == "1分钟前" + assert self.locale._format_relative("2分钟", "minutes", -2) == "2分钟前" + assert self.locale._format_relative("1小时", "hour", -1) == "1小时前" + assert self.locale._format_relative("2小时", "hours", -2) == "2小时前" + assert self.locale._format_relative("1天", "day", -1) == "1天前" + assert self.locale._format_relative("2天", "days", -2) == "2天前" + assert self.locale._format_relative("1周", "week", -1) == "1周前" + assert self.locale._format_relative("2周", "weeks", -2) == "2周前" + assert self.locale._format_relative("1个月", "month", -1) == "1个月前" + assert self.locale._format_relative("2个月", "months", -2) == "2个月前" + assert self.locale._format_relative("1年", "year", -1) == "1年前" + assert self.locale._format_relative("2年", "years", -2) == "2年前" + @pytest.mark.usefixtures("lang_locale") class TestSwahiliLocale: