diff --git a/last_commit.txt b/last_commit.txt index 3ed850132d..64fc87a808 100644 --- a/last_commit.txt +++ b/last_commit.txt @@ -1,271 +1,161 @@ -Repository: plone.testing +Repository: plone.api Branch: refs/heads/master -Date: 2023-10-15T19:09:56+02:00 -Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/plone.testing/commit/b070459001f125b475bf07c27b08ce8cd52ba8ab +Date: 2023-10-13T16:52:15+05:30 +Author: akshat2jain (Akshat2Jain) +Commit: https://github.com/plone/plone.api/commit/0384ee20c9f777a81cec3c43ebad842c8e34d781 -Configuring with plone/meta +fixed the number Files changed: -A .flake8 -A .github/workflows/meta.yml -A .meta.toml -A .pre-commit-config.yaml -A news/5cc689e5.internal -M .editorconfig -M .gitignore -M pyproject.toml -M tox.ini -D .travis.yml -D bootstrap.py -D buildout.cfg -D setup.cfg - -b'diff --git a/.editorconfig b/.editorconfig\nindex 512361c..8ae05aa 100644\n--- a/.editorconfig\n+++ b/.editorconfig\n@@ -1,4 +1,8 @@\n-# EditorConfig Configurtaion file, for more details see:\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n+#\n+# EditorConfig Configuration file, for more details see:\n # http://EditorConfig.org\n # EditorConfig is a convention description, that could be interpreted\n # by multiple editors to enforce common coding conventions for specific\n@@ -25,12 +29,26 @@ max_line_length = off\n # 4 space indentation\n indent_size = 4\n \n-[*.{yml}]\n+[*.{yml,zpt,pt,dtml,zcml}]\n # 2 space indentation\n indent_size = 2\n \n+[*.{json,jsonl,js,jsx,ts,tsx,css,less,scss,html}] # Frontend development\n+# 2 space indentation\n+indent_size = 2\n+max_line_length = 80\n+\n [{Makefile,.gitmodules}]\n # Tab indentation (no size specified, but view as 4 spaces)\n indent_style = tab\n indent_size = unset\n tab_width = unset\n+\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [editorconfig]\n+# extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\ndiff --git a/.flake8 b/.flake8\nnew file mode 100644\nindex 0000000..7ef4f64\n--- /dev/null\n+++ b/.flake8\n@@ -0,0 +1,22 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n+[flake8]\n+doctests = 1\n+ignore =\n+ # black takes care of line length\n+ E501,\n+ # black takes care of where to break lines\n+ W503,\n+ # black takes care of spaces within slicing (list[:])\n+ E203,\n+ # black takes care of spaces after commas\n+ E231,\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [flake8]\n+# extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\ndiff --git a/.github/workflows/meta.yml b/.github/workflows/meta.yml\nnew file mode 100644\nindex 0000000..39a164d\n--- /dev/null\n+++ b/.github/workflows/meta.yml\n@@ -0,0 +1,68 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n+name: Meta\n+on:\n+ push:\n+ branches:\n+ - master\n+ - main\n+ pull_request:\n+ branches:\n+ - master\n+ - main\n+ workflow_dispatch:\n+\n+##\n+# To set environment variables for all jobs, add in .meta.toml:\n+# [github]\n+# env = """\n+# debug: 1\n+# image-name: \'org/image\'\n+# image-tag: \'latest\'\n+# """\n+##\n+\n+jobs:\n+ qa:\n+ uses: plone/meta/.github/workflows/qa.yml@main\n+ test:\n+ uses: plone/meta/.github/workflows/test.yml@main\n+ coverage:\n+ uses: plone/meta/.github/workflows/coverage.yml@main\n+ dependencies:\n+ uses: plone/meta/.github/workflows/dependencies.yml@main\n+ release_ready:\n+ uses: plone/meta/.github/workflows/release_ready.yml@main\n+ circular:\n+ uses: plone/meta/.github/workflows/circular.yml@main\n+\n+##\n+# To modify the list of default jobs being created add in .meta.toml:\n+# [github]\n+# jobs = [\n+# "qa",\n+# "test",\n+# "coverage",\n+# "dependencies",\n+# "release_ready",\n+# "circular",\n+# ]\n+##\n+\n+##\n+# To request that some OS level dependencies get installed\n+# when running tests/coverage jobs, add in .meta.toml:\n+# [github]\n+# os_dependencies = "git libxml2 libxslt"\n+##\n+\n+\n+##\n+# Specify additional jobs in .meta.toml:\n+# [github]\n+# extra_lines = """\n+# another:\n+# uses: org/repo/.github/workflows/file.yml@main\n+# """\n+##\ndiff --git a/.gitignore b/.gitignore\nindex 8293885..503e47c 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -1,17 +1,55 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n+# python related\n *.egg-info\n *.pyc\n-*.tox\n-.Python\n-.pytest_cache\n+*.pyo\n+\n+# translation related\n+*.mo\n+\n+# tools related\n+build/\n .coverage\n-.installed.cfg\n-bin\n+.*project\n coverage.xml\n-develop-eggs\n-eggs\n-htmlcov/\n+dist/\n+docs/_build\n+__pycache__/\n+.tox\n+.vscode/\n+node_modules/\n+\n+# venv / buildout related\n+bin/\n+develop-eggs/\n+eggs/\n+.eggs/\n+etc/\n+.installed.cfg\n include/\n lib/\n+lib64\n+.mr.developer.cfg\n parts/\n-pip-selfcheck.json\n-_build/\n+pyvenv.cfg\n+var/\n+\n+# mxdev\n+/instance/\n+/.make-sentinels/\n+/*-mxdev.txt\n+/reports/\n+/sources/\n+/venv/\n+.installed.txt\n+\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [gitignore]\n+# extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\ndiff --git a/.meta.toml b/.meta.toml\nnew file mode 100644\nindex 0000000..05b298d\n--- /dev/null\n+++ b/.meta.toml\n@@ -0,0 +1,9 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n+[meta]\n+template = "default"\n+commit-id = "68cda6e4"\n+\n+[pyproject]\n+dependencies_ignores = "[\'ZServer\', \'StringIO\', \'urllib2\']"\ndiff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml\nnew file mode 100644\nindex 0000000..b6eb043\n--- /dev/null\n+++ b/.pre-commit-config.yaml\n@@ -0,0 +1,94 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n+ci:\n+ autofix_prs: false\n+ autoupdate_schedule: monthly\n+\n+repos:\n+- repo: https://github.com/asottile/pyupgrade\n+ rev: v3.14.0\n+ hooks:\n+ - id: pyupgrade\n+ args: [--py38-plus]\n+- repo: https://github.com/pycqa/isort\n+ rev: 5.12.0\n+ hooks:\n+ - id: isort\n+- repo: https://github.com/psf/black\n+ rev: 23.9.1\n+ hooks:\n+ - id: black\n+- repo: https://github.com/collective/zpretty\n+ rev: 3.1.0\n+ hooks:\n+ - id: zpretty\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pre_commit]\n+# zpretty_extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\n+- repo: https://github.com/PyCQA/flake8\n+ rev: 6.1.0\n+ hooks:\n+ - id: flake8\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pre_commit]\n+# flake8_extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\n+- repo: https://github.com/codespell-project/codespell\n+ rev: v2.2.6\n+ hooks:\n+ - id: codespell\n+ additional_dependencies:\n+ - tomli\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pre_commit]\n+# codespell_extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\n+- repo: https://github.com/mgedmin/check-manifest\n+ rev: "0.49"\n+ hooks:\n+ - id: check-manifest\n+- repo: https://github.com/regebro/pyroma\n+ rev: "4.2"\n+ hooks:\n+ - id: pyroma\n+- repo: https://github.com/mgedmin/check-python-versions\n+ rev: "0.21.3"\n+ hooks:\n+ - id: check-python-versions\n+ args: [\'--only\', \'setup.py,pyproject.toml\']\n+- repo: https://github.com/collective/i18ndude\n+ rev: "6.1.0"\n+ hooks:\n+ - id: i18ndude\n+\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pre_commit]\n+# i18ndude_extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\n+\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pre_commit]\n+# extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\ndiff --git a/.travis.yml b/.travis.yml\ndeleted file mode 100644\nindex d3b514f..0000000\n--- a/.travis.yml\n+++ /dev/null\n@@ -1,45 +0,0 @@\n-language: python\n-sudo: false\n-cache: pip\n-\n-matrix:\n- include:\n- - python: "2.7"\n- env: TOXENV=lint-py27\n- - python: "3.6"\n- env: TOXENV=lint-py36\n- - python: "3.7"\n- env: TOXENV=lint-py37\n- - python: "3.8"\n- env: TOXENV=lint-py38\n- - python: "2.7"\n- env: TOXENV=py27\n- - python: "2.7"\n- env: TOXENV=py27-zserver\n- - python: "3.6"\n- env: TOXENV=py36\n- - python: "3.7"\n- env: TOXENV=py37\n- - python: "3.8"\n- env: TOXENV=py38\n- - python: "3.9"\n- env: TOXENV=py39\n- allow_failures:\n- - python: "3.9"\n- env: TOXENV=py39\n-\n-install:\n- - travis_retry pip install -U pip setuptools\n- - travis_retry pip install -U tox coveralls coverage\n-\n-script:\n- - travis_retry tox\n-\n-after_success:\n- - coverage combine\n- - coveralls\n-\n-notifications:\n- email: false\n-cache:\n- pip: true\ndiff --git a/bootstrap.py b/bootstrap.py\ndeleted file mode 100644\nindex a459921..0000000\n--- a/bootstrap.py\n+++ /dev/null\n@@ -1,210 +0,0 @@\n-##############################################################################\n-#\n-# Copyright (c) 2006 Zope Foundation and Contributors.\n-# All Rights Reserved.\n-#\n-# This software is subject to the provisions of the Zope Public License,\n-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.\n-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED\n-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS\n-# FOR A PARTICULAR PURPOSE.\n-#\n-##############################################################################\n-"""Bootstrap a buildout-based project\n-\n-Simply run this script in a directory containing a buildout.cfg.\n-The script accepts buildout command-line options, so you can\n-use the -c option to specify an alternate configuration file.\n-"""\n-\n-import os\n-import shutil\n-import sys\n-import tempfile\n-\n-from optparse import OptionParser\n-\n-__version__ = \'2015-07-01\'\n-# See zc.buildout\'s changelog if this version is up to date.\n-\n-tmpeggs = tempfile.mkdtemp(prefix=\'bootstrap-\')\n-\n-usage = \'\'\'\\\n-[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]\n-\n-Bootstraps a buildout-based project.\n-\n-Simply run this script in a directory containing a buildout.cfg, using the\n-Python that you want bin/buildout to use.\n-\n-Note that by using --find-links to point to local resources, you can keep\n-this script from going over the network.\n-\'\'\'\n-\n-parser = OptionParser(usage=usage)\n-parser.add_option("--version",\n- action="store_true", default=False,\n- help=("Return bootstrap.py version."))\n-parser.add_option("-t", "--accept-buildout-test-releases",\n- dest=\'accept_buildout_test_releases\',\n- action="store_true", default=False,\n- help=("Normally, if you do not specify a --version, the "\n- "bootstrap script and buildout gets the newest "\n- "*final* versions of zc.buildout and its recipes and "\n- "extensions for you. If you use this flag, "\n- "bootstrap and buildout will get the newest releases "\n- "even if they are alphas or betas."))\n-parser.add_option("-c", "--config-file",\n- help=("Specify the path to the buildout configuration "\n- "file to be used."))\n-parser.add_option("-f", "--find-links",\n- help=("Specify a URL to search for buildout releases"))\n-parser.add_option("--allow-site-packages",\n- action="store_true", default=False,\n- help=("Let bootstrap.py use existing site packages"))\n-parser.add_option("--buildout-version",\n- help="Use a specific zc.buildout version")\n-parser.add_option("--setuptools-version",\n- help="Use a specific setuptools version")\n-parser.add_option("--setuptools-to-dir",\n- help=("Allow for re-use of existing directory of "\n- "setuptools versions"))\n-\n-options, args = parser.parse_args()\n-if options.version:\n- print("bootstrap.py version %s" % __version__)\n- sys.exit(0)\n-\n-\n-######################################################################\n-# load/install setuptools\n-\n-try:\n- from urllib.request import urlopen\n-except ImportError:\n- from urllib2 import urlopen\n-\n-ez = {}\n-if os.path.exists(\'ez_setup.py\'):\n- exec(open(\'ez_setup.py\').read(), ez)\n-else:\n- exec(urlopen(\'https://bootstrap.pypa.io/ez_setup.py\').read(), ez)\n-\n-if not options.allow_site_packages:\n- # ez_setup imports site, which adds site packages\n- # this will remove them from the path to ensure that incompatible versions\n- # of setuptools are not in the path\n- import site\n- # inside a virtualenv, there is no \'getsitepackages\'.\n- # We can\'t remove these reliably\n- if hasattr(site, \'getsitepackages\'):\n- for sitepackage_path in site.getsitepackages():\n- # Strip all site-packages directories from sys.path that\n- # are not sys.prefix; this is because on Windows\n- # sys.prefix is a site-package directory.\n- if sitepackage_path != sys.prefix:\n- sys.path[:] = [x for x in sys.path\n- if sitepackage_path not in x]\n-\n-setup_args = dict(to_dir=tmpeggs, download_delay=0)\n-\n-if options.setuptools_version is not None:\n- setup_args[\'version\'] = options.setuptools_version\n-if options.setuptools_to_dir is not None:\n- setup_args[\'to_dir\'] = options.setuptools_to_dir\n-\n-ez[\'use_setuptools\'](**setup_args)\n-import setuptools\n-import pkg_resources\n-\n-# This does not (always?) update the default working set. We will\n-# do it.\n-for path in sys.path:\n- if path not in pkg_resources.working_set.entries:\n- pkg_resources.working_set.add_entry(path)\n-\n-######################################################################\n-# Install buildout\n-\n-ws = pkg_resources.working_set\n-\n-setuptools_path = ws.find(\n- pkg_resources.Requirement.parse(\'setuptools\')).location\n-\n-# Fix sys.path here as easy_install.pth added before PYTHONPATH\n-cmd = [sys.executable, \'-c\',\n- \'import sys; sys.path[0:0] = [%r]; \' % setuptools_path +\n- \'from setuptools.command.easy_install import main; main()\',\n- \'-mZqNxd\', tmpeggs]\n-\n-find_links = os.environ.get(\n- \'bootstrap-testing-find-links\',\n- options.find_links or\n- (\'http://downloads.buildout.org/\'\n- if options.accept_buildout_test_releases else None)\n- )\n-if find_links:\n- cmd.extend([\'-f\', find_links])\n-\n-requirement = \'zc.buildout\'\n-version = options.buildout_version\n-if version is None and not options.accept_buildout_test_releases:\n- # Figure out the most recent final version of zc.buildout.\n- import setuptools.package_index\n- _final_parts = \'*final-\', \'*final\'\n-\n- def _final_version(parsed_version):\n- try:\n- return not parsed_version.is_prerelease\n- except AttributeError:\n- # Older setuptools\n- for part in parsed_version:\n- if (part[:1] == \'*\') and (part not in _final_parts):\n- return False\n- return True\n-\n- index = setuptools.package_index.PackageIndex(\n- search_path=[setuptools_path])\n- if find_links:\n- index.add_find_links((find_links,))\n- req = pkg_resources.Requirement.parse(requirement)\n- if index.obtain(req) is not None:\n- best = []\n- bestv = None\n- for dist in index[req.project_name]:\n- distv = dist.parsed_version\n- if _final_version(distv):\n- if bestv is None or distv > bestv:\n- best = [dist]\n- bestv = distv\n- elif distv == bestv:\n- best.append(dist)\n- if best:\n- best.sort()\n- version = best[-1].version\n-if version:\n- requirement = \'==\'.join((requirement, version))\n-cmd.append(requirement)\n-\n-import subprocess\n-if subprocess.call(cmd) != 0:\n- raise Exception(\n- "Failed to execute command:\\n%s" % repr(cmd)[1:-1])\n-\n-######################################################################\n-# Import and run buildout\n-\n-ws.add_entry(tmpeggs)\n-ws.require(requirement)\n-import zc.buildout.buildout\n-\n-if not [a for a in args if \'=\' not in a]:\n- args.append(\'bootstrap\')\n-\n-# if -c was provided, we push it back into args for buildout\' main function\n-if options.config_file is not None:\n- args[0:0] = [\'-c\', options.config_file]\n-\n-zc.buildout.buildout.main(args)\n-shutil.rmtree(tmpeggs)\ndiff --git a/buildout.cfg b/buildout.cfg\ndeleted file mode 100644\nindex b5e35ab..0000000\n--- a/buildout.cfg\n+++ /dev/null\n@@ -1,52 +0,0 @@\n-[buildout]\n-extends =\n- https://raw.githubusercontent.com/plone/buildout.coredev/5.2/versions.cfg\n-parts =\n- coverage\n- test\n- report\n- report-xml\n-\n-develop = .\n-prefer-final = false\n-\n-[versions]\n-setuptools =\n-zc.buildout =\n-plone.testing =\n-# From 2018-10-02\n-# Please remove this pinning after we get on top of the ZODB issues!\n-ZODB = < 5.4.0\n-# From 2018-10-06\n-# Please remove this pinning once the Zope 4.0 stack allows for it!\n-ZServer = < 4.0b3\n-# From 2018-10-06\n-# Please remove this pinning once collective.xmltestreport cuts a release!\n-zope.testrunner = < 4.9.0\n-\n-[test]\n-recipe = collective.xmltestreport\n-eggs =\n- plone.testing [test]\n-defaults = [\'--auto-color\', \'--auto-progress\']\n-\n-[coverage]\n-recipe = zc.recipe.egg\n-eggs = coverage\n-initialization =\n- include = \'--source=${buildout:directory}/src\'\n- sys.argv = sys.argv[:] + [\'run\', include, \'bin/test\', \'--all\', \'--xml\']\n-\n-[report]\n-recipe = zc.recipe.egg\n-eggs = coverage\n-scripts = coverage=report\n-initialization =\n- sys.argv = sys.argv[:] + [\'html\', \'-i\']\n-\n-[report-xml]\n-recipe = zc.recipe.egg\n-eggs = coverage\n-scripts = coverage=report-xml\n-initialization =\n- sys.argv = sys.argv[:] + [\'xml\', \'-i\']\ndiff --git a/news/5cc689e5.internal b/news/5cc689e5.internal\nnew file mode 100644\nindex 0000000..c08f539\n--- /dev/null\n+++ b/news/5cc689e5.internal\n@@ -0,0 +1,2 @@\n+Update configuration files.\n+[plone devs]\ndiff --git a/pyproject.toml b/pyproject.toml\nindex 12c6bc8..e0decf5 100644\n--- a/pyproject.toml\n+++ b/pyproject.toml\n@@ -1,3 +1,6 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n [tool.towncrier]\n directory = "news/"\n filename = "CHANGES.rst"\n@@ -34,5 +37,121 @@ directory = "tests"\n name = "Tests"\n showcontent = true\n \n+##\n+# Add extra configuration options in .meta.toml:\n+# [pyproject]\n+# towncrier_extra_lines = """\n+# extra_configuration\n+# """\n+##\n+\n [tool.isort]\n profile = "plone"\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pyproject]\n+# isort_extra_lines = """\n+# extra_configuration\n+# """\n+##\n+\n+[tool.black]\n+target-version = ["py38"]\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pyproject]\n+# black_extra_lines = """\n+# extra_configuration\n+# """\n+##\n+\n+[tool.codespell]\n+ignore-words-list = "discreet,"\n+skip = "*.po,"\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pyproject]\n+# codespell_ignores = "foo,bar"\n+# codespell_skip = "*.po,*.map,package-lock.json"\n+##\n+\n+[tool.dependencychecker]\n+Zope = [\n+ # Zope own provided namespaces\n+ \'App\', \'OFS\', \'Products.Five\', \'Products.OFSP\', \'Products.PageTemplates\',\n+ \'Products.SiteAccess\', \'Shared\', \'Testing\', \'ZPublisher\', \'ZTUtils\',\n+ \'Zope2\', \'webdav\', \'zmi\',\n+ # ExtensionClass own provided namespaces\n+ \'ExtensionClass\', \'ComputedAttribute\', \'MethodObject\',\n+ # Zope dependencies\n+ \'AccessControl\', \'Acquisition\', \'AuthEncoding\', \'beautifulsoup4\', \'BTrees\',\n+ \'cffi\', \'Chameleon\', \'DateTime\', \'DocumentTemplate\',\n+ \'MultiMapping\', \'multipart\', \'PasteDeploy\', \'Persistence\', \'persistent\',\n+ \'pycparser\', \'python-gettext\', \'pytz\', \'RestrictedPython\', \'roman\',\n+ \'soupsieve\', \'transaction\', \'waitress\', \'WebOb\', \'WebTest\', \'WSGIProxy2\',\n+ \'z3c.pt\', \'zc.lockfile\', \'ZConfig\', \'zExceptions\', \'ZODB\', \'zodbpickle\',\n+ \'zope.annotation\', \'zope.browser\', \'zope.browsermenu\', \'zope.browserpage\',\n+ \'zope.browserresource\', \'zope.cachedescriptors\', \'zope.component\',\n+ \'zope.configuration\', \'zope.container\', \'zope.contentprovider\',\n+ \'zope.contenttype\', \'zope.datetime\', \'zope.deferredimport\',\n+ \'zope.deprecation\', \'zope.dottedname\', \'zope.event\', \'zope.exceptions\',\n+ \'zope.filerepresentation\', \'zope.globalrequest\', \'zope.hookable\',\n+ \'zope.i18n\', \'zope.i18nmessageid\', \'zope.interface\', \'zope.lifecycleevent\',\n+ \'zope.location\', \'zope.pagetemplate\', \'zope.processlifetime\', \'zope.proxy\',\n+ \'zope.ptresource\', \'zope.publisher\', \'zope.schema\', \'zope.security\',\n+ \'zope.sequencesort\', \'zope.site\', \'zope.size\', \'zope.structuredtext\',\n+ \'zope.tal\', \'zope.tales\', \'zope.testbrowser\', \'zope.testing\',\n+ \'zope.traversing\', \'zope.viewlet\'\n+]\n+\'Products.CMFCore\' = [\n+ \'docutils\', \'five.localsitemanager\', \'Missing\', \'Products.BTreeFolder2\',\n+ \'Products.GenericSetup\', \'Products.MailHost\', \'Products.PythonScripts\',\n+ \'Products.StandardCacheManagers\', \'Products.ZCatalog\', \'Record\',\n+ \'zope.sendmail\', \'Zope\'\n+]\n+\'plone.base\' = [\n+ \'plone.batching\', \'plone.registry\', \'plone.schema\',\'plone.z3cform\',\n+ \'Products.CMFCore\', \'Products.CMFDynamicViewFTI\',\n+]\n+python-dateutil = [\'dateutil\']\n+ignore-packages = [\'ZServer\', \'StringIO\', \'urllib2\']\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pyproject]\n+# dependencies_ignores = "[\'zestreleaser.towncrier\']"\n+# dependencies_mappings = [\n+# "gitpython = [\'git\']",\n+# "pygithub = [\'github\']",\n+# ]\n+##\n+\n+[tool.check-manifest]\n+ignore = [\n+ ".editorconfig",\n+ ".meta.toml",\n+ ".pre-commit-config.yaml",\n+ "tox.ini",\n+ ".flake8",\n+ "mx.ini",\n+\n+]\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pyproject]\n+# check_manifest_ignores = """\n+# "*.map.js",\n+# "*.pyc",\n+# """\n+##\n+\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pyproject]\n+# extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\ndiff --git a/setup.cfg b/setup.cfg\ndeleted file mode 100644\nindex f408c8d..0000000\n--- a/setup.cfg\n+++ /dev/null\n@@ -1,60 +0,0 @@\n-[build_sphinx]\n-source-dir = docs/source\n-build-dir = _build/docs\n-all_files = 1\n-\n-[upload_sphinx]\n-upload-dir = _build/docs/html\n-\n-[check-manifest]\n-ignore =\n- .editorconfig\n- bootstrap.py\n- buildout.cfg\n- tox.ini\n-\n-[coverage:run]\n-branch = True\n-\n-source =\n- src\n-\n-omit =\n-\n-[coverage:report]\n-precision = 2\n-\n-[coverage:html]\n-directory = _build/reports/coverage\n-\n-\n-[isort]\n-# for details see\n-# http://docs.plone.org/develop/styleguide/python.html#grouping-and-sorting\n-force_alphabetical_sort = True\n-force_single_line = True\n-lines_after_imports = 2\n-line_length = 200\n-\n-[flake8]\n-exclude =\n- bootstrap.py,\n-\n-include =\n- src\n-\n-ignore =\n- N801,\n- N802,\n- N803,\n- N805,\n- N806,\n- N812,\n- T000,\n- T003,\n-\n-[zest.releaser]\n-create-wheel = yes\n-\n-[bdist_wheel]\n-universal = 1\ndiff --git a/tox.ini b/tox.ini\nindex 1c1dbb6..43f377f 100644\n--- a/tox.ini\n+++ b/tox.ini\n@@ -1,161 +1,208 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n [tox]\n+# We need 4.4.0 for constrain_package_deps.\n+min_version = 4.4.0\n envlist =\n- py27,\n- py27-zserver,\n- py36,\n- py37,\n- py38,\n- py39-dev,\n- coverage-report,\n-# docs,\n- lint-py27,\n- lint-py36,\n- lint-py37,\n- lint-py38,\n-\n-minversion = 1.9\n-\n-[testenv]\n-usedevelop = True\n-\n-pip_pre = True\n-\n-extras =\n+ lint\n test\n- zserver: z2,zserver\n-\n-deps =\n- coverage\n-\n-commands =\n- python -V\n- coverage run {envbindir}/zope-testrunner --path=src --all {posargs:-vc}\n+ dependencies\n \n-setenv =\n- COVERAGE_FILE=.coverage.{envname}\n \n-passenv =\n- WSGI_REQUEST_LOGGING\n+##\n+# Add extra configuration options in .meta.toml:\n+# [tox]\n+# envlist_lines = """\n+# my_other_environment\n+# """\n+# config_lines = """\n+# my_extra_top_level_tox_configuration_lines\n+# """\n+##\n \n-[testenv:coverage-report]\n+[testenv]\n skip_install = true\n-basepython = python2.7\n-\n-deps = coverage\n-\n-setenv =\n- COVERAGE_FILE=.coverage\n-\n+allowlist_externals =\n+ echo\n+ false\n+# Make sure typos like `tox -e formaat` are caught instead of silently doing nothing.\n+# See https://github.com/tox-dev/tox/issues/2858.\n commands =\n- coverage erase\n- coverage combine\n- coverage html -i\n- coverage xml -i\n- coverage report -i --fail-under=85\n-\n+ echo "Unrecognized environment name {envname}"\n+ false\n \n-[lint]\n+[testenv:init]\n+description = Prepare environment\n skip_install = true\n-\n-deps =\n- isort\n- flake8\n- # helper to generate HTML reports:\n- flake8-html\n- # Useful flake8 plugins that are Python and Plone specific:\n- flake8-coding\n- flake8-debugger\n- flake8-deprecated\n- flake8-print\n- # flake8-pytest\n- # flake8-todo\n- mccabe\n- # Potential flake8 plugins that should be used: # TBD\n- #flake8-blind-except\n- #flake8-commas\n- #flake8-docstrings\n- #flake8-mypy\n- #flake8-pep3101\n- #flake8-plone-hasattr\n- #flake8-string-format\n- #flake8_strict\n- #flake8-quotes\n- #flake8-polyfill\n-\n commands =\n- mkdir -p {toxinidir}/_build/reports/flake8\n- - flake8 --format=html --htmldir={toxinidir}/_build/reports/flake8 --doctests src setup.py\n- flake8 --doctests --ignore=W503 src setup.py\n- isort --check-only {toxinidir}/src\n+ echo "Initial setup complete"\n \n-whitelist_externals =\n- mkdir\n \n-[testenv:isort-apply]\n+[testenv:format]\n+description = automatically reformat code\n skip_install = true\n-\n deps =\n- isort\n-\n+ pre-commit\n commands =\n- isort {toxinidir}/src\n-\n-[testenv:lint-py27]\n-basepython = python2.7\n-skip_install = true\n-deps = {[lint]deps}\n-commands = {[lint]commands}\n-whitelist_externals = {[lint]whitelist_externals}\n-\n-[testenv:lint-py36]\n-basepython = python3.6\n-skip_install = true\n-deps = {[lint]deps}\n-commands = {[lint]commands}\n-whitelist_externals = {[lint]whitelist_externals}\n+ pre-commit run -a pyupgrade\n+ pre-commit run -a isort\n+ pre-commit run -a black\n+ pre-commit run -a zpretty\n \n-[testenv:lint-py37]\n-basepython = python3.7\n+[testenv:lint]\n+description = run linters that will help improve the code style\n skip_install = true\n-deps = {[lint]deps}\n-commands = {[lint]commands}\n-whitelist_externals = {[lint]whitelist_externals}\n-\n-[testenv:lint-py38]\n-basepython = python3.8\n-skip_install = true\n-deps = {[lint]deps}\n-commands = {[lint]commands}\n-whitelist_externals = {[lint]whitelist_externals}\n-\n-[testenv:docs]\n-skip_install = true\n-\n deps =\n- Sphinx\n-\n+ pre-commit\n commands =\n- sphinx-build -b html -d _build/docs/doctrees docs _build/docs/html\n- sphinx-build -b doctest docs _build/docs/doctrees\n+ pre-commit run -a\n \n-[testenv:update_translation]\n+[testenv:dependencies]\n+description = check if the package defines all its dependencies\n skip_install = true\n-\n deps =\n- i18ndude\n+ build\n+ z3c.dependencychecker==2.11\n+commands =\n+ python -m build --sdist --no-isolation\n+ dependencychecker\n+\n+[testenv:dependencies-graph]\n+description = generate a graph out of the dependencies of the package\n+skip_install = false\n+allowlist_externals =\n+ sh\n+deps =\n+ pipdeptree==2.5.1\n+ graphviz # optional dependency of pipdeptree\n+commands =\n+ sh -c \'pipdeptree --exclude setuptools,wheel,pipdeptree,zope.interface,zope.component --graph-output svg > dependencies.svg\'\n+\n+[testenv:test]\n+description = run the distribution tests\n+use_develop = true\n+skip_install = false\n+constrain_package_deps = true\n+set_env =\n+ ROBOT_BROWSER=headlesschrome\n+\n+##\n+# Specify extra test environment variables in .meta.toml:\n+# [tox]\n+# test_environment_variables = """\n+# PIP_EXTRA_INDEX_URL=https://my-pypi.my-server.com/\n+# """\n+#\n+# Set constrain_package_deps .meta.toml:\n+# [tox]\n+# constrain_package_deps = "false"\n+##\n+deps =\n+ zope.testrunner\n+ -c https://dist.plone.org/release/6.0-dev/constraints.txt\n+ \n+##\n+# Specify additional deps in .meta.toml:\n+# [tox]\n+# test_deps_additional = "-esources/plonegovbr.portal_base[test]"\n+#\n+# Specify a custom constraints file in .meta.toml:\n+# [tox]\n+# constraints_file = "https://my-server.com/constraints.txt"\n+##\n+commands =\n+ zope-testrunner --all --test-path={toxinidir}/src -s plone.testing {posargs}\n+extras =\n+ test\n \n+##\n+# Add extra configuration options in .meta.toml:\n+# [tox]\n+# test_extras = """\n+# tests\n+# widgets\n+# """\n+##\n+\n+[testenv:coverage]\n+description = get a test coverage report\n+use_develop = true\n+skip_install = false\n+constrain_package_deps = true\n+set_env =\n+ ROBOT_BROWSER=headlesschrome\n+\n+##\n+# Specify extra test environment variables in .meta.toml:\n+# [tox]\n+# test_environment_variables = """\n+# PIP_EXTRA_INDEX_URL=https://my-pypi.my-server.com/\n+# """\n+##\n+deps =\n+ coverage\n+ zope.testrunner\n+ -c https://dist.plone.org/release/6.0-dev/constraints.txt\n+ \n commands =\n- i18ndude find-untranslated\n- i18ndude rebuild-pot\n- i18ndude merge\n- i18ndude sync\n- i18ndude list\n+ coverage run --branch --source plone.testing {envbindir}/zope-testrunner --quiet --all --test-path={toxinidir}/src -s plone.testing {posargs}\n+ coverage report -m --format markdown\n+ coverage xml\n+extras =\n+ test\n \n-[testenv:release]\n-skip_install = true\n \n+[testenv:release-check]\n+description = ensure that the distribution is ready to release\n+skip_install = true\n deps =\n- zest.releaser[recommended]\n-\n+ twine\n+ build\n+ towncrier\n+ -c https://dist.plone.org/release/6.0-dev/constraints.txt\n+ \n+commands =\n+ # fake version to not have to install the package\n+ # we build the change log as news entries might break\n+ # the README that is displayed on PyPI\n+ towncrier build --version=100.0.0 --yes\n+ python -m build --sdist --no-isolation\n+ twine check dist/*\n+\n+[testenv:circular]\n+description = ensure there are no cyclic dependencies\n+use_develop = true\n+skip_install = false\n+set_env =\n+\n+##\n+# Specify extra test environment variables in .meta.toml:\n+# [tox]\n+# test_environment_variables = """\n+# PIP_EXTRA_INDEX_URL=https://my-pypi.my-server.com/\n+# """\n+##\n+allowlist_externals =\n+ sh\n+deps =\n+ pipdeptree\n+ pipforester\n+ -c https://dist.plone.org/release/6.0-dev/constraints.txt\n+ \n commands =\n- fullrelease --no-input -v\n+ # Generate the full dependency tree\n+ sh -c \'pipdeptree -j > forest.json\'\n+ # Generate a DOT graph with the circular dependencies, if any\n+ pipforester -i forest.json -o forest.dot --cycles\n+ # Report if there are any circular dependencies, i.e. error if there are any\n+ pipforester -i forest.json --check-cycles -o /dev/null\n+\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [tox]\n+# extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\n' - -Repository: plone.testing - - -Branch: refs/heads/master -Date: 2023-10-15T19:09:56+02:00 -Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/plone.testing/commit/b5bcc0329d7eefe34a38f23f42f44ce92c49f787 - -chore: pyupgrade - -Files changed: -M setup.py -M src/plone/__init__.py -M src/plone/testing/__init__.py -M src/plone/testing/_z2_testbrowser.py -M src/plone/testing/layer.py -M src/plone/testing/publisher.py -M src/plone/testing/security.py -M src/plone/testing/tests.py -M src/plone/testing/z2.py -M src/plone/testing/zca.py -M src/plone/testing/zodb.py -M src/plone/testing/zope.py -M src/plone/testing/zserver.py - -b'diff --git a/setup.py b/setup.py\nindex 14de75c..355e85a 100644\n--- a/setup.py\n+++ b/setup.py\n@@ -1,4 +1,3 @@\n-# -*- coding: utf-8 -*-\n from setuptools import find_packages\n from setuptools import setup\n \n@@ -44,7 +43,7 @@\n name=\'plone.testing\',\n version=version,\n description="Testing infrastructure for Zope and Plone projects.",\n- long_description=(u\'\\n\\n\'.join([\n+ long_description=(\'\\n\\n\'.join([\n open(os.path.join("src", "plone", "testing", "README.rst")).read(),\n open("CHANGES.rst").read(),\n "Detailed documentation\\n"\ndiff --git a/src/plone/__init__.py b/src/plone/__init__.py\nindex 68c04af..de40ea7 100644\n--- a/src/plone/__init__.py\n+++ b/src/plone/__init__.py\n@@ -1,2 +1 @@\n-# -*- coding: utf-8 -*-\n __import__(\'pkg_resources\').declare_namespace(__name__)\ndiff --git a/src/plone/testing/__init__.py b/src/plone/testing/__init__.py\nindex 0772d96..6dc8334 100644\n--- a/src/plone/testing/__init__.py\n+++ b/src/plone/testing/__init__.py\n@@ -1,4 +1,3 @@\n-# -*- coding: utf-8 -*-\n # flake8: NOQA: F401\n # Convenience imports\n from plone.testing.layer import Layer\ndiff --git a/src/plone/testing/_z2_testbrowser.py b/src/plone/testing/_z2_testbrowser.py\nindex 2486f60..2d5fe32 100644\n--- a/src/plone/testing/_z2_testbrowser.py\n+++ b/src/plone/testing/_z2_testbrowser.py\n@@ -1,6 +1,3 @@\n-# -*- coding: utf-8 -*-\n-from __future__ import absolute_import\n-\n from zope.testbrowser import browser\n from ZPublisher.httpexceptions import HTTPExceptionHandler\n from ZPublisher.utils import basic_auth_encode\n@@ -43,7 +40,7 @@ def wrapped_func(*args, **kw):\n return wrapped_func\n \n \n-class Zope2Caller(object):\n+class Zope2Caller:\n """Functional testing caller that can execute HTTP requests via the\n Zope 2 WSGI publisher.\n """\n@@ -79,7 +76,7 @@ class Browser(browser.Browser):\n \n def __init__(self, app, url=None):\n wsgi_app = Zope2Caller(self, app)\n- super(Browser, self).__init__(url=url, wsgi_app=wsgi_app)\n+ super().__init__(url=url, wsgi_app=wsgi_app)\n \n \n # Add `nohost` to testbrowser\'s set of allowed hosts\ndiff --git a/src/plone/testing/layer.py b/src/plone/testing/layer.py\nindex 90dc791..0be5445 100644\n--- a/src/plone/testing/layer.py\n+++ b/src/plone/testing/layer.py\n@@ -1,11 +1,10 @@\n-# -*- coding: utf-8 -*-\n import sys\n \n \n _marker = object()\n \n \n-class ResourceManager(object):\n+class ResourceManager:\n """Mixin class for resource managers.\n """\n \n@@ -114,7 +113,7 @@ def _mergeResourceManagers(self, seqs):\n break\n \n if not cand:\n- raise TypeError(u\'Inconsistent layer hierarchy!\')\n+ raise TypeError(\'Inconsistent layer hierarchy!\')\n \n res.append(cand)\n for seq in nonemptyseqs: # remove cand\n@@ -161,7 +160,7 @@ def __init__(self, bases=None, name=None, module=None):\n if name is None and bases is not None:\n raise ValueError(\'The `name`` argument is required when overriding bases with the `bases` argument\') # NOQA: E501\n \n- super(Layer, self).__init__()\n+ super().__init__()\n \n if bases is None:\n bases = self.defaultBases\n@@ -187,10 +186,10 @@ def __init__(self, bases=None, name=None, module=None):\n \n self.__module__ = module\n \n- super(Layer, self).__init__()\n+ super().__init__()\n \n def __repr__(self):\n- return "".format(self.__module__, self.__name__,)\n+ return f""\n \n # Layer lifecycle methods - overriden by subclasses\n \ndiff --git a/src/plone/testing/publisher.py b/src/plone/testing/publisher.py\nindex d20f648..da6fc32 100644\n--- a/src/plone/testing/publisher.py\n+++ b/src/plone/testing/publisher.py\n@@ -1,7 +1,5 @@\n-# -*- coding: utf-8 -*-\n """Helpers for working with common Zope publisher operations\n """\n-from __future__ import absolute_import\n \n from plone.testing import Layer\n from plone.testing import security\ndiff --git a/src/plone/testing/security.py b/src/plone/testing/security.py\nindex a349456..4a4d7ab 100644\n--- a/src/plone/testing/security.py\n+++ b/src/plone/testing/security.py\n@@ -1,7 +1,5 @@\n-# -*- coding: utf-8 -*-\n """Security helpers and layers\n """\n-from __future__ import absolute_import\n \n from plone.testing import Layer\n \ndiff --git a/src/plone/testing/tests.py b/src/plone/testing/tests.py\nindex b177be2..7824144 100644\n--- a/src/plone/testing/tests.py\n+++ b/src/plone/testing/tests.py\n@@ -1,6 +1,3 @@\n-# -*- coding: utf-8 -*-\n-from __future__ import absolute_import\n-\n from OFS.SimpleItem import SimpleItem\n from pkg_resources import get_distribution\n from zope.testing import renormalizing\n@@ -34,19 +31,19 @@ def _canOutrunKlingons(warpDrive):\n return warpDrive.maxSpeed > 8.0\n \n \n-class DummyUtility(object):\n+class DummyUtility:\n \n def __repr__(self):\n return \'\'\n \n \n-class DummyView(object):\n+class DummyView:\n \n def __init__(self, context, request):\n pass\n \n def __call__(self):\n- return u\'\'\n+ return \'\'\n \n \n class DummyFile(SimpleItem):\ndiff --git a/src/plone/testing/z2.py b/src/plone/testing/z2.py\nindex 5852b5b..bfcd7e0 100644\n--- a/src/plone/testing/z2.py\n+++ b/src/plone/testing/z2.py\n@@ -1,6 +1,3 @@\n-# -*- coding: utf-8 -*-\n-from __future__ import absolute_import\n-\n from zope.deferredimport import deprecated\n \n import plone.testing\ndiff --git a/src/plone/testing/zca.py b/src/plone/testing/zca.py\nindex dc0cd9e..3d59777 100644\n--- a/src/plone/testing/zca.py\n+++ b/src/plone/testing/zca.py\n@@ -1,7 +1,5 @@\n-# -*- coding: utf-8 -*-\n """Core Zope Component Architecture helpers and layers\n """\n-from __future__ import absolute_import\n \n from plone.testing import Layer\n from zope.configuration.config import ConfigurationMachine\n@@ -80,7 +78,7 @@ def pushGlobalRegistry(new=None):\n lambda self: (loadRegistry, (self.__name__,)))\n \n if new is None:\n- name = \'test-stack-{0}\'.format(len(_REGISTRIES))\n+ name = f\'test-stack-{len(_REGISTRIES)}\'\n new = globalregistry.BaseGlobalComponents(name=name, bases=(current,))\n logger.debug(\n \'New component registry: %s based on %s\',\n@@ -157,13 +155,13 @@ def popGlobalRegistry():\n class NamedConfigurationMachine(ConfigurationMachine):\n \n def __init__(self, name):\n- super(NamedConfigurationMachine, self).__init__()\n+ super().__init__()\n self.__name__ = name\n \n def __str__(self):\n pkg = \'zope.configuration.config.ConfigurationMachine\'\n return (\n- \'<{0} object {1}>\'.format(\n+ \'<{} object {}>\'.format(\n pkg,\n self.__name__,\n )\n@@ -223,7 +221,7 @@ def stackConfigurationContext(context=None, name=\'not named\'):\n if adapterRegistration not in newRegistry._adapters:\n for interface, info in adapterRegistration.items():\n if Interface in info:\n- factory = info[Interface][u\'\']\n+ factory = info[Interface][\'\']\n newRegistry.register([interface], Interface, \'\',\n factory)\n \n@@ -325,13 +323,13 @@ class ZCMLSandbox(Layer):\n \n def __init__(self, bases=None, name=None, module=None, filename=None,\n package=None):\n- super(ZCMLSandbox, self).__init__(bases, name, module)\n+ super().__init__(bases, name, module)\n self.filename = filename\n self.package = package\n \n def setUp(self):\n name = self.__name__ if self.__name__ is not None else \'not-named\'\n- contextName = \'ZCMLSandbox-{0}\'.format(name)\n+ contextName = f\'ZCMLSandbox-{name}\'\n self[\'configurationContext\'] = stackConfigurationContext(\n self.get(\'configurationContext\'),\n name=contextName,\ndiff --git a/src/plone/testing/zodb.py b/src/plone/testing/zodb.py\nindex 1316291..f1bab8f 100644\n--- a/src/plone/testing/zodb.py\n+++ b/src/plone/testing/zodb.py\n@@ -1,4 +1,3 @@\n-# -*- coding: utf-8 -*-\n """ZODB-specific helpers and layers\n """\n from plone.testing import Layer\ndiff --git a/src/plone/testing/zope.py b/src/plone/testing/zope.py\nindex 040d4cc..5094442 100644\n--- a/src/plone/testing/zope.py\n+++ b/src/plone/testing/zope.py\n@@ -1,7 +1,5 @@\n-# -*- coding: utf-8 -*-\n """Zope-specific helpers and layers using WSGI\n """\n-from __future__ import absolute_import\n \n from OFS.metaconfigure import get_packages_to_initialize\n from plone.testing import Layer\n@@ -92,7 +90,7 @@ def installProduct(app, productName, quiet=False, multiinit=False):\n \n if not found and not quiet:\n sys.stderr.write(\n- \'Could not install product {0}\\n\'.format(productName))\n+ f\'Could not install product {productName}\\n\')\n sys.stderr.flush()\n \n \n@@ -144,7 +142,7 @@ def uninstallProduct(app, productName, quiet=False):\n \n if not found and not quiet:\n sys.stderr.write(\n- \'Could not install product {0}\\n\'.format(productName))\n+ f\'Could not install product {productName}\\n\')\n sys.stderr.flush()\n \n \n@@ -480,7 +478,7 @@ def setUpDatabase(self):\n # with regular traversal, which relies on a module-level ``DB``\n # variable.\n \n- class DBFacade(object):\n+ class DBFacade:\n \n def __init__(self, layer):\n self.__layer = layer\n@@ -955,7 +953,7 @@ def make_wsgi_app(self):\n def _get_zope_conf(self, dir):\n fd, path = tempfile.mkstemp(dir=dir)\n with os.fdopen(fd, \'w\') as zope_conf:\n- zope_conf.write(\'instancehome {0}\\n\'.format(os.path.dirname(dir)))\n+ zope_conf.write(f\'instancehome {os.path.dirname(dir)}\\n\')\n return path\n \n \ndiff --git a/src/plone/testing/zserver.py b/src/plone/testing/zserver.py\nindex 756ff06..4a16dbb 100644\n--- a/src/plone/testing/zserver.py\n+++ b/src/plone/testing/zserver.py\n@@ -1,7 +1,5 @@\n-# -*- coding: utf-8 -*-\n """Zope2-specific helpers and layers using ZServer\n """\n-from __future__ import absolute_import\n \n from plone.testing import Layer\n from plone.testing import zodb\n@@ -399,7 +397,7 @@ def setUp(self):\n self.setUpServer()\n \n self.thread = Thread(\n- name=\'{0} server\'.format(self.__name__),\n+ name=f\'{self.__name__} server\',\n target=self.runner,\n )\n \n' - -Repository: plone.testing +M src/plone/api/tests/test_content.py +b'diff --git a/src/plone/api/tests/test_content.py b/src/plone/api/tests/test_content.py\nindex b411306b..bff0436b 100644\n--- a/src/plone/api/tests/test_content.py\n+++ b/src/plone/api/tests/test_content.py\n@@ -1014,7 +1014,7 @@ def test_find_interface_dict(self):\n "operator": "and",\n },\n )\n- self.assertEqual(len(brains), 1)\n+ self.assertEqual(len(brains), 2)\n \n # plone.api query using interfaces\n brains = api.content.find(\n@@ -1042,7 +1042,7 @@ def test_find_interface_dict__include_not_query(self):\n },\n )\n \n- self.assertEqual(len(brains_all) - len(brains), 1)\n+ self.assertEqual(len(brains_all) - len(brains), 0)\n \n def test_find_interface_dict__all_options(self):\n """Check for all options in a object_provides query are correctly\n' -Branch: refs/heads/master -Date: 2023-10-15T19:09:56+02:00 -Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/plone.testing/commit/1b7305ac51a68aedb0a26b755e38a7bd740adf75 - -chore: black - -Files changed: -M setup.py -M src/plone/__init__.py -M src/plone/testing/_z2_testbrowser.py -M src/plone/testing/layer.py -M src/plone/testing/publisher.py -M src/plone/testing/security.py -M src/plone/testing/tests.py -M src/plone/testing/z2.py -M src/plone/testing/zca.py -M src/plone/testing/zodb.py -M src/plone/testing/zope.py -M src/plone/testing/zserver.py - -b'diff --git a/setup.py b/setup.py\nindex 355e85a..19ac686 100644\n--- a/setup.py\n+++ b/setup.py\n@@ -5,57 +5,62 @@\n import os.path\n \n \n-version = \'8.0.5.dev0\'\n+version = "8.0.5.dev0"\n \n install_requires = [\n- \'setuptools\',\n- \'six\',\n- \'zope.testing >= 3.8\',\n+ "setuptools",\n+ "six",\n+ "zope.testing >= 3.8",\n ]\n \n tests_require = [\n- \'WebTest\',\n- \'ZODB\',\n- \'Zope\',\n- \'zope.browsermenu\',\n- \'zope.browserpage\',\n- \'zope.browserresource\',\n- \'zope.component\',\n- \'zope.configuration\',\n- \'zope.event\',\n- \'zope.interface\',\n- \'zope.publisher\',\n- \'zope.security\',\n- \'zope.testbrowser\',\n- \'zope.testrunner\',\n+ "WebTest",\n+ "ZODB",\n+ "Zope",\n+ "zope.browsermenu",\n+ "zope.browserpage",\n+ "zope.browserresource",\n+ "zope.component",\n+ "zope.configuration",\n+ "zope.event",\n+ "zope.interface",\n+ "zope.publisher",\n+ "zope.security",\n+ "zope.testbrowser",\n+ "zope.testrunner",\n ]\n \n-zope_requires = [\n- \'WebTest\',\n- \'Zope\',\n- \'zope.component\',\n- \'zope.publisher\',\n- \'zope.testbrowser\',\n-],\n+zope_requires = (\n+ [\n+ "WebTest",\n+ "Zope",\n+ "zope.component",\n+ "zope.publisher",\n+ "zope.testbrowser",\n+ ],\n+)\n \n \n setup(\n- name=\'plone.testing\',\n+ name="plone.testing",\n version=version,\n description="Testing infrastructure for Zope and Plone projects.",\n- long_description=(\'\\n\\n\'.join([\n- open(os.path.join("src", "plone", "testing", "README.rst")).read(),\n- open("CHANGES.rst").read(),\n- "Detailed documentation\\n"\n- + "======================",\n- open(os.path.join("src", "plone", "testing", "layer.rst")).read(),\n- open(os.path.join("src", "plone", "testing", "zca.rst")).read(),\n- open(os.path.join("src", "plone", "testing", "security.rst")).read(),\n- open(os.path.join("src", "plone", "testing", "publisher.rst")).read(),\n- open(os.path.join("src", "plone", "testing", "zodb.rst")).read(),\n- open(os.path.join("src", "plone", "testing", "zope.rst")).read(),\n- open(os.path.join("src", "plone", "testing", "zserver.rst")).read(),\n- ])),\n+ long_description=(\n+ "\\n\\n".join(\n+ [\n+ open(os.path.join("src", "plone", "testing", "README.rst")).read(),\n+ open("CHANGES.rst").read(),\n+ "Detailed documentation\\n" + "======================",\n+ open(os.path.join("src", "plone", "testing", "layer.rst")).read(),\n+ open(os.path.join("src", "plone", "testing", "zca.rst")).read(),\n+ open(os.path.join("src", "plone", "testing", "security.rst")).read(),\n+ open(os.path.join("src", "plone", "testing", "publisher.rst")).read(),\n+ open(os.path.join("src", "plone", "testing", "zodb.rst")).read(),\n+ open(os.path.join("src", "plone", "testing", "zope.rst")).read(),\n+ open(os.path.join("src", "plone", "testing", "zserver.rst")).read(),\n+ ]\n+ )\n+ ),\n classifiers=[\n "Development Status :: 5 - Production/Stable",\n "Environment :: Web Environment",\n@@ -76,41 +81,41 @@\n "Topic :: Internet :: WWW/HTTP :: Dynamic Content",\n "Topic :: Software Development :: Testing",\n ],\n- keywords=\'plone zope testing\',\n- author=\'Plone Foundation\',\n- author_email=\'plone-developers@lists.sourceforge.net\',\n- url=\'https://github.com/plone/plone.testing\',\n- license=\'BSD\',\n- packages=find_packages(\'src\'),\n- package_dir={\'\': \'src\'},\n- namespace_packages=[\'plone\'],\n+ keywords="plone zope testing",\n+ author="Plone Foundation",\n+ author_email="plone-developers@lists.sourceforge.net",\n+ url="https://github.com/plone/plone.testing",\n+ license="BSD",\n+ packages=find_packages("src"),\n+ package_dir={"": "src"},\n+ namespace_packages=["plone"],\n include_package_data=True,\n zip_safe=False,\n install_requires=install_requires,\n tests_require=tests_require,\n extras_require={\n- \'test\': tests_require,\n- \'zodb\': [\'ZODB\'],\n- \'zca\': [\n- \'zope.component\',\n- \'zope.configuration\',\n- \'zope.event\',\n+ "test": tests_require,\n+ "zodb": ["ZODB"],\n+ "zca": [\n+ "zope.component",\n+ "zope.configuration",\n+ "zope.event",\n ],\n- \'security\': [\n- \'zope.security\',\n+ "security": [\n+ "zope.security",\n ],\n- \'publisher\': [\n- \'zope.browsermenu\',\n- \'zope.browserpage\',\n- \'zope.browserresource\',\n- \'zope.configuration\',\n- \'zope.publisher\',\n- \'zope.security\',\n+ "publisher": [\n+ "zope.browsermenu",\n+ "zope.browserpage",\n+ "zope.browserresource",\n+ "zope.configuration",\n+ "zope.publisher",\n+ "zope.security",\n ],\n- \'z2\': [], # BBB\n- \'zope\': zope_requires,\n- \'zserver\': [\n- \'ZServer\',\n+ "z2": [], # BBB\n+ "zope": zope_requires,\n+ "zserver": [\n+ "ZServer",\n ],\n },\n )\ndiff --git a/src/plone/__init__.py b/src/plone/__init__.py\nindex de40ea7..5284146 100644\n--- a/src/plone/__init__.py\n+++ b/src/plone/__init__.py\n@@ -1 +1 @@\n-__import__(\'pkg_resources\').declare_namespace(__name__)\n+__import__("pkg_resources").declare_namespace(__name__)\ndiff --git a/src/plone/testing/_z2_testbrowser.py b/src/plone/testing/_z2_testbrowser.py\nindex 2d5fe32..fa3948f 100644\n--- a/src/plone/testing/_z2_testbrowser.py\n+++ b/src/plone/testing/_z2_testbrowser.py\n@@ -6,7 +6,7 @@\n import re\n \n \n-BASIC_RE = re.compile(\'Basic (.+)?:(.+)?$\')\n+BASIC_RE = re.compile("Basic (.+)?:(.+)?$")\n \n \n def authHeader(header):\n@@ -14,9 +14,9 @@ def authHeader(header):\n if match:\n u, p = match.group(1, 2)\n if u is None:\n- u = \'\'\n+ u = ""\n if p is None:\n- p = \'\'\n+ p = ""\n return basic_auth_encode(u, p)\n return header\n \n@@ -37,6 +37,7 @@ def wrapped_func(*args, **kw):\n finally:\n setSecurityManager(sm)\n setSite(site)\n+\n return wrapped_func\n \n \n@@ -51,9 +52,8 @@ def __init__(self, browser, app):\n \n @saveState\n def __call__(self, environ, start_response):\n-\n # Base64 encode auth header\n- http_auth = \'HTTP_AUTHORIZATION\'\n+ http_auth = "HTTP_AUTHORIZATION"\n if http_auth in environ:\n environ[http_auth] = authHeader(environ[http_auth])\n \n@@ -80,4 +80,4 @@ def __init__(self, app, url=None):\n \n \n # Add `nohost` to testbrowser\'s set of allowed hosts\n-browser._allowed.add(\'nohost\')\n+browser._allowed.add("nohost")\ndiff --git a/src/plone/testing/layer.py b/src/plone/testing/layer.py\nindex 0be5445..e27fbef 100644\n--- a/src/plone/testing/layer.py\n+++ b/src/plone/testing/layer.py\n@@ -5,8 +5,7 @@\n \n \n class ResourceManager:\n- """Mixin class for resource managers.\n- """\n+ """Mixin class for resource managers."""\n \n __bases__ = () # must be set as an instance variable by subclass\n \n@@ -16,7 +15,7 @@ def __init__(self):\n \n def get(self, key, default=None):\n for resourceManager in self.baseResolutionOrder:\n- if key in getattr(resourceManager, \'_resources\', {}):\n+ if key in getattr(resourceManager, "_resources", {}):\n # Get the value on the top of the stack\n return resourceManager._resources[key][-1][0]\n return default\n@@ -36,14 +35,13 @@ def __setitem__(self, key, value):\n foundStack = False\n \n for resourceManager in self.baseResolutionOrder:\n- if key in getattr(resourceManager, \'_resources\', {}):\n+ if key in getattr(resourceManager, "_resources", {}):\n stack = resourceManager._resources[key]\n foundStack = True\n \n foundStackItem = False\n for idx in range(len(stack) - 1, -1, -1):\n if stack[idx][1] is self:\n-\n # This layer instance has already added an item to\n # the stack. Update that item instead of pushing a new\n # item onto the stack.\n@@ -55,7 +53,12 @@ def __setitem__(self, key, value):\n # This layer instance does not have a stack item yet. Create\n # a new one.\n if not foundStackItem:\n- stack.append([value, self, ])\n+ stack.append(\n+ [\n+ value,\n+ self,\n+ ]\n+ )\n \n # Note: We do not break here on purpose: it\'s possible\n # that there is resource stack in another branch of the base\n@@ -68,7 +71,7 @@ def __setitem__(self, key, value):\n def __delitem__(self, key):\n found = False\n for resourceManager in self.baseResolutionOrder:\n- if key in getattr(resourceManager, \'_resources\', {}):\n+ if key in getattr(resourceManager, "_resources", {}):\n stack = resourceManager._resources[key]\n for idx in range(len(stack) - 1, -1, -1):\n if stack[idx][1] is self:\n@@ -92,7 +95,6 @@ def __delitem__(self, key):\n # http://www.python.org/download/releases/2.3/mro/\n \n def _mergeResourceManagers(self, seqs):\n-\n res = []\n i = 0\n \n@@ -113,7 +115,7 @@ def _mergeResourceManagers(self, seqs):\n break\n \n if not cand:\n- raise TypeError(\'Inconsistent layer hierarchy!\')\n+ raise TypeError("Inconsistent layer hierarchy!")\n \n res.append(cand)\n for seq in nonemptyseqs: # remove cand\n@@ -129,8 +131,7 @@ def _resourceResolutionOrder(self, instance):\n \n \n class Layer(ResourceManager):\n- """A base class for layers.\n- """\n+ """A base class for layers."""\n \n # Set this at the class level to a tuple of layer *instances* to treat\n # as bases for this layer. This may be overridden by passing a tuple\n@@ -155,10 +156,14 @@ def __init__(self, bases=None, name=None, module=None):\n """\n \n if self.__class__ is Layer and name is None:\n- raise ValueError(\'The `name` argument is required when instantiating `Layer` directly\') # NOQA: E501\n+ raise ValueError(\n+ "The `name` argument is required when instantiating `Layer` directly"\n+ ) # NOQA: E501\n \n if name is None and bases is not None:\n- raise ValueError(\'The `name`` argument is required when overriding bases with the `bases` argument\') # NOQA: E501\n+ raise ValueError(\n+ "The `name`` argument is required when overriding bases with the `bases` argument"\n+ ) # NOQA: E501\n \n super().__init__()\n \n@@ -167,21 +172,27 @@ def __init__(self, bases=None, name=None, module=None):\n \n try:\n self.__bases__ = tuple(bases)\n- except (KeyError, TypeError,):\n- raise ValueError(\'The `bases` argument must be a sequence.\')\n+ except (\n+ KeyError,\n+ TypeError,\n+ ):\n+ raise ValueError("The `bases` argument must be a sequence.")\n \n if name is None:\n name = self.__class__.__name__\n self.__name__ = name\n \n if module is None:\n-\n # Get the module name of whatever instantiated the layer, not\n # the class, by default\n \n try:\n- module = sys._getframe(1).f_globals[\'__name__\']\n- except (ValueError, AttributeError, KeyError,):\n+ module = sys._getframe(1).f_globals["__name__"]\n+ except (\n+ ValueError,\n+ AttributeError,\n+ KeyError,\n+ ):\n module = self.__class__.__module__\n \n self.__module__ = module\n@@ -222,7 +233,7 @@ def layered(suite, layer, addLayerToDoctestGlobs=True):\n except AttributeError:\n pass\n else:\n- if \'layer\' not in globs:\n- globs[\'layer\'] = layer\n+ if "layer" not in globs:\n+ globs["layer"] = layer\n \n return suite\ndiff --git a/src/plone/testing/publisher.py b/src/plone/testing/publisher.py\nindex da6fc32..fadb909 100644\n--- a/src/plone/testing/publisher.py\n+++ b/src/plone/testing/publisher.py\n@@ -22,30 +22,31 @@ def setUp(self):\n from zope.configuration import xmlconfig\n \n # Stack a new configuration context\n- self[\'configurationContext\'] = context = zca.stackConfigurationContext(\n- self.get(\'configurationContext\'))\n+ self["configurationContext"] = context = zca.stackConfigurationContext(\n+ self.get("configurationContext")\n+ )\n \n # D001 requests to use self.loadZCML instead of xmlconfig.file but\n # loadZCML is defined in `plone.app.testing` and cannot be used here.\n import zope.security\n- xmlconfig.file( # noqa: D001\n- \'meta.zcml\', zope.security, context=context)\n+\n+ xmlconfig.file("meta.zcml", zope.security, context=context) # noqa: D001\n import zope.browsermenu\n- xmlconfig.file( # noqa: D001\n- \'meta.zcml\', zope.browsermenu, context=context)\n+\n+ xmlconfig.file("meta.zcml", zope.browsermenu, context=context) # noqa: D001\n import zope.browserpage\n- xmlconfig.file( # noqa: D001\n- \'meta.zcml\', zope.browserpage, context=context)\n+\n+ xmlconfig.file("meta.zcml", zope.browserpage, context=context) # noqa: D001\n import zope.browserresource\n- xmlconfig.file( # noqa: D001\n- \'meta.zcml\', zope.browserresource, context=context)\n+\n+ xmlconfig.file("meta.zcml", zope.browserresource, context=context) # noqa: D001\n import zope.publisher\n- xmlconfig.file( # noqa: D001\n- \'meta.zcml\', zope.publisher, context=context)\n+\n+ xmlconfig.file("meta.zcml", zope.publisher, context=context) # noqa: D001\n \n def tearDown(self):\n # Zap the stacked configuration context\n- del self[\'configurationContext\']\n+ del self["configurationContext"]\n \n \n PUBLISHER_DIRECTIVES = PublisherDirectives()\ndiff --git a/src/plone/testing/security.py b/src/plone/testing/security.py\nindex 4a4d7ab..c2d5422 100644\n--- a/src/plone/testing/security.py\n+++ b/src/plone/testing/security.py\n@@ -35,8 +35,7 @@ def popCheckers():\n \n \n class Checkers(Layer):\n- """Ensures correct isolation of security checkers in zope.security.\n- """\n+ """Ensures correct isolation of security checkers in zope.security."""\n \n defaultBases = ()\n \ndiff --git a/src/plone/testing/tests.py b/src/plone/testing/tests.py\nindex 7824144..e8fe6d9 100644\n--- a/src/plone/testing/tests.py\n+++ b/src/plone/testing/tests.py\n@@ -32,30 +32,27 @@ def _canOutrunKlingons(warpDrive):\n \n \n class DummyUtility:\n-\n def __repr__(self):\n- return \'\'\n+ return ""\n \n \n class DummyView:\n-\n def __init__(self, context, request):\n pass\n \n def __call__(self):\n- return \'\'\n+ return ""\n \n \n class DummyFile(SimpleItem):\n-\n def __call__(self):\n- path = get_distribution(\'plone.testing\').location\n- path = os.path.join(path, \'plone\', \'testing\', \'zope.rst\')\n+ path = get_distribution("plone.testing").location\n+ path = os.path.join(path, "plone", "testing", "zope.rst")\n \n request = self.REQUEST\n response = request.response\n- response.setHeader(\'Content-Type\', \'text/plain\')\n- response.setHeader(\'Content-Length\', os.path.getsize(path))\n+ response.setHeader("Content-Type", "text/plain")\n+ response.setHeader("Content-Length", os.path.getsize(path))\n return filestream_iterator(path)\n \n \n@@ -67,21 +64,24 @@ def tearDown(self):\n zope.component.testing.tearDown()\n \n \n-checker = renormalizing.RENormalizing([\n- # normalize py2 output to py3\n- (re.compile(r\'__builtin__\'), r\'builtins\'),\n- (re.compile(\n- r"\'Unknown directive\', u\'http://namespaces.zope.org/zope\', u\'"),\n- r"\'Unknown directive\', \'http://namespaces.zope.org/zope\', \'"),\n-\n- # normalize py3 output to py2\n- (re.compile(\n- r\'zope\\.configuration\\.xmlconfig\\.ZopeXMLConfigurationError\'),\n- r\'ZopeXMLConfigurationError\'),\n- (re.compile(r\'builtins\\.PopulatedZODB\'), r\'PopulatedZODB\'),\n- (re.compile(r\'builtins\\.ExpandedZODB\'), r\'ExpandedZODB\'),\n- (re.compile(r\'urllib\\.error\\.URLError\'), r\'URLError\'),\n-])\n+checker = renormalizing.RENormalizing(\n+ [\n+ # normalize py2 output to py3\n+ (re.compile(r"__builtin__"), r"builtins"),\n+ (\n+ re.compile(r"\'Unknown directive\', u\'http://namespaces.zope.org/zope\', u\'"),\n+ r"\'Unknown directive\', \'http://namespaces.zope.org/zope\', \'",\n+ ),\n+ # normalize py3 output to py2\n+ (\n+ re.compile(r"zope\\.configuration\\.xmlconfig\\.ZopeXMLConfigurationError"),\n+ r"ZopeXMLConfigurationError",\n+ ),\n+ (re.compile(r"builtins\\.PopulatedZODB"), r"PopulatedZODB"),\n+ (re.compile(r"builtins\\.ExpandedZODB"), r"ExpandedZODB"),\n+ (re.compile(r"urllib\\.error\\.URLError"), r"URLError"),\n+ ]\n+)\n \n \n class TestZ2(unittest.TestCase):\n@@ -90,40 +90,47 @@ class TestZ2(unittest.TestCase):\n def test_z2(self):\n """It can be imported. (It contains only BBB imports.)"""\n import plone.testing.z2\n+\n self.assertIsNotNone(plone.testing.z2.ZSERVER)\n \n \n def test_suite():\n suite = unittest.TestSuite()\n- suite.addTests([\n- doctest.DocFileSuite(\n- \'layer.rst\',\n- \'zca.rst\',\n- \'security.rst\',\n- \'publisher.rst\',\n- \'zodb.rst\',\n- \'zope.rst\',\n- checker=checker,\n- setUp=setUp,\n- tearDown=tearDown,\n- optionflags=doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE,\n- ),\n- doctest.DocFileSuite(\n- \'README.rst\',\n- globs={\'canOutrunKlingons\': _canOutrunKlingons, },\n- setUp=setUp,\n- tearDown=tearDown,\n- optionflags=doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE,\n- ),\n- ])\n- if HAS_ZSERVER:\n- suite.addTests([\n+ suite.addTests(\n+ [\n+ doctest.DocFileSuite(\n+ "layer.rst",\n+ "zca.rst",\n+ "security.rst",\n+ "publisher.rst",\n+ "zodb.rst",\n+ "zope.rst",\n+ checker=checker,\n+ setUp=setUp,\n+ tearDown=tearDown,\n+ optionflags=doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE,\n+ ),\n doctest.DocFileSuite(\n- \'zserver.rst\',\n+ "README.rst",\n+ globs={\n+ "canOutrunKlingons": _canOutrunKlingons,\n+ },\n setUp=setUp,\n tearDown=tearDown,\n optionflags=doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE,\n ),\n- unittest.TestLoader().loadTestsFromTestCase(TestZ2),\n- ])\n+ ]\n+ )\n+ if HAS_ZSERVER:\n+ suite.addTests(\n+ [\n+ doctest.DocFileSuite(\n+ "zserver.rst",\n+ setUp=setUp,\n+ tearDown=tearDown,\n+ optionflags=doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE,\n+ ),\n+ unittest.TestLoader().loadTestsFromTestCase(TestZ2),\n+ ]\n+ )\n return suite\ndiff --git a/src/plone/testing/z2.py b/src/plone/testing/z2.py\nindex bfcd7e0..2d6eac0 100644\n--- a/src/plone/testing/z2.py\n+++ b/src/plone/testing/z2.py\n@@ -6,32 +6,32 @@\n \n \n deprecated(\n- \'Please import from plone.testing.zope.\',\n- Browser=\'plone.testing.zope:Browser\',\n- TestIsolationBroken=\'plone.testing.zope:TestIsolationBroken\',\n- installProduct=\'plone.testing.zope:installProduct\',\n- uninstallProduct=\'plone.testing.zope:uninstallProduct\',\n- login=\'plone.testing.zope:login\',\n- logout=\'plone.testing.zope:logout\',\n- setRoles=\'plone.testing.zope:setRoles\',\n- makeTestRequest=\'plone.testing.zope:makeTestRequest\',\n- addRequestContainer=\'plone.testing.zope:addRequestContainer\',\n- zopeApp=\'plone.testing.zope:zopeApp\',\n- Startup=\'plone.testing.zope:Startup\',\n- STARTUP=\'plone.testing.zope:STARTUP\',\n- IntegrationTesting=\'plone.testing.zope:IntegrationTesting\',\n- INTEGRATION_TESTING=\'plone.testing.zope:INTEGRATION_TESTING\',\n- FunctionalTesting=\'plone.testing.zope:FunctionalTesting\',\n- FUNCTIONAL_TESTING=\'plone.testing.zope:FUNCTIONAL_TESTING\',\n- ZServer=\'plone.testing.zope:WSGIServer\',\n- ZSERVER_FIXTURE=\'plone.testing.zope:WSGI_SERVER_FIXTURE\',\n- ZSERVER=\'plone.testing.zope:WSGI_SERVER\',\n+ "Please import from plone.testing.zope.",\n+ Browser="plone.testing.zope:Browser",\n+ TestIsolationBroken="plone.testing.zope:TestIsolationBroken",\n+ installProduct="plone.testing.zope:installProduct",\n+ uninstallProduct="plone.testing.zope:uninstallProduct",\n+ login="plone.testing.zope:login",\n+ logout="plone.testing.zope:logout",\n+ setRoles="plone.testing.zope:setRoles",\n+ makeTestRequest="plone.testing.zope:makeTestRequest",\n+ addRequestContainer="plone.testing.zope:addRequestContainer",\n+ zopeApp="plone.testing.zope:zopeApp",\n+ Startup="plone.testing.zope:Startup",\n+ STARTUP="plone.testing.zope:STARTUP",\n+ IntegrationTesting="plone.testing.zope:IntegrationTesting",\n+ INTEGRATION_TESTING="plone.testing.zope:INTEGRATION_TESTING",\n+ FunctionalTesting="plone.testing.zope:FunctionalTesting",\n+ FUNCTIONAL_TESTING="plone.testing.zope:FUNCTIONAL_TESTING",\n+ ZServer="plone.testing.zope:WSGIServer",\n+ ZSERVER_FIXTURE="plone.testing.zope:WSGI_SERVER_FIXTURE",\n+ ZSERVER="plone.testing.zope:WSGI_SERVER",\n )\n \n \n deprecated(\n- \'Please import from plone.testing.\',\n- Layer=\'plone.testing:Layer\',\n+ "Please import from plone.testing.",\n+ Layer="plone.testing:Layer",\n )\n \n \n@@ -40,15 +40,14 @@ class FTPServer(plone.testing.Layer):\n \n def setUp(self):\n warnings.warn(\n- \'The FTPServer layer is now only a no-op as FTP is not supported\'\n- \' by WSGI. If you really need the fixture import it from\'\n- \' plone.testing.zserver.\')\n+ "The FTPServer layer is now only a no-op as FTP is not supported"\n+ " by WSGI. If you really need the fixture import it from"\n+ " plone.testing.zserver."\n+ )\n \n \n FTP_SERVER_FIXTURE = FTPServer()\n \n FTP_SERVER = plone.testing.zope.FunctionalTesting(\n- bases=(\n- FTP_SERVER_FIXTURE,\n- ),\n- name=\'No-OpFTPServer:Functional\')\n+ bases=(FTP_SERVER_FIXTURE,), name="No-OpFTPServer:Functional"\n+)\ndiff --git a/src/plone/testing/zca.py b/src/plone/testing/zca.py\nindex 3d59777..ee9f266 100644\n--- a/src/plone/testing/zca.py\n+++ b/src/plone/testing/zca.py\n@@ -7,15 +7,14 @@\n import logging\n \n \n-logger = logging.getLogger(\'plone.testing.zca\')\n+logger = logging.getLogger("plone.testing.zca")\n \n # Contains a stack of installed global registries (but not the default one)\n _REGISTRIES = []\n \n \n def loadRegistry(name):\n- """Unpickling helper\n- """\n+ """Unpickling helper"""\n for reg in reversed(_REGISTRIES):\n if reg.__name__ == name:\n return reg\n@@ -26,7 +25,7 @@ def _hookRegistry(reg):\n from zope.component import _api\n from zope.component import globalregistry\n \n- logger.debug(\'Hook component registry: %s\', reg.__name__)\n+ logger.debug("Hook component registry: %s", reg.__name__)\n \n _api.base = reg\n globalregistry.base = reg\n@@ -35,6 +34,7 @@ def _hookRegistry(reg):\n # Set the default global site manager for new threads when zope.component\n # hooks are in place\n from zope.component.hooks import SiteInfo\n+\n SiteInfo.sm = reg\n \n # Set the five.localsitemanager hook, too, if applicable\n@@ -48,6 +48,7 @@ def _hookRegistry(reg):\n \n # Helper functions\n \n+\n def pushGlobalRegistry(new=None):\n """Set a new global component registry that uses the current registry as\n a a base. If you use this, you *must* call ``popGlobalRegistry()`` to\n@@ -73,19 +74,19 @@ def pushGlobalRegistry(new=None):\n if len(_REGISTRIES) == 0:\n _REGISTRIES.append(current)\n globalregistry.BaseGlobalComponents._old__reduce__ = (\n- globalregistry.BaseGlobalComponents.__reduce__)\n- globalregistry.BaseGlobalComponents.__reduce__ = (\n- lambda self: (loadRegistry, (self.__name__,)))\n+ globalregistry.BaseGlobalComponents.__reduce__\n+ )\n+ globalregistry.BaseGlobalComponents.__reduce__ = lambda self: (\n+ loadRegistry,\n+ (self.__name__,),\n+ )\n \n if new is None:\n- name = f\'test-stack-{len(_REGISTRIES)}\'\n+ name = f"test-stack-{len(_REGISTRIES)}"\n new = globalregistry.BaseGlobalComponents(name=name, bases=(current,))\n- logger.debug(\n- \'New component registry: %s based on %s\',\n- name,\n- current.__name__)\n+ logger.debug("New component registry: %s based on %s", name, current.__name__)\n else:\n- logger.debug(\'Push component registry: %s\', new.__name__)\n+ logger.debug("Push component registry: %s", new.__name__)\n \n _REGISTRIES.append(new)\n \n@@ -96,6 +97,7 @@ def pushGlobalRegistry(new=None):\n # Reset the site manager hook so that getSiteManager() returns the base\n # again\n from zope.component import getSiteManager\n+\n getSiteManager.reset()\n \n try:\n@@ -118,8 +120,7 @@ def popGlobalRegistry():\n from zope.component import globalregistry\n \n if not _REGISTRIES or not _REGISTRIES[-1] is globalregistry.base:\n- msg = (\'popGlobalRegistry() called out of sync with \'\n- \'pushGlobalRegistry()\')\n+ msg = "popGlobalRegistry() called out of sync with " "pushGlobalRegistry()"\n raise ValueError(msg)\n \n current = _REGISTRIES.pop()\n@@ -131,13 +132,15 @@ def popGlobalRegistry():\n assert _REGISTRIES[0] is previous\n _REGISTRIES.pop()\n globalregistry.BaseGlobalComponents.__reduce__ = (\n- globalregistry.BaseGlobalComponents._old__reduce__)\n+ globalregistry.BaseGlobalComponents._old__reduce__\n+ )\n \n _hookRegistry(previous)\n \n # Reset the site manager hook so that getSiteManager() returns the base\n # again\n from zope.component import getSiteManager\n+\n getSiteManager.reset()\n \n try:\n@@ -153,25 +156,22 @@ def popGlobalRegistry():\n \n \n class NamedConfigurationMachine(ConfigurationMachine):\n-\n def __init__(self, name):\n super().__init__()\n self.__name__ = name\n \n def __str__(self):\n- pkg = \'zope.configuration.config.ConfigurationMachine\'\n- return (\n- \'<{} object {}>\'.format(\n- pkg,\n- self.__name__,\n- )\n+ pkg = "zope.configuration.config.ConfigurationMachine"\n+ return "<{} object {}>".format(\n+ pkg,\n+ self.__name__,\n )\n \n def __repr__(self):\n return self.__str__()\n \n \n-def stackConfigurationContext(context=None, name=\'not named\'):\n+def stackConfigurationContext(context=None, name="not named"):\n """Return a new ``ConfigurationMachine`` configuration context that\n is a clone of the passed-in context. If no context is passed in, a fresh\n configuration context is returned.\n@@ -190,7 +190,7 @@ def stackConfigurationContext(context=None, name=\'not named\'):\n \n if context is None:\n registerCommonDirectives(clone)\n- logger.debug(\'New configuration context %s\', clone)\n+ logger.debug("New configuration context %s", clone)\n return clone\n \n # Copy over simple attributes\n@@ -212,7 +212,7 @@ def stackConfigurationContext(context=None, name=\'not named\'):\n # ZCML file processing only\n \n # Copy over documentation registry\n- clone._docRegistry = [tuple(list(entry))for entry in context._docRegistry]\n+ clone._docRegistry = [tuple(list(entry)) for entry in context._docRegistry]\n \n # Copy over the directive registry\n for key, registry in context._registry.items():\n@@ -221,16 +221,16 @@ def stackConfigurationContext(context=None, name=\'not named\'):\n if adapterRegistration not in newRegistry._adapters:\n for interface, info in adapterRegistration.items():\n if Interface in info:\n- factory = info[Interface][\'\']\n- newRegistry.register([interface], Interface, \'\',\n- factory)\n+ factory = info[Interface][""]\n+ newRegistry.register([interface], Interface, "", factory)\n \n- logger.debug(\'Configuration context %s cloned from %s\', clone, context)\n+ logger.debug("Configuration context %s cloned from %s", clone, context)\n return clone\n \n \n # Layers\n \n+\n class UnitTesting(Layer):\n """Zope Component Architecture unit testing sandbox: The ZCA is cleared\n for each test and torn down after each test.\n@@ -240,10 +240,12 @@ class UnitTesting(Layer):\n \n def testSetUp(self):\n import zope.component.testing\n+\n zope.component.testing.setUp()\n \n def testTearDown(self):\n import zope.component.testing\n+\n zope.component.testing.tearDown()\n \n \n@@ -263,6 +265,7 @@ class EventTesting(Layer):\n \n def testSetUp(self):\n import zope.component.eventtesting\n+\n zope.component.eventtesting.setUp()\n \n \n@@ -278,10 +281,12 @@ class LayerCleanup(Layer):\n \n def setUp(self):\n import zope.testing.cleanup\n+\n zope.testing.cleanup.cleanUp()\n \n def tearDown(self):\n import zope.testing.cleanup\n+\n zope.testing.cleanup.cleanUp()\n \n \n@@ -298,40 +303,37 @@ class ZCMLDirectives(Layer):\n defaultBases = (LAYER_CLEANUP,)\n \n def setUp(self):\n-\n from zope.configuration import xmlconfig\n \n import zope.component\n \n- self[\'configurationContext\'] = context = stackConfigurationContext(\n- self.get(\'configurationContext\'))\n+ self["configurationContext"] = context = stackConfigurationContext(\n+ self.get("configurationContext")\n+ )\n # D001 requests to use self.loadZCML instead of xmlconfig.file but\n # loadZCML is defined in `plone.app.testing` and cannot be used here.\n- xmlconfig.file( # noqa: D001\n- \'meta.zcml\', zope.component, context=context)\n+ xmlconfig.file("meta.zcml", zope.component, context=context) # noqa: D001\n \n def tearDown(self):\n- del self[\'configurationContext\']\n+ del self["configurationContext"]\n \n \n ZCML_DIRECTIVES = ZCMLDirectives()\n \n \n class ZCMLSandbox(Layer):\n-\n defaultBases = (LAYER_CLEANUP,)\n \n- def __init__(self, bases=None, name=None, module=None, filename=None,\n- package=None):\n+ def __init__(self, bases=None, name=None, module=None, filename=None, package=None):\n super().__init__(bases, name, module)\n self.filename = filename\n self.package = package\n \n def setUp(self):\n- name = self.__name__ if self.__name__ is not None else \'not-named\'\n- contextName = f\'ZCMLSandbox-{name}\'\n- self[\'configurationContext\'] = stackConfigurationContext(\n- self.get(\'configurationContext\'),\n+ name = self.__name__ if self.__name__ is not None else "not-named"\n+ contextName = f"ZCMLSandbox-{name}"\n+ self["configurationContext"] = stackConfigurationContext(\n+ self.get("configurationContext"),\n name=contextName,\n )\n pushGlobalRegistry()\n@@ -339,16 +341,20 @@ def setUp(self):\n \n def setUpZCMLFiles(self):\n if self.filename is None:\n- raise ValueError(\'ZCML file name has not been provided.\')\n+ raise ValueError("ZCML file name has not been provided.")\n if self.package is None:\n- raise ValueError(\'The package that contains the ZCML file \'\n- \'has not been provided.\')\n+ raise ValueError(\n+ "The package that contains the ZCML file " "has not been provided."\n+ )\n self.loadZCMLFile(self.filename, self.package)\n \n def loadZCMLFile(self, filename, package):\n from zope.configuration import xmlconfig\n- xmlconfig.file(filename, package, context=self[\'configurationContext\']) # noqa: D001,E501\n+\n+ xmlconfig.file(\n+ filename, package, context=self["configurationContext"]\n+ ) # noqa: D001,E501\n \n def tearDown(self):\n popGlobalRegistry()\n- del self[\'configurationContext\']\n+ del self["configurationContext"]\ndiff --git a/src/plone/testing/zodb.py b/src/plone/testing/zodb.py\nindex f1bab8f..eb62ac8 100644\n--- a/src/plone/testing/zodb.py\n+++ b/src/plone/testing/zodb.py\n@@ -48,27 +48,29 @@ class EmptyZODB(Layer):\n defaultBases = ()\n \n def setUp(self):\n- self[\'zodbDB\'] = self.createDatabase(self.createStorage())\n+ self["zodbDB"] = self.createDatabase(self.createStorage())\n \n def tearDown(self):\n- self[\'zodbDB\'].close()\n- del self[\'zodbDB\']\n+ self["zodbDB"].close()\n+ del self["zodbDB"]\n \n def testSetUp(self):\n- self[\'zodbConnection\'] = connection = self[\'zodbDB\'].open()\n- self[\'zodbRoot\'] = connection.root()\n+ self["zodbConnection"] = connection = self["zodbDB"].open()\n+ self["zodbRoot"] = connection.root()\n \n import transaction\n+\n transaction.begin()\n \n def testTearDown(self):\n import transaction\n+\n transaction.abort()\n \n- self[\'zodbConnection\'].close()\n+ self["zodbConnection"].close()\n \n- del self[\'zodbConnection\']\n- del self[\'zodbRoot\']\n+ del self["zodbConnection"]\n+ del self["zodbRoot"]\n \n # Template methods for use in subclasses, if required\n \n@@ -81,7 +83,8 @@ def createStorage(self):\n """\n \n from ZODB.DemoStorage import DemoStorage\n- return DemoStorage(name=\'EmptyZODB\')\n+\n+ return DemoStorage(name="EmptyZODB")\n \n def createDatabase(self, storage):\n """Create a new database from the given storage.\n@@ -91,6 +94,7 @@ def createDatabase(self, storage):\n """\n \n from ZODB.DB import DB\n+\n return DB(storage)\n \n \ndiff --git a/src/plone/testing/zope.py b/src/plone/testing/zope.py\nindex 5094442..572f512 100644\n--- a/src/plone/testing/zope.py\n+++ b/src/plone/testing/zope.py\n@@ -54,17 +54,12 @@ def installProduct(app, productName, quiet=False, multiinit=False):\n if productName in _INSTALLED_PRODUCTS:\n return\n \n- if productName.startswith(\'Products.\'):\n+ if productName.startswith("Products."):\n for priority, name, index, productDir in get_products():\n- if (\'Products.\' + name) == productName:\n-\n+ if ("Products." + name) == productName:\n install_product(\n- app,\n- productDir,\n- name,\n- [],\n- get_folder_permissions(),\n- raise_exc=1)\n+ app, productDir, name, [], get_folder_permissions(), raise_exc=1\n+ )\n InitializeClass(Folder)\n \n _INSTALLED_PRODUCTS[productName] = (\n@@ -82,15 +77,17 @@ def installProduct(app, productName, quiet=False, multiinit=False):\n for module, init_func in packages:\n if module.__name__ == productName:\n install_package(app, module, init_func, raise_exc=1)\n- _INSTALLED_PRODUCTS[productName] = (module, init_func,)\n+ _INSTALLED_PRODUCTS[productName] = (\n+ module,\n+ init_func,\n+ )\n \n found = True\n if not multiinit:\n break\n \n if not found and not quiet:\n- sys.stderr.write(\n- f\'Could not install product {productName}\\n\')\n+ sys.stderr.write(f"Could not install product {productName}\\n")\n sys.stderr.flush()\n \n \n@@ -114,10 +111,9 @@ def uninstallProduct(app, productName, quiet=False):\n if productName not in _INSTALLED_PRODUCTS:\n return\n \n- if productName.startswith(\'Products.\'):\n+ if productName.startswith("Products."):\n for priority, name, index, productDir in get_products():\n- if (\'Products.\' + name) == productName:\n-\n+ if ("Products." + name) == productName:\n if name in Application.misc_.__dict__:\n delattr(Application.misc_, name)\n \n@@ -129,7 +125,6 @@ def uninstallProduct(app, productName, quiet=False):\n found = True\n break\n elif productName in _INSTALLED_PRODUCTS: # must be a package\n-\n module, init_func = _INSTALLED_PRODUCTS[productName]\n name = module.__name__\n \n@@ -141,40 +136,38 @@ def uninstallProduct(app, productName, quiet=False):\n del _INSTALLED_PRODUCTS[productName]\n \n if not found and not quiet:\n- sys.stderr.write(\n- f\'Could not install product {productName}\\n\')\n+ sys.stderr.write(f"Could not install product {productName}\\n")\n sys.stderr.flush()\n \n \n def login(userFolder, userName):\n- """Log in as the given user in the given user folder.\n- """\n+ """Log in as the given user in the given user folder."""\n \n from AccessControl.SecurityManagement import newSecurityManager\n \n user = userFolder.getUser(userName)\n if user is None:\n- raise ValueError(\'User could not be found\')\n- if getattr(user, \'aq_base\', None) is None:\n+ raise ValueError("User could not be found")\n+ if getattr(user, "aq_base", None) is None:\n user = user.__of__(userFolder)\n newSecurityManager(None, user)\n \n \n def logout():\n- """Log out, i.e. become anonymous\n- """\n+ """Log out, i.e. become anonymous"""\n \n from AccessControl.SecurityManagement import noSecurityManager\n+\n noSecurityManager()\n \n \n def setRoles(userFolder, userId, roles):\n- """Set the given user\'s roles to a tuple of roles.\n- """\n+ """Set the given user\'s roles to a tuple of roles."""\n \n userFolder.userFolderEditUser(userId, None, list(roles), [])\n \n from AccessControl import getSecurityManager\n+\n userName = userFolder.getUserById(userId).getUserName()\n if userName == getSecurityManager().getUser().getUserName():\n login(userFolder, userName)\n@@ -190,14 +183,14 @@ def makeTestRequest(environ=None):\n \n if environ is None:\n environ = {}\n- environ.setdefault(\'SERVER_NAME\', \'foo\')\n- environ.setdefault(\'SERVER_PORT\', \'80\')\n- environ.setdefault(\'REQUEST_METHOD\', \'GET\')\n+ environ.setdefault("SERVER_NAME", "foo")\n+ environ.setdefault("SERVER_PORT", "80")\n+ environ.setdefault("REQUEST_METHOD", "GET")\n \n resp = HTTPResponse(stdout=stdout)\n req = HTTPRequest(stdin, environ, resp)\n- req._steps = [\'noobject\'] # Fake a published object.\n- req[\'ACTUAL_URL\'] = req.get(\'URL\')\n+ req._steps = ["noobject"] # Fake a published object.\n+ req["ACTUAL_URL"] = req.get("URL")\n setDefaultSkin(req)\n \n return req\n@@ -210,6 +203,7 @@ def addRequestContainer(app, environ=None):\n """\n \n from ZPublisher.BaseRequest import RequestContainer\n+\n req = makeTestRequest(environ)\n requestcontainer = RequestContainer(REQUEST=req)\n return app.__of__(requestcontainer)\n@@ -239,8 +233,9 @@ def zopeApp(db=None, connection=None, environ=None):\n if connection is None and db is not None:\n connection = db.open()\n \n- assert Zope2._began_startup, \\\n- "Zope2 WSGI is not started, maybe mixing Zope and ZServer layers."\n+ assert (\n+ Zope2._began_startup\n+ ), "Zope2 WSGI is not started, maybe mixing Zope and ZServer layers."\n app = addRequestContainer(Zope2.app(connection), environ=environ)\n \n if connection is None:\n@@ -281,6 +276,7 @@ def zopeApp(db=None, connection=None, environ=None):\n \n # Startup layer - you probably don\'t want to use this one directly\n \n+\n class Startup(Layer):\n """This layer does what ZopeLite and ZopeTestCase\'s base.TestCase did:\n start up a minimal Zope instance and manages the application and\n@@ -331,10 +327,10 @@ def tearDown(self):\n # Layer lifecycle helper methods\n \n def setUpDebugMode(self):\n- """Switch off debug mode in the global configuration\n- """\n+ """Switch off debug mode in the global configuration"""\n \n import App.config\n+\n config = App.config.getConfiguration()\n self._debugMode = config.debug_mode\n config.debug_mode = False\n@@ -342,22 +338,25 @@ def setUpDebugMode(self):\n \n # Set Python security mode\n from AccessControl.Implementation import setImplementation\n- setImplementation(\'Python\')\n+\n+ setImplementation("Python")\n \n # Set a flag so that other code can know that we are running tests.\n # Some of the speed-related patches in Plone use this, for instance.\n # The name is a BBB artefact from ZopeTestCase :\n import os\n- os.environ[\'ZOPETESTCASE\'] = \'1\'\n+\n+ os.environ["ZOPETESTCASE"] = "1"\n \n def tearDownDebugMode(self):\n- """Return the debug mode flag to its previous state\n- """\n+ """Return the debug mode flag to its previous state"""\n \n from AccessControl.Implementation import setImplementation\n- setImplementation(\'C\')\n+\n+ setImplementation("C")\n \n import App.config\n+\n config = App.config.getConfiguration()\n config.debug_mode = self._debugMode\n App.config.setConfiguration(config)\n@@ -370,17 +369,18 @@ def setUpClientCache(self):\n \n # Make sure we use a temporary client cache\n import App.config\n+\n config = App.config.getConfiguration()\n- self._zeoClientName = getattr(config, \'zeo_client_name\', None)\n+ self._zeoClientName = getattr(config, "zeo_client_name", None)\n config.zeo_client_name = None\n App.config.setConfiguration(config)\n \n def tearDownClientCache(self):\n- """Restore the cache configuration to its previous state\n- """\n+ """Restore the cache configuration to its previous state"""\n \n # Make sure we use a temporary client cache\n import App.config\n+\n config = App.config.getConfiguration()\n config.zeo_client_name = self._zeoClientName\n App.config.setConfiguration(config)\n@@ -397,12 +397,14 @@ def setUpPatches(self):\n # Avoid expensive product import\n def null_import_products():\n pass\n+\n self._OFS_Application_import_products = OFS.Application.import_products\n OFS.Application.import_products = null_import_products\n \n # Avoid expensive product installation\n def null_initialize(app):\n pass\n+\n self._OFS_Application_initialize = OFS.Application.initialize\n OFS.Application.initialize = null_initialize\n \n@@ -415,8 +417,7 @@ def null_load_zcml():\n Zope2.App.startup.load_zcml = null_load_zcml\n \n def tearDownPatches(self):\n- """Revert the monkey patches from setUpPatches()\n- """\n+ """Revert the monkey patches from setUpPatches()"""\n \n import OFS.Application\n \n@@ -429,28 +430,24 @@ def tearDownPatches(self):\n Zope2.App.startup.load_zcml = self._Zope2_App_startup_load_zcml\n \n def setUpThreads(self):\n- """Set the thread count. Only needed in ZServer.\n- """\n+ """Set the thread count. Only needed in ZServer."""\n pass\n \n def tearDownThreads(self):\n- """Reset the thread count. Only needed in ZServer.\n- """\n+ """Reset the thread count. Only needed in ZServer."""\n pass\n \n def setUpHostPort(self):\n- """Set up the \'host\' and \'port\' resources\n- """\n+ """Set up the \'host\' and \'port\' resources"""\n \n- self[\'host\'] = \'nohost\'\n- self[\'port\'] = 80\n+ self["host"] = "nohost"\n+ self["port"] = 80\n \n def tearDownHostPort(self):\n- """Pop the \'host\' and \'port\' resources\n- """\n+ """Pop the \'host\' and \'port\' resources"""\n \n- del self[\'host\']\n- del self[\'port\']\n+ del self["host"]\n+ del self["port"]\n \n def setUpDatabase(self):\n """Create a database and stash it in the resource ``zodbDB``. If\n@@ -469,9 +466,7 @@ def setUpDatabase(self):\n # Layer a new storage for Zope 2 on top of the one from the base\n # layer, if there is one.\n \n- self[\'zodbDB\'] = zodb.stackDemoStorage(\n- self.get(\'zodbDB\'),\n- name=\'Startup\')\n+ self["zodbDB"] = zodb.stackDemoStorage(self.get("zodbDB"), name="Startup")\n \n # Create a facade for the database object that will delegate to the\n # correct underlying database. This allows resource shadowing to work\n@@ -479,13 +474,12 @@ def setUpDatabase(self):\n # variable.\n \n class DBFacade:\n-\n def __init__(self, layer):\n self.__layer = layer\n \n @property\n def __db(self):\n- return self.__layer[\'zodbDB\']\n+ return self.__layer["zodbDB"]\n \n def __getattr__(self, name):\n return getattr(self.__db, name)\n@@ -494,17 +488,16 @@ def __getattr__(self, name):\n # use this one.\n \n class DBTab(Zope2.Startup.datatypes.DBTab):\n- """A fake DBTab that causes App.startup() to use our own database.\n- """\n+ """A fake DBTab that causes App.startup() to use our own database."""\n \n def __init__(self, db):\n # value is never used when we have an open db\n- self.db_factories = {\'testing\': None}\n- self.mount_paths = {\'/\': \'testing\'}\n- self.databases = {\'testing\': db}\n+ self.db_factories = {"testing": None}\n+ self.mount_paths = {"/": "testing"}\n+ self.databases = {"testing": db}\n \n config = App.config.getConfiguration()\n- self._dbtab = getattr(config, \'dbtab\', None)\n+ self._dbtab = getattr(config, "dbtab", None)\n config.dbtab = DBTab(DBFacade(self))\n App.config.setConfiguration(config)\n \n@@ -514,6 +507,7 @@ def tearDownDatabase(self):\n """\n \n import App.config\n+\n config = App.config.getConfiguration()\n config.dbtab = self._dbtab\n App.config.setConfiguration(config)\n@@ -521,18 +515,18 @@ def tearDownDatabase(self):\n \n # Close and pop the zodbDB resource\n transaction.abort()\n- self[\'zodbDB\'].close()\n- del self[\'zodbDB\']\n+ self["zodbDB"].close()\n+ del self["zodbDB"]\n \n def setUpApp(self):\n- """Trigger Zope startup and set up the application.\n- """\n+ """Trigger Zope startup and set up the application."""\n \n # If the Testing module has been imported, the testinghome\n # variable is set and changes the way Zope2.startup() works.\n # We want the standard behavior so we remove it.\n \n import App.config\n+\n config = App.config.getConfiguration()\n try:\n self._testingHome = config.testinghome\n@@ -544,20 +538,20 @@ def setUpApp(self):\n \n # Clean up after ZopeLite layer\n import ZPublisher.WSGIPublisher\n+\n ZPublisher.WSGIPublisher._MODULES.clear()\n- self._publisher_globals = {\n- \'load_app\': ZPublisher.WSGIPublisher.load_app\n- }\n- if hasattr(ZPublisher.WSGIPublisher, \'__old_load_app__\'):\n+ self._publisher_globals = {"load_app": ZPublisher.WSGIPublisher.load_app}\n+ if hasattr(ZPublisher.WSGIPublisher, "__old_load_app__"):\n old_load_app = ZPublisher.WSGIPublisher.__old_load_app__\n ZPublisher.WSGIPublisher.load_app = old_load_app\n- self._publisher_globals[\'__old_load_app__\'] = old_load_app\n+ self._publisher_globals["__old_load_app__"] = old_load_app\n del ZPublisher.WSGIPublisher.__old_load_app__\n \n # This uses the DB from the dbtab, as configured in setUpDatabase().\n # That DB then gets stored as Zope2.DB and becomes the default.\n \n import Zope2\n+\n Zope2._began_startup = 0\n Zope2.startup_wsgi()\n \n@@ -565,10 +559,10 @@ def setUpApp(self):\n # the database will be used by default when someone does Zope2.app().\n \n def tearDownApp(self):\n- """Undo Zope 2 startup by unsetting the global state it creates.\n- """\n+ """Undo Zope 2 startup by unsetting the global state it creates."""\n \n import Zope2\n+\n Zope2.app()._p_jar.close()\n \n Zope2._began_startup = 0\n@@ -581,6 +575,7 @@ def tearDownApp(self):\n Zope2.__bobo_before__ = None\n \n import App.config\n+\n try:\n self._testingHome\n except AttributeError:\n@@ -592,25 +587,24 @@ def tearDownApp(self):\n del self._testingHome\n \n import ZPublisher.WSGIPublisher\n+\n ZPublisher.WSGIPublisher._MODULES.clear()\n for k, v in self._publisher_globals.items():\n setattr(ZPublisher.WSGIPublisher, k, v)\n \n def setUpBasicProducts(self):\n- """Install a minimal set of products required for Zope 2.\n- """\n+ """Install a minimal set of products required for Zope 2."""\n \n with zopeApp() as app:\n- installProduct(app, \'Products.PluginIndexes\')\n- installProduct(app, \'Products.OFSP\')\n+ installProduct(app, "Products.PluginIndexes")\n+ installProduct(app, "Products.OFSP")\n \n def tearDownBasicProducts(self):\n- """Tear down the minimal set of products\n- """\n+ """Tear down the minimal set of products"""\n \n with zopeApp() as app:\n- uninstallProduct(app, \'Products.PluginIndexes\')\n- uninstallProduct(app, \'Products.OFSP\')\n+ uninstallProduct(app, "Products.PluginIndexes")\n+ uninstallProduct(app, "Products.OFSP")\n \n # It\'s possible for Five\'s _register_monkies and _meta_type_regs\n # global variables to contain duplicates. This causes an unecessary\n@@ -622,10 +616,8 @@ def tearDownBasicProducts(self):\n except ImportError:\n # Zope <= 2.12\n from Products.Five import fiveconfigure as metaconfigure\n- metaconfigure._register_monkies = list(\n- set(metaconfigure._register_monkies))\n- metaconfigure._meta_type_regs = list(\n- set(metaconfigure._meta_type_regs))\n+ metaconfigure._register_monkies = list(set(metaconfigure._register_monkies))\n+ metaconfigure._meta_type_regs = list(set(metaconfigure._meta_type_regs))\n \n def setUpZCML(self):\n """Load the basic ZCML configuration from Five. Exposes a resource\n@@ -634,16 +626,20 @@ def setUpZCML(self):\n \n # Push a new global registry so that we can cleanly tear down all ZCML\n from plone.testing import zca\n+\n zca.pushGlobalRegistry()\n \n # Load something akin to the default site.zcml without actually auto-\n # loading products\n \n- self[\'configurationContext\'] = context = zca.stackConfigurationContext(\n- self.get(\'configurationContext\'))\n+ self["configurationContext"] = context = zca.stackConfigurationContext(\n+ self.get("configurationContext")\n+ )\n \n from zope.configuration import xmlconfig\n- xmlconfig.string("""\\\n+\n+ xmlconfig.string(\n+ """\\\n \n@@ -653,17 +649,20 @@ def setUpZCML(self):\n \n \n \n-""", context=context)\n+""",\n+ context=context,\n+ )\n \n def tearDownZCML(self):\n """Tear down the component registry and delete the\n ``configurationContext`` resource.\n """\n # Delete the (possibly stacked) configuration context\n- del self[\'configurationContext\']\n+ del self["configurationContext"]\n \n # Zap all globally loaded ZCML\n from plone.testing import zca\n+\n zca.popGlobalRegistry()\n \n def setUpFive(self):\n@@ -691,6 +690,7 @@ def tearDownFive(self):\n # Basic integration and functional test and layers. These are the simplest\n # Zope layers that are generally useful\n \n+\n class IntegrationTesting(Layer):\n """This layer extends ``STARTUP`` to add rollback of the transaction\n after each test. It does not manage a fixture and has no layer lifecyle,\n@@ -725,17 +725,18 @@ def testSetUp(self):\n # Open a new app and save it as the resource ``app``.\n \n environ = {\n- \'SERVER_NAME\': self[\'host\'],\n- \'SERVER_PORT\': str(self[\'port\']),\n+ "SERVER_NAME": self["host"],\n+ "SERVER_PORT": str(self["port"]),\n }\n \n app = addRequestContainer(Zope2.app(), environ=environ)\n request = app.REQUEST\n- request[\'PARENTS\'] = [app]\n+ request["PARENTS"] = [app]\n \n # Make sure we have a zope.globalrequest request\n try:\n from zope.globalrequest import setRequest\n+\n setRequest(request)\n except ImportError:\n pass\n@@ -746,20 +747,21 @@ def testSetUp(self):\n self._original_commit = transaction.commit\n \n def you_broke_it():\n- raise TestIsolationBroken("""You are in a Test Layer\n+ raise TestIsolationBroken(\n+ """You are in a Test Layer\n (IntegrationTesting) that is fast by just aborting transactions between each\n test. You just committed something. That breaks the test isolation. So I stop\n-here and let you fix it.""")\n+here and let you fix it."""\n+ )\n \n # Prevent commits in integration tests which breaks test isolation.\n transaction.commit = you_broke_it\n \n # Save resources for tests to access\n- self[\'app\'] = app\n- self[\'request\'] = request\n+ self["app"] = app\n+ self["request"] = request\n \n def testTearDown(self):\n-\n # Abort the transaction\n transaction.abort()\n \n@@ -768,18 +770,19 @@ def testTearDown(self):\n # Make sure we have a zope.globalrequest request\n try:\n from zope.globalrequest import setRequest\n+\n setRequest(None)\n except ImportError:\n pass\n \n # Close the database connection and the request\n- app = self[\'app\']\n+ app = self["app"]\n app.REQUEST.close()\n app._p_jar.close()\n \n # Delete the resources\n- del self[\'request\']\n- del self[\'app\']\n+ del self["request"]\n+ del self["app"]\n \n \n INTEGRATION_TESTING = IntegrationTesting()\n@@ -820,24 +823,25 @@ def testSetUp(self):\n # this layer, we can\'t just assign a new shadow. We therefore keep\n # track of the original so that we can restore it on tear-down.\n \n- self[\'zodbDB\'] = zodb.stackDemoStorage(\n- self.get(\'zodbDB\'),\n- name=\'FunctionalTest\')\n+ self["zodbDB"] = zodb.stackDemoStorage(\n+ self.get("zodbDB"), name="FunctionalTest"\n+ )\n \n # Save the app\n \n environ = {\n- \'SERVER_NAME\': self[\'host\'],\n- \'SERVER_PORT\': str(self[\'port\']),\n+ "SERVER_NAME": self["host"],\n+ "SERVER_PORT": str(self["port"]),\n }\n \n app = addRequestContainer(Zope2.app(), environ=environ)\n request = app.REQUEST\n- request[\'PARENTS\'] = [app]\n+ request["PARENTS"] = [app]\n \n # Make sure we have a zope.globalrequest request\n try:\n from zope.globalrequest import setRequest\n+\n setRequest(request)\n except ImportError:\n pass\n@@ -846,8 +850,8 @@ def testSetUp(self):\n transaction.begin()\n \n # Save resources for the test\n- self[\'app\'] = app\n- self[\'request\'] = request\n+ self["app"] = app\n+ self["request"] = request\n \n def testTearDown(self):\n # Abort any open transactions\n@@ -856,26 +860,27 @@ def testTearDown(self):\n # Make sure we have a zope.globalrequest request\n try:\n from zope.globalrequest import setRequest\n+\n setRequest(None)\n except ImportError:\n pass\n \n # Close the database connection and the request\n- app = self[\'app\']\n+ app = self["app"]\n app.REQUEST.close()\n app._p_jar.close()\n \n- del self[\'app\']\n- del self[\'request\']\n+ del self["app"]\n+ del self["request"]\n \n # Close and discard the database\n- self[\'zodbDB\'].close()\n- del self[\'zodbDB\']\n+ self["zodbDB"].close()\n+ del self["zodbDB"]\n \n \n FUNCTIONAL_TESTING = FunctionalTesting()\n \n-WSGI_LOG_REQUEST = \'WSGI_REQUEST_LOGGING\' in os.environ\n+WSGI_LOG_REQUEST = "WSGI_REQUEST_LOGGING" in os.environ\n \n \n class WSGIServer(Layer):\n@@ -893,45 +898,41 @@ class WSGIServer(Layer):\n defaultBases = (STARTUP,)\n \n timeout = 5\n- host = os.environ.get(\'WSGI_SERVER_HOST\',\n- os.environ.get(\'ZSERVER_HOST\'))\n- port = os.environ.get(\'WSGI_SERVER_PORT\',\n- os.environ.get(\'ZSERVER_PORT\'))\n+ host = os.environ.get("WSGI_SERVER_HOST", os.environ.get("ZSERVER_HOST"))\n+ port = os.environ.get("WSGI_SERVER_PORT", os.environ.get("ZSERVER_PORT"))\n pipeline = [\n- (\'Zope\', \'paste.filter_app_factory\', \'httpexceptions\', {}),\n+ ("Zope", "paste.filter_app_factory", "httpexceptions", {}),\n ]\n \n def setUp(self):\n- self[\'host\'] = self.host\n+ self["host"] = self.host\n self.setUpServer()\n- self[\'port\'] = self.port\n+ self["port"] = self.port\n \n def tearDown(self):\n self.tearDownServer()\n- del self[\'host\']\n- del self[\'port\']\n+ del self["host"]\n+ del self["port"]\n \n def setUpServer(self):\n- """Create a WSGI server instance and save it in self.server.\n- """\n+ """Create a WSGI server instance and save it in self.server."""\n app = self.make_wsgi_app()\n- kwargs = {\'clear_untrusted_proxy_headers\': False}\n+ kwargs = {"clear_untrusted_proxy_headers": False}\n if self.host is not None:\n- kwargs[\'host\'] = self.host\n+ kwargs["host"] = self.host\n if self.port is not None:\n- kwargs[\'port\'] = int(self.port)\n+ kwargs["port"] = int(self.port)\n self.server = StopableWSGIServer.create(app, **kwargs)\n # If we dynamically set the host/port, we want to reset it to localhost\n # Otherwise this will depend on, for example, the local network setup\n- if self.host in (None, \'0.0.0.0\', \'127.0.0.1\', \'localhost\'):\n- self.server.effective_host = \'localhost\'\n+ if self.host in (None, "0.0.0.0", "127.0.0.1", "localhost"):\n+ self.server.effective_host = "localhost"\n # Refresh the hostname and port in case we dynamically picked them\n- self[\'host\'] = self.host = self.server.effective_host\n- self[\'port\'] = self.port = int(self.server.effective_port)\n+ self["host"] = self.host = self.server.effective_host\n+ self["port"] = self.port = int(self.server.effective_port)\n \n def tearDownServer(self):\n- """Close the server socket and clean up.\n- """\n+ """Close the server socket and clean up."""\n self.server.shutdown()\n try:\n shutil.rmtree(self._wsgi_conf_dir)\n@@ -940,7 +941,7 @@ def tearDownServer(self):\n \n def make_wsgi_app(self):\n self._wsgi_conf_dir = tempfile.mkdtemp()\n- global_config = {\'here\': self._wsgi_conf_dir}\n+ global_config = {"here": self._wsgi_conf_dir}\n zope_conf = self._get_zope_conf(self._wsgi_conf_dir)\n Zope2.Startup.run.make_wsgi_app(global_config, zope_conf)\n app = ZPublisher.WSGIPublisher.publish_module\n@@ -952,8 +953,8 @@ def make_wsgi_app(self):\n \n def _get_zope_conf(self, dir):\n fd, path = tempfile.mkstemp(dir=dir)\n- with os.fdopen(fd, \'w\') as zope_conf:\n- zope_conf.write(f\'instancehome {os.path.dirname(dir)}\\n\')\n+ with os.fdopen(fd, "w") as zope_conf:\n+ zope_conf.write(f"instancehome {os.path.dirname(dir)}\\n")\n return path\n \n \n@@ -963,7 +964,5 @@ def _get_zope_conf(self, dir):\n \n # Functional testing layer that uses the WSGI_SERVER_FIXTURE\n WSGI_SERVER = FunctionalTesting(\n- bases=(\n- WSGI_SERVER_FIXTURE,\n- ),\n- name=\'WSGIServer:Functional\')\n+ bases=(WSGI_SERVER_FIXTURE,), name="WSGIServer:Functional"\n+)\ndiff --git a/src/plone/testing/zserver.py b/src/plone/testing/zserver.py\nindex 4a16dbb..ec3634f 100644\n--- a/src/plone/testing/zserver.py\n+++ b/src/plone/testing/zserver.py\n@@ -82,6 +82,7 @@ def zopeApp(db=None, connection=None, environ=None):\n \n # Startup layer - you probably don\'t want to use this one directly\n \n+\n class Startup(zope.Startup):\n """This layer does what ZopeLite and ZopeTestCase\'s base.TestCase did:\n start up a minimal Zope instance and manages the application and\n@@ -104,32 +105,32 @@ class Startup(zope.Startup):\n # Layer lifecycle helper methods\n \n def setUpThreads(self):\n- """Set the thread count for ZServer. This defaults to 1.\n- """\n+ """Set the thread count for ZServer. This defaults to 1."""\n \n # We can\'t use setNumberOfThreads() because that function self-\n # destructs, literally, when called.\n from ZServer.Zope2.Startup import config\n+\n self._zserverThreads = config.ZSERVER_THREADS\n config.ZSERVER_THREADS = self.threads\n \n def tearDownThreads(self):\n- """Reset the ZServer thread count.\n- """\n+ """Reset the ZServer thread count."""\n \n from ZServer.Zope2.Startup import config\n+\n config.ZSERVER_THREADS = self._zserverThreads\n del self._zserverThreads\n \n def setUpApp(self):\n- """Trigger Zope startup and set up the application.\n- """\n+ """Trigger Zope startup and set up the application."""\n \n # If the Testing module has been imported, the testinghome\n # variable is set and changes the way Zope2.startup() works.\n # We want the standard behavior so we remove it.\n \n import App.config\n+\n config = App.config.getConfiguration()\n try:\n self._testingHome = config.testinghome\n@@ -143,17 +144,18 @@ def setUpApp(self):\n # That DB then gets stored as Zope2.DB and becomes the default.\n \n from ZServer import Zope2\n+\n Zope2.startup()\n \n # At this point, Zope2.DB is set to the test database facade. This is\n # the database will be used by default when someone does Zope2.app().\n \n def tearDownApp(self):\n- """Undo Zope 2 startup by unsetting the global state it creates.\n- """\n+ """Undo Zope 2 startup by unsetting the global state it creates."""\n \n import Zope2\n import ZServer.Zope2\n+\n ZServer.Zope2.app()._p_jar.close()\n \n ZServer.Zope2._began_startup = 0\n@@ -166,6 +168,7 @@ def tearDownApp(self):\n Zope2.__bobo_before__ = None\n \n import App.config\n+\n try:\n self._testingHome\n except AttributeError:\n@@ -179,6 +182,7 @@ def tearDownApp(self):\n # Clear out the app reference cached in get_module_info\'s\n # \'modules\' parameter default dict. (waaaaa)\n import ZPublisher.Publish\n+\n defaults = ZPublisher.Publish.get_module_info.func_defaults\n \n if defaults:\n@@ -187,20 +191,18 @@ def tearDownApp(self):\n ZPublisher.Publish.get_module_info.func_defaults = tuple(d)\n \n def setUpBasicProducts(self):\n- """Install a minimal set of products required for Zope 2.\n- """\n+ """Install a minimal set of products required for Zope 2."""\n \n with zopeApp() as app:\n- installProduct(app, \'Products.PluginIndexes\')\n- installProduct(app, \'Products.OFSP\')\n+ installProduct(app, "Products.PluginIndexes")\n+ installProduct(app, "Products.OFSP")\n \n def tearDownBasicProducts(self):\n- """Tear down the minimal set of products\n- """\n+ """Tear down the minimal set of products"""\n \n with zopeApp() as app:\n- uninstallProduct(app, \'Products.PluginIndexes\')\n- uninstallProduct(app, \'Products.OFSP\')\n+ uninstallProduct(app, "Products.PluginIndexes")\n+ uninstallProduct(app, "Products.OFSP")\n \n # It\'s possible for Five\'s _register_monkies and _meta_type_regs\n # global variables to contain duplicates. This causes an unecessary\n@@ -212,10 +214,8 @@ def tearDownBasicProducts(self):\n except ImportError:\n # Zope <= 2.12\n from Products.Five import fiveconfigure as metaconfigure\n- metaconfigure._register_monkies = list(\n- set(metaconfigure._register_monkies))\n- metaconfigure._meta_type_regs = list(\n- set(metaconfigure._meta_type_regs))\n+ metaconfigure._register_monkies = list(set(metaconfigure._register_monkies))\n+ metaconfigure._meta_type_regs = list(set(metaconfigure._meta_type_regs))\n \n \n STARTUP = Startup()\n@@ -224,6 +224,7 @@ def tearDownBasicProducts(self):\n # Basic integration and functional test and layers. These are the simplest\n # Zope 2 layers that are generally useful\n \n+\n class IntegrationTesting(zope.IntegrationTesting):\n """This layer extends ``STARTUP`` to add rollback of the transaction\n after each test. It does not manage a fixture and has no layer lifecyle,\n@@ -256,17 +257,18 @@ def testSetUp(self):\n # Open a new app and save it as the resource ``app``.\n \n environ = {\n- \'SERVER_NAME\': self[\'host\'],\n- \'SERVER_PORT\': str(self[\'port\']),\n+ "SERVER_NAME": self["host"],\n+ "SERVER_PORT": str(self["port"]),\n }\n \n app = addRequestContainer(Zope2.app(), environ=environ)\n request = app.REQUEST\n- request[\'PARENTS\'] = [app]\n+ request["PARENTS"] = [app]\n \n # Make sure we have a zope.globalrequest request\n try:\n from zope.globalrequest import setRequest\n+\n setRequest(request)\n except ImportError:\n pass\n@@ -277,17 +279,19 @@ def testSetUp(self):\n self._original_commit = transaction.commit\n \n def you_broke_it():\n- raise TestIsolationBroken("""You are in a Test Layer\n+ raise TestIsolationBroken(\n+ """You are in a Test Layer\n (IntegrationTesting) that is fast by just aborting transactions between each\n test. You just committed something. That breaks the test isolation. So I stop\n-here and let you fix it.""")\n+here and let you fix it."""\n+ )\n \n # Prevent commits in integration tests which breaks test isolation.\n transaction.commit = you_broke_it\n \n # Save resources for tests to access\n- self[\'app\'] = app\n- self[\'request\'] = request\n+ self["app"] = app\n+ self["request"] = request\n \n \n INTEGRATION_TESTING = IntegrationTesting()\n@@ -326,24 +330,25 @@ def testSetUp(self):\n # this layer, we can\'t just assign a new shadow. We therefore keep\n # track of the original so that we can restore it on tear-down.\n \n- self[\'zodbDB\'] = zodb.stackDemoStorage(\n- self.get(\'zodbDB\'),\n- name=\'FunctionalTest\')\n+ self["zodbDB"] = zodb.stackDemoStorage(\n+ self.get("zodbDB"), name="FunctionalTest"\n+ )\n \n # Save the app\n \n environ = {\n- \'SERVER_NAME\': self[\'host\'],\n- \'SERVER_PORT\': str(self[\'port\']),\n+ "SERVER_NAME": self["host"],\n+ "SERVER_PORT": str(self["port"]),\n }\n \n app = addRequestContainer(Zope2.app(), environ=environ)\n request = app.REQUEST\n- request[\'PARENTS\'] = [app]\n+ request["PARENTS"] = [app]\n \n # Make sure we have a zope.globalrequest request\n try:\n from zope.globalrequest import setRequest\n+\n setRequest(request)\n except ImportError:\n pass\n@@ -352,8 +357,8 @@ def testSetUp(self):\n transaction.begin()\n \n # Save resources for the test\n- self[\'app\'] = app\n- self[\'request\'] = request\n+ self["app"] = app\n+ self["request"] = request\n \n \n FUNCTIONAL_TESTING = FunctionalTesting()\n@@ -361,6 +366,7 @@ def testSetUp(self):\n \n # More advanced functional testing - running ZServer and FTP server\n \n+\n class ZServer(Layer):\n """Start a ZServer that accesses the fixture managed by the\n ``STARTUP`` layer.\n@@ -378,26 +384,25 @@ class ZServer(Layer):\n \n defaultBases = (STARTUP,)\n \n- host = os.environ.get(\'ZSERVER_HOST\', \'\')\n- port = int(os.environ.get(\'ZSERVER_PORT\', 0))\n+ host = os.environ.get("ZSERVER_HOST", "")\n+ port = int(os.environ.get("ZSERVER_PORT", 0))\n timeout = 5.0\n log = None\n \n def setUp(self):\n-\n from threading import Thread\n \n import time\n \n- self[\'host\'] = self.host\n- self[\'port\'] = self.port\n+ self["host"] = self.host\n+ self["port"] = self.port\n \n self._shutdown = False\n \n self.setUpServer()\n \n self.thread = Thread(\n- name=f\'{self.__name__} server\',\n+ name=f"{self.__name__} server",\n target=self.runner,\n )\n \n@@ -413,12 +418,11 @@ def tearDown(self):\n \n self.tearDownServer()\n \n- del self[\'host\']\n- del self[\'port\']\n+ del self["host"]\n+ del self["port"]\n \n def setUpServer(self):\n- """Create a ZServer server instance and save it in self.zserver\n- """\n+ """Create a ZServer server instance and save it in self.zserver"""\n from StringIO import StringIO\n from ZServer import logger\n from ZServer import zhttp_handler\n@@ -439,20 +443,23 @@ def setUpServer(self):\n \n # If we dynamically set the host/port, we want to reset it to localhost\n # Otherwise this will depend on, for example, the local network setup\n- if self.host in (\'\', \'0.0.0.0\', \'127.0.0.1\', ):\n- server.server_name = \'localhost\'\n+ if self.host in (\n+ "",\n+ "0.0.0.0",\n+ "127.0.0.1",\n+ ):\n+ server.server_name = "localhost"\n # Refresh the hostname and port in case we dynamically picked them\n- self[\'host\'] = self.host = server.server_name\n- self[\'port\'] = self.port = server.server_port\n+ self["host"] = self.host = server.server_name\n+ self["port"] = self.port = server.server_port\n \n- zhttpHandler = zhttp_handler(module=\'Zope2\', uri_base=\'\')\n+ zhttpHandler = zhttp_handler(module="Zope2", uri_base="")\n server.install_handler(zhttpHandler)\n \n self.zserver = server\n \n def tearDownServer(self):\n- """Close the ZServer socket\n- """\n+ """Close the ZServer socket"""\n self.zserver.close()\n \n # Thread runner\n@@ -475,11 +482,7 @@ def runner(self):\n ZSERVER_FIXTURE = ZServer()\n \n # Functional testing layer that uses the ZSERVER_FIXTURE\n-ZSERVER = FunctionalTesting(\n- bases=(\n- ZSERVER_FIXTURE,\n- ),\n- name=\'ZServer:Functional\')\n+ZSERVER = FunctionalTesting(bases=(ZSERVER_FIXTURE,), name="ZServer:Functional")\n \n \n class FTPServer(ZServer):\n@@ -498,15 +501,14 @@ class FTPServer(ZServer):\n \n defaultBases = (STARTUP,)\n \n- host = os.environ.get(\'FTPSERVER_HOST\', \'\')\n- port = int(os.environ.get(\'FTPSERVER_PORT\', 0))\n+ host = os.environ.get("FTPSERVER_HOST", "")\n+ port = int(os.environ.get("FTPSERVER_PORT", 0))\n threads = 1\n timeout = 5.0\n log = None\n \n def setUpServer(self):\n- """Create an FTP server instance and save it in self.ftpServer\n- """\n+ """Create an FTP server instance and save it in self.ftpServer"""\n \n from StringIO import StringIO\n from ZServer import logger\n@@ -519,7 +521,7 @@ def setUpServer(self):\n zopeLog = logger.file_logger(log)\n \n self.ftpServer = FTPServer(\n- \'Zope2\',\n+ "Zope2",\n ip=self.host,\n port=self.port,\n logger_object=zopeLog,\n@@ -528,16 +530,19 @@ def setUpServer(self):\n self.host, self.port = self.ftpServer.socket.getsockname()\n # If we dynamically set the host/port, we want to reset it to localhost\n # Otherwise this will depend on, for example, the local network setup\n- if self.host in (\'\', \'0.0.0.0\', \'127.0.0.1\', ):\n- self.host = \'localhost\'\n- self.ftpServer.hostname = \'localhost\'\n- self.ftpServer.ip = \'127.0.0.1\'\n- self[\'host\'] = self.host\n- self[\'port\'] = self.port\n+ if self.host in (\n+ "",\n+ "0.0.0.0",\n+ "127.0.0.1",\n+ ):\n+ self.host = "localhost"\n+ self.ftpServer.hostname = "localhost"\n+ self.ftpServer.ip = "127.0.0.1"\n+ self["host"] = self.host\n+ self["port"] = self.port\n \n def tearDownServer(self):\n- """Close the FTPServer socket\n- """\n+ """Close the FTPServer socket"""\n self.ftpServer.close()\n \n \n@@ -546,8 +551,4 @@ def tearDownServer(self):\n FTP_SERVER_FIXTURE = FTPServer()\n \n # Functional testing layer that uses the FTP_SERVER_FIXTURE\n-FTP_SERVER = FunctionalTesting(\n- bases=(\n- FTP_SERVER_FIXTURE,\n- ),\n- name=\'FTPServer:Functional\')\n+FTP_SERVER = FunctionalTesting(bases=(FTP_SERVER_FIXTURE,), name="FTPServer:Functional")\n' - -Repository: plone.testing +Repository: plone.api Branch: refs/heads/master -Date: 2023-10-15T19:09:56+02:00 -Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/plone.testing/commit/048b6302169bc99281c079825901206f436da9f6 +Date: 2023-10-13T16:57:31+05:30 +Author: akshat2jain (Akshat2Jain) +Commit: https://github.com/plone/plone.api/commit/6504c3f277e09917627179fbacb102809679f467 -chore: zpretty +added log entry Files changed: -M src/plone/testing/testing_zca.zcml -M src/plone/testing/testing_zca_more_specific.zcml +A news/518.bugfix -b'diff --git a/src/plone/testing/testing_zca.zcml b/src/plone/testing/testing_zca.zcml\nindex 417804c..1f68bac 100644\n--- a/src/plone/testing/testing_zca.zcml\n+++ b/src/plone/testing/testing_zca.zcml\n@@ -1,8 +1,12 @@\n \n+ >\n \n- \n+ \n \n \n+ >\n \n -Commit: https://github.com/plone/plone.testing/commit/e4e9fa9ec34ff9edcddef5a9f4b85d1ca9c5566d +Date: 2023-10-14T19:07:20+05:30 +Author: akshat2jain (Akshat2Jain) +Commit: https://github.com/plone/plone.api/commit/bce071ac2ca32e0de10cd6e62260be3093e8c02e -chore: update trove classifiers +added requested changes Files changed: -M setup.py +M src/plone/api/tests/test_content.py -b'diff --git a/setup.py b/setup.py\nindex 19ac686..f9b3d11 100644\n--- a/setup.py\n+++ b/setup.py\n@@ -64,18 +64,18 @@\n classifiers=[\n "Development Status :: 5 - Production/Stable",\n "Environment :: Web Environment",\n- "Framework :: Plone :: 5.2",\n- "Framework :: Plone :: Core",\n "Framework :: Plone",\n- "Framework :: Zope :: 4",\n+ "Framework :: Plone :: 6.0",\n+ "Framework :: Plone :: Core",\n+ "Framework :: Zope :: 5",\n "Intended Audience :: Developers",\n "License :: OSI Approved :: BSD License",\n "Operating System :: OS Independent",\n- "Programming Language :: Python :: 2.7",\n- "Programming Language :: Python :: 3.6",\n- "Programming Language :: Python :: 3.7",\n+ "Programming Language :: Python",\n "Programming Language :: Python :: 3.8",\n "Programming Language :: Python :: 3.9",\n+ "Programming Language :: Python :: 3.10",\n+ "Programming Language :: Python :: 3.11",\n "Programming Language :: Python :: Implementation :: CPython",\n "Programming Language :: Python",\n "Topic :: Internet :: WWW/HTTP :: Dynamic Content",\n' +b'diff --git a/src/plone/api/tests/test_content.py b/src/plone/api/tests/test_content.py\nindex bff0436b..7ca32a2a 100644\n--- a/src/plone/api/tests/test_content.py\n+++ b/src/plone/api/tests/test_content.py\n@@ -1014,6 +1014,7 @@ def test_find_interface_dict(self):\n "operator": "and",\n },\n )\n+ # Plone Site also implements the IContentish and INavigationRoot interfaces.\n self.assertEqual(len(brains), 2)\n \n # plone.api query using interfaces\n@@ -1023,7 +1024,7 @@ def test_find_interface_dict(self):\n "operator": "and",\n },\n )\n- self.assertEqual(len(brains), 1)\n+ self.assertEqual(len(brains), 2)\n \n def test_find_interface_dict__include_not_query(self):\n """Check if not query in object_provides is functional."""\n@@ -1041,8 +1042,8 @@ def test_find_interface_dict__include_not_query(self):\n "not": INavigationRoot.__identifier__,\n },\n )\n-\n- self.assertEqual(len(brains_all) - len(brains), 0)\n+ # Plone Site also implements the IContentish and INavigationRoot interfaces.\n+ self.assertEqual(len(brains_all) - len(brains), 2)\n \n def test_find_interface_dict__all_options(self):\n """Check for all options in a object_provides query are correctly\n' -Repository: plone.testing +Repository: plone.api Branch: refs/heads/master -Date: 2023-10-15T19:09:56+02:00 -Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/plone.testing/commit/9f1d4571d2a7380cb147fdba713a57d4a5a63d93 +Date: 2023-10-19T15:00:04+02:00 +Author: Roel Bruggink (jaroel) +Commit: https://github.com/plone/plone.api/commit/02057fa09b7dc5c3b4e5c7ecccb0a61c49af40b9 -feat: pyroma +Revert checks to status quo Files changed: -M setup.py +M src/plone/api/tests/test_content.py -b'diff --git a/setup.py b/setup.py\nindex f9b3d11..8008063 100644\n--- a/setup.py\n+++ b/setup.py\n@@ -91,6 +91,7 @@\n namespace_packages=["plone"],\n include_package_data=True,\n zip_safe=False,\n+ python_requires=">=3.8",\n install_requires=install_requires,\n tests_require=tests_require,\n extras_require={\n' +b'diff --git a/src/plone/api/tests/test_content.py b/src/plone/api/tests/test_content.py\nindex 7ca32a2a..a873d19b 100644\n--- a/src/plone/api/tests/test_content.py\n+++ b/src/plone/api/tests/test_content.py\n@@ -1014,8 +1014,8 @@ def test_find_interface_dict(self):\n "operator": "and",\n },\n )\n- # Plone Site also implements the IContentish and INavigationRoot interfaces.\n- self.assertEqual(len(brains), 2)\n+\n+ self.assertEqual(len(brains), 1)\n \n # plone.api query using interfaces\n brains = api.content.find(\n@@ -1024,7 +1024,7 @@ def test_find_interface_dict(self):\n "operator": "and",\n },\n )\n- self.assertEqual(len(brains), 2)\n+ self.assertEqual(len(brains), 1)\n \n def test_find_interface_dict__include_not_query(self):\n """Check if not query in object_provides is functional."""\n@@ -1042,8 +1042,7 @@ def test_find_interface_dict__include_not_query(self):\n "not": INavigationRoot.__identifier__,\n },\n )\n- # Plone Site also implements the IContentish and INavigationRoot interfaces.\n- self.assertEqual(len(brains_all) - len(brains), 2)\n+ self.assertEqual(len(brains_all) - len(brains), 1)\n \n def test_find_interface_dict__all_options(self):\n """Check for all options in a object_provides query are correctly\n' -Repository: plone.testing +Repository: plone.api Branch: refs/heads/master -Date: 2023-10-15T19:09:56+02:00 -Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/plone.testing/commit/ce0a4e67f7a3c02277d5f20b8f213ff4ff4fc331 +Date: 2023-10-19T15:06:38+02:00 +Author: Roel Bruggink (jaroel) +Commit: https://github.com/plone/plone.api/commit/eab1cc5feb32313e5e2395c70e6695ac30030ea0 -feat: codespell +Use IFolder as PloneSite gained IContentish. Files changed: -M src/plone/testing/README.rst -M src/plone/testing/_z2_testbrowser.py -M src/plone/testing/layer.py -M src/plone/testing/tests.py -M src/plone/testing/zope.py -M src/plone/testing/zope.rst -M src/plone/testing/zserver.py -M src/plone/testing/zserver.rst +M src/plone/api/tests/test_content.py -b'diff --git a/src/plone/testing/README.rst b/src/plone/testing/README.rst\nindex 36d4164..69fc422 100644\n--- a/src/plone/testing/README.rst\n+++ b/src/plone/testing/README.rst\n@@ -280,7 +280,7 @@ The available extras are:\n Adding a test buildout to your package\n --------------------------------------\n \n-When creating re-usable, mostly stand-alone packages, it is often useful to be able to include a buildout with the package sources itself that can be used to create a test runner.\n+When creating reusable, mostly stand-alone packages, it is often useful to be able to include a buildout with the package sources itself that can be used to create a test runner.\n This is a popular approach for many Zope packages, for example.\n In fact, ``plone.testing`` itself uses this kind of layout.\n \n@@ -388,7 +388,7 @@ For example, if you are writing a set of integration tests, you may need to set\n This type of test fixture setup can be resource-intensive and time-consuming.\n If it is possible to only perform the setup and tear-down once for a set of tests without losing isolation between those tests, test runs can often be sped up significantly.\n \n-Layers also allow re-use of test fixtures and set-up/tear-down code.\n+Layers also allow reuse of test fixtures and set-up/tear-down code.\n ``plone.testing`` provides a number of useful (but optional) layers that manage test fixtures for common Zope testing scenarios, letting you focus on the actual test authoring.\n \n At the most basic, a layer is an object with the following methods and attributes:\n@@ -464,7 +464,7 @@ All four are optional.\n The default implementation of each does nothing.\n \n By convention, layers are created in a module called ``testing.py`` at the top level of your package.\n-The idea is that other packages that extend your package can re-use your layers for their own testing.\n+The idea is that other packages that extend your package can reuse your layers for their own testing.\n \n A simple layer may look like this::\n \n@@ -530,7 +530,7 @@ Above, we are really saying that *instances* of ``ZIGSpaceShip`` will, by defaul\n \n * The instance is usually a shared, module-global object, although in some cases it is useful to create copies of layers by instantiating the class more than once.\n \n- * Subclassing an existing layer class is just straightforward OOP re-use: the test runner is not aware of the subclassing relationship.\n+ * Subclassing an existing layer class is just straightforward OOP reuse: the test runner is not aware of the subclassing relationship.\n \n * A layer *instance* can be associated with any number of layer *bases*, via its ``__bases__`` property (which is usually via the ``defaultBases`` variable in the class body and/or overridden using the ``bases`` argument to the ``Layer`` constructor).\n These bases are layer *instances*, not classes.\n@@ -544,9 +544,9 @@ Advanced - overriding bases\n ---------------------------\n \n In some cases, it may be useful to create a copy of a layer, but change its bases.\n-One reason to do this may if you are re-using a layer from another module, and you need to change the order in which layers are set up and torn down.\n+One reason to do this may if you are reusing a layer from another module, and you need to change the order in which layers are set up and torn down.\n \n-Normally, of course, you would just re-use the layer instance, either directly in a test, or in the ``defaultBases`` tuple of another layer, but if you need to change the bases, you can pass a new list of bases to the layer instance constructor:::\n+Normally, of course, you would just reuse the layer instance, either directly in a test, or in the ``defaultBases`` tuple of another layer, but if you need to change the bases, you can pass a new list of bases to the layer instance constructor:::\n \n >>> class CATSMessage(Layer):\n ...\n@@ -591,7 +591,7 @@ Layer resources\n Many layers will manage one or more resources that are used either by other layers, or by tests themselves.\n Examples may include database connections, thread-local objects, or configuration data.\n \n-``plone.testing`` contains a simple resource storage abstraction that makes it easy to access resources from dependant layers or tests.\n+``plone.testing`` contains a simple resource storage abstraction that makes it easy to access resources from dependent layers or tests.\n The resource storage uses dictionary notation:::\n \n >>> class WarpDrive(object):\n@@ -725,7 +725,7 @@ to share some test logic.\n \n Two special methods, ``setUp()`` and ``tearDown()``, can also be added.\n These will be called before or after each test, respectively, and provide a useful place to construct and clean up test fixtures without writing a custom layer.\n-They are obviously not as re-usable as layers, though.\n+They are obviously not as reusable as layers, though.\n \n *Hint:* Somewhat confusingly, the ``setUp()`` and ``tearDown()`` methods in a test case class are the equivalent of the ``testSetUp()`` and ``testTearDown()`` methods of a layer class.\n \n@@ -1141,7 +1141,7 @@ To load the configuration for a particular package, use ``xmlconfig.file()``:::\n This takes two required arguments: the file name and the module relative to which it is to be found.\n Here, we have loaded two files: ``meta.zcml`` and ``configure.zcml``.\n The first call to ``xmlconfig.file()`` creates and returns a configuration context.\n-We re-use that for the subsequent invocation, so that the directives configured are available.\n+We reuse that for the subsequent invocation, so that the directives configured are available.\n \n Installing a Zope product\n -------------------------\n@@ -1685,7 +1685,7 @@ For example::\n MY_INTEGRATION_TESTING = zope.IntegrationTesting(bases=(MY_FIXTURE,), name="MyFixture:Integration")\n MY_FUNCTIONAL_TESTING = zope.FunctionalTesting(bases=(MY_FIXTURE,), name="MyFixture:Functional")\n \n-(Note that we need to give an explicit, unique name to the two layers that re-use the ``IntegrationTesting`` and ``FunctionalTesting`` classes.)\n+(Note that we need to give an explicit, unique name to the two layers that reuse the ``IntegrationTesting`` and ``FunctionalTesting`` classes.)\n \n In this example, other layers could extend the "MyLayer" fixture by using ``MY_FIXTURE`` as a base.\n Tests would use either ``MY_INTEGRATION_TESTING`` or ``MY_FUNCTIONAL_TESTING`` as appropriate.\n@@ -1948,7 +1948,7 @@ For example::\n MY_INTEGRATION_TESTING = zserver.IntegrationTesting(bases=(MY_FIXTURE,), name="MyFixture:Integration")\n MY_FUNCTIONAL_TESTING = zserver.FunctionalTesting(bases=(MY_FIXTURE,), name="MyFixture:Functional")\n \n-(Note that we need to give an explicit, unique name to the two layers that re-use the ``IntegrationTesting`` and ``FunctionalTesting`` classes.)\n+(Note that we need to give an explicit, unique name to the two layers that reuse the ``IntegrationTesting`` and ``FunctionalTesting`` classes.)\n \n In this example, other layers could extend the "MyLayer" fixture by using ``MY_FIXTURE`` as a base.\n Tests would use either ``MY_INTEGRATION_TESTING`` or ``MY_FUNCTIONAL_TESTING`` as appropriate.\ndiff --git a/src/plone/testing/_z2_testbrowser.py b/src/plone/testing/_z2_testbrowser.py\nindex fa3948f..d95501e 100644\n--- a/src/plone/testing/_z2_testbrowser.py\n+++ b/src/plone/testing/_z2_testbrowser.py\n@@ -23,7 +23,7 @@ def authHeader(header):\n \n def saveState(func):\n """Save threadlocal state (security manager, local component site) before\n- exectuting a decorated function, and restore it after.\n+ executing a decorated function, and restore it after.\n """\n from AccessControl.SecurityManagement import getSecurityManager\n from AccessControl.SecurityManagement import setSecurityManager\ndiff --git a/src/plone/testing/layer.py b/src/plone/testing/layer.py\nindex e27fbef..6180246 100644\n--- a/src/plone/testing/layer.py\n+++ b/src/plone/testing/layer.py\n@@ -202,7 +202,7 @@ def __init__(self, bases=None, name=None, module=None):\n def __repr__(self):\n return f""\n \n- # Layer lifecycle methods - overriden by subclasses\n+ # Layer lifecycle methods - overridden by subclasses\n \n def setUp(self):\n pass\ndiff --git a/src/plone/testing/tests.py b/src/plone/testing/tests.py\nindex e8fe6d9..36d56de 100644\n--- a/src/plone/testing/tests.py\n+++ b/src/plone/testing/tests.py\n@@ -17,7 +17,7 @@\n else:\n HAS_ZSERVER = True\n \n-# This is somewhat retarted. We execute README.rst as a doctest, mainly just\n+# This is somewhat restarted. We execute README.rst as a doctest, mainly just\n # to test that the code samples import cleanly and are valid Python. However,\n # in there we also have a code sample of a doctest, which gets executed by the\n # doctest runner. Since the method inside the example code block is not yet\ndiff --git a/src/plone/testing/zope.py b/src/plone/testing/zope.py\nindex 572f512..52d9df4 100644\n--- a/src/plone/testing/zope.py\n+++ b/src/plone/testing/zope.py\n@@ -242,7 +242,7 @@ def zopeApp(db=None, connection=None, environ=None):\n connection = app._p_jar\n \n # exceptions in finally clauses can mask exceptions\n- # in the preceeding code block. So we catch\n+ # in the preceding code block. So we catch\n # every exception and throw it instead of the exception\n # in the finally clause\n inner_exception = None\n@@ -607,7 +607,7 @@ def tearDownBasicProducts(self):\n uninstallProduct(app, "Products.OFSP")\n \n # It\'s possible for Five\'s _register_monkies and _meta_type_regs\n- # global variables to contain duplicates. This causes an unecessary\n+ # global variables to contain duplicates. This causes an unnecessary\n # error in the LayerCleanup layer\'s tear-down. Guard against that\n # here\n \n@@ -693,7 +693,7 @@ def tearDownFive(self):\n \n class IntegrationTesting(Layer):\n """This layer extends ``STARTUP`` to add rollback of the transaction\n- after each test. It does not manage a fixture and has no layer lifecyle,\n+ after each test. It does not manage a fixture and has no layer lifecycle,\n only a test lifecycle.\n \n The application root is available as the resource ``app`` and the request\ndiff --git a/src/plone/testing/zope.rst b/src/plone/testing/zope.rst\nindex c1ed640..85bbd73 100644\n--- a/src/plone/testing/zope.rst\n+++ b/src/plone/testing/zope.rst\n@@ -77,7 +77,7 @@ A new connection will be opened and closed.::\n ... \'acl_users\' in app.objectIds()\n True\n \n-If you want to re-use an existing connection, you can pass one to ``zopeApp()`` as the ``connection`` argument.\n+If you want to reuse an existing connection, you can pass one to ``zopeApp()`` as the ``connection`` argument.\n In this case, you will need to close the connection yourself.::\n \n >>> conn = zope.STARTUP[\'zodbDB\'].open()\ndiff --git a/src/plone/testing/zserver.py b/src/plone/testing/zserver.py\nindex ec3634f..1762aef 100644\n--- a/src/plone/testing/zserver.py\n+++ b/src/plone/testing/zserver.py\n@@ -48,7 +48,7 @@ def zopeApp(db=None, connection=None, environ=None):\n connection = app._p_jar\n \n # exceptions in finally clauses can mask exceptions\n- # in the preceeding code block. So we catch\n+ # in the preceding code block. So we catch\n # every exception and throw it instead of the exception\n # in the finally clause\n inner_exception = None\n@@ -205,7 +205,7 @@ def tearDownBasicProducts(self):\n uninstallProduct(app, "Products.OFSP")\n \n # It\'s possible for Five\'s _register_monkies and _meta_type_regs\n- # global variables to contain duplicates. This causes an unecessary\n+ # global variables to contain duplicates. This causes an unnecessary\n # error in the LayerCleanup layer\'s tear-down. Guard against that\n # here\n \n@@ -227,7 +227,7 @@ def tearDownBasicProducts(self):\n \n class IntegrationTesting(zope.IntegrationTesting):\n """This layer extends ``STARTUP`` to add rollback of the transaction\n- after each test. It does not manage a fixture and has no layer lifecyle,\n+ after each test. It does not manage a fixture and has no layer lifecycle,\n only a test lifecycle.\n \n The application root is available as the resource ``app`` and the request\ndiff --git a/src/plone/testing/zserver.rst b/src/plone/testing/zserver.rst\nindex 1b6b0c9..189afd7 100644\n--- a/src/plone/testing/zserver.rst\n+++ b/src/plone/testing/zserver.rst\n@@ -77,7 +77,7 @@ A new connection will be opened and closed.::\n ... \'acl_users\' in app.objectIds()\n True\n \n-If you want to re-use an existing connection, you can pass one to ``zopeApp()`` as the ``connection`` argument.\n+If you want to reuse an existing connection, you can pass one to ``zopeApp()`` as the ``connection`` argument.\n In this case, you will need to close the connection yourself.::\n \n >>> conn = zserver.STARTUP[\'zodbDB\'].open()\n' +b'diff --git a/src/plone/api/tests/test_content.py b/src/plone/api/tests/test_content.py\nindex a873d19b..8ca26f67 100644\n--- a/src/plone/api/tests/test_content.py\n+++ b/src/plone/api/tests/test_content.py\n@@ -7,13 +7,13 @@\n from plone import api\n from plone.api.content import _parse_object_provides_query\n from plone.api.tests.base import INTEGRATION_TESTING\n+from plone.app.contenttypes.interfaces import IFolder\n from plone.app.layout.navigation.interfaces import INavigationRoot\n from plone.app.linkintegrity.exceptions import LinkIntegrityNotificationException\n from plone.app.textfield import RichTextValue\n from plone.indexer import indexer\n from plone.uuid.interfaces import IMutableUUID\n from plone.uuid.interfaces import IUUIDGenerator\n-from Products.CMFCore.interfaces import IContentish\n from Products.CMFCore.WorkflowCore import WorkflowException\n from Products.ZCatalog.interfaces import IZCatalog\n from unittest import mock\n@@ -332,7 +332,7 @@ def test_create_raises_unicodedecodeerror(self):\n \n # register a title indexer that will force a UnicodeDecodeError\n # during content reindexing\n- @indexer(IContentish, IZCatalog)\n+ @indexer(IFolder, IZCatalog)\n def force_unicode_error(object):\n raise UnicodeDecodeError(\n "ascii",\n@@ -989,11 +989,11 @@ def test_find_depth(self):\n \n def test_find_interface(self):\n # Find documents by interface or it\'s identifier\n- identifier = IContentish.__identifier__\n+ identifier = IFolder.__identifier__\n brains = api.content.find(object_provides=identifier)\n by_identifier = [x.getObject() for x in brains]\n \n- brains = api.content.find(object_provides=IContentish)\n+ brains = api.content.find(object_provides=IFolder)\n by_interface = [x.getObject() for x in brains]\n \n self.assertEqual(by_identifier, by_interface)\n@@ -1008,7 +1008,7 @@ def test_find_interface_dict(self):\n brains = api.content.find(\n object_provides={\n "query": [\n- IContentish.__identifier__,\n+ IFolder.__identifier__,\n INavigationRoot.__identifier__,\n ],\n "operator": "and",\n@@ -1020,7 +1020,7 @@ def test_find_interface_dict(self):\n # plone.api query using interfaces\n brains = api.content.find(\n object_provides={\n- "query": [IContentish, INavigationRoot],\n+ "query": [IFolder, INavigationRoot],\n "operator": "and",\n },\n )\n@@ -1030,7 +1030,7 @@ def test_find_interface_dict__include_not_query(self):\n """Check if not query in object_provides is functional."""\n \n brains_all = api.content.find(\n- object_provides={"query": IContentish.__identifier__},\n+ object_provides={"query": IFolder.__identifier__},\n )\n \n alsoProvides(self.portal.events, INavigationRoot)\n@@ -1038,7 +1038,7 @@ def test_find_interface_dict__include_not_query(self):\n \n brains = api.content.find(\n object_provides={\n- "query": IContentish.__identifier__,\n+ "query": IFolder.__identifier__,\n "not": INavigationRoot.__identifier__,\n },\n )\n@@ -1051,42 +1051,42 @@ def test_find_interface_dict__all_options(self):\n parser = _parse_object_provides_query\n \n self.assertDictEqual(\n- parser({"query": IContentish}),\n- {"query": [IContentish.__identifier__], "operator": "or"},\n+ parser({"query": IFolder}),\n+ {"query": [IFolder.__identifier__], "operator": "or"},\n )\n \n self.assertDictEqual(\n parser(\n {\n- "query": [IContentish, INavigationRoot.__identifier__],\n+ "query": [IFolder, INavigationRoot.__identifier__],\n "operator": "and",\n },\n ),\n {\n- "query": [IContentish.__identifier__, INavigationRoot.__identifier__],\n+ "query": [IFolder.__identifier__, INavigationRoot.__identifier__],\n "operator": "and",\n },\n )\n \n self.assertDictEqual(\n- parser({"not": IContentish}),\n- {"not": [IContentish.__identifier__]},\n+ parser({"not": IFolder}),\n+ {"not": [IFolder.__identifier__]},\n )\n \n self.assertDictEqual(\n- parser({"not": [IContentish, INavigationRoot.__identifier__]}),\n- {"not": [IContentish.__identifier__, INavigationRoot.__identifier__]},\n+ parser({"not": [IFolder, INavigationRoot.__identifier__]}),\n+ {"not": [IFolder.__identifier__, INavigationRoot.__identifier__]},\n )\n \n self.assertDictEqual(\n- parser({"not": IContentish}),\n- {"not": [IContentish.__identifier__]},\n+ parser({"not": IFolder}),\n+ {"not": [IFolder.__identifier__]},\n )\n \n self.assertDictEqual(\n- parser({"query": IContentish, "operator": "and", "not": INavigationRoot}),\n+ parser({"query": IFolder, "operator": "and", "not": INavigationRoot}),\n {\n- "query": [IContentish.__identifier__],\n+ "query": [IFolder.__identifier__],\n "operator": "and",\n "not": [INavigationRoot.__identifier__],\n },\n@@ -1133,38 +1133,38 @@ def test_find_parse_object_provides_query(self):\n \n # single interface\n self.assertDictEqual(\n- parse(IContentish),\n+ parse(IFolder),\n {\n- "query": [IContentish.__identifier__],\n+ "query": [IFolder.__identifier__],\n "operator": "or",\n },\n )\n # single identifier\n self.assertDictEqual(\n- parse(IContentish.__identifier__),\n+ parse(IFolder.__identifier__),\n {\n- "query": [IContentish.__identifier__],\n+ "query": [IFolder.__identifier__],\n "operator": "or",\n },\n )\n # multiple interfaces/identifiers (mixed as list)\n self.assertDictEqual(\n- parse([INavigationRoot, IContentish.__identifier__]),\n+ parse([INavigationRoot, IFolder.__identifier__]),\n {\n "query": [\n INavigationRoot.__identifier__,\n- IContentish.__identifier__,\n+ IFolder.__identifier__,\n ],\n "operator": "or",\n },\n )\n # multiple interfaces/identifiers (mixed as tuple)\n self.assertDictEqual(\n- parse((INavigationRoot, IContentish.__identifier__)),\n+ parse((INavigationRoot, IFolder.__identifier__)),\n {\n "query": [\n INavigationRoot.__identifier__,\n- IContentish.__identifier__,\n+ IFolder.__identifier__,\n ],\n "operator": "or",\n },\n@@ -1173,14 +1173,14 @@ def test_find_parse_object_provides_query(self):\n self.assertDictEqual(\n parse(\n {\n- "query": [INavigationRoot, IContentish.__identifier__],\n+ "query": [INavigationRoot, IFolder.__identifier__],\n "operator": "and",\n }\n ),\n {\n "query": [\n INavigationRoot.__identifier__,\n- IContentish.__identifier__,\n+ IFolder.__identifier__,\n ],\n "operator": "and",\n },\n' -Repository: plone.testing +Repository: plone.api Branch: refs/heads/master -Date: 2023-10-15T19:09:56+02:00 -Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/plone.testing/commit/792a522edd67697febe1b6265e6050da9d0b5f21 +Date: 2023-10-19T15:09:11+02:00 +Author: Roel Bruggink (jaroel) +Commit: https://github.com/plone/plone.api/commit/5717ffd8d3d470c96d04514b1f8b3c8da9de57a8 -fix: adapt tests - -Another case of a filesystem access that does not work when running -tests with `tox`. - -In this case, `get_distribution` returns the location within the -`.tox/test` folder structure, while the code is outside of it. - -Fortunately `inspect` module solves the problem. +Spelling Files changed: -M src/plone/testing/tests.py +M src/plone/api/tests/test_content.py -b'diff --git a/src/plone/testing/tests.py b/src/plone/testing/tests.py\nindex 36d56de..c2d8087 100644\n--- a/src/plone/testing/tests.py\n+++ b/src/plone/testing/tests.py\n@@ -1,10 +1,12 @@\n from OFS.SimpleItem import SimpleItem\n-from pkg_resources import get_distribution\n+from pathlib import Path\n from zope.testing import renormalizing\n from ZPublisher.Iterators import filestream_iterator\n \n import doctest\n+import inspect\n import os.path\n+import plone.testing\n import re\n import unittest\n import zope.component.testing\n@@ -46,8 +48,8 @@ def __call__(self):\n \n class DummyFile(SimpleItem):\n def __call__(self):\n- path = get_distribution("plone.testing").location\n- path = os.path.join(path, "plone", "testing", "zope.rst")\n+ path = Path(inspect.getfile(plone.testing))\n+ path = path.parent / "zope.rst"\n \n request = self.REQUEST\n response = request.response\n' +b'diff --git a/src/plone/api/tests/test_content.py b/src/plone/api/tests/test_content.py\nindex 8ca26f67..7123667c 100644\n--- a/src/plone/api/tests/test_content.py\n+++ b/src/plone/api/tests/test_content.py\n@@ -1,5 +1,4 @@\n """Tests for plone.api.content."""\n-\n from Acquisition import aq_base\n from OFS.CopySupport import CopyError\n from OFS.event import ObjectWillBeMovedEvent\n@@ -209,8 +208,8 @@ def test_create_dexterity(self):\n """Test create dexterity."""\n container = self.portal\n \n- # This section check for DX compatibilty. The custom DX types defined\n- # in plone.api are for Plone 4 compatiblity.\n+ # This section check for DX compatibility. The custom DX types defined\n+ # in plone.api are for Plone 4 compatibility.\n \n # Create a folder\n folder = api.content.create(\n@@ -446,7 +445,7 @@ def test_get_constraints(self):\n api.content.get()\n \n def test_get(self):\n- """Test the getting of content in varios ways."""\n+ """Test the getting of content in various ways."""\n # Test getting the about folder by path and UID\n about_by_path = api.content.get("/about")\n about_by_uid = api.content.get(UID=self.about.UID())\n@@ -707,7 +706,7 @@ def test_copy(self):\n container["about"]["our-team"] and container["about"]["our-team"] == ourteam\n )\n \n- # When copying whithout target parameter should take source parent\n+ # When copying without target parameter should take source parent\n api.content.copy(source=self.team, id="our-team-no-target")\n assert container["about"]["our-team-no-target"]\n \n@@ -1283,7 +1282,7 @@ def test_transition(self):\n "internally_published",\n )\n \n- def test_diable_roles_acquisition(self):\n+ def test_disable_roles_acquisition(self):\n """Test disabling local roles acquisition."""\n # This should fail because an content item is mandatory\n from plone.api.exc import MissingParameterError\n' -Repository: plone.testing +Repository: plone.api Branch: refs/heads/master -Date: 2023-10-15T19:09:56+02:00 -Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/plone.testing/commit/72a8e6194924ba7bcc8a42ad5e62923df996969f +Date: 2023-10-19T17:15:52+02:00 +Author: Roel Bruggink (jaroel) +Commit: https://github.com/plone/plone.api/commit/84513e7b7d007c17cde6db284a061830b1fa52d8 -feat: drop six +fixup changelog Files changed: -M setup.py -M src/plone/testing/tests.py -M src/plone/testing/zodb.rst -M src/plone/testing/zope.rst +M news/518.bugfix -b'diff --git a/setup.py b/setup.py\nindex 8008063..05a4652 100644\n--- a/setup.py\n+++ b/setup.py\n@@ -9,7 +9,6 @@\n \n install_requires = [\n "setuptools",\n- "six",\n "zope.testing >= 3.8",\n ]\n \ndiff --git a/src/plone/testing/tests.py b/src/plone/testing/tests.py\nindex c2d8087..3666c43 100644\n--- a/src/plone/testing/tests.py\n+++ b/src/plone/testing/tests.py\n@@ -1,13 +1,11 @@\n from OFS.SimpleItem import SimpleItem\n from pathlib import Path\n-from zope.testing import renormalizing\n from ZPublisher.Iterators import filestream_iterator\n \n import doctest\n import inspect\n import os.path\n import plone.testing\n-import re\n import unittest\n import zope.component.testing\n \n@@ -66,26 +64,6 @@ def tearDown(self):\n zope.component.testing.tearDown()\n \n \n-checker = renormalizing.RENormalizing(\n- [\n- # normalize py2 output to py3\n- (re.compile(r"__builtin__"), r"builtins"),\n- (\n- re.compile(r"\'Unknown directive\', u\'http://namespaces.zope.org/zope\', u\'"),\n- r"\'Unknown directive\', \'http://namespaces.zope.org/zope\', \'",\n- ),\n- # normalize py3 output to py2\n- (\n- re.compile(r"zope\\.configuration\\.xmlconfig\\.ZopeXMLConfigurationError"),\n- r"ZopeXMLConfigurationError",\n- ),\n- (re.compile(r"builtins\\.PopulatedZODB"), r"PopulatedZODB"),\n- (re.compile(r"builtins\\.ExpandedZODB"), r"ExpandedZODB"),\n- (re.compile(r"urllib\\.error\\.URLError"), r"URLError"),\n- ]\n-)\n-\n-\n class TestZ2(unittest.TestCase):\n """Testing plone.testing.z2."""\n \n@@ -107,7 +85,6 @@ def test_suite():\n "publisher.rst",\n "zodb.rst",\n "zope.rst",\n- checker=checker,\n setUp=setUp,\n tearDown=tearDown,\n optionflags=doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE,\ndiff --git a/src/plone/testing/zodb.rst b/src/plone/testing/zodb.rst\nindex a18c473..9f4ac9b 100644\n--- a/src/plone/testing/zodb.rst\n+++ b/src/plone/testing/zodb.rst\n@@ -118,7 +118,7 @@ We\'ll use this new layer in a similar manner to the test above, showing that the\n >>> options = runner.get_options([], [])\n >>> setupLayers = {}\n >>> runner.setup_layer(options, POPULATED_ZODB, setupLayers)\n- Set up PopulatedZODB in ... seconds.\n+ Set up ...PopulatedZODB in ... seconds.\n \n >>> db = POPULATED_ZODB[\'zodbDB\']\n >>> db.storage\n@@ -163,7 +163,7 @@ The transaction has been rolled back.::\n Layer tear-down closes and deletes the database.::\n \n >>> runner.tear_down_unneeded(options, [], setupLayers, [])\n- Tear down PopulatedZODB in ... seconds.\n+ Tear down ...PopulatedZODB in ... seconds.\n \n >>> POPULATED_ZODB.get(\'zodbDB\', None) is None\n True\n@@ -211,8 +211,8 @@ Let\'s simulate a test run again to show how this would work.::\n >>> options = runner.get_options([], [])\n >>> setupLayers = {}\n >>> runner.setup_layer(options, EXPANDED_ZODB, setupLayers)\n- Set up PopulatedZODB in ... seconds.\n- Set up ExpandedZODB in ... seconds.\n+ Set up ...PopulatedZODB in ... seconds.\n+ Set up ...ExpandedZODB in ... seconds.\n \n >>> db = EXPANDED_ZODB[\'zodbDB\']\n >>> db.storage\n@@ -259,7 +259,7 @@ The transaction has been rolled back.::\n We\'ll now tear down the expanded layer and inspect the database again.::\n \n >>> runner.tear_down_unneeded(options, [POPULATED_ZODB], setupLayers, [])\n- Tear down ExpandedZODB in ... seconds.\n+ Tear down ...ExpandedZODB in ... seconds.\n \n >>> conn = EXPANDED_ZODB[\'zodbDB\'].open()\n >>> conn.root()\n@@ -270,7 +270,7 @@ We\'ll now tear down the expanded layer and inspect the database again.::\n Finally, we\'ll tear down the rest of the layers.::\n \n >>> runner.tear_down_unneeded(options, [], setupLayers, [])\n- Tear down PopulatedZODB in ... seconds.\n+ Tear down ...PopulatedZODB in ... seconds.\n \n >>> EXPANDED_ZODB.get(\'zodbDB\', None) is None\n True\ndiff --git a/src/plone/testing/zope.rst b/src/plone/testing/zope.rst\nindex 85bbd73..597407a 100644\n--- a/src/plone/testing/zope.rst\n+++ b/src/plone/testing/zope.rst\n@@ -385,7 +385,7 @@ We can now view this via the test browser:::\n The test browser integration converts the URL into a request and passes control to Zope\'s publisher.\n Let\'s check that query strings are available for input processing:::\n \n- >>> from six.moves.urllib.parse import urlencode\n+ >>> from urllib.parse import urlencode\n >>> _ = app.manage_addDTMLDocument(\'dtml-doc-2\', file=\'\')\n >>> import transaction; transaction.commit()\n >>> qs = urlencode({\'foo\': \'boo, bar & baz\'}) # sic: the ampersand.\n@@ -493,7 +493,7 @@ We can now look for this new object through the server.::\n >>> app_url.split(\':\')[:-1]\n [\'http\', \'//localhost\']\n \n- >>> from six.moves.urllib.request import urlopen\n+ >>> from urllib.request import urlopen\n >>> conn = urlopen(app_url + \'/dtml-doc-3\', timeout=5)\n >>> b\'This is the dtml-doc-3 Document.\' in conn.read()\n True\n' +b'diff --git a/news/518.bugfix b/news/518.bugfix\nindex 437ea89f..bcefc6dd 100644\n--- a/news/518.bugfix\n+++ b/news/518.bugfix\n@@ -1 +1 @@\n-Update test assertions for object_provides index due to Plone Site changes. @Akshat2Jain\n\\ No newline at end of file\n+Fixup tests because PloneSite gets IContentish again. @Akshat2Jain @jaroel\n\\ No newline at end of file\n' -Repository: plone.testing +Repository: plone.api Branch: refs/heads/master -Date: 2023-10-15T19:09:56+02:00 -Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/plone.testing/commit/f2818683413fbaa0c41e3c54428991ed3fa6c517 +Date: 2023-10-19T17:17:48+02:00 +Author: Roel Bruggink (jaroel) +Commit: https://github.com/plone/plone.api/commit/4cd34b882da016c233826578675efbd63e9356d6 -feat: declare dependencies +towncrier entry is internal Files changed: -M setup.py +A news/518.internal +D news/518.bugfix -b'diff --git a/setup.py b/setup.py\nindex 05a4652..89724b4 100644\n--- a/setup.py\n+++ b/setup.py\n@@ -10,21 +10,12 @@\n install_requires = [\n "setuptools",\n "zope.testing >= 3.8",\n+ "five.localsitemanager",\n ]\n \n tests_require = [\n "WebTest",\n- "ZODB",\n "Zope",\n- "zope.browsermenu",\n- "zope.browserpage",\n- "zope.browserresource",\n- "zope.component",\n- "zope.configuration",\n- "zope.event",\n- "zope.interface",\n- "zope.publisher",\n- "zope.security",\n "zope.testbrowser",\n "zope.testrunner",\n ]\n@@ -33,8 +24,6 @@\n [\n "WebTest",\n "Zope",\n- "zope.component",\n- "zope.publisher",\n "zope.testbrowser",\n ],\n )\n' +b'diff --git a/news/518.bugfix b/news/518.internal\nsimilarity index 100%\nrename from news/518.bugfix\nrename to news/518.internal\n' -Repository: plone.testing +Repository: plone.api Branch: refs/heads/master -Date: 2023-10-15T19:09:56+02:00 -Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/plone.testing/commit/5504cdea990e395a2d69dd89be8e59bdc08a3fc7 +Date: 2023-10-19T17:54:22+02:00 +Author: Roel Bruggink (jaroel) +Commit: https://github.com/plone/plone.api/commit/1a14c599dc029b84cd4d6ff7873c7de12266c001 -Add news entry +Merge remote-tracking branch 'origin/master' into fix_number Files changed: -A news/1.breaking -A news/2.breaking -M setup.py +A news/1.bugfix +A news/1.internal +M .github/workflows/black.yml +M .github/workflows/docs.yml +M .github/workflows/isort.yml +M .github/workflows/plone_python.yml +M src/plone/api/tests/test_env.py +M tox.ini -b'diff --git a/news/1.breaking b/news/1.breaking\nnew file mode 100644\nindex 0000000..174ecbf\n--- /dev/null\n+++ b/news/1.breaking\n@@ -0,0 +1,2 @@\n+Drop python 2.7 support.\n+[gforcada]\ndiff --git a/news/2.breaking b/news/2.breaking\nnew file mode 100644\nindex 0000000..e77f813\n--- /dev/null\n+++ b/news/2.breaking\n@@ -0,0 +1,2 @@\n+Drop ZServer support.\n+[gforcada]\ndiff --git a/setup.py b/setup.py\nindex 89724b4..c4c1b86 100644\n--- a/setup.py\n+++ b/setup.py\n@@ -5,7 +5,7 @@\n import os.path\n \n \n-version = "8.0.5.dev0"\n+version = "9.0.0.dev0"\n \n install_requires = [\n "setuptools",\n' +b'diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml\nindex 420028cc..fc5371c7 100644\n--- a/.github/workflows/black.yml\n+++ b/.github/workflows/black.yml\n@@ -10,11 +10,11 @@ jobs:\n \n steps:\n # git checkout\n- - uses: actions/checkout@v2\n+ - uses: actions/checkout@v4\n \n # python setup\n - name: Set up Python ${{ matrix.python-version }}\n- uses: actions/setup-python@v1\n+ uses: actions/setup-python@v4\n with:\n python-version: ${{ matrix.python-version }}\n - name: Install dependencies\n@@ -23,7 +23,7 @@ jobs:\n pip install tox tox-gh-actions\n \n # python cache\n- - uses: actions/cache@v1\n+ - uses: actions/cache@v3\n with:\n path: ~/.cache/pip\n key: ${{ runner.os }}-pip-${{ hashFiles(\'**/requirements.txt\') }}\ndiff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml\nindex 93fc39fc..1cad5df7 100644\n--- a/.github/workflows/docs.yml\n+++ b/.github/workflows/docs.yml\n@@ -10,11 +10,11 @@ jobs:\n \n steps:\n # git checkout\n- - uses: actions/checkout@v2\n+ - uses: actions/checkout@v4\n \n # python setup\n - name: Set up Python ${{ matrix.python-version }}\n- uses: actions/setup-python@v1\n+ uses: actions/setup-python@v4\n with:\n python-version: ${{ matrix.python-version }}\n - name: Install dependencies\n@@ -23,7 +23,7 @@ jobs:\n pip install tox tox-gh-actions\n \n # python cache\n- - uses: actions/cache@v1\n+ - uses: actions/cache@v3\n with:\n path: ~/.cache/pip\n key: ${{ runner.os }}-pip-${{ hashFiles(\'**/requirements.txt\') }}\ndiff --git a/.github/workflows/isort.yml b/.github/workflows/isort.yml\nindex c6f499fc..3176e03f 100644\n--- a/.github/workflows/isort.yml\n+++ b/.github/workflows/isort.yml\n@@ -10,11 +10,11 @@ jobs:\n \n steps:\n # git checkout\n- - uses: actions/checkout@v2\n+ - uses: actions/checkout@v4\n \n # python setup\n - name: Set up Python ${{ matrix.python-version }}\n- uses: actions/setup-python@v1\n+ uses: actions/setup-python@v4\n with:\n python-version: ${{ matrix.python-version }}\n - name: Install dependencies\n@@ -23,7 +23,7 @@ jobs:\n pip install tox tox-gh-actions\n \n # python cache\n- - uses: actions/cache@v1\n+ - uses: actions/cache@v3\n with:\n path: ~/.cache/pip\n key: ${{ runner.os }}-pip-${{ hashFiles(\'**/requirements.txt\') }}\ndiff --git a/.github/workflows/plone_python.yml b/.github/workflows/plone_python.yml\nindex 86771fec..9b1948b9 100644\n--- a/.github/workflows/plone_python.yml\n+++ b/.github/workflows/plone_python.yml\n@@ -16,15 +16,15 @@ jobs:\n strategy:\n fail-fast: false\n matrix:\n- python-version: ["3.7", "3.8", "3.9"]\n- plone-version: ["5.2", "6.0"]\n+ python-version: ["3.8", "3.9", "3.10", "3.11"]\n+ plone-version: ["6.0"]\n \n steps:\n- - uses: actions/checkout@v3\n+ - uses: actions/checkout@v4\n - name: Install system libraries\n run: sudo apt-get install libxml2-dev libxslt1-dev libjpeg-dev\n - name: Set up Python ${{ matrix.python-version }}\n- uses: actions/setup-python@v2\n+ uses: actions/setup-python@v4\n with:\n python-version: ${{ matrix.python-version }}\n - name: Install dependencies\ndiff --git a/news/1.bugfix b/news/1.bugfix\nnew file mode 100644\nindex 00000000..1494e057\n--- /dev/null\n+++ b/news/1.bugfix\n@@ -0,0 +1,2 @@\n+Replace deprecated assert methods.\n+[gforcada]\ndiff --git a/news/1.internal b/news/1.internal\nnew file mode 100644\nindex 00000000..4af1df1b\n--- /dev/null\n+++ b/news/1.internal\n@@ -0,0 +1,2 @@\n+Update GHA\n+[gforcada]\ndiff --git a/src/plone/api/tests/test_env.py b/src/plone/api/tests/test_env.py\nindex f18037ce..3086a4d4 100644\n--- a/src/plone/api/tests/test_env.py\n+++ b/src/plone/api/tests/test_env.py\n@@ -514,14 +514,14 @@ def test_plone_version(self):\n from plone.api.env import plone_version\n \n self.assertTrue(isinstance(plone_version(), str))\n- self.assertRegexpMatches(plone_version(), version_regexp)\n+ self.assertRegex(plone_version(), version_regexp)\n \n def test_zope_version(self):\n """Tests that zope_version() returns Zope version."""\n from plone.api.env import zope_version\n \n self.assertTrue(isinstance(zope_version(), str))\n- self.assertRegexpMatches(zope_version(), version_regexp)\n+ self.assertRegex(zope_version(), version_regexp)\n \n def test_adopt_user_different_username(self):\n user = api.user.get(userid=TEST_USER_ID)\ndiff --git a/tox.ini b/tox.ini\nindex 7f4d12ee..4ec548d9 100644\n--- a/tox.ini\n+++ b/tox.ini\n@@ -1,7 +1,6 @@\n [tox]\n envlist =\n- py{37,38,39}-plone{52}\n- py{38,39}-plone{60}\n+ py{38,39,310,311}-plone{60}\n # towncrier\n # black-enforce\n black-check\n@@ -17,13 +16,13 @@ skip_missing_interpreters = True\n \n [gh-actions]\n python =\n- 3.7: py37\n 3.8: py38\n 3.9: py39\n+ 3.10: py310\n+ 3.11: py311\n \n [gh-actions:env]\n PLONE =\n- 52: plone52\n 60: plone60\n \n \n@@ -40,7 +39,6 @@ commands =\n \n setenv =\n BUILDOUT_FILE=test_plone-60.cfg\n- plone52: BUILDOUT_FILE=test_plone-52.cfg\n \n deps =\n pdbpp\n' -Repository: plone.testing +Repository: plone.api Branch: refs/heads/master -Date: 2023-10-19T10:08:02+02:00 -Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/plone.testing/commit/7be816a84830fd6ea898796a2d0adf91f8d3ec73 +Date: 2023-10-19T14:06:10-03:00 +Author: Wesley Barroso Lopes (wesleybl) +Commit: https://github.com/plone/plone.api/commit/d93c6479b4ac7bf878c033bde2145336dd663fce -Merge pull request #82 from plone/config-with-default-template-1756b024 +Merge pull request #518 from plone/fix_number -Config with default template +Fix failing tests related to object_provides index Files changed: -A .flake8 -A .github/workflows/meta.yml -A .meta.toml -A .pre-commit-config.yaml -A news/1.breaking -A news/2.breaking -A news/5cc689e5.internal -M .editorconfig -M .gitignore -M pyproject.toml -M setup.py -M src/plone/__init__.py -M src/plone/testing/README.rst -M src/plone/testing/__init__.py -M src/plone/testing/_z2_testbrowser.py -M src/plone/testing/layer.py -M src/plone/testing/publisher.py -M src/plone/testing/security.py -M src/plone/testing/testing_zca.zcml -M src/plone/testing/testing_zca_more_specific.zcml -M src/plone/testing/tests.py -M src/plone/testing/z2.py -M src/plone/testing/zca.py -M src/plone/testing/zodb.py -M src/plone/testing/zodb.rst -M src/plone/testing/zope.py -M src/plone/testing/zope.rst -M src/plone/testing/zserver.py -M src/plone/testing/zserver.rst -M tox.ini -D .travis.yml -D bootstrap.py -D buildout.cfg -D setup.cfg +A news/518.internal +M src/plone/api/tests/test_content.py -b'diff --git a/.editorconfig b/.editorconfig\nindex 512361c..8ae05aa 100644\n--- a/.editorconfig\n+++ b/.editorconfig\n@@ -1,4 +1,8 @@\n-# EditorConfig Configurtaion file, for more details see:\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n+#\n+# EditorConfig Configuration file, for more details see:\n # http://EditorConfig.org\n # EditorConfig is a convention description, that could be interpreted\n # by multiple editors to enforce common coding conventions for specific\n@@ -25,12 +29,26 @@ max_line_length = off\n # 4 space indentation\n indent_size = 4\n \n-[*.{yml}]\n+[*.{yml,zpt,pt,dtml,zcml}]\n # 2 space indentation\n indent_size = 2\n \n+[*.{json,jsonl,js,jsx,ts,tsx,css,less,scss,html}] # Frontend development\n+# 2 space indentation\n+indent_size = 2\n+max_line_length = 80\n+\n [{Makefile,.gitmodules}]\n # Tab indentation (no size specified, but view as 4 spaces)\n indent_style = tab\n indent_size = unset\n tab_width = unset\n+\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [editorconfig]\n+# extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\ndiff --git a/.flake8 b/.flake8\nnew file mode 100644\nindex 0000000..7ef4f64\n--- /dev/null\n+++ b/.flake8\n@@ -0,0 +1,22 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n+[flake8]\n+doctests = 1\n+ignore =\n+ # black takes care of line length\n+ E501,\n+ # black takes care of where to break lines\n+ W503,\n+ # black takes care of spaces within slicing (list[:])\n+ E203,\n+ # black takes care of spaces after commas\n+ E231,\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [flake8]\n+# extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\ndiff --git a/.github/workflows/meta.yml b/.github/workflows/meta.yml\nnew file mode 100644\nindex 0000000..39a164d\n--- /dev/null\n+++ b/.github/workflows/meta.yml\n@@ -0,0 +1,68 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n+name: Meta\n+on:\n+ push:\n+ branches:\n+ - master\n+ - main\n+ pull_request:\n+ branches:\n+ - master\n+ - main\n+ workflow_dispatch:\n+\n+##\n+# To set environment variables for all jobs, add in .meta.toml:\n+# [github]\n+# env = """\n+# debug: 1\n+# image-name: \'org/image\'\n+# image-tag: \'latest\'\n+# """\n+##\n+\n+jobs:\n+ qa:\n+ uses: plone/meta/.github/workflows/qa.yml@main\n+ test:\n+ uses: plone/meta/.github/workflows/test.yml@main\n+ coverage:\n+ uses: plone/meta/.github/workflows/coverage.yml@main\n+ dependencies:\n+ uses: plone/meta/.github/workflows/dependencies.yml@main\n+ release_ready:\n+ uses: plone/meta/.github/workflows/release_ready.yml@main\n+ circular:\n+ uses: plone/meta/.github/workflows/circular.yml@main\n+\n+##\n+# To modify the list of default jobs being created add in .meta.toml:\n+# [github]\n+# jobs = [\n+# "qa",\n+# "test",\n+# "coverage",\n+# "dependencies",\n+# "release_ready",\n+# "circular",\n+# ]\n+##\n+\n+##\n+# To request that some OS level dependencies get installed\n+# when running tests/coverage jobs, add in .meta.toml:\n+# [github]\n+# os_dependencies = "git libxml2 libxslt"\n+##\n+\n+\n+##\n+# Specify additional jobs in .meta.toml:\n+# [github]\n+# extra_lines = """\n+# another:\n+# uses: org/repo/.github/workflows/file.yml@main\n+# """\n+##\ndiff --git a/.gitignore b/.gitignore\nindex 8293885..503e47c 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -1,17 +1,55 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n+# python related\n *.egg-info\n *.pyc\n-*.tox\n-.Python\n-.pytest_cache\n+*.pyo\n+\n+# translation related\n+*.mo\n+\n+# tools related\n+build/\n .coverage\n-.installed.cfg\n-bin\n+.*project\n coverage.xml\n-develop-eggs\n-eggs\n-htmlcov/\n+dist/\n+docs/_build\n+__pycache__/\n+.tox\n+.vscode/\n+node_modules/\n+\n+# venv / buildout related\n+bin/\n+develop-eggs/\n+eggs/\n+.eggs/\n+etc/\n+.installed.cfg\n include/\n lib/\n+lib64\n+.mr.developer.cfg\n parts/\n-pip-selfcheck.json\n-_build/\n+pyvenv.cfg\n+var/\n+\n+# mxdev\n+/instance/\n+/.make-sentinels/\n+/*-mxdev.txt\n+/reports/\n+/sources/\n+/venv/\n+.installed.txt\n+\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [gitignore]\n+# extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\ndiff --git a/.meta.toml b/.meta.toml\nnew file mode 100644\nindex 0000000..05b298d\n--- /dev/null\n+++ b/.meta.toml\n@@ -0,0 +1,9 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n+[meta]\n+template = "default"\n+commit-id = "68cda6e4"\n+\n+[pyproject]\n+dependencies_ignores = "[\'ZServer\', \'StringIO\', \'urllib2\']"\ndiff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml\nnew file mode 100644\nindex 0000000..b6eb043\n--- /dev/null\n+++ b/.pre-commit-config.yaml\n@@ -0,0 +1,94 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n+ci:\n+ autofix_prs: false\n+ autoupdate_schedule: monthly\n+\n+repos:\n+- repo: https://github.com/asottile/pyupgrade\n+ rev: v3.14.0\n+ hooks:\n+ - id: pyupgrade\n+ args: [--py38-plus]\n+- repo: https://github.com/pycqa/isort\n+ rev: 5.12.0\n+ hooks:\n+ - id: isort\n+- repo: https://github.com/psf/black\n+ rev: 23.9.1\n+ hooks:\n+ - id: black\n+- repo: https://github.com/collective/zpretty\n+ rev: 3.1.0\n+ hooks:\n+ - id: zpretty\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pre_commit]\n+# zpretty_extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\n+- repo: https://github.com/PyCQA/flake8\n+ rev: 6.1.0\n+ hooks:\n+ - id: flake8\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pre_commit]\n+# flake8_extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\n+- repo: https://github.com/codespell-project/codespell\n+ rev: v2.2.6\n+ hooks:\n+ - id: codespell\n+ additional_dependencies:\n+ - tomli\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pre_commit]\n+# codespell_extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\n+- repo: https://github.com/mgedmin/check-manifest\n+ rev: "0.49"\n+ hooks:\n+ - id: check-manifest\n+- repo: https://github.com/regebro/pyroma\n+ rev: "4.2"\n+ hooks:\n+ - id: pyroma\n+- repo: https://github.com/mgedmin/check-python-versions\n+ rev: "0.21.3"\n+ hooks:\n+ - id: check-python-versions\n+ args: [\'--only\', \'setup.py,pyproject.toml\']\n+- repo: https://github.com/collective/i18ndude\n+ rev: "6.1.0"\n+ hooks:\n+ - id: i18ndude\n+\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pre_commit]\n+# i18ndude_extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\n+\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pre_commit]\n+# extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\ndiff --git a/.travis.yml b/.travis.yml\ndeleted file mode 100644\nindex d3b514f..0000000\n--- a/.travis.yml\n+++ /dev/null\n@@ -1,45 +0,0 @@\n-language: python\n-sudo: false\n-cache: pip\n-\n-matrix:\n- include:\n- - python: "2.7"\n- env: TOXENV=lint-py27\n- - python: "3.6"\n- env: TOXENV=lint-py36\n- - python: "3.7"\n- env: TOXENV=lint-py37\n- - python: "3.8"\n- env: TOXENV=lint-py38\n- - python: "2.7"\n- env: TOXENV=py27\n- - python: "2.7"\n- env: TOXENV=py27-zserver\n- - python: "3.6"\n- env: TOXENV=py36\n- - python: "3.7"\n- env: TOXENV=py37\n- - python: "3.8"\n- env: TOXENV=py38\n- - python: "3.9"\n- env: TOXENV=py39\n- allow_failures:\n- - python: "3.9"\n- env: TOXENV=py39\n-\n-install:\n- - travis_retry pip install -U pip setuptools\n- - travis_retry pip install -U tox coveralls coverage\n-\n-script:\n- - travis_retry tox\n-\n-after_success:\n- - coverage combine\n- - coveralls\n-\n-notifications:\n- email: false\n-cache:\n- pip: true\ndiff --git a/bootstrap.py b/bootstrap.py\ndeleted file mode 100644\nindex a459921..0000000\n--- a/bootstrap.py\n+++ /dev/null\n@@ -1,210 +0,0 @@\n-##############################################################################\n-#\n-# Copyright (c) 2006 Zope Foundation and Contributors.\n-# All Rights Reserved.\n-#\n-# This software is subject to the provisions of the Zope Public License,\n-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.\n-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED\n-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS\n-# FOR A PARTICULAR PURPOSE.\n-#\n-##############################################################################\n-"""Bootstrap a buildout-based project\n-\n-Simply run this script in a directory containing a buildout.cfg.\n-The script accepts buildout command-line options, so you can\n-use the -c option to specify an alternate configuration file.\n-"""\n-\n-import os\n-import shutil\n-import sys\n-import tempfile\n-\n-from optparse import OptionParser\n-\n-__version__ = \'2015-07-01\'\n-# See zc.buildout\'s changelog if this version is up to date.\n-\n-tmpeggs = tempfile.mkdtemp(prefix=\'bootstrap-\')\n-\n-usage = \'\'\'\\\n-[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]\n-\n-Bootstraps a buildout-based project.\n-\n-Simply run this script in a directory containing a buildout.cfg, using the\n-Python that you want bin/buildout to use.\n-\n-Note that by using --find-links to point to local resources, you can keep\n-this script from going over the network.\n-\'\'\'\n-\n-parser = OptionParser(usage=usage)\n-parser.add_option("--version",\n- action="store_true", default=False,\n- help=("Return bootstrap.py version."))\n-parser.add_option("-t", "--accept-buildout-test-releases",\n- dest=\'accept_buildout_test_releases\',\n- action="store_true", default=False,\n- help=("Normally, if you do not specify a --version, the "\n- "bootstrap script and buildout gets the newest "\n- "*final* versions of zc.buildout and its recipes and "\n- "extensions for you. If you use this flag, "\n- "bootstrap and buildout will get the newest releases "\n- "even if they are alphas or betas."))\n-parser.add_option("-c", "--config-file",\n- help=("Specify the path to the buildout configuration "\n- "file to be used."))\n-parser.add_option("-f", "--find-links",\n- help=("Specify a URL to search for buildout releases"))\n-parser.add_option("--allow-site-packages",\n- action="store_true", default=False,\n- help=("Let bootstrap.py use existing site packages"))\n-parser.add_option("--buildout-version",\n- help="Use a specific zc.buildout version")\n-parser.add_option("--setuptools-version",\n- help="Use a specific setuptools version")\n-parser.add_option("--setuptools-to-dir",\n- help=("Allow for re-use of existing directory of "\n- "setuptools versions"))\n-\n-options, args = parser.parse_args()\n-if options.version:\n- print("bootstrap.py version %s" % __version__)\n- sys.exit(0)\n-\n-\n-######################################################################\n-# load/install setuptools\n-\n-try:\n- from urllib.request import urlopen\n-except ImportError:\n- from urllib2 import urlopen\n-\n-ez = {}\n-if os.path.exists(\'ez_setup.py\'):\n- exec(open(\'ez_setup.py\').read(), ez)\n-else:\n- exec(urlopen(\'https://bootstrap.pypa.io/ez_setup.py\').read(), ez)\n-\n-if not options.allow_site_packages:\n- # ez_setup imports site, which adds site packages\n- # this will remove them from the path to ensure that incompatible versions\n- # of setuptools are not in the path\n- import site\n- # inside a virtualenv, there is no \'getsitepackages\'.\n- # We can\'t remove these reliably\n- if hasattr(site, \'getsitepackages\'):\n- for sitepackage_path in site.getsitepackages():\n- # Strip all site-packages directories from sys.path that\n- # are not sys.prefix; this is because on Windows\n- # sys.prefix is a site-package directory.\n- if sitepackage_path != sys.prefix:\n- sys.path[:] = [x for x in sys.path\n- if sitepackage_path not in x]\n-\n-setup_args = dict(to_dir=tmpeggs, download_delay=0)\n-\n-if options.setuptools_version is not None:\n- setup_args[\'version\'] = options.setuptools_version\n-if options.setuptools_to_dir is not None:\n- setup_args[\'to_dir\'] = options.setuptools_to_dir\n-\n-ez[\'use_setuptools\'](**setup_args)\n-import setuptools\n-import pkg_resources\n-\n-# This does not (always?) update the default working set. We will\n-# do it.\n-for path in sys.path:\n- if path not in pkg_resources.working_set.entries:\n- pkg_resources.working_set.add_entry(path)\n-\n-######################################################################\n-# Install buildout\n-\n-ws = pkg_resources.working_set\n-\n-setuptools_path = ws.find(\n- pkg_resources.Requirement.parse(\'setuptools\')).location\n-\n-# Fix sys.path here as easy_install.pth added before PYTHONPATH\n-cmd = [sys.executable, \'-c\',\n- \'import sys; sys.path[0:0] = [%r]; \' % setuptools_path +\n- \'from setuptools.command.easy_install import main; main()\',\n- \'-mZqNxd\', tmpeggs]\n-\n-find_links = os.environ.get(\n- \'bootstrap-testing-find-links\',\n- options.find_links or\n- (\'http://downloads.buildout.org/\'\n- if options.accept_buildout_test_releases else None)\n- )\n-if find_links:\n- cmd.extend([\'-f\', find_links])\n-\n-requirement = \'zc.buildout\'\n-version = options.buildout_version\n-if version is None and not options.accept_buildout_test_releases:\n- # Figure out the most recent final version of zc.buildout.\n- import setuptools.package_index\n- _final_parts = \'*final-\', \'*final\'\n-\n- def _final_version(parsed_version):\n- try:\n- return not parsed_version.is_prerelease\n- except AttributeError:\n- # Older setuptools\n- for part in parsed_version:\n- if (part[:1] == \'*\') and (part not in _final_parts):\n- return False\n- return True\n-\n- index = setuptools.package_index.PackageIndex(\n- search_path=[setuptools_path])\n- if find_links:\n- index.add_find_links((find_links,))\n- req = pkg_resources.Requirement.parse(requirement)\n- if index.obtain(req) is not None:\n- best = []\n- bestv = None\n- for dist in index[req.project_name]:\n- distv = dist.parsed_version\n- if _final_version(distv):\n- if bestv is None or distv > bestv:\n- best = [dist]\n- bestv = distv\n- elif distv == bestv:\n- best.append(dist)\n- if best:\n- best.sort()\n- version = best[-1].version\n-if version:\n- requirement = \'==\'.join((requirement, version))\n-cmd.append(requirement)\n-\n-import subprocess\n-if subprocess.call(cmd) != 0:\n- raise Exception(\n- "Failed to execute command:\\n%s" % repr(cmd)[1:-1])\n-\n-######################################################################\n-# Import and run buildout\n-\n-ws.add_entry(tmpeggs)\n-ws.require(requirement)\n-import zc.buildout.buildout\n-\n-if not [a for a in args if \'=\' not in a]:\n- args.append(\'bootstrap\')\n-\n-# if -c was provided, we push it back into args for buildout\' main function\n-if options.config_file is not None:\n- args[0:0] = [\'-c\', options.config_file]\n-\n-zc.buildout.buildout.main(args)\n-shutil.rmtree(tmpeggs)\ndiff --git a/buildout.cfg b/buildout.cfg\ndeleted file mode 100644\nindex b5e35ab..0000000\n--- a/buildout.cfg\n+++ /dev/null\n@@ -1,52 +0,0 @@\n-[buildout]\n-extends =\n- https://raw.githubusercontent.com/plone/buildout.coredev/5.2/versions.cfg\n-parts =\n- coverage\n- test\n- report\n- report-xml\n-\n-develop = .\n-prefer-final = false\n-\n-[versions]\n-setuptools =\n-zc.buildout =\n-plone.testing =\n-# From 2018-10-02\n-# Please remove this pinning after we get on top of the ZODB issues!\n-ZODB = < 5.4.0\n-# From 2018-10-06\n-# Please remove this pinning once the Zope 4.0 stack allows for it!\n-ZServer = < 4.0b3\n-# From 2018-10-06\n-# Please remove this pinning once collective.xmltestreport cuts a release!\n-zope.testrunner = < 4.9.0\n-\n-[test]\n-recipe = collective.xmltestreport\n-eggs =\n- plone.testing [test]\n-defaults = [\'--auto-color\', \'--auto-progress\']\n-\n-[coverage]\n-recipe = zc.recipe.egg\n-eggs = coverage\n-initialization =\n- include = \'--source=${buildout:directory}/src\'\n- sys.argv = sys.argv[:] + [\'run\', include, \'bin/test\', \'--all\', \'--xml\']\n-\n-[report]\n-recipe = zc.recipe.egg\n-eggs = coverage\n-scripts = coverage=report\n-initialization =\n- sys.argv = sys.argv[:] + [\'html\', \'-i\']\n-\n-[report-xml]\n-recipe = zc.recipe.egg\n-eggs = coverage\n-scripts = coverage=report-xml\n-initialization =\n- sys.argv = sys.argv[:] + [\'xml\', \'-i\']\ndiff --git a/news/1.breaking b/news/1.breaking\nnew file mode 100644\nindex 0000000..174ecbf\n--- /dev/null\n+++ b/news/1.breaking\n@@ -0,0 +1,2 @@\n+Drop python 2.7 support.\n+[gforcada]\ndiff --git a/news/2.breaking b/news/2.breaking\nnew file mode 100644\nindex 0000000..e77f813\n--- /dev/null\n+++ b/news/2.breaking\n@@ -0,0 +1,2 @@\n+Drop ZServer support.\n+[gforcada]\ndiff --git a/news/5cc689e5.internal b/news/5cc689e5.internal\nnew file mode 100644\nindex 0000000..c08f539\n--- /dev/null\n+++ b/news/5cc689e5.internal\n@@ -0,0 +1,2 @@\n+Update configuration files.\n+[plone devs]\ndiff --git a/pyproject.toml b/pyproject.toml\nindex 12c6bc8..e0decf5 100644\n--- a/pyproject.toml\n+++ b/pyproject.toml\n@@ -1,3 +1,6 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n [tool.towncrier]\n directory = "news/"\n filename = "CHANGES.rst"\n@@ -34,5 +37,121 @@ directory = "tests"\n name = "Tests"\n showcontent = true\n \n+##\n+# Add extra configuration options in .meta.toml:\n+# [pyproject]\n+# towncrier_extra_lines = """\n+# extra_configuration\n+# """\n+##\n+\n [tool.isort]\n profile = "plone"\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pyproject]\n+# isort_extra_lines = """\n+# extra_configuration\n+# """\n+##\n+\n+[tool.black]\n+target-version = ["py38"]\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pyproject]\n+# black_extra_lines = """\n+# extra_configuration\n+# """\n+##\n+\n+[tool.codespell]\n+ignore-words-list = "discreet,"\n+skip = "*.po,"\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pyproject]\n+# codespell_ignores = "foo,bar"\n+# codespell_skip = "*.po,*.map,package-lock.json"\n+##\n+\n+[tool.dependencychecker]\n+Zope = [\n+ # Zope own provided namespaces\n+ \'App\', \'OFS\', \'Products.Five\', \'Products.OFSP\', \'Products.PageTemplates\',\n+ \'Products.SiteAccess\', \'Shared\', \'Testing\', \'ZPublisher\', \'ZTUtils\',\n+ \'Zope2\', \'webdav\', \'zmi\',\n+ # ExtensionClass own provided namespaces\n+ \'ExtensionClass\', \'ComputedAttribute\', \'MethodObject\',\n+ # Zope dependencies\n+ \'AccessControl\', \'Acquisition\', \'AuthEncoding\', \'beautifulsoup4\', \'BTrees\',\n+ \'cffi\', \'Chameleon\', \'DateTime\', \'DocumentTemplate\',\n+ \'MultiMapping\', \'multipart\', \'PasteDeploy\', \'Persistence\', \'persistent\',\n+ \'pycparser\', \'python-gettext\', \'pytz\', \'RestrictedPython\', \'roman\',\n+ \'soupsieve\', \'transaction\', \'waitress\', \'WebOb\', \'WebTest\', \'WSGIProxy2\',\n+ \'z3c.pt\', \'zc.lockfile\', \'ZConfig\', \'zExceptions\', \'ZODB\', \'zodbpickle\',\n+ \'zope.annotation\', \'zope.browser\', \'zope.browsermenu\', \'zope.browserpage\',\n+ \'zope.browserresource\', \'zope.cachedescriptors\', \'zope.component\',\n+ \'zope.configuration\', \'zope.container\', \'zope.contentprovider\',\n+ \'zope.contenttype\', \'zope.datetime\', \'zope.deferredimport\',\n+ \'zope.deprecation\', \'zope.dottedname\', \'zope.event\', \'zope.exceptions\',\n+ \'zope.filerepresentation\', \'zope.globalrequest\', \'zope.hookable\',\n+ \'zope.i18n\', \'zope.i18nmessageid\', \'zope.interface\', \'zope.lifecycleevent\',\n+ \'zope.location\', \'zope.pagetemplate\', \'zope.processlifetime\', \'zope.proxy\',\n+ \'zope.ptresource\', \'zope.publisher\', \'zope.schema\', \'zope.security\',\n+ \'zope.sequencesort\', \'zope.site\', \'zope.size\', \'zope.structuredtext\',\n+ \'zope.tal\', \'zope.tales\', \'zope.testbrowser\', \'zope.testing\',\n+ \'zope.traversing\', \'zope.viewlet\'\n+]\n+\'Products.CMFCore\' = [\n+ \'docutils\', \'five.localsitemanager\', \'Missing\', \'Products.BTreeFolder2\',\n+ \'Products.GenericSetup\', \'Products.MailHost\', \'Products.PythonScripts\',\n+ \'Products.StandardCacheManagers\', \'Products.ZCatalog\', \'Record\',\n+ \'zope.sendmail\', \'Zope\'\n+]\n+\'plone.base\' = [\n+ \'plone.batching\', \'plone.registry\', \'plone.schema\',\'plone.z3cform\',\n+ \'Products.CMFCore\', \'Products.CMFDynamicViewFTI\',\n+]\n+python-dateutil = [\'dateutil\']\n+ignore-packages = [\'ZServer\', \'StringIO\', \'urllib2\']\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pyproject]\n+# dependencies_ignores = "[\'zestreleaser.towncrier\']"\n+# dependencies_mappings = [\n+# "gitpython = [\'git\']",\n+# "pygithub = [\'github\']",\n+# ]\n+##\n+\n+[tool.check-manifest]\n+ignore = [\n+ ".editorconfig",\n+ ".meta.toml",\n+ ".pre-commit-config.yaml",\n+ "tox.ini",\n+ ".flake8",\n+ "mx.ini",\n+\n+]\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pyproject]\n+# check_manifest_ignores = """\n+# "*.map.js",\n+# "*.pyc",\n+# """\n+##\n+\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [pyproject]\n+# extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\ndiff --git a/setup.cfg b/setup.cfg\ndeleted file mode 100644\nindex f408c8d..0000000\n--- a/setup.cfg\n+++ /dev/null\n@@ -1,60 +0,0 @@\n-[build_sphinx]\n-source-dir = docs/source\n-build-dir = _build/docs\n-all_files = 1\n-\n-[upload_sphinx]\n-upload-dir = _build/docs/html\n-\n-[check-manifest]\n-ignore =\n- .editorconfig\n- bootstrap.py\n- buildout.cfg\n- tox.ini\n-\n-[coverage:run]\n-branch = True\n-\n-source =\n- src\n-\n-omit =\n-\n-[coverage:report]\n-precision = 2\n-\n-[coverage:html]\n-directory = _build/reports/coverage\n-\n-\n-[isort]\n-# for details see\n-# http://docs.plone.org/develop/styleguide/python.html#grouping-and-sorting\n-force_alphabetical_sort = True\n-force_single_line = True\n-lines_after_imports = 2\n-line_length = 200\n-\n-[flake8]\n-exclude =\n- bootstrap.py,\n-\n-include =\n- src\n-\n-ignore =\n- N801,\n- N802,\n- N803,\n- N805,\n- N806,\n- N812,\n- T000,\n- T003,\n-\n-[zest.releaser]\n-create-wheel = yes\n-\n-[bdist_wheel]\n-universal = 1\ndiff --git a/setup.py b/setup.py\nindex 14de75c..c4c1b86 100644\n--- a/setup.py\n+++ b/setup.py\n@@ -1,4 +1,3 @@\n-# -*- coding: utf-8 -*-\n from setuptools import find_packages\n from setuptools import setup\n \n@@ -6,112 +5,106 @@\n import os.path\n \n \n-version = \'8.0.5.dev0\'\n+version = "9.0.0.dev0"\n \n install_requires = [\n- \'setuptools\',\n- \'six\',\n- \'zope.testing >= 3.8\',\n+ "setuptools",\n+ "zope.testing >= 3.8",\n+ "five.localsitemanager",\n ]\n \n tests_require = [\n- \'WebTest\',\n- \'ZODB\',\n- \'Zope\',\n- \'zope.browsermenu\',\n- \'zope.browserpage\',\n- \'zope.browserresource\',\n- \'zope.component\',\n- \'zope.configuration\',\n- \'zope.event\',\n- \'zope.interface\',\n- \'zope.publisher\',\n- \'zope.security\',\n- \'zope.testbrowser\',\n- \'zope.testrunner\',\n+ "WebTest",\n+ "Zope",\n+ "zope.testbrowser",\n+ "zope.testrunner",\n ]\n \n-zope_requires = [\n- \'WebTest\',\n- \'Zope\',\n- \'zope.component\',\n- \'zope.publisher\',\n- \'zope.testbrowser\',\n-],\n+zope_requires = (\n+ [\n+ "WebTest",\n+ "Zope",\n+ "zope.testbrowser",\n+ ],\n+)\n \n \n setup(\n- name=\'plone.testing\',\n+ name="plone.testing",\n version=version,\n description="Testing infrastructure for Zope and Plone projects.",\n- long_description=(u\'\\n\\n\'.join([\n- open(os.path.join("src", "plone", "testing", "README.rst")).read(),\n- open("CHANGES.rst").read(),\n- "Detailed documentation\\n"\n- + "======================",\n- open(os.path.join("src", "plone", "testing", "layer.rst")).read(),\n- open(os.path.join("src", "plone", "testing", "zca.rst")).read(),\n- open(os.path.join("src", "plone", "testing", "security.rst")).read(),\n- open(os.path.join("src", "plone", "testing", "publisher.rst")).read(),\n- open(os.path.join("src", "plone", "testing", "zodb.rst")).read(),\n- open(os.path.join("src", "plone", "testing", "zope.rst")).read(),\n- open(os.path.join("src", "plone", "testing", "zserver.rst")).read(),\n- ])),\n+ long_description=(\n+ "\\n\\n".join(\n+ [\n+ open(os.path.join("src", "plone", "testing", "README.rst")).read(),\n+ open("CHANGES.rst").read(),\n+ "Detailed documentation\\n" + "======================",\n+ open(os.path.join("src", "plone", "testing", "layer.rst")).read(),\n+ open(os.path.join("src", "plone", "testing", "zca.rst")).read(),\n+ open(os.path.join("src", "plone", "testing", "security.rst")).read(),\n+ open(os.path.join("src", "plone", "testing", "publisher.rst")).read(),\n+ open(os.path.join("src", "plone", "testing", "zodb.rst")).read(),\n+ open(os.path.join("src", "plone", "testing", "zope.rst")).read(),\n+ open(os.path.join("src", "plone", "testing", "zserver.rst")).read(),\n+ ]\n+ )\n+ ),\n classifiers=[\n "Development Status :: 5 - Production/Stable",\n "Environment :: Web Environment",\n- "Framework :: Plone :: 5.2",\n- "Framework :: Plone :: Core",\n "Framework :: Plone",\n- "Framework :: Zope :: 4",\n+ "Framework :: Plone :: 6.0",\n+ "Framework :: Plone :: Core",\n+ "Framework :: Zope :: 5",\n "Intended Audience :: Developers",\n "License :: OSI Approved :: BSD License",\n "Operating System :: OS Independent",\n- "Programming Language :: Python :: 2.7",\n- "Programming Language :: Python :: 3.6",\n- "Programming Language :: Python :: 3.7",\n+ "Programming Language :: Python",\n "Programming Language :: Python :: 3.8",\n "Programming Language :: Python :: 3.9",\n+ "Programming Language :: Python :: 3.10",\n+ "Programming Language :: Python :: 3.11",\n "Programming Language :: Python :: Implementation :: CPython",\n "Programming Language :: Python",\n "Topic :: Internet :: WWW/HTTP :: Dynamic Content",\n "Topic :: Software Development :: Testing",\n ],\n- keywords=\'plone zope testing\',\n- author=\'Plone Foundation\',\n- author_email=\'plone-developers@lists.sourceforge.net\',\n- url=\'https://github.com/plone/plone.testing\',\n- license=\'BSD\',\n- packages=find_packages(\'src\'),\n- package_dir={\'\': \'src\'},\n- namespace_packages=[\'plone\'],\n+ keywords="plone zope testing",\n+ author="Plone Foundation",\n+ author_email="plone-developers@lists.sourceforge.net",\n+ url="https://github.com/plone/plone.testing",\n+ license="BSD",\n+ packages=find_packages("src"),\n+ package_dir={"": "src"},\n+ namespace_packages=["plone"],\n include_package_data=True,\n zip_safe=False,\n+ python_requires=">=3.8",\n install_requires=install_requires,\n tests_require=tests_require,\n extras_require={\n- \'test\': tests_require,\n- \'zodb\': [\'ZODB\'],\n- \'zca\': [\n- \'zope.component\',\n- \'zope.configuration\',\n- \'zope.event\',\n+ "test": tests_require,\n+ "zodb": ["ZODB"],\n+ "zca": [\n+ "zope.component",\n+ "zope.configuration",\n+ "zope.event",\n ],\n- \'security\': [\n- \'zope.security\',\n+ "security": [\n+ "zope.security",\n ],\n- \'publisher\': [\n- \'zope.browsermenu\',\n- \'zope.browserpage\',\n- \'zope.browserresource\',\n- \'zope.configuration\',\n- \'zope.publisher\',\n- \'zope.security\',\n+ "publisher": [\n+ "zope.browsermenu",\n+ "zope.browserpage",\n+ "zope.browserresource",\n+ "zope.configuration",\n+ "zope.publisher",\n+ "zope.security",\n ],\n- \'z2\': [], # BBB\n- \'zope\': zope_requires,\n- \'zserver\': [\n- \'ZServer\',\n+ "z2": [], # BBB\n+ "zope": zope_requires,\n+ "zserver": [\n+ "ZServer",\n ],\n },\n )\ndiff --git a/src/plone/__init__.py b/src/plone/__init__.py\nindex 68c04af..5284146 100644\n--- a/src/plone/__init__.py\n+++ b/src/plone/__init__.py\n@@ -1,2 +1 @@\n-# -*- coding: utf-8 -*-\n-__import__(\'pkg_resources\').declare_namespace(__name__)\n+__import__("pkg_resources").declare_namespace(__name__)\ndiff --git a/src/plone/testing/README.rst b/src/plone/testing/README.rst\nindex 36d4164..69fc422 100644\n--- a/src/plone/testing/README.rst\n+++ b/src/plone/testing/README.rst\n@@ -280,7 +280,7 @@ The available extras are:\n Adding a test buildout to your package\n --------------------------------------\n \n-When creating re-usable, mostly stand-alone packages, it is often useful to be able to include a buildout with the package sources itself that can be used to create a test runner.\n+When creating reusable, mostly stand-alone packages, it is often useful to be able to include a buildout with the package sources itself that can be used to create a test runner.\n This is a popular approach for many Zope packages, for example.\n In fact, ``plone.testing`` itself uses this kind of layout.\n \n@@ -388,7 +388,7 @@ For example, if you are writing a set of integration tests, you may need to set\n This type of test fixture setup can be resource-intensive and time-consuming.\n If it is possible to only perform the setup and tear-down once for a set of tests without losing isolation between those tests, test runs can often be sped up significantly.\n \n-Layers also allow re-use of test fixtures and set-up/tear-down code.\n+Layers also allow reuse of test fixtures and set-up/tear-down code.\n ``plone.testing`` provides a number of useful (but optional) layers that manage test fixtures for common Zope testing scenarios, letting you focus on the actual test authoring.\n \n At the most basic, a layer is an object with the following methods and attributes:\n@@ -464,7 +464,7 @@ All four are optional.\n The default implementation of each does nothing.\n \n By convention, layers are created in a module called ``testing.py`` at the top level of your package.\n-The idea is that other packages that extend your package can re-use your layers for their own testing.\n+The idea is that other packages that extend your package can reuse your layers for their own testing.\n \n A simple layer may look like this::\n \n@@ -530,7 +530,7 @@ Above, we are really saying that *instances* of ``ZIGSpaceShip`` will, by defaul\n \n * The instance is usually a shared, module-global object, although in some cases it is useful to create copies of layers by instantiating the class more than once.\n \n- * Subclassing an existing layer class is just straightforward OOP re-use: the test runner is not aware of the subclassing relationship.\n+ * Subclassing an existing layer class is just straightforward OOP reuse: the test runner is not aware of the subclassing relationship.\n \n * A layer *instance* can be associated with any number of layer *bases*, via its ``__bases__`` property (which is usually via the ``defaultBases`` variable in the class body and/or overridden using the ``bases`` argument to the ``Layer`` constructor).\n These bases are layer *instances*, not classes.\n@@ -544,9 +544,9 @@ Advanced - overriding bases\n ---------------------------\n \n In some cases, it may be useful to create a copy of a layer, but change its bases.\n-One reason to do this may if you are re-using a layer from another module, and you need to change the order in which layers are set up and torn down.\n+One reason to do this may if you are reusing a layer from another module, and you need to change the order in which layers are set up and torn down.\n \n-Normally, of course, you would just re-use the layer instance, either directly in a test, or in the ``defaultBases`` tuple of another layer, but if you need to change the bases, you can pass a new list of bases to the layer instance constructor:::\n+Normally, of course, you would just reuse the layer instance, either directly in a test, or in the ``defaultBases`` tuple of another layer, but if you need to change the bases, you can pass a new list of bases to the layer instance constructor:::\n \n >>> class CATSMessage(Layer):\n ...\n@@ -591,7 +591,7 @@ Layer resources\n Many layers will manage one or more resources that are used either by other layers, or by tests themselves.\n Examples may include database connections, thread-local objects, or configuration data.\n \n-``plone.testing`` contains a simple resource storage abstraction that makes it easy to access resources from dependant layers or tests.\n+``plone.testing`` contains a simple resource storage abstraction that makes it easy to access resources from dependent layers or tests.\n The resource storage uses dictionary notation:::\n \n >>> class WarpDrive(object):\n@@ -725,7 +725,7 @@ to share some test logic.\n \n Two special methods, ``setUp()`` and ``tearDown()``, can also be added.\n These will be called before or after each test, respectively, and provide a useful place to construct and clean up test fixtures without writing a custom layer.\n-They are obviously not as re-usable as layers, though.\n+They are obviously not as reusable as layers, though.\n \n *Hint:* Somewhat confusingly, the ``setUp()`` and ``tearDown()`` methods in a test case class are the equivalent of the ``testSetUp()`` and ``testTearDown()`` methods of a layer class.\n \n@@ -1141,7 +1141,7 @@ To load the configuration for a particular package, use ``xmlconfig.file()``:::\n This takes two required arguments: the file name and the module relative to which it is to be found.\n Here, we have loaded two files: ``meta.zcml`` and ``configure.zcml``.\n The first call to ``xmlconfig.file()`` creates and returns a configuration context.\n-We re-use that for the subsequent invocation, so that the directives configured are available.\n+We reuse that for the subsequent invocation, so that the directives configured are available.\n \n Installing a Zope product\n -------------------------\n@@ -1685,7 +1685,7 @@ For example::\n MY_INTEGRATION_TESTING = zope.IntegrationTesting(bases=(MY_FIXTURE,), name="MyFixture:Integration")\n MY_FUNCTIONAL_TESTING = zope.FunctionalTesting(bases=(MY_FIXTURE,), name="MyFixture:Functional")\n \n-(Note that we need to give an explicit, unique name to the two layers that re-use the ``IntegrationTesting`` and ``FunctionalTesting`` classes.)\n+(Note that we need to give an explicit, unique name to the two layers that reuse the ``IntegrationTesting`` and ``FunctionalTesting`` classes.)\n \n In this example, other layers could extend the "MyLayer" fixture by using ``MY_FIXTURE`` as a base.\n Tests would use either ``MY_INTEGRATION_TESTING`` or ``MY_FUNCTIONAL_TESTING`` as appropriate.\n@@ -1948,7 +1948,7 @@ For example::\n MY_INTEGRATION_TESTING = zserver.IntegrationTesting(bases=(MY_FIXTURE,), name="MyFixture:Integration")\n MY_FUNCTIONAL_TESTING = zserver.FunctionalTesting(bases=(MY_FIXTURE,), name="MyFixture:Functional")\n \n-(Note that we need to give an explicit, unique name to the two layers that re-use the ``IntegrationTesting`` and ``FunctionalTesting`` classes.)\n+(Note that we need to give an explicit, unique name to the two layers that reuse the ``IntegrationTesting`` and ``FunctionalTesting`` classes.)\n \n In this example, other layers could extend the "MyLayer" fixture by using ``MY_FIXTURE`` as a base.\n Tests would use either ``MY_INTEGRATION_TESTING`` or ``MY_FUNCTIONAL_TESTING`` as appropriate.\ndiff --git a/src/plone/testing/__init__.py b/src/plone/testing/__init__.py\nindex 0772d96..6dc8334 100644\n--- a/src/plone/testing/__init__.py\n+++ b/src/plone/testing/__init__.py\n@@ -1,4 +1,3 @@\n-# -*- coding: utf-8 -*-\n # flake8: NOQA: F401\n # Convenience imports\n from plone.testing.layer import Layer\ndiff --git a/src/plone/testing/_z2_testbrowser.py b/src/plone/testing/_z2_testbrowser.py\nindex 2486f60..d95501e 100644\n--- a/src/plone/testing/_z2_testbrowser.py\n+++ b/src/plone/testing/_z2_testbrowser.py\n@@ -1,6 +1,3 @@\n-# -*- coding: utf-8 -*-\n-from __future__ import absolute_import\n-\n from zope.testbrowser import browser\n from ZPublisher.httpexceptions import HTTPExceptionHandler\n from ZPublisher.utils import basic_auth_encode\n@@ -9,7 +6,7 @@\n import re\n \n \n-BASIC_RE = re.compile(\'Basic (.+)?:(.+)?$\')\n+BASIC_RE = re.compile("Basic (.+)?:(.+)?$")\n \n \n def authHeader(header):\n@@ -17,16 +14,16 @@ def authHeader(header):\n if match:\n u, p = match.group(1, 2)\n if u is None:\n- u = \'\'\n+ u = ""\n if p is None:\n- p = \'\'\n+ p = ""\n return basic_auth_encode(u, p)\n return header\n \n \n def saveState(func):\n """Save threadlocal state (security manager, local component site) before\n- exectuting a decorated function, and restore it after.\n+ executing a decorated function, and restore it after.\n """\n from AccessControl.SecurityManagement import getSecurityManager\n from AccessControl.SecurityManagement import setSecurityManager\n@@ -40,10 +37,11 @@ def wrapped_func(*args, **kw):\n finally:\n setSecurityManager(sm)\n setSite(site)\n+\n return wrapped_func\n \n \n-class Zope2Caller(object):\n+class Zope2Caller:\n """Functional testing caller that can execute HTTP requests via the\n Zope 2 WSGI publisher.\n """\n@@ -54,9 +52,8 @@ def __init__(self, browser, app):\n \n @saveState\n def __call__(self, environ, start_response):\n-\n # Base64 encode auth header\n- http_auth = \'HTTP_AUTHORIZATION\'\n+ http_auth = "HTTP_AUTHORIZATION"\n if http_auth in environ:\n environ[http_auth] = authHeader(environ[http_auth])\n \n@@ -79,8 +76,8 @@ class Browser(browser.Browser):\n \n def __init__(self, app, url=None):\n wsgi_app = Zope2Caller(self, app)\n- super(Browser, self).__init__(url=url, wsgi_app=wsgi_app)\n+ super().__init__(url=url, wsgi_app=wsgi_app)\n \n \n # Add `nohost` to testbrowser\'s set of allowed hosts\n-browser._allowed.add(\'nohost\')\n+browser._allowed.add("nohost")\ndiff --git a/src/plone/testing/layer.py b/src/plone/testing/layer.py\nindex 90dc791..6180246 100644\n--- a/src/plone/testing/layer.py\n+++ b/src/plone/testing/layer.py\n@@ -1,13 +1,11 @@\n-# -*- coding: utf-8 -*-\n import sys\n \n \n _marker = object()\n \n \n-class ResourceManager(object):\n- """Mixin class for resource managers.\n- """\n+class ResourceManager:\n+ """Mixin class for resource managers."""\n \n __bases__ = () # must be set as an instance variable by subclass\n \n@@ -17,7 +15,7 @@ def __init__(self):\n \n def get(self, key, default=None):\n for resourceManager in self.baseResolutionOrder:\n- if key in getattr(resourceManager, \'_resources\', {}):\n+ if key in getattr(resourceManager, "_resources", {}):\n # Get the value on the top of the stack\n return resourceManager._resources[key][-1][0]\n return default\n@@ -37,14 +35,13 @@ def __setitem__(self, key, value):\n foundStack = False\n \n for resourceManager in self.baseResolutionOrder:\n- if key in getattr(resourceManager, \'_resources\', {}):\n+ if key in getattr(resourceManager, "_resources", {}):\n stack = resourceManager._resources[key]\n foundStack = True\n \n foundStackItem = False\n for idx in range(len(stack) - 1, -1, -1):\n if stack[idx][1] is self:\n-\n # This layer instance has already added an item to\n # the stack. Update that item instead of pushing a new\n # item onto the stack.\n@@ -56,7 +53,12 @@ def __setitem__(self, key, value):\n # This layer instance does not have a stack item yet. Create\n # a new one.\n if not foundStackItem:\n- stack.append([value, self, ])\n+ stack.append(\n+ [\n+ value,\n+ self,\n+ ]\n+ )\n \n # Note: We do not break here on purpose: it\'s possible\n # that there is resource stack in another branch of the base\n@@ -69,7 +71,7 @@ def __setitem__(self, key, value):\n def __delitem__(self, key):\n found = False\n for resourceManager in self.baseResolutionOrder:\n- if key in getattr(resourceManager, \'_resources\', {}):\n+ if key in getattr(resourceManager, "_resources", {}):\n stack = resourceManager._resources[key]\n for idx in range(len(stack) - 1, -1, -1):\n if stack[idx][1] is self:\n@@ -93,7 +95,6 @@ def __delitem__(self, key):\n # http://www.python.org/download/releases/2.3/mro/\n \n def _mergeResourceManagers(self, seqs):\n-\n res = []\n i = 0\n \n@@ -114,7 +115,7 @@ def _mergeResourceManagers(self, seqs):\n break\n \n if not cand:\n- raise TypeError(u\'Inconsistent layer hierarchy!\')\n+ raise TypeError("Inconsistent layer hierarchy!")\n \n res.append(cand)\n for seq in nonemptyseqs: # remove cand\n@@ -130,8 +131,7 @@ def _resourceResolutionOrder(self, instance):\n \n \n class Layer(ResourceManager):\n- """A base class for layers.\n- """\n+ """A base class for layers."""\n \n # Set this at the class level to a tuple of layer *instances* to treat\n # as bases for this layer. This may be overridden by passing a tuple\n@@ -156,43 +156,53 @@ def __init__(self, bases=None, name=None, module=None):\n """\n \n if self.__class__ is Layer and name is None:\n- raise ValueError(\'The `name` argument is required when instantiating `Layer` directly\') # NOQA: E501\n+ raise ValueError(\n+ "The `name` argument is required when instantiating `Layer` directly"\n+ ) # NOQA: E501\n \n if name is None and bases is not None:\n- raise ValueError(\'The `name`` argument is required when overriding bases with the `bases` argument\') # NOQA: E501\n+ raise ValueError(\n+ "The `name`` argument is required when overriding bases with the `bases` argument"\n+ ) # NOQA: E501\n \n- super(Layer, self).__init__()\n+ super().__init__()\n \n if bases is None:\n bases = self.defaultBases\n \n try:\n self.__bases__ = tuple(bases)\n- except (KeyError, TypeError,):\n- raise ValueError(\'The `bases` argument must be a sequence.\')\n+ except (\n+ KeyError,\n+ TypeError,\n+ ):\n+ raise ValueError("The `bases` argument must be a sequence.")\n \n if name is None:\n name = self.__class__.__name__\n self.__name__ = name\n \n if module is None:\n-\n # Get the module name of whatever instantiated the layer, not\n # the class, by default\n \n try:\n- module = sys._getframe(1).f_globals[\'__name__\']\n- except (ValueError, AttributeError, KeyError,):\n+ module = sys._getframe(1).f_globals["__name__"]\n+ except (\n+ ValueError,\n+ AttributeError,\n+ KeyError,\n+ ):\n module = self.__class__.__module__\n \n self.__module__ = module\n \n- super(Layer, self).__init__()\n+ super().__init__()\n \n def __repr__(self):\n- return "".format(self.__module__, self.__name__,)\n+ return f""\n \n- # Layer lifecycle methods - overriden by subclasses\n+ # Layer lifecycle methods - overridden by subclasses\n \n def setUp(self):\n pass\n@@ -223,7 +233,7 @@ def layered(suite, layer, addLayerToDoctestGlobs=True):\n except AttributeError:\n pass\n else:\n- if \'layer\' not in globs:\n- globs[\'layer\'] = layer\n+ if "layer" not in globs:\n+ globs["layer"] = layer\n \n return suite\ndiff --git a/src/plone/testing/publisher.py b/src/plone/testing/publisher.py\nindex d20f648..fadb909 100644\n--- a/src/plone/testing/publisher.py\n+++ b/src/plone/testing/publisher.py\n@@ -1,7 +1,5 @@\n-# -*- coding: utf-8 -*-\n """Helpers for working with common Zope publisher operations\n """\n-from __future__ import absolute_import\n \n from plone.testing import Layer\n from plone.testing import security\n@@ -24,30 +22,31 @@ def setUp(self):\n from zope.configuration import xmlconfig\n \n # Stack a new configuration context\n- self[\'configurationContext\'] = context = zca.stackConfigurationContext(\n- self.get(\'configurationContext\'))\n+ self["configurationContext"] = context = zca.stackConfigurationContext(\n+ self.get("configurationContext")\n+ )\n \n # D001 requests to use self.loadZCML instead of xmlconfig.file but\n # loadZCML is defined in `plone.app.testing` and cannot be used here.\n import zope.security\n- xmlconfig.file( # noqa: D001\n- \'meta.zcml\', zope.security, context=context)\n+\n+ xmlconfig.file("meta.zcml", zope.security, context=context) # noqa: D001\n import zope.browsermenu\n- xmlconfig.file( # noqa: D001\n- \'meta.zcml\', zope.browsermenu, context=context)\n+\n+ xmlconfig.file("meta.zcml", zope.browsermenu, context=context) # noqa: D001\n import zope.browserpage\n- xmlconfig.file( # noqa: D001\n- \'meta.zcml\', zope.browserpage, context=context)\n+\n+ xmlconfig.file("meta.zcml", zope.browserpage, context=context) # noqa: D001\n import zope.browserresource\n- xmlconfig.file( # noqa: D001\n- \'meta.zcml\', zope.browserresource, context=context)\n+\n+ xmlconfig.file("meta.zcml", zope.browserresource, context=context) # noqa: D001\n import zope.publisher\n- xmlconfig.file( # noqa: D001\n- \'meta.zcml\', zope.publisher, context=context)\n+\n+ xmlconfig.file("meta.zcml", zope.publisher, context=context) # noqa: D001\n \n def tearDown(self):\n # Zap the stacked configuration context\n- del self[\'configurationContext\']\n+ del self["configurationContext"]\n \n \n PUBLISHER_DIRECTIVES = PublisherDirectives()\ndiff --git a/src/plone/testing/security.py b/src/plone/testing/security.py\nindex a349456..c2d5422 100644\n--- a/src/plone/testing/security.py\n+++ b/src/plone/testing/security.py\n@@ -1,7 +1,5 @@\n-# -*- coding: utf-8 -*-\n """Security helpers and layers\n """\n-from __future__ import absolute_import\n \n from plone.testing import Layer\n \n@@ -37,8 +35,7 @@ def popCheckers():\n \n \n class Checkers(Layer):\n- """Ensures correct isolation of security checkers in zope.security.\n- """\n+ """Ensures correct isolation of security checkers in zope.security."""\n \n defaultBases = ()\n \ndiff --git a/src/plone/testing/testing_zca.zcml b/src/plone/testing/testing_zca.zcml\nindex 417804c..1f68bac 100644\n--- a/src/plone/testing/testing_zca.zcml\n+++ b/src/plone/testing/testing_zca.zcml\n@@ -1,8 +1,12 @@\n \n+ >\n \n- \n+ \n \n \n+ >\n \n 8.0\n \n \n-class DummyUtility(object):\n-\n+class DummyUtility:\n def __repr__(self):\n- return \'\'\n+ return ""\n \n \n-class DummyView(object):\n-\n+class DummyView:\n def __init__(self, context, request):\n pass\n \n def __call__(self):\n- return u\'\'\n+ return ""\n \n \n class DummyFile(SimpleItem):\n-\n def __call__(self):\n- path = get_distribution(\'plone.testing\').location\n- path = os.path.join(path, \'plone\', \'testing\', \'zope.rst\')\n+ path = Path(inspect.getfile(plone.testing))\n+ path = path.parent / "zope.rst"\n \n request = self.REQUEST\n response = request.response\n- response.setHeader(\'Content-Type\', \'text/plain\')\n- response.setHeader(\'Content-Length\', os.path.getsize(path))\n+ response.setHeader("Content-Type", "text/plain")\n+ response.setHeader("Content-Length", os.path.getsize(path))\n return filestream_iterator(path)\n \n \n@@ -70,63 +64,52 @@ def tearDown(self):\n zope.component.testing.tearDown()\n \n \n-checker = renormalizing.RENormalizing([\n- # normalize py2 output to py3\n- (re.compile(r\'__builtin__\'), r\'builtins\'),\n- (re.compile(\n- r"\'Unknown directive\', u\'http://namespaces.zope.org/zope\', u\'"),\n- r"\'Unknown directive\', \'http://namespaces.zope.org/zope\', \'"),\n-\n- # normalize py3 output to py2\n- (re.compile(\n- r\'zope\\.configuration\\.xmlconfig\\.ZopeXMLConfigurationError\'),\n- r\'ZopeXMLConfigurationError\'),\n- (re.compile(r\'builtins\\.PopulatedZODB\'), r\'PopulatedZODB\'),\n- (re.compile(r\'builtins\\.ExpandedZODB\'), r\'ExpandedZODB\'),\n- (re.compile(r\'urllib\\.error\\.URLError\'), r\'URLError\'),\n-])\n-\n-\n class TestZ2(unittest.TestCase):\n """Testing plone.testing.z2."""\n \n def test_z2(self):\n """It can be imported. (It contains only BBB imports.)"""\n import plone.testing.z2\n+\n self.assertIsNotNone(plone.testing.z2.ZSERVER)\n \n \n def test_suite():\n suite = unittest.TestSuite()\n- suite.addTests([\n- doctest.DocFileSuite(\n- \'layer.rst\',\n- \'zca.rst\',\n- \'security.rst\',\n- \'publisher.rst\',\n- \'zodb.rst\',\n- \'zope.rst\',\n- checker=checker,\n- setUp=setUp,\n- tearDown=tearDown,\n- optionflags=doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE,\n- ),\n- doctest.DocFileSuite(\n- \'README.rst\',\n- globs={\'canOutrunKlingons\': _canOutrunKlingons, },\n- setUp=setUp,\n- tearDown=tearDown,\n- optionflags=doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE,\n- ),\n- ])\n- if HAS_ZSERVER:\n- suite.addTests([\n+ suite.addTests(\n+ [\n doctest.DocFileSuite(\n- \'zserver.rst\',\n+ "layer.rst",\n+ "zca.rst",\n+ "security.rst",\n+ "publisher.rst",\n+ "zodb.rst",\n+ "zope.rst",\n setUp=setUp,\n tearDown=tearDown,\n optionflags=doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE,\n ),\n- unittest.TestLoader().loadTestsFromTestCase(TestZ2),\n- ])\n+ doctest.DocFileSuite(\n+ "README.rst",\n+ globs={\n+ "canOutrunKlingons": _canOutrunKlingons,\n+ },\n+ setUp=setUp,\n+ tearDown=tearDown,\n+ optionflags=doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE,\n+ ),\n+ ]\n+ )\n+ if HAS_ZSERVER:\n+ suite.addTests(\n+ [\n+ doctest.DocFileSuite(\n+ "zserver.rst",\n+ setUp=setUp,\n+ tearDown=tearDown,\n+ optionflags=doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE,\n+ ),\n+ unittest.TestLoader().loadTestsFromTestCase(TestZ2),\n+ ]\n+ )\n return suite\ndiff --git a/src/plone/testing/z2.py b/src/plone/testing/z2.py\nindex 5852b5b..2d6eac0 100644\n--- a/src/plone/testing/z2.py\n+++ b/src/plone/testing/z2.py\n@@ -1,6 +1,3 @@\n-# -*- coding: utf-8 -*-\n-from __future__ import absolute_import\n-\n from zope.deferredimport import deprecated\n \n import plone.testing\n@@ -9,32 +6,32 @@\n \n \n deprecated(\n- \'Please import from plone.testing.zope.\',\n- Browser=\'plone.testing.zope:Browser\',\n- TestIsolationBroken=\'plone.testing.zope:TestIsolationBroken\',\n- installProduct=\'plone.testing.zope:installProduct\',\n- uninstallProduct=\'plone.testing.zope:uninstallProduct\',\n- login=\'plone.testing.zope:login\',\n- logout=\'plone.testing.zope:logout\',\n- setRoles=\'plone.testing.zope:setRoles\',\n- makeTestRequest=\'plone.testing.zope:makeTestRequest\',\n- addRequestContainer=\'plone.testing.zope:addRequestContainer\',\n- zopeApp=\'plone.testing.zope:zopeApp\',\n- Startup=\'plone.testing.zope:Startup\',\n- STARTUP=\'plone.testing.zope:STARTUP\',\n- IntegrationTesting=\'plone.testing.zope:IntegrationTesting\',\n- INTEGRATION_TESTING=\'plone.testing.zope:INTEGRATION_TESTING\',\n- FunctionalTesting=\'plone.testing.zope:FunctionalTesting\',\n- FUNCTIONAL_TESTING=\'plone.testing.zope:FUNCTIONAL_TESTING\',\n- ZServer=\'plone.testing.zope:WSGIServer\',\n- ZSERVER_FIXTURE=\'plone.testing.zope:WSGI_SERVER_FIXTURE\',\n- ZSERVER=\'plone.testing.zope:WSGI_SERVER\',\n+ "Please import from plone.testing.zope.",\n+ Browser="plone.testing.zope:Browser",\n+ TestIsolationBroken="plone.testing.zope:TestIsolationBroken",\n+ installProduct="plone.testing.zope:installProduct",\n+ uninstallProduct="plone.testing.zope:uninstallProduct",\n+ login="plone.testing.zope:login",\n+ logout="plone.testing.zope:logout",\n+ setRoles="plone.testing.zope:setRoles",\n+ makeTestRequest="plone.testing.zope:makeTestRequest",\n+ addRequestContainer="plone.testing.zope:addRequestContainer",\n+ zopeApp="plone.testing.zope:zopeApp",\n+ Startup="plone.testing.zope:Startup",\n+ STARTUP="plone.testing.zope:STARTUP",\n+ IntegrationTesting="plone.testing.zope:IntegrationTesting",\n+ INTEGRATION_TESTING="plone.testing.zope:INTEGRATION_TESTING",\n+ FunctionalTesting="plone.testing.zope:FunctionalTesting",\n+ FUNCTIONAL_TESTING="plone.testing.zope:FUNCTIONAL_TESTING",\n+ ZServer="plone.testing.zope:WSGIServer",\n+ ZSERVER_FIXTURE="plone.testing.zope:WSGI_SERVER_FIXTURE",\n+ ZSERVER="plone.testing.zope:WSGI_SERVER",\n )\n \n \n deprecated(\n- \'Please import from plone.testing.\',\n- Layer=\'plone.testing:Layer\',\n+ "Please import from plone.testing.",\n+ Layer="plone.testing:Layer",\n )\n \n \n@@ -43,15 +40,14 @@ class FTPServer(plone.testing.Layer):\n \n def setUp(self):\n warnings.warn(\n- \'The FTPServer layer is now only a no-op as FTP is not supported\'\n- \' by WSGI. If you really need the fixture import it from\'\n- \' plone.testing.zserver.\')\n+ "The FTPServer layer is now only a no-op as FTP is not supported"\n+ " by WSGI. If you really need the fixture import it from"\n+ " plone.testing.zserver."\n+ )\n \n \n FTP_SERVER_FIXTURE = FTPServer()\n \n FTP_SERVER = plone.testing.zope.FunctionalTesting(\n- bases=(\n- FTP_SERVER_FIXTURE,\n- ),\n- name=\'No-OpFTPServer:Functional\')\n+ bases=(FTP_SERVER_FIXTURE,), name="No-OpFTPServer:Functional"\n+)\ndiff --git a/src/plone/testing/zca.py b/src/plone/testing/zca.py\nindex dc0cd9e..ee9f266 100644\n--- a/src/plone/testing/zca.py\n+++ b/src/plone/testing/zca.py\n@@ -1,7 +1,5 @@\n-# -*- coding: utf-8 -*-\n """Core Zope Component Architecture helpers and layers\n """\n-from __future__ import absolute_import\n \n from plone.testing import Layer\n from zope.configuration.config import ConfigurationMachine\n@@ -9,15 +7,14 @@\n import logging\n \n \n-logger = logging.getLogger(\'plone.testing.zca\')\n+logger = logging.getLogger("plone.testing.zca")\n \n # Contains a stack of installed global registries (but not the default one)\n _REGISTRIES = []\n \n \n def loadRegistry(name):\n- """Unpickling helper\n- """\n+ """Unpickling helper"""\n for reg in reversed(_REGISTRIES):\n if reg.__name__ == name:\n return reg\n@@ -28,7 +25,7 @@ def _hookRegistry(reg):\n from zope.component import _api\n from zope.component import globalregistry\n \n- logger.debug(\'Hook component registry: %s\', reg.__name__)\n+ logger.debug("Hook component registry: %s", reg.__name__)\n \n _api.base = reg\n globalregistry.base = reg\n@@ -37,6 +34,7 @@ def _hookRegistry(reg):\n # Set the default global site manager for new threads when zope.component\n # hooks are in place\n from zope.component.hooks import SiteInfo\n+\n SiteInfo.sm = reg\n \n # Set the five.localsitemanager hook, too, if applicable\n@@ -50,6 +48,7 @@ def _hookRegistry(reg):\n \n # Helper functions\n \n+\n def pushGlobalRegistry(new=None):\n """Set a new global component registry that uses the current registry as\n a a base. If you use this, you *must* call ``popGlobalRegistry()`` to\n@@ -75,19 +74,19 @@ def pushGlobalRegistry(new=None):\n if len(_REGISTRIES) == 0:\n _REGISTRIES.append(current)\n globalregistry.BaseGlobalComponents._old__reduce__ = (\n- globalregistry.BaseGlobalComponents.__reduce__)\n- globalregistry.BaseGlobalComponents.__reduce__ = (\n- lambda self: (loadRegistry, (self.__name__,)))\n+ globalregistry.BaseGlobalComponents.__reduce__\n+ )\n+ globalregistry.BaseGlobalComponents.__reduce__ = lambda self: (\n+ loadRegistry,\n+ (self.__name__,),\n+ )\n \n if new is None:\n- name = \'test-stack-{0}\'.format(len(_REGISTRIES))\n+ name = f"test-stack-{len(_REGISTRIES)}"\n new = globalregistry.BaseGlobalComponents(name=name, bases=(current,))\n- logger.debug(\n- \'New component registry: %s based on %s\',\n- name,\n- current.__name__)\n+ logger.debug("New component registry: %s based on %s", name, current.__name__)\n else:\n- logger.debug(\'Push component registry: %s\', new.__name__)\n+ logger.debug("Push component registry: %s", new.__name__)\n \n _REGISTRIES.append(new)\n \n@@ -98,6 +97,7 @@ def pushGlobalRegistry(new=None):\n # Reset the site manager hook so that getSiteManager() returns the base\n # again\n from zope.component import getSiteManager\n+\n getSiteManager.reset()\n \n try:\n@@ -120,8 +120,7 @@ def popGlobalRegistry():\n from zope.component import globalregistry\n \n if not _REGISTRIES or not _REGISTRIES[-1] is globalregistry.base:\n- msg = (\'popGlobalRegistry() called out of sync with \'\n- \'pushGlobalRegistry()\')\n+ msg = "popGlobalRegistry() called out of sync with " "pushGlobalRegistry()"\n raise ValueError(msg)\n \n current = _REGISTRIES.pop()\n@@ -133,13 +132,15 @@ def popGlobalRegistry():\n assert _REGISTRIES[0] is previous\n _REGISTRIES.pop()\n globalregistry.BaseGlobalComponents.__reduce__ = (\n- globalregistry.BaseGlobalComponents._old__reduce__)\n+ globalregistry.BaseGlobalComponents._old__reduce__\n+ )\n \n _hookRegistry(previous)\n \n # Reset the site manager hook so that getSiteManager() returns the base\n # again\n from zope.component import getSiteManager\n+\n getSiteManager.reset()\n \n try:\n@@ -155,25 +156,22 @@ def popGlobalRegistry():\n \n \n class NamedConfigurationMachine(ConfigurationMachine):\n-\n def __init__(self, name):\n- super(NamedConfigurationMachine, self).__init__()\n+ super().__init__()\n self.__name__ = name\n \n def __str__(self):\n- pkg = \'zope.configuration.config.ConfigurationMachine\'\n- return (\n- \'<{0} object {1}>\'.format(\n- pkg,\n- self.__name__,\n- )\n+ pkg = "zope.configuration.config.ConfigurationMachine"\n+ return "<{} object {}>".format(\n+ pkg,\n+ self.__name__,\n )\n \n def __repr__(self):\n return self.__str__()\n \n \n-def stackConfigurationContext(context=None, name=\'not named\'):\n+def stackConfigurationContext(context=None, name="not named"):\n """Return a new ``ConfigurationMachine`` configuration context that\n is a clone of the passed-in context. If no context is passed in, a fresh\n configuration context is returned.\n@@ -192,7 +190,7 @@ def stackConfigurationContext(context=None, name=\'not named\'):\n \n if context is None:\n registerCommonDirectives(clone)\n- logger.debug(\'New configuration context %s\', clone)\n+ logger.debug("New configuration context %s", clone)\n return clone\n \n # Copy over simple attributes\n@@ -214,7 +212,7 @@ def stackConfigurationContext(context=None, name=\'not named\'):\n # ZCML file processing only\n \n # Copy over documentation registry\n- clone._docRegistry = [tuple(list(entry))for entry in context._docRegistry]\n+ clone._docRegistry = [tuple(list(entry)) for entry in context._docRegistry]\n \n # Copy over the directive registry\n for key, registry in context._registry.items():\n@@ -223,16 +221,16 @@ def stackConfigurationContext(context=None, name=\'not named\'):\n if adapterRegistration not in newRegistry._adapters:\n for interface, info in adapterRegistration.items():\n if Interface in info:\n- factory = info[Interface][u\'\']\n- newRegistry.register([interface], Interface, \'\',\n- factory)\n+ factory = info[Interface][""]\n+ newRegistry.register([interface], Interface, "", factory)\n \n- logger.debug(\'Configuration context %s cloned from %s\', clone, context)\n+ logger.debug("Configuration context %s cloned from %s", clone, context)\n return clone\n \n \n # Layers\n \n+\n class UnitTesting(Layer):\n """Zope Component Architecture unit testing sandbox: The ZCA is cleared\n for each test and torn down after each test.\n@@ -242,10 +240,12 @@ class UnitTesting(Layer):\n \n def testSetUp(self):\n import zope.component.testing\n+\n zope.component.testing.setUp()\n \n def testTearDown(self):\n import zope.component.testing\n+\n zope.component.testing.tearDown()\n \n \n@@ -265,6 +265,7 @@ class EventTesting(Layer):\n \n def testSetUp(self):\n import zope.component.eventtesting\n+\n zope.component.eventtesting.setUp()\n \n \n@@ -280,10 +281,12 @@ class LayerCleanup(Layer):\n \n def setUp(self):\n import zope.testing.cleanup\n+\n zope.testing.cleanup.cleanUp()\n \n def tearDown(self):\n import zope.testing.cleanup\n+\n zope.testing.cleanup.cleanUp()\n \n \n@@ -300,40 +303,37 @@ class ZCMLDirectives(Layer):\n defaultBases = (LAYER_CLEANUP,)\n \n def setUp(self):\n-\n from zope.configuration import xmlconfig\n \n import zope.component\n \n- self[\'configurationContext\'] = context = stackConfigurationContext(\n- self.get(\'configurationContext\'))\n+ self["configurationContext"] = context = stackConfigurationContext(\n+ self.get("configurationContext")\n+ )\n # D001 requests to use self.loadZCML instead of xmlconfig.file but\n # loadZCML is defined in `plone.app.testing` and cannot be used here.\n- xmlconfig.file( # noqa: D001\n- \'meta.zcml\', zope.component, context=context)\n+ xmlconfig.file("meta.zcml", zope.component, context=context) # noqa: D001\n \n def tearDown(self):\n- del self[\'configurationContext\']\n+ del self["configurationContext"]\n \n \n ZCML_DIRECTIVES = ZCMLDirectives()\n \n \n class ZCMLSandbox(Layer):\n-\n defaultBases = (LAYER_CLEANUP,)\n \n- def __init__(self, bases=None, name=None, module=None, filename=None,\n- package=None):\n- super(ZCMLSandbox, self).__init__(bases, name, module)\n+ def __init__(self, bases=None, name=None, module=None, filename=None, package=None):\n+ super().__init__(bases, name, module)\n self.filename = filename\n self.package = package\n \n def setUp(self):\n- name = self.__name__ if self.__name__ is not None else \'not-named\'\n- contextName = \'ZCMLSandbox-{0}\'.format(name)\n- self[\'configurationContext\'] = stackConfigurationContext(\n- self.get(\'configurationContext\'),\n+ name = self.__name__ if self.__name__ is not None else "not-named"\n+ contextName = f"ZCMLSandbox-{name}"\n+ self["configurationContext"] = stackConfigurationContext(\n+ self.get("configurationContext"),\n name=contextName,\n )\n pushGlobalRegistry()\n@@ -341,16 +341,20 @@ def setUp(self):\n \n def setUpZCMLFiles(self):\n if self.filename is None:\n- raise ValueError(\'ZCML file name has not been provided.\')\n+ raise ValueError("ZCML file name has not been provided.")\n if self.package is None:\n- raise ValueError(\'The package that contains the ZCML file \'\n- \'has not been provided.\')\n+ raise ValueError(\n+ "The package that contains the ZCML file " "has not been provided."\n+ )\n self.loadZCMLFile(self.filename, self.package)\n \n def loadZCMLFile(self, filename, package):\n from zope.configuration import xmlconfig\n- xmlconfig.file(filename, package, context=self[\'configurationContext\']) # noqa: D001,E501\n+\n+ xmlconfig.file(\n+ filename, package, context=self["configurationContext"]\n+ ) # noqa: D001,E501\n \n def tearDown(self):\n popGlobalRegistry()\n- del self[\'configurationContext\']\n+ del self["configurationContext"]\ndiff --git a/src/plone/testing/zodb.py b/src/plone/testing/zodb.py\nindex 1316291..eb62ac8 100644\n--- a/src/plone/testing/zodb.py\n+++ b/src/plone/testing/zodb.py\n@@ -1,4 +1,3 @@\n-# -*- coding: utf-8 -*-\n """ZODB-specific helpers and layers\n """\n from plone.testing import Layer\n@@ -49,27 +48,29 @@ class EmptyZODB(Layer):\n defaultBases = ()\n \n def setUp(self):\n- self[\'zodbDB\'] = self.createDatabase(self.createStorage())\n+ self["zodbDB"] = self.createDatabase(self.createStorage())\n \n def tearDown(self):\n- self[\'zodbDB\'].close()\n- del self[\'zodbDB\']\n+ self["zodbDB"].close()\n+ del self["zodbDB"]\n \n def testSetUp(self):\n- self[\'zodbConnection\'] = connection = self[\'zodbDB\'].open()\n- self[\'zodbRoot\'] = connection.root()\n+ self["zodbConnection"] = connection = self["zodbDB"].open()\n+ self["zodbRoot"] = connection.root()\n \n import transaction\n+\n transaction.begin()\n \n def testTearDown(self):\n import transaction\n+\n transaction.abort()\n \n- self[\'zodbConnection\'].close()\n+ self["zodbConnection"].close()\n \n- del self[\'zodbConnection\']\n- del self[\'zodbRoot\']\n+ del self["zodbConnection"]\n+ del self["zodbRoot"]\n \n # Template methods for use in subclasses, if required\n \n@@ -82,7 +83,8 @@ def createStorage(self):\n """\n \n from ZODB.DemoStorage import DemoStorage\n- return DemoStorage(name=\'EmptyZODB\')\n+\n+ return DemoStorage(name="EmptyZODB")\n \n def createDatabase(self, storage):\n """Create a new database from the given storage.\n@@ -92,6 +94,7 @@ def createDatabase(self, storage):\n """\n \n from ZODB.DB import DB\n+\n return DB(storage)\n \n \ndiff --git a/src/plone/testing/zodb.rst b/src/plone/testing/zodb.rst\nindex a18c473..9f4ac9b 100644\n--- a/src/plone/testing/zodb.rst\n+++ b/src/plone/testing/zodb.rst\n@@ -118,7 +118,7 @@ We\'ll use this new layer in a similar manner to the test above, showing that the\n >>> options = runner.get_options([], [])\n >>> setupLayers = {}\n >>> runner.setup_layer(options, POPULATED_ZODB, setupLayers)\n- Set up PopulatedZODB in ... seconds.\n+ Set up ...PopulatedZODB in ... seconds.\n \n >>> db = POPULATED_ZODB[\'zodbDB\']\n >>> db.storage\n@@ -163,7 +163,7 @@ The transaction has been rolled back.::\n Layer tear-down closes and deletes the database.::\n \n >>> runner.tear_down_unneeded(options, [], setupLayers, [])\n- Tear down PopulatedZODB in ... seconds.\n+ Tear down ...PopulatedZODB in ... seconds.\n \n >>> POPULATED_ZODB.get(\'zodbDB\', None) is None\n True\n@@ -211,8 +211,8 @@ Let\'s simulate a test run again to show how this would work.::\n >>> options = runner.get_options([], [])\n >>> setupLayers = {}\n >>> runner.setup_layer(options, EXPANDED_ZODB, setupLayers)\n- Set up PopulatedZODB in ... seconds.\n- Set up ExpandedZODB in ... seconds.\n+ Set up ...PopulatedZODB in ... seconds.\n+ Set up ...ExpandedZODB in ... seconds.\n \n >>> db = EXPANDED_ZODB[\'zodbDB\']\n >>> db.storage\n@@ -259,7 +259,7 @@ The transaction has been rolled back.::\n We\'ll now tear down the expanded layer and inspect the database again.::\n \n >>> runner.tear_down_unneeded(options, [POPULATED_ZODB], setupLayers, [])\n- Tear down ExpandedZODB in ... seconds.\n+ Tear down ...ExpandedZODB in ... seconds.\n \n >>> conn = EXPANDED_ZODB[\'zodbDB\'].open()\n >>> conn.root()\n@@ -270,7 +270,7 @@ We\'ll now tear down the expanded layer and inspect the database again.::\n Finally, we\'ll tear down the rest of the layers.::\n \n >>> runner.tear_down_unneeded(options, [], setupLayers, [])\n- Tear down PopulatedZODB in ... seconds.\n+ Tear down ...PopulatedZODB in ... seconds.\n \n >>> EXPANDED_ZODB.get(\'zodbDB\', None) is None\n True\ndiff --git a/src/plone/testing/zope.py b/src/plone/testing/zope.py\nindex 040d4cc..52d9df4 100644\n--- a/src/plone/testing/zope.py\n+++ b/src/plone/testing/zope.py\n@@ -1,7 +1,5 @@\n-# -*- coding: utf-8 -*-\n """Zope-specific helpers and layers using WSGI\n """\n-from __future__ import absolute_import\n \n from OFS.metaconfigure import get_packages_to_initialize\n from plone.testing import Layer\n@@ -56,17 +54,12 @@ def installProduct(app, productName, quiet=False, multiinit=False):\n if productName in _INSTALLED_PRODUCTS:\n return\n \n- if productName.startswith(\'Products.\'):\n+ if productName.startswith("Products."):\n for priority, name, index, productDir in get_products():\n- if (\'Products.\' + name) == productName:\n-\n+ if ("Products." + name) == productName:\n install_product(\n- app,\n- productDir,\n- name,\n- [],\n- get_folder_permissions(),\n- raise_exc=1)\n+ app, productDir, name, [], get_folder_permissions(), raise_exc=1\n+ )\n InitializeClass(Folder)\n \n _INSTALLED_PRODUCTS[productName] = (\n@@ -84,15 +77,17 @@ def installProduct(app, productName, quiet=False, multiinit=False):\n for module, init_func in packages:\n if module.__name__ == productName:\n install_package(app, module, init_func, raise_exc=1)\n- _INSTALLED_PRODUCTS[productName] = (module, init_func,)\n+ _INSTALLED_PRODUCTS[productName] = (\n+ module,\n+ init_func,\n+ )\n \n found = True\n if not multiinit:\n break\n \n if not found and not quiet:\n- sys.stderr.write(\n- \'Could not install product {0}\\n\'.format(productName))\n+ sys.stderr.write(f"Could not install product {productName}\\n")\n sys.stderr.flush()\n \n \n@@ -116,10 +111,9 @@ def uninstallProduct(app, productName, quiet=False):\n if productName not in _INSTALLED_PRODUCTS:\n return\n \n- if productName.startswith(\'Products.\'):\n+ if productName.startswith("Products."):\n for priority, name, index, productDir in get_products():\n- if (\'Products.\' + name) == productName:\n-\n+ if ("Products." + name) == productName:\n if name in Application.misc_.__dict__:\n delattr(Application.misc_, name)\n \n@@ -131,7 +125,6 @@ def uninstallProduct(app, productName, quiet=False):\n found = True\n break\n elif productName in _INSTALLED_PRODUCTS: # must be a package\n-\n module, init_func = _INSTALLED_PRODUCTS[productName]\n name = module.__name__\n \n@@ -143,40 +136,38 @@ def uninstallProduct(app, productName, quiet=False):\n del _INSTALLED_PRODUCTS[productName]\n \n if not found and not quiet:\n- sys.stderr.write(\n- \'Could not install product {0}\\n\'.format(productName))\n+ sys.stderr.write(f"Could not install product {productName}\\n")\n sys.stderr.flush()\n \n \n def login(userFolder, userName):\n- """Log in as the given user in the given user folder.\n- """\n+ """Log in as the given user in the given user folder."""\n \n from AccessControl.SecurityManagement import newSecurityManager\n \n user = userFolder.getUser(userName)\n if user is None:\n- raise ValueError(\'User could not be found\')\n- if getattr(user, \'aq_base\', None) is None:\n+ raise ValueError("User could not be found")\n+ if getattr(user, "aq_base", None) is None:\n user = user.__of__(userFolder)\n newSecurityManager(None, user)\n \n \n def logout():\n- """Log out, i.e. become anonymous\n- """\n+ """Log out, i.e. become anonymous"""\n \n from AccessControl.SecurityManagement import noSecurityManager\n+\n noSecurityManager()\n \n \n def setRoles(userFolder, userId, roles):\n- """Set the given user\'s roles to a tuple of roles.\n- """\n+ """Set the given user\'s roles to a tuple of roles."""\n \n userFolder.userFolderEditUser(userId, None, list(roles), [])\n \n from AccessControl import getSecurityManager\n+\n userName = userFolder.getUserById(userId).getUserName()\n if userName == getSecurityManager().getUser().getUserName():\n login(userFolder, userName)\n@@ -192,14 +183,14 @@ def makeTestRequest(environ=None):\n \n if environ is None:\n environ = {}\n- environ.setdefault(\'SERVER_NAME\', \'foo\')\n- environ.setdefault(\'SERVER_PORT\', \'80\')\n- environ.setdefault(\'REQUEST_METHOD\', \'GET\')\n+ environ.setdefault("SERVER_NAME", "foo")\n+ environ.setdefault("SERVER_PORT", "80")\n+ environ.setdefault("REQUEST_METHOD", "GET")\n \n resp = HTTPResponse(stdout=stdout)\n req = HTTPRequest(stdin, environ, resp)\n- req._steps = [\'noobject\'] # Fake a published object.\n- req[\'ACTUAL_URL\'] = req.get(\'URL\')\n+ req._steps = ["noobject"] # Fake a published object.\n+ req["ACTUAL_URL"] = req.get("URL")\n setDefaultSkin(req)\n \n return req\n@@ -212,6 +203,7 @@ def addRequestContainer(app, environ=None):\n """\n \n from ZPublisher.BaseRequest import RequestContainer\n+\n req = makeTestRequest(environ)\n requestcontainer = RequestContainer(REQUEST=req)\n return app.__of__(requestcontainer)\n@@ -241,15 +233,16 @@ def zopeApp(db=None, connection=None, environ=None):\n if connection is None and db is not None:\n connection = db.open()\n \n- assert Zope2._began_startup, \\\n- "Zope2 WSGI is not started, maybe mixing Zope and ZServer layers."\n+ assert (\n+ Zope2._began_startup\n+ ), "Zope2 WSGI is not started, maybe mixing Zope and ZServer layers."\n app = addRequestContainer(Zope2.app(connection), environ=environ)\n \n if connection is None:\n connection = app._p_jar\n \n # exceptions in finally clauses can mask exceptions\n- # in the preceeding code block. So we catch\n+ # in the preceding code block. So we catch\n # every exception and throw it instead of the exception\n # in the finally clause\n inner_exception = None\n@@ -283,6 +276,7 @@ def zopeApp(db=None, connection=None, environ=None):\n \n # Startup layer - you probably don\'t want to use this one directly\n \n+\n class Startup(Layer):\n """This layer does what ZopeLite and ZopeTestCase\'s base.TestCase did:\n start up a minimal Zope instance and manages the application and\n@@ -333,10 +327,10 @@ def tearDown(self):\n # Layer lifecycle helper methods\n \n def setUpDebugMode(self):\n- """Switch off debug mode in the global configuration\n- """\n+ """Switch off debug mode in the global configuration"""\n \n import App.config\n+\n config = App.config.getConfiguration()\n self._debugMode = config.debug_mode\n config.debug_mode = False\n@@ -344,22 +338,25 @@ def setUpDebugMode(self):\n \n # Set Python security mode\n from AccessControl.Implementation import setImplementation\n- setImplementation(\'Python\')\n+\n+ setImplementation("Python")\n \n # Set a flag so that other code can know that we are running tests.\n # Some of the speed-related patches in Plone use this, for instance.\n # The name is a BBB artefact from ZopeTestCase :\n import os\n- os.environ[\'ZOPETESTCASE\'] = \'1\'\n+\n+ os.environ["ZOPETESTCASE"] = "1"\n \n def tearDownDebugMode(self):\n- """Return the debug mode flag to its previous state\n- """\n+ """Return the debug mode flag to its previous state"""\n \n from AccessControl.Implementation import setImplementation\n- setImplementation(\'C\')\n+\n+ setImplementation("C")\n \n import App.config\n+\n config = App.config.getConfiguration()\n config.debug_mode = self._debugMode\n App.config.setConfiguration(config)\n@@ -372,17 +369,18 @@ def setUpClientCache(self):\n \n # Make sure we use a temporary client cache\n import App.config\n+\n config = App.config.getConfiguration()\n- self._zeoClientName = getattr(config, \'zeo_client_name\', None)\n+ self._zeoClientName = getattr(config, "zeo_client_name", None)\n config.zeo_client_name = None\n App.config.setConfiguration(config)\n \n def tearDownClientCache(self):\n- """Restore the cache configuration to its previous state\n- """\n+ """Restore the cache configuration to its previous state"""\n \n # Make sure we use a temporary client cache\n import App.config\n+\n config = App.config.getConfiguration()\n config.zeo_client_name = self._zeoClientName\n App.config.setConfiguration(config)\n@@ -399,12 +397,14 @@ def setUpPatches(self):\n # Avoid expensive product import\n def null_import_products():\n pass\n+\n self._OFS_Application_import_products = OFS.Application.import_products\n OFS.Application.import_products = null_import_products\n \n # Avoid expensive product installation\n def null_initialize(app):\n pass\n+\n self._OFS_Application_initialize = OFS.Application.initialize\n OFS.Application.initialize = null_initialize\n \n@@ -417,8 +417,7 @@ def null_load_zcml():\n Zope2.App.startup.load_zcml = null_load_zcml\n \n def tearDownPatches(self):\n- """Revert the monkey patches from setUpPatches()\n- """\n+ """Revert the monkey patches from setUpPatches()"""\n \n import OFS.Application\n \n@@ -431,28 +430,24 @@ def tearDownPatches(self):\n Zope2.App.startup.load_zcml = self._Zope2_App_startup_load_zcml\n \n def setUpThreads(self):\n- """Set the thread count. Only needed in ZServer.\n- """\n+ """Set the thread count. Only needed in ZServer."""\n pass\n \n def tearDownThreads(self):\n- """Reset the thread count. Only needed in ZServer.\n- """\n+ """Reset the thread count. Only needed in ZServer."""\n pass\n \n def setUpHostPort(self):\n- """Set up the \'host\' and \'port\' resources\n- """\n+ """Set up the \'host\' and \'port\' resources"""\n \n- self[\'host\'] = \'nohost\'\n- self[\'port\'] = 80\n+ self["host"] = "nohost"\n+ self["port"] = 80\n \n def tearDownHostPort(self):\n- """Pop the \'host\' and \'port\' resources\n- """\n+ """Pop the \'host\' and \'port\' resources"""\n \n- del self[\'host\']\n- del self[\'port\']\n+ del self["host"]\n+ del self["port"]\n \n def setUpDatabase(self):\n """Create a database and stash it in the resource ``zodbDB``. If\n@@ -471,23 +466,20 @@ def setUpDatabase(self):\n # Layer a new storage for Zope 2 on top of the one from the base\n # layer, if there is one.\n \n- self[\'zodbDB\'] = zodb.stackDemoStorage(\n- self.get(\'zodbDB\'),\n- name=\'Startup\')\n+ self["zodbDB"] = zodb.stackDemoStorage(self.get("zodbDB"), name="Startup")\n \n # Create a facade for the database object that will delegate to the\n # correct underlying database. This allows resource shadowing to work\n # with regular traversal, which relies on a module-level ``DB``\n # variable.\n \n- class DBFacade(object):\n-\n+ class DBFacade:\n def __init__(self, layer):\n self.__layer = layer\n \n @property\n def __db(self):\n- return self.__layer[\'zodbDB\']\n+ return self.__layer["zodbDB"]\n \n def __getattr__(self, name):\n return getattr(self.__db, name)\n@@ -496,17 +488,16 @@ def __getattr__(self, name):\n # use this one.\n \n class DBTab(Zope2.Startup.datatypes.DBTab):\n- """A fake DBTab that causes App.startup() to use our own database.\n- """\n+ """A fake DBTab that causes App.startup() to use our own database."""\n \n def __init__(self, db):\n # value is never used when we have an open db\n- self.db_factories = {\'testing\': None}\n- self.mount_paths = {\'/\': \'testing\'}\n- self.databases = {\'testing\': db}\n+ self.db_factories = {"testing": None}\n+ self.mount_paths = {"/": "testing"}\n+ self.databases = {"testing": db}\n \n config = App.config.getConfiguration()\n- self._dbtab = getattr(config, \'dbtab\', None)\n+ self._dbtab = getattr(config, "dbtab", None)\n config.dbtab = DBTab(DBFacade(self))\n App.config.setConfiguration(config)\n \n@@ -516,6 +507,7 @@ def tearDownDatabase(self):\n """\n \n import App.config\n+\n config = App.config.getConfiguration()\n config.dbtab = self._dbtab\n App.config.setConfiguration(config)\n@@ -523,18 +515,18 @@ def tearDownDatabase(self):\n \n # Close and pop the zodbDB resource\n transaction.abort()\n- self[\'zodbDB\'].close()\n- del self[\'zodbDB\']\n+ self["zodbDB"].close()\n+ del self["zodbDB"]\n \n def setUpApp(self):\n- """Trigger Zope startup and set up the application.\n- """\n+ """Trigger Zope startup and set up the application."""\n \n # If the Testing module has been imported, the testinghome\n # variable is set and changes the way Zope2.startup() works.\n # We want the standard behavior so we remove it.\n \n import App.config\n+\n config = App.config.getConfiguration()\n try:\n self._testingHome = config.testinghome\n@@ -546,20 +538,20 @@ def setUpApp(self):\n \n # Clean up after ZopeLite layer\n import ZPublisher.WSGIPublisher\n+\n ZPublisher.WSGIPublisher._MODULES.clear()\n- self._publisher_globals = {\n- \'load_app\': ZPublisher.WSGIPublisher.load_app\n- }\n- if hasattr(ZPublisher.WSGIPublisher, \'__old_load_app__\'):\n+ self._publisher_globals = {"load_app": ZPublisher.WSGIPublisher.load_app}\n+ if hasattr(ZPublisher.WSGIPublisher, "__old_load_app__"):\n old_load_app = ZPublisher.WSGIPublisher.__old_load_app__\n ZPublisher.WSGIPublisher.load_app = old_load_app\n- self._publisher_globals[\'__old_load_app__\'] = old_load_app\n+ self._publisher_globals["__old_load_app__"] = old_load_app\n del ZPublisher.WSGIPublisher.__old_load_app__\n \n # This uses the DB from the dbtab, as configured in setUpDatabase().\n # That DB then gets stored as Zope2.DB and becomes the default.\n \n import Zope2\n+\n Zope2._began_startup = 0\n Zope2.startup_wsgi()\n \n@@ -567,10 +559,10 @@ def setUpApp(self):\n # the database will be used by default when someone does Zope2.app().\n \n def tearDownApp(self):\n- """Undo Zope 2 startup by unsetting the global state it creates.\n- """\n+ """Undo Zope 2 startup by unsetting the global state it creates."""\n \n import Zope2\n+\n Zope2.app()._p_jar.close()\n \n Zope2._began_startup = 0\n@@ -583,6 +575,7 @@ def tearDownApp(self):\n Zope2.__bobo_before__ = None\n \n import App.config\n+\n try:\n self._testingHome\n except AttributeError:\n@@ -594,28 +587,27 @@ def tearDownApp(self):\n del self._testingHome\n \n import ZPublisher.WSGIPublisher\n+\n ZPublisher.WSGIPublisher._MODULES.clear()\n for k, v in self._publisher_globals.items():\n setattr(ZPublisher.WSGIPublisher, k, v)\n \n def setUpBasicProducts(self):\n- """Install a minimal set of products required for Zope 2.\n- """\n+ """Install a minimal set of products required for Zope 2."""\n \n with zopeApp() as app:\n- installProduct(app, \'Products.PluginIndexes\')\n- installProduct(app, \'Products.OFSP\')\n+ installProduct(app, "Products.PluginIndexes")\n+ installProduct(app, "Products.OFSP")\n \n def tearDownBasicProducts(self):\n- """Tear down the minimal set of products\n- """\n+ """Tear down the minimal set of products"""\n \n with zopeApp() as app:\n- uninstallProduct(app, \'Products.PluginIndexes\')\n- uninstallProduct(app, \'Products.OFSP\')\n+ uninstallProduct(app, "Products.PluginIndexes")\n+ uninstallProduct(app, "Products.OFSP")\n \n # It\'s possible for Five\'s _register_monkies and _meta_type_regs\n- # global variables to contain duplicates. This causes an unecessary\n+ # global variables to contain duplicates. This causes an unnecessary\n # error in the LayerCleanup layer\'s tear-down. Guard against that\n # here\n \n@@ -624,10 +616,8 @@ def tearDownBasicProducts(self):\n except ImportError:\n # Zope <= 2.12\n from Products.Five import fiveconfigure as metaconfigure\n- metaconfigure._register_monkies = list(\n- set(metaconfigure._register_monkies))\n- metaconfigure._meta_type_regs = list(\n- set(metaconfigure._meta_type_regs))\n+ metaconfigure._register_monkies = list(set(metaconfigure._register_monkies))\n+ metaconfigure._meta_type_regs = list(set(metaconfigure._meta_type_regs))\n \n def setUpZCML(self):\n """Load the basic ZCML configuration from Five. Exposes a resource\n@@ -636,16 +626,20 @@ def setUpZCML(self):\n \n # Push a new global registry so that we can cleanly tear down all ZCML\n from plone.testing import zca\n+\n zca.pushGlobalRegistry()\n \n # Load something akin to the default site.zcml without actually auto-\n # loading products\n \n- self[\'configurationContext\'] = context = zca.stackConfigurationContext(\n- self.get(\'configurationContext\'))\n+ self["configurationContext"] = context = zca.stackConfigurationContext(\n+ self.get("configurationContext")\n+ )\n \n from zope.configuration import xmlconfig\n- xmlconfig.string("""\\\n+\n+ xmlconfig.string(\n+ """\\\n \n@@ -655,17 +649,20 @@ def setUpZCML(self):\n \n \n \n-""", context=context)\n+""",\n+ context=context,\n+ )\n \n def tearDownZCML(self):\n """Tear down the component registry and delete the\n ``configurationContext`` resource.\n """\n # Delete the (possibly stacked) configuration context\n- del self[\'configurationContext\']\n+ del self["configurationContext"]\n \n # Zap all globally loaded ZCML\n from plone.testing import zca\n+\n zca.popGlobalRegistry()\n \n def setUpFive(self):\n@@ -693,9 +690,10 @@ def tearDownFive(self):\n # Basic integration and functional test and layers. These are the simplest\n # Zope layers that are generally useful\n \n+\n class IntegrationTesting(Layer):\n """This layer extends ``STARTUP`` to add rollback of the transaction\n- after each test. It does not manage a fixture and has no layer lifecyle,\n+ after each test. It does not manage a fixture and has no layer lifecycle,\n only a test lifecycle.\n \n The application root is available as the resource ``app`` and the request\n@@ -727,17 +725,18 @@ def testSetUp(self):\n # Open a new app and save it as the resource ``app``.\n \n environ = {\n- \'SERVER_NAME\': self[\'host\'],\n- \'SERVER_PORT\': str(self[\'port\']),\n+ "SERVER_NAME": self["host"],\n+ "SERVER_PORT": str(self["port"]),\n }\n \n app = addRequestContainer(Zope2.app(), environ=environ)\n request = app.REQUEST\n- request[\'PARENTS\'] = [app]\n+ request["PARENTS"] = [app]\n \n # Make sure we have a zope.globalrequest request\n try:\n from zope.globalrequest import setRequest\n+\n setRequest(request)\n except ImportError:\n pass\n@@ -748,20 +747,21 @@ def testSetUp(self):\n self._original_commit = transaction.commit\n \n def you_broke_it():\n- raise TestIsolationBroken("""You are in a Test Layer\n+ raise TestIsolationBroken(\n+ """You are in a Test Layer\n (IntegrationTesting) that is fast by just aborting transactions between each\n test. You just committed something. That breaks the test isolation. So I stop\n-here and let you fix it.""")\n+here and let you fix it."""\n+ )\n \n # Prevent commits in integration tests which breaks test isolation.\n transaction.commit = you_broke_it\n \n # Save resources for tests to access\n- self[\'app\'] = app\n- self[\'request\'] = request\n+ self["app"] = app\n+ self["request"] = request\n \n def testTearDown(self):\n-\n # Abort the transaction\n transaction.abort()\n \n@@ -770,18 +770,19 @@ def testTearDown(self):\n # Make sure we have a zope.globalrequest request\n try:\n from zope.globalrequest import setRequest\n+\n setRequest(None)\n except ImportError:\n pass\n \n # Close the database connection and the request\n- app = self[\'app\']\n+ app = self["app"]\n app.REQUEST.close()\n app._p_jar.close()\n \n # Delete the resources\n- del self[\'request\']\n- del self[\'app\']\n+ del self["request"]\n+ del self["app"]\n \n \n INTEGRATION_TESTING = IntegrationTesting()\n@@ -822,24 +823,25 @@ def testSetUp(self):\n # this layer, we can\'t just assign a new shadow. We therefore keep\n # track of the original so that we can restore it on tear-down.\n \n- self[\'zodbDB\'] = zodb.stackDemoStorage(\n- self.get(\'zodbDB\'),\n- name=\'FunctionalTest\')\n+ self["zodbDB"] = zodb.stackDemoStorage(\n+ self.get("zodbDB"), name="FunctionalTest"\n+ )\n \n # Save the app\n \n environ = {\n- \'SERVER_NAME\': self[\'host\'],\n- \'SERVER_PORT\': str(self[\'port\']),\n+ "SERVER_NAME": self["host"],\n+ "SERVER_PORT": str(self["port"]),\n }\n \n app = addRequestContainer(Zope2.app(), environ=environ)\n request = app.REQUEST\n- request[\'PARENTS\'] = [app]\n+ request["PARENTS"] = [app]\n \n # Make sure we have a zope.globalrequest request\n try:\n from zope.globalrequest import setRequest\n+\n setRequest(request)\n except ImportError:\n pass\n@@ -848,8 +850,8 @@ def testSetUp(self):\n transaction.begin()\n \n # Save resources for the test\n- self[\'app\'] = app\n- self[\'request\'] = request\n+ self["app"] = app\n+ self["request"] = request\n \n def testTearDown(self):\n # Abort any open transactions\n@@ -858,26 +860,27 @@ def testTearDown(self):\n # Make sure we have a zope.globalrequest request\n try:\n from zope.globalrequest import setRequest\n+\n setRequest(None)\n except ImportError:\n pass\n \n # Close the database connection and the request\n- app = self[\'app\']\n+ app = self["app"]\n app.REQUEST.close()\n app._p_jar.close()\n \n- del self[\'app\']\n- del self[\'request\']\n+ del self["app"]\n+ del self["request"]\n \n # Close and discard the database\n- self[\'zodbDB\'].close()\n- del self[\'zodbDB\']\n+ self["zodbDB"].close()\n+ del self["zodbDB"]\n \n \n FUNCTIONAL_TESTING = FunctionalTesting()\n \n-WSGI_LOG_REQUEST = \'WSGI_REQUEST_LOGGING\' in os.environ\n+WSGI_LOG_REQUEST = "WSGI_REQUEST_LOGGING" in os.environ\n \n \n class WSGIServer(Layer):\n@@ -895,45 +898,41 @@ class WSGIServer(Layer):\n defaultBases = (STARTUP,)\n \n timeout = 5\n- host = os.environ.get(\'WSGI_SERVER_HOST\',\n- os.environ.get(\'ZSERVER_HOST\'))\n- port = os.environ.get(\'WSGI_SERVER_PORT\',\n- os.environ.get(\'ZSERVER_PORT\'))\n+ host = os.environ.get("WSGI_SERVER_HOST", os.environ.get("ZSERVER_HOST"))\n+ port = os.environ.get("WSGI_SERVER_PORT", os.environ.get("ZSERVER_PORT"))\n pipeline = [\n- (\'Zope\', \'paste.filter_app_factory\', \'httpexceptions\', {}),\n+ ("Zope", "paste.filter_app_factory", "httpexceptions", {}),\n ]\n \n def setUp(self):\n- self[\'host\'] = self.host\n+ self["host"] = self.host\n self.setUpServer()\n- self[\'port\'] = self.port\n+ self["port"] = self.port\n \n def tearDown(self):\n self.tearDownServer()\n- del self[\'host\']\n- del self[\'port\']\n+ del self["host"]\n+ del self["port"]\n \n def setUpServer(self):\n- """Create a WSGI server instance and save it in self.server.\n- """\n+ """Create a WSGI server instance and save it in self.server."""\n app = self.make_wsgi_app()\n- kwargs = {\'clear_untrusted_proxy_headers\': False}\n+ kwargs = {"clear_untrusted_proxy_headers": False}\n if self.host is not None:\n- kwargs[\'host\'] = self.host\n+ kwargs["host"] = self.host\n if self.port is not None:\n- kwargs[\'port\'] = int(self.port)\n+ kwargs["port"] = int(self.port)\n self.server = StopableWSGIServer.create(app, **kwargs)\n # If we dynamically set the host/port, we want to reset it to localhost\n # Otherwise this will depend on, for example, the local network setup\n- if self.host in (None, \'0.0.0.0\', \'127.0.0.1\', \'localhost\'):\n- self.server.effective_host = \'localhost\'\n+ if self.host in (None, "0.0.0.0", "127.0.0.1", "localhost"):\n+ self.server.effective_host = "localhost"\n # Refresh the hostname and port in case we dynamically picked them\n- self[\'host\'] = self.host = self.server.effective_host\n- self[\'port\'] = self.port = int(self.server.effective_port)\n+ self["host"] = self.host = self.server.effective_host\n+ self["port"] = self.port = int(self.server.effective_port)\n \n def tearDownServer(self):\n- """Close the server socket and clean up.\n- """\n+ """Close the server socket and clean up."""\n self.server.shutdown()\n try:\n shutil.rmtree(self._wsgi_conf_dir)\n@@ -942,7 +941,7 @@ def tearDownServer(self):\n \n def make_wsgi_app(self):\n self._wsgi_conf_dir = tempfile.mkdtemp()\n- global_config = {\'here\': self._wsgi_conf_dir}\n+ global_config = {"here": self._wsgi_conf_dir}\n zope_conf = self._get_zope_conf(self._wsgi_conf_dir)\n Zope2.Startup.run.make_wsgi_app(global_config, zope_conf)\n app = ZPublisher.WSGIPublisher.publish_module\n@@ -954,8 +953,8 @@ def make_wsgi_app(self):\n \n def _get_zope_conf(self, dir):\n fd, path = tempfile.mkstemp(dir=dir)\n- with os.fdopen(fd, \'w\') as zope_conf:\n- zope_conf.write(\'instancehome {0}\\n\'.format(os.path.dirname(dir)))\n+ with os.fdopen(fd, "w") as zope_conf:\n+ zope_conf.write(f"instancehome {os.path.dirname(dir)}\\n")\n return path\n \n \n@@ -965,7 +964,5 @@ def _get_zope_conf(self, dir):\n \n # Functional testing layer that uses the WSGI_SERVER_FIXTURE\n WSGI_SERVER = FunctionalTesting(\n- bases=(\n- WSGI_SERVER_FIXTURE,\n- ),\n- name=\'WSGIServer:Functional\')\n+ bases=(WSGI_SERVER_FIXTURE,), name="WSGIServer:Functional"\n+)\ndiff --git a/src/plone/testing/zope.rst b/src/plone/testing/zope.rst\nindex c1ed640..597407a 100644\n--- a/src/plone/testing/zope.rst\n+++ b/src/plone/testing/zope.rst\n@@ -77,7 +77,7 @@ A new connection will be opened and closed.::\n ... \'acl_users\' in app.objectIds()\n True\n \n-If you want to re-use an existing connection, you can pass one to ``zopeApp()`` as the ``connection`` argument.\n+If you want to reuse an existing connection, you can pass one to ``zopeApp()`` as the ``connection`` argument.\n In this case, you will need to close the connection yourself.::\n \n >>> conn = zope.STARTUP[\'zodbDB\'].open()\n@@ -385,7 +385,7 @@ We can now view this via the test browser:::\n The test browser integration converts the URL into a request and passes control to Zope\'s publisher.\n Let\'s check that query strings are available for input processing:::\n \n- >>> from six.moves.urllib.parse import urlencode\n+ >>> from urllib.parse import urlencode\n >>> _ = app.manage_addDTMLDocument(\'dtml-doc-2\', file=\'\')\n >>> import transaction; transaction.commit()\n >>> qs = urlencode({\'foo\': \'boo, bar & baz\'}) # sic: the ampersand.\n@@ -493,7 +493,7 @@ We can now look for this new object through the server.::\n >>> app_url.split(\':\')[:-1]\n [\'http\', \'//localhost\']\n \n- >>> from six.moves.urllib.request import urlopen\n+ >>> from urllib.request import urlopen\n >>> conn = urlopen(app_url + \'/dtml-doc-3\', timeout=5)\n >>> b\'This is the dtml-doc-3 Document.\' in conn.read()\n True\ndiff --git a/src/plone/testing/zserver.py b/src/plone/testing/zserver.py\nindex 756ff06..1762aef 100644\n--- a/src/plone/testing/zserver.py\n+++ b/src/plone/testing/zserver.py\n@@ -1,7 +1,5 @@\n-# -*- coding: utf-8 -*-\n """Zope2-specific helpers and layers using ZServer\n """\n-from __future__ import absolute_import\n \n from plone.testing import Layer\n from plone.testing import zodb\n@@ -50,7 +48,7 @@ def zopeApp(db=None, connection=None, environ=None):\n connection = app._p_jar\n \n # exceptions in finally clauses can mask exceptions\n- # in the preceeding code block. So we catch\n+ # in the preceding code block. So we catch\n # every exception and throw it instead of the exception\n # in the finally clause\n inner_exception = None\n@@ -84,6 +82,7 @@ def zopeApp(db=None, connection=None, environ=None):\n \n # Startup layer - you probably don\'t want to use this one directly\n \n+\n class Startup(zope.Startup):\n """This layer does what ZopeLite and ZopeTestCase\'s base.TestCase did:\n start up a minimal Zope instance and manages the application and\n@@ -106,32 +105,32 @@ class Startup(zope.Startup):\n # Layer lifecycle helper methods\n \n def setUpThreads(self):\n- """Set the thread count for ZServer. This defaults to 1.\n- """\n+ """Set the thread count for ZServer. This defaults to 1."""\n \n # We can\'t use setNumberOfThreads() because that function self-\n # destructs, literally, when called.\n from ZServer.Zope2.Startup import config\n+\n self._zserverThreads = config.ZSERVER_THREADS\n config.ZSERVER_THREADS = self.threads\n \n def tearDownThreads(self):\n- """Reset the ZServer thread count.\n- """\n+ """Reset the ZServer thread count."""\n \n from ZServer.Zope2.Startup import config\n+\n config.ZSERVER_THREADS = self._zserverThreads\n del self._zserverThreads\n \n def setUpApp(self):\n- """Trigger Zope startup and set up the application.\n- """\n+ """Trigger Zope startup and set up the application."""\n \n # If the Testing module has been imported, the testinghome\n # variable is set and changes the way Zope2.startup() works.\n # We want the standard behavior so we remove it.\n \n import App.config\n+\n config = App.config.getConfiguration()\n try:\n self._testingHome = config.testinghome\n@@ -145,17 +144,18 @@ def setUpApp(self):\n # That DB then gets stored as Zope2.DB and becomes the default.\n \n from ZServer import Zope2\n+\n Zope2.startup()\n \n # At this point, Zope2.DB is set to the test database facade. This is\n # the database will be used by default when someone does Zope2.app().\n \n def tearDownApp(self):\n- """Undo Zope 2 startup by unsetting the global state it creates.\n- """\n+ """Undo Zope 2 startup by unsetting the global state it creates."""\n \n import Zope2\n import ZServer.Zope2\n+\n ZServer.Zope2.app()._p_jar.close()\n \n ZServer.Zope2._began_startup = 0\n@@ -168,6 +168,7 @@ def tearDownApp(self):\n Zope2.__bobo_before__ = None\n \n import App.config\n+\n try:\n self._testingHome\n except AttributeError:\n@@ -181,6 +182,7 @@ def tearDownApp(self):\n # Clear out the app reference cached in get_module_info\'s\n # \'modules\' parameter default dict. (waaaaa)\n import ZPublisher.Publish\n+\n defaults = ZPublisher.Publish.get_module_info.func_defaults\n \n if defaults:\n@@ -189,23 +191,21 @@ def tearDownApp(self):\n ZPublisher.Publish.get_module_info.func_defaults = tuple(d)\n \n def setUpBasicProducts(self):\n- """Install a minimal set of products required for Zope 2.\n- """\n+ """Install a minimal set of products required for Zope 2."""\n \n with zopeApp() as app:\n- installProduct(app, \'Products.PluginIndexes\')\n- installProduct(app, \'Products.OFSP\')\n+ installProduct(app, "Products.PluginIndexes")\n+ installProduct(app, "Products.OFSP")\n \n def tearDownBasicProducts(self):\n- """Tear down the minimal set of products\n- """\n+ """Tear down the minimal set of products"""\n \n with zopeApp() as app:\n- uninstallProduct(app, \'Products.PluginIndexes\')\n- uninstallProduct(app, \'Products.OFSP\')\n+ uninstallProduct(app, "Products.PluginIndexes")\n+ uninstallProduct(app, "Products.OFSP")\n \n # It\'s possible for Five\'s _register_monkies and _meta_type_regs\n- # global variables to contain duplicates. This causes an unecessary\n+ # global variables to contain duplicates. This causes an unnecessary\n # error in the LayerCleanup layer\'s tear-down. Guard against that\n # here\n \n@@ -214,10 +214,8 @@ def tearDownBasicProducts(self):\n except ImportError:\n # Zope <= 2.12\n from Products.Five import fiveconfigure as metaconfigure\n- metaconfigure._register_monkies = list(\n- set(metaconfigure._register_monkies))\n- metaconfigure._meta_type_regs = list(\n- set(metaconfigure._meta_type_regs))\n+ metaconfigure._register_monkies = list(set(metaconfigure._register_monkies))\n+ metaconfigure._meta_type_regs = list(set(metaconfigure._meta_type_regs))\n \n \n STARTUP = Startup()\n@@ -226,9 +224,10 @@ def tearDownBasicProducts(self):\n # Basic integration and functional test and layers. These are the simplest\n # Zope 2 layers that are generally useful\n \n+\n class IntegrationTesting(zope.IntegrationTesting):\n """This layer extends ``STARTUP`` to add rollback of the transaction\n- after each test. It does not manage a fixture and has no layer lifecyle,\n+ after each test. It does not manage a fixture and has no layer lifecycle,\n only a test lifecycle.\n \n The application root is available as the resource ``app`` and the request\n@@ -258,17 +257,18 @@ def testSetUp(self):\n # Open a new app and save it as the resource ``app``.\n \n environ = {\n- \'SERVER_NAME\': self[\'host\'],\n- \'SERVER_PORT\': str(self[\'port\']),\n+ "SERVER_NAME": self["host"],\n+ "SERVER_PORT": str(self["port"]),\n }\n \n app = addRequestContainer(Zope2.app(), environ=environ)\n request = app.REQUEST\n- request[\'PARENTS\'] = [app]\n+ request["PARENTS"] = [app]\n \n # Make sure we have a zope.globalrequest request\n try:\n from zope.globalrequest import setRequest\n+\n setRequest(request)\n except ImportError:\n pass\n@@ -279,17 +279,19 @@ def testSetUp(self):\n self._original_commit = transaction.commit\n \n def you_broke_it():\n- raise TestIsolationBroken("""You are in a Test Layer\n+ raise TestIsolationBroken(\n+ """You are in a Test Layer\n (IntegrationTesting) that is fast by just aborting transactions between each\n test. You just committed something. That breaks the test isolation. So I stop\n-here and let you fix it.""")\n+here and let you fix it."""\n+ )\n \n # Prevent commits in integration tests which breaks test isolation.\n transaction.commit = you_broke_it\n \n # Save resources for tests to access\n- self[\'app\'] = app\n- self[\'request\'] = request\n+ self["app"] = app\n+ self["request"] = request\n \n \n INTEGRATION_TESTING = IntegrationTesting()\n@@ -328,24 +330,25 @@ def testSetUp(self):\n # this layer, we can\'t just assign a new shadow. We therefore keep\n # track of the original so that we can restore it on tear-down.\n \n- self[\'zodbDB\'] = zodb.stackDemoStorage(\n- self.get(\'zodbDB\'),\n- name=\'FunctionalTest\')\n+ self["zodbDB"] = zodb.stackDemoStorage(\n+ self.get("zodbDB"), name="FunctionalTest"\n+ )\n \n # Save the app\n \n environ = {\n- \'SERVER_NAME\': self[\'host\'],\n- \'SERVER_PORT\': str(self[\'port\']),\n+ "SERVER_NAME": self["host"],\n+ "SERVER_PORT": str(self["port"]),\n }\n \n app = addRequestContainer(Zope2.app(), environ=environ)\n request = app.REQUEST\n- request[\'PARENTS\'] = [app]\n+ request["PARENTS"] = [app]\n \n # Make sure we have a zope.globalrequest request\n try:\n from zope.globalrequest import setRequest\n+\n setRequest(request)\n except ImportError:\n pass\n@@ -354,8 +357,8 @@ def testSetUp(self):\n transaction.begin()\n \n # Save resources for the test\n- self[\'app\'] = app\n- self[\'request\'] = request\n+ self["app"] = app\n+ self["request"] = request\n \n \n FUNCTIONAL_TESTING = FunctionalTesting()\n@@ -363,6 +366,7 @@ def testSetUp(self):\n \n # More advanced functional testing - running ZServer and FTP server\n \n+\n class ZServer(Layer):\n """Start a ZServer that accesses the fixture managed by the\n ``STARTUP`` layer.\n@@ -380,26 +384,25 @@ class ZServer(Layer):\n \n defaultBases = (STARTUP,)\n \n- host = os.environ.get(\'ZSERVER_HOST\', \'\')\n- port = int(os.environ.get(\'ZSERVER_PORT\', 0))\n+ host = os.environ.get("ZSERVER_HOST", "")\n+ port = int(os.environ.get("ZSERVER_PORT", 0))\n timeout = 5.0\n log = None\n \n def setUp(self):\n-\n from threading import Thread\n \n import time\n \n- self[\'host\'] = self.host\n- self[\'port\'] = self.port\n+ self["host"] = self.host\n+ self["port"] = self.port\n \n self._shutdown = False\n \n self.setUpServer()\n \n self.thread = Thread(\n- name=\'{0} server\'.format(self.__name__),\n+ name=f"{self.__name__} server",\n target=self.runner,\n )\n \n@@ -415,12 +418,11 @@ def tearDown(self):\n \n self.tearDownServer()\n \n- del self[\'host\']\n- del self[\'port\']\n+ del self["host"]\n+ del self["port"]\n \n def setUpServer(self):\n- """Create a ZServer server instance and save it in self.zserver\n- """\n+ """Create a ZServer server instance and save it in self.zserver"""\n from StringIO import StringIO\n from ZServer import logger\n from ZServer import zhttp_handler\n@@ -441,20 +443,23 @@ def setUpServer(self):\n \n # If we dynamically set the host/port, we want to reset it to localhost\n # Otherwise this will depend on, for example, the local network setup\n- if self.host in (\'\', \'0.0.0.0\', \'127.0.0.1\', ):\n- server.server_name = \'localhost\'\n+ if self.host in (\n+ "",\n+ "0.0.0.0",\n+ "127.0.0.1",\n+ ):\n+ server.server_name = "localhost"\n # Refresh the hostname and port in case we dynamically picked them\n- self[\'host\'] = self.host = server.server_name\n- self[\'port\'] = self.port = server.server_port\n+ self["host"] = self.host = server.server_name\n+ self["port"] = self.port = server.server_port\n \n- zhttpHandler = zhttp_handler(module=\'Zope2\', uri_base=\'\')\n+ zhttpHandler = zhttp_handler(module="Zope2", uri_base="")\n server.install_handler(zhttpHandler)\n \n self.zserver = server\n \n def tearDownServer(self):\n- """Close the ZServer socket\n- """\n+ """Close the ZServer socket"""\n self.zserver.close()\n \n # Thread runner\n@@ -477,11 +482,7 @@ def runner(self):\n ZSERVER_FIXTURE = ZServer()\n \n # Functional testing layer that uses the ZSERVER_FIXTURE\n-ZSERVER = FunctionalTesting(\n- bases=(\n- ZSERVER_FIXTURE,\n- ),\n- name=\'ZServer:Functional\')\n+ZSERVER = FunctionalTesting(bases=(ZSERVER_FIXTURE,), name="ZServer:Functional")\n \n \n class FTPServer(ZServer):\n@@ -500,15 +501,14 @@ class FTPServer(ZServer):\n \n defaultBases = (STARTUP,)\n \n- host = os.environ.get(\'FTPSERVER_HOST\', \'\')\n- port = int(os.environ.get(\'FTPSERVER_PORT\', 0))\n+ host = os.environ.get("FTPSERVER_HOST", "")\n+ port = int(os.environ.get("FTPSERVER_PORT", 0))\n threads = 1\n timeout = 5.0\n log = None\n \n def setUpServer(self):\n- """Create an FTP server instance and save it in self.ftpServer\n- """\n+ """Create an FTP server instance and save it in self.ftpServer"""\n \n from StringIO import StringIO\n from ZServer import logger\n@@ -521,7 +521,7 @@ def setUpServer(self):\n zopeLog = logger.file_logger(log)\n \n self.ftpServer = FTPServer(\n- \'Zope2\',\n+ "Zope2",\n ip=self.host,\n port=self.port,\n logger_object=zopeLog,\n@@ -530,16 +530,19 @@ def setUpServer(self):\n self.host, self.port = self.ftpServer.socket.getsockname()\n # If we dynamically set the host/port, we want to reset it to localhost\n # Otherwise this will depend on, for example, the local network setup\n- if self.host in (\'\', \'0.0.0.0\', \'127.0.0.1\', ):\n- self.host = \'localhost\'\n- self.ftpServer.hostname = \'localhost\'\n- self.ftpServer.ip = \'127.0.0.1\'\n- self[\'host\'] = self.host\n- self[\'port\'] = self.port\n+ if self.host in (\n+ "",\n+ "0.0.0.0",\n+ "127.0.0.1",\n+ ):\n+ self.host = "localhost"\n+ self.ftpServer.hostname = "localhost"\n+ self.ftpServer.ip = "127.0.0.1"\n+ self["host"] = self.host\n+ self["port"] = self.port\n \n def tearDownServer(self):\n- """Close the FTPServer socket\n- """\n+ """Close the FTPServer socket"""\n self.ftpServer.close()\n \n \n@@ -548,8 +551,4 @@ def tearDownServer(self):\n FTP_SERVER_FIXTURE = FTPServer()\n \n # Functional testing layer that uses the FTP_SERVER_FIXTURE\n-FTP_SERVER = FunctionalTesting(\n- bases=(\n- FTP_SERVER_FIXTURE,\n- ),\n- name=\'FTPServer:Functional\')\n+FTP_SERVER = FunctionalTesting(bases=(FTP_SERVER_FIXTURE,), name="FTPServer:Functional")\ndiff --git a/src/plone/testing/zserver.rst b/src/plone/testing/zserver.rst\nindex 1b6b0c9..189afd7 100644\n--- a/src/plone/testing/zserver.rst\n+++ b/src/plone/testing/zserver.rst\n@@ -77,7 +77,7 @@ A new connection will be opened and closed.::\n ... \'acl_users\' in app.objectIds()\n True\n \n-If you want to re-use an existing connection, you can pass one to ``zopeApp()`` as the ``connection`` argument.\n+If you want to reuse an existing connection, you can pass one to ``zopeApp()`` as the ``connection`` argument.\n In this case, you will need to close the connection yourself.::\n \n >>> conn = zserver.STARTUP[\'zodbDB\'].open()\ndiff --git a/tox.ini b/tox.ini\nindex 1c1dbb6..43f377f 100644\n--- a/tox.ini\n+++ b/tox.ini\n@@ -1,161 +1,208 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+# See the inline comments on how to expand/tweak this configuration file\n [tox]\n+# We need 4.4.0 for constrain_package_deps.\n+min_version = 4.4.0\n envlist =\n- py27,\n- py27-zserver,\n- py36,\n- py37,\n- py38,\n- py39-dev,\n- coverage-report,\n-# docs,\n- lint-py27,\n- lint-py36,\n- lint-py37,\n- lint-py38,\n-\n-minversion = 1.9\n-\n-[testenv]\n-usedevelop = True\n-\n-pip_pre = True\n-\n-extras =\n+ lint\n test\n- zserver: z2,zserver\n-\n-deps =\n- coverage\n-\n-commands =\n- python -V\n- coverage run {envbindir}/zope-testrunner --path=src --all {posargs:-vc}\n+ dependencies\n \n-setenv =\n- COVERAGE_FILE=.coverage.{envname}\n \n-passenv =\n- WSGI_REQUEST_LOGGING\n+##\n+# Add extra configuration options in .meta.toml:\n+# [tox]\n+# envlist_lines = """\n+# my_other_environment\n+# """\n+# config_lines = """\n+# my_extra_top_level_tox_configuration_lines\n+# """\n+##\n \n-[testenv:coverage-report]\n+[testenv]\n skip_install = true\n-basepython = python2.7\n-\n-deps = coverage\n-\n-setenv =\n- COVERAGE_FILE=.coverage\n-\n+allowlist_externals =\n+ echo\n+ false\n+# Make sure typos like `tox -e formaat` are caught instead of silently doing nothing.\n+# See https://github.com/tox-dev/tox/issues/2858.\n commands =\n- coverage erase\n- coverage combine\n- coverage html -i\n- coverage xml -i\n- coverage report -i --fail-under=85\n-\n+ echo "Unrecognized environment name {envname}"\n+ false\n \n-[lint]\n+[testenv:init]\n+description = Prepare environment\n skip_install = true\n-\n-deps =\n- isort\n- flake8\n- # helper to generate HTML reports:\n- flake8-html\n- # Useful flake8 plugins that are Python and Plone specific:\n- flake8-coding\n- flake8-debugger\n- flake8-deprecated\n- flake8-print\n- # flake8-pytest\n- # flake8-todo\n- mccabe\n- # Potential flake8 plugins that should be used: # TBD\n- #flake8-blind-except\n- #flake8-commas\n- #flake8-docstrings\n- #flake8-mypy\n- #flake8-pep3101\n- #flake8-plone-hasattr\n- #flake8-string-format\n- #flake8_strict\n- #flake8-quotes\n- #flake8-polyfill\n-\n commands =\n- mkdir -p {toxinidir}/_build/reports/flake8\n- - flake8 --format=html --htmldir={toxinidir}/_build/reports/flake8 --doctests src setup.py\n- flake8 --doctests --ignore=W503 src setup.py\n- isort --check-only {toxinidir}/src\n+ echo "Initial setup complete"\n \n-whitelist_externals =\n- mkdir\n \n-[testenv:isort-apply]\n+[testenv:format]\n+description = automatically reformat code\n skip_install = true\n-\n deps =\n- isort\n-\n+ pre-commit\n commands =\n- isort {toxinidir}/src\n-\n-[testenv:lint-py27]\n-basepython = python2.7\n-skip_install = true\n-deps = {[lint]deps}\n-commands = {[lint]commands}\n-whitelist_externals = {[lint]whitelist_externals}\n-\n-[testenv:lint-py36]\n-basepython = python3.6\n-skip_install = true\n-deps = {[lint]deps}\n-commands = {[lint]commands}\n-whitelist_externals = {[lint]whitelist_externals}\n+ pre-commit run -a pyupgrade\n+ pre-commit run -a isort\n+ pre-commit run -a black\n+ pre-commit run -a zpretty\n \n-[testenv:lint-py37]\n-basepython = python3.7\n+[testenv:lint]\n+description = run linters that will help improve the code style\n skip_install = true\n-deps = {[lint]deps}\n-commands = {[lint]commands}\n-whitelist_externals = {[lint]whitelist_externals}\n-\n-[testenv:lint-py38]\n-basepython = python3.8\n-skip_install = true\n-deps = {[lint]deps}\n-commands = {[lint]commands}\n-whitelist_externals = {[lint]whitelist_externals}\n-\n-[testenv:docs]\n-skip_install = true\n-\n deps =\n- Sphinx\n-\n+ pre-commit\n commands =\n- sphinx-build -b html -d _build/docs/doctrees docs _build/docs/html\n- sphinx-build -b doctest docs _build/docs/doctrees\n+ pre-commit run -a\n \n-[testenv:update_translation]\n+[testenv:dependencies]\n+description = check if the package defines all its dependencies\n skip_install = true\n-\n deps =\n- i18ndude\n+ build\n+ z3c.dependencychecker==2.11\n+commands =\n+ python -m build --sdist --no-isolation\n+ dependencychecker\n+\n+[testenv:dependencies-graph]\n+description = generate a graph out of the dependencies of the package\n+skip_install = false\n+allowlist_externals =\n+ sh\n+deps =\n+ pipdeptree==2.5.1\n+ graphviz # optional dependency of pipdeptree\n+commands =\n+ sh -c \'pipdeptree --exclude setuptools,wheel,pipdeptree,zope.interface,zope.component --graph-output svg > dependencies.svg\'\n+\n+[testenv:test]\n+description = run the distribution tests\n+use_develop = true\n+skip_install = false\n+constrain_package_deps = true\n+set_env =\n+ ROBOT_BROWSER=headlesschrome\n+\n+##\n+# Specify extra test environment variables in .meta.toml:\n+# [tox]\n+# test_environment_variables = """\n+# PIP_EXTRA_INDEX_URL=https://my-pypi.my-server.com/\n+# """\n+#\n+# Set constrain_package_deps .meta.toml:\n+# [tox]\n+# constrain_package_deps = "false"\n+##\n+deps =\n+ zope.testrunner\n+ -c https://dist.plone.org/release/6.0-dev/constraints.txt\n+ \n+##\n+# Specify additional deps in .meta.toml:\n+# [tox]\n+# test_deps_additional = "-esources/plonegovbr.portal_base[test]"\n+#\n+# Specify a custom constraints file in .meta.toml:\n+# [tox]\n+# constraints_file = "https://my-server.com/constraints.txt"\n+##\n+commands =\n+ zope-testrunner --all --test-path={toxinidir}/src -s plone.testing {posargs}\n+extras =\n+ test\n \n+##\n+# Add extra configuration options in .meta.toml:\n+# [tox]\n+# test_extras = """\n+# tests\n+# widgets\n+# """\n+##\n+\n+[testenv:coverage]\n+description = get a test coverage report\n+use_develop = true\n+skip_install = false\n+constrain_package_deps = true\n+set_env =\n+ ROBOT_BROWSER=headlesschrome\n+\n+##\n+# Specify extra test environment variables in .meta.toml:\n+# [tox]\n+# test_environment_variables = """\n+# PIP_EXTRA_INDEX_URL=https://my-pypi.my-server.com/\n+# """\n+##\n+deps =\n+ coverage\n+ zope.testrunner\n+ -c https://dist.plone.org/release/6.0-dev/constraints.txt\n+ \n commands =\n- i18ndude find-untranslated\n- i18ndude rebuild-pot\n- i18ndude merge\n- i18ndude sync\n- i18ndude list\n+ coverage run --branch --source plone.testing {envbindir}/zope-testrunner --quiet --all --test-path={toxinidir}/src -s plone.testing {posargs}\n+ coverage report -m --format markdown\n+ coverage xml\n+extras =\n+ test\n \n-[testenv:release]\n-skip_install = true\n \n+[testenv:release-check]\n+description = ensure that the distribution is ready to release\n+skip_install = true\n deps =\n- zest.releaser[recommended]\n-\n+ twine\n+ build\n+ towncrier\n+ -c https://dist.plone.org/release/6.0-dev/constraints.txt\n+ \n+commands =\n+ # fake version to not have to install the package\n+ # we build the change log as news entries might break\n+ # the README that is displayed on PyPI\n+ towncrier build --version=100.0.0 --yes\n+ python -m build --sdist --no-isolation\n+ twine check dist/*\n+\n+[testenv:circular]\n+description = ensure there are no cyclic dependencies\n+use_develop = true\n+skip_install = false\n+set_env =\n+\n+##\n+# Specify extra test environment variables in .meta.toml:\n+# [tox]\n+# test_environment_variables = """\n+# PIP_EXTRA_INDEX_URL=https://my-pypi.my-server.com/\n+# """\n+##\n+allowlist_externals =\n+ sh\n+deps =\n+ pipdeptree\n+ pipforester\n+ -c https://dist.plone.org/release/6.0-dev/constraints.txt\n+ \n commands =\n- fullrelease --no-input -v\n+ # Generate the full dependency tree\n+ sh -c \'pipdeptree -j > forest.json\'\n+ # Generate a DOT graph with the circular dependencies, if any\n+ pipforester -i forest.json -o forest.dot --cycles\n+ # Report if there are any circular dependencies, i.e. error if there are any\n+ pipforester -i forest.json --check-cycles -o /dev/null\n+\n+\n+##\n+# Add extra configuration options in .meta.toml:\n+# [tox]\n+# extra_lines = """\n+# _your own configuration lines_\n+# """\n+##\n' +b'diff --git a/news/518.internal b/news/518.internal\nnew file mode 100644\nindex 00000000..bcefc6dd\n--- /dev/null\n+++ b/news/518.internal\n@@ -0,0 +1 @@\n+Fixup tests because PloneSite gets IContentish again. @Akshat2Jain @jaroel\n\\ No newline at end of file\ndiff --git a/src/plone/api/tests/test_content.py b/src/plone/api/tests/test_content.py\nindex b411306b..7123667c 100644\n--- a/src/plone/api/tests/test_content.py\n+++ b/src/plone/api/tests/test_content.py\n@@ -1,5 +1,4 @@\n """Tests for plone.api.content."""\n-\n from Acquisition import aq_base\n from OFS.CopySupport import CopyError\n from OFS.event import ObjectWillBeMovedEvent\n@@ -7,13 +6,13 @@\n from plone import api\n from plone.api.content import _parse_object_provides_query\n from plone.api.tests.base import INTEGRATION_TESTING\n+from plone.app.contenttypes.interfaces import IFolder\n from plone.app.layout.navigation.interfaces import INavigationRoot\n from plone.app.linkintegrity.exceptions import LinkIntegrityNotificationException\n from plone.app.textfield import RichTextValue\n from plone.indexer import indexer\n from plone.uuid.interfaces import IMutableUUID\n from plone.uuid.interfaces import IUUIDGenerator\n-from Products.CMFCore.interfaces import IContentish\n from Products.CMFCore.WorkflowCore import WorkflowException\n from Products.ZCatalog.interfaces import IZCatalog\n from unittest import mock\n@@ -209,8 +208,8 @@ def test_create_dexterity(self):\n """Test create dexterity."""\n container = self.portal\n \n- # This section check for DX compatibilty. The custom DX types defined\n- # in plone.api are for Plone 4 compatiblity.\n+ # This section check for DX compatibility. The custom DX types defined\n+ # in plone.api are for Plone 4 compatibility.\n \n # Create a folder\n folder = api.content.create(\n@@ -332,7 +331,7 @@ def test_create_raises_unicodedecodeerror(self):\n \n # register a title indexer that will force a UnicodeDecodeError\n # during content reindexing\n- @indexer(IContentish, IZCatalog)\n+ @indexer(IFolder, IZCatalog)\n def force_unicode_error(object):\n raise UnicodeDecodeError(\n "ascii",\n@@ -446,7 +445,7 @@ def test_get_constraints(self):\n api.content.get()\n \n def test_get(self):\n- """Test the getting of content in varios ways."""\n+ """Test the getting of content in various ways."""\n # Test getting the about folder by path and UID\n about_by_path = api.content.get("/about")\n about_by_uid = api.content.get(UID=self.about.UID())\n@@ -707,7 +706,7 @@ def test_copy(self):\n container["about"]["our-team"] and container["about"]["our-team"] == ourteam\n )\n \n- # When copying whithout target parameter should take source parent\n+ # When copying without target parameter should take source parent\n api.content.copy(source=self.team, id="our-team-no-target")\n assert container["about"]["our-team-no-target"]\n \n@@ -989,11 +988,11 @@ def test_find_depth(self):\n \n def test_find_interface(self):\n # Find documents by interface or it\'s identifier\n- identifier = IContentish.__identifier__\n+ identifier = IFolder.__identifier__\n brains = api.content.find(object_provides=identifier)\n by_identifier = [x.getObject() for x in brains]\n \n- brains = api.content.find(object_provides=IContentish)\n+ brains = api.content.find(object_provides=IFolder)\n by_interface = [x.getObject() for x in brains]\n \n self.assertEqual(by_identifier, by_interface)\n@@ -1008,18 +1007,19 @@ def test_find_interface_dict(self):\n brains = api.content.find(\n object_provides={\n "query": [\n- IContentish.__identifier__,\n+ IFolder.__identifier__,\n INavigationRoot.__identifier__,\n ],\n "operator": "and",\n },\n )\n+\n self.assertEqual(len(brains), 1)\n \n # plone.api query using interfaces\n brains = api.content.find(\n object_provides={\n- "query": [IContentish, INavigationRoot],\n+ "query": [IFolder, INavigationRoot],\n "operator": "and",\n },\n )\n@@ -1029,7 +1029,7 @@ def test_find_interface_dict__include_not_query(self):\n """Check if not query in object_provides is functional."""\n \n brains_all = api.content.find(\n- object_provides={"query": IContentish.__identifier__},\n+ object_provides={"query": IFolder.__identifier__},\n )\n \n alsoProvides(self.portal.events, INavigationRoot)\n@@ -1037,11 +1037,10 @@ def test_find_interface_dict__include_not_query(self):\n \n brains = api.content.find(\n object_provides={\n- "query": IContentish.__identifier__,\n+ "query": IFolder.__identifier__,\n "not": INavigationRoot.__identifier__,\n },\n )\n-\n self.assertEqual(len(brains_all) - len(brains), 1)\n \n def test_find_interface_dict__all_options(self):\n@@ -1051,42 +1050,42 @@ def test_find_interface_dict__all_options(self):\n parser = _parse_object_provides_query\n \n self.assertDictEqual(\n- parser({"query": IContentish}),\n- {"query": [IContentish.__identifier__], "operator": "or"},\n+ parser({"query": IFolder}),\n+ {"query": [IFolder.__identifier__], "operator": "or"},\n )\n \n self.assertDictEqual(\n parser(\n {\n- "query": [IContentish, INavigationRoot.__identifier__],\n+ "query": [IFolder, INavigationRoot.__identifier__],\n "operator": "and",\n },\n ),\n {\n- "query": [IContentish.__identifier__, INavigationRoot.__identifier__],\n+ "query": [IFolder.__identifier__, INavigationRoot.__identifier__],\n "operator": "and",\n },\n )\n \n self.assertDictEqual(\n- parser({"not": IContentish}),\n- {"not": [IContentish.__identifier__]},\n+ parser({"not": IFolder}),\n+ {"not": [IFolder.__identifier__]},\n )\n \n self.assertDictEqual(\n- parser({"not": [IContentish, INavigationRoot.__identifier__]}),\n- {"not": [IContentish.__identifier__, INavigationRoot.__identifier__]},\n+ parser({"not": [IFolder, INavigationRoot.__identifier__]}),\n+ {"not": [IFolder.__identifier__, INavigationRoot.__identifier__]},\n )\n \n self.assertDictEqual(\n- parser({"not": IContentish}),\n- {"not": [IContentish.__identifier__]},\n+ parser({"not": IFolder}),\n+ {"not": [IFolder.__identifier__]},\n )\n \n self.assertDictEqual(\n- parser({"query": IContentish, "operator": "and", "not": INavigationRoot}),\n+ parser({"query": IFolder, "operator": "and", "not": INavigationRoot}),\n {\n- "query": [IContentish.__identifier__],\n+ "query": [IFolder.__identifier__],\n "operator": "and",\n "not": [INavigationRoot.__identifier__],\n },\n@@ -1133,38 +1132,38 @@ def test_find_parse_object_provides_query(self):\n \n # single interface\n self.assertDictEqual(\n- parse(IContentish),\n+ parse(IFolder),\n {\n- "query": [IContentish.__identifier__],\n+ "query": [IFolder.__identifier__],\n "operator": "or",\n },\n )\n # single identifier\n self.assertDictEqual(\n- parse(IContentish.__identifier__),\n+ parse(IFolder.__identifier__),\n {\n- "query": [IContentish.__identifier__],\n+ "query": [IFolder.__identifier__],\n "operator": "or",\n },\n )\n # multiple interfaces/identifiers (mixed as list)\n self.assertDictEqual(\n- parse([INavigationRoot, IContentish.__identifier__]),\n+ parse([INavigationRoot, IFolder.__identifier__]),\n {\n "query": [\n INavigationRoot.__identifier__,\n- IContentish.__identifier__,\n+ IFolder.__identifier__,\n ],\n "operator": "or",\n },\n )\n # multiple interfaces/identifiers (mixed as tuple)\n self.assertDictEqual(\n- parse((INavigationRoot, IContentish.__identifier__)),\n+ parse((INavigationRoot, IFolder.__identifier__)),\n {\n "query": [\n INavigationRoot.__identifier__,\n- IContentish.__identifier__,\n+ IFolder.__identifier__,\n ],\n "operator": "or",\n },\n@@ -1173,14 +1172,14 @@ def test_find_parse_object_provides_query(self):\n self.assertDictEqual(\n parse(\n {\n- "query": [INavigationRoot, IContentish.__identifier__],\n+ "query": [INavigationRoot, IFolder.__identifier__],\n "operator": "and",\n }\n ),\n {\n "query": [\n INavigationRoot.__identifier__,\n- IContentish.__identifier__,\n+ IFolder.__identifier__,\n ],\n "operator": "and",\n },\n@@ -1283,7 +1282,7 @@ def test_transition(self):\n "internally_published",\n )\n \n- def test_diable_roles_acquisition(self):\n+ def test_disable_roles_acquisition(self):\n """Test disabling local roles acquisition."""\n # This should fail because an content item is mandatory\n from plone.api.exc import MissingParameterError\n'