diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 0000000..0f06e16 --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,33 @@ +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/pure-python +name: pre-commit + +on: + pull_request: + push: + branches: + - master + # Allow to run this workflow manually from the Actions tab + workflow_dispatch: + +env: + FORCE_COLOR: 1 + +jobs: + pre-commit: + name: linting + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: 3.x + - uses: pre-commit/action@v3.0.1 + with: + extra_args: --all-files --show-diff-on-failure + env: + PRE_COMMIT_COLOR: always + - uses: pre-commit-ci/lite-action@v1.0.2 + if: always() + with: + msg: Apply pre-commit code formatting diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 48765f8..34c09e5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,28 +17,30 @@ jobs: fail-fast: false matrix: os: - - ["ubuntu", "ubuntu-20.04"] + - ["ubuntu", "ubuntu-latest"] config: # [Python version, tox env] - - ["3.9", "lint"] - - ["3.7", "py37"] - - ["3.8", "py38"] - - ["3.9", "py39"] - - ["3.10", "py310"] - - ["3.11", "py311"] - - ["3.9", "coverage"] + - ["3.11", "release-check"] + - ["3.8", "py38"] + - ["3.9", "py39"] + - ["3.10", "py310"] + - ["3.11", "py311"] + - ["3.12", "py312"] + - ["3.13", "py313"] + - ["3.11", "coverage"] runs-on: ${{ matrix.os[1] }} if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name name: ${{ matrix.config[1] }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.config[0] }} + allow-prereleases: true - name: Pip cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ matrix.config[0] }}-${{ hashFiles('setup.*', 'tox.ini') }} @@ -50,7 +52,11 @@ jobs: python -m pip install --upgrade pip pip install tox - name: Test + if: ${{ !startsWith(runner.os, 'Mac') }} run: tox -e ${{ matrix.config[1] }} + - name: Test (macOS) + if: ${{ startsWith(runner.os, 'Mac') }} + run: tox -e ${{ matrix.config[1] }}-universal2 - name: Coverage if: matrix.config[1] == 'coverage' run: | diff --git a/.meta.toml b/.meta.toml index c80802d..ede61d3 100644 --- a/.meta.toml +++ b/.meta.toml @@ -2,7 +2,7 @@ # https://github.com/zopefoundation/meta/tree/master/config/pure-python [meta] template = "pure-python" -commit-id = "66322213" +commit-id = "79dc0656" [python] with-sphinx-doctests = false @@ -10,9 +10,7 @@ with-future-python = false with-pypy = false with-macos = false with-windows = false - -[isort] -known_third_party = "docutils, pkg_resources, pytz" +with-docs = false [manifest] additional-rules = [ @@ -20,14 +18,9 @@ additional-rules = [ ] [tox] -use-flake8 = true -testenv-additional = [ - "allowlist_externals =", - ] testenv-deps = [ "zope.testrunner", - "py27: mock", ] [coverage] -fail-under = 91.66 +fail-under = 91.3 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..9f06e98 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,28 @@ +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/pure-python +minimum_pre_commit_version: '3.6' +repos: + - repo: https://github.com/pycqa/isort + rev: "5.13.2" + hooks: + - id: isort + - repo: https://github.com/hhatto/autopep8 + rev: "v2.3.1" + hooks: + - id: autopep8 + args: [--in-place, --aggressive, --aggressive] + - repo: https://github.com/asottile/pyupgrade + rev: v3.19.0 + hooks: + - id: pyupgrade + args: [--py38-plus] + - repo: https://github.com/isidentical/teyit + rev: 0.4.3 + hooks: + - id: teyit + - repo: https://github.com/PyCQA/flake8 + rev: "7.1.1" + hooks: + - id: flake8 + additional_dependencies: + - flake8-debugger == 4.1.2 diff --git a/CHANGES.rst b/CHANGES.rst index 642b4e8..b000c3f 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -6,7 +6,9 @@ Changes 2.1 (unreleased) ================ -- Nothing changed yet. +- Add support for Python 3.12, 3.13. + +- Drop support for Python 3.7. 2.0 (2023-04-05) diff --git a/MANIFEST.in b/MANIFEST.in index 1222801..7a6749c 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -5,6 +5,7 @@ include *.rst include *.txt include buildout.cfg include tox.ini +include .pre-commit-config.yaml recursive-include src *.py recursive-include src *.rst diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..3343cc7 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,21 @@ +# +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/pure-python + +[build-system] +requires = ["setuptools < 74"] +build-backend = "setuptools.build_meta" + +[tool.coverage.run] +branch = true +source = ["zc.relation"] + +[tool.coverage.report] +fail_under = 91.3 +precision = 2 +ignore_errors = true +show_missing = true +exclude_lines = ["pragma: no cover", "pragma: nocover", "except ImportError:", "raise NotImplementedError", "if __name__ == '__main__':", "self.fail", "raise AssertionError", "raise unittest.Skip"] + +[tool.coverage.html] +directory = "parts/htmlcov" diff --git a/setup.cfg b/setup.cfg index d18b07e..064a6fe 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,7 +1,5 @@ # Generated from: # https://github.com/zopefoundation/meta/tree/master/config/pure-python -[bdist_wheel] -universal = 0 [flake8] doctests = 1 diff --git a/setup.py b/setup.py index 32a5965..186de61 100644 --- a/setup.py +++ b/setup.py @@ -45,17 +45,18 @@ def read(path): ]), classifiers=[ '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', + 'Programming Language :: Python :: 3.12', + 'Programming Language :: Python :: 3.13', 'Programming Language :: Python :: Implementation :: CPython', 'License :: OSI Approved :: Zope Public License', ], license='ZPL 2.1', keywords="zope zope3 relation", - python_requires='>=3.7', + python_requires='>=3.8', install_requires=[ 'BTrees', 'zope.interface', diff --git a/src/zc/__init__.py b/src/zc/__init__.py index 2a1d15f..656dc0f 100644 --- a/src/zc/__init__.py +++ b/src/zc/__init__.py @@ -1,20 +1 @@ -############################################################################## -# -# Copyright (c) 2006-2008 Zope Foundation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -# this is a namespace package -try: - import pkg_resources - pkg_resources.declare_namespace(__name__) -except ImportError: - import pkgutil - __path__ = pkgutil.extend_path(__path__, __name__) +__import__('pkg_resources').declare_namespace(__name__) # pragma: no cover diff --git a/src/zc/relation/timeit/manual_intersection.py b/src/zc/relation/timeit/manual_intersection.py index c216271..d6268eb 100644 --- a/src/zc/relation/timeit/manual_intersection.py +++ b/src/zc/relation/timeit/manual_intersection.py @@ -76,17 +76,17 @@ for i, big in enumerate(options): for little in options[:i]: d.append(( - 'manual {} {}'.format(little, big), + f'manual {little} {big}', min(timeit.Timer( manual_template % (little, big), setup).repeat(3, runs)) - control_result)) d.append(( - 'intersect {} {}'.format(little, big), + f'intersect {little} {big}', min(timeit.Timer( intersect_template % (little, big), setup).repeat(3, runs)) - control_result)) d.append(( - 'intersect {} {}'.format(big, little), + f'intersect {big} {little}', min(timeit.Timer( intersect_template % (big, little), setup).repeat(3, runs)) - control_result)) diff --git a/src/zc/relation/timeit/transitive_search_index.py b/src/zc/relation/timeit/transitive_search_index.py index 54e8e04..38c9c23 100644 --- a/src/zc/relation/timeit/transitive_search_index.py +++ b/src/zc/relation/timeit/transitive_search_index.py @@ -297,8 +297,8 @@ def loadRelation(token, index, cache): assert brute == relation == value, '{}: {!r}, {!r}, {!r}'.format( run, brute, relation, value) # end verify - d.append('**** {} ****'.format(run.strip())) - d.append('**** {} ****'.format(brute)) + d.append(f'**** {run.strip()} ****') + d.append(f'**** {brute} ****') if not canfind: # show how long it takes to make the generator altered = run.replace('list(', '', 1) @@ -350,7 +350,7 @@ def loadRelation(token, index, cache): for template in (relations_run_template, value_run_template): for o in (9, 0): run = template % (o,) - d.append('**** {} ****'.format(run.strip())) + d.append(f'**** {run.strip()} ****') d.append(( 'brute', min(timeit.Timer( diff --git a/tox.ini b/tox.ini index 0fafe23..086dfeb 100644 --- a/tox.ini +++ b/tox.ini @@ -3,77 +3,71 @@ [tox] minversion = 3.18 envlist = + release-check lint - py37 py38 py39 py310 py311 + py312 + py313 coverage [testenv] usedevelop = true +package = wheel +wheel_build_env = .pkg deps = + setuptools < 74 zope.testrunner - py27: mock commands = zope-testrunner --test-path=src {posargs:-vc} extras = test -allowlist_externals = -[testenv:lint] +[testenv:setuptools-latest] +basepython = python3 +deps = + git+https://github.com/pypa/setuptools.git\#egg=setuptools + zope.testrunner + +[testenv:release-check] +description = ensure that the distribution is ready to release basepython = python3 skip_install = true -commands = - isort --check-only --diff {toxinidir}/src {toxinidir}/setup.py - flake8 src setup.py - check-manifest - check-python-versions deps = + setuptools < 74 + twine + build check-manifest - check-python-versions >= 0.19.1 + check-python-versions >= 0.20.0 wheel - flake8 - isort +commands_pre = +commands = + check-manifest + check-python-versions --only setup.py,tox.ini,.github/workflows/tests.yml + python -m build --sdist --no-isolation + twine check dist/* -[testenv:isort-apply] +[testenv:lint] +description = This env runs all linters configured in .pre-commit-config.yaml basepython = python3 skip_install = true -commands_pre = deps = - isort + pre-commit +commands_pre = commands = - isort {toxinidir}/src {toxinidir}/setup.py [] + pre-commit run --all-files --show-diff-on-failure [testenv:coverage] basepython = python3 allowlist_externals = mkdir deps = - coverage + coverage[toml] zope.testrunner - py27: mock commands = mkdir -p {toxinidir}/parts/htmlcov coverage run -m zope.testrunner --test-path=src {posargs:-vc} - coverage html --ignore-errors - coverage report --ignore-errors --show-missing --fail-under=91.66 - -[coverage:run] -branch = True -source = zc.relation - -[coverage:report] -precision = 2 -exclude_lines = - pragma: no cover - pragma: nocover - except ImportError: - raise NotImplementedError - if __name__ == '__main__': - self.fail - raise AssertionError - -[coverage:html] -directory = parts/htmlcov + coverage html + coverage report