From 82fbbeb6b22dd6ea30355b62b2f3a45ec86ba15d Mon Sep 17 00:00:00 2001 From: Peter Bittner Date: Fri, 4 Apr 2025 13:23:06 +0200 Subject: [PATCH] Migrate packaging from setup.py to pyproject.toml --- .github/workflows/check.yml | 16 ++--- .github/workflows/release.yml | 19 +++--- .github/workflows/test.yml | 37 +++++----- .gitignore | 3 + CHANGELOG.rst | 2 + analytical/__init__.py | 7 +- docs/conf.py | 6 +- pyproject.toml | 123 ++++++++++++++++++++++++++++++---- requirements.txt | 1 - setup.py | 62 ----------------- tox.ini | 99 ++++++++++++++++----------- 11 files changed, 216 insertions(+), 159 deletions(-) delete mode 100644 requirements.txt delete mode 100644 setup.py diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 2836be2..9a7923e 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -15,21 +15,21 @@ jobs: fail-fast: false matrix: env: - - isort - - flake8 - - bandit - - readme + - lint + - format + - audit + - package - docs steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v5 with: - python-version: '3.8' + python-version: '3.12' - name: Install prerequisites - run: python -m pip install --upgrade setuptools pip wheel tox + run: python -m pip install tox - name: Run ${{ matrix.env }} run: tox -e ${{ matrix.env }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4784861..2ae375f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,20 +5,24 @@ on: tags: - '*' +env: + PIP_DISABLE_PIP_VERSION_CHECK: '1' + PY_COLORS: '1' + jobs: build: if: github.repository == 'jazzband/django-analytical' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: - python-version: '3.8' + python-version: '3.12' - name: Get pip cache dir id: pip-cache @@ -26,7 +30,7 @@ jobs: echo "::set-output name=dir::$(pip cache dir)" - name: Cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ${{ steps.pip-cache.outputs.dir }} key: release-${{ hashFiles('**/setup.py') }} @@ -35,14 +39,11 @@ jobs: - name: Install dependencies run: | - python -m pip install -U pip - python -m pip install -U setuptools twine wheel + python -m pip install tox - name: Build package run: | - python setup.py --version - python setup.py sdist --format=gztar bdist_wheel - twine check dist/* + tox -e package - name: Upload packages to Jazzband if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9948809..3cab676 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,6 +8,10 @@ on: branches: - main +env: + PIP_DISABLE_PIP_VERSION_CHECK: '1' + PY_COLORS: '1' + jobs: python-django: runs-on: ubuntu-latest @@ -15,25 +19,25 @@ jobs: max-parallel: 5 matrix: python-version: - - '3.6' - - '3.7' - - '3.8' - - '3.9' - '3.10' + - '3.11' + - '3.12' + - '3.13' django-version: - - '2.2' - - '3.2' - - '4.0' + - '4.2' + - '5.1' + - '5.2' + include: + - { django-version: '4.2', python-version: '3.8' } + - { django-version: '4.2', python-version: '3.9' } exclude: - - { django-version: '2.2', python-version: '3.10' } - - { django-version: '4.0', python-version: '3.6' } - - { django-version: '4.0', python-version: '3.7' } + - { django-version: '4.2', python-version: '3.13' } steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -43,18 +47,17 @@ jobs: echo "::set-output name=dir::$(pip cache dir)" - name: Cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ${{ steps.pip-cache.outputs.dir }} key: - ${{ matrix.python-version }}-v1-${{ hashFiles('**/setup.py') }} + ${{ matrix.python-version }}-v1-${{ hashFiles('**/pyproject.toml') }} restore-keys: | ${{ matrix.python-version }}-v1- - name: Install dependencies run: | - python -m pip install --upgrade pip - python -m pip install --upgrade tox tox-gh-actions + python -m pip install tox tox-gh-actions - name: Tox tests (Python ${{ matrix.python-version }}, Django ${{ matrix.django-version }}) run: tox @@ -62,6 +65,6 @@ jobs: DJANGO: ${{ matrix.django-version }} - name: Upload coverage - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v5 with: name: Python ${{ matrix.python-version }} diff --git a/.gitignore b/.gitignore index c671177..5275f3c 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,6 @@ /docs/_templates/layout.html /MANIFEST *.egg-info + +/requirements.txt +/uv.lock diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1f990c9..f3e8561 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,8 @@ Unreleased ---------- * Remove deprecated Piwik integration. Use Matomo instead! (Peter Bittner) +* Migrate packaging from setup.py to pyproject.toml with Ruff for linting + and formatting (Peter Bittner) Version 3.1.0 ------------- diff --git a/analytical/__init__.py b/analytical/__init__.py index 7541c72..cbdca74 100644 --- a/analytical/__init__.py +++ b/analytical/__init__.py @@ -1,8 +1,5 @@ """ -Analytics service integration for Django projects +Analytics service integration for Django projects. """ -__author__ = "Joost Cassee" -__email__ = "joost@cassee.net" -__version__ = "3.1.0" -__copyright__ = "Copyright (C) 2011 Joost Cassee and contributors" +__version__ = '3.2.0.dev0' diff --git a/docs/conf.py b/docs/conf.py index 1894cd9..215350a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -28,9 +28,9 @@ add_function_parentheses = True pygments_style = 'sphinx' intersphinx_mapping = { - 'http://docs.python.org/2.7': None, - 'http://docs.djangoproject.com/en/1.9': - 'http://docs.djangoproject.com/en/1.9/_objects/', + 'python': ('http://docs.python.org/3.13', None), + 'django': ('http://docs.djangoproject.com/en/stable', + 'http://docs.djangoproject.com/en/stable/_objects/'), } diff --git a/pyproject.toml b/pyproject.toml index 99679b2..b99677a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,20 +1,115 @@ -[tool.bandit] -# Exclude/ignore of files and TOML reading is currently broken in Bandit -exclude = [".cache",".git",".github",".tox","build","dist","docs","tests"] +[build-system] +build-backend = "setuptools.build_meta" +requires = ["setuptools>=64"] -[tool.black] -color = true +[project] +name = "django-analytical" +dynamic = ["version"] +description = "Analytics service integration for Django projects" +readme = "README.rst" +authors = [ + {name = "Joost Cassee", email = "joost@cassee.net"}, + {name = "Joshua Krall", email = "joshuakrall@pobox.com"}, + {name = "Aleck Landgraf", email = "aleck.landgraf@buildingenergy.com"}, + {name = "Alexandre Pocquet", email = "apocquet@lecko.fr"}, + {name = "Bateau Knowledge", email = "info@bateauknowledge.nl"}, + {name = "Bogdan Bodnar", email = "bogdanbodnar@mail.com"}, + {name = "Brad Pitcher", email = "bradpitcher@gmail.com"}, + {name = "Corentin Mercier", email = "corentin@mercier.link"}, + {name = "Craig Bruce", email = "craig@eyesopen.com"}, + {name = "Daniel Vitiello", email = "ezdismissal@gmail.com"}, + {name = "David Smith", email = "smithdc@gmail.com"}, + {name = "Diederik van der Boor", email = "vdboor@edoburu.nl"}, + {name = "Eric Amador", email = "eric.amador14@gmail.com"}, + {name = "Eric Davis", email = "eric@davislv.com"}, + {name = "Eric Wang", email = "gnawrice@gmail.com"}, + {name = "Garrett Coakley", email = "garrettc@users.noreply.github.com"}, + {name = "Garrett Robinson", email = "garrett.f.robinson@gmail.com"}, + {name = "GreenKahuna", email = "info@greenkahuna.com"}, + {name = "Hugo Osvaldo Barrera", email = "hugo@barrera.io"}, + {name = "Ian Ramsay", email = "ianalexr@yahoo.com"}, + {name = "Iván Raskovsky", email = "raskovsky+git@gmail.com"}, + {name = "James Paden", email = "james@xemion.com"}, + {name = "Jannis Leidel", email = "jannis@leidel.info"}, + {name = "Julien Grenier", email = "julien.grenier42@gmail.com"}, + {name = "Kevin Olbrich", email = "ko@sv01.de"}, + {name = "Marc Bourqui", email = "m.bourqui@edsi-tech.com"}, + {name = "Martey Dodoo", email = "martey@mobolic.com"}, + {name = "Martín Gaitán", email = "gaitan@gmail.com"}, + {name = "Matthäus G. Chajdas", email = "dev@anteru.net"}, + {name = "Max Arnold", email = "arnold.maxim@gmail.com"}, + {name = "Nikolay Korotkiy", email = "sikmir@gmail.com"}, + {name = "Paul Oswald", email = "pauloswald@gmail.com"}, + {name = "Peter Bittner", email = "django@bittner.it"}, + {name = "Petr Dlouhý", email = "petr.dlouhy@email.cz"}, + {name = "Philippe O. Wagner", email = "admin@arteria.ch"}, + {name = "Pi Delport", email = "pjdelport@gmail.com"}, + {name = "Sandra Mau", email = "sandra.mau@gmail.com"}, + {name = "Scott Adams", email = "scottadams80@gmail.com"}, + {name = "Scott Karlin", email = "gitlab@karlin-online.com"}, + {name = "Sean Wallace", email = "sean@lowpro.ca"}, + {name = "Sid Mitra", email = "sidmitra.del@gmail.com"}, + {name = "Simon Ye", email = "sye737@gmail.com"}, + {name = "Steve Schwarz", email = "steve@agilitynerd.com"}, + {name = "Steven Skoczen", email = "steven.skoczen@wk.com"}, + {name = "Tim Gates", email = "tim.gates@iress.com"}, + {name = "Tinnet Coronam", email = "tinnet@coronam.net"}, + {name = "Uros Trebec", email = "uros@trebec.org"}, + {name = "Walter Renner", email = "walter.renner@me.com"}, +] +maintainers = [ + {name = "Jazzband community", email = "jazzband-bot@users.noreply.github.com"}, + {name = "Peter Bittner", email = "django@bittner.it"}, +] +keywords=[ + "django", + "analytics", +] +classifiers=[ + "Development Status :: 5 - Production/Stable", + "Environment :: Web Environment", + "Framework :: Django", + "Framework :: Django :: 4.2", + "Framework :: Django :: 5.1", + "Framework :: Django :: 5.2", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "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", + "Programming Language :: Python :: 3.13", + "Topic :: Internet :: WWW/HTTP", + "Topic :: Software Development :: Libraries :: Python Modules", +] +requires-python = ">=3.8" +dependencies = [ + "django>=4.2", +] -[tool.coverage.xml] -output = "tests/coverage-report.xml" - -[tool.isort] -color_output = true -profile = "black" - -[tool.pylint.master] -output-format = "colorized" +[project.urls] +Homepage = "https://github.com/jazzband/django-analytical" +Documentation = "https://django-analytical.readthedocs.io/" [tool.pytest.ini_options] addopts = "--junitxml=tests/unittests-report.xml --color=yes --verbose" DJANGO_SETTINGS_MODULE = "tests.testproject.settings" + +[tool.ruff.format] +quote-style = "single" + +[tool.ruff.lint.flake8-quotes] +inline-quotes = "single" + +[tool.setuptools] +packages = [ + "analytical", + "analytical.templatetags", +] + +[tool.setuptools.dynamic] +version = {attr = "analytical.__version__"} diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 4298a2d..0000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -Django>=2.2.* diff --git a/setup.py b/setup.py deleted file mode 100644 index 4bf7a51..0000000 --- a/setup.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -Packaging setup for django-analytical. -""" - -from pathlib import Path - -from setuptools import setup - -import analytical as package - - -def read_file(filename): - """Read a text file and return its contents.""" - project_home = Path(__file__).parent.resolve() - file_path = project_home / filename - return file_path.read_text(encoding="utf-8") - - -setup( - name='django-analytical', - version=package.__version__, - description=package.__doc__.strip(), - long_description=read_file('README.rst'), - long_description_content_type='text/x-rst', - author=package.__author__, - author_email=package.__email__, - packages=[ - 'analytical', - 'analytical.templatetags', - ], - keywords=[ - 'django', - 'analytics', - ], - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Environment :: Web Environment', - 'Framework :: Django', - 'Framework :: Django :: 2.2', - 'Framework :: Django :: 3.2', - 'Framework :: Django :: 4.0', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Topic :: Internet :: WWW/HTTP', - 'Topic :: Software Development :: Libraries :: Python Modules', - ], - python_requires='>=3.6', - platforms=['any'], - url='https://github.com/jazzband/django-analytical', - download_url='https://github.com/jazzband/django-analytical/archive/main.zip', - project_urls={ - 'Documentation': 'https://django-analytical.readthedocs.io/', - }, -) diff --git a/tox.ini b/tox.ini index e286479..9cc4be0 100644 --- a/tox.ini +++ b/tox.ini @@ -1,79 +1,98 @@ [tox] envlist = - isort - flake8 - bandit + lint + format + audit # Python/Django combinations that are officially supported - py{36,37,38,39}-django{22} - py{36,37,38,39,310}-django{32} - py{38,39,310}-django{40} - readme + py{38,39,310,311,312}-django{42} + py{310,311,312,313}-django{51} + py{310,311,312,313}-django{52} + package docs + clean [gh-actions] python = - 3.6: py36 - 3.7: py37 3.8: py38 3.9: py39 3.10: py310 + 3.10: py310 + 3.11: py311 + 3.12: py312 + 3.13: py313 [gh-actions:env] DJANGO = - 2.2: django22 - 3.2: django32 - 4.0: django40 + 4.2: django42 + 5.1: django51 + 5.2: django52 [testenv] description = Unit tests deps = coverage[toml] pytest-django - django22: Django>=2.2,<3.0 - django32: Django>=3.2,<4.0 - django40: Django>=4.0,<4.1 + django42: Django>=4.2,<5.0 + django51: Django>=5.1,<5.2 + django52: Django>=5.2,<6.0 commands = coverage run -m pytest {posargs} coverage xml +[testenv:audit] +description = Scan for vulnerable dependencies +skip_install = true +deps = + pip-audit + uv +commands = + uv export --no-emit-project --no-hashes -o requirements.txt -q + pip-audit {posargs:-r requirements.txt --progress-spinner off} + [testenv:bandit] description = PyCQA security linter +skip_install = true deps = bandit -commands = -bandit {posargs:-r analytical} -v +commands = bandit {posargs:-r analytical} -v + +[testenv:clean] +description = Clean up bytecode and build artifacts +skip_install = true +deps = pyclean +commands = pyclean {posargs:. --debris --erase requirements.txt tests/unittests-report.xml --yes} [testenv:docs] description = Build the HTML documentation deps = sphinx commands = sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html -[testenv:flake8] -description = Static code analysis and code style -deps = flake8 -commands = flake8 {posargs} +[testenv:format] +description = Ensure consistent code style (Ruff) +skip_install = true +deps = ruff +commands = ruff format {posargs:--check --diff .} -[testenv:isort] -description = Ensure imports are ordered consistently -deps = isort[colors] -commands = isort --check-only --diff {posargs:analytical setup.py tests} +[testenv:lint] +description = Lightening-fast linting (Ruff) +skip_install = true +deps = ruff +commands = ruff check {posargs:--output-format=full .} -[testenv:readme] -description = Ensure README renders on PyPI +[testenv:mypy] +description = Perform static type checking +deps = mypy +commands = mypy {posargs:.} + +[testenv:package] +description = Build package and check metadata (or upload package) +skip_install = true deps = build twine commands = python -m build - twine check dist/* - -[testenv:clean] -description = Clean up bytecode and build artifacts -deps = pyclean -commands = - pyclean {posargs:.} - rm -rf .tox/ build/ dist/ django_analytical.egg-info/ .coverage coverage.xml tests/coverage-report.xml tests/unittests-report.xml -allowlist_externals = - rm - -[flake8] -exclude = .cache,.git,.tox,build,dist -max-line-length = 100 + twine {posargs:check --strict} dist/* +passenv = + TWINE_USERNAME + TWINE_PASSWORD + TWINE_REPOSITORY_URL