From e78100fcc3e4f453990a0da27586af65e9cd0be8 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 15 Oct 2026 06:46:07 +0000 Subject: [PATCH 1/4] Drop support for Python 3.10. --- CHANGES.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 36153f4..4b541ea 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -7,6 +7,8 @@ For changes before version 3.0, see ``HISTORY.rst``. ---------------- +- Drop support for Python 3.10. + 7.5 (2026-08-20) ---------------- From 300b01b95eb757cb38019a935d306bdce6b19eab Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 15 Oct 2026 06:46:07 +0000 Subject: [PATCH 2/4] Add support for Python 3.15. --- CHANGES.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 4b541ea..b9ba16a 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -7,6 +7,8 @@ For changes before version 3.0, see ``HISTORY.rst``. ---------------- +- Add support for Python 3.15. + - Drop support for Python 3.10. 7.5 (2026-08-20) From 0bc500ee6ac5001d4d146fa12b25bb0b7ae63f5a Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 15 Oct 2026 06:46:08 +0000 Subject: [PATCH 3/4] Configuring for c-code --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/tests.yml | 66 +------------------------------- .gitignore | 1 + .manylinux-install.sh | 13 ++----- .meta.toml | 2 +- .pre-commit-config.yaml | 2 +- pyproject.toml | 30 +++++++-------- tox.ini | 2 - 8 files changed, 23 insertions(+), 95 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 136dce6..78609a5 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -30,7 +30,7 @@ jobs: extra_args: --all-files --show-diff-on-failure env: PRE_COMMIT_COLOR: always - - uses: pre-commit-ci/lite-action@5d6cc0eb514c891a40562a58a8e71576c5c7fb43 #v1.1.0 + - uses: pre-commit-ci/lite-action@062bca0919bc9d6e66755cc05074b70c77e111fc #v1.2.0 if: always() with: msg: Apply pre-commit code formatting diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c2dd52d..22f0aa3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -95,16 +95,12 @@ jobs: fail-fast: false matrix: python-version: - - "3.10" - "3.11" - "3.12" - "3.13" - "3.14" - "3.15" os: [ubuntu-latest, macos-latest, windows-latest, windows-11-arm] - exclude: - - os: windows-11-arm - python-version: "3.10" steps: - name: checkout @@ -133,19 +129,7 @@ jobs: path: ${{ steps.pip-cache.outputs.dir }} key: ${{ runner.os }}-${{ runner.arch }}-pip-${{ matrix.python-version }} - - name: Install Build Dependencies (3.15) - if: startsWith(matrix.python-version, '3.15') - run: | - # PyPI downloads are occasionally cut off mid-transfer, which makes - # pip fail with ``IncompleteRead``. pip does not retry a truncated - # download, so retry the complete command. Purge pip's cache before - # the last attempt: should a truncated download ever get *cached*, - # it would fail every attempt in the same way. - retry() { for i in 1 2; do "$@" && return 0; echo "Attempt $i failed, retrying in 15s ..."; sleep 15; done; pip cache purge || true; "$@"; } - retry python -m pip install -U pip - retry pip install -U "setuptools >= 78.1.1,< 82" wheel twine cffi pycparser - name: Install Build Dependencies - if: ${{ !startsWith(matrix.python-version, '3.15') }} run: | # PyPI downloads are occasionally cut off mid-transfer, which makes # pip fail with ``IncompleteRead``. pip does not retry a truncated @@ -195,25 +179,11 @@ jobs: - name: Create AccessControl sdist if: > startsWith(runner.os, 'Linux') - && matrix.python-version == '3.14' + && matrix.python-version == '3.15' run: | python setup.py sdist - - name: Install AccessControl and dependencies (3.15) - if: startsWith(matrix.python-version, '3.15') - run: | - # PyPI downloads are occasionally cut off mid-transfer, which makes - # pip fail with ``IncompleteRead``. pip does not retry a truncated - # download, so retry the complete command. Purge pip's cache before - # the last attempt: should a truncated download ever get *cached*, - # it would fail every attempt in the same way. - retry() { for i in 1 2; do "$@" && return 0; echo "Attempt $i failed, retrying in 15s ..."; sleep 15; done; pip cache purge || true; "$@"; } - # Install to collect dependencies into the (pip) cache. - # Use "--pre" here because dependencies with support for this future - # Python release may only be available as pre-releases - retry pip install --pre .[test] - name: Install AccessControl and dependencies - if: ${{ !startsWith(matrix.python-version, '3.15') }} run: | # PyPI downloads are occasionally cut off mid-transfer, which makes # pip fail with ``IncompleteRead``. pip does not retry a truncated @@ -264,7 +234,7 @@ jobs: - name: Upload AccessControl sdist if: > startsWith(runner.os, 'Linux') - && matrix.python-version == '3.14' + && matrix.python-version == '3.15' uses: actions/upload-artifact@v7 with: name: AccessControl.tar.gz @@ -277,16 +247,12 @@ jobs: fail-fast: false matrix: python-version: - - "3.10" - "3.11" - "3.12" - "3.13" - "3.14" - "3.15" os: [ubuntu-latest, macos-latest, windows-latest, windows-11-arm] - exclude: - - os: windows-11-arm - python-version: "3.10" steps: - name: checkout @@ -327,29 +293,7 @@ jobs: with: name: AccessControl-${{ runner.os }}-${{ matrix.python-version }}-${{ runner.arch }}.whl path: dist/ - - name: Install AccessControl ${{ matrix.python-version }} - if: startsWith(matrix.python-version, '3.15') - run: | - # PyPI downloads are occasionally cut off mid-transfer, which makes - # pip fail with ``IncompleteRead``. pip does not retry a truncated - # download, so retry the complete command. Purge pip's cache before - # the last attempt: should a truncated download ever get *cached*, - # it would fail every attempt in the same way. - retry() { for i in 1 2; do "$@" && return 0; echo "Attempt $i failed, retrying in 15s ..."; sleep 15; done; pip cache purge || true; "$@"; } - retry pip install -U wheel "setuptools >= 78.1.1,< 82" - # coverage might have a wheel on PyPI for a future python version which is - # not ABI compatible with the current one, so build it from sdist: - retry pip install -U --no-binary :all: coverage[toml] - # Unzip into src/ so that testrunner can find the .so files - # when we ask it to load tests from that directory. This - # might also save some build time? - ls -l dist/ - unzip -n dist/*.whl -d src - # Use "--pre" here because dependencies with support for this future - # Python release may only be available as pre-releases - retry pip install --pre -e .[test] - name: Install AccessControl - if: ${{ !startsWith(matrix.python-version, '3.15') }} run: | # PyPI downloads are occasionally cut off mid-transfer, which makes # pip fail with ``IncompleteRead``. pip does not retry a truncated @@ -524,9 +468,6 @@ jobs: - name: Restore pip cache permissions run: sudo chown -R $(whoami) ${{ steps.pip-cache.outputs.dir }} - - name: Prevent publishing wheels for unreleased Python versions - run: VER=$(echo '3.15' | tr -d .) && ls -al wheelhouse && sudo rm -f wheelhouse/*-cp${VER}*.whl && ls -al wheelhouse - publish: name: Publish to PyPI runs-on: ubuntu-latest @@ -560,9 +501,6 @@ jobs: # PyPy wheels shouldn't be uploaded, remove them if present find dist/ -name "*pypy*" -type f -delete || true find dist/ -name "*none-any*" -type f -delete || true - # Wheels for the not-yet-supported future Python version need to go - find dist/ -name "*3.15*" -type f -delete || true - find dist/ -name "*cp315*" -type f -delete || true # For Linux, we only want the manylinux wheels find dist/ -name "*linux_x86_64*" -type f -delete || true diff --git a/.gitignore b/.gitignore index c9557a8..a4a38a1 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ .installed.cfg .mr.developer.cfg .tox/ +.venv .vscode/ __pycache__/ bin/ diff --git a/.manylinux-install.sh b/.manylinux-install.sh index df1a5e1..d656661 100755 --- a/.manylinux-install.sh +++ b/.manylinux-install.sh @@ -28,7 +28,6 @@ yum -y install libffi-devel tox_env_map() { case $1 in - *"cp310"*) echo 'py310';; *"cp311"*) echo 'py311';; *"cp312"*) echo 'py312';; *"cp313"*) echo 'py313';; @@ -41,19 +40,13 @@ tox_env_map() { # Compile wheels for PYBIN in /opt/python/*/bin; do if \ - [[ "${PYBIN}" == *"cp310/"* ]] || \ [[ "${PYBIN}" == *"cp311/"* ]] || \ [[ "${PYBIN}" == *"cp312/"* ]] || \ [[ "${PYBIN}" == *"cp313/"* ]] || \ [[ "${PYBIN}" == *"cp314/"* ]] || \ - [[ "${PYBIN}" == *"cp315/"* ]] ; then - if [[ "${PYBIN}" == *"cp315/"* ]] ; then - "${PYBIN}/pip" install --pre -e /io/ - "${PYBIN}/pip" wheel /io/ --pre -w wheelhouse/ - else - "${PYBIN}/pip" install -e /io/ - "${PYBIN}/pip" wheel /io/ -w wheelhouse/ - fi + [[ "${PYBIN}" == *"cp315/"* ]] ; then + "${PYBIN}/pip" install -e /io/ + "${PYBIN}/pip" wheel /io/ -w wheelhouse/ if [ `uname -m` == 'aarch64' ]; then cd /io/ ${PYBIN}/pip install tox diff --git a/.meta.toml b/.meta.toml index d15d904..bd9844e 100644 --- a/.meta.toml +++ b/.meta.toml @@ -2,7 +2,7 @@ # https://github.com/zopefoundation/meta/tree/master/src/zope/meta/c-code [meta] template = "c-code" -commit-id = "7cab96bb" +commit-id = "f63da99d" [python] with-windows = true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fd0f5d8..ffee6a1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,7 +24,7 @@ repos: rev: v3.21.2 hooks: - id: pyupgrade - args: [--py310-plus] + args: [--py311-plus] - repo: https://github.com/isidentical/teyit rev: 0.4.3 hooks: diff --git a/pyproject.toml b/pyproject.toml index 03b3930..ce2b2ec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,7 @@ version = "7.6.dev0" description = "Security framework for Zope" keywords = ["security", "access", "authorization"] dynamic = ["readme"] -requires-python = ">=3.10" +requires-python = ">=3.11" license = "ZPL-2.1" authors = [ { name = "Zope Foundation and contributors", email = "zope-dev@zope.dev" }, @@ -22,21 +22,19 @@ maintainers = [ { name = "Plone Foundation and contributors", email = "zope-dev@zope.dev" }, ] classifiers = [ - "Development Status :: 6 - Mature", - "Environment :: Web Environment", - "Framework :: Zope", - "Framework :: Zope :: 5", - "Operating System :: OS Independent", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: 3.14", - "Programming Language :: Python :: 3.15", - "Programming Language :: Python :: Implementation :: CPython", + "Development Status :: 6 - Mature", + "Environment :: Web Environment", + "Framework :: Zope", + "Framework :: Zope :: 5", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: 3.15", + "Programming Language :: Python :: Implementation :: CPython", ] dependencies = [ "Acquisition", diff --git a/tox.ini b/tox.ini index 9042f33..6713227 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,6 @@ minversion = 4.0 envlist = release-check lint - py310,py310-pure py311,py311-pure py312,py312-pure py313,py313-pure @@ -14,7 +13,6 @@ envlist = coverage [testenv] -pip_pre = py315: true deps = setuptools >= 78.1.1,< 82 setenv = From ff54003e30c18880e6a45e7e91e296a45a6896a1 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 15 Oct 2026 06:46:37 +0000 Subject: [PATCH 4/4] Update Python version support. --- src/AccessControl/tests/actual_python.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AccessControl/tests/actual_python.py b/src/AccessControl/tests/actual_python.py index 866a480..3d7879e 100644 --- a/src/AccessControl/tests/actual_python.py +++ b/src/AccessControl/tests/actual_python.py @@ -127,9 +127,9 @@ def f7(): iter_ = access() # iterate twice on the same view assert list(iter_) == list(iter_) - assert sorted([k for k in getattr(d, meth)()]) == expected[kind] + assert sorted([*getattr(d, meth)()]) == expected[kind] assert sorted(k for k in getattr(d, meth)()) == expected[kind] - assert {k: v for k, v in d.items()} == d + assert {**d} == d assert 1 in d assert 1 in d.keys()