Repository: zopefoundation/Zope (language: python)

Issue:
Python 3.13 support release blockers
Before declaring official support for Python 3.13 the following issues have to be resolved and releases published afterwards:

- [x] https://github.com/zopefoundation/RestrictedPython/issues/264
- [x] https://github.com/zopefoundation/AccessControl/pull/156
- [x] https://github.com/zopefoundation/zope.interface/pull/322 - strange test failures and incompatibilites between local and GHA runs
- [x] https://github.com/zopefoundation/Zope/pull/1215 – collect all the new releases
- [x] https://github.com/zopefoundation/zope.testrunner/issues/155
- [x] https://github.com/zopefoundation/persistent/pull/188 – requires a `cffi` release
- [x] https://github.com/zopefoundation/zope.interface/issues/279 – currently also blocked by `cffi`
- [x] https://github.com/zopefoundation/Acquisition/pull/68 – test failures
- [x] https://github.com/zopefoundation/AccessControl/pull/143 – cannot be build without Acquisition fixed first
- [x] https://github.com/zopefoundation/zodbpickle/pull/81 – segfault in tests
- [x] https://github.com/zopefoundation/zope.security/pull/104 – segfault in tests
- [x] https://github.com/zopefoundation/zope.security/pull/105 Wheel does not build on MacOS
- [x] https://github.com/zopefoundation/BTrees/pull/202
- [x] https://github.com/zopefoundation/AccessControl/pull/154
- [x] https://github.com/zopefoundation/zope.security/pull/110
- [x] https://github.com/zopefoundation/zodbpickle/pull/83 Compilation errors in C code
- [x] https://github.com/zopefoundation/zope.container/pull/53
- [x] https://github.com/zopefoundation/ZConfig/pull/97 test failure
- [x] ~~https://github.com/zopefoundation/zope.testrunner/issues/167 test failures~~ The fact that the zope.testrunner tests themselves fail on Python 3.13 is not a release blocker for Zope's Python 3.13 support if Zope's own tests run fine on Python 3.13.


Discussion / hints:

Fix patch:
diff --git a/.meta.toml b/.meta.toml
index 7c5b7b9370..5036989b5d 100644
--- a/.meta.toml
+++ b/.meta.toml
@@ -2,7 +2,7 @@
 # https://github.com/zopefoundation/meta/tree/master/config/zope-product
 [meta]
 template = "zope-product"
-commit-id = "15e6a5a9"
+commit-id = "210c1a0c"
 
 [python]
 with-pypy = false
@@ -10,10 +10,10 @@ with-docs = true
 with-sphinx-doctests = false
 with-windows = true
 with-macos = true
-with-future-python = true
+with-future-python = false
 
 [coverage]
-fail-under = 80
+fail-under = 82
 
 [coverage-run]
 source = "src"
diff --git a/CHANGES.rst b/CHANGES.rst
index 2d2b8e6ed4..5b4801a85f 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -10,6 +10,8 @@ https://github.com/zopefoundation/Zope/blob/4.x/CHANGES.rst
 5.11 (unreleased)
 -----------------
 
+- Add support for Python 3.13.
+
 - Drop support for Python 3.7.
 
 - Update to newest compatible versions of dependencies.
diff --git a/constraints.txt b/constraints.txt
index 8df0a2970e..2725ef890d 100644
--- a/constraints.txt
+++ b/constraints.txt
@@ -1,45 +1,40 @@
-AccessControl==7.0
-Acquisition==6.0
+AccessControl==7.1
+Acquisition==6.1
 AuthEncoding==5.0
-BTrees==6.0
+BTrees==6.1
 Chameleon==4.4.4; python_version == '3.8'
 Chameleon==4.4.4; python_version > '3.8'
 DateTime==5.5
 DocumentTemplate==4.6
-ExtensionClass==5.1
+ExtensionClass==6.0
 MultiMapping==5.0
 Paste==3.10.1
 PasteDeploy==3.1.0
-Persistence==5.0
-RestrictedPython==7.2; python_version == '3.10'
-RestrictedPython==7.2; python_version == '3.11'
-RestrictedPython==7.2; python_version == '3.12'
-RestrictedPython==7.2; python_version == '3.8'
-RestrictedPython==7.2; python_version == '3.9'
-RestrictedPython==7.2a1.dev0; python_version > '3.12'
+Persistence==5.1
+RestrictedPython==7.4
 WSGIProxy2==0.5.1
