From e7a48134fff1dda0dc2593c3e00237dba7107b4f Mon Sep 17 00:00:00 2001 From: Nicolas Simonds Date: Wed, 28 Feb 2024 10:16:22 -0800 Subject: [PATCH 1/2] Modernize Python tooling Move all configs into `pyproject.toml`, switch test/packaging to use Hatch, and do all the linting with Ruff. Fix issues that Ruff turned up, and annotate/ignore the pieces that it got wrong. Fixes: Issue #33 --- .coveragerc | 4 - .github/workflows/python-publish.yml | 4 +- .github/workflows/tests.yml | 6 +- .gitignore | 4 + doc/conf.py | 5 +- pyproject.toml | 122 +++++++++++++++++++++++++++ pytest.ini | 2 - setup.py | 75 ---------------- spinach/__init__.py | 3 - spinach/const.py | 2 - tox.ini | 28 ------ 11 files changed, 134 insertions(+), 121 deletions(-) delete mode 100644 .coveragerc create mode 100644 pyproject.toml delete mode 100644 pytest.ini delete mode 100644 setup.py delete mode 100644 tox.ini diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index c35604b..0000000 --- a/.coveragerc +++ /dev/null @@ -1,4 +0,0 @@ -[run] -relative_files = True -include = - spinach/* \ No newline at end of file diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 93e30e4..3e051df 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -18,11 +18,11 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install setuptools wheel twine + pip install hatch twine - name: Build and publish env: TWINE_USERNAME: __token__ TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} run: | - python setup.py sdist bdist_wheel + hatch build twine upload dist/* diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 34b0753..067b6fb 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -28,15 +28,15 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e .[tests] + pip install hatch - name: Lint run: | - pycodestyle --ignore=E252,W503,W504 spinach tests + hatch run pep8 - name: Test with pytest run: | - pytest -v --cov=spinach tests/ + hatch run ci - name: Coveralls uses: AndreMiras/coveralls-python-action@develop diff --git a/.gitignore b/.gitignore index 5194427..756c307 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +# _version is generated by setuptools_scm and requests not to be under a VCS +spinach/_version.py + +.hatch .pyc __pycache__ diff --git a/doc/conf.py b/doc/conf.py index 128fded..cc1209b 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -22,6 +22,7 @@ sys.path.insert(0, os.path.abspath('..')) import spinach +from spinach import _version as spinach_version # -- General configuration ------------------------------------------------ @@ -66,9 +67,9 @@ # built documents. # # The short X.Y version. -version = spinach.__version__ +version = spinach_version.__version__ # The full version, including alpha/beta/rc tags. -release = spinach.__version__ +release = spinach_version.__version__ # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..05bbd57 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,122 @@ +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" + +[project] +name = "spinach" +dynamic = ["version"] +description = "Modern Redis task queue for Python 3" +readme = "README.rst" +license-files = { paths = ["LICENSE"] } +requires-python = ">=3.8.0,<4.0.0" +authors = [ + { name = "Nicolas Le Manchet", email = "nicolas@lemanchet.fr" }, +] +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "Topic :: Software Development :: Libraries", + "Topic :: System :: Distributed Computing", + "License :: OSI Approved :: BSD License", + "Natural Language :: English", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", +] +keywords = ["task", "queue", "jobs", "redis"] +urls.Source = "https://github.com/NicolasLM/spinach" + +dependencies = [ + "redis", + "blinker" +] + +[project.optional-dependencies] +tests = [ + "pytest", + "pytest-cov", + "pytest-threadleak", + "ruff", + "flask", + "django" +] + +[tool.hatch.version] +source = "vcs" + +[tool.hatch.build.hooks.vcs] +version-file = "spinach/_version.py" + +[tool.hatch.build.targets.sdist] +ignore-vcs = true +include = ["/spinach", "/tests"] + +[tool.hatch.build.targets.wheel] +packages = ["spinach"] + +[tool.hatch.build.targets.wheel.package-data] +"spinach.brokers.redis_scripts" = [ + "deregister.lua", + "enqueue_job.lua", + "enqueue_jobs_from_dead_broker.lua", + "flush.lua", + "get_jobs_from_queue.lua", + "move_future_jobs.lua", + "register_periodic_tasks.lua", + "remove_job_from_running.lua", + "set_concurrency_keys.lua", +] + +[tool.hatch.envs.default] +path = ".hatch" +features = ["tests"] + +scripts.pep8 = ["ruff spinach tests"] + +scripts.py3 = [ + "docker-compose -f tests/docker-compose.yml up -d", + "pytest tests {args}", + "docker-compose -f tests/docker-compose.yml down", +] + +# A minimalist pytest runner for Github to use +scripts.ci = ["pytest -v --cov=spinach tests {args}"] + +[tool.ruff.lint] +select = ["B", "C9", "D", "E", "F", "S", "W"] +ignore = [ + "B018", # Useless expression (seems to have false-positive bugs) + "S101", # Use of `assert` detected (conflicts with pytest) + "D10", # Missing docstring in public function / module / etc. + "D203", # 1 blank line required before class docstring + "D205", # 1 blank line required between summary line and description + "D213", # Multi-line docstring summary should start at the second line + "D40", # First line of docstring complaints + "D415", # First line should end with a period, question mark, or exclamation point + # TODO(nic): The remaining ignores point to actual issues in the code. + # Remove them and fix the issues later. + "B024", + "B027", + "B904", + "D204", + "F401", + "F841", + "S301", + "S311", +] +# Aggregating symbols into a convenient location for import is good practice +# for libraries, we don't care if they look unused +per-file-ignores = { "__init__.py" = ["F401"] } +mccabe.max-complexity = 13 + +[tool.coverage.run] +relative_files = true +include = ["spinach/*"] +omit = ["spinach/_version.py"] + +[tool.pytest.ini_options] +threadleak = true diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index 4a1804a..0000000 --- a/pytest.ini +++ /dev/null @@ -1,2 +0,0 @@ -[pytest] -threadleak = True \ No newline at end of file diff --git a/setup.py b/setup.py deleted file mode 100644 index 4b4afff..0000000 --- a/setup.py +++ /dev/null @@ -1,75 +0,0 @@ -from setuptools import setup, find_packages -from codecs import open -from os import path - -here = path.abspath(path.dirname(__file__)) - -with open(path.join(here, 'README.rst'), encoding='utf-8') as f: - long_description = f.read() - -with open(path.join(here, 'LICENSE'), encoding='utf-8') as f: - long_description += f.read() - -with open(path.join(here, 'spinach', 'const.py'), encoding='utf-8') as fp: - version = dict() - exec(fp.read(), version) - version = version['VERSION'] - -setup( - name='spinach', - version=version, - description='Modern Redis task queue for Python 3', - long_description=long_description, - url='https://github.com/NicolasLM/spinach', - author='Nicolas Le Manchet', - author_email='nicolas@lemanchet.fr', - license='BSD 2-clause', - # See https://pypi.python.org/pypi?%3Aaction=list_classifiers - classifiers=[ - 'Development Status :: 4 - Beta', - 'Intended Audience :: Developers', - 'Topic :: Software Development :: Libraries', - 'Topic :: System :: Distributed Computing', - 'License :: OSI Approved :: BSD License', - 'Natural Language :: English', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3 :: Only', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: 3.11', - 'Programming Language :: Python :: 3.12', - ], - keywords='task queue jobs redis', - - packages=find_packages(include=('spinach', 'spinach.*')), - install_requires=[ - 'redis', - 'blinker' - ], - - extras_require={ - 'tests': [ - 'pytest', - 'pytest-cov', - 'pytest-threadleak', - 'pycodestyle', - 'flask', - 'django' - ], - }, - - package_data={ - 'spinach.brokers.redis_scripts': [ - 'deregister.lua', - 'enqueue_job.lua', - 'enqueue_jobs_from_dead_broker.lua', - 'flush.lua', - 'get_jobs_from_queue.lua', - 'move_future_jobs.lua', - 'register_periodic_tasks.lua', - 'remove_job_from_running.lua', - 'set_concurrency_keys.lua', - ], - }, -) diff --git a/spinach/__init__.py b/spinach/__init__.py index dc3fc3d..2cafae2 100644 --- a/spinach/__init__.py +++ b/spinach/__init__.py @@ -1,8 +1,5 @@ from .brokers.memory import MemoryBroker from .brokers.redis import RedisBroker -from .const import VERSION from .engine import Engine from .task import Tasks, Batch, RetryException, AbortException from .worker import ThreadWorkers, AsyncioWorkers - -__version__ = VERSION diff --git a/spinach/const.py b/spinach/const.py index 4f902dc..c758507 100644 --- a/spinach/const.py +++ b/spinach/const.py @@ -1,5 +1,3 @@ -VERSION = '0.0.24' - DEFAULT_QUEUE = 'spinach' DEFAULT_NAMESPACE = 'spinach' DEFAULT_MAX_RETRIES = 0 diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 2a62ff8..0000000 --- a/tox.ini +++ /dev/null @@ -1,28 +0,0 @@ -[tox] -envlist = py3, pep8 - -[testenv] -basepython = python3 -envdir = - py3: {toxworkdir}/py3 - pep8: {toxworkdir}/py3 -usedevelop = True -allowlist_externals = - docker-compose -deps = - pytest - pytest-cov - pytest-threadleak - pycodestyle - flake8 - flask - django - -[testenv:pep8] -commands = - pycodestyle --ignore=E252,W503,W504 spinach tests - -[testenv:py3] -commands_pre = docker-compose -f {toxinidir}/tests/docker-compose.yml up -d -commands = pytest tests {posargs} -commands_post = docker-compose -f {toxinidir}/tests/docker-compose.yml down From abdcc7cb4d6a713485a559a1a566579128327c3e Mon Sep 17 00:00:00 2001 From: Nicolas Simonds Date: Wed, 28 Feb 2024 12:50:48 -0800 Subject: [PATCH 2/2] Add a build target for the docs Generate the documentation with `hatch run docs:build $TYPE` --- doc/hacking/contributing.rst | 21 ++++++++------------- pyproject.toml | 9 +++++++++ 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/doc/hacking/contributing.rst b/doc/hacking/contributing.rst index 5de8940..21ddc4d 100644 --- a/doc/hacking/contributing.rst +++ b/doc/hacking/contributing.rst @@ -30,26 +30,22 @@ Python sources The code base follows `pep8 `_ guidelines with lines wrapping at the 79th character. You can verify that the code follows the conventions with:: - $ pycodestyle --ignore=E252,W503,W504 spinach tests + $ hatch run pep8 Running tests is an invaluable help when adding a new feature or when refactoring. Try to add the -proper test cases in ``tests/`` together with your patch. The test suite can be run with pytest:: +proper test cases in ``tests/`` together with your patch. Because the Redis broker tests require +a running Redis server, there is a convenience `pyproject.toml` that runs all the tests and pep8 +checks for you after starting Redis in a container via docker-compose. Simply running:: - $ pytest tests - -Because the Redis broker tests require a running Redis server, there is also a convenience -`tox.ini` that runs all the tests and pep8 checks for you after starting Redis in a container via -docker-compose. Simply running:: - - $ tox + $ hatch run py3 will build a virtualenv, install Spinach and its dependencies into it, start the Redis server in -the container, and run tests and pycodestyle, tearing down the Redis server container when done. +the container, and run tests and pep8, tearing down the Redis server container when done. Compatibility ------------- -Spinach runs on all versions of Python starting from 3.6. Tests are run via GitHub actions to +Spinach runs on all versions of Python starting from 3.8. Tests are run via GitHub actions to ensure that. Documentation sources @@ -61,7 +57,6 @@ with `Sphinx `_. If you modify the docs, make sure it builds without errors:: - $ cd doc/ - $ make html + $ hatch run docs:build html The generated HTML pages should land in ``doc/_build/html``. diff --git a/pyproject.toml b/pyproject.toml index 05bbd57..e2e65f5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,6 +86,15 @@ scripts.py3 = [ # A minimalist pytest runner for Github to use scripts.ci = ["pytest -v --cov=spinach tests {args}"] +[tool.hatch.envs.docs] +detatched = true +dependencies = [ + "sphinx", + "blinker" +] +path = ".hatch" +scripts.build = ["cd doc && make {args}"] + [tool.ruff.lint] select = ["B", "C9", "D", "E", "F", "S", "W"] ignore = [