diff --git a/last_commit.txt b/last_commit.txt index c5ad317276..3ed850132d 100644 --- a/last_commit.txt +++ b/last_commit.txt @@ -1,239 +1,271 @@ -Repository: plone.app.robotframework +Repository: plone.testing Branch: refs/heads/master -Date: 2023-10-15T18:28:12+02:00 +Date: 2023-10-15T19:09:56+02:00 Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/plone.app.robotframework/commit/ab81e06055b0f7800c9970328c87596329218d90 +Commit: https://github.com/plone/plone.testing/commit/b070459001f125b475bf07c27b08ce8cd52ba8ab Configuring with plone/meta Files changed: -A .editorconfig A .flake8 A .github/workflows/meta.yml A .meta.toml A .pre-commit-config.yaml -A news/434550cc.internal -A tox.ini +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\nnew file mode 100644\nindex 00000000..8ae05aaa\n--- /dev/null\n+++ b/.editorconfig\n@@ -0,0 +1,54 @@\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+# file types\n+\n+# top-most EditorConfig file:\n+# Will ignore other EditorConfig files in Home directory or upper tree level.\n+root = true\n+\n+\n+[*] # For All Files\n+# Unix-style newlines with a newline ending every file\n+end_of_line = lf\n+insert_final_newline = true\n+trim_trailing_whitespace = true\n+# Set default charset\n+charset = utf-8\n+# Indent style default\n+indent_style = space\n+# Max Line Length - a hard line wrap, should be disabled\n+max_line_length = off\n+\n+[*.{py,cfg,ini}]\n+# 4 space indentation\n+indent_size = 4\n+\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 00000000..590eb044\n--- /dev/null\n+++ b/.flake8\n@@ -0,0 +1,24 @@\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+per-file-ignores =\n+ src/plone/app/robotframework/__init__.py:F401\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 00000000..d13f706c\n--- /dev/null\n+++ b/.github/workflows/meta.yml\n@@ -0,0 +1,66 @@\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+ dependencies:\n+ uses: plone/meta/.github/workflows/dependencies.yml@main\n+ release_ready:\n+ uses: plone/meta/.github/workflows/release_ready.yml@main\n+\n+#TODO: remove the tests and coverage, as they fail on GHA for now.\n+# Removed the circular dependency check as well,\n+# due to plone.app.multilingual and Products.CMFPlone having a circular dependency.\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 855b1cab..503e47c5 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -1,25 +1,55 @@\n-syntax: glob\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-*.mo\n-*.swp\n *.pyc\n-*.py.bak\n-.DS_Store\n-.idea\n+*.pyo\n+\n+# translation related\n+*.mo\n+\n+# tools related\n+build/\n+.coverage\n+.*project\n+coverage.xml\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-.ropeproject\n-bin\n-buildout-cache\n-develop-eggs\n-dist\n-docs/make.bat\n-docs/Makefile\n-etc\n-include\n-lib\n-local\n-parts\n-pip-selfcheck.json\n-var\n+parts/\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 00000000..de2bf65b\n--- /dev/null\n+++ b/.meta.toml\n@@ -0,0 +1,27 @@\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+[flake8]\n+extra_lines = """\n+per-file-ignores =\n+ src/plone/app/robotframework/__init__.py:F401\n+"""\n+\n+[pyproject]\n+codespell_ignores = "ot,nin,"\n+dependencies_ignores = "[\'robotide\', \'collective.js.speakjs\', \'watchdog\', \'robotframework-debuglibrary\', \'robotframework-ride\', \'robotframework-selenium2library\', \'robotframework-seleniumtestability\', \'sphinxcontrib-robotdoc\', \'robotsuite\', \'robotframework-browser\' ]"\n+dependencies_mappings = [\n+ "Pillow = [\'PIL\']",\n+ "robotframework = [\'robot\']",\n+ ]\n+\n+[github]\n+jobs = [\n+ "qa",\n+ "dependencies",\n+ "release_ready",\n+ ]\ndiff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml\nnew file mode 100644\nindex 00000000..b6eb0432\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/news/434550cc.internal b/news/434550cc.internal\nnew file mode 100644\nindex 00000000..c08f5399\n--- /dev/null\n+++ b/news/434550cc.internal\n@@ -0,0 +1,2 @@\n+Update configuration files.\n+[plone devs]\ndiff --git a/pyproject.toml b/pyproject.toml\nindex 05b615de..4a596000 100644\n--- a/pyproject.toml\n+++ b/pyproject.toml\n@@ -1,6 +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 [tool.towncrier]\n-filename = "CHANGES.rst"\n directory = "news/"\n+filename = "CHANGES.rst"\n title_format = "{version} ({project_date})"\n underlines = ["-", ""]\n \n@@ -18,3 +21,139 @@ showcontent = true\n directory = "bugfix"\n name = "Bug fixes:"\n showcontent = true\n+\n+[[tool.towncrier.type]]\n+directory = "internal"\n+name = "Internal:"\n+showcontent = true\n+\n+[[tool.towncrier.type]]\n+directory = "documentation"\n+name = "Documentation:"\n+showcontent = true\n+\n+[[tool.towncrier.type]]\n+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,ot,nin,"\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 = [\'robotide\', \'collective.js.speakjs\', \'watchdog\', \'robotframework-debuglibrary\', \'robotframework-ride\', \'robotframework-selenium2library\', \'robotframework-seleniumtestability\', \'sphinxcontrib-robotdoc\', \'robotsuite\', \'robotframework-browser\' ]\n+Pillow = [\'PIL\']\n+robotframework = [\'robot\']\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 4f3a3e25..00000000\n--- a/setup.cfg\n+++ /dev/null\n@@ -1,14 +0,0 @@\n-[check-manifest]\n-ignore =\n- *.cfg\n- requirements.txt\n-\n-[isort]\n-profile = black\n-force_alphabetical_sort = True\n-force_single_line = True\n-lines_after_imports = 2\n-\n-[bdist_wheel]\n-# Py3 only\n-universal = 0\ndiff --git a/tox.ini b/tox.ini\nnew file mode 100644\nindex 00000000..0cb1d9e0\n--- /dev/null\n+++ b/tox.ini\n@@ -0,0 +1,210 @@\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+ lint\n+ test\n+ dependencies\n+\n+\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]\n+skip_install = true\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+ echo "Unrecognized environment name {envname}"\n+ false\n+\n+[testenv:init]\n+description = Prepare environment\n+skip_install = true\n+commands =\n+ echo "Initial setup complete"\n+\n+\n+[testenv:format]\n+description = automatically reformat code\n+skip_install = true\n+deps =\n+ pre-commit\n+commands =\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]\n+description = run linters that will help improve the code style\n+skip_install = true\n+deps =\n+ pre-commit\n+commands =\n+ pre-commit run -a\n+\n+[testenv:dependencies]\n+description = check if the package defines all its dependencies\n+skip_install = true\n+deps =\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+ rfbrowser init\n+ zope-testrunner --all --test-path={toxinidir}/src -s plone.app.robotframework {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+ rfbrowser init\n+ coverage run --branch --source plone.app.robotframework {envbindir}/zope-testrunner --quiet --all --test-path={toxinidir}/src -s plone.app.robotframework {posargs}\n+ coverage report -m --format markdown\n+ coverage xml\n+extras =\n+ test\n+\n+\n+[testenv:release-check]\n+description = ensure that the distribution is ready to release\n+skip_install = true\n+deps =\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+ # 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/.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.app.robotframework +Repository: plone.testing Branch: refs/heads/master -Date: 2023-10-15T18:28:12+02:00 +Date: 2023-10-15T19:09:56+02:00 Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/plone.app.robotframework/commit/9742811d44b3cecb70306c9039a81246dec31d36 +Commit: https://github.com/plone/plone.testing/commit/b5bcc0329d7eefe34a38f23f42f44ce92c49f787 -chore: drop old files +chore: pyupgrade Files changed: -D buildout.cfg -D docs.cfg -D requirements.txt +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/buildout.cfg b/buildout.cfg\ndeleted file mode 100644\nindex 3026c2e..0000000\n--- a/buildout.cfg\n+++ /dev/null\n@@ -1,59 +0,0 @@\n-[buildout]\n-extends =\n- https://raw.githubusercontent.com/collective/buildout.plonetest/master/test-5.1.x.cfg\n- versions.cfg\n-parts +=\n- docs\n- libdoc\n- robot\n-package-name = plone.app.robotframework\n-package-extras = [test,speak]\n-test-eggs = Pillow\n-develop = .\n-versions = versions\n-\n-[versions]\n-setuptools =\n-zc.buildout =\n-plone.app.robotframework =\n-\n-[instance]\n-zcml =\n-\n-[docs]\n-recipe = collective.recipe.sphinxbuilder\n-eggs =\n- Pillow\n- plone.app.robotframework [docs]\n-\n-[libdoc]\n-recipe = zc.recipe.egg\n-eggs = plone.app.robotframework [docs]\n-entry-points = libdoc=robot.libdoc:libdoc_cli\n-scripts = libdoc\n-arguments = sys.argv[1:]\n-\n-[environment]\n-zope_i18n_compile_mo_files = true\n-ROBOT_SELENIUM2LIBRARY_RUN_ON_FAILURE = Capture page screenshot and log source\n-\n-[test]\n-environment = environment\n-\n-[robot]\n-recipe = zc.recipe.egg\n-eggs =\n- Pillow\n- plone.app.robotframework [test,ride,speak,reload,debug]\n-\n-[nix]\n-recipe = collective.recipe.nix\n-name = default\n-eggs =\n- ${test:eggs}\n- ${robot:eggs}\n-nixpkgs =\n- watchdog=pythonPackages.watchdog\n- zc.buildout=pythonPackages.zc_buildout_nix\n-outputs = default.nix\n-allow-from-cache = true\ndiff --git a/docs.cfg b/docs.cfg\ndeleted file mode 100644\nindex 5275a2b..0000000\n--- a/docs.cfg\n+++ /dev/null\n@@ -1,7 +0,0 @@\n-[buildout]\n-parts = sphinxbuilder\n-index = http://pypi.python.org/simple\n-\n-[sphinxbuilder]\n-recipe = collective.recipe.sphinxbuilder\n-eggs = sphinxcontrib-robotdoc\ndiff --git a/requirements.txt b/requirements.txt\ndeleted file mode 100644\nindex bba2416..0000000\n--- a/requirements.txt\n+++ /dev/null\n@@ -1,2 +0,0 @@\n-setuptools==33.1.1\n-zc.buildout==2.12.1\n' +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.app.robotframework +Repository: plone.testing Branch: refs/heads/master -Date: 2023-10-15T18:28:12+02:00 +Date: 2023-10-15T19:09:56+02:00 Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/plone.app.robotframework/commit/edafb601f848ade2c3af0e40d3cd85c4382775a8 +Commit: https://github.com/plone/plone.testing/commit/1b7305ac51a68aedb0a26b755e38a7bd740adf75 -chore: pyupgrade +chore: black Files changed: -M src/plone/app/robotframework/server.py +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/src/plone/app/robotframework/server.py b/src/plone/app/robotframework/server.py\nindex 0015186..55b8b4f 100644\n--- a/src/plone/app/robotframework/server.py\n+++ b/src/plone/app/robotframework/server.py\n@@ -321,7 +321,7 @@ def zodb_setup(self, layer_dotted_name=None):\n if HAS_VERBOSE_CONSOLE:\n print(\n WAIT(\n- "Test set up {}.{}".format(layer.__module__, layer.__name__)\n+ f"Test set up {layer.__module__}.{layer.__name__}"\n )\n )\n layer.testSetUp()\n' +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.app.robotframework +Repository: plone.testing Branch: refs/heads/master -Date: 2023-10-15T18:28:12+02:00 +Date: 2023-10-15T19:09:56+02:00 Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/plone.app.robotframework/commit/11aea772398106c0a58e077854c1c1ed6c419fe4 +Commit: https://github.com/plone/plone.testing/commit/048b6302169bc99281c079825901206f436da9f6 -chore: isort +chore: zpretty Files changed: -M src/plone/app/robotframework/testing.py +M src/plone/testing/testing_zca.zcml +M src/plone/testing/testing_zca_more_specific.zcml -b'diff --git a/src/plone/app/robotframework/testing.py b/src/plone/app/robotframework/testing.py\nindex 7086070..744ac34 100644\n--- a/src/plone/app/robotframework/testing.py\n+++ b/src/plone/app/robotframework/testing.py\n@@ -18,8 +18,8 @@\n from plone.app.testing import ploneSite\n from plone.testing import Layer\n from plone.testing import zope as zope_testing\n-from plone.testing.zope import WSGIServer\n from plone.testing.zope import WSGI_SERVER_FIXTURE\n+from plone.testing.zope import WSGIServer\n from Products.MailHost.interfaces import IMailHost\n from robot.libraries.BuiltIn import BuiltIn\n from webtest.http import StopableWSGIServer\n' +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.app.robotframework/commit/6954b93d9abd25d2ed1e2cf3c6409f77f2b1aaae +Commit: https://github.com/plone/plone.testing/commit/e4e9fa9ec34ff9edcddef5a9f4b85d1ca9c5566d -chore: black +chore: update trove classifiers Files changed: -M src/plone/app/robotframework/reload.py -M src/plone/app/robotframework/remote.py -M src/plone/app/robotframework/saucelabs.py -M src/plone/app/robotframework/server.py -M src/plone/app/robotframework/testing.py -M src/plone/app/robotframework/tests/test_content.py +M setup.py -b'diff --git a/src/plone/app/robotframework/reload.py b/src/plone/app/robotframework/reload.py\nindex 201aa65..614b882 100644\n--- a/src/plone/app/robotframework/reload.py\n+++ b/src/plone/app/robotframework/reload.py\n@@ -19,7 +19,6 @@ def ERROR(msg):\n \n \n class Watcher(FileSystemEventHandler):\n-\n allowed_extensions = {"po", "pt", "py", "xml", "csv", "zcml"}\n \n def __init__(self, paths, forkloop, minimum_wait=2.0):\n@@ -74,7 +73,6 @@ def on_any_event(self, event):\n \n class ForkLoop:\n def __init__(self):\n-\n self.fork = True # Must be \'True\' to create new child on start\n self.active = False\n self.pause = False\ndiff --git a/src/plone/app/robotframework/remote.py b/src/plone/app/robotframework/remote.py\nindex 2967001..e210e16 100644\n--- a/src/plone/app/robotframework/remote.py\n+++ b/src/plone/app/robotframework/remote.py\n@@ -51,7 +51,6 @@ def run_keyword(self, name, args, kwargs={}):\n \n \n class RemoteLibraryLayer(Layer):\n-\n defaultBases = (PLONE_FIXTURE,)\n libraryBases = ()\n \ndiff --git a/src/plone/app/robotframework/saucelabs.py b/src/plone/app/robotframework/saucelabs.py\nindex 59c92cb..978327b 100644\n--- a/src/plone/app/robotframework/saucelabs.py\n+++ b/src/plone/app/robotframework/saucelabs.py\n@@ -13,12 +13,7 @@\n class SauceLabs:\n def report_sauce_status(self, name, status, tags=[], remote_url=""):\n """Report test status and tags to SauceLabs"""\n- job_id = (\n- BuiltIn()\n- .get_library_instance("Selenium2Library")\n- .driver\n- .session_id\n- )\n+ job_id = BuiltIn().get_library_instance("Selenium2Library").driver.session_id\n \n if USERNAME_ACCESS_KEY.match(remote_url):\n username, access_key = USERNAME_ACCESS_KEY.findall(remote_url)[0][1:]\ndiff --git a/src/plone/app/robotframework/server.py b/src/plone/app/robotframework/server.py\nindex 55b8b4f..c21ba8b 100644\n--- a/src/plone/app/robotframework/server.py\n+++ b/src/plone/app/robotframework/server.py\n@@ -47,7 +47,6 @@ def READY(msg):\n \n \n def start(zope_layer_dotted_name):\n-\n print(WAIT("Starting Zope robot server"))\n \n zsl = Zope2Server()\n@@ -98,7 +97,6 @@ def start_reload(\n preload_layer_dotted_name="plone.app.testing.PLONE_FIXTURE",\n extensions=None,\n ):\n-\n print(WAIT("Starting Zope robot server"))\n \n zsl = Zope2Server()\n@@ -231,7 +229,6 @@ def server():\n \n \n class RobotListener:\n-\n ROBOT_LISTENER_API_VERSION = 2\n \n def __init__(self):\n@@ -249,7 +246,6 @@ def end_test(self, name, attrs):\n \n \n class Zope2Server:\n-\n stop_zope_server_lazy = False # trigger lazy Zope2Server shutdown\n stop_zope_server_layer = None # sticky layer for lazy shutdown\n \n@@ -319,11 +315,7 @@ def zodb_setup(self, layer_dotted_name=None):\n for layer in layers:\n if hasattr(layer, "testSetUp"):\n if HAS_VERBOSE_CONSOLE:\n- print(\n- WAIT(\n- f"Test set up {layer.__module__}.{layer.__name__}"\n- )\n- )\n+ print(WAIT(f"Test set up {layer.__module__}.{layer.__name__}"))\n layer.testSetUp()\n if HAS_VERBOSE_CONSOLE:\n print(READY("Test set up"))\ndiff --git a/src/plone/app/robotframework/testing.py b/src/plone/app/robotframework/testing.py\nindex 744ac34..6e3a191 100644\n--- a/src/plone/app/robotframework/testing.py\n+++ b/src/plone/app/robotframework/testing.py\n@@ -56,7 +56,6 @@ def tearDown(self):\n \n \n class SimplePublicationWithTypesLayer(Layer):\n-\n defaultBases = (SIMPLE_PUBLICATION_FIXTURE,)\n \n def setUp(self):\n@@ -207,7 +206,6 @@ def _get_robot_variable(self, name):\n return filter(bool, [s.strip() for s in candidates])\n \n def setUpZope(self, app, configurationContext):\n-\n # This installs the VHM in the Zope root, so we can have VHM support too\n AppInitializer(app).install_virtual_hosting()\n \n@@ -294,26 +292,22 @@ def __nonzero__(x):\n \n \n class WSGIServerSingleThreaded(WSGIServer):\n-\n def setUpServer(self):\n- """Create a single threaded WSGI server instance and save it in self.server.\n- """\n+ """Create a single threaded WSGI server instance and save it in self.server."""\n app = self.make_wsgi_app()\n- kwargs = {\'clear_untrusted_proxy_headers\': False,\n- \'threads\': 1}\n+ kwargs = {"clear_untrusted_proxy_headers": False, "threads": 1}\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-\n+ self["host"] = self.host = self.server.effective_host\n+ self["port"] = self.port = int(self.server.effective_port)\n \n \n WSGI_SERVER_SINGLE_THREADED_FIXTURE = WSGIServerSingleThreaded()\n@@ -332,7 +326,6 @@ def setUpServer(self):\n if HAS_SPEAKJS:\n \n class SpeakJSLayer(Layer):\n-\n defaultBases = (PLONE_FIXTURE,)\n \n def setUp(self):\ndiff --git a/src/plone/app/robotframework/tests/test_content.py b/src/plone/app/robotframework/tests/test_content.py\nindex 9052b24..516878e 100644\n--- a/src/plone/app/robotframework/tests/test_content.py\n+++ b/src/plone/app/robotframework/tests/test_content.py\n@@ -7,7 +7,6 @@\n \n \n class TestCreateContent(unittest.TestCase):\n-\n layer = PLONE_ROBOT_INTEGRATION_TESTING\n \n def setUp(self):\n@@ -50,7 +49,6 @@ def test_create_content_updates_catalog(self):\n \n \n class TestGlobalAllow(unittest.TestCase):\n-\n layer = PLONE_ROBOT_INTEGRATION_TESTING\n \n def setUp(self):\n' +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' -Repository: plone.app.robotframework +Repository: plone.testing Branch: refs/heads/master -Date: 2023-10-15T18:28:12+02:00 +Date: 2023-10-15T19:09:56+02:00 Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/plone.app.robotframework/commit/63c61ab607b5d553b0f21458773c64a5d7e4ef46 +Commit: https://github.com/plone/plone.testing/commit/9f1d4571d2a7380cb147fdba713a57d4a5a63d93 -chore: zpretty +feat: pyroma Files changed: -M docs/source/libdoc/python_debugging.html -M docs/source/libdoc/python_layoutmath.html -M docs/source/libdoc/python_saucelabs.html -M docs/source/libdoc/python_zope2server.html -M docs/source/libdoc/remote_autologin.html -M docs/source/libdoc/remote_content.html -M docs/source/libdoc/remote_genericsetup.html -M docs/source/libdoc/remote_i18n.html -M docs/source/libdoc/remote_mockmailhost.html -M docs/source/libdoc/remote_quickinstaller.html -M docs/source/libdoc/remote_users.html -M docs/source/libdoc/remote_zope2server.html -M docs/source/libdoc/selenium.html -M docs/source/libdoc/user_keywords.html -M docs/source/libdoc/user_saucelabs.html -M docs/source/libdoc/user_selenium.html -M docs/source/libdoc/user_server.html - -b'diff --git a/docs/source/libdoc/python_debugging.html b/docs/source/libdoc/python_debugging.html\nindex 0da14491..840b74cb 100644\n--- a/docs/source/libdoc/python_debugging.html\n+++ b/docs/source/libdoc/python_debugging.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/python_layoutmath.html b/docs/source/libdoc/python_layoutmath.html\nindex 97356fed..d672ecc2 100644\n--- a/docs/source/libdoc/python_layoutmath.html\n+++ b/docs/source/libdoc/python_layoutmath.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/python_saucelabs.html b/docs/source/libdoc/python_saucelabs.html\nindex e31f6d15..47c85ae8 100644\n--- a/docs/source/libdoc/python_saucelabs.html\n+++ b/docs/source/libdoc/python_saucelabs.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/python_zope2server.html b/docs/source/libdoc/python_zope2server.html\nindex 634cac2e..1576c859 100644\n--- a/docs/source/libdoc/python_zope2server.html\n+++ b/docs/source/libdoc/python_zope2server.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/remote_autologin.html b/docs/source/libdoc/remote_autologin.html\nindex 673199cb..113d195b 100644\n--- a/docs/source/libdoc/remote_autologin.html\n+++ b/docs/source/libdoc/remote_autologin.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/remote_content.html b/docs/source/libdoc/remote_content.html\nindex c19ccbfc..16452ddb 100644\n--- a/docs/source/libdoc/remote_content.html\n+++ b/docs/source/libdoc/remote_content.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/remote_genericsetup.html b/docs/source/libdoc/remote_genericsetup.html\nindex 5a478d02..b3d4b7bd 100644\n--- a/docs/source/libdoc/remote_genericsetup.html\n+++ b/docs/source/libdoc/remote_genericsetup.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/remote_i18n.html b/docs/source/libdoc/remote_i18n.html\nindex 970e0b4a..6efb53ea 100644\n--- a/docs/source/libdoc/remote_i18n.html\n+++ b/docs/source/libdoc/remote_i18n.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/remote_mockmailhost.html b/docs/source/libdoc/remote_mockmailhost.html\nindex 962eb517..1ed80700 100644\n--- a/docs/source/libdoc/remote_mockmailhost.html\n+++ b/docs/source/libdoc/remote_mockmailhost.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/remote_quickinstaller.html b/docs/source/libdoc/remote_quickinstaller.html\nindex fd713c5e..58085bd4 100644\n--- a/docs/source/libdoc/remote_quickinstaller.html\n+++ b/docs/source/libdoc/remote_quickinstaller.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/remote_users.html b/docs/source/libdoc/remote_users.html\nindex fef16e93..ca10bc10 100644\n--- a/docs/source/libdoc/remote_users.html\n+++ b/docs/source/libdoc/remote_users.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/remote_zope2server.html b/docs/source/libdoc/remote_zope2server.html\nindex e4c539fe..829dc641 100644\n--- a/docs/source/libdoc/remote_zope2server.html\n+++ b/docs/source/libdoc/remote_zope2server.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/selenium.html b/docs/source/libdoc/selenium.html\nindex 55c01242..f82b307f 100644\n--- a/docs/source/libdoc/selenium.html\n+++ b/docs/source/libdoc/selenium.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n-\n+ \n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/user_keywords.html b/docs/source/libdoc/user_keywords.html\nindex 990f5417..27abf9cf 100644\n--- a/docs/source/libdoc/user_keywords.html\n+++ b/docs/source/libdoc/user_keywords.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/user_saucelabs.html b/docs/source/libdoc/user_saucelabs.html\nindex c3356ea6..66b25d38 100644\n--- a/docs/source/libdoc/user_saucelabs.html\n+++ b/docs/source/libdoc/user_saucelabs.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/user_selenium.html b/docs/source/libdoc/user_selenium.html\nindex 3b8b8f11..280a3f0a 100644\n--- a/docs/source/libdoc/user_selenium.html\n+++ b/docs/source/libdoc/user_selenium.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/user_server.html b/docs/source/libdoc/user_server.html\nindex 523d80e5..7624256a 100644\n--- a/docs/source/libdoc/user_server.html\n+++ b/docs/source/libdoc/user_server.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \n' - -Repository: plone.app.robotframework +M setup.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' + +Repository: plone.testing Branch: refs/heads/master -Date: 2023-10-15T18:28:12+02:00 +Date: 2023-10-15T19:09:56+02:00 Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/plone.app.robotframework/commit/5189df595412fd1223eb82fde180f0a98353527b +Commit: https://github.com/plone/plone.testing/commit/ce0a4e67f7a3c02277d5f20b8f213ff4ff4fc331 feat: codespell Files changed: -M CHANGES.rst -M docs/source/happy.rst -M docs/source/keywords.rst -M docs/source/remote.rst -M docs/source/robot.rst -M src/plone/app/robotframework/content.py -M src/plone/app/robotframework/i18n.py -M src/plone/app/robotframework/robotentrypoints.py -M src/plone/app/robotframework/server.py -M src/plone/app/robotframework/users.py +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 -b'diff --git a/CHANGES.rst b/CHANGES.rst\nindex 0163e8e..a1cd163 100644\n--- a/CHANGES.rst\n+++ b/CHANGES.rst\n@@ -585,7 +585,7 @@ Fixes:\n ------------------\n \n - Add a new command-line option for robot-server to start Zope in debug-mode\n- (useage: bin/robot-server -d or bin/robot-server --debug-mode)\n+ (usage: bin/robot-server -d or bin/robot-server --debug-mode)\n [datakurre]\n - Change robot LISTENER_PORT (used in communication between bin/robot-server\n and bin/robot via robotframework) to default port 49999 instead of 10001\n@@ -676,7 +676,7 @@ Fixes:\n 0.7.1 (2014-02-08)\n ------------------\n \n-- Add ignored Sphinx-directives to pybot to make it easier to run pybot agains\n+- Add ignored Sphinx-directives to pybot to make it easier to run pybot against\n Sphinx documentation\n [datakurre]\n - Update libdoc-generated documentations\n@@ -825,7 +825,7 @@ This is Arnhem Sprint preview release of 0.7.0.\n 0.6.0 (2013-04-30)\n ------------------\n \n-- Add verbose console outout for robot-server for test setup and teardown\n+- Add verbose console output for robot-server for test setup and teardown\n [datakurre]\n - Documentation update\n [datakurre, Silvio Tomatis]\n@@ -892,7 +892,7 @@ This is Arnhem Sprint preview release of 0.7.0.\n ------------------\n \n - PLOG2013 development release.\n-- Define dedicated re-usable AUTOLOGIN_ROBOT_FIXTURE\n+- Define dedicated reusable AUTOLOGIN_ROBOT_FIXTURE\n - Drop BBB for plone.act\n - Drop entrypoints for pure pybot and rebot to make it easier to use them pure\n without extra dependencies by installing robotentrypoints-package\ndiff --git a/docs/source/happy.rst b/docs/source/happy.rst\nindex 5fd8002..f21e291 100644\n--- a/docs/source/happy.rst\n+++ b/docs/source/happy.rst\n@@ -398,7 +398,7 @@ execution* keyword, you can pause the test at any point to make it possible to\n figure out what to do next.\n (Dialogs depend on `TkInter-library `_.)\n \n-.. note:: Be sure to remove *Import libary* and *Pause execution*\n+.. note:: Be sure to remove *Import library* and *Pause execution*\n keyword calls before committing your tests to avoid pausing your\n tests on CI.\n \ndiff --git a/docs/source/keywords.rst b/docs/source/keywords.rst\nindex c18883e..d838e52 100644\n--- a/docs/source/keywords.rst\n+++ b/docs/source/keywords.rst\n@@ -10,7 +10,7 @@ Selenium2Library Keywords\n \n Selenium2Library is a web testing library for Robot Framework. It provides you\n with several low-level keywords to access certain elements of a web page, to\n-conduct actions on a web page and to test if a page met certain acceptance critera.\n+conduct actions on a web page and to test if a page met certain acceptance criteria.\n \n \n First Example\ndiff --git a/docs/source/remote.rst b/docs/source/remote.rst\nindex 1284b91..46f9988 100644\n--- a/docs/source/remote.rst\n+++ b/docs/source/remote.rst\n@@ -6,7 +6,7 @@ test environment for the actual tests-clauses (*When* and *Then*).\n \n Because Given-clauses are not really part of the actual test, it is not\n necessary to run them through Selenium (using Selenium2Library), but it would\n-be faster to write custon Python keywords for them.\n+be faster to write custom Python keywords for them.\n \n **plone.act** includes an example, how to a robot\n `remote library `_,\ndiff --git a/docs/source/robot.rst b/docs/source/robot.rst\nindex 0729d50..4210d2e 100644\n--- a/docs/source/robot.rst\n+++ b/docs/source/robot.rst\n@@ -49,7 +49,7 @@ Each test suite may contain one to four different parts:\n calling test keywords.\n \n **Keywords**\n- Is used to define new user keywords, which may re-use existing keywords\n+ Is used to define new user keywords, which may reuse existing keywords\n from imported libraries or resource files.\n \n \n@@ -132,14 +132,14 @@ Remote-library approach provides the following benefits when testing Plone:\n Resource files\n --------------\n \n-Resource files provide a re-usable way to abstract your test suites. To put\n+Resource files provide a reusable way to abstract your test suites. To put\n it simply, resources files are just like all the other ``.robot``-files, but\n they should not contain ``*** Test Cases ***`` certain ``*** Settings ***``\n commands (*Suite Setup*, *Suite Teardown*, *Test Setup* or *Test Teardown*).\n \n Resource files are the perfect way to import common libraries (with *Library*\n command in ```*** Settings ***``), define global ``*** Variables ***`` and\n-define re-usable common ```*** Keywords ***```. Resource files are included\n+define reusable common ```*** Keywords ***```. Resource files are included\n in a test suite with *Resource*-command in ```*** Settings ***``:\n \n .. code-block:: robotframework\ndiff --git a/src/plone/app/robotframework/content.py b/src/plone/app/robotframework/content.py\nindex 31459b2..75d6cc8 100644\n--- a/src/plone/app/robotframework/content.py\n+++ b/src/plone/app/robotframework/content.py\n@@ -224,7 +224,7 @@ def fire_transition(self, content, action):\n """Fire workflow action for content"""\n disableCSRFProtection()\n # It should be ok to use unrestricted-methods, because workflow\n- # transition guard should proctect unprivileged transition:\n+ # transition guard should protect unprivileged transition:\n pc = getToolByName(self, "portal_catalog")\n results = pc.unrestrictedSearchResults(UID=content)\n obj = results[0]._unrestrictedGetObject()\ndiff --git a/src/plone/app/robotframework/i18n.py b/src/plone/app/robotframework/i18n.py\nindex 2af6f82..73d132a 100644\n--- a/src/plone/app/robotframework/i18n.py\n+++ b/src/plone/app/robotframework/i18n.py\n@@ -21,7 +21,7 @@ def set_default_language(self, language=None):\n \n def translate(self, msgid, *args, **kwargs):\n """Return localized string for given msgid"""\n- # FIXME: we are alrady using robotframework = 3.0\n+ # FIXME: we are already using robotframework = 3.0\n # XXX: Because kwargs are only supported with robotframework >= 2.8.3,\n # we must parse them here to support robotframework < 2.8.3.\n for arg in [x for x in args if "=" in x]:\ndiff --git a/src/plone/app/robotframework/robotentrypoints.py b/src/plone/app/robotframework/robotentrypoints.py\nindex 71357d5..8159b32 100644\n--- a/src/plone/app/robotframework/robotentrypoints.py\n+++ b/src/plone/app/robotframework/robotentrypoints.py\n@@ -69,7 +69,7 @@ def ride():\n \n plone.app.robotframework[ride,reload]\n \n-Remember that ride must be lauched with system python with\n+Remember that ride must be launched with system python with\n wxPython installed, like:\n \n /usr/bin/python bin/ride\ndiff --git a/src/plone/app/robotframework/server.py b/src/plone/app/robotframework/server.py\nindex c21ba8b..6f8205e 100644\n--- a/src/plone/app/robotframework/server.py\n+++ b/src/plone/app/robotframework/server.py\n@@ -300,7 +300,7 @@ def stop_zope_server(self, force=False):\n if not self.stop_zope_server_lazy or force:\n tear_down()\n else:\n- # With lazy stop, the layer is saved to enable Zope2Server re-use\n+ # With lazy stop, the layer is saved to enable Zope2Server reuse\n # within the same process, until tear_down is called explicitly.\n Zope2Server.stop_zope_server_layer = self.zope_layer\n self.zope_layer = None\ndiff --git a/src/plone/app/robotframework/users.py b/src/plone/app/robotframework/users.py\nindex 537e34e..2611968 100644\n--- a/src/plone/app/robotframework/users.py\n+++ b/src/plone/app/robotframework/users.py\n@@ -11,7 +11,7 @@ class Users(RemoteLibrary):\n def create_user(self, *args, **kwargs):\n """Create user with given details and return its id"""\n disableCSRFProtection()\n- # FIXME: we are alrady using robotframework = 3.0\n+ # FIXME: we are already using robotframework = 3.0\n # XXX: Because kwargs are only supported with robotframework >= 2.8.3,\n # we must parse them here to support robotframework < 2.8.3.\n for arg in [x for x in args if "=" in x]:\n' +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' -Repository: plone.app.robotframework +Repository: plone.testing Branch: refs/heads/master -Date: 2023-10-15T18:28:13+02:00 +Date: 2023-10-15T19:09:56+02:00 Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/plone.app.robotframework/commit/7aa057388618e4d2ec75ce10ce59af4dded3fae9 +Commit: https://github.com/plone/plone.testing/commit/792a522edd67697febe1b6265e6050da9d0b5f21 + +fix: adapt tests -feat: flake8 +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. Files changed: -M docs/source/conf.py +M src/plone/testing/tests.py -b"diff --git a/docs/source/conf.py b/docs/source/conf.py\nindex 7743766..0f15e1e 100644\n--- a/docs/source/conf.py\n+++ b/docs/source/conf.py\n@@ -10,10 +10,6 @@\n # All configuration values have a default; values that are commented out\n # serve to show the default.\n \n-import os\n-import sys\n-\n-\n # If extensions (or modules to document with autodoc) are in another directory,\n # add these directories to sys.path here. If the directory is relative to the\n # documentation root, use os.path.abspath to make it absolute, like shown here.\n@@ -172,11 +168,11 @@\n \n latex_elements = {\n # The paper size ('letterpaper' or 'a4paper').\n- #'papersize': 'letterpaper',\n+ # 'papersize': 'letterpaper',\n # The font size ('10pt', '11pt' or '12pt').\n- #'pointsize': '10pt',\n+ # 'pointsize': '10pt',\n # Additional stuff for the LaTeX preamble.\n- #'preamble': '',\n+ # 'preamble': '',\n }\n \n # Grouping the document tree into LaTeX files. List of tuples\n" +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' -Repository: plone.app.robotframework +Repository: plone.testing Branch: refs/heads/master -Date: 2023-10-15T18:28:13+02:00 +Date: 2023-10-15T19:09:56+02:00 Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/plone.app.robotframework/commit/151dc374970c3295ebe33db797da72a23e57ed68 +Commit: https://github.com/plone/plone.testing/commit/72a8e6194924ba7bcc8a42ad5e62923df996969f + +feat: drop six + +Files changed: +M setup.py +M src/plone/testing/tests.py +M src/plone/testing/zodb.rst +M src/plone/testing/zope.rst + +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' + +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/f2818683413fbaa0c41e3c54428991ed3fa6c517 feat: declare dependencies Files changed: M setup.py -b'diff --git a/setup.py b/setup.py\nindex a78eeb3..c578ea7 100644\n--- a/setup.py\n+++ b/setup.py\n@@ -49,14 +49,20 @@ def read(filename):\n entry_points = dict(console_scripts=console_scripts)\n \n install_requires = [\n- "Products.CMFCore",\n+ "Pillow",\n "Products.CMFPlone",\n- "Products.MailHost",\n "Products.PlonePAS >= 5.0.1",\n "Products.PluggableAuthService",\n "babel",\n+ "docutils",\n "plone.app.testing",\n+ "plone.app.textfield",\n "plone.base",\n+ "plone.dexterity",\n+ "plone.i18n",\n+ "plone.namedfile",\n+ "plone.protect",\n+ "plone.registry",\n "plone.testing",\n "plone.uuid",\n "robotframework",\n@@ -66,19 +72,23 @@ def read(filename):\n "robotsuite", # not a direct dependency, but required for convenience\n "selenium",\n "setuptools",\n+ "z3c.form",\n+ "z3c.relationfield",\n "zope.component",\n- "zope.configuration",\n "zope.i18n",\n+ "zope.intid",\n "zope.schema",\n "zope.testrunner",\n ]\n \n test_requires = [\n- "plone.app.dexterity",\n+ "Products.MailHost",\n "plone.app.textfield",\n "plone.dexterity",\n "robotsuite",\n+ "webtest",\n "z3c.form",\n+ "zope.configuration",\n ]\n \n debug_requires = [\n' +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' + +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/5504cdea990e395a2d69dd89be8e59bdc08a3fc7 + +Add news entry + +Files changed: +A news/1.breaking +A news/2.breaking +M setup.py + +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' -Repository: plone.app.robotframework +Repository: plone.testing Branch: refs/heads/master -Date: 2023-10-19T10:07:36+02:00 +Date: 2023-10-19T10:08:02+02:00 Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/plone.app.robotframework/commit/b99da570c0649cd308837058768e83e77bb1cb88 +Commit: https://github.com/plone/plone.testing/commit/7be816a84830fd6ea898796a2d0adf91f8d3ec73 -Merge pull request #145 from plone/config-with-default-template-78bb80ce +Merge pull request #82 from plone/config-with-default-template-1756b024 Config with default template Files changed: -A .editorconfig A .flake8 A .github/workflows/meta.yml A .meta.toml A .pre-commit-config.yaml -A news/434550cc.internal -A tox.ini +A news/1.breaking +A news/2.breaking +A news/5cc689e5.internal +M .editorconfig M .gitignore -M CHANGES.rst -M docs/source/conf.py -M docs/source/happy.rst -M docs/source/keywords.rst -M docs/source/libdoc/python_debugging.html -M docs/source/libdoc/python_layoutmath.html -M docs/source/libdoc/python_saucelabs.html -M docs/source/libdoc/python_zope2server.html -M docs/source/libdoc/remote_autologin.html -M docs/source/libdoc/remote_content.html -M docs/source/libdoc/remote_genericsetup.html -M docs/source/libdoc/remote_i18n.html -M docs/source/libdoc/remote_mockmailhost.html -M docs/source/libdoc/remote_quickinstaller.html -M docs/source/libdoc/remote_users.html -M docs/source/libdoc/remote_zope2server.html -M docs/source/libdoc/selenium.html -M docs/source/libdoc/user_keywords.html -M docs/source/libdoc/user_saucelabs.html -M docs/source/libdoc/user_selenium.html -M docs/source/libdoc/user_server.html -M docs/source/remote.rst -M docs/source/robot.rst M pyproject.toml M setup.py -M src/plone/app/robotframework/content.py -M src/plone/app/robotframework/i18n.py -M src/plone/app/robotframework/reload.py -M src/plone/app/robotframework/remote.py -M src/plone/app/robotframework/robotentrypoints.py -M src/plone/app/robotframework/saucelabs.py -M src/plone/app/robotframework/server.py -M src/plone/app/robotframework/testing.py -M src/plone/app/robotframework/tests/test_content.py -M src/plone/app/robotframework/users.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 docs.cfg -D requirements.txt D setup.cfg -b'diff --git a/.editorconfig b/.editorconfig\nnew file mode 100644\nindex 00000000..8ae05aaa\n--- /dev/null\n+++ b/.editorconfig\n@@ -0,0 +1,54 @@\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+# file types\n+\n+# top-most EditorConfig file:\n+# Will ignore other EditorConfig files in Home directory or upper tree level.\n+root = true\n+\n+\n+[*] # For All Files\n+# Unix-style newlines with a newline ending every file\n+end_of_line = lf\n+insert_final_newline = true\n+trim_trailing_whitespace = true\n+# Set default charset\n+charset = utf-8\n+# Indent style default\n+indent_style = space\n+# Max Line Length - a hard line wrap, should be disabled\n+max_line_length = off\n+\n+[*.{py,cfg,ini}]\n+# 4 space indentation\n+indent_size = 4\n+\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 00000000..590eb044\n--- /dev/null\n+++ b/.flake8\n@@ -0,0 +1,24 @@\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+per-file-ignores =\n+ src/plone/app/robotframework/__init__.py:F401\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 00000000..d13f706c\n--- /dev/null\n+++ b/.github/workflows/meta.yml\n@@ -0,0 +1,66 @@\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+ dependencies:\n+ uses: plone/meta/.github/workflows/dependencies.yml@main\n+ release_ready:\n+ uses: plone/meta/.github/workflows/release_ready.yml@main\n+\n+#TODO: remove the tests and coverage, as they fail on GHA for now.\n+# Removed the circular dependency check as well,\n+# due to plone.app.multilingual and Products.CMFPlone having a circular dependency.\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 855b1cab..503e47c5 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -1,25 +1,55 @@\n-syntax: glob\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-*.mo\n-*.swp\n *.pyc\n-*.py.bak\n-.DS_Store\n-.idea\n+*.pyo\n+\n+# translation related\n+*.mo\n+\n+# tools related\n+build/\n+.coverage\n+.*project\n+coverage.xml\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-.ropeproject\n-bin\n-buildout-cache\n-develop-eggs\n-dist\n-docs/make.bat\n-docs/Makefile\n-etc\n-include\n-lib\n-local\n-parts\n-pip-selfcheck.json\n-var\n+parts/\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 00000000..de2bf65b\n--- /dev/null\n+++ b/.meta.toml\n@@ -0,0 +1,27 @@\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+[flake8]\n+extra_lines = """\n+per-file-ignores =\n+ src/plone/app/robotframework/__init__.py:F401\n+"""\n+\n+[pyproject]\n+codespell_ignores = "ot,nin,"\n+dependencies_ignores = "[\'robotide\', \'collective.js.speakjs\', \'watchdog\', \'robotframework-debuglibrary\', \'robotframework-ride\', \'robotframework-selenium2library\', \'robotframework-seleniumtestability\', \'sphinxcontrib-robotdoc\', \'robotsuite\', \'robotframework-browser\' ]"\n+dependencies_mappings = [\n+ "Pillow = [\'PIL\']",\n+ "robotframework = [\'robot\']",\n+ ]\n+\n+[github]\n+jobs = [\n+ "qa",\n+ "dependencies",\n+ "release_ready",\n+ ]\ndiff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml\nnew file mode 100644\nindex 00000000..b6eb0432\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/CHANGES.rst b/CHANGES.rst\nindex 0163e8ee..a1cd1635 100644\n--- a/CHANGES.rst\n+++ b/CHANGES.rst\n@@ -585,7 +585,7 @@ Fixes:\n ------------------\n \n - Add a new command-line option for robot-server to start Zope in debug-mode\n- (useage: bin/robot-server -d or bin/robot-server --debug-mode)\n+ (usage: bin/robot-server -d or bin/robot-server --debug-mode)\n [datakurre]\n - Change robot LISTENER_PORT (used in communication between bin/robot-server\n and bin/robot via robotframework) to default port 49999 instead of 10001\n@@ -676,7 +676,7 @@ Fixes:\n 0.7.1 (2014-02-08)\n ------------------\n \n-- Add ignored Sphinx-directives to pybot to make it easier to run pybot agains\n+- Add ignored Sphinx-directives to pybot to make it easier to run pybot against\n Sphinx documentation\n [datakurre]\n - Update libdoc-generated documentations\n@@ -825,7 +825,7 @@ This is Arnhem Sprint preview release of 0.7.0.\n 0.6.0 (2013-04-30)\n ------------------\n \n-- Add verbose console outout for robot-server for test setup and teardown\n+- Add verbose console output for robot-server for test setup and teardown\n [datakurre]\n - Documentation update\n [datakurre, Silvio Tomatis]\n@@ -892,7 +892,7 @@ This is Arnhem Sprint preview release of 0.7.0.\n ------------------\n \n - PLOG2013 development release.\n-- Define dedicated re-usable AUTOLOGIN_ROBOT_FIXTURE\n+- Define dedicated reusable AUTOLOGIN_ROBOT_FIXTURE\n - Drop BBB for plone.act\n - Drop entrypoints for pure pybot and rebot to make it easier to use them pure\n without extra dependencies by installing robotentrypoints-package\ndiff --git a/buildout.cfg b/buildout.cfg\ndeleted file mode 100644\nindex 3026c2ee..00000000\n--- a/buildout.cfg\n+++ /dev/null\n@@ -1,59 +0,0 @@\n-[buildout]\n-extends =\n- https://raw.githubusercontent.com/collective/buildout.plonetest/master/test-5.1.x.cfg\n- versions.cfg\n-parts +=\n- docs\n- libdoc\n- robot\n-package-name = plone.app.robotframework\n-package-extras = [test,speak]\n-test-eggs = Pillow\n-develop = .\n-versions = versions\n-\n-[versions]\n-setuptools =\n-zc.buildout =\n-plone.app.robotframework =\n-\n-[instance]\n-zcml =\n-\n-[docs]\n-recipe = collective.recipe.sphinxbuilder\n-eggs =\n- Pillow\n- plone.app.robotframework [docs]\n-\n-[libdoc]\n-recipe = zc.recipe.egg\n-eggs = plone.app.robotframework [docs]\n-entry-points = libdoc=robot.libdoc:libdoc_cli\n-scripts = libdoc\n-arguments = sys.argv[1:]\n-\n-[environment]\n-zope_i18n_compile_mo_files = true\n-ROBOT_SELENIUM2LIBRARY_RUN_ON_FAILURE = Capture page screenshot and log source\n-\n-[test]\n-environment = environment\n-\n-[robot]\n-recipe = zc.recipe.egg\n-eggs =\n- Pillow\n- plone.app.robotframework [test,ride,speak,reload,debug]\n-\n-[nix]\n-recipe = collective.recipe.nix\n-name = default\n-eggs =\n- ${test:eggs}\n- ${robot:eggs}\n-nixpkgs =\n- watchdog=pythonPackages.watchdog\n- zc.buildout=pythonPackages.zc_buildout_nix\n-outputs = default.nix\n-allow-from-cache = true\ndiff --git a/docs.cfg b/docs.cfg\ndeleted file mode 100644\nindex 5275a2b2..00000000\n--- a/docs.cfg\n+++ /dev/null\n@@ -1,7 +0,0 @@\n-[buildout]\n-parts = sphinxbuilder\n-index = http://pypi.python.org/simple\n-\n-[sphinxbuilder]\n-recipe = collective.recipe.sphinxbuilder\n-eggs = sphinxcontrib-robotdoc\ndiff --git a/docs/source/conf.py b/docs/source/conf.py\nindex 77437660..0f15e1ea 100644\n--- a/docs/source/conf.py\n+++ b/docs/source/conf.py\n@@ -10,10 +10,6 @@\n # All configuration values have a default; values that are commented out\n # serve to show the default.\n \n-import os\n-import sys\n-\n-\n # If extensions (or modules to document with autodoc) are in another directory,\n # add these directories to sys.path here. If the directory is relative to the\n # documentation root, use os.path.abspath to make it absolute, like shown here.\n@@ -172,11 +168,11 @@\n \n latex_elements = {\n # The paper size (\'letterpaper\' or \'a4paper\').\n- #\'papersize\': \'letterpaper\',\n+ # \'papersize\': \'letterpaper\',\n # The font size (\'10pt\', \'11pt\' or \'12pt\').\n- #\'pointsize\': \'10pt\',\n+ # \'pointsize\': \'10pt\',\n # Additional stuff for the LaTeX preamble.\n- #\'preamble\': \'\',\n+ # \'preamble\': \'\',\n }\n \n # Grouping the document tree into LaTeX files. List of tuples\ndiff --git a/docs/source/happy.rst b/docs/source/happy.rst\nindex 5fd8002b..f21e291b 100644\n--- a/docs/source/happy.rst\n+++ b/docs/source/happy.rst\n@@ -398,7 +398,7 @@ execution* keyword, you can pause the test at any point to make it possible to\n figure out what to do next.\n (Dialogs depend on `TkInter-library `_.)\n \n-.. note:: Be sure to remove *Import libary* and *Pause execution*\n+.. note:: Be sure to remove *Import library* and *Pause execution*\n keyword calls before committing your tests to avoid pausing your\n tests on CI.\n \ndiff --git a/docs/source/keywords.rst b/docs/source/keywords.rst\nindex c18883ed..d838e520 100644\n--- a/docs/source/keywords.rst\n+++ b/docs/source/keywords.rst\n@@ -10,7 +10,7 @@ Selenium2Library Keywords\n \n Selenium2Library is a web testing library for Robot Framework. It provides you\n with several low-level keywords to access certain elements of a web page, to\n-conduct actions on a web page and to test if a page met certain acceptance critera.\n+conduct actions on a web page and to test if a page met certain acceptance criteria.\n \n \n First Example\ndiff --git a/docs/source/libdoc/python_debugging.html b/docs/source/libdoc/python_debugging.html\nindex 0da14491..840b74cb 100644\n--- a/docs/source/libdoc/python_debugging.html\n+++ b/docs/source/libdoc/python_debugging.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/python_layoutmath.html b/docs/source/libdoc/python_layoutmath.html\nindex 97356fed..d672ecc2 100644\n--- a/docs/source/libdoc/python_layoutmath.html\n+++ b/docs/source/libdoc/python_layoutmath.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/python_saucelabs.html b/docs/source/libdoc/python_saucelabs.html\nindex e31f6d15..47c85ae8 100644\n--- a/docs/source/libdoc/python_saucelabs.html\n+++ b/docs/source/libdoc/python_saucelabs.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/python_zope2server.html b/docs/source/libdoc/python_zope2server.html\nindex 634cac2e..1576c859 100644\n--- a/docs/source/libdoc/python_zope2server.html\n+++ b/docs/source/libdoc/python_zope2server.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/remote_autologin.html b/docs/source/libdoc/remote_autologin.html\nindex 673199cb..113d195b 100644\n--- a/docs/source/libdoc/remote_autologin.html\n+++ b/docs/source/libdoc/remote_autologin.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/remote_content.html b/docs/source/libdoc/remote_content.html\nindex c19ccbfc..16452ddb 100644\n--- a/docs/source/libdoc/remote_content.html\n+++ b/docs/source/libdoc/remote_content.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/remote_genericsetup.html b/docs/source/libdoc/remote_genericsetup.html\nindex 5a478d02..b3d4b7bd 100644\n--- a/docs/source/libdoc/remote_genericsetup.html\n+++ b/docs/source/libdoc/remote_genericsetup.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/remote_i18n.html b/docs/source/libdoc/remote_i18n.html\nindex 970e0b4a..6efb53ea 100644\n--- a/docs/source/libdoc/remote_i18n.html\n+++ b/docs/source/libdoc/remote_i18n.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/remote_mockmailhost.html b/docs/source/libdoc/remote_mockmailhost.html\nindex 962eb517..1ed80700 100644\n--- a/docs/source/libdoc/remote_mockmailhost.html\n+++ b/docs/source/libdoc/remote_mockmailhost.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/remote_quickinstaller.html b/docs/source/libdoc/remote_quickinstaller.html\nindex fd713c5e..58085bd4 100644\n--- a/docs/source/libdoc/remote_quickinstaller.html\n+++ b/docs/source/libdoc/remote_quickinstaller.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/remote_users.html b/docs/source/libdoc/remote_users.html\nindex fef16e93..ca10bc10 100644\n--- a/docs/source/libdoc/remote_users.html\n+++ b/docs/source/libdoc/remote_users.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/remote_zope2server.html b/docs/source/libdoc/remote_zope2server.html\nindex e4c539fe..829dc641 100644\n--- a/docs/source/libdoc/remote_zope2server.html\n+++ b/docs/source/libdoc/remote_zope2server.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/selenium.html b/docs/source/libdoc/selenium.html\nindex 55c01242..f82b307f 100644\n--- a/docs/source/libdoc/selenium.html\n+++ b/docs/source/libdoc/selenium.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n-\n+ \n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/user_keywords.html b/docs/source/libdoc/user_keywords.html\nindex 990f5417..27abf9cf 100644\n--- a/docs/source/libdoc/user_keywords.html\n+++ b/docs/source/libdoc/user_keywords.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/user_saucelabs.html b/docs/source/libdoc/user_saucelabs.html\nindex c3356ea6..66b25d38 100644\n--- a/docs/source/libdoc/user_saucelabs.html\n+++ b/docs/source/libdoc/user_saucelabs.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/user_selenium.html b/docs/source/libdoc/user_selenium.html\nindex 3b8b8f11..280a3f0a 100644\n--- a/docs/source/libdoc/user_selenium.html\n+++ b/docs/source/libdoc/user_selenium.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/libdoc/user_server.html b/docs/source/libdoc/user_server.html\nindex 523d80e5..7624256a 100644\n--- a/docs/source/libdoc/user_server.html\n+++ b/docs/source/libdoc/user_server.html\n@@ -1,13 +1,28 @@\n \n \n-\n-\n-\n-\n-\n-\n-\n-\n-\n+ \n-\n+ \n-\n+ \n-\n-\n+ \n-\n+ \n-\n+ \n-\n+ \n-\n-\n-\n+ \n+ \n+ \n+ \n \n-
\n-