-WebOb==1.8.7
-WebTest==3.0.0
+WebOb==1.8.8
+WebTest==3.0.1
 ZConfig==4.1
 ZODB==6.0
 Zope2==4.0
 beautifulsoup4==4.12.3
-cffi==1.17.0
+cffi==1.17.1
 multipart==0.2.5
-persistent==6.0
+persistent==6.1
 pycparser==2.22
 python-gettext==5.0
-pytz==2024.1
+pytz==2024.2
 roman==4.2
 six==1.16.0
-soupsieve==2.5
-transaction==4.0
+soupsieve==2.6
+transaction==5.0
 waitress==3.0.0
 z3c.pt==4.4
 zExceptions==5.0
 zc.lockfile==3.0.post1
 zc.recipe.egg==2.0.7
-zodbpickle==4.0
+zodbpickle==4.1.1
 zope.annotation==5.0
 zope.browser==3.0
 zope.browsermenu==5.0
@@ -48,7 +43,7 @@ zope.browserresource==5.1
 zope.cachedescriptors==5.0
 zope.component==6.0
 zope.configuration==5.0.1
-zope.container==6.0
+zope.container==6.1
 zope.contentprovider==6.0
 zope.contenttype==5.1
 zope.datetime==5.0.0
@@ -59,19 +54,19 @@ zope.event==5.0
 zope.exceptions==5.1
 zope.filerepresentation==6.0
 zope.globalrequest==2.0
-zope.hookable==6.0
-zope.i18n==5.1
-zope.i18nmessageid==6.1.0
-zope.interface==6.4.post2
+zope.hookable==7.0
+zope.i18n==5.2
+zope.i18nmessageid==7.0
+zope.interface==7.1.0
 zope.lifecycleevent==5.0
 zope.location==5.0
 zope.pagetemplate==5.1
 zope.processlifetime==3.0
-zope.proxy==5.3
+zope.proxy==6.1
 zope.ptresource==5.0
-zope.publisher==7.0
+zope.publisher==7.1
 zope.schema==7.0.1
-zope.security==7.0
+zope.security==7.3
 zope.sequencesort==5.0
 zope.site==5.0
 zope.size==5.0
diff --git a/docs/INSTALL.rst b/docs/INSTALL.rst
index 510c6c3b17..204401c84a 100644
--- a/docs/INSTALL.rst
+++ b/docs/INSTALL.rst
@@ -12,7 +12,7 @@ available:
 
 - A supported version of Python, including the development support if
   installed from system-level packages.  Supported versions include
-  **3.8** up to **3.12**.
+  **3.8** up to **3.13**.
 
 - Zope needs the Python ``zlib`` module to be importable.  If you are
   building your own Python from source, please be sure that you have the
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000000..5a0b170000
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,21 @@
+# 
+# Generated from:
+# https://github.com/zopefoundation/meta/tree/master/config/zope-product
+
+[build-system]
+requires = ["setuptools < 74"]
+build-backend = "setuptools.build_meta"
+
+[tool.coverage.run]
+branch = true
+source = ["src"]
+
+[tool.coverage.report]
+fail_under = 82
+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/requirements-full.txt b/requirements-full.txt
index 69220da131..b964ef58f9 100644
--- a/requirements-full.txt
+++ b/requirements-full.txt
@@ -1,46 +1,41 @@
 -e git+https://github.com/zopefoundation/Zope.git@master#egg=Zope
-AccessControl==7.0
-Acquisition==6.0
+AccessControl==7.1
+Acquisition==6.1
 AuthEncoding==5.0
-BTrees==6.0
+BTrees==6.1
 Chameleon==4.4.4; python_version == '3.8'
 Chameleon==4.4.4; python_version > '3.8'
 DateTime==5.5
 DocumentTemplate==4.6
-ExtensionClass==5.1
+ExtensionClass==6.0
 MultiMapping==5.0
 Paste==3.10.1
 PasteDeploy==3.1.0
-Persistence==5.0
-RestrictedPython==7.2; python_version == '3.10'
-RestrictedPython==7.2; python_version == '3.11'
-RestrictedPython==7.2; python_version == '3.12'
-RestrictedPython==7.2; python_version == '3.8'
-RestrictedPython==7.2; python_version == '3.9'
-RestrictedPython==7.2a1.dev0; python_version > '3.12'
+Persistence==5.1
+RestrictedPython==7.4
 WSGIProxy2==0.5.1
