From 682b65896b9ecacc6bf59aee96d1fcefc4018de5 Mon Sep 17 00:00:00 2001 From: Michael Howitz Date: Thu, 28 Nov 2024 09:24:10 +0100 Subject: [PATCH] Preliminary support for Python 3.14a2. (#335) This means that `.common.builtins.IByteString` and `.common.collections.IByteString` are no longer available from this Python version onwards as Python 3.14 dropped `collections.abc.ByteString`. --------- Co-authored-by: Jens Vagelpohl --- .github/workflows/tests.yml | 21 ++++++++++++++++++- .manylinux-install.sh | 13 +++++++++--- .meta.toml | 4 ++-- CHANGES.rst | 5 +++++ pyproject.toml | 2 +- src/zope/interface/_compat.py | 3 +++ src/zope/interface/common/builtins.py | 20 ++++++++++-------- src/zope/interface/common/collections.py | 16 +++++++------- .../interface/common/tests/test_builtins.py | 13 +++++++++--- src/zope/interface/interface.py | 2 ++ tox.ini | 7 +++++-- 11 files changed, 78 insertions(+), 28 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index dccee042..120e9b7e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -103,6 +103,7 @@ jobs: - "3.11" - "3.12" - "3.13" + - "3.14" os: [ubuntu-latest, macos-latest, windows-latest] exclude: - os: macos-latest @@ -152,10 +153,16 @@ jobs: restore-keys: | ${{ runner.os }}-pip- + - name: Install Build Dependencies (3.14) + if: matrix.python-version == '3.14' + run: | + pip install -U pip + pip install -U "setuptools < 74" wheel twine - name: Install Build Dependencies + if: matrix.python-version != '3.14' run: | pip install -U pip - pip install -U "setuptools <74" wheel twine + pip install -U "setuptools < 74" wheel twine - name: Build zope.interface (macOS x86_64) if: > @@ -193,7 +200,15 @@ jobs: python setup.py build_ext -i python setup.py bdist_wheel + - name: Install zope.interface and dependencies (3.14) + if: matrix.python-version == '3.14' + run: | + # 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 + pip install --pre .[test] - name: Install zope.interface and dependencies + if: matrix.python-version != '3.14' run: | # Install to collect dependencies into the (pip) cache. pip install .[test] @@ -236,6 +251,7 @@ jobs: && startsWith(github.ref, 'refs/tags') && !startsWith(runner.os, 'Linux') && !startsWith(matrix.python-version, 'pypy') + && !startsWith(matrix.python-version, '3.14') env: TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }} run: | @@ -255,6 +271,7 @@ jobs: - "3.11" - "3.12" - "3.13" + - "3.14" os: [ubuntu-latest, macos-latest, windows-latest] exclude: - os: macos-latest @@ -507,6 +524,8 @@ jobs: name: manylinux_${{ matrix.image }}_wheels.zip - name: Restore pip cache permissions run: sudo chown -R $(whoami) ${{ steps.pip-cache-default.outputs.dir }} + - name: Prevent publishing wheels for unreleased Python versions + run: VER=$(echo '3.14' | tr -d .) && ls -al wheelhouse && sudo rm -f wheelhouse/*-cp${VER}*.whl && ls -al wheelhouse - name: Publish package to PyPI uses: pypa/gh-action-pypi-publish@release/v1 if: > diff --git a/.manylinux-install.sh b/.manylinux-install.sh index 7efbd2ed..7a338397 100755 --- a/.manylinux-install.sh +++ b/.manylinux-install.sh @@ -34,6 +34,7 @@ tox_env_map() { *"cp311"*) echo 'py311';; *"cp312"*) echo 'py312';; *"cp313"*) echo 'py313';; + *"cp314"*) echo 'py314';; *) echo 'py';; esac } @@ -46,9 +47,15 @@ for PYBIN in /opt/python/*/bin; do [[ "${PYBIN}" == *"cp310/"* ]] || \ [[ "${PYBIN}" == *"cp311/"* ]] || \ [[ "${PYBIN}" == *"cp312/"* ]] || \ - [[ "${PYBIN}" == *"cp313/"* ]] ; then - "${PYBIN}/pip" install -e /io/ - "${PYBIN}/pip" wheel /io/ -w wheelhouse/ + [[ "${PYBIN}" == *"cp313/"* ]] || \ + [[ "${PYBIN}" == *"cp314/"* ]] ; then + if [[ "${PYBIN}" == *"cp314/"* ]] ; 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 if [ `uname -m` == 'aarch64' ]; then cd /io/ ${PYBIN}/pip install tox diff --git a/.meta.toml b/.meta.toml index 67fe6188..3fe4302d 100644 --- a/.meta.toml +++ b/.meta.toml @@ -2,13 +2,13 @@ # https://github.com/zopefoundation/meta/tree/master/config/c-code [meta] template = "c-code" -commit-id = "85622de1" +commit-id = "baf6089f" [python] with-pypy = true with-sphinx-doctests = true with-windows = true -with-future-python = false +with-future-python = true with-docs = true with-macos = false diff --git a/CHANGES.rst b/CHANGES.rst index 31355bbd..87afbc6e 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,11 @@ 7.1.2 (unreleased) ================== +- Add preliminary support for Python 3.14a2, this means that + ``.common.builtins.IByteString`` and ``.common.collections.IByteString`` are + no longer available from this Python version onwards as Python 3.14 dropped + ``collections.abc.ByteString``. + 7.1.1 (2024-10-23) ================== diff --git a/pyproject.toml b/pyproject.toml index 17da486f..c787aa9e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ # https://github.com/zopefoundation/meta/tree/master/config/c-code [build-system] -requires = ["setuptools<74"] +requires = ["setuptools < 74"] build-backend = "setuptools.build_meta" [tool.coverage.run] diff --git a/src/zope/interface/_compat.py b/src/zope/interface/_compat.py index bc3f8671..38032953 100644 --- a/src/zope/interface/_compat.py +++ b/src/zope/interface/_compat.py @@ -22,6 +22,9 @@ import sys +PY313_OR_OLDER = sys.version_info < (3, 14) + + def _normalize_name(name): if isinstance(name, bytes): name = str(name, 'ascii') diff --git a/src/zope/interface/common/builtins.py b/src/zope/interface/common/builtins.py index 09de5b3b..9e543c83 100644 --- a/src/zope/interface/common/builtins.py +++ b/src/zope/interface/common/builtins.py @@ -19,6 +19,7 @@ """ from zope.interface import classImplements +from zope.interface._compat import PY313_OR_OLDER from zope.interface.common import collections from zope.interface.common import io from zope.interface.common import numbers @@ -67,17 +68,18 @@ class ITextString(collections.ISequence): extra_classes = (str,) -class IByteString(collections.IByteString): - """ - Interface for immutable byte strings. +if PY313_OR_OLDER: + class IByteString(collections.IByteString): + """ + Interface for immutable byte strings. - On all Python versions this is :class:`bytes`. + On all Python versions this is :class:`bytes`. - Unlike :class:`zope.interface.common.collections.IByteString` - (the parent of this interface) this does *not* include - :class:`bytearray`. - """ - extra_classes = (bytes,) + Unlike :class:`zope.interface.common.collections.IByteString` + (the parent of this interface) this does *not* include + :class:`bytearray`. + """ + extra_classes = (bytes,) class INativeString(ITextString): diff --git a/src/zope/interface/common/collections.py b/src/zope/interface/common/collections.py index 543266d9..defa8a15 100644 --- a/src/zope/interface/common/collections.py +++ b/src/zope/interface/common/collections.py @@ -38,6 +38,7 @@ from collections import UserString from collections import abc +from zope.interface._compat import PY313_OR_OLDER from zope.interface.common import ABCInterface from zope.interface.common import optional @@ -190,13 +191,14 @@ class IMutableSequence(ISequence): extra_classes = (UserList,) -class IByteString(ISequence): - """ - This unifies `bytes` and `bytearray`. - """ - abc = _new_in_ver( - 'ByteString', True, (ISequence.getABC(),), (bytes, bytearray), - ) +if PY313_OR_OLDER: + class IByteString(ISequence): + """ + This unifies `bytes` and `bytearray`. + """ + abc = _new_in_ver( + 'ByteString', True, (ISequence.getABC(),), (bytes, bytearray), + ) class ISet(ICollection): diff --git a/src/zope/interface/common/tests/test_builtins.py b/src/zope/interface/common/tests/test_builtins.py index cf7019bf..3c764392 100644 --- a/src/zope/interface/common/tests/test_builtins.py +++ b/src/zope/interface/common/tests/test_builtins.py @@ -12,6 +12,7 @@ import unittest +from zope.interface._compat import PY313_OR_OLDER from zope.interface.common import builtins from . import VerifyClassMixin @@ -24,16 +25,22 @@ class TestVerifyClass(VerifyClassMixin, pass -add_verify_tests(TestVerifyClass, ( +VERIFY_TESTS = [ (builtins.IList, (list,)), (builtins.ITuple, (tuple,)), (builtins.ITextString, (str,)), - (builtins.IByteString, (bytes,)), (builtins.INativeString, (str,)), (builtins.IBool, (bool,)), (builtins.IDict, (dict,)), (builtins.IFile, ()), -)) + +] +if PY313_OR_OLDER: + VERIFY_TESTS.append( + (builtins.IByteString, (bytes,)) + ) + +add_verify_tests(TestVerifyClass, tuple(VERIFY_TESTS)) class TestVerifyObject(VerifyObjectMixin, diff --git a/src/zope/interface/interface.py b/src/zope/interface/interface.py index e5dddb88..ad8a7de6 100644 --- a/src/zope/interface/interface.py +++ b/src/zope/interface/interface.py @@ -825,6 +825,8 @@ def update_value(aname, aval): # __firstlineno__: Python 3.13b1+ # https://github.com/python/cpython/pull/118475 '__firstlineno__', + # __classdictcell__: Python 3.14 + '__classdictcell__', ) and aval is not _decorator_non_return # noqa W503 } diff --git a/tox.ini b/tox.ini index ed7830b5..1a686364 100644 --- a/tox.ini +++ b/tox.ini @@ -10,13 +10,16 @@ envlist = py311,py311-pure py312,py312-pure py313,py313-pure + py314,py314-pure pypy3 docs coverage [testenv] +pip_pre = py314: true deps = - setuptools <74 + setuptools < 74 + Sphinx setenv = pure: PURE_PYTHON=1 !pure-!pypy3: PURE_PYTHON=0 @@ -55,7 +58,7 @@ description = ensure that the distribution is ready to release basepython = python3 skip_install = true deps = - setuptools <74 + setuptools < 74 twine build check-manifest