Opening library documentation failed

\n-
    \n-
  • Verify that you have JavaScript enabled in your browser.
  • \n-
  • Make sure you are using a modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n-
  • Check are there messages in your browser\'s JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n-
\n-
\n+
\n+

Opening library documentation failed

\n+
    \n+
  • Verify that you have\n+ JavaScript enabled\n+ in your browser.
  • \n+
  • Make sure you are using a\n+ modern enough browser. Firefox 3.5, IE 8, or equivalent is required, newer browsers are recommended.
  • \n+
  • Check are there messages in your browser\'s\n+ JavaScript error log. Please report the problem if you suspect you have encountered a bug.
  • \n+
\n+
\n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n-\n+ \n \n \n-\n+ \n \n-\n+ \n \ndiff --git a/docs/source/remote.rst b/docs/source/remote.rst\nindex 1284b91e..46f9988e 100644\n--- a/docs/source/remote.rst\n+++ b/docs/source/remote.rst\n@@ -6,7 +6,7 @@ test environment for the actual tests-clauses (*When* and *Then*).\n \n Because Given-clauses are not really part of the actual test, it is not\n necessary to run them through Selenium (using Selenium2Library), but it would\n-be faster to write custon Python keywords for them.\n+be faster to write custom Python keywords for them.\n \n **plone.act** includes an example, how to a robot\n `remote library `_,\ndiff --git a/docs/source/robot.rst b/docs/source/robot.rst\nindex 0729d502..4210d2ea 100644\n--- a/docs/source/robot.rst\n+++ b/docs/source/robot.rst\n@@ -49,7 +49,7 @@ Each test suite may contain one to four different parts:\n calling test keywords.\n \n **Keywords**\n- Is used to define new user keywords, which may re-use existing keywords\n+ Is used to define new user keywords, which may reuse existing keywords\n from imported libraries or resource files.\n \n \n@@ -132,14 +132,14 @@ Remote-library approach provides the following benefits when testing Plone:\n Resource files\n --------------\n \n-Resource files provide a re-usable way to abstract your test suites. To put\n+Resource files provide a reusable way to abstract your test suites. To put\n it simply, resources files are just like all the other ``.robot``-files, but\n they should not contain ``*** Test Cases ***`` certain ``*** Settings ***``\n commands (*Suite Setup*, *Suite Teardown*, *Test Setup* or *Test Teardown*).\n \n Resource files are the perfect way to import common libraries (with *Library*\n command in ```*** Settings ***``), define global ``*** Variables ***`` and\n-define re-usable common ```*** Keywords ***```. Resource files are included\n+define reusable common ```*** Keywords ***```. Resource files are included\n in a test suite with *Resource*-command in ```*** Settings ***``:\n \n .. code-block:: robotframework\ndiff --git a/news/434550cc.internal b/news/434550cc.internal\nnew file mode 100644\nindex 00000000..c08f5399\n--- /dev/null\n+++ b/news/434550cc.internal\n@@ -0,0 +1,2 @@\n+Update configuration files.\n+[plone devs]\ndiff --git a/pyproject.toml b/pyproject.toml\nindex 05b615de..4a596000 100644\n--- a/pyproject.toml\n+++ b/pyproject.toml\n@@ -1,6 +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 [tool.towncrier]\n-filename = "CHANGES.rst"\n directory = "news/"\n+filename = "CHANGES.rst"\n title_format = "{version} ({project_date})"\n underlines = ["-", ""]\n \n@@ -18,3 +21,139 @@ showcontent = true\n directory = "bugfix"\n name = "Bug fixes:"\n showcontent = true\n+\n+[[tool.towncrier.type]]\n+directory = "internal"\n+name = "Internal:"\n+showcontent = true\n+\n+[[tool.towncrier.type]]\n+directory = "documentation"\n+name = "Documentation:"\n+showcontent = true\n+\n+[[tool.towncrier.type]]\n+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,ot,nin,"\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 = [\'robotide\', \'collective.js.speakjs\', \'watchdog\', \'robotframework-debuglibrary\', \'robotframework-ride\', \'robotframework-selenium2library\', \'robotframework-seleniumtestability\', \'sphinxcontrib-robotdoc\', \'robotsuite\', \'robotframework-browser\' ]\n+Pillow = [\'PIL\']\n+robotframework = [\'robot\']\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/requirements.txt b/requirements.txt\ndeleted file mode 100644\nindex bba24162..00000000\n--- a/requirements.txt\n+++ /dev/null\n@@ -1,2 +0,0 @@\n-setuptools==33.1.1\n-zc.buildout==2.12.1\ndiff --git a/setup.cfg b/setup.cfg\ndeleted file mode 100644\nindex 4f3a3e25..00000000\n--- a/setup.cfg\n+++ /dev/null\n@@ -1,14 +0,0 @@\n-[check-manifest]\n-ignore =\n- *.cfg\n- requirements.txt\n-\n-[isort]\n-profile = black\n-force_alphabetical_sort = True\n-force_single_line = True\n-lines_after_imports = 2\n-\n-[bdist_wheel]\n-# Py3 only\n-universal = 0\ndiff --git a/setup.py b/setup.py\nindex a78eeb34..c578ea70 100644\n--- a/setup.py\n+++ b/setup.py\n@@ -49,14 +49,20 @@ def read(filename):\n entry_points = dict(console_scripts=console_scripts)\n \n install_requires = [\n- "Products.CMFCore",\n+ "Pillow",\n "Products.CMFPlone",\n- "Products.MailHost",\n "Products.PlonePAS >= 5.0.1",\n "Products.PluggableAuthService",\n "babel",\n+ "docutils",\n "plone.app.testing",\n+ "plone.app.textfield",\n "plone.base",\n+ "plone.dexterity",\n+ "plone.i18n",\n+ "plone.namedfile",\n+ "plone.protect",\n+ "plone.registry",\n "plone.testing",\n "plone.uuid",\n "robotframework",\n@@ -66,19 +72,23 @@ def read(filename):\n "robotsuite", # not a direct dependency, but required for convenience\n "selenium",\n "setuptools",\n+ "z3c.form",\n+ "z3c.relationfield",\n "zope.component",\n- "zope.configuration",\n "zope.i18n",\n+ "zope.intid",\n "zope.schema",\n "zope.testrunner",\n ]\n \n test_requires = [\n- "plone.app.dexterity",\n+ "Products.MailHost",\n "plone.app.textfield",\n "plone.dexterity",\n "robotsuite",\n+ "webtest",\n "z3c.form",\n+ "zope.configuration",\n ]\n \n debug_requires = [\ndiff --git a/src/plone/app/robotframework/content.py b/src/plone/app/robotframework/content.py\nindex 31459b28..75d6cc89 100644\n--- a/src/plone/app/robotframework/content.py\n+++ b/src/plone/app/robotframework/content.py\n@@ -224,7 +224,7 @@ def fire_transition(self, content, action):\n """Fire workflow action for content"""\n disableCSRFProtection()\n # It should be ok to use unrestricted-methods, because workflow\n- # transition guard should proctect unprivileged transition:\n+ # transition guard should protect unprivileged transition:\n pc = getToolByName(self, "portal_catalog")\n results = pc.unrestrictedSearchResults(UID=content)\n obj = results[0]._unrestrictedGetObject()\ndiff --git a/src/plone/app/robotframework/i18n.py b/src/plone/app/robotframework/i18n.py\nindex 2af6f824..73d132a0 100644\n--- a/src/plone/app/robotframework/i18n.py\n+++ b/src/plone/app/robotframework/i18n.py\n@@ -21,7 +21,7 @@ def set_default_language(self, language=None):\n \n def translate(self, msgid, *args, **kwargs):\n """Return localized string for given msgid"""\n- # FIXME: we are alrady using robotframework = 3.0\n+ # FIXME: we are already using robotframework = 3.0\n # XXX: Because kwargs are only supported with robotframework >= 2.8.3,\n # we must parse them here to support robotframework < 2.8.3.\n for arg in [x for x in args if "=" in x]:\ndiff --git a/src/plone/app/robotframework/reload.py b/src/plone/app/robotframework/reload.py\nindex 201aa656..614b8827 100644\n--- a/src/plone/app/robotframework/reload.py\n+++ b/src/plone/app/robotframework/reload.py\n@@ -19,7 +19,6 @@ def ERROR(msg):\n \n \n class Watcher(FileSystemEventHandler):\n-\n allowed_extensions = {"po", "pt", "py", "xml", "csv", "zcml"}\n \n def __init__(self, paths, forkloop, minimum_wait=2.0):\n@@ -74,7 +73,6 @@ def on_any_event(self, event):\n \n class ForkLoop:\n def __init__(self):\n-\n self.fork = True # Must be \'True\' to create new child on start\n self.active = False\n self.pause = False\ndiff --git a/src/plone/app/robotframework/remote.py b/src/plone/app/robotframework/remote.py\nindex 29670010..e210e160 100644\n--- a/src/plone/app/robotframework/remote.py\n+++ b/src/plone/app/robotframework/remote.py\n@@ -51,7 +51,6 @@ def run_keyword(self, name, args, kwargs={}):\n \n \n class RemoteLibraryLayer(Layer):\n-\n defaultBases = (PLONE_FIXTURE,)\n libraryBases = ()\n \ndiff --git a/src/plone/app/robotframework/robotentrypoints.py b/src/plone/app/robotframework/robotentrypoints.py\nindex 71357d5a..8159b327 100644\n--- a/src/plone/app/robotframework/robotentrypoints.py\n+++ b/src/plone/app/robotframework/robotentrypoints.py\n@@ -69,7 +69,7 @@ def ride():\n \n plone.app.robotframework[ride,reload]\n \n-Remember that ride must be lauched with system python with\n+Remember that ride must be launched with system python with\n wxPython installed, like:\n \n /usr/bin/python bin/ride\ndiff --git a/src/plone/app/robotframework/saucelabs.py b/src/plone/app/robotframework/saucelabs.py\nindex 59c92cb3..978327ba 100644\n--- a/src/plone/app/robotframework/saucelabs.py\n+++ b/src/plone/app/robotframework/saucelabs.py\n@@ -13,12 +13,7 @@\n class SauceLabs:\n def report_sauce_status(self, name, status, tags=[], remote_url=""):\n """Report test status and tags to SauceLabs"""\n- job_id = (\n- BuiltIn()\n- .get_library_instance("Selenium2Library")\n- .driver\n- .session_id\n- )\n+ job_id = BuiltIn().get_library_instance("Selenium2Library").driver.session_id\n \n if USERNAME_ACCESS_KEY.match(remote_url):\n username, access_key = USERNAME_ACCESS_KEY.findall(remote_url)[0][1:]\ndiff --git a/src/plone/app/robotframework/server.py b/src/plone/app/robotframework/server.py\nindex 00151862..6f8205e6 100644\n--- a/src/plone/app/robotframework/server.py\n+++ b/src/plone/app/robotframework/server.py\n@@ -47,7 +47,6 @@ def READY(msg):\n \n \n def start(zope_layer_dotted_name):\n-\n print(WAIT("Starting Zope robot server"))\n \n zsl = Zope2Server()\n@@ -98,7 +97,6 @@ def start_reload(\n preload_layer_dotted_name="plone.app.testing.PLONE_FIXTURE",\n extensions=None,\n ):\n-\n print(WAIT("Starting Zope robot server"))\n \n zsl = Zope2Server()\n@@ -231,7 +229,6 @@ def server():\n \n \n class RobotListener:\n-\n ROBOT_LISTENER_API_VERSION = 2\n \n def __init__(self):\n@@ -249,7 +246,6 @@ def end_test(self, name, attrs):\n \n \n class Zope2Server:\n-\n stop_zope_server_lazy = False # trigger lazy Zope2Server shutdown\n stop_zope_server_layer = None # sticky layer for lazy shutdown\n \n@@ -304,7 +300,7 @@ def stop_zope_server(self, force=False):\n if not self.stop_zope_server_lazy or force:\n tear_down()\n else:\n- # With lazy stop, the layer is saved to enable Zope2Server re-use\n+ # With lazy stop, the layer is saved to enable Zope2Server reuse\n # within the same process, until tear_down is called explicitly.\n Zope2Server.stop_zope_server_layer = self.zope_layer\n self.zope_layer = None\n@@ -319,11 +315,7 @@ def zodb_setup(self, layer_dotted_name=None):\n for layer in layers:\n if hasattr(layer, "testSetUp"):\n if HAS_VERBOSE_CONSOLE:\n- print(\n- WAIT(\n- "Test set up {}.{}".format(layer.__module__, layer.__name__)\n- )\n- )\n+ print(WAIT(f"Test set up {layer.__module__}.{layer.__name__}"))\n layer.testSetUp()\n if HAS_VERBOSE_CONSOLE:\n print(READY("Test set up"))\ndiff --git a/src/plone/app/robotframework/testing.py b/src/plone/app/robotframework/testing.py\nindex 70860709..6e3a191b 100644\n--- a/src/plone/app/robotframework/testing.py\n+++ b/src/plone/app/robotframework/testing.py\n@@ -18,8 +18,8 @@\n from plone.app.testing import ploneSite\n from plone.testing import Layer\n from plone.testing import zope as zope_testing\n-from plone.testing.zope import WSGIServer\n from plone.testing.zope import WSGI_SERVER_FIXTURE\n+from plone.testing.zope import WSGIServer\n from Products.MailHost.interfaces import IMailHost\n from robot.libraries.BuiltIn import BuiltIn\n from webtest.http import StopableWSGIServer\n@@ -56,7 +56,6 @@ def tearDown(self):\n \n \n class SimplePublicationWithTypesLayer(Layer):\n-\n defaultBases = (SIMPLE_PUBLICATION_FIXTURE,)\n \n def setUp(self):\n@@ -207,7 +206,6 @@ def _get_robot_variable(self, name):\n return filter(bool, [s.strip() for s in candidates])\n \n def setUpZope(self, app, configurationContext):\n-\n # This installs the VHM in the Zope root, so we can have VHM support too\n AppInitializer(app).install_virtual_hosting()\n \n@@ -294,26 +292,22 @@ def __nonzero__(x):\n \n \n class WSGIServerSingleThreaded(WSGIServer):\n-\n def setUpServer(self):\n- """Create a single threaded WSGI server instance and save it in self.server.\n- """\n+ """Create a single threaded WSGI server instance and save it in self.server."""\n app = self.make_wsgi_app()\n- kwargs = {\'clear_untrusted_proxy_headers\': False,\n- \'threads\': 1}\n+ kwargs = {"clear_untrusted_proxy_headers": False, "threads": 1}\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-\n+ self["host"] = self.host = self.server.effective_host\n+ self["port"] = self.port = int(self.server.effective_port)\n \n \n WSGI_SERVER_SINGLE_THREADED_FIXTURE = WSGIServerSingleThreaded()\n@@ -332,7 +326,6 @@ def setUpServer(self):\n if HAS_SPEAKJS:\n \n class SpeakJSLayer(Layer):\n-\n defaultBases = (PLONE_FIXTURE,)\n \n def setUp(self):\ndiff --git a/src/plone/app/robotframework/tests/test_content.py b/src/plone/app/robotframework/tests/test_content.py\nindex 9052b24d..516878e7 100644\n--- a/src/plone/app/robotframework/tests/test_content.py\n+++ b/src/plone/app/robotframework/tests/test_content.py\n@@ -7,7 +7,6 @@\n \n \n class TestCreateContent(unittest.TestCase):\n-\n layer = PLONE_ROBOT_INTEGRATION_TESTING\n \n def setUp(self):\n@@ -50,7 +49,6 @@ def test_create_content_updates_catalog(self):\n \n \n class TestGlobalAllow(unittest.TestCase):\n-\n layer = PLONE_ROBOT_INTEGRATION_TESTING\n \n def setUp(self):\ndiff --git a/src/plone/app/robotframework/users.py b/src/plone/app/robotframework/users.py\nindex 537e34e6..2611968f 100644\n--- a/src/plone/app/robotframework/users.py\n+++ b/src/plone/app/robotframework/users.py\n@@ -11,7 +11,7 @@ class Users(RemoteLibrary):\n def create_user(self, *args, **kwargs):\n """Create user with given details and return its id"""\n disableCSRFProtection()\n- # FIXME: we are alrady using robotframework = 3.0\n+ # FIXME: we are already using robotframework = 3.0\n # XXX: Because kwargs are only supported with robotframework >= 2.8.3,\n # we must parse them here to support robotframework < 2.8.3.\n for arg in [x for x in args if "=" in x]:\ndiff --git a/tox.ini b/tox.ini\nnew file mode 100644\nindex 00000000..0cb1d9e0\n--- /dev/null\n+++ b/tox.ini\n@@ -0,0 +1,210 @@\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+ lint\n+ test\n+ dependencies\n+\n+\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]\n+skip_install = true\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+ echo "Unrecognized environment name {envname}"\n+ false\n+\n+[testenv:init]\n+description = Prepare environment\n+skip_install = true\n+commands =\n+ echo "Initial setup complete"\n+\n+\n+[testenv:format]\n+description = automatically reformat code\n+skip_install = true\n+deps =\n+ pre-commit\n+commands =\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]\n+description = run linters that will help improve the code style\n+skip_install = true\n+deps =\n+ pre-commit\n+commands =\n+ pre-commit run -a\n+\n+[testenv:dependencies]\n+description = check if the package defines all its dependencies\n+skip_install = true\n+deps =\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+ rfbrowser init\n+ zope-testrunner --all --test-path={toxinidir}/src -s plone.app.robotframework {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+ rfbrowser init\n+ coverage run --branch --source plone.app.robotframework {envbindir}/zope-testrunner --quiet --all --test-path={toxinidir}/src -s plone.app.robotframework {posargs}\n+ coverage report -m --format markdown\n+ coverage xml\n+extras =\n+ test\n+\n+\n+[testenv:release-check]\n+description = ensure that the distribution is ready to release\n+skip_install = true\n+deps =\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+ # 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/.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'