-WebOb==1.8.7
-WebTest==3.0.0
+WebOb==1.8.8
+WebTest==3.0.1
 ZConfig==4.1
 ZODB==6.0
 Zope2==4.0
 beautifulsoup4==4.12.3
-cffi==1.17.0
+cffi==1.17.1
 multipart==0.2.5
-persistent==6.0
+persistent==6.1
 pycparser==2.22
 python-gettext==5.0
-pytz==2024.1
+pytz==2024.2
 roman==4.2
 six==1.16.0
-soupsieve==2.5
-transaction==4.0
+soupsieve==2.6
+transaction==5.0
 waitress==3.0.0
 z3c.pt==4.4
 zExceptions==5.0
 zc.lockfile==3.0.post1
 zc.recipe.egg==2.0.7
-zodbpickle==4.0
+zodbpickle==4.1.1
 zope.annotation==5.0
 zope.browser==3.0
 zope.browsermenu==5.0
@@ -49,7 +44,7 @@ zope.browserresource==5.1
 zope.cachedescriptors==5.0
 zope.component==6.0
 zope.configuration==5.0.1
-zope.container==6.0
+zope.container==6.1
 zope.contentprovider==6.0
 zope.contenttype==5.1
 zope.datetime==5.0.0
@@ -60,19 +55,19 @@ zope.event==5.0
 zope.exceptions==5.1
 zope.filerepresentation==6.0
 zope.globalrequest==2.0
-zope.hookable==6.0
-zope.i18n==5.1
-zope.i18nmessageid==6.1.0
-zope.interface==6.4.post2
+zope.hookable==7.0
+zope.i18n==5.2
+zope.i18nmessageid==7.0
+zope.interface==7.1.0
 zope.lifecycleevent==5.0
 zope.location==5.0
 zope.pagetemplate==5.1
 zope.processlifetime==3.0
-zope.proxy==5.3
+zope.proxy==6.1
 zope.ptresource==5.0
-zope.publisher==7.0
+zope.publisher==7.1
 zope.schema==7.0.1
-zope.security==7.0
+zope.security==7.3
 zope.sequencesort==5.0
 zope.site==5.0
 zope.size==5.0
diff --git a/setup.py b/setup.py
index f254e257b0..be2627a07c 100644
--- a/setup.py
+++ b/setup.py
@@ -45,6 +45,7 @@ def _read_file(filename):
     author='Zope Foundation and Contributors',
     author_email='zope-dev@zope.dev',
     long_description="\n\n".join([README, CHANGES]),
