From 41286f93069125ba9549ffbe4d076b3a12ea8ee1 Mon Sep 17 00:00:00 2001 From: Dmitry Pershin Date: Sun, 24 Apr 2022 20:38:42 +0500 Subject: [PATCH 1/8] code reformatted. --- .flake8 | 2 +- .github/workflows/test.yml | 42 ++++++------ .pre-commit-config.yaml | 66 +++++++++++-------- crontools/__init__.py | 18 ++---- tests/test_crontab.py | 129 +++++++++++++++++++------------------ 5 files changed, 130 insertions(+), 127 deletions(-) diff --git a/.flake8 b/.flake8 index 542b77f..7179745 100644 --- a/.flake8 +++ b/.flake8 @@ -1,4 +1,4 @@ [flake8] -max-line-length = 130 +max-line-length = 120 per-file-ignores = crontools/*__init__.py: F401 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d551df2..c378e1d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,24 +16,24 @@ jobs: matrix: python-version: [3.7, 3.8, 3.9] steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install pipenv --upgrade - pipenv install --python ${{ matrix.python-version }} --dev - - name: Run linter - run: pipenv run flake8 . - - name: Run tests - run: PYTHONPATH="$(pwd):$PYTHONPATH" pipenv run py.test --cov=crontools --cov-report=xml tests - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v1 - with: - token: ${{ secrets.CODECOV_TOKEN }} - files: ./coverage.xml - flags: unittests - fail_ci_if_error: true + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install poetry + poetry install --no-root + - name: Run pre-commit hooks + run: poetry run pre-commit run --hook-stage merge-commit --all-files + - name: Run tests + run: PYTHONPATH="$(pwd):$PYTHONPATH" poetry run py.test --cov=crontools --cov-report=xml tests + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: ./coverage.xml + flags: unittests + fail_ci_if_error: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ff7e8c1..b9cfa04 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,52 +1,64 @@ +default_stages: + - commit + - merge-commit + repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.4.0 + rev: v4.4.0 hooks: - - id: check-docstring-first - stages: - - commit - - push - - id: check-merge-conflict - stages: - - push + - id: check-yaml + - id: check-toml - id: trailing-whitespace - stages: - - commit - - push - id: end-of-file-fixer stages: - commit - - push - id: mixed-line-ending + name: fix line ending stages: - commit - - push args: - --fix=lf - - id: no-commit-to-branch + - id: mixed-line-ending + name: check line ending + stages: + - merge-commit + args: + - --fix=no + - repo: https://github.com/asottile/add-trailing-comma + rev: v2.4.0 + hooks: + - id: add-trailing-comma stages: - commit - repo: https://github.com/pre-commit/mirrors-autopep8 - rev: v1.5.5 + rev: v2.0.1 hooks: - id: autopep8 stages: - commit - - push args: - - --max-line-length=130 - --diff - - repo: https://github.com/asottile/add-trailing-comma - rev: v2.1.0 - hooks: - - id: add-trailing-comma - stages: - - commit - - push - - repo: https://gitlab.com/pycqa/flake8 - rev: 3.9.0 + - repo: https://github.com/pycqa/flake8 + rev: 5.0.4 hooks: - id: flake8 + - repo: https://github.com/pycqa/isort + rev: 5.11.5 + hooks: + - id: isort + name: fix import order stages: - commit - - push + args: + - --line-length=120 + - --multi-line=9 + - --project=crontools + - id: isort + name: check import order + stages: + - merge-commit + args: + - --check-only + - --line-length=120 + - --multi-line=9 + - --project=crontools diff --git a/crontools/__init__.py b/crontools/__init__.py index e93eb17..9cc545e 100644 --- a/crontools/__init__.py +++ b/crontools/__init__.py @@ -2,20 +2,10 @@ Python cron tools. """ -from .crontab import Crontab -from .crontab import Range, SecondsRange, MinuteRange, HourRange, MonthdayRange, MonthRange, WeekdayRange, YearRange -from .crontab import Field, SecondsField, MinuteField, HourField, MonthdayField, MonthField, WeekdayField, YearField, DayField - - -from .__about__ import ( - __title__, - __description__, - __url__, - __version__, - __author__, - __email__, - __license__, -) +from .__about__ import __author__, __description__, __email__, __license__, __title__, __url__, __version__ +from .crontab import Crontab, DayField, Field, HourField, HourRange, MinuteField, MinuteRange, MonthdayField +from .crontab import MonthdayRange, MonthField, MonthRange, Range, SecondsField, SecondsRange, WeekdayField +from .crontab import WeekdayRange, YearField, YearRange __all__ = [ '__title__', diff --git a/tests/test_crontab.py b/tests/test_crontab.py index 2c6fc5f..b657be7 100644 --- a/tests/test_crontab.py +++ b/tests/test_crontab.py @@ -1,11 +1,12 @@ import datetime as dt +from datetime import timezone import freezegun import pytest -from crontools.crontab import Crontab -from crontools.crontab import SecondsField, MinuteField, HourField, MonthdayField, MonthField, WeekdayField, YearField -from crontools.crontab import SecondsRange, MinuteRange, HourRange, MonthdayRange, MonthRange, WeekdayRange, YearRange +from crontools.crontab import Crontab, HourField, HourRange, MinuteField, MinuteRange, MonthdayField, MonthdayRange +from crontools.crontab import MonthField, MonthRange, SecondsField, SecondsRange, WeekdayField, WeekdayRange, YearField +from crontools.crontab import YearRange @pytest.mark.parametrize( @@ -314,8 +315,8 @@ def test_cron_field_iterator(expr, Field, result, start_from): ( '0 0 1 1 *', [ - dt.datetime(year=2020, month=1, day=1, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2021, month=1, day=1, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), + dt.datetime(year=2020, month=1, day=1, hour=0, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2021, month=1, day=1, hour=0, minute=0, second=0, tzinfo=timezone.utc), ], False, False, @@ -323,10 +324,10 @@ def test_cron_field_iterator(expr, Field, result, start_from): ( '0 0 * * TUE,FRI', [ - dt.datetime(year=2020, month=1, day=3, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=1, day=7, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=1, day=10, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=1, day=14, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), + dt.datetime(year=2020, month=1, day=3, hour=0, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2020, month=1, day=7, hour=0, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2020, month=1, day=10, hour=0, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2020, month=1, day=14, hour=0, minute=0, second=0, tzinfo=timezone.utc), ], False, False, @@ -334,12 +335,12 @@ def test_cron_field_iterator(expr, Field, result, start_from): ( '0 0 10,3,2,1 * TUE,FRI', [ - dt.datetime(year=2020, month=1, day=1, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=1, day=2, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=1, day=3, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=1, day=7, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=1, day=10, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=1, day=14, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), + dt.datetime(year=2020, month=1, day=1, hour=0, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2020, month=1, day=2, hour=0, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2020, month=1, day=3, hour=0, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2020, month=1, day=7, hour=0, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2020, month=1, day=10, hour=0, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2020, month=1, day=14, hour=0, minute=0, second=0, tzinfo=timezone.utc), ], False, False, @@ -347,12 +348,12 @@ def test_cron_field_iterator(expr, Field, result, start_from): ( '0 1-10/2,2 1 1 *', [ - dt.datetime(year=2020, month=1, day=1, hour=1, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=1, day=1, hour=2, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=1, day=1, hour=3, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=1, day=1, hour=5, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=1, day=1, hour=7, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=1, day=1, hour=9, minute=0, second=0, tzinfo=dt.timezone.utc), + dt.datetime(year=2020, month=1, day=1, hour=1, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2020, month=1, day=1, hour=2, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2020, month=1, day=1, hour=3, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2020, month=1, day=1, hour=5, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2020, month=1, day=1, hour=7, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2020, month=1, day=1, hour=9, minute=0, second=0, tzinfo=timezone.utc), ], False, False, @@ -360,9 +361,9 @@ def test_cron_field_iterator(expr, Field, result, start_from): ( '0 0 0 28-31 2,3 * 2020', [ - dt.datetime(year=2020, month=2, day=28, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=2, day=29, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=3, day=28, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), + dt.datetime(year=2020, month=2, day=28, hour=0, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2020, month=2, day=29, hour=0, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2020, month=3, day=28, hour=0, minute=0, second=0, tzinfo=timezone.utc), ], True, True, @@ -370,8 +371,8 @@ def test_cron_field_iterator(expr, Field, result, start_from): ( '0 0 0 28-31 2,3 * 2021', [ - dt.datetime(year=2021, month=2, day=28, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2021, month=3, day=28, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), + dt.datetime(year=2021, month=2, day=28, hour=0, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2021, month=3, day=28, hour=0, minute=0, second=0, tzinfo=timezone.utc), ], True, True, @@ -379,12 +380,12 @@ def test_cron_field_iterator(expr, Field, result, start_from): ( '0 0 0 1 1-5,2-4,3 * 2020,2021', [ - dt.datetime(year=2020, month=1, day=1, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=2, day=1, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=3, day=1, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=4, day=1, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=5, day=1, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2021, month=1, day=1, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), + dt.datetime(year=2020, month=1, day=1, hour=0, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2020, month=2, day=1, hour=0, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2020, month=3, day=1, hour=0, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2020, month=4, day=1, hour=0, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2020, month=5, day=1, hour=0, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2021, month=1, day=1, hour=0, minute=0, second=0, tzinfo=timezone.utc), ], True, True, @@ -393,7 +394,7 @@ def test_cron_field_iterator(expr, Field, result, start_from): ) @freezegun.freeze_time('2020-01-01 00:00:00.000Z+00:00') def test_cron_iterator(expr, result, years_ext, seconds_ext): - cron = Crontab.parse(expr, years_ext=years_ext, seconds_ext=seconds_ext, tz=dt.timezone.utc) + cron = Crontab.parse(expr, years_ext=years_ext, seconds_ext=seconds_ext, tz=timezone.utc) for actual, expected in zip(cron, result): assert actual == expected @@ -404,49 +405,49 @@ def test_cron_iterator(expr, result, years_ext, seconds_ext): [ ( '* * * * * *', - dt.datetime(year=2020, month=2, day=28, hour=12, minute=30, second=0, microsecond=1, tzinfo=dt.timezone.utc), + dt.datetime(year=2020, month=2, day=28, hour=12, minute=30, second=0, microsecond=1, tzinfo=timezone.utc), [ - dt.datetime(year=2020, month=2, day=28, hour=12, minute=31, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=2, day=28, hour=12, minute=32, second=0, tzinfo=dt.timezone.utc), + dt.datetime(year=2020, month=2, day=28, hour=12, minute=31, second=0, tzinfo=timezone.utc), + dt.datetime(year=2020, month=2, day=28, hour=12, minute=32, second=0, tzinfo=timezone.utc), ], True, False, ), ( '* * * * * * *', - dt.datetime(year=2020, month=1, day=1, hour=12, minute=30, second=0, microsecond=1, tzinfo=dt.timezone.utc), + dt.datetime(year=2020, month=1, day=1, hour=12, minute=30, second=0, microsecond=1, tzinfo=timezone.utc), [ - dt.datetime(year=2020, month=1, day=1, hour=12, minute=30, second=1, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=1, day=1, hour=12, minute=30, second=2, tzinfo=dt.timezone.utc), + dt.datetime(year=2020, month=1, day=1, hour=12, minute=30, second=1, tzinfo=timezone.utc), + dt.datetime(year=2020, month=1, day=1, hour=12, minute=30, second=2, tzinfo=timezone.utc), ], True, True, ), ( '0 * * * * * *', - dt.datetime(year=2020, month=1, day=1, hour=12, minute=30, second=0, microsecond=1, tzinfo=dt.timezone.utc), + dt.datetime(year=2020, month=1, day=1, hour=12, minute=30, second=0, microsecond=1, tzinfo=timezone.utc), [ - dt.datetime(year=2020, month=1, day=1, hour=12, minute=31, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=1, day=1, hour=12, minute=32, second=0, tzinfo=dt.timezone.utc), + dt.datetime(year=2020, month=1, day=1, hour=12, minute=31, second=0, tzinfo=timezone.utc), + dt.datetime(year=2020, month=1, day=1, hour=12, minute=32, second=0, tzinfo=timezone.utc), ], True, True, ), ( '0 0 * * *', - dt.datetime(year=2020, month=2, day=28, hour=0, minute=0, second=0, microsecond=1, tzinfo=dt.timezone.utc), + dt.datetime(year=2020, month=2, day=28, hour=0, minute=0, second=0, microsecond=1, tzinfo=timezone.utc), [ - dt.datetime(year=2020, month=2, day=29, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=3, day=1, hour=0, minute=0, second=0, tzinfo=dt.timezone.utc), + dt.datetime(year=2020, month=2, day=29, hour=0, minute=0, second=0, tzinfo=timezone.utc), + dt.datetime(year=2020, month=3, day=1, hour=0, minute=0, second=0, tzinfo=timezone.utc), ], False, False, ), ( '0 0 1-31 * *', - dt.datetime(year=2020, month=1, day=1, tzinfo=dt.timezone.utc), + dt.datetime(year=2020, month=1, day=1, tzinfo=timezone.utc), [ - dt.datetime(year=2020, month=1, day=1, tzinfo=dt.timezone.utc) + dt.timedelta(days=day) + dt.datetime(year=2020, month=1, day=1, tzinfo=timezone.utc) + dt.timedelta(days=day) for day in range(368) ], False, @@ -454,9 +455,9 @@ def test_cron_iterator(expr, result, years_ext, seconds_ext): ), ( '0 0 * * MON-SUN', - dt.datetime(year=2020, month=1, day=1, tzinfo=dt.timezone.utc), + dt.datetime(year=2020, month=1, day=1, tzinfo=timezone.utc), [ - dt.datetime(year=2020, month=1, day=1, tzinfo=dt.timezone.utc) + dt.timedelta(days=day) + dt.datetime(year=2020, month=1, day=1, tzinfo=timezone.utc) + dt.timedelta(days=day) for day in range(367*7) ], False, @@ -466,7 +467,7 @@ def test_cron_iterator(expr, result, years_ext, seconds_ext): ) @freezegun.freeze_time('2020-01-01 00:00:00.000Z+00:00') def test_cron_iterator_start_from(expr, start_from, result, years_ext, seconds_ext): - cron = Crontab.parse(expr, years_ext=years_ext, seconds_ext=seconds_ext, tz=dt.timezone.utc) + cron = Crontab.parse(expr, years_ext=years_ext, seconds_ext=seconds_ext, tz=timezone.utc) for actual, expected in zip(cron.iter(start_from), result): assert actual == expected @@ -477,50 +478,50 @@ def test_cron_iterator_start_from(expr, start_from, result, years_ext, seconds_e [ ( '* * * * *', - dt.datetime(year=2021, month=3, day=13, hour=23, minute=14, second=0, microsecond=1, tzinfo=dt.timezone.utc), - dt.datetime(year=2021, month=3, day=13, hour=23, minute=15, second=0, microsecond=0, tzinfo=dt.timezone.utc), + dt.datetime(year=2021, month=3, day=13, hour=23, minute=14, second=0, microsecond=1, tzinfo=timezone.utc), + dt.datetime(year=2021, month=3, day=13, hour=23, minute=15, second=0, microsecond=0, tzinfo=timezone.utc), False, False, ), ( '* * * * * *', - dt.datetime(year=2021, month=3, day=13, hour=23, minute=14, second=0, microsecond=1, tzinfo=dt.timezone.utc), - dt.datetime(year=2021, month=3, day=13, hour=23, minute=14, second=1, microsecond=0, tzinfo=dt.timezone.utc), + dt.datetime(year=2021, month=3, day=13, hour=23, minute=14, second=0, microsecond=1, tzinfo=timezone.utc), + dt.datetime(year=2021, month=3, day=13, hour=23, minute=14, second=1, microsecond=0, tzinfo=timezone.utc), False, True, ), ( '* * * * *', - dt.datetime(year=2020, month=2, day=28, hour=23, minute=59, second=1, tzinfo=dt.timezone.utc), - dt.datetime(year=2020, month=2, day=29, hour=0, minute=0, tzinfo=dt.timezone.utc), + dt.datetime(year=2020, month=2, day=28, hour=23, minute=59, second=1, tzinfo=timezone.utc), + dt.datetime(year=2020, month=2, day=29, hour=0, minute=0, tzinfo=timezone.utc), False, False, ), ( '* * * * *', - dt.datetime(year=2020, month=12, day=31, hour=23, minute=59, second=1, tzinfo=dt.timezone.utc), - dt.datetime(year=2021, month=1, day=1, hour=0, minute=0, tzinfo=dt.timezone.utc), + dt.datetime(year=2020, month=12, day=31, hour=23, minute=59, second=1, tzinfo=timezone.utc), + dt.datetime(year=2021, month=1, day=1, hour=0, minute=0, tzinfo=timezone.utc), False, False, ), ( '1 42 13 12 3 * 2021', - dt.datetime(year=2021, month=3, day=12, hour=13, minute=42, second=1, microsecond=1, tzinfo=dt.timezone.utc), + dt.datetime(year=2021, month=3, day=12, hour=13, minute=42, second=1, microsecond=1, tzinfo=timezone.utc), None, True, True, ), ( '0 0 * * MON', - dt.datetime(year=2021, month=2, day=28, hour=0, minute=0, second=0, microsecond=0, tzinfo=dt.timezone.utc), - dt.datetime(year=2021, month=3, day=1, hour=0, minute=0, second=0, microsecond=0, tzinfo=dt.timezone.utc), + dt.datetime(year=2021, month=2, day=28, hour=0, minute=0, second=0, microsecond=0, tzinfo=timezone.utc), + dt.datetime(year=2021, month=3, day=1, hour=0, minute=0, second=0, microsecond=0, tzinfo=timezone.utc), False, False, ), ( '0 0 * * WED,THU', - dt.datetime(year=2021, month=3, day=31, hour=0, minute=0, second=0, microsecond=1, tzinfo=dt.timezone.utc), - dt.datetime(year=2021, month=4, day=1, hour=0, minute=0, second=0, microsecond=0, tzinfo=dt.timezone.utc), + dt.datetime(year=2021, month=3, day=31, hour=0, minute=0, second=0, microsecond=1, tzinfo=timezone.utc), + dt.datetime(year=2021, month=4, day=1, hour=0, minute=0, second=0, microsecond=0, tzinfo=timezone.utc), False, False, ), @@ -528,6 +529,6 @@ def test_cron_iterator_start_from(expr, start_from, result, years_ext, seconds_e ) @freezegun.freeze_time('2020-01-01 00:00:00.000Z+00:00') def test_cron_next_fire_time(expr, now, result, years_ext, seconds_ext): - cron = Crontab.parse(expr, years_ext=years_ext, seconds_ext=seconds_ext, tz=dt.timezone.utc) + cron = Crontab.parse(expr, years_ext=years_ext, seconds_ext=seconds_ext, tz=timezone.utc) assert cron.next_fire_time(now) == result From 940e40517b2259589e746a546feb0249205b6702 Mon Sep 17 00:00:00 2001 From: Dmitry Pershin Date: Sun, 24 Apr 2022 20:48:09 +0500 Subject: [PATCH 2/8] pipenv substituted by poetry --- .github/workflows/release.yml | 11 ++---- .gitignore | 2 +- CHANGELOG.rst | 7 ++++ Pipfile | 13 ------ pyproject.toml | 32 +++++++++++++++ setup.py | 74 ----------------------------------- 6 files changed, 44 insertions(+), 95 deletions(-) delete mode 100644 Pipfile create mode 100644 pyproject.toml delete mode 100644 setup.py diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 143d58e..2d17663 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,12 +16,9 @@ jobs: python-version: '3.x' - name: Install dependencies run: | - python -m pip install --upgrade pip - pip install setuptools wheel twine + python -m pip install --upgrade pip poetry + poetry install - name: Build and publish - env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} run: | - python setup.py sdist - twine upload dist/* + poetry build + poetry publish -u __token__ -p ${{ secrets.PYPI_TOKEN }} diff --git a/.gitignore b/.gitignore index 40641a5..57d8ace 100644 --- a/.gitignore +++ b/.gitignore @@ -130,4 +130,4 @@ dmypy.json .idea/ -Pipfile.lock +poetry.lock diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 479f9eb..b55f88b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,13 @@ Changelog ========= + +0.1.6 (2022-04-24) +------------------ + +- pipenv substituted by poetry + + 0.1.5 (2022-04-24) ------------------ diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 59bd1aa..0000000 --- a/Pipfile +++ /dev/null @@ -1,13 +0,0 @@ -[[source]] -name = "pypi" -url = "https://pypi.org/simple" -verify_ssl = true - -[dev-packages] -pytest = "~=6.0" -pytest-cov = "~=2.0" -freezegun = "~=0.0" -flake8 = "~=3.0" - -[packages] -tzlocal = "~=2.0" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..3f4da5a --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,32 @@ +[tool.poetry] +name = "crontools" +version = "0.1.5" +description = "Python cron tools" +authors = ["Dmitry Pershin "] +license = "Unlicense" +readme = "README.rst" +homepage = "https://github.com/dapper91/crontools" +repository = "https://github.com/dapper91/crontools" +keywords = ["cron", "crontab", "cron-utils", "cron-tools", "parser"] +classifiers = [ + "License :: Public Domain", + "Programming Language :: Python :: 3", + "Intended Audience :: Developers", + "Topic :: Software Development :: Libraries", + "Topic :: Utilities" +] + +[tool.poetry.dependencies] +python = "^3.7" +tzlocal = "^2.0" +types-tzlocal = "^4.1.0" + +[tool.poetry.dev-dependencies] +pytest = "^6.0" +pytest-cov = "^2.0" +freezegun = "^1.2" +pre-commit = "^2.18.1" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/setup.py b/setup.py deleted file mode 100644 index 1d8f137..0000000 --- a/setup.py +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env python - -import pathlib -import setuptools.command.test -import sys -from setuptools import setup, find_packages - -requirements = [ - 'tzlocal~=2.0', -] - -test_requirements = [ - 'pytest~=6.0', -] - -with open('README.rst', 'r') as file: - readme = file.read() - - -def parse_about(): - about_globals = {} - this_path = pathlib.Path(__file__).parent - about_module_text = pathlib.Path(this_path, 'crontools', '__about__.py').read_text() - exec(about_module_text, about_globals) - - return about_globals - - -about = parse_about() - - -class PyTest(setuptools.command.test.test): - user_options = [('pytest-args=', 'a', 'Arguments to pass to py.test')] - - def initialize_options(self): - setuptools.command.test.test.initialize_options(self) - self.pytest_args = [] - - def run_tests(self): - import pytest - sys.exit(pytest.main(self.pytest_args)) - - -setup( - name=about['__title__'], - version=about['__version__'], - description=about['__description__'], - long_description=readme, - author=about['__author__'], - author_email=about['__email__'], - url=about['__url__'], - license=about['__license__'], - keywords=[ - 'cron', 'crontab', 'cron-utils', 'cron-tools', 'parser', - ], - python_requires=">=3.7", - packages=find_packages(), - install_requires=requirements, - tests_require=test_requirements, - classifiers=[ - 'Development Status :: 4 - Beta', - 'Intended Audience :: Developers', - 'Natural Language :: English', - 'License :: Public Domain', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - ], - project_urls={ - 'Source': 'https://github.com/dapper91/crontools', - }, - cmdclass={'test': PyTest}, -) From 539d10a3e96e9b3800b2730ee171819f90b72bbc Mon Sep 17 00:00:00 2001 From: Dmitry Pershin Date: Sun, 24 Apr 2022 20:51:48 +0500 Subject: [PATCH 3/8] mypy checker added --- .pre-commit-config.yaml | 10 ++++++++ CHANGELOG.rst | 1 + crontools/crontab.py | 53 +++++++++++++++++++++++++---------------- crontools/py.typed | 0 pyproject.toml | 14 +++++++++++ 5 files changed, 58 insertions(+), 20 deletions(-) create mode 100644 crontools/py.typed diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b9cfa04..c15686c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -62,3 +62,13 @@ repos: - --line-length=120 - --multi-line=9 - --project=crontools + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.0.1 + hooks: + - id: mypy + stages: + - commit + name: mypy + pass_filenames: false + args: ["--package", "crontools"] + additional_dependencies: ["types-tzlocal"] diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b55f88b..1cfcbe9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,7 @@ Changelog ------------------ - pipenv substituted by poetry +- mypy checker added 0.1.5 (2022-04-24) diff --git a/crontools/crontab.py b/crontools/crontab.py index f9f2b74..b5dd2a3 100644 --- a/crontools/crontab.py +++ b/crontools/crontab.py @@ -2,10 +2,12 @@ import dataclasses as dc import datetime as dt import heapq -from math import ceil import operator as op +from math import ceil +from typing import Any, ClassVar, Dict, Generator, Generic, Iterable, Iterator, Optional, Tuple, Type, TypeVar, Union +from typing import cast + import tzlocal -from typing import Any, ClassVar, Dict, Generic, Iterator, Iterable, Optional, Type, TypeVar, Tuple SENTINEL = object() @@ -83,19 +85,19 @@ def fromstr(cls, string: str) -> 'Range': begin, end, step = None, None, None string = string.strip() - interval, *maybe_step = string.split('/', maxsplit=1) - if maybe_step: - maybe_step = maybe_step[0] + interval, *rem = string.split('/', maxsplit=1) + if rem: + maybe_step = rem[0] step = cls._parse_number(maybe_step) if interval == '*': return cls(None, None, step) - begin, *maybe_end = interval.split('-', maxsplit=1) + begin, *rem = interval.split('-', maxsplit=1) begin = cls.aliases.get(begin, begin) if cls.aliases else begin begin = cls._parse_number(begin) - if maybe_end: - maybe_end = maybe_end[0] + if rem: + maybe_end = rem[0] maybe_end = cls.aliases.get(maybe_end, maybe_end) if cls.aliases else maybe_end end = cls._parse_number(maybe_end) @@ -105,16 +107,18 @@ def fromstr(cls, string: str) -> 'Range': return cls(begin, end, step) @classmethod - def _parse_number(cls, value: str): + def _parse_number(cls, value: Union[str, int]) -> int: try: - value = int(value) + parsed_value = int(value) except ValueError: raise ValueError(f"{cls.title} value must be of type int, got: {value}") - if not (cls.min_value <= value <= cls.max_value): - raise ValueError(f"{cls.title} value must be of range [{cls.min_value}, {cls.max_value}], got: {value}") + if not (cls.min_value <= parsed_value <= cls.max_value): + raise ValueError( + f"{cls.title} value must be of range [{cls.min_value}, {cls.max_value}], got: {parsed_value}", + ) - return value + return parsed_value @property def is_default(self) -> bool: @@ -136,6 +140,8 @@ def iter(self, start_from: Optional[int] = None) -> Iterator[int]: begin = self.min_value end = self.max_value else: + assert self.begin is not None + begin = self.begin end = self.begin if self.end is None else self.end @@ -263,9 +269,9 @@ def fromstr(cls, string: str) -> 'Field[RangeType]': :return: field """ - ranges = (cls.range_type.fromstr(item) for item in string.split(',')) + ranges = cast(Iterable[RangeType], (cls.range_type.fromstr(item) for item in string.split(','))) - return cls(ranges=tuple(sorted(ranges, key=lambda rng: rng.begin))) + return cls(ranges=tuple(sorted(ranges, key=lambda rng: rng.begin if rng.begin is not None else rng.min_value))) @property def is_default(self) -> bool: @@ -313,23 +319,27 @@ def iter(self, year: Optional[int] = None, month: Optional[int] = None, start_fr year = now.year if year is None else year month = now.month if month is None else month + day_iter: Iterable[int] if self._weekday_field.is_default: day_iter = self._monthday_iter(year, month, start_from) elif self._monthday_field.is_default: day_iter = self._weekday_iter(year, month, start_from) else: - day_iter = heapq.merge(self._monthday_iter(year, month, start_from), self._weekday_iter(year, month, start_from)) + day_iter = heapq.merge( + self._monthday_iter(year, month, start_from), + self._weekday_iter(year, month, start_from), + ) return unique(day_iter) - def _monthday_iter(self, year: int, month: int, start_from: int = 1) -> Iterator[int]: + def _monthday_iter(self, year: int, month: int, start_from: int = 1) -> Generator[int, None, None]: for day in self._monthday_field.iter(start_from=start_from): if day > calendar.monthrange(year, month)[1]: break yield day - def _weekday_iter(self, year: int, month: int, start_day: int = 1) -> Iterator[int]: + def _weekday_iter(self, year: int, month: int, start_day: int = 1) -> Generator[int, None, None]: curr_day = start_day curr_weekday = calendar.weekday(year, month, curr_day) + 1 weekday_iter = self._weekday_field.iter(start_from=curr_weekday) @@ -430,6 +440,7 @@ def parse( fields_iter = iter(fields) now = (now or dt.datetime.now(tz=tz)).astimezone(tz) + assert now.tzinfo is not None return cls( second_field=SecondsField.fromstr(next(fields_iter)) if seconds_ext else SecondsField.fromstr('0'), @@ -452,7 +463,8 @@ def __iter__(self) -> Iterator[dt.datetime]: for minute in self.minute_field: for second in self.second_field: yield dt.datetime( - year=year, month=month, day=day, hour=hour, minute=minute, second=second, tzinfo=self.tz, + year=year, month=month, day=day, + hour=hour, minute=minute, second=second, tzinfo=self.tz, ) def iter(self, start_from: dt.datetime) -> Iterator[dt.datetime]: @@ -508,7 +520,8 @@ def iter(self, start_from: dt.datetime) -> Iterator[dt.datetime]: continue yield dt.datetime( - year=year, month=month, day=day, hour=hour, minute=minute, second=second, tzinfo=self.tz, + year=year, month=month, day=day, + hour=hour, minute=minute, second=second, tzinfo=self.tz, ) first_run = False diff --git a/crontools/py.typed b/crontools/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/pyproject.toml b/pyproject.toml index 3f4da5a..e7008b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,7 @@ classifiers = [ "Topic :: Software Development :: Libraries", "Topic :: Utilities" ] +include = ["crontools/py.typed"] [tool.poetry.dependencies] python = "^3.7" @@ -25,8 +26,21 @@ types-tzlocal = "^4.1.0" pytest = "^6.0" pytest-cov = "^2.0" freezegun = "^1.2" +mypy = "^1.0.1" pre-commit = "^2.18.1" [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" + + +[tool.mypy] +allow_redefinition = true +disallow_incomplete_defs = true +disallow_any_generics = true +disallow_untyped_decorators = true +disallow_untyped_defs = true +no_implicit_optional = true +show_error_codes = true +strict_equality = true +warn_unused_ignores = true From 59e73ff8595716ec231255e2f32b8fdaa22d60ec Mon Sep 17 00:00:00 2001 From: Dmitry Pershin Date: Sun, 24 Apr 2022 20:52:35 +0500 Subject: [PATCH 4/8] python 3.10, 3.11 tests added. --- .github/workflows/test.yml | 2 +- pyproject.toml | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c378e1d..a48b89f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.7, 3.8, 3.9] + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} diff --git a/pyproject.toml b/pyproject.toml index e7008b0..845f7a3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,6 +11,11 @@ keywords = ["cron", "crontab", "cron-utils", "cron-tools", "parser"] classifiers = [ "License :: Public Domain", "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "Intended Audience :: Developers", "Topic :: Software Development :: Libraries", "Topic :: Utilities" From fa54ed2fc07206a27afb1ee29e59f0fb54a74fbc Mon Sep 17 00:00:00 2001 From: Dmitry Pershin Date: Sun, 24 Apr 2022 20:53:05 +0500 Subject: [PATCH 5/8] downloads readme budge added. --- README.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 291b137..29a1804 100644 --- a/README.rst +++ b/README.rst @@ -2,7 +2,10 @@ crontools ========= -.. image:: https://github.com/dapper91/crontools/actions/workflows/test.yml/badge.svg +.. image:: https://static.pepy.tech/personalized-badge/crontools?period=month&units=international_system&left_color=grey&right_color=orange&left_text=Downloads/month + :target: https://pepy.tech/project/crontools + :alt: Downloads/month +.. image:: https://github.com/dapper91/crontools/actions/workflows/test.yml/badge.svg?branch=master :target: https://github.com/dapper91/crontools/actions/workflows/test.yml :alt: Build status .. image:: https://img.shields.io/pypi/l/crontools.svg From b3855cc307a57a2818b73bbd487dc2fd936f6bf2 Mon Sep 17 00:00:00 2001 From: Dmitry Pershin Date: Sat, 25 Feb 2023 16:45:15 +0500 Subject: [PATCH 6/8] author email updated. --- crontools/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crontools/__about__.py b/crontools/__about__.py index f81b0a1..f6da45b 100644 --- a/crontools/__about__.py +++ b/crontools/__about__.py @@ -5,6 +5,6 @@ __version__ = '0.1.5' __author__ = 'Dmitry Pershin' -__email__ = 'dapper91@mail.ru' +__email__ = 'dapper1291@gmail.com' __license__ = 'Public Domain License' From 195ae22666e37f098c8adf0f2ff03723ff04dae3 Mon Sep 17 00:00:00 2001 From: Dmitry Pershin Date: Sat, 25 Feb 2023 16:50:25 +0500 Subject: [PATCH 7/8] dev dependencies updated. --- pyproject.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 845f7a3..3c62639 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,14 +25,14 @@ include = ["crontools/py.typed"] [tool.poetry.dependencies] python = "^3.7" tzlocal = "^2.0" -types-tzlocal = "^4.1.0" [tool.poetry.dev-dependencies] -pytest = "^6.0" -pytest-cov = "^2.0" -freezegun = "^1.2" +pre-commit = "^2.21.0" mypy = "^1.0.1" -pre-commit = "^2.18.1" +pytest = "^7.2.1" +pytest-cov = "^4.0.0" +freezegun = "^1.2.1" +types-tzlocal = "^4.1.0" [build-system] requires = ["poetry-core>=1.0.0"] From 677d7714c7d7e1d30eb090542ebfa98db0b82224 Mon Sep 17 00:00:00 2001 From: Dmitry Pershin Date: Sat, 25 Feb 2023 17:31:16 +0500 Subject: [PATCH 8/8] bump version 0.1.6. --- CHANGELOG.rst | 3 ++- crontools/__about__.py | 2 +- pyproject.toml | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1cfcbe9..942686f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,11 +2,12 @@ Changelog ========= -0.1.6 (2022-04-24) +0.1.6 (2023-02-25) ------------------ - pipenv substituted by poetry - mypy checker added +- python 3.10, 3.11 support added 0.1.5 (2022-04-24) diff --git a/crontools/__about__.py b/crontools/__about__.py index f6da45b..2ef5685 100644 --- a/crontools/__about__.py +++ b/crontools/__about__.py @@ -2,7 +2,7 @@ __description__ = 'Python cron tools' __url__ = 'https://github.com/dapper91/crontools' -__version__ = '0.1.5' +__version__ = '0.1.6' __author__ = 'Dmitry Pershin' __email__ = 'dapper1291@gmail.com' diff --git a/pyproject.toml b/pyproject.toml index 3c62639..4a8cc78 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "crontools" -version = "0.1.5" +version = "0.1.6" description = "Python cron tools" authors = ["Dmitry Pershin "] license = "Unlicense" @@ -9,6 +9,7 @@ homepage = "https://github.com/dapper91/crontools" repository = "https://github.com/dapper91/crontools" keywords = ["cron", "crontab", "cron-utils", "cron-tools", "parser"] classifiers = [ + "Development Status :: 5 - Production/Stable", "License :: Public Domain", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.7",