+    long_description_content_type='text/x-rst',
     classifiers=[
         "Development Status :: 6 - Mature",
         "Environment :: Web Environment",
@@ -58,6 +59,7 @@ def _read_file(filename):
         "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",
         "Topic :: Internet :: WWW/HTTP :: Dynamic Content",
         "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
diff --git a/tox.ini b/tox.ini
index 495aae31f0..4a4eadaa1a 100644
--- a/tox.ini
+++ b/tox.ini
@@ -37,8 +37,6 @@ deps =
     universal2: MarkupSafe
     universal2: zope.testrunner
 setenv =
-    py312: VIRTUALENV_PIP=23.1.2
-    py312: PIP_REQUIRE_VIRTUALENV=0
 commands_pre =
     {envbindir}/buildout -c {toxinidir}/buildout.cfg buildout:directory={envdir} buildout:develop={toxinidir} buildout:root-directory={toxinidir}
 commands =
@@ -50,12 +48,36 @@ commands =
     !universal2: {envdir}/bin/alltests --layer '!Products.PluginIndexes' {posargs:-vc}
 allowlist_externals = *
 
+[testenv:setuptools-latest]
+basepython = python3
+deps =
+    git+https://github.com/pypa/setuptools.git\#egg=setuptools
+    zc.buildout >= 3.1
+    wheel > 0.37
+    cffi >= 1.17.0rc1
+    # The universal2 environment is for Python on macOS built with
+    # universal2 mode instead of architecture-specific. These dependencies
+    # must be installed separately, zc.buildout is incompatible with the
+    # universal2 mode and cannot install them itself.
+    universal2: -c {toxinidir}/constraints.txt
+    universal2: zope.interface
+    universal2: zope.security
+    universal2: zope.container
+    universal2: Persistence
+    universal2: Acquisition
+    universal2: AccessControl
+    universal2: zodbpickle
+    universal2: charset_normalizer
+    universal2: MarkupSafe
+    universal2: zope.testrunner
+
 
 [testenv:release-check]
 description = ensure that the distribution is ready to release
 basepython = python3
 skip_install = true
 deps =
+    setuptools < 74
     twine
     build
     check-manifest
@@ -95,28 +117,9 @@ allowlist_externals =
     mkdir
 deps =
     {[testenv]deps}
-    coverage
+    coverage[toml]
 commands =
     mkdir -p {toxinidir}/parts/htmlcov
     coverage run {envdir}/bin/alltests {posargs:-vc}
     coverage html
-    coverage report -m --fail-under=80
-
-[coverage:run]
-branch = True
-source = src
-
-[coverage:report]
-precision = 2
-ignore_errors = True
-exclude_lines =
-    pragma: no cover
-    pragma: nocover
-    except ImportError:
-    raise NotImplementedError
-    if __name__ == '__main__':
-    self.fail
-    raise AssertionError
-
-[coverage:html]
-directory = parts/htmlcov
+    coverage report
diff --git a/versions-prod.cfg b/versions-prod.cfg
index 491a165f9f..eee47a631b 100644
--- a/versions-prod.cfg
+++ b/versions-prod.cfg
@@ -4,41 +4,41 @@
 [versions]
 Zope =
 Zope2 = 4.0
-AccessControl = 7.0
-Acquisition = 6.0
+AccessControl = 7.1
+Acquisition = 6.1
 AuthEncoding = 5.0
-BTrees = 6.0
+BTrees = 6.1
 Chameleon = 4.4.4
 DateTime = 5.5
 DocumentTemplate = 4.6
-ExtensionClass = 5.1
+ExtensionClass = 6.0
 MultiMapping = 5.0
 Paste = 3.10.1
 PasteDeploy = 3.1.0
-Persistence = 5.0
-RestrictedPython = 7.2a1.dev0
-WebTest = 3.0.0
+Persistence = 5.1
+RestrictedPython = 7.4
+WebTest = 3.0.1
 WSGIProxy2 = 0.5.1
-WebOb = 1.8.7
+WebOb = 1.8.8
 ZConfig = 4.1
 ZODB = 6.0
 beautifulsoup4 = 4.12.3
-cffi = 1.17.0
+cffi = 1.17.1
 multipart = 0.2.5
-persistent = 6.0
+persistent = 6.1
 pycparser = 2.22
 python-gettext = 5.0
-pytz = 2024.1
+pytz = 2024.2
 six = 1.16.0
 roman = 4.2
-soupsieve = 2.5
-transaction = 4.0
+soupsieve = 2.6
+transaction = 5.0
 waitress = 3.0.0
 z3c.pt = 4.4
 zExceptions = 5.0
 zc.lockfile = 3.0.post1
 zc.recipe.egg = 2.0.7
-zodbpickle = 4.0
+zodbpickle = 4.1.1
 zope.annotation = 5.0
 zope.browser = 3.0
 zope.browsermenu = 5.0
@@ -47,7 +47,7 @@ zope.browserresource = 5.1
 zope.cachedescriptors = 5.0
 zope.component = 6.0
 zope.configuration = 5.0.1
-zope.container = 6.0
+zope.container = 6.1
 zope.contentprovider = 6.0
 zope.contenttype = 5.1
 zope.datetime = 5.0.0
@@ -58,19 +58,19 @@ zope.event = 5.0
 zope.exceptions = 5.1
 zope.filerepresentation = 6.0
 zope.globalrequest = 2.0
-zope.hookable = 6.0
-zope.i18n = 5.1
-zope.i18nmessageid = 6.1.0
-zope.interface = 6.4.post2
+zope.hookable = 7.0
+zope.i18n = 5.2
+zope.i18nmessageid = 7.0
+zope.interface = 7.1.0
 zope.lifecycleevent = 5.0
 zope.location = 5.0
 zope.pagetemplate = 5.1
 zope.processlifetime = 3.0
-zope.proxy = 5.3
+zope.proxy = 6.1
 zope.ptresource = 5.0
-zope.publisher = 7.0
+zope.publisher = 7.1
 zope.schema = 7.0.1
-zope.security = 7.0
+zope.security = 7.3
 zope.sequencesort = 5.0
 zope.site = 5.0
 zope.size = 5.0
@@ -85,21 +85,3 @@ zope.viewlet = 5.0
 [versions:python38]
 # Chameleon >= 4.5 requires Python 3.9
 Chameleon = 4.4.4
-# Use newest final release
-RestrictedPython = 7.2
-
-[versions:python39]
-# Use newest final release
-RestrictedPython = 7.2
-
-[versions:python310]
-# Use newest final release
-RestrictedPython = 7.2
-
-[versions:python311]
-# Use newest final release
-RestrictedPython = 7.2
-
-[versions:python312]
-# Use newest final release
-RestrictedPython = 7.2
diff --git a/versions.cfg b/versions.cfg
index f5c30ce236..569f9d2d09 100644
--- a/versions.cfg
+++ b/versions.cfg
@@ -5,26 +5,26 @@ versions = versions
 
 [versions]
 # Version pins for development and optional dependencies.
-Babel = 2.15.0
+Babel = 2.16.0
 Jinja2 = 3.1.4
 Missing = 5.0
-MarkupSafe = 2.1.5
+MarkupSafe = 3.0.1
 Products.BTreeFolder2 = 5.1
 Products.ZCatalog = 7.1
 Pygments = 2.18.0
 Record = 4.1
 Sphinx = 8.0.2
 alabaster = 1.0.0
-certifi = 2024.7.4
-charset-normalizer = 3.3.2
+certifi = 2024.8.30
+charset-normalizer = 3.4.0
 collective.recipe.template = 2.2
 colorama = 0.4.6
 docutils = 0.21.2
 five.localsitemanager = 4.0
 furo = 2024.8.6
-idna = 3.7
+idna = 3.10
 imagesize = 1.4.1
-importlib-metadata = 8.2.0
+importlib-metadata = 8.5.0
 # Required by zope.testbrowser on Python 3.13 because WebOb still uses cgi.
 legacy-cgi = 2.6.1
 mr.developer = 2.0.2
@@ -40,11 +40,11 @@ sphinxcontrib-jsmath = 1.0.1
 sphinxcontrib-qthelp = 2.0.0
 sphinxcontrib-serializinghtml = 2.0.0
 tempstorage = 6.0
-tomli = 2.0.1
-urllib3 = 2.2.2
+tomli = 2.0.2
+urllib3 = 2.2.3
 z3c.checkversions = 2.1
-zc.recipe.testrunner = 3.0
-zipp = 3.19.2
+zc.recipe.testrunner = 3.1
+zipp = 3.20.2
 zope.testrunner = 6.5
 
 [versions:python39]
@@ -62,6 +62,8 @@ alabaster = 0.7.13
 docutils = 0.20.1
 # Required dependency on Python 3.8 only
 importlib-resources = 6.4.0
+# MarkupSafe >= 3 requires Python 3.9
+MarkupSafe = 2.1.5
 # Sphinx >= 7.2 requires Python 3.9+
 Sphinx = 7.1.2
 # sphinxcontrib-serializinghtml >= 1.1.6 requires Python 3.9+


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 6fe4f28287..4fc56e11d2 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -22,22 +22,22 @@ jobs:
         - ["macos", "macos-latest"]
         config:
         # [Python version, tox env]
-        - ["3.11",  "release-check"]
-        - ["3.8",   "py38"]
-        - ["3.9",   "py39"]
-        - ["3.10",  "py310"]
-        - ["3.11",  "py311"]
-        - ["3.12",  "py312"]
-        - ["3.13",  "py313"]
-        - ["3.11",   "docs"]
-        - ["3.11",   "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", "docs"]
+        - ["3.11", "coverage"]
         exclude:
-          - { os: ["windows", "windows-latest"], config: ["3.11",  "release-check"] }
-          - { os: ["windows", "windows-latest"], config: ["3.11",  "docs"] }
-          - { os: ["windows", "windows-latest"], config: ["3.11",  "coverage"] }
-          - { os: ["macos", "macos-latest"], config: ["3.11",  "release-check"] }
-          - { os: ["macos", "macos-latest"], config: ["3.11",  "docs"] }
-          - { os: ["macos", "macos-latest"], config: ["3.11",  "coverage"] }
+          - { os: ["windows", "windows-latest"], config: ["3.11", "release-check"] }
+          - { os: ["windows", "windows-latest"], config: ["3.11", "docs"] }
+          - { os: ["windows", "windows-latest"], config: ["3.11", "coverage"] }
+          - { os: ["macos", "macos-latest"], config: ["3.11", "release-check"] }
+          - { os: ["macos", "macos-latest"], config: ["3.11", "docs"] }
+          - { os: ["macos", "macos-latest"], config: ["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