From 5fc2067f98d131b0e4c5e547344873969b4b0921 Mon Sep 17 00:00:00 2001 From: mauritsvanrees Date: Fri, 19 May 2023 23:57:46 +0200 Subject: [PATCH] [fc] Repository: plone.batching Branch: refs/heads/master Date: 2023-05-19T14:37:17+02:00 Author: Maurits van Rees (mauritsvanrees) Commit: https://github.com/plone/plone.batching/commit/fbba68ce484cce2550c620234798501424cddd44 Configuring with plone/meta Files changed: A news/50c0e759.internal M .meta.toml M .pre-commit-config.yaml M tox.ini Repository: plone.batching Branch: refs/heads/master Date: 2023-05-19T23:57:46+02:00 Author: Maurits van Rees (mauritsvanrees) Commit: https://github.com/plone/plone.batching/commit/33ce4a23cb594abd4e2ee1f1fce200675d49e658 Merge pull request #49 from plone/config-with-default-template-e963330c Configuring with plone/meta Files changed: A news/50c0e759.internal M .meta.toml M .pre-commit-config.yaml M tox.ini --- last_commit.txt | 1063 +---------------------------------------------- 1 file changed, 19 insertions(+), 1044 deletions(-) diff --git a/last_commit.txt b/last_commit.txt index 6e034f14ef..388650a893 100644 --- a/last_commit.txt +++ b/last_commit.txt @@ -1,1063 +1,38 @@ -Repository: Products.CMFPlone +Repository: plone.batching -Branch: refs/heads/6.0.x -Date: 2023-05-17T00:24:54+02:00 -Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/Products.CMFPlone/commit/202aaf8f62406c910c26e083b5bda3e480291573 - -Configuring with plone/meta - -Files changed: -A .editorconfig -A .meta.toml -A .pre-commit-config.yaml -A news/2a5f5557.internal -A tox.ini -M pyproject.toml -M setup.cfg - -b'diff --git a/.editorconfig b/.editorconfig\nnew file mode 100644\nindex 0000000000..b4158b89d9\n--- /dev/null\n+++ b/.editorconfig\n@@ -0,0 +1,39 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\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+[{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\ndiff --git a/.meta.toml b/.meta.toml\nnew file mode 100644\nindex 0000000000..c2597cca6f\n--- /dev/null\n+++ b/.meta.toml\n@@ -0,0 +1,5 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+[meta]\n+template = "default"\n+commit-id = "2a5f5557"\ndiff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml\nnew file mode 100644\nindex 0000000000..f9cdf5cd12\n--- /dev/null\n+++ b/.pre-commit-config.yaml\n@@ -0,0 +1,42 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+ci:\n+ autofix_prs: false\n+ autoupdate_schedule: monthly\n+\n+repos:\n+- repo: https://github.com/asottile/pyupgrade\n+ rev: v3.3.2\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.3.0\n+ hooks:\n+ - id: black\n+- repo: https://github.com/collective/zpretty\n+ rev: 3.0.4\n+ hooks:\n+ - id: zpretty\n+- repo: https://github.com/PyCQA/flake8\n+ rev: 6.0.0\n+ hooks:\n+ - id: flake8\n+- repo: https://github.com/codespell-project/codespell\n+ rev: v2.2.4\n+ hooks:\n+ - id: codespell\n+ additional_dependencies:\n+ - tomli\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\ndiff --git a/news/2a5f5557.internal b/news/2a5f5557.internal\nnew file mode 100644\nindex 0000000000..c08f539916\n--- /dev/null\n+++ b/news/2a5f5557.internal\n@@ -0,0 +1,2 @@\n+Update configuration files.\n+[plone devs]\ndiff --git a/pyproject.toml b/pyproject.toml\nindex 10d43bb1bd..0c874a1b22 100644\n--- a/pyproject.toml\n+++ b/pyproject.toml\n@@ -1,3 +1,5 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n [tool.towncrier]\n filename = "CHANGES.md"\n directory = "news/"\n@@ -20,3 +22,65 @@ 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+[tool.isort]\n+profile = "plone"\n+\n+[tool.black]\n+target-version = ["py38"]\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\']\ndiff --git a/setup.cfg b/setup.cfg\nindex a9ab3befbf..4a29c7d490 100644\n--- a/setup.cfg\n+++ b/setup.cfg\n@@ -1,11 +1,26 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n [zest.releaser]\n extra-message = [ci skip]\n \n [bdist_wheel]\n universal = 0\n \n-[isort]\n-profile = black\n-force_alphabetical_sort=True\n-force_single_line=True\n-lines_after_imports=2\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+[check-manifest]\n+ignore =\n+ .editorconfig\n+ .meta.toml\n+ .pre-commit-config.yaml\n+ tox.ini\ndiff --git a/tox.ini b/tox.ini\nnew file mode 100644\nindex 0000000000..20bdc5ed4b\n--- /dev/null\n+++ b/tox.ini\n@@ -0,0 +1,76 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+[tox]\n+# We need 4.4.0 for constrain_package_deps.\n+min_version = 4.4.0\n+envlist =\n+ format\n+ lint\n+ test\n+\n+[testenv]\n+allowlist_externals =\n+ sh\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 package\'s dependencies\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+use_develop = true\n+constrain_package_deps = true\n+set_env = ROBOT_BROWSER=headlesschrome\n+deps =\n+ zope.testrunner\n+ -c https://dist.plone.org/release/6.0-dev/constraints.txt\n+commands =\n+ zope-testrunner --all --test-path={toxinidir} -s Products.CMFPlone {posargs}\n+extras =\n+ test\n+\n+[testenv:coverage]\n+use_develop = true\n+constrain_package_deps = true\n+set_env = ROBOT_BROWSER=headlesschrome\n+deps =\n+ coverage\n+ zope.testrunner\n+ -c https://dist.plone.org/release/6.0-dev/constraints.txt\n+commands =\n+ coverage run {envbindir}/zope-testrunner --quiet --all --test-path={toxinidir} -s Products.CMFPlone {posargs}\n+ coverage report -m --format markdown\n+extras =\n+ test\n' - -Repository: Products.CMFPlone - - -Branch: refs/heads/6.0.x -Date: 2023-05-17T00:25:46+02:00 -Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/Products.CMFPlone/commit/6c0f4e194bf1ad221b44f5be196350870d34bcae - -chore: pyupgrade - -Files changed: -M Products/CMFPlone/tests/test_redirect_after_login.py - -b'diff --git a/Products/CMFPlone/tests/test_redirect_after_login.py b/Products/CMFPlone/tests/test_redirect_after_login.py\nindex 4eb69b4a35..a5c8db9cac 100644\n--- a/Products/CMFPlone/tests/test_redirect_after_login.py\n+++ b/Products/CMFPlone/tests/test_redirect_after_login.py\n@@ -206,7 +206,7 @@ def test_password_reset_uses_all_adapters(self):\n # We need to configure the mailhost first.\n registry = getUtility(IRegistry, context=self.portal)\n mail_settings = registry.forInterface(IMailSchema, prefix="plone")\n- mail_settings.smtp_host = u\'localhost\'\n+ mail_settings.smtp_host = \'localhost\'\n mail_settings.email_from_address = \'smith@example.com\'\n # and an email address for the test user:\n member = self.portal.portal_membership.getMemberById(TEST_USER_ID)\n@@ -230,7 +230,7 @@ def test_password_reset_uses_all_adapters(self):\n self.assertIn(please_visit_text, msg)\n url_index = msg.index(please_visit_text) + len(please_visit_text)\n address = msg[url_index:].strip().split()[0].decode()\n- self.assertTrue(address.startswith(u\'http://nohost/plone/passwordreset/\'))\n+ self.assertTrue(address.startswith(\'http://nohost/plone/passwordreset/\'))\n \n # Now that we have the address, we will reset our password:\n \n' - -Repository: Products.CMFPlone - - -Branch: refs/heads/6.0.x -Date: 2023-05-17T00:26:07+02:00 -Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/Products.CMFPlone/commit/b4ca0a7dd5991bea8b012951410776230e5379a1 - -chore: isort - -Files changed: -M Products/CMFPlone/RegistrationTool.py -M Products/CMFPlone/browser/contact_info.py -M Products/CMFPlone/browser/login/login_help.py -M Products/CMFPlone/browser/search.py - -b'diff --git a/Products/CMFPlone/RegistrationTool.py b/Products/CMFPlone/RegistrationTool.py\nindex b79cfc1ea4..1e2fc043c8 100644\n--- a/Products/CMFPlone/RegistrationTool.py\n+++ b/Products/CMFPlone/RegistrationTool.py\n@@ -33,6 +33,7 @@\n import random\n import re\n \n+\n try:\n # Products.MailHost has a patch to fix quoted-printable soft line breaks.\n # See https://github.com/zopefoundation/Products.MailHost/issues/35\ndiff --git a/Products/CMFPlone/browser/contact_info.py b/Products/CMFPlone/browser/contact_info.py\nindex c1cec8398c..dd38f91da0 100644\n--- a/Products/CMFPlone/browser/contact_info.py\n+++ b/Products/CMFPlone/browser/contact_info.py\n@@ -15,6 +15,7 @@\n import logging\n import warnings\n \n+\n try:\n # Products.MailHost has a patch to fix quoted-printable soft line breaks.\n # See https://github.com/zopefoundation/Products.MailHost/issues/35\ndiff --git a/Products/CMFPlone/browser/login/login_help.py b/Products/CMFPlone/browser/login/login_help.py\nindex c151141547..06f4170872 100644\n--- a/Products/CMFPlone/browser/login/login_help.py\n+++ b/Products/CMFPlone/browser/login/login_help.py\n@@ -21,6 +21,7 @@\n \n import logging\n \n+\n try:\n # Products.MailHost has a patch to fix quoted-printable soft line breaks.\n # See https://github.com/zopefoundation/Products.MailHost/issues/35\ndiff --git a/Products/CMFPlone/browser/search.py b/Products/CMFPlone/browser/search.py\nindex 902d052720..fa74d78782 100644\n--- a/Products/CMFPlone/browser/search.py\n+++ b/Products/CMFPlone/browser/search.py\n@@ -2,8 +2,8 @@\n from plone.app.contentlisting.interfaces import IContentListing\n from plone.app.layout.navigation.interfaces import INavigationRoot\n from plone.base.batch import Batch\n-from plone.base.interfaces.siteroot import IPloneSiteRoot\n from plone.base.interfaces import ISearchSchema\n+from plone.base.interfaces.siteroot import IPloneSiteRoot\n from plone.registry.interfaces import IRegistry\n from Products.CMFCore.utils import getToolByName\n from Products.CMFPlone.browser.navtree import getNavigationRoot\n' - -Repository: Products.CMFPlone - - -Branch: refs/heads/6.0.x -Date: 2023-05-17T00:27:37+02:00 -Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/Products.CMFPlone/commit/bad7ee61597c72f165f5db979ee04efd06066d22 - -chore: black - -Files changed: -M Products/CMFPlone/ActionsTool.py -M Products/CMFPlone/CatalogTool.py -M Products/CMFPlone/MigrationTool.py -M Products/CMFPlone/PasswordResetTool.py -M Products/CMFPlone/PloneBatch.py -M Products/CMFPlone/PloneControlPanel.py -M Products/CMFPlone/PloneTool.py -M Products/CMFPlone/Portal.py -M Products/CMFPlone/PropertiesTool.py -M Products/CMFPlone/RegistrationTool.py -M Products/CMFPlone/SkinsTool.py -M Products/CMFPlone/TranslationServiceTool.py -M Products/CMFPlone/TypesTool.py -M Products/CMFPlone/URLTool.py -M Products/CMFPlone/UnicodeSplitter/config.py -M Products/CMFPlone/UnicodeSplitter/splitter.py -M Products/CMFPlone/WorkflowTool.py -M Products/CMFPlone/__init__.py -M Products/CMFPlone/bbb.py -M Products/CMFPlone/browser/admin.py -M Products/CMFPlone/browser/atd.py -M Products/CMFPlone/browser/author.py -M Products/CMFPlone/browser/contact_info.py -M Products/CMFPlone/browser/defaultpage.py -M Products/CMFPlone/browser/exceptions.py -M Products/CMFPlone/browser/global_statusmessage.py -M Products/CMFPlone/browser/icons.py -M Products/CMFPlone/browser/interfaces.py -M Products/CMFPlone/browser/login/login.py -M Products/CMFPlone/browser/login/login_help.py -M Products/CMFPlone/browser/login/logout.py -M Products/CMFPlone/browser/login/mail_password.py -M Products/CMFPlone/browser/login/password_reset.py -M Products/CMFPlone/browser/login/utils.py -M Products/CMFPlone/browser/main_template.py -M Products/CMFPlone/browser/navtree.py -M Products/CMFPlone/browser/okay.py -M Products/CMFPlone/browser/ploneview.py -M Products/CMFPlone/browser/robots.py -M Products/CMFPlone/browser/search.py -M Products/CMFPlone/browser/sendto.py -M Products/CMFPlone/browser/sitelogo.py -M Products/CMFPlone/browser/sitemap.py -M Products/CMFPlone/browser/syndication/adapters.py -M Products/CMFPlone/browser/syndication/settings.py -M Products/CMFPlone/browser/syndication/tool.py -M Products/CMFPlone/browser/syndication/utils.py -M Products/CMFPlone/browser/syndication/views.py -M Products/CMFPlone/browser/test_rendering.py -M Products/CMFPlone/controlpanel/bbb/editing.py -M Products/CMFPlone/controlpanel/bbb/filter.py -M Products/CMFPlone/controlpanel/bbb/language.py -M Products/CMFPlone/controlpanel/bbb/mail.py -M Products/CMFPlone/controlpanel/bbb/maintenance.py -M Products/CMFPlone/controlpanel/bbb/markup.py -M Products/CMFPlone/controlpanel/bbb/navigation.py -M Products/CMFPlone/controlpanel/bbb/search.py -M Products/CMFPlone/controlpanel/bbb/security.py -M Products/CMFPlone/controlpanel/bbb/site.py -M Products/CMFPlone/controlpanel/bbb/usergroups.py -M Products/CMFPlone/controlpanel/browser/actions.py -M Products/CMFPlone/controlpanel/browser/dateandtime.py -M Products/CMFPlone/controlpanel/browser/editing.py -M Products/CMFPlone/controlpanel/browser/error_log_form.py -M Products/CMFPlone/controlpanel/browser/filter.py -M Products/CMFPlone/controlpanel/browser/imaging.py -M Products/CMFPlone/controlpanel/browser/language.py -M Products/CMFPlone/controlpanel/browser/mail.py -M Products/CMFPlone/controlpanel/browser/maintenance.py -M Products/CMFPlone/controlpanel/browser/markup.py -M Products/CMFPlone/controlpanel/browser/navigation.py -M Products/CMFPlone/controlpanel/browser/overview.py -M Products/CMFPlone/controlpanel/browser/prefsmaintemplate.py -M Products/CMFPlone/controlpanel/browser/quickinstaller.py -M Products/CMFPlone/controlpanel/browser/redirects.py -M Products/CMFPlone/controlpanel/browser/relations.py -M Products/CMFPlone/controlpanel/browser/resourceregistry.py -M Products/CMFPlone/controlpanel/browser/search.py -M Products/CMFPlone/controlpanel/browser/security.py -M Products/CMFPlone/controlpanel/browser/site.py -M Products/CMFPlone/controlpanel/browser/socialmedia.py -M Products/CMFPlone/controlpanel/browser/syndication.py -M Products/CMFPlone/controlpanel/browser/tinymce.py -M Products/CMFPlone/controlpanel/browser/types.py -M Products/CMFPlone/controlpanel/browser/usergroups.py -M Products/CMFPlone/controlpanel/browser/usergroups_groupdetails.py -M Products/CMFPlone/controlpanel/browser/usergroups_groupmembership.py -M Products/CMFPlone/controlpanel/browser/usergroups_groupsoverview.py -M Products/CMFPlone/controlpanel/browser/usergroups_usermembership.py -M Products/CMFPlone/controlpanel/browser/usergroups_usersoverview.py -M Products/CMFPlone/controlpanel/events.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_actions.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_editing_adapter.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_filter_adapter.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_language_adapter.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_mail_adapter.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_maintenance_adapter.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_markup_adapter.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_navigation_adapter.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_search_adapter.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_security_adapter.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_site_adapter.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_usergroups_adapter.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_editing.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_error_log.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_filter.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_installer.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_language.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_mail.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_maintenance.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_markup.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_navigation.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_redirection.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_search.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_security.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_site.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_syndication.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_types.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_usergroups.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_usergroups_siteadmin_role.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_dateandtime.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_doctest.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_editing.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_events.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_filter.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_installer.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_language.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_mail.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_markup.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_navigation.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_overview.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_relations.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_search.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_security.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_site.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_types.py -M Products/CMFPlone/controlpanel/tests/test_controlpanel_usergroups.py -M Products/CMFPlone/controlpanel/tests/test_doctests.py -M Products/CMFPlone/controlpanel/utils.py -M Products/CMFPlone/controlpanel/widgets.py -M Products/CMFPlone/defaultpage.py -M Products/CMFPlone/earlypatches/security.py -M Products/CMFPlone/events.py -M Products/CMFPlone/exportimport/controlpanel.py -M Products/CMFPlone/exportimport/memberdata_properties.py -M Products/CMFPlone/exportimport/propertiestool.py -M Products/CMFPlone/exportimport/tests/base.py -M Products/CMFPlone/exportimport/tests/testControlPanel.py -M Products/CMFPlone/exportimport/tests/testPropertiesTool.py -M Products/CMFPlone/factory.py -M Products/CMFPlone/i18nl10n.py -M Products/CMFPlone/interfaces/atd.py -M Products/CMFPlone/interfaces/basetool.py -M Products/CMFPlone/interfaces/breadcrumbs.py -M Products/CMFPlone/interfaces/constrains.py -M Products/CMFPlone/interfaces/controlpanel.py -M Products/CMFPlone/interfaces/defaultpage.py -M Products/CMFPlone/interfaces/events.py -M Products/CMFPlone/interfaces/installable.py -M Products/CMFPlone/interfaces/interface.py -M Products/CMFPlone/interfaces/language.py -M Products/CMFPlone/interfaces/login.py -M Products/CMFPlone/interfaces/migration.py -M Products/CMFPlone/interfaces/password_reset.py -M Products/CMFPlone/interfaces/patterns.py -M Products/CMFPlone/interfaces/properties.py -M Products/CMFPlone/interfaces/resources.py -M Products/CMFPlone/interfaces/siteroot.py -M Products/CMFPlone/interfaces/structure.py -M Products/CMFPlone/interfaces/syndication.py -M Products/CMFPlone/interfaces/translationservice.py -M Products/CMFPlone/interfaces/workflow.py -M Products/CMFPlone/log.py -M Products/CMFPlone/patches/__init__.py -M Products/CMFPlone/patches/addzmiplonesite.py -M Products/CMFPlone/patches/addzmisecuritywarning.py -M Products/CMFPlone/patches/csrf.py -M Products/CMFPlone/patches/dateIndexPatch.py -M Products/CMFPlone/patches/gtbn.py -M Products/CMFPlone/patches/iso8601.py -M Products/CMFPlone/patches/publishing.py -M Products/CMFPlone/patches/sendmail.py -M Products/CMFPlone/patches/speed.py -M Products/CMFPlone/patches/templatecookcheck.py -M Products/CMFPlone/patches/unicodehacks.py -M Products/CMFPlone/patches/z3c_form.py -M Products/CMFPlone/permissions.py -M Products/CMFPlone/relationhelper.py -M Products/CMFPlone/resources/browser/resource.py -M Products/CMFPlone/setuphandlers.py -M Products/CMFPlone/skins/plone_scripts/externalEditorEnabled.py -M Products/CMFPlone/skins/plone_scripts/external_edit.py -M Products/CMFPlone/skins/plone_scripts/getFolderContents.py -M Products/CMFPlone/skins/plone_scripts/pretty_title_or_id.py -M Products/CMFPlone/skins/plone_scripts/queryCatalog.py -M Products/CMFPlone/skins/plone_scripts/toLocalizedTime.py -M Products/CMFPlone/skins/plone_scripts/translate.py -M Products/CMFPlone/skins/plone_scripts/utranslate.py -M Products/CMFPlone/testing.py -M Products/CMFPlone/tests/PloneTestCase.py -M Products/CMFPlone/tests/dummy.py -M Products/CMFPlone/tests/robot/robot_setup.py -M Products/CMFPlone/tests/testActionsTool.py -M Products/CMFPlone/tests/testBatch.py -M Products/CMFPlone/tests/testBrowserAdmin.py -M Products/CMFPlone/tests/testBrowserDefault.py -M Products/CMFPlone/tests/testBrowserLayerPrecedence.py -M Products/CMFPlone/tests/testCSRFProtection.py -M Products/CMFPlone/tests/testCatalogTool.py -M Products/CMFPlone/tests/testCheckId.py -M Products/CMFPlone/tests/testContentSecurity.py -M Products/CMFPlone/tests/testControlPanel.py -M Products/CMFPlone/tests/testControlPanelScripts.py -M Products/CMFPlone/tests/testCookieAuth.py -M Products/CMFPlone/tests/testCutPasteSecurity.py -M Products/CMFPlone/tests/testDateIndexRanges.py -M Products/CMFPlone/tests/testDateTimeIntegration.py -M Products/CMFPlone/tests/testEmailLogin.py -M Products/CMFPlone/tests/testExternalEditorEnabled.py -M Products/CMFPlone/tests/testIImagingSchema.py -M Products/CMFPlone/tests/testInterfaces.py -M Products/CMFPlone/tests/testMigrationTool.py -M Products/CMFPlone/tests/testNavTree.py -M Products/CMFPlone/tests/testNavigationView.py -M Products/CMFPlone/tests/testNextPrevious.py -M Products/CMFPlone/tests/testOrderSupport.py -M Products/CMFPlone/tests/testPloneTestCase.py -M Products/CMFPlone/tests/testPloneView.py -M Products/CMFPlone/tests/testPortalCreation.py -M Products/CMFPlone/tests/testQueryCatalog.py -M Products/CMFPlone/tests/testRegistrationTool.py -M Products/CMFPlone/tests/testResourceRegistries.py -M Products/CMFPlone/tests/testRestrictedAcquisition.py -M Products/CMFPlone/tests/testSearch.py -M Products/CMFPlone/tests/testSecurity.py -M Products/CMFPlone/tests/testSecurityDeclarations.py -M Products/CMFPlone/tests/testSiteAdminRole.py -M Products/CMFPlone/tests/testSyndication.py -M Products/CMFPlone/tests/testTranslationServiceTool.py -M Products/CMFPlone/tests/testURLTool.py -M Products/CMFPlone/tests/testUnicodeSplitter.py -M Products/CMFPlone/tests/testUserFolderBasics.py -M Products/CMFPlone/tests/testWebDAV.py -M Products/CMFPlone/tests/testWorkflowTool.py -M Products/CMFPlone/tests/test_PloneTool.py -M Products/CMFPlone/tests/test_defaultpage.py -M Products/CMFPlone/tests/test_doctests.py -M Products/CMFPlone/tests/test_error_message.py -M Products/CMFPlone/tests/test_expressions.py -M Products/CMFPlone/tests/test_factory.py -M Products/CMFPlone/tests/test_functional.py -M Products/CMFPlone/tests/test_icons.py -M Products/CMFPlone/tests/test_login_form.py -M Products/CMFPlone/tests/test_login_help.py -M Products/CMFPlone/tests/test_login_logout.py -M Products/CMFPlone/tests/test_login_views.py -M Products/CMFPlone/tests/test_mails.py -M Products/CMFPlone/tests/test_nogopip.py -M Products/CMFPlone/tests/test_okay.py -M Products/CMFPlone/tests/test_passwordreset.py -M Products/CMFPlone/tests/test_patternsettings.py -M Products/CMFPlone/tests/test_redirect_after_login.py -M Products/CMFPlone/tests/test_robot.py -M Products/CMFPlone/tests/test_robots_txt.py -M Products/CMFPlone/tests/test_safe_formatter.py -M Products/CMFPlone/tests/test_sitelogo.py -M Products/CMFPlone/tests/test_sitemap.py -M Products/CMFPlone/tests/test_utils.py -M Products/CMFPlone/tests/test_z3c_form_widgets.py -M Products/CMFPlone/tests/test_zmi.py -M Products/CMFPlone/tests/utils.py -M Products/CMFPlone/unicodeconflictresolver.py -M Products/CMFPlone/utils.py -M Products/CMFPlone/workflow.py -M Products/__init__.py -M setup.py - -b'diff --git a/Products/CMFPlone/ActionsTool.py b/Products/CMFPlone/ActionsTool.py\nindex 5ae39fb5f0..e0c01f8d8d 100644\n--- a/Products/CMFPlone/ActionsTool.py\n+++ b/Products/CMFPlone/ActionsTool.py\n@@ -8,7 +8,6 @@\n \n \n class ActionsTool(PloneBaseTool, BaseTool):\n-\n meta_type = "Plone Actions Tool"\n toolicon = "skins/plone_images/confirm_icon.png"\n \ndiff --git a/Products/CMFPlone/CatalogTool.py b/Products/CMFPlone/CatalogTool.py\nindex c83320dc07..0e07a2fb72 100644\n--- a/Products/CMFPlone/CatalogTool.py\n+++ b/Products/CMFPlone/CatalogTool.py\n@@ -1,7 +1,9 @@\n from AccessControl import ClassSecurityInfo\n from AccessControl.class_init import InitializeClass\n from AccessControl.PermissionRole import rolesForPermissionOn\n-from AccessControl.Permissions import manage_zcatalog_entries as ManageZCatalogEntries # noqa\n+from AccessControl.Permissions import (\n+ manage_zcatalog_entries as ManageZCatalogEntries,\n+) # noqa\n from AccessControl.Permissions import search_zcatalog as SearchZCatalog\n from Acquisition import aq_base\n from Acquisition import aq_inner\n@@ -45,70 +47,72 @@\n import urllib\n \n \n-logger = logging.getLogger(\'Plone\')\n+logger = logging.getLogger("Plone")\n \n _marker = object()\n \n-DENIED_INTERFACES = frozenset((\n- \'AccessControl.interfaces.IOwned\',\n- \'AccessControl.interfaces.IPermissionMappingSupport\',\n- \'AccessControl.interfaces.IRoleManager\',\n- \'Acquisition.interfaces.IAcquirer\',\n- \'App.interfaces.INavigation\',\n- \'App.interfaces.IPersistentExtra\',\n- \'App.interfaces.IUndoSupport\',\n- \'OFS.interfaces.ICopyContainer\',\n- \'OFS.interfaces.ICopySource\',\n- \'OFS.interfaces.IFindSupport\',\n- \'OFS.interfaces.IFolder\',\n- \'OFS.interfaces.IFTPAccess\',\n- \'OFS.interfaces.IItem\',\n- \'OFS.interfaces.IManageable\',\n- \'OFS.interfaces.IObjectManager\',\n- \'OFS.interfaces.IOrderedContainer\',\n- \'OFS.interfaces.IPropertyManager\',\n- \'OFS.interfaces.ISimpleItem\',\n- \'OFS.interfaces.ITraversable\',\n- \'OFS.interfaces.IZopeObject\',\n- \'persistent.interfaces.IPersistent\',\n- \'plone.app.iterate.interfaces.IIterateAware\',\n- \'plone.contentrules.engine.interfaces.IRuleAssignable\',\n- \'plone.folder.interfaces.IFolder\',\n- \'plone.folder.interfaces.IOrderableFolder\',\n- \'plone.locking.interfaces.ITTWLockable\',\n- \'plone.portlets.interfaces.ILocalPortletAssignable\',\n- \'plone.uuid.interfaces.IUUIDAware\',\n- \'Products.CMFCore.interfaces._content.ICatalogableDublinCore\',\n- \'Products.CMFCore.interfaces._content.ICatalogAware\',\n- \'Products.CMFCore.interfaces._content.IDublinCore\',\n- \'Products.CMFCore.interfaces._content.IDynamicType\',\n- \'Products.CMFCore.interfaces._content.IFolderish\',\n- \'Products.CMFCore.interfaces._content.IMinimalDublinCore\',\n- \'Products.CMFCore.interfaces._content.IMutableDublinCore\',\n- \'Products.CMFCore.interfaces._content.IMutableMinimalDublinCore\',\n- \'Products.CMFCore.interfaces._content.IOpaqueItemManager\',\n- \'Products.CMFCore.interfaces._content.IWorkflowAware\',\n- \'Products.CMFDynamicViewFTI.interfaces.IBrowserDefault\',\n- \'Products.CMFDynamicViewFTI.interfaces.ISelectableBrowserDefault\',\n- \'plone.base.interfaces.constrains.IConstrainTypes\',\n- \'plone.base.interfaces.constrains.ISelectableConstrainTypes\',\n- \'Products.GenericSetup.interfaces.IDAVAware\',\n- \'webdav.EtagSupport.EtagBaseInterface\',\n- \'webdav.interfaces.IDAVCollection\',\n- \'webdav.interfaces.IDAVResource\',\n- \'zope.annotation.interfaces.IAnnotatable\',\n- \'zope.annotation.interfaces.IAttributeAnnotatable\',\n- \'zope.component.interfaces.IPossibleSite\',\n- \'zope.container.interfaces.IContainer\',\n- \'zope.container.interfaces.IItemContainer\',\n- \'zope.container.interfaces.IReadContainer\',\n- \'zope.container.interfaces.ISimpleReadContainer\',\n- \'zope.container.interfaces.IWriteContainer\',\n- \'zope.interface.common.mapping.IEnumerableMapping\',\n- \'zope.interface.common.mapping.IItemMapping\',\n- \'zope.interface.common.mapping.IReadMapping\',\n- \'zope.interface.Interface\',\n-))\n+DENIED_INTERFACES = frozenset(\n+ (\n+ "AccessControl.interfaces.IOwned",\n+ "AccessControl.interfaces.IPermissionMappingSupport",\n+ "AccessControl.interfaces.IRoleManager",\n+ "Acquisition.interfaces.IAcquirer",\n+ "App.interfaces.INavigation",\n+ "App.interfaces.IPersistentExtra",\n+ "App.interfaces.IUndoSupport",\n+ "OFS.interfaces.ICopyContainer",\n+ "OFS.interfaces.ICopySource",\n+ "OFS.interfaces.IFindSupport",\n+ "OFS.interfaces.IFolder",\n+ "OFS.interfaces.IFTPAccess",\n+ "OFS.interfaces.IItem",\n+ "OFS.interfaces.IManageable",\n+ "OFS.interfaces.IObjectManager",\n+ "OFS.interfaces.IOrderedContainer",\n+ "OFS.interfaces.IPropertyManager",\n+ "OFS.interfaces.ISimpleItem",\n+ "OFS.interfaces.ITraversable",\n+ "OFS.interfaces.IZopeObject",\n+ "persistent.interfaces.IPersistent",\n+ "plone.app.iterate.interfaces.IIterateAware",\n+ "plone.contentrules.engine.interfaces.IRuleAssignable",\n+ "plone.folder.interfaces.IFolder",\n+ "plone.folder.interfaces.IOrderableFolder",\n+ "plone.locking.interfaces.ITTWLockable",\n+ "plone.portlets.interfaces.ILocalPortletAssignable",\n+ "plone.uuid.interfaces.IUUIDAware",\n+ "Products.CMFCore.interfaces._content.ICatalogableDublinCore",\n+ "Products.CMFCore.interfaces._content.ICatalogAware",\n+ "Products.CMFCore.interfaces._content.IDublinCore",\n+ "Products.CMFCore.interfaces._content.IDynamicType",\n+ "Products.CMFCore.interfaces._content.IFolderish",\n+ "Products.CMFCore.interfaces._content.IMinimalDublinCore",\n+ "Products.CMFCore.interfaces._content.IMutableDublinCore",\n+ "Products.CMFCore.interfaces._content.IMutableMinimalDublinCore",\n+ "Products.CMFCore.interfaces._content.IOpaqueItemManager",\n+ "Products.CMFCore.interfaces._content.IWorkflowAware",\n+ "Products.CMFDynamicViewFTI.interfaces.IBrowserDefault",\n+ "Products.CMFDynamicViewFTI.interfaces.ISelectableBrowserDefault",\n+ "plone.base.interfaces.constrains.IConstrainTypes",\n+ "plone.base.interfaces.constrains.ISelectableConstrainTypes",\n+ "Products.GenericSetup.interfaces.IDAVAware",\n+ "webdav.EtagSupport.EtagBaseInterface",\n+ "webdav.interfaces.IDAVCollection",\n+ "webdav.interfaces.IDAVResource",\n+ "zope.annotation.interfaces.IAnnotatable",\n+ "zope.annotation.interfaces.IAttributeAnnotatable",\n+ "zope.component.interfaces.IPossibleSite",\n+ "zope.container.interfaces.IContainer",\n+ "zope.container.interfaces.IItemContainer",\n+ "zope.container.interfaces.IReadContainer",\n+ "zope.container.interfaces.ISimpleReadContainer",\n+ "zope.container.interfaces.IWriteContainer",\n+ "zope.interface.common.mapping.IEnumerableMapping",\n+ "zope.interface.common.mapping.IItemMapping",\n+ "zope.interface.common.mapping.IReadMapping",\n+ "zope.interface.Interface",\n+ )\n+)\n \n # bbb, remove in Plone 7\n BLACKLISTED_INTERFACES = DENIED_INTERFACES\n@@ -123,48 +127,49 @@ def allowedRolesAndUsers(obj):\n # \'Access contents information\' is the correct permission for\n # accessing and displaying metadata of an item.\n # \'View\' should be reserved for accessing the item itself.\n- allowed = set(rolesForPermissionOn(\'Access contents information\', obj))\n+ allowed = set(rolesForPermissionOn("Access contents information", obj))\n \n # shortcut roles and only index the most basic system role if the object\n # is viewable by either of those\n- if \'Anonymous\' in allowed:\n- return [\'Anonymous\']\n- elif \'Authenticated\' in allowed:\n- return [\'Authenticated\']\n+ if "Anonymous" in allowed:\n+ return ["Anonymous"]\n+ elif "Authenticated" in allowed:\n+ return ["Authenticated"]\n localroles = {}\n try:\n- acl_users = getToolByName(obj, \'acl_users\', None)\n+ acl_users = getToolByName(obj, "acl_users", None)\n if acl_users is not None:\n localroles = acl_users._getAllLocalRoles(obj)\n except AttributeError:\n localroles = _mergedLocalRoles(obj)\n for user, roles in localroles.items():\n if allowed.intersection(roles):\n- allowed.update([\'user:\' + user])\n- if \'Owner\' in allowed:\n- allowed.remove(\'Owner\')\n+ allowed.update(["user:" + user])\n+ if "Owner" in allowed:\n+ allowed.remove("Owner")\n return list(allowed)\n \n \n @indexer(Interface)\n def object_provides(obj):\n return tuple(\n- i.__identifier__ for i in providedBy(obj).flattened()\n- if i.__identifier__ not in DENIED_INTERFACES\n+ i.__identifier__\n+ for i in providedBy(obj).flattened()\n+ if i.__identifier__ not in DENIED_INTERFACES\n )\n \n \n def zero_fill(matchobj):\n return matchobj.group().zfill(4)\n \n-num_sort_regex = re.compile(r\'\\d+\')\n+\n+num_sort_regex = re.compile(r"\\d+")\n \n \n @indexer(Interface)\n def sortable_title(obj):\n- """ Helper method for to provide FieldIndex for Title.\n- """\n- title = getattr(obj, \'Title\', None)\n+ """Helper method for to provide FieldIndex for Title."""\n+ title = getattr(obj, "Title", None)\n if title is not None:\n if safe_callable(title):\n title = title()\n@@ -175,13 +180,12 @@ def sortable_title(obj):\n # Replace numbers with zero filled numbers\n sortabletitle = num_sort_regex.sub(zero_fill, sortabletitle)\n return sortabletitle\n- return \'\'\n+ return ""\n \n \n @indexer(Interface)\n def getObjPositionInParent(obj):\n- """ Helper method for catalog based folder contents.\n- """\n+ """Helper method for catalog based folder contents."""\n parent = aq_parent(aq_inner(obj))\n ordered = IOrderedContainer(parent, None)\n if ordered is not None:\n@@ -191,9 +195,8 @@ def getObjPositionInParent(obj):\n \n @indexer(Interface)\n def getObjSize(obj):\n- """ Helper method for catalog based folder contents.\n- """\n- if base_hasattr(obj, \'get_size\'):\n+ """Helper method for catalog based folder contents."""\n+ if base_hasattr(obj, "get_size"):\n size = obj.get_size()\n else:\n size = 0\n@@ -210,15 +213,14 @@ def is_folderish(obj):\n """\n # If the object explicitly states it doesn\'t want to be treated as a\n # structural folder, don\'t argue with it.\n- folderish = bool(getattr(aq_base(obj), \'isPrincipiaFolderish\', False))\n+ folderish = bool(getattr(aq_base(obj), "isPrincipiaFolderish", False))\n return folderish and not INonStructuralFolder.providedBy(obj)\n \n \n @indexer(Interface)\n def is_default_page(obj):\n- """Is this the default page in its folder\n- """\n- ptool = getToolByName(obj, \'plone_utils\', None)\n+ """Is this the default page in its folder"""\n+ ptool = getToolByName(obj, "plone_utils", None)\n if ptool is None:\n return False\n return ptool.isDefaultPage(obj)\n@@ -235,7 +237,7 @@ def getIcon(obj):\n when obj is an image or has a lead image\n or has an image field with name \'image\': true else false\n """\n- return bool(getattr(obj.aq_base, \'image\', False))\n+ return bool(getattr(obj.aq_base, "image", False))\n \n \n @indexer(Interface)\n@@ -247,22 +249,22 @@ def mime_type(obj):\n class CatalogTool(PloneBaseTool, BaseTool):\n """Plone\'s catalog tool"""\n \n- meta_type = \'Plone Catalog Tool\'\n+ meta_type = "Plone Catalog Tool"\n security = ClassSecurityInfo()\n- toolicon = \'skins/plone_images/book_icon.png\'\n+ toolicon = "skins/plone_images/book_icon.png"\n _counter = None\n \n- manage_catalogAdvanced = DTMLFile(\'www/catalogAdvanced\', globals())\n+ manage_catalogAdvanced = DTMLFile("www/catalogAdvanced", globals())\n \n manage_options = (\n- {\'action\': \'manage_main\', \'label\': \'Contents\'},\n- {\'action\': \'manage_catalogView\', \'label\': \'Catalog\'},\n- {\'action\': \'manage_catalogIndexes\', \'label\': \'Indexes\'},\n- {\'action\': \'manage_catalogSchema\', \'label\': \'Metadata\'},\n- {\'action\': \'manage_catalogAdvanced\', \'label\': \'Advanced\'},\n- {\'action\': \'manage_catalogReport\', \'label\': \'Query Report\'},\n- {\'action\': \'manage_catalogPlan\', \'label\': \'Query Plan\'},\n- {\'action\': \'manage_propertiesForm\', \'label\': \'Properties\'},\n+ {"action": "manage_main", "label": "Contents"},\n+ {"action": "manage_catalogView", "label": "Catalog"},\n+ {"action": "manage_catalogIndexes", "label": "Indexes"},\n+ {"action": "manage_catalogSchema", "label": "Metadata"},\n+ {"action": "manage_catalogAdvanced", "label": "Advanced"},\n+ {"action": "manage_catalogReport", "label": "Query Report"},\n+ {"action": "manage_catalogPlan", "label": "Query Plan"},\n+ {"action": "manage_propertiesForm", "label": "Properties"},\n )\n \n def __init__(self):\n@@ -278,17 +280,17 @@ def _removeIndex(self, index):\n def _listAllowedRolesAndUsers(self, user):\n # Makes sure the list includes the user\'s groups.\n result = user.getRoles()\n- if \'Anonymous\' in result:\n+ if "Anonymous" in result:\n # The anonymous user has no further roles\n- return [\'Anonymous\']\n+ return ["Anonymous"]\n result = list(result)\n- if hasattr(aq_base(user), \'getGroups\'):\n- groups = [\'user:%s\' % x for x in user.getGroups()]\n+ if hasattr(aq_base(user), "getGroups"):\n+ groups = ["user:%s" % x for x in user.getGroups()]\n if groups:\n result = result + groups\n # Order the arguments from small to large sets\n- result.insert(0, \'user:%s\' % user.getId())\n- result.append(\'Anonymous\')\n+ result.insert(0, "user:%s" % user.getId())\n+ result.append("Anonymous")\n return result\n \n @security.private\n@@ -301,8 +303,9 @@ def indexObject(self, object, idxs=None):\n self.reindexObject(object, idxs)\n \n @security.protected(ManageZCatalogEntries)\n- def catalog_object(self, object, uid=None, idxs=None,\n- update_metadata=1, pghandler=None):\n+ def catalog_object(\n+ self, object, uid=None, idxs=None, update_metadata=1, pghandler=None\n+ ):\n if idxs is None:\n idxs = []\n self._increment_counter()\n@@ -315,8 +318,9 @@ def catalog_object(self, object, uid=None, idxs=None,\n if wrapper is not None:\n w = wrapper\n \n- ZCatalog.catalog_object(self, w, uid, idxs,\n- update_metadata, pghandler=pghandler)\n+ ZCatalog.catalog_object(\n+ self, w, uid, idxs, update_metadata, pghandler=pghandler\n+ )\n \n @security.protected(ManageZCatalogEntries)\n def uncatalog_object(self, *args, **kwargs):\n@@ -346,14 +350,14 @@ def allow_inactive(self, query_kw):\n if allow_inactive:\n return True\n \n- paths = query_kw.get(\'path\', False)\n+ paths = query_kw.get("path", False)\n if not paths:\n return False\n \n if isinstance(paths, dict):\n # Like: {\'path\': {\'depth\': 0, \'query\': [\'/Plone/events/\']}}\n # Or: {\'path\': {\'depth\': 0, \'query\': \'/Plone/events/\'}}\n- paths = paths.get(\'query\', [])\n+ paths = paths.get("query", [])\n \n if isinstance(paths, str):\n paths = [paths]\n@@ -362,9 +366,9 @@ def allow_inactive(self, query_kw):\n site = getSite()\n for path in list(paths):\n try:\n- site_path = \'/\'.join(site.getPhysicalPath())\n- parts = path[len(site_path) + 1:].split(\'/\')\n- parent = site.unrestrictedTraverse(\'/\'.join(parts[:-1]))\n+ site_path = "/".join(site.getPhysicalPath())\n+ parts = path[len(site_path) + 1 :].split("/")\n+ parent = site.unrestrictedTraverse("/".join(parts[:-1]))\n objs.append(parent.restrictedTraverse(parts[-1]))\n except (KeyError, AttributeError, Unauthorized):\n # When no object is found don\'t raise an error\n@@ -375,8 +379,7 @@ def allow_inactive(self, query_kw):\n \n allow = True\n for ob in objs:\n- allow = allow and\\\n- _checkPermission(AccessInactivePortalContent, ob)\n+ allow = allow and _checkPermission(AccessInactivePortalContent, ob)\n \n return allow\n \n@@ -395,18 +398,18 @@ def searchResults(self, query=None, **kw):\n processQueue()\n \n kw = kw.copy()\n- show_inactive = kw.get(\'show_inactive\', False)\n+ show_inactive = kw.get("show_inactive", False)\n if isinstance(query, dict) and not show_inactive:\n- show_inactive = \'show_inactive\' in query\n+ show_inactive = "show_inactive" in query\n \n user = _getAuthenticatedUser(self)\n- kw[\'allowedRolesAndUsers\'] = self._listAllowedRolesAndUsers(user)\n+ kw["allowedRolesAndUsers"] = self._listAllowedRolesAndUsers(user)\n \n if not show_inactive and not self.allow_inactive(kw):\n- kw[\'effectiveRange\'] = DateTime()\n+ kw["effectiveRange"] = DateTime()\n \n # filter out invalid sort_on indexes\n- sort_on = kw.get(\'sort_on\') or []\n+ sort_on = kw.get("sort_on") or []\n if isinstance(sort_on, str):\n sort_on = [sort_on]\n valid_indexes = self.indexes()\n@@ -416,29 +419,27 @@ def searchResults(self, query=None, **kw):\n # sort_on is not iterable\n sort_on = []\n if not sort_on:\n- kw.pop(\'sort_on\', None)\n+ kw.pop("sort_on", None)\n else:\n- kw[\'sort_on\'] = sort_on\n+ kw["sort_on"] = sort_on\n \n return ZCatalog.searchResults(self, query, **kw)\n \n __call__ = searchResults\n \n- def search(self, query,\n- sort_index=None, reverse=0, limit=None, merge=1):\n+ def search(self, query, sort_index=None, reverse=0, limit=None, merge=1):\n # Wrap search() the same way that searchResults() is\n \n # Make sure any pending index tasks have been processed\n processQueue()\n \n user = _getAuthenticatedUser(self)\n- query[\'allowedRolesAndUsers\'] = self._listAllowedRolesAndUsers(user)\n+ query["allowedRolesAndUsers"] = self._listAllowedRolesAndUsers(user)\n \n if not self.allow_inactive(query):\n- query[\'effectiveRange\'] = DateTime()\n+ query["effectiveRange"] = DateTime()\n \n- return super().search(\n- query, sort_index, reverse, limit, merge)\n+ return super().search(query, sort_index, reverse, limit, merge)\n \n @security.protected(ManageZCatalogEntries)\n def clearFindAndRebuild(self):\n@@ -450,7 +451,7 @@ def clearFindAndRebuild(self):\n def indexObject(obj, path):\n if (\n obj != self\n- and base_hasattr(obj, \'reindexObject\')\n+ and base_hasattr(obj, "reindexObject")\n and safe_callable(obj.reindexObject)\n ):\n try:\n@@ -469,14 +470,11 @@ def indexObject(obj, path):\n # Catalogs have \'indexObject\' as well, but they\n # take different args, and will fail\n pass\n+\n self.manage_catalogClear()\n portal = aq_parent(aq_inner(self))\n- indexObject(portal, \'\')\n- portal.ZopeFindAndApply(\n- portal,\n- search_sub=True,\n- apply_func=indexObject\n- )\n+ indexObject(portal, "")\n+ portal.ZopeFindAndApply(portal, search_sub=True, apply_func=indexObject)\n \n @security.protected(ManageZCatalogEntries)\n def manage_catalogRebuild(self, RESPONSE=None, URL1=None):\n@@ -491,14 +489,19 @@ def manage_catalogRebuild(self, RESPONSE=None, URL1=None):\n elapse = time.time() - elapse\n c_elapse = process_time() - c_elapse\n \n- msg = (\'Catalog Rebuilt\\n\'\n- \'Total time: %s\\n\'\n- \'Total CPU time: %s\' % (repr(elapse), repr(c_elapse)))\n+ msg = (\n+ "Catalog Rebuilt\\n"\n+ "Total time: %s\\n"\n+ "Total CPU time: %s" % (repr(elapse), repr(c_elapse))\n+ )\n logger.info(msg)\n \n if RESPONSE is not None:\n RESPONSE.redirect(\n- URL1 + \'/manage_catalogAdvanced?manage_tabs_message=\' +\n- urllib.parse.quote(msg))\n+ URL1\n+ + "/manage_catalogAdvanced?manage_tabs_message="\n+ + urllib.parse.quote(msg)\n+ )\n+\n \n InitializeClass(CatalogTool)\ndiff --git a/Products/CMFPlone/MigrationTool.py b/Products/CMFPlone/MigrationTool.py\nindex 98285bd0c8..aefc10f3ac 100644\n--- a/Products/CMFPlone/MigrationTool.py\n+++ b/Products/CMFPlone/MigrationTool.py\n@@ -20,7 +20,7 @@\n import transaction\n \n \n-logger = logging.getLogger(\'plone.app.upgrade\')\n+logger = logging.getLogger("plone.app.upgrade")\n _upgradePaths = {}\n \n \n@@ -46,8 +46,7 @@ def __init__(self, profile_id=None, check_module=None):\n self.check_module = check_module\n \n def __repr__(self):\n- return \'<{} profile {}>\'.format(\n- self.__class__.__name__, self.profile_id)\n+ return "<{} profile {}>".format(self.__class__.__name__, self.profile_id)\n \n def safe(self):\n # Is this addon safe to upgrade?\n@@ -68,16 +67,16 @@ def safe(self):\n try:\n __import__(self.check_module)\n except ImportError:\n- logger.info(\'Cannot import module %s. Ignoring %s\',\n- self.check_module, self)\n+ logger.info(\n+ "Cannot import module %s. Ignoring %s", self.check_module, self\n+ )\n return False\n return True\n \n \n class AddonList(list):\n-\n def upgrade_all(self, context):\n- setup = getToolByName(context, \'portal_setup\')\n+ setup = getToolByName(context, "portal_setup")\n for addon in self:\n if addon.safe():\n setup.upgradeProfile(addon.profile_id, quiet=True)\n@@ -88,153 +87,144 @@ def upgrade_all(self, context):\n # Good start is portal_setup.listProfilesWithUpgrades()\n # Please use \'check_module\' for packages that are not direct dependencies\n # of Products.CMFPlone, but of the Plone package.\n-ADDON_LIST = AddonList([\n- Addon(profile_id=\'Products.CMFEditions:CMFEditions\'),\n- Addon(\n- profile_id=\'Products.CMFPlacefulWorkflow:CMFPlacefulWorkflow\',\n- check_module=\'Products.CMFPlacefulWorkflow\'\n- ),\n- Addon(profile_id=\'Products.PlonePAS:PlonePAS\'),\n- Addon(\n- profile_id=\'plone.app.caching:default\',\n- check_module=\'plone.app.caching\'\n- ),\n- Addon(profile_id=\'plone.app.contenttypes:default\'),\n- Addon(profile_id=\'plone.app.dexterity:default\'),\n- Addon(profile_id=\'plone.app.discussion:default\'),\n- Addon(profile_id=\'plone.app.event:default\'),\n- Addon(\n- profile_id=\'plone.app.iterate:default\',\n- check_module=\'plone.app.iterate\'\n- ),\n- Addon(profile_id=\'plone.app.multilingual:default\'),\n- Addon(profile_id=\'plone.app.querystring:default\'),\n- Addon(profile_id=\'plone.app.theming:default\'),\n- Addon(profile_id=\'plone.app.users:default\'),\n- Addon(\n- profile_id=\'plone.restapi:default\',\n- check_module=\'plone.restapi\'\n- ),\n- Addon(profile_id=\'plone.session:default\'),\n- Addon(profile_id=\'plone.staticresources:default\'),\n- Addon(\n- profile_id=\'plone.volto:default\',\n- check_module=\'plone.volto\'\n- ),\n- Addon(profile_id=\'plonetheme.barceloneta:default\'),\n-])\n+ADDON_LIST = AddonList(\n+ [\n+ Addon(profile_id="Products.CMFEditions:CMFEditions"),\n+ Addon(\n+ profile_id="Products.CMFPlacefulWorkflow:CMFPlacefulWorkflow",\n+ check_module="Products.CMFPlacefulWorkflow",\n+ ),\n+ Addon(profile_id="Products.PlonePAS:PlonePAS"),\n+ Addon(profile_id="plone.app.caching:default", check_module="plone.app.caching"),\n+ Addon(profile_id="plone.app.contenttypes:default"),\n+ Addon(profile_id="plone.app.dexterity:default"),\n+ Addon(profile_id="plone.app.discussion:default"),\n+ Addon(profile_id="plone.app.event:default"),\n+ Addon(profile_id="plone.app.iterate:default", check_module="plone.app.iterate"),\n+ Addon(profile_id="plone.app.multilingual:default"),\n+ Addon(profile_id="plone.app.querystring:default"),\n+ Addon(profile_id="plone.app.theming:default"),\n+ Addon(profile_id="plone.app.users:default"),\n+ Addon(profile_id="plone.restapi:default", check_module="plone.restapi"),\n+ Addon(profile_id="plone.session:default"),\n+ Addon(profile_id="plone.staticresources:default"),\n+ Addon(profile_id="plone.volto:default", check_module="plone.volto"),\n+ Addon(profile_id="plonetheme.barceloneta:default"),\n+ ]\n+)\n \n \n @implementer(IMigrationTool)\n class MigrationTool(PloneBaseTool, UniqueObject, SimpleItem):\n """Handles migrations between Plone releases"""\n \n- id = \'portal_migration\'\n- meta_type = \'Plone Migration Tool\'\n- toolicon = \'skins/plone_images/site_icon.png\'\n+ id = "portal_migration"\n+ meta_type = "Plone Migration Tool"\n+ toolicon = "skins/plone_images/site_icon.png"\n \n manage_options = (\n- ({\'label\': \'Upgrade\', \'action\': \'../@@plone-upgrade\'}, ) +\n- SimpleItem.manage_options)\n+ {"label": "Upgrade", "action": "../@@plone-upgrade"},\n+ ) + SimpleItem.manage_options\n \n _needRecatalog = 0\n _needUpdateRole = 0\n \n security = ClassSecurityInfo()\n \n- security.declareProtected(ManagePortal, \'getInstanceVersion\')\n+ security.declareProtected(ManagePortal, "getInstanceVersion")\n \n def getInstanceVersion(self):\n # The version this instance of plone is on.\n- setup = getToolByName(self, \'portal_setup\')\n+ setup = getToolByName(self, "portal_setup")\n version = setup.getLastVersionForProfile(_DEFAULT_PROFILE)\n if isinstance(version, tuple):\n- version = \'.\'.join(version)\n+ version = ".".join(version)\n \n- _version = getattr(self, \'_version\', None)\n+ _version = getattr(self, "_version", None)\n if _version is None:\n self._version = False\n \n- if version == \'unknown\':\n+ if version == "unknown":\n if _version:\n # Instance version was not pkg_resources compatible...\n- _version = _version.replace(\'devel (svn/unreleased)\', \'dev\')\n- _version = _version.rstrip(\'-final\')\n- _version = _version.rstrip(\'final\')\n- _version = _version.replace(\'alpha\', \'a\')\n- _version = _version.replace(\'beta\', \'b\')\n- _version = _version.replace(\'-\', \'.\')\n+ _version = _version.replace("devel (svn/unreleased)", "dev")\n+ _version = _version.rstrip("-final")\n+ _version = _version.rstrip("final")\n+ _version = _version.replace("alpha", "a")\n+ _version = _version.replace("beta", "b")\n+ _version = _version.replace("-", ".")\n version = _version\n else:\n version = setup.getVersionForProfile(_DEFAULT_PROFILE)\n self.setInstanceVersion(version)\n return version\n \n- security.declareProtected(ManagePortal, \'setInstanceVersion\')\n+ security.declareProtected(ManagePortal, "setInstanceVersion")\n \n def setInstanceVersion(self, version):\n # The version this instance of plone is on.\n- setup = getToolByName(self, \'portal_setup\')\n+ setup = getToolByName(self, "portal_setup")\n setup.setLastVersionForProfile(_DEFAULT_PROFILE, version)\n self._version = False\n \n- security.declareProtected(ManagePortal, \'getFileSystemVersion\')\n+ security.declareProtected(ManagePortal, "getFileSystemVersion")\n \n def getFileSystemVersion(self):\n # The version this instance of plone is on.\n- setup = getToolByName(self, \'portal_setup\')\n+ setup = getToolByName(self, "portal_setup")\n try:\n return setup.getVersionForProfile(_DEFAULT_PROFILE)\n except KeyError:\n pass\n return None\n \n- security.declareProtected(ManagePortal, \'getSoftwareVersion\')\n+ security.declareProtected(ManagePortal, "getSoftwareVersion")\n \n def getSoftwareVersion(self):\n # The software version.\n- dist = pkg_resources.get_distribution(\'Products.CMFPlone\')\n+ dist = pkg_resources.get_distribution("Products.CMFPlone")\n return dist.version\n \n- security.declareProtected(ManagePortal, \'needUpgrading\')\n+ security.declareProtected(ManagePortal, "needUpgrading")\n \n def needUpgrading(self):\n # Need upgrading?\n return self.getInstanceVersion() != self.getFileSystemVersion()\n \n- security.declareProtected(ManagePortal, \'coreVersions\')\n+ security.declareProtected(ManagePortal, "coreVersions")\n \n def coreVersions(self):\n # Useful core information.\n vars = {}\n get_dist = pkg_resources.get_distribution\n- vars[\'Zope\'] = get_dist(\'Zope\').version\n- vars[\'Python\'] = sys.version\n- vars[\'Platform\'] = sys.platform\n- vars[\'Plone\'] = get_dist(\'Products.CMFPlone\').version\n- vars[\'Plone Instance\'] = self.getInstanceVersion()\n- vars[\'Plone File System\'] = self.getFileSystemVersion()\n- vars[\'CMF\'] = get_dist(\'Products.CMFCore\').version\n- vars[\'Debug mode\'] = getConfiguration().debug_mode and \'Yes\' or \'No\'\n+ vars["Zope"] = get_dist("Zope").version\n+ vars["Python"] = sys.version\n+ vars["Platform"] = sys.platform\n+ vars["Plone"] = get_dist("Products.CMFPlone").version\n+ vars["Plone Instance"] = self.getInstanceVersion()\n+ vars["Plone File System"] = self.getFileSystemVersion()\n+ vars["CMF"] = get_dist("Products.CMFCore").version\n+ vars["Debug mode"] = getConfiguration().debug_mode and "Yes" or "No"\n try:\n- vars[\'PIL\'] = get_dist(\'PIL\').version\n+ vars["PIL"] = get_dist("PIL").version\n except pkg_resources.DistributionNotFound:\n try:\n- vars[\'PIL\'] = get_dist(\'PILwoTK\').version\n+ vars["PIL"] = get_dist("PILwoTK").version\n except pkg_resources.DistributionNotFound:\n try:\n- vars[\'PIL\'] = "%s (Pillow)" % get_dist(\'Pillow\').version\n+ vars["PIL"] = "%s (Pillow)" % get_dist("Pillow").version\n except pkg_resources.DistributionNotFound:\n try:\n import _imaging\n+\n _imaging # pyflakes\n- vars[\'PIL\'] = \'unknown\'\n+ vars["PIL"] = "unknown"\n except ImportError:\n pass\n \n return vars\n \n- security.declareProtected(ManagePortal, \'coreVersionsList\')\n+ security.declareProtected(ManagePortal, "coreVersionsList")\n \n def coreVersionsList(self):\n # Useful core information.\n@@ -242,34 +232,34 @@ def coreVersionsList(self):\n res.sort()\n return res\n \n- security.declareProtected(ManagePortal, \'needUpdateRole\')\n+ security.declareProtected(ManagePortal, "needUpdateRole")\n \n def needUpdateRole(self):\n # Do roles need to be updated?\n return self._needUpdateRole\n \n- security.declareProtected(ManagePortal, \'needRecatalog\')\n+ security.declareProtected(ManagePortal, "needRecatalog")\n \n def needRecatalog(self):\n # Does this thing now need recataloging?\n return self._needRecatalog\n \n- security.declareProtected(ManagePortal, \'listUpgrades\')\n+ security.declareProtected(ManagePortal, "listUpgrades")\n \n def listUpgrades(self):\n # List available upgrade steps for our default profile.\n # Do not include upgrade steps for too new versions:\n # using a newer plone.app.upgrade version should not give problems.\n- setup = getToolByName(self, \'portal_setup\')\n+ setup = getToolByName(self, "portal_setup")\n fs_version = self.getFileSystemVersion()\n upgrades = setup.listUpgrades(_DEFAULT_PROFILE, dest=fs_version)\n return upgrades\n \n- security.declareProtected(ManagePortal, \'upgrade\')\n+ security.declareProtected(ManagePortal, "upgrade")\n \n def upgrade(self, REQUEST=None, dry_run=None, swallow_errors=True):\n # Perform the upgrade.\n- setup = getToolByName(self, \'portal_setup\')\n+ setup = getToolByName(self, "portal_setup")\n \n # This sets the profile version if it wasn\'t set yet\n version = self.getInstanceVersion()\n@@ -286,7 +276,7 @@ def upgrade(self, REQUEST=None, dry_run=None, swallow_errors=True):\n handler = logging.StreamHandler(stream)\n handler.setLevel(logging.DEBUG)\n logger.addHandler(handler)\n- gslogger = logging.getLogger(\'GenericSetup\')\n+ gslogger = logging.getLogger("GenericSetup")\n gslogger.addHandler(handler)\n \n if dry_run:\n@@ -296,10 +286,9 @@ def upgrade(self, REQUEST=None, dry_run=None, swallow_errors=True):\n \n for step in steps:\n try:\n- step[\'step\'].doStep(setup)\n- setup.setLastVersionForProfile(\n- _DEFAULT_PROFILE, step[\'dest\'])\n- logger.info("Ran upgrade step: %s" % step[\'title\'])\n+ step["step"].doStep(setup)\n+ setup.setLastVersionForProfile(_DEFAULT_PROFILE, step["dest"])\n+ logger.info("Ran upgrade step: %s" % step["title"])\n except (ConflictError, KeyboardInterrupt):\n raise\n except:\n@@ -329,7 +318,7 @@ def upgrade(self, REQUEST=None, dry_run=None, swallow_errors=True):\n catalog = self.portal_catalog\n # Reduce threshold for the reindex run\n old_threshold = catalog.threshold\n- pg_threshold = getattr(catalog, \'pgthreshold\', 0)\n+ pg_threshold = getattr(catalog, "pgthreshold", 0)\n catalog.pgthreshold = 300\n catalog.threshold = 2000\n catalog.refreshCatalog(clear=1)\n@@ -339,8 +328,9 @@ def upgrade(self, REQUEST=None, dry_run=None, swallow_errors=True):\n except (ConflictError, KeyboardInterrupt):\n raise\n except:\n- logger.error("Exception was thrown while cataloging:"\n- "\\n", exc_info=True)\n+ logger.error(\n+ "Exception was thrown while cataloging:" "\\n", exc_info=True\n+ )\n if not swallow_errors:\n raise\n \n@@ -352,8 +342,10 @@ def upgrade(self, REQUEST=None, dry_run=None, swallow_errors=True):\n except (ConflictError, KeyboardInterrupt):\n raise\n except:\n- logger.error("Exception was thrown while updating "\n- "role mappings", exc_info=True)\n+ logger.error(\n+ "Exception was thrown while updating " "role mappings",\n+ exc_info=True,\n+ )\n if not swallow_errors:\n raise\n logger.info("Your Plone instance is now up-to-date.")\n@@ -372,8 +364,9 @@ def upgrade(self, REQUEST=None, dry_run=None, swallow_errors=True):\n \n \n def registerUpgradePath(oldversion, newversion, function):\n- """ Basic register func """\n+ """Basic register func"""\n pass\n \n+\n InitializeClass(MigrationTool)\n-registerToolInterface(\'portal_migration\', IMigrationTool)\n+registerToolInterface("portal_migration", IMigrationTool)\ndiff --git a/Products/CMFPlone/PasswordResetTool.py b/Products/CMFPlone/PasswordResetTool.py\nindex 620a34a0b7..3b26743aa3 100644\n--- a/Products/CMFPlone/PasswordResetTool.py\n+++ b/Products/CMFPlone/PasswordResetTool.py\n@@ -22,13 +22,14 @@\n import datetime\n \n \n-module_security = ModuleSecurityInfo(\'Products.CMFPlone.PasswordResetTool\')\n+module_security = ModuleSecurityInfo("Products.CMFPlone.PasswordResetTool")\n \n \n @module_security.public\n class InvalidRequestError(Exception):\n- """ Request reset URL is invalid """\n- def __init__(self, value=\'\'):\n+ """Request reset URL is invalid"""\n+\n+ def __init__(self, value=""):\n self.value = value\n \n def __str__(self):\n@@ -37,11 +38,11 @@ def __str__(self):\n \n @module_security.public\n class ExpiredRequestError(InvalidRequestError):\n- """ Request reset URL is expired """\n+ """Request reset URL is expired"""\n \n \n @implementer(IPWResetTool)\n-class PasswordResetTool (UniqueObject, SimpleItem):\n+class PasswordResetTool(UniqueObject, SimpleItem):\n """Provides a default implementation for a password reset scheme.\n \n From a \'forgotten password\' template, you submit your username to\n@@ -52,8 +53,8 @@ class PasswordResetTool (UniqueObject, SimpleItem):\n The user visits that URL (the \'reset form\') and enters their username,\n """\n \n- id = \'portal_password_reset\'\n- meta_type = \'Password Reset Tool\'\n+ id = "portal_password_reset"\n+ meta_type = "Password Reset Tool"\n \n security = ClassSecurityInfo()\n \n@@ -62,7 +63,7 @@ def __init__(self):\n \n # Internal attributes\n _user_check = True\n- _timedelta = 7 # DAYS\n+ _timedelta = 7 # DAYS\n \n # Interface fulfillment ##\n @security.protected(ManagePortal)\n@@ -88,9 +89,9 @@ def requestReset(self, userid):\n self._p_changed = 1\n \n retval = {}\n- retval[\'randomstring\'] = randomstring\n- retval[\'expires\'] = expiry\n- retval[\'userid\'] = userid\n+ retval["randomstring"] = randomstring\n+ retval["expires"] = expiry\n+ retval["userid"] = userid\n return retval\n \n @security.public\n@@ -109,7 +110,8 @@ def resetPassword(self, userid, randomstring, password):\n """\n if get_member_by_login_name:\n found_member = get_member_by_login_name(\n- self, userid, raise_exceptions=False)\n+ self, userid, raise_exceptions=False\n+ )\n if found_member is not None:\n userid = found_member.getId()\n try:\n@@ -130,7 +132,7 @@ def resetPassword(self, userid, randomstring, password):\n \n # actually change password\n user = member.getUser()\n- uf = getToolByName(self, \'acl_users\')\n+ uf = getToolByName(self, "acl_users")\n uf.userSetPassword(user.getUserId(), password)\n member.setMemberProperties(dict(must_change_password=0))\n \n@@ -140,14 +142,12 @@ def resetPassword(self, userid, randomstring, password):\n \n @security.protected(ManagePortal)\n def setExpirationTimeout(self, timedelta):\n- """Set the length of time a reset request will be valid in days.\n- """\n+ """Set the length of time a reset request will be valid in days."""\n self._timedelta = abs(timedelta)\n \n @security.public\n def getExpirationTimeout(self):\n- """Get the length of time a reset request will be valid.\n- """\n+ """Get the length of time a reset request will be valid."""\n return self._timedelta\n \n @security.public\n@@ -158,8 +158,7 @@ def checkUser(self):\n \n @security.public\n def verifyKey(self, key):\n- """Verify a key. Raises an exception if the key is invalid or expired.\n- """\n+ """Verify a key. Raises an exception if the key is invalid or expired."""\n try:\n u, expiry = self._requests[key]\n except KeyError:\n@@ -169,7 +168,7 @@ def verifyKey(self, key):\n raise ExpiredRequestError\n \n if not self.getValidUser(u):\n- raise InvalidRequestError(\'No such user\')\n+ raise InvalidRequestError("No such user")\n \n @security.private\n def clearExpired(self, days=0):\n@@ -207,24 +206,17 @@ def expirationDate(self):\n \n This is used by housekeeping methods (like clearEpired)\n and stored in reset request records."""\n- return (\n- datetime.datetime.utcnow() +\n- datetime.timedelta(days=self._timedelta)\n- )\n+ return datetime.datetime.utcnow() + datetime.timedelta(days=self._timedelta)\n \n @security.private\n def getValidUser(self, userid):\n """Returns the member with \'userid\' if available and None otherwise."""\n if get_member_by_login_name:\n registry = getUtility(IRegistry)\n- settings = registry.forInterface(ISecuritySchema, prefix=\'plone\')\n+ settings = registry.forInterface(ISecuritySchema, prefix="plone")\n if settings.use_email_as_login:\n- return get_member_by_login_name(\n- self,\n- userid,\n- raise_exceptions=False\n- )\n- membertool = getToolByName(self, \'portal_membership\')\n+ return get_member_by_login_name(self, userid, raise_exceptions=False)\n+ membertool = getToolByName(self, "portal_membership")\n return membertool.getMemberById(userid)\n \n @security.private\ndiff --git a/Products/CMFPlone/PloneBatch.py b/Products/CMFPlone/PloneBatch.py\nindex b96f72402a..f1a974e1a9 100644\n--- a/Products/CMFPlone/PloneBatch.py\n+++ b/Products/CMFPlone/PloneBatch.py\n@@ -1,4 +1,4 @@\n from zope.deprecation import moved\n \n \n-moved(\'plone.base.batch\', \'Version 7.0\')\n+moved("plone.base.batch", "Version 7.0")\ndiff --git a/Products/CMFPlone/PloneControlPanel.py b/Products/CMFPlone/PloneControlPanel.py\nindex d3bdd10096..357ee8ece3 100644\n--- a/Products/CMFPlone/PloneControlPanel.py\n+++ b/Products/CMFPlone/PloneControlPanel.py\n@@ -23,7 +23,6 @@\n \n \n class PloneConfiglet(ActionInformation):\n-\n def __init__(self, appId, **kwargs):\n self.appId = appId\n ActionInformation.__init__(self, **kwargs)\n@@ -39,66 +38,66 @@ def clone(self):\n \n def getAction(self, ec):\n res = ActionInformation.getAction(self, ec)\n- res[\'description\'] = self.getDescription()\n+ res["description"] = self.getDescription()\n return res\n \n \n @implementer(IControlPanel)\n-class PloneControlPanel(PloneBaseTool, UniqueObject,\n- Folder, ActionProviderBase, PropertyManager):\n+class PloneControlPanel(\n+ PloneBaseTool, UniqueObject, Folder, ActionProviderBase, PropertyManager\n+):\n """Weave together the various sources of "actions" which\n are apropos to the current user and context.\n """\n \n security = ClassSecurityInfo()\n \n- id = \'portal_controlpanel\'\n- title = \'Control Panel\'\n- toolicon = \'skins/plone_images/site_icon.png\'\n- meta_type = \'Plone Control Panel Tool\'\n- _actions_form = DTMLFile(\'www/editPloneConfiglets\', globals())\n+ id = "portal_controlpanel"\n+ title = "Control Panel"\n+ toolicon = "skins/plone_images/site_icon.png"\n+ meta_type = "Plone Control Panel Tool"\n+ _actions_form = DTMLFile("www/editPloneConfiglets", globals())\n \n- manage_options = (ActionProviderBase.manage_options +\n- PropertyManager.manage_options)\n+ manage_options = ActionProviderBase.manage_options + PropertyManager.manage_options\n \n group = dict(\n member=[\n- (\'Member\', _(\'My Preferences\')),\n+ ("Member", _("My Preferences")),\n ],\n site=[\n- (\'plone-general\', _(\'General\')),\n- (\'plone-content\', _(\'Content\')),\n- (\'plone-users\', _(\'Users\')),\n- (\'plone-security\', _(\'Security\')),\n- (\'plone-advanced\', _(\'Advanced\')),\n- (\'Plone\', _(\'Plone Configuration\')),\n- (\'Products\', _(\'Add-on Configuration\')),\n- ]\n+ ("plone-general", _("General")),\n+ ("plone-content", _("Content")),\n+ ("plone-users", _("Users")),\n+ ("plone-security", _("Security")),\n+ ("plone-advanced", _("Advanced")),\n+ ("Plone", _("Plone Configuration")),\n+ ("Products", _("Add-on Configuration")),\n+ ],\n )\n \n def __init__(self, **kw):\n if kw:\n self.__dict__.update(**kw)\n \n- security.declareProtected(ManagePortal, \'registerConfiglets\')\n+ security.declareProtected(ManagePortal, "registerConfiglets")\n \n def registerConfiglets(self, configlets):\n for conf in configlets:\n self.registerConfiglet(**conf)\n \n- security.declareProtected(ManagePortal, \'getGroupIds\')\n+ security.declareProtected(ManagePortal, "getGroupIds")\n \n- def getGroupIds(self, category=\'site\'):\n+ def getGroupIds(self, category="site"):\n groups = self.group.get(category, [])\n return [g[0] for g in groups if g]\n \n- security.declareProtected(View, \'getGroups\')\n+ security.declareProtected(View, "getGroups")\n \n- def getGroups(self, category=\'site\'):\n+ def getGroups(self, category="site"):\n groups = self.group.get(category, [])\n- return [{\'id\': g[0], \'title\': g[1]} for g in groups if g]\n+ return [{"id": g[0], "title": g[1]} for g in groups if g]\n \n- security.declarePrivate(\'listActions\')\n+ security.declarePrivate("listActions")\n \n def listActions(self, info=None, object=None):\n # This exists here to shut up a deprecation warning about old-style\n@@ -108,21 +107,21 @@ def listActions(self, info=None, object=None):\n # before CMF 2.4 when support for old-style actions is removed.\n return self._actions or ()\n \n- security.declarePublic(\'maySeeSomeConfiglets\')\n+ security.declarePublic("maySeeSomeConfiglets")\n \n def maySeeSomeConfiglets(self):\n- groups = self.getGroups(\'site\')\n+ groups = self.getGroups("site")\n \n all = []\n for group in groups:\n- all.extend(self.enumConfiglets(group=group[\'id\']))\n- all = [item for item in all if item[\'visible\']]\n+ all.extend(self.enumConfiglets(group=group["id"]))\n+ all = [item for item in all if item["visible"]]\n return len(all) != 0\n \n- security.declarePublic(\'enumConfiglets\')\n+ security.declarePublic("enumConfiglets")\n \n def enumConfiglets(self, group=None):\n- portal = getToolByName(self, \'portal_url\').getPortalObject()\n+ portal = getToolByName(self, "portal_url").getPortalObject()\n context = createExprContext(self, portal, self)\n res = []\n for a in self.listActions():\n@@ -130,24 +129,28 @@ def enumConfiglets(self, group=None):\n for permission in a.permissions:\n if _checkPermission(permission, portal):\n verified = 1\n- if verified and a.category == group and a.visible and a.testCondition(context):\n+ if (\n+ verified\n+ and a.category == group\n+ and a.visible\n+ and a.testCondition(context)\n+ ):\n res.append(a.getAction(context))\n # Translate the title for sorting\n- if getattr(self, \'REQUEST\', None) is not None:\n+ if getattr(self, "REQUEST", None) is not None:\n for a in res:\n- title = a[\'title\']\n+ title = a["title"]\n if not isinstance(title, Message):\n- title = Message(title, domain=\'plone\')\n- a[\'title\'] = translate(title,\n- context=self.REQUEST)\n+ title = Message(title, domain="plone")\n+ a["title"] = translate(title, context=self.REQUEST)\n \n def _title(v):\n- return v[\'title\']\n+ return v["title"]\n \n res.sort(key=_title)\n return res\n \n- security.declareProtected(ManagePortal, \'unregisterConfiglet\')\n+ security.declareProtected(ManagePortal, "unregisterConfiglet")\n \n def unregisterConfiglet(self, id):\n actids = [o.id for o in self.listActions()]\n@@ -156,7 +159,7 @@ def unregisterConfiglet(self, id):\n return\n self.deleteActions(selection)\n \n- security.declareProtected(ManagePortal, \'unregisterApplication\')\n+ security.declareProtected(ManagePortal, "unregisterApplication")\n \n def unregisterApplication(self, appId):\n acts = list(self.listActions())\n@@ -167,28 +170,28 @@ def unregisterApplication(self, appId):\n \n def _extractAction(self, properties, index):\n # Extract an ActionInformation from the funky form properties.\n- id = str(properties.get(\'id_%d\' % index, \'\'))\n- name = str(properties.get(\'name_%d\' % index, \'\'))\n- action = str(properties.get(\'action_%d\' % index, \'\'))\n- condition = str(properties.get(\'condition_%d\' % index, \'\'))\n- category = str(properties.get(\'category_%d\' % index, \'\'))\n- visible = properties.get(\'visible_%d\' % index, 0)\n- permissions = properties.get(\'permission_%d\' % index, ())\n- appId = properties.get(\'appId_%d\' % index, \'\')\n- description = properties.get(\'description_%d\' % index, \'\')\n- icon_expr = properties.get(\'icon_expr_%d\' % index, \'\')\n+ id = str(properties.get("id_%d" % index, ""))\n+ name = str(properties.get("name_%d" % index, ""))\n+ action = str(properties.get("action_%d" % index, ""))\n+ condition = str(properties.get("condition_%d" % index, ""))\n+ category = str(properties.get("category_%d" % index, ""))\n+ visible = properties.get("visible_%d" % index, 0)\n+ permissions = properties.get("permission_%d" % index, ())\n+ appId = properties.get("appId_%d" % index, "")\n+ description = properties.get("description_%d" % index, "")\n+ icon_expr = properties.get("icon_expr_%d" % index, "")\n \n if not name:\n- raise ValueError(\'A name is required.\')\n+ raise ValueError("A name is required.")\n \n- if action != \'\':\n+ if action != "":\n action = Expression(text=action)\n \n- if condition != \'\':\n+ if condition != "":\n condition = Expression(text=condition)\n \n- if category == \'\':\n- category = \'object\'\n+ if category == "":\n+ category = "object"\n \n if not isinstance(visible, int):\n try:\n@@ -197,93 +200,93 @@ def _extractAction(self, properties, index):\n visible = 0\n \n if isinstance(permissions, str):\n- permissions = (permissions, )\n-\n- return PloneConfiglet(id=id,\n- title=name,\n- action=action,\n- condition=condition,\n- permissions=permissions,\n- category=category,\n- visible=visible,\n- appId=appId,\n- description=description,\n- icon_expr=icon_expr,\n- )\n-\n- security.declareProtected(ManagePortal, \'addAction\')\n-\n- def addAction(self,\n- id,\n- name,\n- action,\n- condition=\'\',\n- permission=\'\',\n- category=\'Plone\',\n- visible=1,\n- appId=None,\n- icon_expr=\'\',\n- description=\'\',\n- REQUEST=None,\n- ):\n+ permissions = (permissions,)\n+\n+ return PloneConfiglet(\n+ id=id,\n+ title=name,\n+ action=action,\n+ condition=condition,\n+ permissions=permissions,\n+ category=category,\n+ visible=visible,\n+ appId=appId,\n+ description=description,\n+ icon_expr=icon_expr,\n+ )\n+\n+ security.declareProtected(ManagePortal, "addAction")\n+\n+ def addAction(\n+ self,\n+ id,\n+ name,\n+ action,\n+ condition="",\n+ permission="",\n+ category="Plone",\n+ visible=1,\n+ appId=None,\n+ icon_expr="",\n+ description="",\n+ REQUEST=None,\n+ ):\n """Add an action to our list."""\n if not name:\n- raise ValueError(\'A name is required.\')\n+ raise ValueError("A name is required.")\n \n- a_expr = action and Expression(text=str(action)) or \'\'\n- c_expr = condition and Expression(text=str(condition)) or \'\'\n+ a_expr = action and Expression(text=str(action)) or ""\n+ c_expr = condition and Expression(text=str(condition)) or ""\n \n if not isinstance(permission, tuple):\n- permission = permission and (str(permission), ) or ()\n+ permission = permission and (str(permission),) or ()\n \n new_actions = self._cloneActions()\n \n- new_action = PloneConfiglet(id=str(id),\n- title=name,\n- action=a_expr,\n- condition=c_expr,\n- permissions=permission,\n- category=str(category),\n- visible=int(visible),\n- appId=appId,\n- description=description,\n- icon_expr=icon_expr,\n- )\n+ new_action = PloneConfiglet(\n+ id=str(id),\n+ title=name,\n+ action=a_expr,\n+ condition=c_expr,\n+ permissions=permission,\n+ category=str(category),\n+ visible=int(visible),\n+ appId=appId,\n+ description=description,\n+ icon_expr=icon_expr,\n+ )\n \n new_actions.append(new_action)\n self._actions = tuple(new_actions)\n \n if REQUEST is not None:\n- return self.manage_editActionsForm(\n- REQUEST, manage_tabs_message=\'Added.\')\n+ return self.manage_editActionsForm(REQUEST, manage_tabs_message="Added.")\n \n- security.declareProtected(ManagePortal, \'registerConfiglet\')\n+ security.declareProtected(ManagePortal, "registerConfiglet")\n registerConfiglet = addAction\n \n- security.declareProtected(ManagePortal, \'manage_editActionsForm\')\n+ security.declareProtected(ManagePortal, "manage_editActionsForm")\n \n def manage_editActionsForm(self, REQUEST, manage_tabs_message=None):\n- """ Show the \'Actions\' management tab.\n- """\n+ """Show the \'Actions\' management tab."""\n actions = []\n \n for a in self.listActions():\n-\n a1 = {}\n- a1[\'id\'] = a.getId()\n- a1[\'name\'] = a.Title()\n+ a1["id"] = a.getId()\n+ a1["name"] = a.Title()\n p = a.getPermissions()\n if p:\n- a1[\'permission\'] = p[0]\n+ a1["permission"] = p[0]\n else:\n- a1[\'permission\'] = \'\'\n- a1[\'category\'] = a.getCategory() or \'object\'\n- a1[\'visible\'] = a.getVisibility()\n- a1[\'action\'] = a.getActionExpression()\n- a1[\'condition\'] = a.getCondition()\n- a1[\'appId\'] = a.getAppId()\n- a1[\'description\'] = a.getDescription()\n- a1[\'icon_expr\'] = a.getIconExpression()\n+ a1["permission"] = ""\n+ a1["category"] = a.getCategory() or "object"\n+ a1["visible"] = a.getVisibility()\n+ a1["action"] = a.getActionExpression()\n+ a1["condition"] = a.getCondition()\n+ a1["appId"] = a.getAppId()\n+ a1["description"] = a.getDescription()\n+ a1["icon_expr"] = a.getIconExpression()\n actions.append(a1)\n \n # possible_permissions is in OFS.role.RoleManager.\n@@ -293,7 +296,7 @@ def manage_editActionsForm(self, REQUEST, manage_tabs_message=None):\n REQUEST,\n actions=actions,\n possible_permissions=pp,\n- management_view=\'Actions\',\n+ management_view="Actions",\n manage_tabs_message=manage_tabs_message,\n )\n \n@@ -308,4 +311,4 @@ def site_url(self):\n \n \n InitializeClass(PloneControlPanel)\n-registerToolInterface(\'portal_controlpanel\', IControlPanel)\n+registerToolInterface("portal_controlpanel", IControlPanel)\ndiff --git a/Products/CMFPlone/PloneTool.py b/Products/CMFPlone/PloneTool.py\nindex f3939235be..441ac10c16 100644\n--- a/Products/CMFPlone/PloneTool.py\n+++ b/Products/CMFPlone/PloneTool.py\n@@ -68,7 +68,10 @@\n BAD_CHARS = bad_id.__self__.findall\n \n # max 63 chars per label in domains, see RFC1035\n-EMAIL_RE = re.compile(r"^(\\w&.%#$&\'\\*+-/=?^_`{}|~]+!)*[\\w&.%#$&\'\\*+-/=?^_`{}|~]+@(([0-9a-z]([0-9a-z-]*[0-9a-z])?\\.)+[a-z]{2,63}|([0-9]{1,3}\\.){3}[0-9]{1,3})$", re.IGNORECASE) # noqa\n+EMAIL_RE = re.compile(\n+ r"^(\\w&.%#$&\'\\*+-/=?^_`{}|~]+!)*[\\w&.%#$&\'\\*+-/=?^_`{}|~]+@(([0-9a-z]([0-9a-z-]*[0-9a-z])?\\.)+[a-z]{2,63}|([0-9]{1,3}\\.){3}[0-9]{1,3})$",\n+ re.IGNORECASE,\n+) # noqa\n # used to find double new line (in any variant)\n EMAIL_CUTOFF_RE = re.compile(r".*[\\n\\r][\\n\\r]")\n \n@@ -77,53 +80,55 @@\n # The first two rows are handle in a special way\n # \'Description\' : \'description\',\n # \'Subject\' : \'keywords\',\n- \'Description\': \'DC.description\',\n- \'Subject\': \'DC.subject\',\n- \'Creator\': \'DC.creator\',\n- \'Contributors\': \'DC.contributors\',\n- \'Publisher\': \'DC.publisher\',\n- \'CreationDate\': \'DC.date.created\',\n- \'ModificationDate\': \'DC.date.modified\',\n- \'Type\': \'DC.type\',\n- \'Format\': \'DC.format\',\n- \'Language\': \'DC.language\',\n- \'Rights\': \'DC.rights\',\n+ "Description": "DC.description",\n+ "Subject": "DC.subject",\n+ "Creator": "DC.creator",\n+ "Contributors": "DC.contributors",\n+ "Publisher": "DC.publisher",\n+ "CreationDate": "DC.date.created",\n+ "ModificationDate": "DC.date.modified",\n+ "Type": "DC.type",\n+ "Format": "DC.format",\n+ "Language": "DC.language",\n+ "Rights": "DC.rights",\n }\n-METADATA_DC_AUTHORFIELDS = (\'Creator\', \'Contributors\', \'Publisher\')\n+METADATA_DC_AUTHORFIELDS = ("Creator", "Contributors", "Publisher")\n \n \n @implementer(IPloneTool)\n class PloneTool(PloneBaseTool, UniqueObject, SimpleItem):\n """Various utility methods."""\n \n- id = \'plone_utils\'\n- meta_type = \'Plone Utility Tool\'\n- toolicon = \'skins/plone_images/site_icon.png\'\n+ id = "plone_utils"\n+ meta_type = "Plone Utility Tool"\n+ toolicon = "skins/plone_images/site_icon.png"\n security = ClassSecurityInfo()\n plone_tool = 1\n # Prefix for forms fields!?\n- field_prefix = \'field_\'\n+ field_prefix = "field_"\n \n @security.protected(ManageUsers)\n @protect(CheckAuthenticator)\n def setMemberProperties(self, member, REQUEST=None, **properties):\n- pas = getToolByName(self, \'acl_users\')\n- if safe_hasattr(member, \'getId\'):\n+ pas = getToolByName(self, "acl_users")\n+ if safe_hasattr(member, "getId"):\n member = member.getId()\n user = pas.getUserById(member)\n user.setProperties(**properties)\n \n @security.public\n- @deprecate(\'`getSiteEncoding` is deprecated. Plone only supports UTF-8 \'\n- \'currently. This method always returns "utf-8"\')\n+ @deprecate(\n+ "`getSiteEncoding` is deprecated. Plone only supports UTF-8 "\n+ \'currently. This method always returns "utf-8"\'\n+ )\n def getSiteEncoding(self):\n- """ Get the the site encoding, which is utf-8."""\n- return \'utf-8\'\n+ """Get the the site encoding, which is utf-8."""\n+ return "utf-8"\n \n @security.private\n def getMailHost(self):\n """Gets the MailHost."""\n- return getattr(aq_parent(self), \'MailHost\')\n+ return getattr(aq_parent(self), "MailHost")\n \n @security.public\n def validateSingleNormalizedEmailAddress(self, address):\n@@ -138,8 +143,8 @@ def validateSingleNormalizedEmailAddress(self, address):\n return False\n \n # sub is an empty string if the address is valid\n- sub = EMAIL_RE.sub(\'\', address)\n- if sub == \'\':\n+ sub = EMAIL_RE.sub("", address)\n+ if sub == "":\n return True\n return False\n \n@@ -185,13 +190,24 @@ def validateEmailAddresses(self, addresses):\n return True\n \n @security.public\n- def editMetadata(self, obj, allowDiscussion=None, title=None,\n- subject=None, description=None, contributors=None,\n- effective_date=None, expiration_date=None, format=None,\n- language=None, rights=None, **kwargs):\n+ def editMetadata(\n+ self,\n+ obj,\n+ allowDiscussion=None,\n+ title=None,\n+ subject=None,\n+ description=None,\n+ contributors=None,\n+ effective_date=None,\n+ expiration_date=None,\n+ format=None,\n+ language=None,\n+ rights=None,\n+ **kwargs,\n+ ):\n # Responsible for setting metadata on a content object.\n # We assume the obj implements IDublinCoreMetadata.\n- mt = getToolByName(self, \'portal_membership\')\n+ mt = getToolByName(self, "portal_membership")\n if not mt.checkPermission(ModifyPortalContent, obj):\n # FIXME: Some scripts rely on this being string?\n raise Unauthorized\n@@ -207,25 +223,25 @@ def tuplify(value):\n \n if IDublinCore.providedBy(obj):\n if title is None:\n- title = getfield(REQUEST, \'title\')\n+ title = getfield(REQUEST, "title")\n if description is None:\n- description = getfield(REQUEST, \'description\')\n+ description = getfield(REQUEST, "description")\n if subject is None:\n- subject = getfield(REQUEST, \'subject\')\n+ subject = getfield(REQUEST, "subject")\n if subject is not None:\n subject = tuplify(subject)\n if contributors is None:\n- contributors = getfield(REQUEST, \'contributors\')\n+ contributors = getfield(REQUEST, "contributors")\n if contributors is not None:\n contributors = tuplify(contributors)\n if effective_date is None:\n- effective_date = getfield(REQUEST, \'effective_date\')\n- if effective_date == \'\':\n- effective_date = \'None\'\n+ effective_date = getfield(REQUEST, "effective_date")\n+ if effective_date == "":\n+ effective_date = "None"\n if expiration_date is None:\n- expiration_date = getfield(REQUEST, \'expiration_date\')\n- if expiration_date == \'\':\n- expiration_date = \'None\'\n+ expiration_date = getfield(REQUEST, "expiration_date")\n+ if expiration_date == "":\n+ expiration_date = "None"\n \n if IMutableDublinCore.providedBy(obj):\n if title is not None:\n@@ -252,20 +268,19 @@ def tuplify(value):\n def _renameObject(self, obj, id):\n if not id:\n REQUEST = self.REQUEST\n- id = REQUEST.get(\'id\', \'\')\n- id = REQUEST.get(self.field_prefix + \'id\', \'\')\n+ id = REQUEST.get("id", "")\n+ id = REQUEST.get(self.field_prefix + "id", "")\n if id != obj.getId():\n parent = aq_parent(aq_inner(obj))\n parent.manage_renameObject(obj.getId(), id)\n \n- def _makeTransactionNote(self, obj, msg=\'\'):\n+ def _makeTransactionNote(self, obj, msg=""):\n # TODO Why not aq_parent()?\n- relative_path = \'/\'.join(\n- getToolByName(self, \'portal_url\').getRelativeContentPath(obj)[:-1]\n+ relative_path = "/".join(\n+ getToolByName(self, "portal_url").getRelativeContentPath(obj)[:-1]\n )\n if not msg:\n- msg = relative_path + \'/\' + obj.title_or_id() \\\n- + \' has been modified.\'\n+ msg = relative_path + "/" + obj.title_or_id() + " has been modified."\n if not transaction.get().description:\n transaction_note(safe_text(msg))\n \n@@ -275,24 +290,23 @@ def contentEdit(self, obj, **kwargs):\n try:\n self.editMetadata(obj, **kwargs)\n except AttributeError as msg:\n- log(\'Failure editing metadata at: %s.\\n%s\\n\' %\n- (obj.absolute_url(), msg))\n- if kwargs.get(\'id\', None) is not None:\n- self._renameObject(obj, id=kwargs[\'id\'].strip())\n+ log("Failure editing metadata at: %s.\\n%s\\n" % (obj.absolute_url(), msg))\n+ if kwargs.get("id", None) is not None:\n+ self._renameObject(obj, id=kwargs["id"].strip())\n self._makeTransactionNote(obj)\n \n @security.public\n def availableMIMETypes(self):\n # Returns a map of mimetypes.\n # Requires mimetype registry from Archetypes >= 1.3.\n- mtr = getToolByName(self, \'mimetypes_registry\')\n+ mtr = getToolByName(self, "mimetypes_registry")\n return mtr.list_mimetypes()\n \n @security.protected(View)\n def getWorkflowChainFor(self, object):\n # Proxy the request for the chain to the workflow tool, as\n # this method is private there.\n- wftool = getToolByName(self, \'portal_workflow\')\n+ wftool = getToolByName(self, "portal_workflow")\n wfs = ()\n try:\n wfs = wftool.getChainFor(object)\n@@ -307,16 +321,15 @@ def getIconFor(self, category, id, default=_marker, context=None):\n # Get an icon for an action, from its icon_expr.\n if context is None:\n context = aq_parent(self)\n- action_chain = f\'{category}/{id}\'\n- if category == \'controlpanel\':\n- tool = getToolByName(context, \'portal_controlpanel\')\n- actions = [ai for ai in tool.listActionInfos() if ai[\'id\'] == id]\n+ action_chain = f"{category}/{id}"\n+ if category == "controlpanel":\n+ tool = getToolByName(context, "portal_controlpanel")\n+ actions = [ai for ai in tool.listActionInfos() if ai["id"] == id]\n else:\n- tool = getToolByName(context, \'portal_actions\')\n- actions = tool.listActionInfos(\n- action_chain=action_chain, object=context)\n+ tool = getToolByName(context, "portal_actions")\n+ actions = tool.listActionInfos(action_chain=action_chain, object=context)\n if len(actions) > 0:\n- icon = actions[0].get(\'icon\', None)\n+ icon = actions[0].get("icon", None)\n if icon:\n return icon\n else:\n@@ -332,11 +345,11 @@ def getReviewStateTitleFor(self, obj):\n # Utility method that gets the workflow state title for the\n # object\'s review_state.\n # Returns None if no review_state found.\n- wf_tool = getToolByName(self, \'portal_workflow\')\n+ wf_tool = getToolByName(self, "portal_workflow")\n wfs = ()\n objstate = None\n try:\n- objstate = wf_tool.getInfoFor(obj, \'review_state\')\n+ objstate = wf_tool.getInfoFor(obj, "review_state")\n wfs = wf_tool.getWorkflowsFor(obj)\n except WorkflowException:\n pass\n@@ -350,8 +363,8 @@ def getReviewStateTitleFor(self, obj):\n @protect(CheckAuthenticator)\n def changeOwnershipOf(self, object, userid, recursive=0, REQUEST=None):\n """Changes the ownership of an object."""\n- membership = getToolByName(self, \'portal_membership\')\n- acl_users = getattr(self, \'acl_users\')\n+ membership = getToolByName(self, "portal_membership")\n+ acl_users = getattr(self, "acl_users")\n user = acl_users.getUserById(userid)\n if user is None:\n # The user could be in the top level acl_users folder in\n@@ -359,42 +372,43 @@ def changeOwnershipOf(self, object, userid, recursive=0, REQUEST=None):\n user = membership.getMemberById(userid)\n if user is None:\n raise KeyError(\n- \'Only retrievable users in this site can be made owners.\')\n+ "Only retrievable users in this site can be made owners."\n+ )\n # Be careful not to pass MemberData to changeOwnership\n user = user.getUser()\n object.changeOwnership(user, recursive)\n \n def fixOwnerRole(object, user_id):\n # Get rid of all other owners\n- owners = object.users_with_local_role(\'Owner\')\n+ owners = object.users_with_local_role("Owner")\n for o in owners:\n roles = list(object.get_local_roles_for_userid(o))\n- roles.remove(\'Owner\')\n+ roles.remove("Owner")\n if roles:\n object.manage_setLocalRoles(o, roles)\n else:\n object.manage_delLocalRoles([o])\n # Fix for 1750\n roles = list(object.get_local_roles_for_userid(user_id))\n- roles.append(\'Owner\')\n+ roles.append("Owner")\n object.manage_setLocalRoles(user_id, roles)\n \n fixOwnerRole(object, user.getId())\n- if base_hasattr(object, \'reindexObject\'):\n+ if base_hasattr(object, "reindexObject"):\n object.reindexObject()\n \n if recursive:\n- catalog_tool = getToolByName(self, \'portal_catalog\')\n- purl = getToolByName(self, \'portal_url\')\n+ catalog_tool = getToolByName(self, "portal_catalog")\n+ purl = getToolByName(self, "portal_url")\n _path = purl.getRelativeContentURL(object)\n subobjects = [\n- b.getObject()\n- for b in catalog_tool(path={\'query\': _path, \'level\': 1})\n+ b.getObject() for b in catalog_tool(path={"query": _path, "level": 1})\n ]\n for obj in subobjects:\n fixOwnerRole(obj, user.getId())\n- if base_hasattr(obj, \'reindexObject\'):\n+ if base_hasattr(obj, "reindexObject"):\n obj.reindexObject()\n+\n changeOwnershipOf = postonly(changeOwnershipOf)\n \n @security.public\n@@ -468,13 +482,13 @@ def bad_chars(self, id):\n @security.public\n def getInheritedLocalRoles(self, context):\n # Returns a tuple with the acquired local roles.\n- portal = getToolByName(context, \'portal_url\').getPortalObject()\n+ portal = getToolByName(context, "portal_url").getPortalObject()\n result = []\n cont = 1\n if portal != context:\n parent = aq_parent(context)\n while cont:\n- if not getattr(parent, \'acl_users\', False):\n+ if not getattr(parent, "acl_users", False):\n break\n userroles = parent.acl_users._getLocalRolesForDisplay(parent)\n for user, roles, role_type, name in userroles:\n@@ -535,13 +549,13 @@ def getDefaultPage(self, obj, request=None):\n # Lookup happens over a view, for which in theory a different\n # implementation may be used.\n if request is None:\n- if hasattr(self, \'REQUEST\'):\n+ if hasattr(self, "REQUEST"):\n request = self.REQUEST\n if request:\n return get_default_page_via_view(obj, request)\n \n @security.public\n- def addPortalMessage(self, message, type=\'info\', request=None):\n+ def addPortalMessage(self, message, type="info", request=None):\n # Call this once or more to add messages to be displayed at the\n # top of the web page.\n \n@@ -627,18 +641,18 @@ def browserDefault(self, obj):\n # and then requests that object, for example for: /, with verb PROPFIND\n # means acquire PROPFIND from the folder and call it\n # its all very odd and WebDAV\'y\n- request = getattr(self, \'REQUEST\', None)\n- if request is not None and \'REQUEST_METHOD\' in request:\n- if request[\'REQUEST_METHOD\'] not in [\'GET\', \'POST\']:\n- return obj, [request[\'REQUEST_METHOD\']]\n+ request = getattr(self, "REQUEST", None)\n+ if request is not None and "REQUEST_METHOD" in request:\n+ if request["REQUEST_METHOD"] not in ["GET", "POST"]:\n+ return obj, [request["REQUEST_METHOD"]]\n # Now back to normal\n \n #\n # 1. Get an attribute or contained object index_html\n #\n- index_obj = getattr(aq_base(obj), \'index_html\', None)\n+ index_obj = getattr(aq_base(obj), "index_html", None)\n if index_obj is not None and not isinstance(index_obj, ComputedAttribute):\n- return obj, [\'index_html\']\n+ return obj, ["index_html"]\n \n #\n # 2. Look for a default_page managed by an IBrowserDefault-implementing\n@@ -656,14 +670,13 @@ def browserDefault(self, obj):\n return obj, [defaultPage]\n # Avoid infinite recursion in the case that the page id == the\n # object id\n- elif (\n- defaultPage != obj.getId()\n- and defaultPage != \'/\'.join(obj.getPhysicalPath())\n+ elif defaultPage != obj.getId() and defaultPage != "/".join(\n+ obj.getPhysicalPath()\n ):\n # For the default_page property, we may get things in the\n # skin layers or with an explicit path - split this path\n # to comply with the __browser_default__() spec\n- return obj, defaultPage.split(\'/\')\n+ return obj, defaultPage.split("/")\n \n # 5. If there is no default page, try IBrowserDefault.getLayout()\n if IBrowserDefault.providedBy(obj):\n@@ -672,12 +685,13 @@ def browserDefault(self, obj):\n browserDefault = queryAdapter(obj, IBrowserDefault)\n if browserDefault is not None:\n default_view_fallback = False\n- if base_hasattr(obj, \'getTypeInfo\'):\n+ if base_hasattr(obj, "getTypeInfo"):\n default_view_fallback = obj.getTypeInfo().default_view_fallback\n layout = browserDefault.getLayout(check_exists=default_view_fallback)\n if layout is None:\n raise AttributeError(\n- "%s has no assigned layout, perhaps it needs an FTI" % obj)\n+ "%s has no assigned layout, perhaps it needs an FTI" % obj\n+ )\n else:\n return obj, [layout]\n \n@@ -691,14 +705,16 @@ def browserDefault(self, obj):\n # action (this applies to old-style folders only, IBrowserDefault is\n # managed explicitly above)\n \n- if base_hasattr(obj, \'getTypeInfo\'):\n+ if base_hasattr(obj, "getTypeInfo"):\n try:\n # XXX: This isn\'t quite right since it assumes the action\n # starts with ${object_url}. Should we raise an error if\n # it doesn\'t?\n- act = obj.getTypeInfo().getActionInfo(\n- \'folder/folderlisting\'\n- )[\'url\'].split(\'/\')[-1]\n+ act = (\n+ obj.getTypeInfo()\n+ .getActionInfo("folder/folderlisting")["url"]\n+ .split("/")[-1]\n+ )\n return obj, [act]\n except ValueError:\n pass\n@@ -711,9 +727,9 @@ def browserDefault(self, obj):\n # XXX: This isn\'t quite right since it assumes the action\n # starts with ${object_url}. Should we raise an error if\n # it doesn\'t?\n- act = obj.getTypeInfo().getActionInfo(\n- \'object/view\'\n- )[\'url\'].split(\'/\')[-1]\n+ act = (\n+ obj.getTypeInfo().getActionInfo("object/view")["url"].split("/")[-1]\n+ )\n return obj, [act]\n except ValueError:\n pass\n@@ -723,8 +739,7 @@ def browserDefault(self, obj):\n #\n \n raise AttributeError(\n- "Failed to get a default page or view_action for %s"\n- % (obj.absolute_url(),)\n+ "Failed to get a default page or view_action for %s" % (obj.absolute_url(),)\n )\n \n @security.public\n@@ -735,10 +750,7 @@ def isStructuralFolder(self, obj):\n INonStructuralFolder to declare that it doesn\'t wish to be treated\n as a folder by the navtree, the tab generation etc.\n """\n- return (\n- obj.isPrincipiaFolderish\n- and not INonStructuralFolder.providedBy(obj)\n- )\n+ return obj.isPrincipiaFolderish and not INonStructuralFolder.providedBy(obj)\n \n @security.public\n @protect(CheckAuthenticator)\n@@ -747,7 +759,7 @@ def acquireLocalRoles(self, obj, status=1, REQUEST=None):\n # behaviour).\n # If it\'s 0, prohibit it (it will allow some kind of local role\n # blacklisting).\n- mt = getToolByName(self, \'portal_membership\')\n+ mt = getToolByName(self, "portal_membership")\n if not mt.checkPermission(ModifyPortalContent, obj):\n raise Unauthorized\n \n@@ -756,18 +768,19 @@ def acquireLocalRoles(self, obj, status=1, REQUEST=None):\n if not status:\n obj.__ac_local_roles_block__ = 1\n else:\n- if getattr(obj, \'__ac_local_roles_block__\', None):\n+ if getattr(obj, "__ac_local_roles_block__", None):\n obj.__ac_local_roles_block__ = None\n \n # Reindex the whole stuff.\n obj.reindexObjectSecurity()\n+\n acquireLocalRoles = postonly(acquireLocalRoles)\n \n @security.public\n def isLocalRoleAcquired(self, obj):\n # Returns local role acquisition blocking status.\n # True if normal, false if blocked.\n- if getattr(obj, \'__ac_local_roles_block__\', None):\n+ if getattr(obj, "__ac_local_roles_block__", None):\n return False\n return True\n \n@@ -775,7 +788,7 @@ def isLocalRoleAcquired(self, obj):\n def getOwnerName(self, obj):\n # Returns the userid of the owner of an object.\n # Note: no docstring please, to avoid reflected XSS.\n- mt = getToolByName(self, \'portal_membership\')\n+ mt = getToolByName(self, "portal_membership")\n if not mt.checkPermission(View, obj):\n raise Unauthorized\n return obj.getOwner().getId()\n@@ -797,24 +810,23 @@ def listMetaTags(self, context):\n # Lists meta tags helper.\n # Creates a mapping of meta tags -> values for the listMetaTags script.\n result = {}\n- mt = getToolByName(self, \'portal_membership\')\n+ mt = getToolByName(self, "portal_membership")\n \n registry = getUtility(IRegistry)\n- site_settings = registry.forInterface(\n- ISiteSchema, prefix="plone", check=False)\n+ site_settings = registry.forInterface(ISiteSchema, prefix="plone", check=False)\n \n try:\n use_all = site_settings.exposeDCMetaTags\n except AttributeError:\n use_all = False\n \n- security_settings = registry.forInterface(\n- ISecuritySchema, prefix=\'plone\')\n- view_about = security_settings.allow_anon_views_about \\\n- or not mt.isAnonymousUser()\n+ security_settings = registry.forInterface(ISecuritySchema, prefix="plone")\n+ view_about = (\n+ security_settings.allow_anon_views_about or not mt.isAnonymousUser()\n+ )\n \n if not use_all:\n- metadata_names = {\'Description\': METADATA_DCNAME[\'Description\']}\n+ metadata_names = {"Description": METADATA_DCNAME["Description"]}\n else:\n metadata_names = METADATA_DCNAME\n for accessor, key in metadata_names.items():\n@@ -823,7 +835,7 @@ def listMetaTags(self, context):\n continue\n \n # short circuit non-special cases\n- if not use_all and accessor not in (\'Description\', \'Subject\'):\n+ if not use_all and accessor not in ("Description", "Subject"):\n continue\n \n method = getattr(aq_inner(context).aq_explicit, accessor, None)\n@@ -839,7 +851,7 @@ def listMetaTags(self, context):\n if not value:\n # No data\n continue\n- if accessor == \'Publisher\' and value == \'No publisher\':\n+ if accessor == "Publisher" and value == "No publisher":\n # No publisher is hardcoded (TODO: still?)\n continue\n \n@@ -852,19 +864,19 @@ def listMetaTags(self, context):\n member = mt.getMemberInfo(userid)\n name = userid\n if member:\n- name = member[\'fullname\'] or userid\n+ name = member["fullname"] or userid\n tmp.append(name)\n value = tmp\n \n if isinstance(value, (list, tuple)):\n # convert a list to a string\n- value = \', \'.join(value)\n+ value = ", ".join(value)\n \n # Special cases\n- if accessor == \'Description\':\n- result[\'description\'] = value\n- elif accessor == \'Subject\':\n- result[\'keywords\'] = value\n+ if accessor == "Description":\n+ result["description"] = value\n+ elif accessor == "Subject":\n+ result["keywords"] = value\n \n if use_all:\n result[key] = value\n@@ -874,7 +886,7 @@ def listMetaTags(self, context):\n \n try:\n effective = context.EffectiveDate()\n- if effective == \'None\':\n+ if effective == "None":\n effective = None\n if effective:\n effective = DateTime(effective)\n@@ -883,7 +895,7 @@ def listMetaTags(self, context):\n \n try:\n expires = context.ExpirationDate()\n- if expires == \'None\':\n+ if expires == "None":\n expires = None\n if expires:\n expires = DateTime(expires)\n@@ -891,20 +903,22 @@ def listMetaTags(self, context):\n expires = None\n \n # Filter out DWIMish artifacts on effective / expiration dates\n- if effective is not None and \\\n- effective > FLOOR_DATE and \\\n- effective != created:\n+ if (\n+ effective is not None\n+ and effective > FLOOR_DATE\n+ and effective != created\n+ ):\n eff_str = effective.Date()\n else:\n- eff_str = \'\'\n+ eff_str = ""\n \n if expires is not None and expires < CEILING_DATE:\n exp_str = expires.Date()\n else:\n- exp_str = \'\'\n+ exp_str = ""\n \n if eff_str or exp_str:\n- result[\'DC.date.valid_range\'] = f\'{eff_str} - {exp_str}\'\n+ result["DC.date.valid_range"] = f"{eff_str} - {exp_str}"\n \n return result\n \n@@ -925,7 +939,7 @@ def getUserFriendlyTypes(self, typesList=None):\n search_settings = registry.forInterface(ISearchSchema, prefix="plone")\n blacklistedTypes = search_settings.types_not_searched\n \n- ttool = getToolByName(self, \'portal_types\')\n+ ttool = getToolByName(self, "portal_types")\n tool_types = ttool.keys()\n if typesList:\n types = [t for t in typesList if t in tool_types]\n@@ -959,7 +973,7 @@ def getMethodAliases(self, typeInfo):\n # Given an FTI, return the dict of method aliases defined on that\n # FTI. If there are no method aliases (i.e. this FTI doesn\'t support\n # it), return None.\n- getMethodAliases = getattr(typeInfo, \'getMethodAliases\', None)\n+ getMethodAliases = getattr(typeInfo, "getMethodAliases", None)\n if getMethodAliases is not None and safe_callable(getMethodAliases):\n return getMethodAliases()\n return None\n@@ -976,12 +990,12 @@ def deleteObjectsByPaths(self, paths, handle_errors=True, REQUEST=None):\n warnings.warn(\n "Use plone.api.content.delete instead of deleteObjectsByPaths. "\n "This method no longer does link integrity checks. Will be removed in Plone 7",\n- DeprecationWarning\n+ DeprecationWarning,\n )\n failure = {}\n success = []\n # use the portal for traversal in case we have relative paths\n- portal = getToolByName(self, \'portal_url\').getPortalObject()\n+ portal = getToolByName(self, "portal_url").getPortalObject()\n traverse = portal.restrictedTraverse\n for path in paths:\n # Skip and note any errors\n@@ -991,7 +1005,7 @@ def deleteObjectsByPaths(self, paths, handle_errors=True, REQUEST=None):\n obj = traverse(path)\n obj_parent = aq_parent(aq_inner(obj))\n obj_parent.manage_delObjects([obj.getId()])\n- success.append(f\'{obj.getId()} ({path})\')\n+ success.append(f"{obj.getId()} ({path})")\n except ConflictError:\n raise\n except Exception as e:\n@@ -1001,17 +1015,18 @@ def deleteObjectsByPaths(self, paths, handle_errors=True, REQUEST=None):\n log_exc()\n else:\n raise\n- transaction_note(\'Deleted %s\' % (\', \'.join(success)))\n+ transaction_note("Deleted %s" % (", ".join(success)))\n return success, failure\n \n @security.public\n @protect(CheckAuthenticator)\n- def renameObjectsByPaths(self, paths, new_ids, new_titles,\n- handle_errors=True, REQUEST=None):\n+ def renameObjectsByPaths(\n+ self, paths, new_ids, new_titles, handle_errors=True, REQUEST=None\n+ ):\n failure = {}\n success = {}\n # use the portal for traversal in case we have relative paths\n- portal = getToolByName(self, \'portal_url\').getPortalObject()\n+ portal = getToolByName(self, "portal_url").getPortalObject()\n traverse = portal.restrictedTraverse\n for i, path in enumerate(paths):\n new_id = new_ids[i]\n@@ -1025,9 +1040,7 @@ def renameObjectsByPaths(self, paths, new_ids, new_titles,\n change_title = new_title and title != new_title\n changed = False\n if change_title:\n- getSecurityManager().validate(\n- obj, obj, \'setTitle\', obj.setTitle\n- )\n+ getSecurityManager().validate(obj, obj, "setTitle", obj.setTitle)\n obj.setTitle(new_title)\n notify(ObjectModifiedEvent(obj))\n changed = True\n@@ -1049,8 +1062,10 @@ def renameObjectsByPaths(self, paths, new_ids, new_titles,\n failure[path] = e\n else:\n raise\n- transaction_note(\'Renamed %s\' % str(success.keys()))\n+ transaction_note("Renamed %s" % str(success.keys()))\n return success, failure\n+\n renameObjectsByPaths = postonly(renameObjectsByPaths)\n \n+\n InitializeClass(PloneTool)\ndiff --git a/Products/CMFPlone/Portal.py b/Products/CMFPlone/Portal.py\nindex 15541f38b8..150e57930e 100644\n--- a/Products/CMFPlone/Portal.py\n+++ b/Products/CMFPlone/Portal.py\n@@ -47,10 +47,10 @@\n \n @implementer(IPloneSiteRoot, ISiteRoot, ISyndicatable, IObjectManagerSite)\n class PloneSite(Container, SkinnableObjectManager, UniqueObject):\n- """ The Plone site object. """\n+ """The Plone site object."""\n \n security = ClassSecurityInfo()\n- meta_type = portal_type = \'Plone Site\'\n+ meta_type = portal_type = "Plone Site"\n \n # Ensure certain attributes come from the correct base class.\n _checkId = SkinnableObjectManager._checkId\n@@ -80,9 +80,7 @@ def __delattr__(self, name):\n \n # Removes the \'Components Folder\'\n \n- manage_options = (\n- Container.manage_options[:2] +\n- Container.manage_options[3:])\n+ manage_options = Container.manage_options[:2] + Container.manage_options[3:]\n \n __ac_permissions__ = (\n (AccessContentsInformation, ()),\n@@ -96,35 +94,42 @@ def __delattr__(self, name):\n (AddPortalFolders, ()),\n (ListPortalMembers, ()),\n (ReplyToItem, ()),\n- (View, (\'isEffective\',)),\n- (ModifyPortalContent, (\'manage_cutObjects\', \'manage_pasteObjects\',\n- \'manage_renameForm\', \'manage_renameObject\',\n- \'manage_renameObjects\')))\n+ (View, ("isEffective",)),\n+ (\n+ ModifyPortalContent,\n+ (\n+ "manage_cutObjects",\n+ "manage_pasteObjects",\n+ "manage_renameForm",\n+ "manage_renameObject",\n+ "manage_renameObjects",\n+ ),\n+ ),\n+ )\n \n # Switch off ZMI ordering interface as it assumes a slightly\n # different functionality\n has_order_support = 0\n- management_page_charset = \'utf-8\'\n- _default_sort_key = \'id\'\n+ management_page_charset = "utf-8"\n+ _default_sort_key = "id"\n _properties = (\n- {\'id\': \'title\', \'type\': \'string\', \'mode\': \'w\'},\n- {\'id\': \'description\', \'type\': \'text\', \'mode\': \'w\'},\n+ {"id": "title", "type": "string", "mode": "w"},\n+ {"id": "description", "type": "text", "mode": "w"},\n )\n- title = \'\'\n- description = \'\'\n- icon = \'misc_/CMFPlone/tool.gif\'\n+ title = ""\n+ description = ""\n+ icon = "misc_/CMFPlone/tool.gif"\n \n # From PortalObjectBase\n- def __init__(self, id, title=\'\'):\n+ def __init__(self, id, title=""):\n super().__init__(id, title=title)\n- components = PersistentComponents(\'++etc++site\')\n+ components = PersistentComponents("++etc++site")\n components.__parent__ = self\n self.setSiteManager(components)\n \n # From PortalObjectBase\n def __before_publishing_traverse__(self, arg1, arg2=None):\n- """ Pre-traversal hook.\n- """\n+ """Pre-traversal hook."""\n # XXX hack around a bug(?) in BeforeTraverse.MultiHook\n REQUEST = arg2 or arg1\n \n@@ -143,35 +148,39 @@ def tpValues(self):\n # Return a list of subobjects, used by ZMI tree tag (and only there).\n # see also https://github.com/plone/Products.CMFPlone/issues/3323\n return sorted(\n- (obj for obj in self.objectValues() if getattr(aq_base(obj), \'isPrincipiaFolderish\', False)),\n+ (\n+ obj\n+ for obj in self.objectValues()\n+ if getattr(aq_base(obj), "isPrincipiaFolderish", False)\n+ ),\n key=lambda obj: obj.getId(),\n )\n \n def __browser_default__(self, request):\n- """ Set default so we can return whatever we want instead\n- of index_html """\n- return getToolByName(self, \'plone_utils\').browserDefault(self)\n+ """Set default so we can return whatever we want instead\n+ of index_html"""\n+ return getToolByName(self, "plone_utils").browserDefault(self)\n \n def index_html(self):\n- """ Acquire if not present. """\n- request = getattr(self, \'REQUEST\', None)\n+ """Acquire if not present."""\n+ request = getattr(self, "REQUEST", None)\n if (\n request is not None\n- and \'REQUEST_METHOD\' in request\n+ and "REQUEST_METHOD" in request\n and request.maybe_webdav_client\n ):\n- method = request[\'REQUEST_METHOD\']\n- if bbb.HAS_ZSERVER and method in (\'PUT\', ):\n+ method = request["REQUEST_METHOD"]\n+ if bbb.HAS_ZSERVER and method in ("PUT",):\n # Very likely a WebDAV client trying to create something\n- result = NullResource(self, \'index_html\')\n- setattr(result, \'__replaceable__\', REPLACEABLE)\n+ result = NullResource(self, "index_html")\n+ setattr(result, "__replaceable__", REPLACEABLE)\n return result\n- elif method not in (\'GET\', \'HEAD\', \'POST\'):\n- raise AttributeError(\'index_html\')\n+ elif method not in ("GET", "HEAD", "POST"):\n+ raise AttributeError("index_html")\n # Acquire from skin.\n- _target = self.__getattr__(\'index_html\')\n+ _target = self.__getattr__("index_html")\n result = aq_base(_target).__of__(self)\n- setattr(result, \'__replaceable__\', REPLACEABLE)\n+ setattr(result, "__replaceable__", REPLACEABLE)\n return result\n \n index_html = ComputedAttribute(index_html, 1)\n@@ -179,8 +188,7 @@ def index_html(self):\n def manage_beforeDelete(self, container, item):\n # Should send out an Event before Site is being deleted.\n self.removal_inprogress = 1\n- PloneSite.inheritedAttribute(\'manage_beforeDelete\')(self, container,\n- item)\n+ PloneSite.inheritedAttribute("manage_beforeDelete")(self, container, item)\n \n @security.protected(permissions.DeleteObjects)\n def manage_delObjects(self, ids=None, REQUEST=None):\n@@ -192,12 +200,11 @@ def manage_delObjects(self, ids=None, REQUEST=None):\n for id in ids:\n item = self._getOb(id)\n if not _checkPermission(permissions.DeleteObjects, item):\n- raise Unauthorized(\n- "Do not have permissions to remove this object")\n+ raise Unauthorized("Do not have permissions to remove this object")\n return PortalObjectBase.manage_delObjects(self, ids, REQUEST=REQUEST)\n \n def view(self):\n- """ Ensure that we get a plain view of the object, via a delegation to\n+ """Ensure that we get a plain view of the object, via a delegation to\n __call__(), which is defined in BrowserDefaultMixin\n """\n return self()\ndiff --git a/Products/CMFPlone/PropertiesTool.py b/Products/CMFPlone/PropertiesTool.py\nindex f0ea227709..4cc6feb44e 100644\n--- a/Products/CMFPlone/PropertiesTool.py\n+++ b/Products/CMFPlone/PropertiesTool.py\n@@ -23,59 +23,56 @@\n \n @implementer(IPropertiesTool)\n class PropertiesTool(PloneBaseTool, Folder, UniqueObject):\n- """ Plone properties tool\n- """\n+ """Plone properties tool"""\n \n- id = \'portal_properties\'\n- toolicon = \'skins/plone_images/topic_icon.png\'\n+ id = "portal_properties"\n+ toolicon = "skins/plone_images/topic_icon.png"\n \n- meta_type = \'Plone Properties Tool\'\n- meta_types = ((\n- {\'name\': \'Plone Property Sheet\',\n- \'action\': \'manage_addPropertySheetForm\'},\n- ))\n+ meta_type = "Plone Properties Tool"\n+ meta_types = (\n+ {"name": "Plone Property Sheet", "action": "manage_addPropertySheetForm"},\n+ )\n \n- manage_options = ((Folder.manage_options[0], ) +\n- ({\'label\': \'Overview\',\n- \'action\': \'manage_overview\'},) +\n- SimpleItem.manage_options)\n+ manage_options = (\n+ (Folder.manage_options[0],)\n+ + ({"label": "Overview", "action": "manage_overview"},)\n+ + SimpleItem.manage_options\n+ )\n \n- manage_addPropertySheetForm = PageTemplateFile(\'www/addPropertySheet\',\n- globals())\n+ manage_addPropertySheetForm = PageTemplateFile("www/addPropertySheet", globals())\n \n security = ClassSecurityInfo()\n \n- security.declareProtected(ManagePortal, \'manage_overview\')\n- manage_overview = DTMLFile(\'explainPropertiesTool\', WWW_DIR)\n+ security.declareProtected(ManagePortal, "manage_overview")\n+ manage_overview = DTMLFile("explainPropertiesTool", WWW_DIR)\n \n def all_meta_types(self, interfaces=None):\n return self.meta_types\n \n- security.declareProtected(ManagePortal, \'addPropertySheet\')\n+ security.declareProtected(ManagePortal, "addPropertySheet")\n \n- def addPropertySheet(self, id, title=\'\', propertysheet=None):\n+ def addPropertySheet(self, id, title="", propertysheet=None):\n # Add a new PropertySheet.\n o = SimpleItemWithProperties(id, title)\n \n # copy the propertysheet values onto the new instance\n if propertysheet is not None:\n- if not hasattr(propertysheet, \'propertyIds\'):\n- raise TypeError(\'propertysheet needs to be a PropertyManager\')\n+ if not hasattr(propertysheet, "propertyIds"):\n+ raise TypeError("propertysheet needs to be a PropertyManager")\n \n for property in propertysheet.propertyMap():\n- pid = property.get(\'id\')\n- ptype = property.get(\'type\')\n+ pid = property.get("id")\n+ ptype = property.get("type")\n pvalue = propertysheet.getProperty(pid)\n if not hasattr(o, pid):\n o._setProperty(pid, pvalue, ptype)\n \n self._setObject(id, o)\n \n- security.declareProtected(ManagePortal, \'manage_addPropertySheet\')\n+ security.declareProtected(ManagePortal, "manage_addPropertySheet")\n \n- def manage_addPropertySheet(self, id, title=\'\',\n- propertysheet=None, REQUEST=None):\n- """ Add a instance of a Property Sheet if handed a\n+ def manage_addPropertySheet(self, id, title="", propertysheet=None, REQUEST=None):\n+ """Add a instance of a Property Sheet if handed a\n propertysheet put the properties into new propertysheet.\n """\n self.addPropertySheet(id, title, propertysheet)\n@@ -86,14 +83,14 @@ def manage_addPropertySheet(self, id, title=\'\',\n #\n # \'portal_properties\' interface methods\n #\n- security.declareProtected(ManagePortal, \'editProperties\')\n+ security.declareProtected(ManagePortal, "editProperties")\n \n def editProperties(self, props):\n # Change portal settings.\n aq_parent(aq_inner(self)).manage_changeProperties(props)\n- if hasattr(self, \'propertysheets\'):\n+ if hasattr(self, "propertysheets"):\n ps = self.propertysheets\n- if hasattr(ps, \'props\'):\n+ if hasattr(ps, "props"):\n ps.props.manage_changeProperties(props)\n \n def title(self):\n@@ -106,7 +103,6 @@ def title(self):\n def smtp_server(self):\n return getUtility(IMailHost).smtp_host\n \n-\n @deprecate(\n "The portal portal_properties tool will be removed in Plone 6.1. "\n "Use the portal_registry instead. "\n@@ -121,20 +117,19 @@ def hasProperty(self, id):\n \n \n @implementer(ISimpleItemWithProperties)\n-class SimpleItemWithProperties (PropertyManager, SimpleItem):\n+class SimpleItemWithProperties(PropertyManager, SimpleItem):\n """\n A common base class for objects with configurable\n properties in a fixed schema.\n """\n \n- def __init__(self, id, title=\'\'):\n+ def __init__(self, id, title=""):\n self.id = id\n self.title = title\n \n- meta_type = \'Plone Property Sheet\'\n+ meta_type = "Plone Property Sheet"\n \n- manage_options = (PropertyManager.manage_options\n- + SimpleItem.manage_options)\n+ manage_options = PropertyManager.manage_options + SimpleItem.manage_options\n \n @deprecate(\n "The portal portal_properties tool will be removed in Plone 6.1. "\ndiff --git a/Products/CMFPlone/RegistrationTool.py b/Products/CMFPlone/RegistrationTool.py\nindex 1e2fc043c8..cc41fd290d 100644\n--- a/Products/CMFPlone/RegistrationTool.py\n+++ b/Products/CMFPlone/RegistrationTool.py\n@@ -45,17 +45,17 @@\n # - remove \'1\', \'l\', and \'I\' to avoid confusion\n # - remove \'0\', \'O\', and \'Q\' to avoid confusion\n # - remove vowels to avoid spelling words\n-invalid_password_chars = [\'a\', \'e\', \'i\', \'o\', \'u\', \'y\', \'l\', \'q\']\n+invalid_password_chars = ["a", "e", "i", "o", "u", "y", "l", "q"]\n \n \n def getValidPasswordChars():\n password_chars = []\n for i in range(0, 26):\n- if chr(ord(\'a\') + i) not in invalid_password_chars:\n- password_chars.append(chr(ord(\'a\') + i))\n- password_chars.append(chr(ord(\'A\') + i))\n+ if chr(ord("a") + i) not in invalid_password_chars:\n+ password_chars.append(chr(ord("a") + i))\n+ password_chars.append(chr(ord("A") + i))\n for i in range(2, 10):\n- password_chars.append(chr(ord(\'0\') + i))\n+ password_chars.append(chr(ord("0") + i))\n return password_chars\n \n \n@@ -70,7 +70,7 @@ def get_member_by_login_name(context, login_name, raise_exceptions=True):\n \n If raise_exceptions is False, we silently return None.\n """\n- membership = getToolByName(context, \'portal_membership\')\n+ membership = getToolByName(context, "portal_membership")\n # First the easy case: it may be a userid after all.\n member = membership.getMemberById(login_name)\n \n@@ -78,45 +78,46 @@ def get_member_by_login_name(context, login_name, raise_exceptions=True):\n return member\n \n # Try to find this user via the login name.\n- acl = getToolByName(context, \'acl_users\')\n- userids = [user.get(\'userid\') for user in\n- acl.searchUsers(name=login_name, exact_match=True)\n- if user.get(\'userid\')]\n+ acl = getToolByName(context, "acl_users")\n+ userids = [\n+ user.get("userid")\n+ for user in acl.searchUsers(name=login_name, exact_match=True)\n+ if user.get("userid")\n+ ]\n if len(userids) == 1:\n userid = userids[0]\n member = membership.getMemberById(userid)\n elif len(userids) > 1:\n if raise_exceptions:\n- raise ValueError(\n- _(\'Multiple users found with the same login name.\'))\n+ raise ValueError(_("Multiple users found with the same login name."))\n if member is None and raise_exceptions:\n- raise ValueError(_(\'The username you entered could not be found.\'))\n+ raise ValueError(_("The username you entered could not be found."))\n return member\n \n+\n # seed the random number generator\n random.seed()\n \n \n class RegistrationTool(PloneBaseTool, BaseTool):\n- """ Manage through-the-web signup policies.\n- """\n+ """Manage through-the-web signup policies."""\n \n- meta_type = \'Plone Registration Tool\'\n+ meta_type = "Plone Registration Tool"\n security = ClassSecurityInfo()\n- toolicon = \'skins/plone_images/pencil_icon.png\'\n+ toolicon = "skins/plone_images/pencil_icon.png"\n plone_tool = 1\n md5key = None\n _v_md5base = None\n- default_member_id_pattern = r\'^\\w[\\w\\.\\-@]+\\w$\'\n+ default_member_id_pattern = r"^\\w[\\w\\.\\-@]+\\w$"\n _ALLOWED_MEMBER_ID_PATTERN = re.compile(default_member_id_pattern)\n \n def __init__(self):\n- if hasattr(BaseTool, \'__init__\'):\n+ if hasattr(BaseTool, "__init__"):\n BaseTool.__init__(self)\n # build and persist an MD5 key\n- self.md5key = \'\'\n+ self.md5key = ""\n for i in range(0, 20):\n- self.md5key += chr(ord(\'a\') + random.randint(0, 26))\n+ self.md5key += chr(ord("a") + random.randint(0, 26))\n \n def _md5base(self):\n if self._v_md5base is None:\n@@ -127,13 +128,15 @@ def _md5base(self):\n return self._v_md5base\n \n def _getValidEmailAddress(self, member):\n- email = member.getProperty(\'email\')\n+ email = member.getProperty("email")\n \n # assert that we can actually get an email address, otherwise\n # the template will be made with a blank To:, this is bad\n if email is None:\n- msg = _(\'No email address is registered for member: \'\n- \'${member_id}\', mapping={\'member_id\': member.getId()})\n+ msg = _(\n+ "No email address is registered for member: " "${member_id}",\n+ mapping={"member_id": member.getId()},\n+ )\n raise ValueError(msg)\n \n checkEmailAddress(email)\n@@ -150,7 +153,7 @@ def getPassword(self, length=5, s=None):\n global password_chars, md5base\n \n if s is None:\n- password = \'\'\n+ password = ""\n nchars = len(password_chars)\n for i in range(0, length):\n password += password_chars[random.randint(0, nchars - 1)]\n@@ -161,14 +164,14 @@ def getPassword(self, length=5, s=None):\n m = self._md5base().copy()\n m.update(s)\n d = m.digest() # compute md5(md5key + s)\n- assert(len(d) >= length)\n- password = \'\'\n+ assert len(d) >= length\n+ password = ""\n nchars = len(password_chars)\n for idx in range(0, length):\n password += password_chars[d[idx] % nchars]\n return password\n \n- security.declarePublic(\'isValidEmail\')\n+ security.declarePublic("isValidEmail")\n \n def isValidEmail(self, email):\n # Checks for valid email.\n@@ -184,20 +187,21 @@ def isValidEmail(self, email):\n #\n # \'portal_registration\' interface\n #\n- security.declarePublic(\'testPasswordValidity\')\n+ security.declarePublic("testPasswordValidity")\n \n def testPasswordValidity(self, password, confirm=None):\n # Verify that the password satisfies the portal\'s requirements.\n #\n # o If the password is valid, return None.\n # o If not, return a string explaining why.\n- err = self.pasValidation(\'password\', password)\n+ err = self.pasValidation("password", password)\n if err:\n return err\n \n if confirm is not None and confirm != password:\n- return _(\'Your password and confirmation did not match. \'\n- \'Please try again.\')\n+ return _(\n+ "Your password and confirmation did not match. " "Please try again."\n+ )\n return None\n \n def pasValidation(self, property, password):\n@@ -211,25 +215,27 @@ def pasValidation(self, property, password):\n err = ""\n for validator_id, validator in validators:\n user = None\n- set_id = \'\'\n+ set_id = ""\n set_info = {property: password}\n errors = validator.validateUserInfo(user, set_id, set_info)\n # We will assume that the PASPlugin returns a list of error\n # strings that have already been translated.\n # We just need to join them in an i18n friendly way\n- for error in [info[\'error\'] for info in errors if info[\'id\'] == property]:\n+ for error in [info["error"] for info in errors if info["id"] == property]:\n if not err:\n err = error\n else:\n- msgid = _(\'${sentances}. ${sentance}\',\n- mapping={\'sentances\': err, \'sentance\': error})\n+ msgid = _(\n+ "${sentances}. ${sentance}",\n+ mapping={"sentances": err, "sentance": error},\n+ )\n err = self.translate(msgid)\n if not err:\n return None\n else:\n return err\n \n- security.declarePublic(\'testPropertiesValidity\')\n+ security.declarePublic("testPropertiesValidity")\n \n def testPropertiesValidity(self, props, member=None):\n # Verify that the properties supplied satisfy portal\'s requirements.\n@@ -240,54 +246,54 @@ def testPropertiesValidity(self, props, member=None):\n # We also check if the email property is writable before verifying it.\n \n if member is None: # New member.\n-\n- username = props.get(\'username\', \'\')\n+ username = props.get("username", "")\n if not username:\n- return _(\'You must enter a valid name.\')\n+ return _("You must enter a valid name.")\n \n if not self.isMemberIdAllowed(username):\n- return _(\'The login name you selected is already in use or \'\n- \'is not valid. Please choose another.\')\n+ return _(\n+ "The login name you selected is already in use or "\n+ "is not valid. Please choose another."\n+ )\n \n- email = props.get(\'email\')\n+ email = props.get("email")\n if email is None:\n- return _(\'You must enter an email address.\')\n+ return _("You must enter an email address.")\n \n try:\n checkEmailAddress(email)\n except EmailAddressInvalid:\n- return _(\'You must enter a valid email address.\')\n+ return _("You must enter a valid email address.")\n \n else: # Existing member.\n- if not hasattr(member, \'canWriteProperty\') or \\\n- member.canWriteProperty(\'email\'):\n-\n- email = props.get(\'email\')\n+ if not hasattr(member, "canWriteProperty") or member.canWriteProperty(\n+ "email"\n+ ):\n+ email = props.get("email")\n \n if email is not None:\n-\n try:\n checkEmailAddress(email)\n except EmailAddressInvalid:\n- return _(\'You must enter a valid email address.\')\n+ return _("You must enter a valid email address.")\n \n # Not allowed to clear an existing non-empty email.\n- existing = member.getProperty(\'email\')\n+ existing = member.getProperty("email")\n \n- if existing and email == \'\':\n- return _(\'You must enter a valid email address.\')\n+ if existing and email == "":\n+ return _("You must enter a valid email address.")\n \n return None\n \n- security.declareProtected(AddPortalMember, \'isMemberIdAllowed\')\n+ security.declareProtected(AddPortalMember, "isMemberIdAllowed")\n \n def isMemberIdAllowed(self, id):\n- if len(id) < 1 or id == \'Anonymous User\':\n+ if len(id) < 1 or id == "Anonymous User":\n return 0\n if not self._ALLOWED_MEMBER_ID_PATTERN.match(id):\n return 0\n \n- pas = getToolByName(self, \'acl_users\')\n+ pas = getToolByName(self, "acl_users")\n if IPluggableAuthService.providedBy(pas):\n results = pas.searchPrincipals(id=id, exact_match=True)\n if results:\n@@ -297,30 +303,28 @@ def isMemberIdAllowed(self, id):\n if hasattr(aq_base(parent), "acl_users"):\n parent = parent.acl_users\n if IPluggableAuthService.providedBy(parent):\n- if parent.searchPrincipals(id=id,\n- exact_match=True):\n+ if parent.searchPrincipals(id=id, exact_match=True):\n return 0\n # When email addresses are used as logins, we need to check\n # if there are any users with the requested login.\n registry = getUtility(IRegistry)\n- security_settings = registry.forInterface(\n- ISecuritySchema, prefix=\'plone\')\n+ security_settings = registry.forInterface(ISecuritySchema, prefix="plone")\n \n if security_settings.use_email_as_login:\n results = pas.searchUsers(name=id, exact_match=True)\n if results:\n return 0\n else:\n- membership = getToolByName(self, \'portal_membership\')\n+ membership = getToolByName(self, "portal_membership")\n if membership.getMemberById(id) is not None:\n return 0\n- groups = getToolByName(self, \'portal_groups\')\n+ groups = getToolByName(self, "portal_groups")\n if groups.getGroupById(id) is not None:\n return 0\n \n return 1\n \n- security.declarePublic(\'generatePassword\')\n+ security.declarePublic("generatePassword")\n \n def generatePassword(self):\n # Generate a strong default password. The user never gets sent\n@@ -328,52 +332,49 @@ def generatePassword(self):\n \n return self.getPassword(56)\n \n- security.declarePublic(\'generateResetCode\')\n+ security.declarePublic("generateResetCode")\n \n def generateResetCode(self, salt, length=14):\n # Generates a reset code which is guaranteed to return the\n # same value for a given length and salt, every time.\n return self.getPassword(length, salt)\n \n- security.declarePublic(\'mailPassword\')\n+ security.declarePublic("mailPassword")\n \n def mailPassword(self, login, REQUEST, immediate=False):\n- """ Wrapper around mailPassword """\n- membership = getToolByName(self, \'portal_membership\')\n- if not membership.checkPermission(\'Mail forgotten password\', self):\n- raise Unauthorized(\n- _("Mailing forgotten passwords has been disabled."))\n+ """Wrapper around mailPassword"""\n+ membership = getToolByName(self, "portal_membership")\n+ if not membership.checkPermission("Mail forgotten password", self):\n+ raise Unauthorized(_("Mailing forgotten passwords has been disabled."))\n \n- utils = getToolByName(self, \'plone_utils\')\n+ utils = getToolByName(self, "plone_utils")\n member = get_member_by_login_name(self, login, raise_exceptions=False)\n \n if member is None:\n- raise ValueError(\n- _(\'The username you entered could not be found.\'))\n+ raise ValueError(_("The username you entered could not be found."))\n \n # Make sure the user is allowed to set the password.\n- portal = getToolByName(self, \'portal_url\').getPortalObject()\n- acl_users = getToolByName(portal, \'acl_users\')\n+ portal = getToolByName(self, "portal_url").getPortalObject()\n+ acl_users = getToolByName(portal, "acl_users")\n user = acl_users.getUserById(member.getId())\n orig_sm = getSecurityManager()\n try:\n newSecurityManager(REQUEST or self.REQUEST, user)\n tmp_sm = getSecurityManager()\n if not tmp_sm.checkPermission(SetOwnPassword, portal):\n- raise Unauthorized(\n- _("Mailing forgotten passwords has been disabled."))\n+ raise Unauthorized(_("Mailing forgotten passwords has been disabled."))\n finally:\n setSecurityManager(orig_sm)\n \n # assert that we can actually get an email address, otherwise\n # the template will be made with a blank To:, this is bad\n- email = member.getProperty(\'email\')\n+ email = member.getProperty("email")\n if not email:\n- raise ValueError(_(\'That user does not have an email address.\'))\n+ raise ValueError(_("That user does not have an email address."))\n else:\n # add the single email address\n if not utils.validateSingleEmailAddress(email):\n- raise ValueError(_(\'The email address did not validate.\'))\n+ raise ValueError(_("The email address did not validate."))\n check, msg = _checkEmail(email)\n if not check:\n raise ValueError(msg)\n@@ -381,98 +382,123 @@ def mailPassword(self, login, REQUEST, immediate=False):\n # Rather than have the template try to use the mailhost, we will\n # render the message ourselves and send it from here (where we\n # don\'t need to worry about \'UseMailHost\' permissions).\n- reset_tool = getToolByName(self, \'portal_password_reset\')\n+ reset_tool = getToolByName(self, "portal_password_reset")\n reset = reset_tool.requestReset(member.getId())\n \n registry = getUtility(IRegistry)\n- encoding = registry.get(\'plone.email_charset\', \'utf-8\')\n+ encoding = registry.get("plone.email_charset", "utf-8")\n mail_password_template = getMultiAdapter(\n- (self, self.REQUEST), name=\'mail_password_template\')\n+ (self, self.REQUEST), name="mail_password_template"\n+ )\n mail_text = mail_password_template(\n- member=member, reset=reset,\n- password=member.getPassword(), charset=encoding)\n+ member=member, reset=reset, password=member.getPassword(), charset=encoding\n+ )\n # The mail headers are not properly encoded we need to extract\n # them and let MailHost manage the encoding.\n message_obj = message_from_string(mail_text.strip())\n- subject = message_obj[\'Subject\']\n- m_to = message_obj[\'To\']\n- m_from = message_obj[\'From\']\n- msg_type = message_obj.get(\'Content-Type\', \'text/plain\')\n- host = getToolByName(self, \'MailHost\')\n+ subject = message_obj["Subject"]\n+ m_to = message_obj["To"]\n+ m_from = message_obj["From"]\n+ msg_type = message_obj.get("Content-Type", "text/plain")\n+ host = getToolByName(self, "MailHost")\n try:\n- host.send(mail_text, m_to, m_from, subject=subject,\n- charset=encoding, immediate=immediate,\n- msg_type=msg_type)\n+ host.send(\n+ mail_text,\n+ m_to,\n+ m_from,\n+ subject=subject,\n+ charset=encoding,\n+ immediate=immediate,\n+ msg_type=msg_type,\n+ )\n except SMTPRecipientsRefused:\n # Don\'t disclose email address on failure\n- raise SMTPRecipientsRefused(\n- _(\'Recipient address rejected by server.\'))\n+ raise SMTPRecipientsRefused(_("Recipient address rejected by server."))\n except SMTPException as e:\n- raise(e)\n+ raise (e)\n mail_password_response = getMultiAdapter(\n- (self, self.REQUEST), name=\'mail_password_response\')\n+ (self, self.REQUEST), name="mail_password_response"\n+ )\n return mail_password_response()\n \n- security.declarePublic(\'registeredNotify\')\n+ security.declarePublic("registeredNotify")\n+\n def registeredNotify(self, new_member_id):\n # Wrapper around registeredNotify.\n- membership = getToolByName(self, \'portal_membership\')\n- utils = getToolByName(self, \'plone_utils\')\n+ membership = getToolByName(self, "portal_membership")\n+ utils = getToolByName(self, "plone_utils")\n member = membership.getMemberById(new_member_id)\n- email = member.getProperty(\'email\')\n+ email = member.getProperty("email")\n \n if member and email:\n # add the single email address\n if not utils.validateSingleEmailAddress(email):\n- raise ValueError(_(\'The email address did not validate.\'))\n+ raise ValueError(_("The email address did not validate."))\n \n try:\n checkEmailAddress(email)\n except EmailAddressInvalid:\n- raise ValueError(_(\'The email address did not validate.\'))\n+ raise ValueError(_("The email address did not validate."))\n \n- pwrt = getToolByName(self, \'portal_password_reset\')\n+ pwrt = getToolByName(self, "portal_password_reset")\n reset = pwrt.requestReset(new_member_id)\n \n # Rather than have the template try to use the mailhost, we will\n # render the message ourselves and send it from here (where we\n # don\'t need to worry about \'UseMailHost\' permissions).\n registry = getUtility(IRegistry)\n- encoding = registry.get(\'plone.email_charset\', \'utf-8\')\n+ encoding = registry.get("plone.email_charset", "utf-8")\n registered_notify_template = getMultiAdapter(\n- (self, self.REQUEST), name=\'registered_notify_template\')\n+ (self, self.REQUEST), name="registered_notify_template"\n+ )\n mail_text = registered_notify_template(\n- member=member, reset=reset, email=email, charset=encoding)\n+ member=member, reset=reset, email=email, charset=encoding\n+ )\n \n # The mail headers are not properly encoded we need to extract\n # them and let MailHost manage the encoding.\n message_obj = message_from_string(mail_text.strip())\n- subject = message_obj[\'Subject\']\n- m_to = message_obj[\'To\']\n- m_from = message_obj[\'From\']\n- msg_type = message_obj.get(\'Content-Type\', \'text/plain\')\n- host = getToolByName(self, \'MailHost\')\n- host.send(mail_text, m_to, m_from, subject=subject, charset=encoding,\n- msg_type=msg_type, immediate=True)\n+ subject = message_obj["Subject"]\n+ m_to = message_obj["To"]\n+ m_from = message_obj["From"]\n+ msg_type = message_obj.get("Content-Type", "text/plain")\n+ host = getToolByName(self, "MailHost")\n+ host.send(\n+ mail_text,\n+ m_to,\n+ m_from,\n+ subject=subject,\n+ charset=encoding,\n+ msg_type=msg_type,\n+ immediate=True,\n+ )\n \n mail_password_response = getMultiAdapter(\n- (self, self.REQUEST), name=\'mail_password_response\')\n+ (self, self.REQUEST), name="mail_password_response"\n+ )\n return mail_password_response()\n \n- security.declareProtected(ManagePortal, \'editMember\')\n+ security.declareProtected(ManagePortal, "editMember")\n \n @postonly\n @protect(CheckAuthenticator)\n- def editMember(self, member_id, properties=None, password=None,\n- roles=None, domains=None, REQUEST=None):\n- """ Edit a user\'s properties and security settings\n+ def editMember(\n+ self,\n+ member_id,\n+ properties=None,\n+ password=None,\n+ roles=None,\n+ domains=None,\n+ REQUEST=None,\n+ ):\n+ """Edit a user\'s properties and security settings\n \n o Checks should be done before this method is called using\n testPropertiesValidity and testPasswordValidity\n """\n # XXX: this method violates the rules for tools/utilities:\n # it depends on a non-utility tool\n- mtool = getToolByName(self, \'portal_membership\')\n+ mtool = getToolByName(self, "portal_membership")\n member = mtool.getMemberById(member_id)\n member.setMemberProperties(properties)\n member.setSecurityProfile(password, roles, domains)\n@@ -483,25 +509,18 @@ def editMember(self, member_id, properties=None, password=None,\n InitializeClass(RegistrationTool)\n \n _TESTS = (\n- (re.compile(r"^[0-9a-zA-Z\\.\\-\\_\\+\\\']+\\@[0-9a-zA-Z\\.\\-]+$"),\n- True, "Failed a"),\n- (re.compile(r"^[^0-9a-zA-Z]|[^0-9a-zA-Z]$"),\n- False, "Failed b"),\n- (re.compile(r"([0-9a-zA-Z_]{1})\\@."),\n- True, "Failed c"),\n- (re.compile(r".\\@([0-9a-zA-Z]{1})"),\n- True, "Failed d"),\n- (re.compile(r".\\.\\-.|.\\-\\..|.\\.\\..|.!(xn)\\-\\-."),\n- False, "Failed e"),\n- (re.compile(r".\\.\\_.|.\\-\\_.|.\\_\\..|.\\_\\-.|.\\_\\_."),\n- False, "Failed f"),\n- (re.compile(r"(.\\.([a-zA-Z]{2,}))$|(.\\.(xn--[0-9a-z]+))$"),\n- True, "Failed g"),\n+ (re.compile(r"^[0-9a-zA-Z\\.\\-\\_\\+\\\']+\\@[0-9a-zA-Z\\.\\-]+$"), True, "Failed a"),\n+ (re.compile(r"^[^0-9a-zA-Z]|[^0-9a-zA-Z]$"), False, "Failed b"),\n+ (re.compile(r"([0-9a-zA-Z_]{1})\\@."), True, "Failed c"),\n+ (re.compile(r".\\@([0-9a-zA-Z]{1})"), True, "Failed d"),\n+ (re.compile(r".\\.\\-.|.\\-\\..|.\\.\\..|.!(xn)\\-\\-."), False, "Failed e"),\n+ (re.compile(r".\\.\\_.|.\\-\\_.|.\\_\\..|.\\_\\-.|.\\_\\_."), False, "Failed f"),\n+ (re.compile(r"(.\\.([a-zA-Z]{2,}))$|(.\\.(xn--[0-9a-z]+))$"), True, "Failed g"),\n )\n \n \n class EmailAddressInvalid(ValidationError):\n- __doc__ = _(\'Invalid email address.\')\n+ __doc__ = _("Invalid email address.")\n \n \n def _checkEmail(address):\n@@ -509,26 +528,29 @@ def _checkEmail(address):\n matched = pattern.search(address) is not None\n if matched != expected:\n return False, message\n- return True, \'\'\n+ return True, ""\n \n \n # RFC 2822 local-part: dot-atom or quoted-string\n # characters allowed in atom: A-Za-z0-9!#$%&\'*+-/=?^_`{|}~\n # RFC 2821 domain: max 255 characters\n-_LOCAL_RE = re.compile(r\'([A-Za-z0-9!#$%&\\\'*+\\-/=?^_`{|}~]+\'\n- r\'(\\.[A-Za-z0-9!#$%&\\\'*+\\-/=?^_`{|}~]+)*|\'\n- r\'"[^(\\|")]*")@[^@]{3,255}$\')\n+_LOCAL_RE = re.compile(\n+ r"([A-Za-z0-9!#$%&\\\'*+\\-/=?^_`{|}~]+"\n+ r"(\\.[A-Za-z0-9!#$%&\\\'*+\\-/=?^_`{|}~]+)*|"\n+ r\'"[^(\\|")]*")@[^@]{3,255}$\'\n+)\n \n # RFC 2821 local-part: max 64 characters\n # RFC 2821 domain: sequence of dot-separated labels\n # characters allowed in label: A-Za-z0-9-, first is a letter\n # Even though the RFC does not allow it all-numeric domains do exist\n-_DOMAIN_RE = re.compile(r\'[^@]{1,64}@[A-Za-z0-9][A-Za-z0-9-]*\'\n- r\'(\\.[A-Za-z0-9][A-Za-z0-9-]*)+$\')\n+_DOMAIN_RE = re.compile(\n+ r"[^@]{1,64}@[A-Za-z0-9][A-Za-z0-9-]*" r"(\\.[A-Za-z0-9][A-Za-z0-9-]*)+$"\n+)\n \n \n def checkEmailAddress(address):\n- """ Check email address.\n+ """Check email address.\n \n This should catch most invalid but no valid addresses.\n """\ndiff --git a/Products/CMFPlone/SkinsTool.py b/Products/CMFPlone/SkinsTool.py\nindex f4ade43b53..cb35d8e587 100644\n--- a/Products/CMFPlone/SkinsTool.py\n+++ b/Products/CMFPlone/SkinsTool.py\n@@ -6,32 +6,38 @@\n \n \n class SkinsTool(PloneBaseTool, BaseTool):\n-\n- meta_type = \'Plone Skins Tool\'\n+ meta_type = "Plone Skins Tool"\n security = ClassSecurityInfo()\n- toolicon = \'skins/plone_images/skins_icon.png\'\n+ toolicon = "skins/plone_images/skins_icon.png"\n \n- default_skin = \'\'\n- request_varname = \'plone_skin\'\n+ default_skin = ""\n+ request_varname = "plone_skin"\n \n- security.declareProtected(ManagePortal, \'addSkinSelection\')\n+ security.declareProtected(ManagePortal, "addSkinSelection")\n \n def addSkinSelection(self, skinname, skinpath, test=0, make_default=0):\n # Adds a skin selection.\n- super().addSkinSelection(skinname, skinpath,\n- test=test, make_default=make_default)\n-\n- security.declareProtected(ManagePortal, \'manage_skinLayers\')\n-\n- def manage_skinLayers(self, chosen=(), add_skin=0, del_skin=0,\n- skinname=\'\', skinpath=\'\', REQUEST=None):\n- """ Change the skinLayers.\n- """\n- response = super().manage_skinLayers(chosen=chosen,\n- add_skin=add_skin, del_skin=del_skin, skinname=skinname,\n- skinpath=skinpath, REQUEST=REQUEST)\n+ super().addSkinSelection(\n+ skinname, skinpath, test=test, make_default=make_default\n+ )\n+\n+ security.declareProtected(ManagePortal, "manage_skinLayers")\n+\n+ def manage_skinLayers(\n+ self, chosen=(), add_skin=0, del_skin=0, skinname="", skinpath="", REQUEST=None\n+ ):\n+ """Change the skinLayers."""\n+ response = super().manage_skinLayers(\n+ chosen=chosen,\n+ add_skin=add_skin,\n+ del_skin=del_skin,\n+ skinname=skinname,\n+ skinpath=skinpath,\n+ REQUEST=REQUEST,\n+ )\n return response\n \n+\n SkinsTool.__doc__ = BaseTool.__doc__\n \n InitializeClass(SkinsTool)\ndiff --git a/Products/CMFPlone/TranslationServiceTool.py b/Products/CMFPlone/TranslationServiceTool.py\nindex 82854b270f..5a9f9cd77b 100644\n--- a/Products/CMFPlone/TranslationServiceTool.py\n+++ b/Products/CMFPlone/TranslationServiceTool.py\n@@ -26,78 +26,95 @@\n \n @implementer(ITranslationServiceTool)\n class TranslationServiceTool(PloneBaseTool, UniqueObject, SimpleItem):\n- """ Utility methods to access the translation machinery """\n+ """Utility methods to access the translation machinery"""\n \n- id = \'translation_service\'\n- meta_type = \'Portal Translation Service Tool\'\n- toolicon = \'skins/plone_images/site_icon.png\'\n+ id = "translation_service"\n+ meta_type = "Portal Translation Service Tool"\n+ toolicon = "skins/plone_images/site_icon.png"\n security = ClassSecurityInfo()\n \n- security.declarePublic(\'utranslate\')\n+ security.declarePublic("utranslate")\n \n def utranslate(self, *args, **kw):\n return self.translate(*args, **kw)\n \n- security.declarePublic(\'translate\')\n-\n- def translate(self, msgid, domain=None, mapping=None, context=None,\n- target_language=None, default=None):\n+ security.declarePublic("translate")\n+\n+ def translate(\n+ self,\n+ msgid,\n+ domain=None,\n+ mapping=None,\n+ context=None,\n+ target_language=None,\n+ default=None,\n+ ):\n # Translate method for resticted code like skins.\n if context is not None:\n if not IBrowserRequest.providedBy(context):\n- context = aq_get(context, \'REQUEST\', None)\n+ context = aq_get(context, "REQUEST", None)\n \n- return translate(msgid, domain=domain, mapping=mapping,\n- context=context, target_language=target_language,\n- default=default)\n+ return translate(\n+ msgid,\n+ domain=domain,\n+ mapping=mapping,\n+ context=context,\n+ target_language=target_language,\n+ default=default,\n+ )\n \n- security.declarePublic(\'encode\')\n+ security.declarePublic("encode")\n \n- def encode(self, m, input_encoding=None, output_encoding=None,\n- errors=\'strict\'):\n+ def encode(self, m, input_encoding=None, output_encoding=None, errors="strict"):\n # encode a give unicode type or string type to string type in encoding\n # output_encoding\n \n # check if input is not type unicode\n if not isinstance(m, str):\n if input_encoding is None:\n- input_encoding = \'utf-8\'\n+ input_encoding = "utf-8"\n m = str(str(m), input_encoding, errors)\n \n if output_encoding is None:\n- output_encoding = \'utf-8\'\n+ output_encoding = "utf-8"\n \n # return as type string\n return m.encode(output_encoding, errors)\n \n- security.declarePublic(\'asunicodetype\')\n+ security.declarePublic("asunicodetype")\n \n- def asunicodetype(self, m, input_encoding=None, errors=\'strict\'):\n+ def asunicodetype(self, m, input_encoding=None, errors="strict"):\n # create type unicode from type string\n \n if isinstance(m, str):\n return m\n \n if input_encoding is None:\n- input_encoding = \'utf-8\'\n+ input_encoding = "utf-8"\n \n # return as type unicode\n return str(str(m), input_encoding, errors)\n \n- security.declarePublic(\'ulocalized_time\')\n-\n- def ulocalized_time(self, time, long_format=None, time_only=None,\n- context=None, domain=\'plonelocales\', request=None):\n+ security.declarePublic("ulocalized_time")\n+\n+ def ulocalized_time(\n+ self,\n+ time,\n+ long_format=None,\n+ time_only=None,\n+ context=None,\n+ domain="plonelocales",\n+ request=None,\n+ ):\n # get some context if none is passed\n if context is None:\n context = self\n- return ulocalized_time(time, long_format, time_only,\n- context, domain, request)\n+ return ulocalized_time(time, long_format, time_only, context, domain, request)\n \n- security.declarePublic(\'day_msgid\')\n+ security.declarePublic("day_msgid")\n \n def day_msgid(self, number, format=None):\n- """ Returns the msgid which can be passed to the translation service\n+ """Returns the msgid which can be passed to the translation service\n for l10n of weekday names. Format is either None, \'a\' or \'s\'.\n \n >>> ttool = TranslationServiceTool()\n@@ -115,10 +132,10 @@ def day_msgid(self, number, format=None):\n \'weekday_wed_short\'\n """\n #\n- if format == \'s\':\n+ if format == "s":\n # short format\n method = weekdayname_msgid_short\n- elif format == \'a\':\n+ elif format == "a":\n # abbreviation\n method = weekdayname_msgid_abbr\n else:\n@@ -126,10 +143,10 @@ def day_msgid(self, number, format=None):\n method = weekdayname_msgid\n return method(number)\n \n- security.declarePublic(\'month_msgid\')\n+ security.declarePublic("month_msgid")\n \n def month_msgid(self, number, format=None):\n- """ Returns the msgid which can be passed to the translation service\n+ """Returns the msgid which can be passed to the translation service\n for l10n of month names. Format is either \'\' or \'a\' (long or\n abbreviation).\n \n@@ -144,14 +161,12 @@ def month_msgid(self, number, format=None):\n >>> ttool.month_msgid(6, format=\'a\')\n \'month_jun_abbr\'\n """\n- return \'a\' == format \\\n- and monthname_msgid_abbr(number) \\\n- or monthname_msgid(number)\n+ return "a" == format and monthname_msgid_abbr(number) or monthname_msgid(number)\n \n- security.declarePublic(\'month_english\')\n+ security.declarePublic("month_english")\n \n def month_english(self, number, format=None):\n- """ Returns the english name of month by number. Format is either \'\' or\n+ """Returns the english name of month by number. Format is either \'\' or\n \'a\' (long or abbreviation).\n \n >>> ttool = TranslationServiceTool()\n@@ -164,23 +179,23 @@ def month_english(self, number, format=None):\n """\n return monthname_english(number, format=format)\n \n- security.declarePublic(\'month\')\n+ security.declarePublic("month")\n \n def month(self, number, format=None, default=None):\n- """ Returns a Message with the month name, that can be translated by\n+ """Returns a Message with the month name, that can be translated by\n the TAL engine. Format is either None or \'a\' (long or abbreviation).\n """\n if default is None:\n default = monthname_english(number, format=format)\n- value = \'a\' == format \\\n- and monthname_msgid_abbr(number) \\\n- or monthname_msgid(number)\n+ value = (\n+ "a" == format and monthname_msgid_abbr(number) or monthname_msgid(number)\n+ )\n return PLMF(value, default=default)\n \n- security.declarePublic(\'weekday_english\')\n+ security.declarePublic("weekday_english")\n \n def weekday_english(self, number, format=None):\n- """ Returns the english name of a week by number. Format is\n+ """Returns the english name of a week by number. Format is\n either None, \'a\' or \'p\'.\n \n >>> ttool = TranslationServiceTool()\n@@ -199,4 +214,5 @@ def weekday_english(self, number, format=None):\n """\n return weekdayname_english(number, format=format)\n \n+\n InitializeClass(TranslationServiceTool)\ndiff --git a/Products/CMFPlone/TypesTool.py b/Products/CMFPlone/TypesTool.py\nindex 4a4c773db4..02d4f12a71 100644\n--- a/Products/CMFPlone/TypesTool.py\n+++ b/Products/CMFPlone/TypesTool.py\n@@ -7,12 +7,11 @@\n \n \n class TypesTool(PloneBaseTool, BaseTool):\n-\n- meta_type = \'Plone Types Tool\'\n+ meta_type = "Plone Types Tool"\n security = ClassSecurityInfo()\n- toolicon = \'skins/plone_images/document_icon.png\'\n+ toolicon = "skins/plone_images/document_icon.png"\n \n- security.declarePublic(\'listTypeTitles\')\n+ security.declarePublic("listTypeTitles")\n \n def listTypeTitles(self, container=None):\n # Return a dictionary of id/Title combinations.\n@@ -24,7 +23,7 @@ def listTypeTitles(self, container=None):\n \n return typenames\n \n- security.declarePrivate(\'listActions\')\n+ security.declarePrivate("listActions")\n \n def listActions(self, info=None, object=None, category=None):\n # List all the actions defined by a provider.\n@@ -36,22 +35,27 @@ def listActions(self, info=None, object=None, category=None):\n if type_info is not None:\n type_actions = type_info.listActions(info, object)\n if category is not None:\n- type_actions = [a for a in type_actions\n- if a.category == category]\n+ type_actions = [a for a in type_actions if a.category == category]\n actions.extend(type_actions)\n \n- if category == \'folder/add\':\n- add_actions = [ti for ti in self.values()\n- if IAction.providedBy(ti)]\n+ if category == "folder/add":\n+ add_actions = [ti for ti in self.values() if IAction.providedBy(ti)]\n actions.extend(add_actions)\n \n return actions\n \n- security.declarePublic(\'listActionInfos\')\n-\n- def listActionInfos(self, action_chain=None, object=None,\n- check_visibility=1, check_permissions=1,\n- check_condition=1, max=-1, category=None):\n+ security.declarePublic("listActionInfos")\n+\n+ def listActionInfos(\n+ self,\n+ action_chain=None,\n+ object=None,\n+ check_visibility=1,\n+ check_permissions=1,\n+ check_condition=1,\n+ max=-1,\n+ category=None,\n+ ):\n # List ActionInfo objects.\n # (method is without docstring to disable publishing)\n #\n@@ -65,28 +69,29 @@ def listActionInfos(self, action_chain=None, object=None,\n if action_chain:\n filtered_actions = []\n if isinstance(action_chain, str):\n- action_chain = (action_chain, )\n+ action_chain = (action_chain,)\n for action_ident in action_chain:\n- sep = action_ident.rfind(\'/\')\n- category, id = action_ident[:sep], action_ident[sep + 1:]\n+ sep = action_ident.rfind("/")\n+ category, id = action_ident[:sep], action_ident[sep + 1 :]\n for ai in actions:\n- if id == ai[\'id\'] and category == ai[\'category\']:\n+ if id == ai["id"] and category == ai["category"]:\n filtered_actions.append(ai)\n actions = filtered_actions\n \n action_infos = []\n for ai in actions:\n- if check_visibility and not ai[\'visible\']:\n+ if check_visibility and not ai["visible"]:\n continue\n- if check_permissions and not ai[\'allowed\']:\n+ if check_permissions and not ai["allowed"]:\n continue\n- if check_condition and not ai[\'available\']:\n+ if check_condition and not ai["available"]:\n continue\n action_infos.append(ai)\n if max + 1 and len(action_infos) >= max:\n break\n return action_infos\n \n+\n TypesTool.__doc__ = BaseTool.__doc__\n \n InitializeClass(TypesTool)\ndiff --git a/Products/CMFPlone/URLTool.py b/Products/CMFPlone/URLTool.py\nindex 87683ac434..76ccbb2f39 100644\n--- a/Products/CMFPlone/URLTool.py\n+++ b/Products/CMFPlone/URLTool.py\n@@ -10,10 +10,9 @@\n \n \n class URLTool(PloneBaseTool, BaseTool):\n-\n- meta_type = \'Plone URL Tool\'\n+ meta_type = "Plone URL Tool"\n security = ClassSecurityInfo()\n- toolicon = \'skins/plone_images/link_icon.png\'\n+ toolicon = "skins/plone_images/link_icon.png"\n \n @security.public\n def isURLInPortal(self, url, context=None):\ndiff --git a/Products/CMFPlone/UnicodeSplitter/config.py b/Products/CMFPlone/UnicodeSplitter/config.py\nindex 980053bb94..2db11d3278 100644\n--- a/Products/CMFPlone/UnicodeSplitter/config.py\n+++ b/Products/CMFPlone/UnicodeSplitter/config.py\n@@ -12,21 +12,17 @@\n rangetable = dict(\n # ascii=u"a-zA-Z0-9_",\n # digit=u"\\d",\n-\n # U+AC00-D7AF Hangul Syllables \xe3\x83\x8f\xe3\x83\xb3\xe3\x82\xb0\xe3\x83\xab\xe9\x9f\xb3\xe7\xaf\x80\xe6\x96\x87\xe5\xad\x97\n hangul="\\uAC00-\\uD7AF",\n-\n # U+30A0-30FF Katakana \xe7\x89\x87\xe4\xbb\xae\xe5\x90\x8d\n # U+3040-309F Hiragana \xe5\xb9\xb3\xe4\xbb\xae\xe5\x90\x8d\n # kana=u"\\u3040-\\u30FF",\n # hiragana=u"\\u3040-\\u309F\\u30FC",\n # katakana=u"\\u30A0-\\u30FF",\n-\n # U+4E00-9FFF CJK Unified Ideographs CJK\xe7\xb5\xb1\xe5\x90\x88\xe6\xbc\xa2\xe5\xad\x97\n # U+3400-4DBF CJK Unified Ideographs Extension A CJK\xe7\xb5\xb1\xe5\x90\x88\xe6\xbc\xa2\xe5\xad\x97\xe6\x8b\xa1\xe5\xbc\xb5A\n # U+F900-FAFF CJK Compatibility Ideographs CJK\xe4\xba\x92\xe6\x8f\x9b\xe6\xbc\xa2\xe5\xad\x97\n # ideo=u"\\u4E00-\\u9FFF\\u3400-\\u4DBF\\uF900-\\uFAFF",\n-\n cj="\\u3040-\\u30FF\\u4E00-\\u9FFF\\u3400-\\u4DBF\\uF900-\\uFAFF",\n thai="\\u0E00-\\u0E7F", # U+0E00-0E7F Thai \xe3\x82\xbf\xe3\x82\xa4\xe6\x96\x87\xe5\xad\x97\n )\n@@ -36,8 +32,7 @@\n # Splitting core.\n ps = rangetable.values()\n allp = "".join(ps)\n-glob_true = fr"[^{allp}]([^{allp}]|[\\*\\?])*|" + \\\n- "|".join([f"[{x}]+" for x in ps])\n+glob_true = rf"[^{allp}]([^{allp}]|[\\*\\?])*|" + "|".join([f"[{x}]+" for x in ps])\n \n glob_false = r"[^%s]+|" % allp + "|".join("[%s]+" % x for x in ps)\n \ndiff --git a/Products/CMFPlone/UnicodeSplitter/splitter.py b/Products/CMFPlone/UnicodeSplitter/splitter.py\nindex 22c8460e31..b78f130932 100644\n--- a/Products/CMFPlone/UnicodeSplitter/splitter.py\n+++ b/Products/CMFPlone/UnicodeSplitter/splitter.py\n@@ -20,7 +20,7 @@\n \n \n def bigram(u, limit=1):\n- """ Split into bi-gram.\n+ """Split into bi-gram.\n limit arg describes ending process.\n If limit = 0 then\n \xe6\x97\xa5\xe6\x9c\xac\xe4\xba\xba-> [\xe6\x97\xa5\xe6\x9c\xac,\xe6\x9c\xac\xe4\xba\xba, \xe4\xba\xba]\n@@ -29,10 +29,10 @@ def bigram(u, limit=1):\n \xe6\x97\xa5\xe6\x9c\xac\xe4\xba\xba-> [\xe6\x97\xa5\xe6\x9c\xac,\xe6\x9c\xac\xe4\xba\xba]\n \xe9\x87\x91 -> []\n """\n- return [u[i:i + 2] for i in range(len(u) - limit)]\n+ return [u[i : i + 2] for i in range(len(u) - limit)]\n \n \n-def process_str_post(s, enc=\'utf-8\'):\n+def process_str_post(s, enc="utf-8"):\n """Receive str, remove ? and *, then return str.\n If decode gets successful, process str as str.\n If decode gets failed, process str as ASCII.\n@@ -50,7 +50,7 @@ def process_str_post(s, enc=\'utf-8\'):\n return s.replace("?", "").replace("*", "")\n \n \n-def process_str(s, enc=\'utf-8\'):\n+def process_str(s, enc="utf-8"):\n """Receive str and encoding, then return the list\n of str as bi-grammed result.\n Decode str into str and pass it to process_unicode.\n@@ -68,7 +68,7 @@ def process_str(s, enc=\'utf-8\'):\n return [x.encode(enc, "strict") for x in bigrams]\n \n \n-def process_str_glob(s, enc=\'utf-8\'):\n+def process_str_glob(s, enc="utf-8"):\n """Receive str and encoding, then return the list\n of str considering glob processing.\n Decode str into str and pass it to process_unicode_glob.\n@@ -90,7 +90,7 @@ def process_unicode(uni):\n """Receive unicode string, then return a list of unicode\n as bi-grammed result.\n """\n- normalized = unicodedata.normalize(\'NFKC\', uni)\n+ normalized = unicodedata.normalize("NFKC", uni)\n for word in rx_U.findall(normalized):\n swords = [g.group() for g in pattern.finditer(word)]\n for sword in swords:\n@@ -104,10 +104,9 @@ def process_unicode_glob(uni):\n """Receive unicode string, then return a list of unicode\n as bi-grammed result. Considering globbing.\n """\n- normalized = unicodedata.normalize(\'NFKC\', uni)\n+ normalized = unicodedata.normalize("NFKC", uni)\n for word in rxGlob_U.findall(normalized):\n- swords = [g.group() for g in pattern_g.finditer(word)\n- if g.group() not in "*?"]\n+ swords = [g.group() for g in pattern_g.finditer(word) if g.group() not in "*?"]\n for i, sword in enumerate(swords):\n if not rx_all.match(sword[0]):\n yield sword\n@@ -125,23 +124,22 @@ def process_unicode_glob(uni):\n \n @implementer(ISplitter)\n class Splitter:\n-\n def process(self, lst):\n- """ Will be called when indexing.\n+ """Will be called when indexing.\n Receive list of str, make it bi-grammed, then return\n the list of str.\n """\n return [x for s in lst for x in process_str(s)]\n \n def processGlob(self, lst):\n- """ Will be called once when searching.\n+ """Will be called once when searching.\n Receive list of str, make it bi-grammed considering\n globbing, then return the list of str.\n """\n return [x for s in lst for x in process_str_glob(s)]\n \n def process_post_glob(self, lst):\n- """ Will be called twice when searching.\n+ """Will be called twice when searching.\n Receive list of str, Remove ? and *, then return\n the list of str.\n """\n@@ -150,8 +148,8 @@ def process_post_glob(self, lst):\n \n try:\n element_factory.registerFactory(\n- \'Word Splitter\',\n- \'Unicode Whitespace splitter\',\n+ "Word Splitter",\n+ "Unicode Whitespace splitter",\n Splitter,\n )\n except ValueError:\n@@ -160,9 +158,8 @@ def process_post_glob(self, lst):\n \n \n class CaseNormalizer:\n-\n def process(self, lst):\n- enc = \'utf-8\'\n+ enc = "utf-8"\n result = []\n for s in lst:\n # This is a hack to get the normalizer working with\n@@ -180,8 +177,8 @@ def process(self, lst):\n \n try:\n element_factory.registerFactory(\n- \'Case Normalizer\',\n- \'Unicode Case Normalizer\',\n+ "Case Normalizer",\n+ "Unicode Case Normalizer",\n CaseNormalizer,\n )\n except ValueError:\n@@ -190,9 +187,8 @@ def process(self, lst):\n \n \n class I18NNormalizer:\n-\n def process(self, lst):\n- enc = \'utf-8\'\n+ enc = "utf-8"\n result = []\n for s in lst:\n try:\n@@ -214,8 +210,8 @@ def process(self, lst):\n \n try:\n element_factory.registerFactory(\n- \'Case Normalizer\',\n- \'Unicode Ignoring Accents Case Normalizer\',\n+ "Case Normalizer",\n+ "Unicode Ignoring Accents Case Normalizer",\n I18NNormalizer,\n )\n except ValueError:\ndiff --git a/Products/CMFPlone/WorkflowTool.py b/Products/CMFPlone/WorkflowTool.py\nindex 53ab7b1732..1ee1f15d0d 100644\n--- a/Products/CMFPlone/WorkflowTool.py\n+++ b/Products/CMFPlone/WorkflowTool.py\n@@ -15,30 +15,35 @@\n \n \n try:\n- pkg_resources.get_distribution(\'plone.app.multilingual\')\n+ pkg_resources.get_distribution("plone.app.multilingual")\n except pkg_resources.DistributionNotFound:\n has_new_lang_bypass = False\n else:\n- has_new_lang_bypass = int(pkg_resources.get_distribution(\n- \'plone.app.multilingual\').version.split(\'.\')[0]) > 1\n+ has_new_lang_bypass = (\n+ int(\n+ pkg_resources.get_distribution("plone.app.multilingual").version.split(".")[\n+ 0\n+ ]\n+ )\n+ > 1\n+ )\n \n \n class WorkflowTool(PloneBaseTool, BaseTool):\n-\n- meta_type = \'Plone Workflow Tool\'\n+ meta_type = "Plone Workflow Tool"\n security = ClassSecurityInfo()\n plone_tool = 1\n- toolicon = \'skins/plone_images/workflow_icon.png\'\n+ toolicon = "skins/plone_images/workflow_icon.png"\n \n # TODO this should not make it into 1.0\n # Refactor me, my maker was tired\n def flattenTransitions(self, objs, container=None):\n # This is really hokey - hold on!!\n- if hasattr(objs, \'startswith\'):\n+ if hasattr(objs, "startswith"):\n return ()\n \n # TODO Need to behave differently for paths\n- if len(objs) and \'/\' in objs[0]:\n+ if len(objs) and "/" in objs[0]:\n return self.flattenTransitionsForPaths(objs)\n transitions = []\n t_names = []\n@@ -55,20 +60,20 @@ def flattenTransitions(self, objs, container=None):\n pass\n if trans:\n for t in trans:\n- if t[\'name\'] not in t_names:\n+ if t["name"] not in t_names:\n transitions.append(t)\n- t_names.append(t[\'name\'])\n+ t_names.append(t["name"])\n \n return tuple(transitions[:])\n \n def flattenTransitionsForPaths(self, paths):\n # This is even more hokey!!\n- if hasattr(paths, \'startswith\'):\n+ if hasattr(paths, "startswith"):\n return ()\n \n transitions = []\n t_names = []\n- portal = getToolByName(self, \'portal_url\').getPortalObject()\n+ portal = getToolByName(self, "portal_url").getPortalObject()\n \n for o in [portal.restrictedTraverse(path) for path in paths]:\n trans = ()\n@@ -80,13 +85,13 @@ def flattenTransitionsForPaths(self, paths):\n pass\n if trans:\n for t in trans:\n- if t[\'name\'] not in t_names:\n+ if t["name"] not in t_names:\n transitions.append(t)\n- t_names.append(t[\'name\'])\n+ t_names.append(t["name"])\n \n return tuple(transitions[:])\n \n- security.declarePublic(\'getTransitionsFor\')\n+ security.declarePublic("getTransitionsFor")\n \n def getTransitionsFor(self, obj=None, container=None, REQUEST=None):\n if type(obj) is type([]):\n@@ -100,21 +105,26 @@ def getTransitionsFor(self, obj=None, container=None, REQUEST=None):\n if sdef is not None:\n for tid in sdef.transitions:\n tdef = wf.transitions.get(tid, None)\n- if tdef is not None and \\\n- tdef.trigger_type == TRIGGER_USER_ACTION and \\\n- tdef.actbox_name and \\\n- wf._checkTransitionGuard(tdef, obj) and \\\n- not tdef.id in result:\n+ if (\n+ tdef is not None\n+ and tdef.trigger_type == TRIGGER_USER_ACTION\n+ and tdef.actbox_name\n+ and wf._checkTransitionGuard(tdef, obj)\n+ and not tdef.id in result\n+ ):\n result[tdef.id] = {\n- \'id\': tdef.id,\n- \'title\': tdef.title,\n- \'title_or_id\': tdef.title_or_id(),\n- \'description\': tdef.description,\n- \'name\': tdef.actbox_name,\n- \'url\': tdef.actbox_url %\n- {\'content_url\': obj.absolute_url(),\n- \'portal_url\': \'\',\n- \'folder_url\': \'\'}}\n+ "id": tdef.id,\n+ "title": tdef.title,\n+ "title_or_id": tdef.title_or_id(),\n+ "description": tdef.description,\n+ "name": tdef.actbox_name,\n+ "url": tdef.actbox_url\n+ % {\n+ "content_url": obj.absolute_url(),\n+ "portal_url": "",\n+ "folder_url": "",\n+ },\n+ }\n return tuple(result.values())\n \n def workflows_in_use(self):\n@@ -130,7 +140,7 @@ def workflows_in_use(self):\n \n return tuple(in_use[:])\n \n- security.declarePublic(\'getWorklists\')\n+ security.declarePublic("getWorklists")\n \n def getWorklists(self):\n # Instead of manually scraping actions_box, let\'s\n@@ -147,7 +157,7 @@ def getWorklists(self):\n # We want to know which types use the workflows with worklists\n # This for example avoids displaying \'pending\' of multiple workflows in\n # the same worklist\n- types_tool = getToolByName(self, \'portal_types\')\n+ types_tool = getToolByName(self, "portal_types")\n list_ptypes = types_tool.listContentTypes()\n types_by_wf = {} # wf:[list,of,types]\n for t in list_ptypes:\n@@ -155,7 +165,7 @@ def getWorklists(self):\n types_by_wf[wf] = types_by_wf.get(wf, []) + [t]\n \n # Placeful stuff\n- placeful_tool = getToolByName(self, \'portal_placeful_workflow\', None)\n+ placeful_tool = getToolByName(self, "portal_placeful_workflow", None)\n if placeful_tool is not None:\n for policy in placeful_tool.getWorkflowPolicies():\n for t in list_ptypes:\n@@ -169,7 +179,7 @@ def getWorklists(self):\n # into 1 sequence\n \n wf = self.getWorkflowById(id)\n- if hasattr(wf, \'worklists\'):\n+ if hasattr(wf, "worklists"):\n wlists = []\n for worklist in wf.worklists:\n wlist_def = wf.worklists[worklist]\n@@ -180,14 +190,15 @@ def getWorklists(self):\n var_matches[key] = wlist_def.var_matches[key]\n \n a_wlist = {\n- \'id\': worklist,\n- \'guard\': wlist_def.getGuard(),\n- \'guard_permissions\': wlist_def.getGuard().permissions,\n- \'guard_roles\': wlist_def.getGuard().roles,\n- \'catalog_vars\': var_matches,\n- \'name\': getattr(wlist_def, \'actbox_name\', None),\n- \'url\': getattr(wlist_def, \'actbox_url\', None),\n- \'types\': types_by_wf.get(id, [])}\n+ "id": worklist,\n+ "guard": wlist_def.getGuard(),\n+ "guard_permissions": wlist_def.getGuard().permissions,\n+ "guard_roles": wlist_def.getGuard().roles,\n+ "catalog_vars": var_matches,\n+ "name": getattr(wlist_def, "actbox_name", None),\n+ "url": getattr(wlist_def, "actbox_url", None),\n+ "types": types_by_wf.get(id, []),\n+ }\n wlists.append(a_wlist)\n # yes, we can duplicates, we filter duplicates out on the\n # calling PyhtonScript client\n@@ -195,7 +206,7 @@ def getWorklists(self):\n \n return wf_with_wlists\n \n- security.declarePublic(\'getWorklistsResults\')\n+ security.declarePublic("getWorklistsResults")\n \n def getWorklistsResults(self):\n # Return all the objects concerned by one or more worklists.\n@@ -208,8 +219,8 @@ def getWorklistsResults(self):\n # We want to know which types use the workflows with worklists\n # This for example avoids displaying \'pending\' of multiple workflows in\n # the same worklist\n- types_tool = getToolByName(self, \'portal_types\')\n- catalog = getToolByName(self, \'portal_catalog\')\n+ types_tool = getToolByName(self, "portal_types")\n+ catalog = getToolByName(self, "portal_catalog")\n \n list_ptypes = types_tool.listContentTypes()\n types_by_wf = {} # wf:[list,of,types]\n@@ -218,7 +229,7 @@ def getWorklistsResults(self):\n types_by_wf[wf] = types_by_wf.get(wf, []) + [t]\n \n # PlacefulWorkflowTool will give us other results\n- placeful_tool = getToolByName(self, \'portal_placeful_workflow\', None)\n+ placeful_tool = getToolByName(self, "portal_placeful_workflow", None)\n if placeful_tool is not None:\n for policy in placeful_tool.getWorkflowPolicies():\n for t in list_ptypes:\n@@ -229,7 +240,7 @@ def getWorklistsResults(self):\n objects_by_path = {}\n for id in self.getWorkflowIds():\n wf = self.getWorkflowById(id)\n- if hasattr(wf, \'worklists\'):\n+ if hasattr(wf, "worklists"):\n for worklist in wf.worklists:\n wlist_def = wf.worklists[worklist]\n # Make the var_matches a dict instead of PersistentMapping\n@@ -239,20 +250,22 @@ def getWorklistsResults(self):\n catalog_vars[key] = wlist_def.var_matches[key]\n # Support LinguaPlone review situations, you want to see\n # content in *all* languages\n- if \'Language\' not in catalog_vars:\n+ if "Language" not in catalog_vars:\n if has_new_lang_bypass:\n- catalog_vars[\'path\'] = \'/\'\n+ catalog_vars["path"] = "/"\n else:\n- catalog_vars[\'Language\'] = \'all\'\n+ catalog_vars["Language"] = "all"\n # Include inactive content in result list. This is\n # especially important for content scheduled to go public\n # in the future, but needs to be reviewed before this.\n- catalog_vars[\'show_inactive\'] = True\n+ catalog_vars["show_inactive"] = True\n for result in catalog.searchResults(catalog_vars):\n o = result.getObject()\n- if o \\\n- and id in self.getChainFor(o) \\\n- and wlist_def.getGuard().check(sm, wf, o):\n+ if (\n+ o\n+ and id in self.getChainFor(o)\n+ and wlist_def.getGuard().check(sm, wf, o)\n+ ):\n absurl = o.absolute_url()\n if absurl:\n objects_by_path[absurl] = (o.modified(), o)\n@@ -260,7 +273,7 @@ def getWorklistsResults(self):\n results = objects_by_path.values()\n return tuple(obj[1] for obj in sorted(results))\n \n- security.declareProtected(ManagePortal, \'getChainForPortalType\')\n+ security.declareProtected(ManagePortal, "getChainForPortalType")\n \n def getChainForPortalType(self, pt_name, managescreen=0):\n # Get a chain for a specific portal type.\n@@ -269,18 +282,18 @@ def getChainForPortalType(self, pt_name, managescreen=0):\n else:\n # (Default) is _not_ a chain nor a workflow in a chain.\n if managescreen:\n- return \'(Default)\'\n+ return "(Default)"\n else:\n # Return the default chain.\n return self._default_chain\n \n- security.declareProtected(ManagePortal, \'listWorkflows\')\n+ security.declareProtected(ManagePortal, "listWorkflows")\n \n def listWorkflows(self):\n # Return the list of workflows.\n return self.keys()\n \n- security.declarePublic(\'getTitleForStateOnType\')\n+ security.declarePublic("getTitleForStateOnType")\n \n def getTitleForStateOnType(self, state_name, p_type):\n # Returns the workflow state title for a given state name,\n@@ -293,11 +306,10 @@ def getTitleForStateOnType(self, state_name, p_type):\n states = wf.states\n state = getattr(states, state_name, None)\n if state is not None:\n- return getattr(aq_base(state), \'title\', None) \\\n- or state_name\n+ return getattr(aq_base(state), "title", None) or state_name\n return state_name\n \n- security.declarePublic(\'getTitleForTransitionOnType\')\n+ security.declarePublic("getTitleForTransitionOnType")\n \n def getTitleForTransitionOnType(self, trans_name, p_type):\n # Returns the workflow transition title for a given transition name,\n@@ -310,11 +322,12 @@ def getTitleForTransitionOnType(self, trans_name, p_type):\n transitions = wf.transitions\n trans = getattr(transitions, trans_name, None)\n if trans is not None:\n- return getattr(aq_base(trans), \'actbox_name\', None) \\\n- or trans_name\n+ return (\n+ getattr(aq_base(trans), "actbox_name", None) or trans_name\n+ )\n return trans_name\n \n- security.declarePublic(\'listWFStatesByTitle\')\n+ security.declarePublic("listWFStatesByTitle")\n \n def listWFStatesByTitle(self, filter_similar=False):\n # Returns the states of all available workflows, optionally filtering\n@@ -322,13 +335,13 @@ def listWFStatesByTitle(self, filter_similar=False):\n states = []\n dup_list = {}\n for wf in self.values():\n- state_folder = getattr(wf, \'states\', None)\n+ state_folder = getattr(wf, "states", None)\n if state_folder is not None:\n if not filter_similar:\n states.extend(state_folder.values())\n else:\n for state in state_folder.values():\n- key = f\'{state.id}:{state.title}\'\n+ key = f"{state.id}:{state.title}"\n if not key in dup_list:\n states.append(state)\n dup_list[key] = 1\n@@ -341,10 +354,10 @@ def getChainFor(self, ob):\n # the portal_type.\n return getMultiAdapter((ob, self), IWorkflowChain)\n \n- security.declarePrivate(\'listActions\')\n+ security.declarePrivate("listActions")\n \n def listActions(self, info=None, object=None):\n- """ Returns a list of actions to be displayed to the user.\n+ """Returns a list of actions to be displayed to the user.\n \n o Invoked by the portal_actions tool.\n \ndiff --git a/Products/CMFPlone/__init__.py b/Products/CMFPlone/__init__.py\nindex 4edd033abe..245b8bbd44 100644\n--- a/Products/CMFPlone/__init__.py\n+++ b/Products/CMFPlone/__init__.py\n@@ -34,7 +34,6 @@\n \n \n def initialize(context):\n-\n # Stuff has been moved from module level to this method for a\n # better separation of import and installation.\n # For the general user this change does not make a difference.\ndiff --git a/Products/CMFPlone/bbb.py b/Products/CMFPlone/bbb.py\nindex c92083cb24..c359ab86f2 100644\n--- a/Products/CMFPlone/bbb.py\n+++ b/Products/CMFPlone/bbb.py\n@@ -3,7 +3,7 @@\n \n HAS_ZSERVER = True\n try:\n- dist = pkg_resources.get_distribution(\'ZServer\')\n+ dist = pkg_resources.get_distribution("ZServer")\n except pkg_resources.DistributionNotFound:\n HAS_ZSERVER = False\n \ndiff --git a/Products/CMFPlone/browser/admin.py b/Products/CMFPlone/browser/admin.py\nindex 98d4a3256c..f687ede690 100644\n--- a/Products/CMFPlone/browser/admin.py\n+++ b/Products/CMFPlone/browser/admin.py\n@@ -43,16 +43,17 @@\n HAS_VOLTO = True\n except pkg_resources.DistributionNotFound:\n HAS_VOLTO = False\n-LOGGER = logging.getLogger(\'Products.CMFPlone\')\n+LOGGER = logging.getLogger("Products.CMFPlone")\n \n \n class AppTraverser(DefaultPublishTraverse):\n adapts(IApplication, IRequest)\n \n def publishTraverse(self, request, name):\n- if name == \'index_html\':\n+ if name == "index_html":\n view = queryMultiAdapter(\n- (self.context, request), Interface, \'plone-overview\')\n+ (self.context, request), Interface, "plone-overview"\n+ )\n if view is not None:\n return view\n return DefaultPublishTraverse.publishTraverse(self, request, name)\n@@ -67,25 +68,22 @@ def sites(self, root=None):\n \n result = []\n secman = getSecurityManager()\n- candidates = (\n- obj for obj in root.values() if not isinstance(obj, Broken)\n- )\n+ candidates = (obj for obj in root.values() if not isinstance(obj, Broken))\n for obj in candidates:\n- if obj.meta_type == \'Folder\':\n+ if obj.meta_type == "Folder":\n result = result + self.sites(obj)\n elif IPloneSiteRoot.providedBy(obj):\n if secman.checkPermission(View, obj):\n result.append(obj)\n- elif obj.getId() in getattr(root, \'_mount_points\', {}):\n+ elif obj.getId() in getattr(root, "_mount_points", {}):\n result.extend(self.sites(root=obj))\n return result\n \n def outdated(self, obj):\n # Try to pick the portal_migration as an attribute\n # (Plone 5 unmigrated site root) or as an item\n- mig = (\n- getattr(obj, "portal_migration", None)\n- or obj.get(\'portal_migration\', None)\n+ mig = getattr(obj, "portal_migration", None) or obj.get(\n+ "portal_migration", None\n )\n if mig is not None:\n return mig.needUpgrading()\n@@ -99,13 +97,13 @@ def upgrade_url(self, site, can_manage=None):\n if can_manage is None:\n can_manage = self.can_manage()\n if can_manage:\n- return site.absolute_url() + \'/@@plone-upgrade\'\n+ return site.absolute_url() + "/@@plone-upgrade"\n else:\n- return self.context.absolute_url() + \'/@@plone-root-login\'\n+ return self.context.absolute_url() + "/@@plone-root-login"\n \n \n class RootLoginRedirect(BrowserView):\n- """ @@plone-root-login\n+ """@@plone-root-login\n \n This view of the Zope root forces authentication via the root\n acl_users and then redirects elsewhere.\n@@ -119,7 +117,8 @@ def __call__(self, came_from=None):\n # Note: \'\\\\domain.org\' is not recognised as host,\n # which is good.\n came_from = parse.urljoin(\n- self.context.absolute_url() + \'/\', came_from,\n+ self.context.absolute_url() + "/",\n+ came_from,\n )\n elif not came_from.startswith(self.context.absolute_url()):\n # Note: we cannot use portal_url.isURLInPortal here, because we\n@@ -131,43 +130,41 @@ def __call__(self, came_from=None):\n \n \n class RootLogout(BrowserView):\n- """ @@plone-root-logout """\n+ """@@plone-root-logout"""\n \n- logout = ViewPageTemplateFile(\'templates/plone-admin-logged-out.pt\')\n+ logout = ViewPageTemplateFile("templates/plone-admin-logged-out.pt")\n \n def __call__(self):\n response = self.request.response\n realm = response.realm\n response.setStatus(401)\n- response.setHeader(\'WWW-Authenticate\', \'basic realm="%s"\' % realm, 1)\n+ response.setHeader("WWW-Authenticate", \'basic realm="%s"\' % realm, 1)\n response.setBody(self.logout())\n return\n \n \n class FrontPage(BrowserView):\n-\n- index = ViewPageTemplateFile(\'templates/plone-frontpage.pt\')\n+ index = ViewPageTemplateFile("templates/plone-frontpage.pt")\n \n \n class AddPloneSite(BrowserView):\n-\n # Profiles that are installed by default,\n # but can be removed later.\n default_extension_profiles = (\n- \'plone.app.caching:default\',\n- \'plonetheme.barceloneta:default\',\n+ "plone.app.caching:default",\n+ "plonetheme.barceloneta:default",\n )\n # Let\'s have a separate list for Volto.\n volto_default_extension_profiles = (\n- \'plone.app.caching:default\',\n- \'plonetheme.barceloneta:default\',\n- \'plone.volto:default\',\n+ "plone.app.caching:default",\n+ "plonetheme.barceloneta:default",\n+ "plone.volto:default",\n )\n \n def profiles(self):\n base_profiles = []\n extension_profiles = []\n- if HAS_VOLTO and not self.request.get(\'classic\'):\n+ if HAS_VOLTO and not self.request.get("classic"):\n selected_extension_profiles = self.volto_default_extension_profiles\n else:\n selected_extension_profiles = self.default_extension_profiles\n@@ -175,30 +172,32 @@ def profiles(self):\n # profiles available for install/uninstall, but hidden at the time\n # the Plone site is created\n not_installable = [\n- \'Products.CMFPlacefulWorkflow:CMFPlacefulWorkflow\',\n+ "Products.CMFPlacefulWorkflow:CMFPlacefulWorkflow",\n ]\n utils = getAllUtilitiesRegisteredFor(INonInstallable)\n for util in utils:\n not_installable.extend(util.getNonInstallableProfiles())\n \n for info in profile_registry.listProfileInfo():\n- if info.get(\'type\') == EXTENSION and \\\n- info.get(\'for\') in (IPloneSiteRoot, None):\n- profile_id = info.get(\'id\')\n+ if info.get("type") == EXTENSION and info.get("for") in (\n+ IPloneSiteRoot,\n+ None,\n+ ):\n+ profile_id = info.get("id")\n if profile_id not in not_installable:\n if profile_id in selected_extension_profiles:\n- info[\'selected\'] = \'selected\'\n+ info["selected"] = "selected"\n extension_profiles.append(info)\n \n def _key(v):\n # Make sure implicitly selected items come first\n- selected = v.get(\'selected\') and \'automatic\' or \'manual\'\n- return \'{}-{}\'.format(selected, v.get(\'title\', \'\'))\n+ selected = v.get("selected") and "automatic" or "manual"\n+ return "{}-{}".format(selected, v.get("title", ""))\n+\n extension_profiles.sort(key=_key)\n \n for info in profile_registry.listProfileInfo():\n- if info.get(\'type\') == BASE and \\\n- info.get(\'for\') in (IPloneSiteRoot, None):\n+ if info.get("type") == BASE and info.get("for") in (IPloneSiteRoot, None):\n base_profiles.append(info)\n \n return dict(\n@@ -208,25 +207,25 @@ def _key(v):\n )\n \n def browser_language(self):\n- language = \'en\'\n+ language = "en"\n pl = IUserPreferredLanguages(self.request)\n if pl is not None:\n languages = pl.getPreferredLanguages()\n for httplang in languages:\n- parts = (httplang.split(\'-\') + [None, None])[:3]\n+ parts = (httplang.split("-") + [None, None])[:3]\n if parts[0] == parts[1]:\n # Avoid creating a country code for simple languages codes\n parts = [parts[0], None, None]\n try:\n locale = locales.getLocale(*parts)\n- language = locale.getLocaleID().replace(\'_\', \'-\').lower()\n+ language = locale.getLocaleID().replace("_", "-").lower()\n break\n except LoadLocaleError:\n # Just try the next combination\n pass\n return language\n \n- def grouped_languages(self, default=\'en\'):\n+ def grouped_languages(self, default="en"):\n util = queryUtility(IContentLanguageAvailability)\n available = util.getLanguages(combined=True)\n languages = dict(util.getLanguageListing())\n@@ -234,41 +233,43 @@ def grouped_languages(self, default=\'en\'):\n # Group country specific versions by language\n grouped = OrderedDict()\n for langcode, data in available.items():\n- lang = langcode.split(\'-\')[0]\n+ lang = langcode.split("-")[0]\n language = languages.get(lang, lang) # Label\n \n- struct = grouped.get(lang, {\'label\': language, \'languages\': []})\n+ struct = grouped.get(lang, {"label": language, "languages": []})\n \n- langs = struct[\'languages\']\n- langs.append({\n- \'langcode\': langcode,\n- \'label\': data.get(\'native\', data.get(\'name\')),\n- })\n+ langs = struct["languages"]\n+ langs.append(\n+ {\n+ "langcode": langcode,\n+ "label": data.get("native", data.get("name")),\n+ }\n+ )\n \n grouped[lang] = struct\n \n # Sort list by language, next by country\n- data = sorted(grouped.values(), key=lambda k: k[\'label\'])\n+ data = sorted(grouped.values(), key=lambda k: k["label"])\n for item in data:\n- item[\'languages\'] = sorted(\n- item[\'languages\'], key=lambda k: k[\'label\'].lower())\n+ item["languages"] = sorted(\n+ item["languages"], key=lambda k: k["label"].lower()\n+ )\n return data\n \n def timezones(self):\n tz_vocab = getUtility(\n- IVocabularyFactory,\n- \'plone.app.vocabularies.CommonTimezones\'\n+ IVocabularyFactory, "plone.app.vocabularies.CommonTimezones"\n )(self.context)\n \n grouped = OrderedDict()\n tz_values = [it.value for it in tz_vocab]\n for value in tz_values:\n- splitted = value.split(\'/\')\n+ splitted = value.split("/")\n group = splitted.pop(0)\n- label = \'/\'.join(splitted)\n+ label = "/".join(splitted)\n \n entries = grouped.get(group, [])\n- entries.append({\'label\': label or group, \'value\': value})\n+ entries.append({"label": label or group, "value": value})\n grouped[group] = entries\n \n return grouped\n@@ -276,9 +277,9 @@ def timezones(self):\n def __call__(self):\n context = self.context\n form = self.request.form\n- submitted = form.get(\'form.submitted\', False)\n+ submitted = form.get("form.submitted", False)\n if submitted:\n- site_id = form.get(\'site_id\', \'Plone\')\n+ site_id = form.get("site_id", "Plone")\n \n # CSRF protect. DO NOT use auto CSRF protection for adding a site\n alsoProvides(self.request, IDisableCSRFProtection)\n@@ -287,57 +288,56 @@ def __call__(self):\n # if it is because it is not installed until a plone site\n # is created\n if queryUtility(IKeyManager) is None:\n- LOGGER.info(\'CSRF protection disabled on initial site \'\n- \'creation\')\n+ LOGGER.info("CSRF protection disabled on initial site " "creation")\n else:\n # we have a keymanager, check csrf protection manually now\n checkCSRF(self.request)\n \n site = addPloneSite(\n- context, site_id,\n- title=form.get(\'title\', \'\'),\n- profile_id=form.get(\'profile_id\', _DEFAULT_PROFILE),\n- extension_ids=form.get(\'extension_ids\', ()),\n- setup_content=form.get(\'setup_content\', False),\n- default_language=form.get(\'default_language\', \'en\'),\n- portal_timezone=form.get(\'portal_timezone\', \'UTC\')\n+ context,\n+ site_id,\n+ title=form.get("title", ""),\n+ profile_id=form.get("profile_id", _DEFAULT_PROFILE),\n+ extension_ids=form.get("extension_ids", ()),\n+ setup_content=form.get("setup_content", False),\n+ default_language=form.get("default_language", "en"),\n+ portal_timezone=form.get("portal_timezone", "UTC"),\n )\n self.request.response.redirect(site.absolute_url())\n- return \'\'\n+ return ""\n \n return self.index()\n \n \n class Upgrade(BrowserView):\n-\n def upgrades(self):\n- pm = getattr(self.context, \'portal_migration\')\n+ pm = getattr(self.context, "portal_migration")\n return pm.listUpgrades()\n \n def versions(self):\n- pm = getattr(self.context, \'portal_migration\')\n+ pm = getattr(self.context, "portal_migration")\n result = {}\n- result[\'instance\'] = pm.getInstanceVersion()\n- result[\'fs\'] = pm.getFileSystemVersion()\n- result[\'equal\'] = result[\'instance\'] == result[\'fs\']\n- instance_version = normalize_version(result[\'instance\'])\n- fs_version = normalize_version(result[\'fs\'])\n- result[\'instance_gt\'] = instance_version > fs_version\n- result[\'instance_lt\'] = instance_version < fs_version\n- result[\'corelist\'] = pm.coreVersions()\n+ result["instance"] = pm.getInstanceVersion()\n+ result["fs"] = pm.getFileSystemVersion()\n+ result["equal"] = result["instance"] == result["fs"]\n+ instance_version = normalize_version(result["instance"])\n+ fs_version = normalize_version(result["fs"])\n+ result["instance_gt"] = instance_version > fs_version\n+ result["instance_lt"] = instance_version < fs_version\n+ result["corelist"] = pm.coreVersions()\n return result\n \n def __call__(self):\n form = self.request.form\n- submitted = form.get(\'form.submitted\', False)\n+ submitted = form.get("form.submitted", False)\n if submitted:\n # CSRF protect. DO NOT use auto CSRF protection for upgrading sites\n alsoProvides(self.request, IDisableCSRFProtection)\n \n- pm = getattr(self.context, \'portal_migration\')\n+ pm = getattr(self.context, "portal_migration")\n report = pm.upgrade(\n REQUEST=self.request,\n- dry_run=form.get(\'dry_run\', False),\n+ dry_run=form.get("dry_run", False),\n )\n return self.index(\n report=report,\n@@ -348,7 +348,7 @@ def __call__(self):\n def can_migrate_to_volto(self):\n if not HAS_VOLTO:\n return False\n- pm = getattr(self.context, \'portal_migration\')\n+ pm = getattr(self.context, "portal_migration")\n if pm.getInstanceVersion() < "6005":\n return False\n try:\ndiff --git a/Products/CMFPlone/browser/atd.py b/Products/CMFPlone/browser/atd.py\nindex 161c430f33..166c368d43 100644\n--- a/Products/CMFPlone/browser/atd.py\n+++ b/Products/CMFPlone/browser/atd.py\n@@ -9,22 +9,20 @@\n \n @implementer(IATDProxyView)\n class ATDProxyView:\n- """ Proxy for the \'After the Deadline\' spellchecker\n- """\n+ """Proxy for the \'After the Deadline\' spellchecker"""\n \n def checkDocument(self):\n- """ Proxy for the AtD service\'s checkDocument function\n- See http://www.afterthedeadline.com/api.slp for more info.\n+ """Proxy for the AtD service\'s checkDocument function\n+ See http://www.afterthedeadline.com/api.slp for more info.\n """\n registry = getUtility(IRegistry)\n- settings = registry.forInterface(\n- ITinyMCESchema, prefix="plone", check=False)\n- if settings.libraries_spellchecker_choice != \'AtD\':\n- return \'atd not enabled\'\n+ settings = registry.forInterface(ITinyMCESchema, prefix="plone", check=False)\n+ if settings.libraries_spellchecker_choice != "AtD":\n+ return "atd not enabled"\n \n tool = getToolByName(self.context, "portal_membership")\n if bool(tool.isAnonymousUser()):\n- return \'must be authenticated to use atd\'\n+ return "must be authenticated to use atd"\n \n data = self.request._file.read()\n service_url = settings.libraries_atd_service_url\n@@ -35,13 +33,12 @@ def checkDocument(self):\n \n if response.status != http_client.OK:\n service.close()\n- raise Exception(\'Unexpected response code from AtD service %d\' %\n- response.status)\n+ raise Exception(\n+ "Unexpected response code from AtD service %d" % response.status\n+ )\n \n- self.request.RESPONSE.setHeader(\'content-type\',\n- \'text/xml;charset=utf-8\')\n+ self.request.RESPONSE.setHeader("content-type", "text/xml;charset=utf-8")\n respxml = response.read()\n service.close()\n- xml = respxml.strip().replace("\\r", \'\').replace("\\n", \'\').replace(\n- \'> \', \'>\')\n+ xml = respxml.strip().replace("\\r", "").replace("\\n", "").replace("> ", ">")\n return xml\ndiff --git a/Products/CMFPlone/browser/author.py b/Products/CMFPlone/browser/author.py\nindex 741d365606..ed13dd4e98 100644\n--- a/Products/CMFPlone/browser/author.py\n+++ b/Products/CMFPlone/browser/author.py\n@@ -28,85 +28,83 @@\n \n \n class AuthorFeedbackForm(form.Form):\n-\n fields = field.Fields(IAuthorFeedbackForm)\n ignoreContext = True\n \n- @button.buttonAndHandler(_(\'label_send\', default=\'Send\'),\n- name=\'send\')\n+ @button.buttonAndHandler(_("label_send", default="Send"), name="send")\n def handle_send(self, action):\n self.portal_state = getMultiAdapter(\n- (self.context, self.request),\n- name=\'plone_portal_state\'\n+ (self.context, self.request), name="plone_portal_state"\n )\n \n self.portal = self.portal_state.portal()\n- self.membership_tool = getToolByName(\n- self.context, \'portal_membership\'\n- )\n+ self.membership_tool = getToolByName(self.context, "portal_membership")\n \n self.feedback_template = self.context.restrictedTraverse(\n- \'@@author-feedback-template\'\n+ "@@author-feedback-template"\n )\n \n data, errors = self.extractData()\n if errors:\n IStatusMessage(self.request).addStatusMessage(\n- self.formErrorsMessage,\n- type=\'error\'\n+ self.formErrorsMessage, type="error"\n )\n \n return\n \n- referer = data.get(\'referer\', \'unknown referer\')\n- subject = data.get(\'subject\', \'\')\n- message = data.get(\'message\', \'\')\n+ referer = data.get("referer", "unknown referer")\n+ subject = data.get("subject", "")\n+ message = data.get("message", "")\n # Author is None means portal administrator\n- author = data.get(\'author\', None)\n+ author = data.get("author", None)\n \n sender = self.portal_state.member()\n registry = getUtility(IRegistry)\n- mail_settings = registry.forInterface(IMailSchema, prefix=\'plone\')\n+ mail_settings = registry.forInterface(IMailSchema, prefix="plone")\n envelope_from = mail_settings.email_from_address\n \n if author is None:\n send_to_address = mail_settings.email_from_address\n else:\n author_member = self.membership_tool.getMemberById(author)\n- send_to_address = author_member.getProperty(\'email\')\n+ send_to_address = author_member.getProperty("email")\n \n- send_from_address = sender.getProperty(\'email\')\n+ send_from_address = sender.getProperty("email")\n \n- if send_from_address == \'\':\n+ if send_from_address == "":\n IStatusMessage(self.request).addStatusMessage(\n- _(\'Could not find a valid email address\'),\n- type=\'error\'\n+ _("Could not find a valid email address"), type="error"\n )\n return\n \n sender_id = "{} ({}), {}".format(\n- sender.getProperty(\'fullname\'),\n- sender.getId(),\n- send_from_address\n+ sender.getProperty("fullname"), sender.getId(), send_from_address\n )\n \n mail_host = getUtility(IMailHost)\n registry = getUtility(IRegistry)\n- email_charset = registry.get(\'plone.email_charset\', \'utf-8\')\n+ email_charset = registry.get("plone.email_charset", "utf-8")\n \n try:\n message = self.feedback_template(\n- self, send_from_address=send_from_address,\n- sender_id=sender_id, url=referer, subject=subject,\n- message=message, encoding=email_charset,\n- email_from_name=mail_settings.email_from_name\n+ self,\n+ send_from_address=send_from_address,\n+ sender_id=sender_id,\n+ url=referer,\n+ subject=subject,\n+ message=message,\n+ encoding=email_charset,\n+ email_from_name=mail_settings.email_from_name,\n )\n \n message = message.encode(email_charset)\n \n mail_host.send(\n- message, send_to_address, envelope_from,\n- subject=subject, charset=email_charset\n+ message,\n+ send_to_address,\n+ envelope_from,\n+ subject=subject,\n+ charset=email_charset,\n )\n except ConflictError:\n raise\n@@ -114,32 +112,27 @@ def handle_send(self, action):\n logger.info("Unable to send mail: " + str(e))\n \n IStatusMessage(self.request).addStatusMessage(\n- _(\'Unable to send mail.\'),\n- type=\'error\'\n+ _("Unable to send mail."), type="error"\n )\n \n return\n \n- IStatusMessage(self.request).addStatusMessage(\n- _(\'Mail sent.\'),\n- type=\'info\'\n+ IStatusMessage(self.request).addStatusMessage(_("Mail sent."), type="info")\n+ self.request.response.redirect(\n+ "{}/author/{}".format(self.portal.absolute_url(), author or "")\n )\n- self.request.response.redirect(\'{}/author/{}\'.format(\n- self.portal.absolute_url(),\n- author or \'\'))\n return\n \n \n @implementer(IPublishTraverse)\n class AuthorView(BrowserView):\n-\n def __init__(self, context, request):\n super().__init__(context, request)\n \n self.username = None\n \n def publishTraverse(self, request, name):\n- request[\'TraversalRequestNameStack\'] = []\n+ request["TraversalRequestNameStack"] = []\n \n self.username = name\n return self\n@@ -166,46 +159,37 @@ def author(self):\n if not authorinfo or not portrait:\n return {}\n \n- return {\n- \'info\': authorinfo,\n- \'portrait\': portrait\n- }\n+ return {"info": authorinfo, "portrait": portrait}\n \n @property\n def member_info(self):\n current_member = self.portal_state.member()\n if not current_member or not current_member.getId():\n- return {\'url\': None, \'email\': None}\n+ return {"url": None, "email": None}\n \n return {\n- \'url\': quote_plus(current_member.getId()),\n- \'email\': current_member.getProperty(\'email\')\n+ "url": quote_plus(current_member.getId()),\n+ "email": current_member.getProperty("email"),\n }\n \n @property\n def author_content(self):\n results = []\n \n- plone_view = self.context.restrictedTraverse(\n- \'@@plone\'\n- )\n+ plone_view = self.context.restrictedTraverse("@@plone")\n \n brains = self.portal_catalog.searchResults(\n- Creator=self.username,\n- sort_on=\'created\',\n- sort_order=\'reverse\'\n+ Creator=self.username, sort_on="created", sort_order="reverse"\n )\n \n for brain in brains[:10]:\n- results.append({\n- \'title\': pretty_title_or_id(\n- self, brain\n- ),\n- \'date\': plone_view.toLocalizedTime(\n- brain.Date\n- ),\n- \'url\': brain.getURL()\n- })\n+ results.append(\n+ {\n+ "title": pretty_title_or_id(self, brain),\n+ "date": plone_view.toLocalizedTime(brain.Date),\n+ "url": brain.getURL(),\n+ }\n+ )\n \n return results\n \n@@ -213,43 +197,31 @@ def home_folder(self, username):\n return self.membership_tool.getHomeFolder(id=username)\n \n def __call__(self):\n+ self.portal_properties = getUtility(IPropertiesTool)\n \n- self.portal_properties = getUtility(\n- IPropertiesTool\n- )\n-\n- self.portal_catalog = getToolByName(\n- self.context, \'portal_catalog\'\n- )\n+ self.portal_catalog = getToolByName(self.context, "portal_catalog")\n \n # XXX: getUtility call does not work.\n- self.membership_tool = getToolByName(\n- self.context, \'portal_membership\'\n- )\n+ self.membership_tool = getToolByName(self.context, "portal_membership")\n \n self.portal_state = getMultiAdapter(\n- (self.context, self.request),\n- name=\'plone_portal_state\'\n+ (self.context, self.request), name="plone_portal_state"\n )\n \n- self.feedback_form = AuthorFeedbackForm(\n- self.context, self.request\n- )\n+ self.feedback_form = AuthorFeedbackForm(self.context, self.request)\n self.feedback_form.update()\n self.feedback_form.widgets["author"].mode = HIDDEN_MODE\n self.feedback_form.widgets["referer"].mode = HIDDEN_MODE\n self.feedback_form.widgets["author"].value = self.username\n self.feedback_form.widgets["referer"].value = self.request.get(\n- \'referer\',\n- self.request.get(\'HTTP_REFERER\', \'unknown url\')\n+ "referer", self.request.get("HTTP_REFERER", "unknown url")\n )\n \n registry = getUtility(IRegistry)\n- security_settings = registry.forInterface(\n- ISecuritySchema, prefix=\'plone\')\n+ security_settings = registry.forInterface(ISecuritySchema, prefix="plone")\n allow_anonymous_view_about = security_settings.allow_anon_views_about\n \n- mail_settings = registry.forInterface(IMailSchema, prefix=\'plone\')\n+ mail_settings = registry.forInterface(IMailSchema, prefix="plone")\n self.email_from_address = mail_settings.email_from_address\n \n if self.is_anonymous and not allow_anonymous_view_about:\ndiff --git a/Products/CMFPlone/browser/contact_info.py b/Products/CMFPlone/browser/contact_info.py\nindex dd38f91da0..3e9e5ac6aa 100644\n--- a/Products/CMFPlone/browser/contact_info.py\n+++ b/Products/CMFPlone/browser/contact_info.py\n@@ -29,9 +29,8 @@\n \n \n class ContactForm(AutoExtensibleForm, form.Form):\n-\n- template = ViewPageTemplateFile(\'templates/contact-info.pt\')\n- template_mailview = \'@@contact-info-email\'\n+ template = ViewPageTemplateFile("templates/contact-info.pt")\n+ template_mailview = "@@contact-info-email"\n \n schema = IContactForm\n ignoreContext = True\n@@ -44,14 +43,11 @@ def mailhost_is_configured(self):\n return False\n return True\n \n- @button.buttonAndHandler(_(\'label_send\', default=\'Send\'), name=\'send\')\n+ @button.buttonAndHandler(_("label_send", default="Send"), name="send")\n def handle_send(self, action):\n data, errors = self.extractData()\n if errors:\n- IStatusMessage(self.request).add(\n- self.formErrorsMessage,\n- type=\'error\'\n- )\n+ IStatusMessage(self.request).add(self.formErrorsMessage, type="error")\n \n return\n \n@@ -74,25 +70,25 @@ def generate_mail(self, variables, encoding=None):\n return result\n \n def send_message(self, data):\n- subject = data.get(\'subject\')\n+ subject = data.get("subject")\n \n portal = getSite()\n registry = getUtility(IRegistry)\n- mail_settings = registry.forInterface(IMailSchema, prefix=\'plone\')\n+ mail_settings = registry.forInterface(IMailSchema, prefix="plone")\n send_to_address = mail_settings.email_from_address\n from_address = mail_settings.email_from_address\n registry = getUtility(IRegistry)\n- encoding = registry.get(\'plone.email_charset\', \'utf-8\')\n- host = getToolByName(self.context, \'MailHost\')\n+ encoding = registry.get("plone.email_charset", "utf-8")\n+ host = getToolByName(self.context, "MailHost")\n \n- data[\'url\'] = portal.absolute_url()\n+ data["url"] = portal.absolute_url()\n message = self.generate_mail(data)\n if isinstance(message, bytes):\n # Maybe someone has customized \'generate_mail\'\n # and still handles the encoding keyword argument.\n message = message.decode(encoding)\n message = message_from_string(message)\n- message[\'Reply-To\'] = data[\'sender_from_address\']\n+ message["Reply-To"] = data["sender_from_address"]\n \n try:\n # This actually sends out the mail\n@@ -101,18 +97,21 @@ def send_message(self, data):\n send_to_address,\n from_address,\n subject=subject,\n- charset=encoding\n+ charset=encoding,\n )\n except (SMTPException, RuntimeError) as e:\n log.error(e)\n- plone_utils = getToolByName(portal, \'plone_utils\')\n+ plone_utils = getToolByName(portal, "plone_utils")\n exception = plone_utils.exceptionString()\n- message = _(\'Unable to send mail: ${exception}\',\n- mapping={\'exception\': exception})\n- IStatusMessage(self.request).add(message, type=\'error\')\n+ message = _(\n+ "Unable to send mail: ${exception}", mapping={"exception": exception}\n+ )\n+ IStatusMessage(self.request).add(message, type="error")\n \n def send_feedback(self):\n IStatusMessage(self.request).add(\n- _(\'A mail has now been sent to the site administrator \'\n- \'regarding your questions and/or comments.\')\n+ _(\n+ "A mail has now been sent to the site administrator "\n+ "regarding your questions and/or comments."\n+ )\n )\ndiff --git a/Products/CMFPlone/browser/defaultpage.py b/Products/CMFPlone/browser/defaultpage.py\nindex 026b54e94b..84b4fc0db0 100644\n--- a/Products/CMFPlone/browser/defaultpage.py\n+++ b/Products/CMFPlone/browser/defaultpage.py\n@@ -8,7 +8,6 @@\n \n @implementer(IDefaultPage)\n class DefaultPage(BrowserView):\n-\n def isDefaultPage(self, obj):\n return is_default_page(aq_inner(self.context), obj)\n \ndiff --git a/Products/CMFPlone/browser/exceptions.py b/Products/CMFPlone/browser/exceptions.py\nindex 7c3825c53e..65853e6f10 100644\n--- a/Products/CMFPlone/browser/exceptions.py\n+++ b/Products/CMFPlone/browser/exceptions.py\n@@ -10,11 +10,10 @@\n \n \n class ExceptionView(BrowserView):\n- basic_template = ViewPageTemplateFile(\'templates/basic_error_message.pt\')\n+ basic_template = ViewPageTemplateFile("templates/basic_error_message.pt")\n \n def is_manager(self):\n- return getSecurityManager().checkPermission(\n- \'Manage portal\', self.context)\n+ return getSecurityManager().checkPermission("Manage portal", self.context)\n \n @property\n @memoize\n@@ -35,27 +34,24 @@ def __call__(self):\n request = self.request\n \n exc_type, value, traceback = sys.exc_info()\n- error_tb = \'\'.join(\n- format_exception(exc_type, value, traceback, as_html=False))\n+ error_tb = "".join(format_exception(exc_type, value, traceback, as_html=False))\n request.response.setStatus(exc_type)\n \n # Indicate exception as JSON\n- if "text/html" not in request.getHeader(\'Accept\', \'\'):\n+ if "text/html" not in request.getHeader("Accept", ""):\n request.response.setHeader("Content-Type", "application/json")\n- return json.dumps({\n- \'error_type\': error_type,\n- })\n+ return json.dumps(\n+ {\n+ "error_type": error_type,\n+ }\n+ )\n \n # Render page with user-facing error notice\n- request.set(\'disable_border\', True)\n- request.set(\'disable_plone.leftcolumn\', True)\n- request.set(\'disable_plone.rightcolumn\', True)\n+ request.set("disable_border", True)\n+ request.set("disable_plone.leftcolumn", True)\n+ request.set("disable_plone.rightcolumn", True)\n \n try:\n- return self.index(\n- error_type=error_type,\n- error_tb=error_tb)\n+ return self.index(error_type=error_type, error_tb=error_tb)\n except:\n- return self.basic_template(\n- error_type=error_type,\n- error_tb=error_tb)\n+ return self.basic_template(error_type=error_type, error_tb=error_tb)\ndiff --git a/Products/CMFPlone/browser/global_statusmessage.py b/Products/CMFPlone/browser/global_statusmessage.py\nindex b0971d10f6..55aad6dd60 100644\n--- a/Products/CMFPlone/browser/global_statusmessage.py\n+++ b/Products/CMFPlone/browser/global_statusmessage.py\n@@ -8,7 +8,7 @@\n class GlobalStatusMessage(BrowserView):\n """Display messages to the current user"""\n \n- index = ViewPageTemplateFile(\'templates/global_statusmessage.pt\')\n+ index = ViewPageTemplateFile("templates/global_statusmessage.pt")\n \n def __call__(self):\n return self.index()\ndiff --git a/Products/CMFPlone/browser/icons.py b/Products/CMFPlone/browser/icons.py\nindex 6858edb649..c3c52ee955 100644\n--- a/Products/CMFPlone/browser/icons.py\n+++ b/Products/CMFPlone/browser/icons.py\n@@ -21,46 +21,50 @@\n \n SVG_MODIFER = {}\n \n+\n def _add_aria_title(svgtree, cfg):\n if not cfg.get("title"):\n return\n root = svgtree.getroot()\n ns = root.nsmap.get(None, "")\n # set title tag\n- title = root.find(f\'{{{ns}}}title\')\n+ title = root.find(f"{{{ns}}}title")\n if title is None:\n title = etree.Element("title")\n root.append(title)\n- title.text = cfg[\'title\']\n+ title.text = cfg["title"]\n # add aria attr\n root.attrib["aria-labelledby"] = "title"\n \n \n-SVG_MODIFER[\'add_aria_title\'] = _add_aria_title\n+SVG_MODIFER["add_aria_title"] = _add_aria_title\n \n ADDITIONAL_CLASSES = [\n # this classes are added to all svg root elements\n "plone-icon",\n ]\n \n+\n def _add_css_class(svgtree, cfg):\n- cssclass = cfg.get(\'cssclass\', "")\n+ cssclass = cfg.get("cssclass", "")\n root = svgtree.getroot()\n- current = root.attrib.get(\'class\', \'\')\n- root.attrib[\'class\'] = f"{\' \'.join(ADDITIONAL_CLASSES)} {cfg[\'cssclass\']} {current}"\n+ current = root.attrib.get("class", "")\n+ root.attrib["class"] = f"{\' \'.join(ADDITIONAL_CLASSES)} {cfg[\'cssclass\']} {current}"\n+\n+\n+SVG_MODIFER["add_css_class"] = _add_css_class\n \n-SVG_MODIFER[\'add_css_class\'] = _add_css_class\n \n def _strip_id(svgtree, cfg):\n for el in svgtree.getroot().xpath("//*[@id]"):\n del el.attrib["id"]\n \n-SVG_MODIFER[\'strip_id\'] = _strip_id\n+\n+SVG_MODIFER["strip_id"] = _strip_id\n \n \n @implementer(IPublishTraverse)\n class IconsView(BrowserView):\n-\n prefix = "plone.icon."\n defaulticon = "++plone++icons/plone.svg"\n name = ""\n@@ -125,11 +129,13 @@ def tag(self, name, tag_class="", tag_alt=""):\n logger.exception(f"SVG File: {iconfile.path}")\n with open(iconfile.path, "rb") as fh:\n return fh.read()\n- if svgtree.docinfo.root_name.lower() != \'svg\':\n- raise ValueError(f"SVG file content root tag mismatch (not svg but {svgtree.docinfo.root_name}): {iconfile.path}")\n+ if svgtree.docinfo.root_name.lower() != "svg":\n+ raise ValueError(\n+ f"SVG file content root tag mismatch (not svg but {svgtree.docinfo.root_name}): {iconfile.path}"\n+ )\n modifier_cfg = {\n- \'cssclass\': tag_class,\n- \'title\': tag_alt,\n+ "cssclass": tag_class,\n+ "title": tag_alt,\n }\n for name, modifier in SVG_MODIFER.items():\n __traceback_info__ = name\ndiff --git a/Products/CMFPlone/browser/interfaces.py b/Products/CMFPlone/browser/interfaces.py\nindex 2e08f93b5e..32c764d342 100644\n--- a/Products/CMFPlone/browser/interfaces.py\n+++ b/Products/CMFPlone/browser/interfaces.py\n@@ -12,40 +12,31 @@\n zope.deferredimport.deprecated(\n "It has been moved to plone.app.layout.navigation.interfaces. "\n "This alias will be removed in Plone 5.0",\n- INavigationRoot=\'plone.app.layout.navigation.interfaces:INavigationRoot\',\n+ INavigationRoot="plone.app.layout.navigation.interfaces:INavigationRoot",\n )\n \n \n class INavigationBreadcrumbs(Interface):\n-\n def breadcrumbs():\n- """Breadcrumbs for Navigation.\n- """\n+ """Breadcrumbs for Navigation."""\n \n \n class INavigationTabs(Interface):\n-\n- def topLevelTabs(actions=None, category=\'portal_tabs\'):\n- """Top level tabs\n- """\n+ def topLevelTabs(actions=None, category="portal_tabs"):\n+ """Top level tabs"""\n \n \n class INavigationTree(Interface):\n-\n def navigationTreeRootPath():\n- """Get the path to the root of the navigation tree\n- """\n+ """Get the path to the root of the navigation tree"""\n \n def navigationTree():\n- """Navigation tree\n- """\n+ """Navigation tree"""\n \n \n class ISiteMap(Interface):\n-\n def siteMap():\n- """Site map\n- """\n+ """Site map"""\n \n \n class INavigationPortlet(Interface):\n@@ -78,12 +69,12 @@ class INewsPortlet(Interface):\n \n def published_news_items():\n """Returns 5 most recently published News Items in reverse\n- chronological order\n+ chronological order\n """\n \n def all_news_link():\n """Returns URL, relative to the portal, of a page that display all\n- published News Items\n+ published News Items\n """\n \n \n@@ -92,17 +83,17 @@ class IEventsPortlet(Interface):\n \n def published_events():\n """Returns 5 most recently published News Items in reverse\n- chronological order\n+ chronological order\n """\n \n def all_events_link():\n """Returns URL, relative to the portal, of a page that display all\n- published News Items\n+ published News Items\n """\n \n def prev_events_link():\n """Returns URL, relative to the portal, of a page that display all\n- past events.\n+ past events.\n """\n \n \n@@ -114,7 +105,6 @@ def results():\n \n \n class ICalendarPortlet(Interface):\n-\n def DateTime():\n """ """\n \n@@ -174,7 +164,7 @@ def getMonthName(self, month):\n \n def isToday(self, day):\n """Returns True if the given day and the current month and year equals\n- today, otherwise False.\n+ today, otherwise False.\n """\n \n \n@@ -200,29 +190,28 @@ class IPlone(Interface):\n """ """\n \n def getCurrentUrl():\n- """ Returns the actual url plus the query string. """\n+ """Returns the actual url plus the query string."""\n \n def uniqueItemIndex(pos=0):\n """Return an index iterator."""\n \n def toLocalizedTime(time, long_format=None, time_only=None):\n- """ The time parameter must be either a string that is suitable for\n- initializing a DateTime or a DateTime object. Returns a localized\n- string.\n+ """The time parameter must be either a string that is suitable for\n+ initializing a DateTime or a DateTime object. Returns a localized\n+ string.\n """\n \n def toLocalizedSize(size):\n- """ Convert an integer to a localized size string\n+ """Convert an integer to a localized size string\n 3322 -> 3KB in english, 3Ko in french\n """\n \n def normalizeString(text):\n- """Normalizes a title to an id.\n- """\n+ """Normalizes a title to an id."""\n \n def isDefaultPageInFolder():\n- """ Returns a boolean indicating whether the current context is the\n- default page of its parent folder.\n+ """Returns a boolean indicating whether the current context is the\n+ default page of its parent folder.\n """\n \n def isStructuralFolder():\n@@ -234,139 +223,124 @@ def isStructuralFolder():\n """\n \n def navigationRootPath():\n- """Get the current navigation root path\n- """\n+ """Get the current navigation root path"""\n \n def navigationRootUrl():\n- """Get the url to the current navigation root\n- """\n+ """Get the url to the current navigation root"""\n \n def getParentObject():\n """Returns the parent of the current object, equivalent to\n- aq_inner(aq_parent(context)), or context.aq_inner.getParentNode()\n+ aq_inner(aq_parent(context)), or context.aq_inner.getParentNode()\n """\n \n def getCurrentFolder():\n """If the context is the default page of a folder or is not itself a\n- folder, the parent is returned, otherwise the object itself is\n- returned. This is useful for providing a context for methods\n- which wish to act on what is considered the current folder in the\n- ui.\n+ folder, the parent is returned, otherwise the object itself is\n+ returned. This is useful for providing a context for methods\n+ which wish to act on what is considered the current folder in the\n+ ui.\n """\n \n def getCurrentFolderUrl():\n """Returns the URL of the current folder as determined by\n- self.getCurrentFolder(), used heavily in actions.\n+ self.getCurrentFolder(), used heavily in actions.\n """\n \n def getCurrentObjectUrl():\n """Returns the URL of the current object unless that object is a\n- folder default page, in which case it returns the parent.\n+ folder default page, in which case it returns the parent.\n """\n \n def isFolderOrFolderDefaultPage():\n """Returns true only if the current object is either a folder (as\n- determined by isStructuralFolder) or the default page in context.\n+ determined by isStructuralFolder) or the default page in context.\n """\n \n def isPortalOrPortalDefaultPage():\n """Returns true only if the current object is either the portal object\n- or the default page of the portal.\n+ or the default page of the portal.\n """\n \n def getViewTemplateId():\n """Returns the template Id corresponding to the default view method of\n- the context object.\n+ the context object.\n """\n \n def showToolbar():\n- """Returns true if the editable border should be shown\n- """\n+ """Returns true if the editable border should be shown"""\n \n def cropText(text, length, ellipsis):\n- """ Crop text on a word boundary """\n+ """Crop text on a word boundary"""\n \n def site_encoding():\n- """ returns site encoding """\n+ """returns site encoding"""\n \n def patterns_settings():\n- """ returns mockup pattern settings """\n+ """returns mockup pattern settings"""\n \n \n class ISendToForm(Interface):\n- """ Interface for describing the \'sendto\' form """\n+ """Interface for describing the \'sendto\' form"""\n \n send_to_address = Email(\n- title=_(\'label_send_to_mail\',\n- default=\'Send to\'),\n- description=_(\'help_send_to_mail\',\n- default=\'The e-mail address to send this link to.\'),\n- required=True\n+ title=_("label_send_to_mail", default="Send to"),\n+ description=_(\n+ "help_send_to_mail", default="The e-mail address to send this link to."\n+ ),\n+ required=True,\n )\n \n send_from_address = Email(\n- title=_(\'label_send_from\',\n- default=\'From\'),\n- description=_(\'help_send_from\',\n- default=\'Your email address.\'),\n- required=True\n+ title=_("label_send_from", default="From"),\n+ description=_("help_send_from", default="Your email address."),\n+ required=True,\n )\n \n comment = schema.Text(\n- title=_(\'label_comment\',\n- default=\'Comment\'),\n- description=_(\'help_comment_to_link\',\n- default=\'A comment about this link.\'),\n- required=False\n+ title=_("label_comment", default="Comment"),\n+ description=_("help_comment_to_link", default="A comment about this link."),\n+ required=False,\n )\n \n \n class IContactForm(Interface):\n- """ Interface for describing the contact info form """\n+ """Interface for describing the contact info form"""\n \n sender_fullname = schema.TextLine(\n- title=_(\'label_sender_fullname\',\n- default=\'Name\'),\n- description=_(\'help_sender_fullname\',\n- default=\'Please enter your full name.\'),\n- required=True\n+ title=_("label_sender_fullname", default="Name"),\n+ description=_("help_sender_fullname", default="Please enter your full name."),\n+ required=True,\n )\n \n sender_from_address = Email(\n- title=_(\'label_sender_from_address\',\n- default=\'From\'),\n- description=_(\'help_sender_from_address\',\n- default=\'Please enter your e-mail address.\'),\n- required=True\n+ title=_("label_sender_from_address", default="From"),\n+ description=_(\n+ "help_sender_from_address", default="Please enter your e-mail address."\n+ ),\n+ required=True,\n )\n \n subject = schema.TextLine(\n- title=_(\'label_subject\',\n- default=\'Subject\'),\n- required=True\n+ title=_("label_subject", default="Subject"), required=True\n )\n \n message = schema.Text(\n- title=_(\'label_message\',\n- default=\'Message\'),\n- description=_(\'help_message\',\n- default=\'Please enter the message you want to send.\'),\n- required=False\n+ title=_("label_message", default="Message"),\n+ description=_(\n+ "help_message", default="Please enter the message you want to send."\n+ ),\n+ required=False,\n )\n \n \n class IAuthorFeedbackForm(Interface):\n- """ Interface describing the author feedback form """\n+ """Interface describing the author feedback form"""\n \n subject = schema.TextLine(\n- title=_(\'label_subject\', default=\'Subject\'),\n- required=True\n+ title=_("label_subject", default="Subject"), required=True\n )\n \n- message = schema.Text(\n- title=_(\'label_message\', default=\'Message\'),\n- required=True\n- )\n+ message = schema.Text(title=_("label_message", default="Message"), required=True)\n \n author = schema.TextLine()\n referer = schema.TextLine(required=False)\ndiff --git a/Products/CMFPlone/browser/login/login.py b/Products/CMFPlone/browser/login/login.py\nindex 12f920cd65..a7fdd67897 100644\n--- a/Products/CMFPlone/browser/login/login.py\n+++ b/Products/CMFPlone/browser/login/login.py\n@@ -28,58 +28,58 @@\n # TODO: Scale down this list now that we\'ve removed a lot of\n # templates.\n LOGIN_TEMPLATE_IDS = [\n- \'localhost\',\n- \'logged-out\',\n- \'logged_in\',\n- \'login\',\n- \'login_failed\',\n- \'login_form\',\n- \'login_password\',\n- \'login_success\',\n- \'logout\',\n- \'mail_password\',\n- \'mail_password_form\',\n- \'member_search_results\',\n- \'pwreset_finish\',\n- \'passwordreset\',\n- \'register\',\n- \'registered\',\n- \'require_login\',\n+ "localhost",\n+ "logged-out",\n+ "logged_in",\n+ "login",\n+ "login_failed",\n+ "login_form",\n+ "login_password",\n+ "login_success",\n+ "logout",\n+ "mail_password",\n+ "mail_password_form",\n+ "member_search_results",\n+ "pwreset_finish",\n+ "passwordreset",\n+ "register",\n+ "registered",\n+ "require_login",\n ]\n \n \n @implementer(ILoginForm)\n class LoginForm(form.EditForm):\n- """ Implementation of the login form """\n+ """Implementation of the login form"""\n \n fields = field.Fields(ILoginFormSchema)\n \n- id = \'LoginForm\'\n- label = _(\'label_log_in\', default=\'Log in\')\n+ id = "LoginForm"\n+ label = _("label_log_in", default="Log in")\n \n ignoreContext = True\n- prefix = \'\'\n+ prefix = ""\n \n def render(self):\n registry = queryUtility(IRegistry)\n- ext_login_url = registry[\'plone.external_login_url\']\n+ ext_login_url = registry["plone.external_login_url"]\n if ext_login_url:\n return self._handle_external_login(ext_login_url)\n return self.index()\n \n def _handle_external_login(self, url):\n """Handle login on this portal where login is external."""\n- next_ = self.request.get(\'next\', None)\n- came_from = self.request.get(\'came_from\')\n+ next_ = self.request.get("next", None)\n+ came_from = self.request.get("came_from")\n urlparts = [part for part in parse.urlparse(url)]\n qs = dict(parse.parse_qsl(urlparts[4]))\n- portal_url = getToolByName(self.context, \'portal_url\')\n+ portal_url = getToolByName(self.context, "portal_url")\n if next_ is not None and not portal_url.isURLInPortal(next_):\n next_ = None\n if next_ is not None:\n- qs[\'next\'] = next_\n+ qs["next"] = next_\n if came_from:\n- qs[\'came_from\'] = came_from\n+ qs["came_from"] = came_from\n urlparts[4] = parse.urlencode(qs)\n self.request.response.redirect(parse.urlunparse(urlparts))\n \n@@ -93,38 +93,37 @@ def _get_auth(self):\n pass\n \n def updateWidgets(self):\n- super().updateWidgets(prefix=\'\')\n+ super().updateWidgets(prefix="")\n \n auth = self._get_auth()\n \n if auth:\n- widgetname_login = auth.get(\'name_cookie\', \'__ac_name\')\n- widgetname_password = auth.get(\'pw_cookie\', \'__ac_password\')\n+ widgetname_login = auth.get("name_cookie", "__ac_name")\n+ widgetname_password = auth.get("pw_cookie", "__ac_password")\n else:\n- widgetname_login = \'__ac_name\'\n- widgetname_password = \'__ac_password\'\n+ widgetname_login = "__ac_name"\n+ widgetname_password = "__ac_password"\n \n- self.widgets[\'ac_name\'].name = widgetname_login\n- self.widgets[\'ac_name\'].id = widgetname_login\n- self.widgets[\'ac_password\'].name = widgetname_password\n- self.widgets[\'ac_password\'].id = widgetname_password\n+ self.widgets["ac_name"].name = widgetname_login\n+ self.widgets["ac_name"].id = widgetname_login\n+ self.widgets["ac_password"].name = widgetname_password\n+ self.widgets["ac_password"].id = widgetname_password\n \n if self.use_email_as_login():\n- self.widgets[\'ac_name\'].label = _(\'label_email\',\n- default=\'Email\')\n- self.widgets[\'came_from\'].mode = HIDDEN_MODE\n- self.widgets[\'came_from\'].value = self.get_came_from()\n+ self.widgets["ac_name"].label = _("label_email", default="Email")\n+ self.widgets["came_from"].mode = HIDDEN_MODE\n+ self.widgets["came_from"].value = self.get_came_from()\n \n def get_came_from(self):\n- came_from = self.request.get(\'came_from\', None)\n+ came_from = self.request.get("came_from", None)\n if not came_from:\n- came_from = self.request.get(\'HTTP_REFERER\', None)\n+ came_from = self.request.get("HTTP_REFERER", None)\n if not came_from:\n return\n- url_tool = getToolByName(self.context, \'portal_url\')\n+ url_tool = getToolByName(self.context, "portal_url")\n if not url_tool.isURLInPortal(came_from):\n return\n- came_from_path = parse.urlparse(came_from)[2].split(\'/\')\n+ came_from_path = parse.urlparse(came_from)[2].split("/")\n for login_template_id in LOGIN_TEMPLATE_IDS:\n if login_template_id in came_from_path:\n return\n@@ -132,13 +131,13 @@ def get_came_from(self):\n \n def updateActions(self):\n super().updateActions()\n- self.actions[\'login\'].addClass(\'btn-primary\')\n+ self.actions["login"].addClass("btn-primary")\n \n def _post_login(self):\n- membership_tool = getToolByName(self.context, \'portal_membership\')\n+ membership_tool = getToolByName(self.context, "portal_membership")\n member = membership_tool.getAuthenticatedMember()\n- must_change_password = member.getProperty(\'must_change_password\', 0)\n- login_time = member.getProperty(\'login_time\', None)\n+ must_change_password = member.getProperty("must_change_password", 0)\n+ login_time = member.getProperty("login_time", None)\n is_initial_login = not has_logged_in(login_time)\n \n membership_tool.loginUser(self.request)\n@@ -149,44 +148,44 @@ def _post_login(self):\n self.force_password_change()\n return is_initial_login\n \n- @button.buttonAndHandler(_(\'Log in\'), name=\'login\')\n+ @button.buttonAndHandler(_("Log in"), name="login")\n def handleLogin(self, action):\n data, errors = self.extractData()\n if errors:\n self.status = self.formErrorsMessage\n return\n- membership_tool = getToolByName(self.context, \'portal_membership\')\n+ membership_tool = getToolByName(self.context, "portal_membership")\n status_msg = IStatusMessage(self.request)\n if membership_tool.isAnonymousUser():\n- self.request.response.expireCookie(\'__ac\', path=\'/\')\n+ self.request.response.expireCookie("__ac", path="/")\n if self.use_email_as_login():\n status_msg.addStatusMessage(\n _(\n- \'Login failed. Both email address and password are \'\n- \'case sensitive, check that caps lock is not enabled.\'\n+ "Login failed. Both email address and password are "\n+ "case sensitive, check that caps lock is not enabled."\n ),\n- \'error\',\n+ "error",\n )\n else:\n status_msg.addStatusMessage(\n _(\n- \'Login failed. Both login name and password are case \'\n- \'sensitive, check that caps lock is not enabled.\'\n+ "Login failed. Both login name and password are case "\n+ "sensitive, check that caps lock is not enabled."\n ),\n- \'error\',\n+ "error",\n )\n return\n \n is_initial_login = self._post_login()\n status_msg.addStatusMessage(\n _(\n- \'you_are_now_logged_in\',\n- default=\'Welcome! You are now logged in.\',\n+ "you_are_now_logged_in",\n+ default="Welcome! You are now logged in.",\n ),\n- \'info\'\n+ "info",\n )\n \n- came_from = data.get(\'came_from\', None)\n+ came_from = data.get("came_from", None)\n self.redirect_after_login(came_from, is_initial_login)\n \n def handle_initial_login(self):\n@@ -206,10 +205,7 @@ def force_password_change(self):\n handler()\n \n def redirect_after_login(self, came_from=None, is_initial_login=False):\n- adapter = queryMultiAdapter(\n- (self.context, self.request),\n- IRedirectAfterLogin\n- )\n+ adapter = queryMultiAdapter((self.context, self.request), IRedirectAfterLogin)\n if adapter:\n came_from = adapter(came_from, is_initial_login)\n if not came_from:\n@@ -219,81 +215,69 @@ def redirect_after_login(self, came_from=None, is_initial_login=False):\n \n def self_registration_enabled(self):\n registry = queryUtility(IRegistry)\n- security_settings = registry.forInterface(\n- ISecuritySchema,\n- prefix=\'plone\'\n- )\n+ security_settings = registry.forInterface(ISecuritySchema, prefix="plone")\n return security_settings.enable_self_reg\n \n def use_email_as_login(self):\n registry = queryUtility(IRegistry)\n- security_settings = registry.forInterface(\n- ISecuritySchema,\n- prefix=\'plone\'\n- )\n+ security_settings = registry.forInterface(ISecuritySchema, prefix="plone")\n return security_settings.use_email_as_login\n \n \n class FailsafeLoginForm(LoginForm):\n-\n def render(self):\n return self.index()\n \n \n class RequireLoginView(BrowserView):\n-\n def __call__(self):\n portal_state = getMultiAdapter(\n (self.context, self.request),\n- name=\'plone_portal_state\',\n+ name="plone_portal_state",\n )\n portal = portal_state.portal()\n if portal_state.anonymous():\n- url = f\'{portal.absolute_url():s}/login\'\n- came_from = self.request.get(\'came_from\', None)\n+ url = f"{portal.absolute_url():s}/login"\n+ came_from = self.request.get("came_from", None)\n if came_from:\n- url += f\'?came_from={parse.quote(came_from):s}\'\n+ url += f"?came_from={parse.quote(came_from):s}"\n else:\n- url = f\'{portal.absolute_url():s}/insufficient-privileges\'\n+ url = f"{portal.absolute_url():s}/insufficient-privileges"\n \n self.request.response.redirect(url)\n \n \n class InsufficientPrivilegesView(BrowserView):\n-\n def request_url(self):\n- return self.request.get(\'came_from\')\n+ return self.request.get("came_from")\n \n \n class InitialLoginPasswordChange(PasswordPanel):\n-\n def render(self):\n return self.index()\n \n @button.buttonAndHandler(\n- _(\'label_change_password\', default=\'Change Password\'),\n- name=\'reset_passwd\',\n+ _("label_change_password", default="Change Password"),\n+ name="reset_passwd",\n )\n def action_reset_passwd(self, action):\n- super().action_reset_passwd(\n- self, action)\n+ super().action_reset_passwd(self, action)\n if not action.form.widgets.errors:\n self.request.response.redirect(self.context.portal_url())\n \n \n class ForcedPasswordChange(PasswordPanel):\n-\n def render(self):\n return self.index()\n \n @button.buttonAndHandler(\n- _(\'label_change_password\', default=\'Change Password\'),\n- name=\'reset_passwd\',\n+ _("label_change_password", default="Change Password"),\n+ name="reset_passwd",\n )\n def action_reset_passwd(self, action):\n super().action_reset_passwd(self, action)\n if not action.form.widgets.errors:\n- membership_tool = getToolByName(self.context, \'portal_membership\')\n+ membership_tool = getToolByName(self.context, "portal_membership")\n member = membership_tool.getAuthenticatedMember()\n member.setProperties(must_change_password=0)\n self.request.response.redirect(self.context.portal_url())\ndiff --git a/Products/CMFPlone/browser/login/login_help.py b/Products/CMFPlone/browser/login/login_help.py\nindex 06f4170872..ae4bcc15b8 100644\n--- a/Products/CMFPlone/browser/login/login_help.py\n+++ b/Products/CMFPlone/browser/login/login_help.py\n@@ -31,7 +31,9 @@\n from email import message_from_string\n \n \n-SEND_USERNAME_TEMPLATE = _("mailtemplate_username_info", default="""From: {encoded_mail_sender}\n+SEND_USERNAME_TEMPLATE = _(\n+ "mailtemplate_username_info",\n+ default="""From: {encoded_mail_sender}\n To: {email}\n Subject: Your username for {portal_url}\n Content-Type: text/plain\n@@ -47,35 +49,31 @@\n \n --\n \n-{email_from_name}""")\n+{email_from_name}""",\n+)\n \n log = logging.getLogger(__name__)\n \n \n class RequestResetPassword(form.Form):\n-\n- id = \'RequestResetPassword\'\n- label = \'\'\n- fields = field.Fields(ILoginHelpFormSchema).select(\'reset_password\')\n+ id = "RequestResetPassword"\n+ label = ""\n+ fields = field.Fields(ILoginHelpFormSchema).select("reset_password")\n ignoreContext = True\n \n- render = ViewPageTemplateFile(\'templates/subform_render.pt\')\n+ render = ViewPageTemplateFile("templates/subform_render.pt")\n \n def updateActions(self):\n super().updateActions()\n- self.actions[\'reset\'].addClass(\'btn-primary\')\n+ self.actions["reset"].addClass("btn-primary")\n \n def updateWidgets(self):\n super().updateWidgets()\n if self.use_email_as_login():\n- self.widgets[\'reset_password\'].label = _(\n- \'label_email\',\n- default=\'Email\'\n- )\n+ self.widgets["reset_password"].label = _("label_email", default="Email")\n \n @button.buttonAndHandler(\n- _(\'button_pwreset_reset_password\', default=\'Reset your password\'),\n- name=\'reset\'\n+ _("button_pwreset_reset_password", default="Reset your password"), name="reset"\n )\n def handleResetPassword(self, action):\n data, errors = self.extractData()\n@@ -83,44 +81,51 @@ def handleResetPassword(self, action):\n self.status = self.formErrorsMessage\n return\n portal = getSite()\n- regtool = getToolByName(portal, \'portal_registration\')\n+ regtool = getToolByName(portal, "portal_registration")\n try:\n- regtool.mailPassword(data[\'reset_password\'], self.request)\n+ regtool.mailPassword(data["reset_password"], self.request)\n except ValueError as e:\n # Paranoia Warning!\n # We act as if a message has been sent to prevent probing Plone\n # for valid loginnames. Instead we log the error-message.\n- log.info(\'Error while trying to send a reset-password notice to user {}: {}\'.format(data[\'reset_password\'], e)) # noqa: E501\n+ log.info(\n+ "Error while trying to send a reset-password notice to user {}: {}".format(\n+ data["reset_password"], e\n+ )\n+ ) # noqa: E501\n pass\n \n IStatusMessage(self.request).addStatusMessage(\n- _(\'statusmessage_pwreset_password_mail_sent\', default=\'An \'\n- \'email has been sent with instructions on how to reset your \'\n- \'password.\'), \'info\')\n+ _(\n+ "statusmessage_pwreset_password_mail_sent",\n+ default="An "\n+ "email has been sent with instructions on how to reset your "\n+ "password.",\n+ ),\n+ "info",\n+ )\n \n def use_email_as_login(self):\n registry = getUtility(IRegistry)\n- security_settings = registry.forInterface(\n- ISecuritySchema, prefix=\'plone\')\n+ security_settings = registry.forInterface(ISecuritySchema, prefix="plone")\n return security_settings.use_email_as_login\n \n \n class RequestUsername(form.Form):\n-\n- id = \'RequestUsername\'\n- label = \'\'\n- fields = field.Fields(ILoginHelpFormSchema).select(\'recover_username\')\n+ id = "RequestUsername"\n+ label = ""\n+ fields = field.Fields(ILoginHelpFormSchema).select("recover_username")\n ignoreContext = True\n \n- render = ViewPageTemplateFile(\'templates/subform_render.pt\')\n+ render = ViewPageTemplateFile("templates/subform_render.pt")\n \n def updateActions(self):\n super().updateActions()\n- self.actions[\'get_username\'].addClass(\'btn-primary\')\n+ self.actions["get_username"].addClass("btn-primary")\n \n @button.buttonAndHandler(\n- _(\'button_pwreset_get_username\', default=\'Get your username\'),\n- name=\'get_username\'\n+ _("button_pwreset_get_username", default="Get your username"),\n+ name="get_username",\n )\n def handleGetUsername(self, action):\n data, errors = self.extractData()\n@@ -128,15 +133,15 @@ def handleGetUsername(self, action):\n self.status = self.formErrorsMessage\n return\n portal = getSite()\n- pas = getToolByName(portal, \'acl_users\')\n- email = data[\'recover_username\']\n+ pas = getToolByName(portal, "acl_users")\n+ email = data["recover_username"]\n results = pas.searchUsers(email=email, exact_match=True)\n send_email = True\n if not results:\n- log.info(f\'No user found for {email}\')\n+ log.info(f"No user found for {email}")\n send_email = False\n if len(results) > 1:\n- log.info(f\'More than one user found for {email}\')\n+ log.info(f"More than one user found for {email}")\n send_email = False\n if send_email:\n self.send_username(portal, results[0])\n@@ -147,51 +152,58 @@ def handleGetUsername(self, action):\n # Because of this we always act as if that an email has been sent.\n # Instead we log the error-message.\n IStatusMessage(self.request).addStatusMessage(\n- _(\'statusmessage_pwreset_username_mail_sent\',\n- default=\'An email has been sent with your username.\'),\n- \'info\'\n+ _(\n+ "statusmessage_pwreset_username_mail_sent",\n+ default="An email has been sent with your username.",\n+ ),\n+ "info",\n )\n \n def send_username(self, portal, userinfo):\n registry = getUtility(IRegistry)\n- encoding = registry.get(\'plone.email_charset\', \'utf-8\')\n+ encoding = registry.get("plone.email_charset", "utf-8")\n translated_template = translate(\n SEND_USERNAME_TEMPLATE,\n context=self.request,\n )\n \n mail_text = translated_template.format(\n- email=userinfo[\'email\'],\n+ email=userinfo["email"],\n portal_url=portal.absolute_url(),\n- fullname=userinfo[\'title\'],\n- login=userinfo[\'login\'],\n- email_from_name=registry[\'plone.email_from_name\'],\n+ fullname=userinfo["title"],\n+ login=userinfo["login"],\n+ email_from_name=registry["plone.email_from_name"],\n encoded_mail_sender=self.encoded_mail_sender(),\n )\n message_obj = message_from_string(mail_text.strip())\n- subject = message_obj[\'Subject\']\n- m_to = message_obj[\'To\']\n- m_from = message_obj[\'From\']\n- msg_type = message_obj.get(\'Content-Type\', \'text/plain\')\n+ subject = message_obj["Subject"]\n+ m_to = message_obj["To"]\n+ m_from = message_obj["From"]\n+ msg_type = message_obj.get("Content-Type", "text/plain")\n \n- host = getToolByName(portal, \'MailHost\')\n+ host = getToolByName(portal, "MailHost")\n try:\n- host.send(mail_text, m_to, m_from, subject=subject,\n- charset=encoding, immediate=True,\n- msg_type=msg_type)\n+ host.send(\n+ mail_text,\n+ m_to,\n+ m_from,\n+ subject=subject,\n+ charset=encoding,\n+ immediate=True,\n+ msg_type=msg_type,\n+ )\n except SMTPRecipientsRefused:\n # Don\'t disclose email address on failure\n- raise SMTPRecipientsRefused(\n- _(\'Recipient address rejected by server.\'))\n+ raise SMTPRecipientsRefused(_("Recipient address rejected by server."))\n except SMTPException as e:\n- raise(e)\n+ raise (e)\n \n def encode_mail_header(self, text):\n- """ Encodes text into correctly encoded email header """\n- return Header(safe_text(text), \'utf-8\')\n+ """Encodes text into correctly encoded email header"""\n+ return Header(safe_text(text), "utf-8")\n \n def encoded_mail_sender(self):\n- """ returns encoded version of Portal name """\n+ """returns encoded version of Portal name """\n registry = getUtility(IRegistry)\n mail_settings = registry.forInterface(IMailSchema, prefix="plone")\n from_ = mail_settings.email_from_name\n@@ -201,12 +213,12 @@ def encoded_mail_sender(self):\n \n @implementer(ILoginHelpForm)\n class LoginHelpForm(form.EditForm):\n- \'\'\' Implementation of the login help form \'\'\'\n+ """Implementation of the login help form"""\n \n subforms = []\n \n- id = \'LoginHelpForm\'\n- label = _(\'heading_login_form_help\', default=\'Need Help?\')\n+ id = "LoginHelpForm"\n+ label = _("heading_login_form_help", default="Need Help?")\n \n ignoreContext = True\n \n@@ -238,6 +250,5 @@ def update(self):\n \n def use_email_as_login(self):\n registry = getUtility(IRegistry)\n- security_settings = registry.forInterface(\n- ISecuritySchema, prefix=\'plone\')\n+ security_settings = registry.forInterface(ISecuritySchema, prefix="plone")\n return security_settings.use_email_as_login\ndiff --git a/Products/CMFPlone/browser/login/logout.py b/Products/CMFPlone/browser/login/logout.py\nindex 874dbfb161..50017cfd80 100644\n--- a/Products/CMFPlone/browser/login/logout.py\n+++ b/Products/CMFPlone/browser/login/logout.py\n@@ -15,21 +15,20 @@ class ILoggedOutView(Interface):\n \n \n class LogoutView(BrowserView):\n-\n def __call__(self):\n- mt = getToolByName(self.context, \'portal_membership\')\n+ mt = getToolByName(self.context, "portal_membership")\n mt.logoutUser(self.request)\n- transaction_note(\'Logged out\')\n+ transaction_note("Logged out")\n # Handle external logout requests from other portals\n- next_ = self.request.get(\'next\', None)\n- portal_url = getToolByName(self.context, \'portal_url\')\n+ next_ = self.request.get("next", None)\n+ portal_url = getToolByName(self.context, "portal_url")\n if next_ is not None and portal_url.isURLInPortal(next_):\n target_url = next_\n else:\n- target_url = self.request.URL1 + \'/logged-out\'\n+ target_url = self.request.URL1 + "/logged-out"\n \n registry = queryUtility(IRegistry)\n- external_logout_url = registry[\'plone.external_logout_url\']\n+ external_logout_url = registry["plone.external_logout_url"]\n if external_logout_url:\n target_url = external_logout_url\n self.request.response.redirect(target_url)\n@@ -37,24 +36,16 @@ def __call__(self):\n \n @implementer(ILoggedOutView)\n class LoggedOutView(BrowserView):\n-\n def __call__(self):\n portal_state = getMultiAdapter(\n (self.context, self.request),\n- name=\'plone_portal_state\',\n+ name="plone_portal_state",\n )\n if portal_state.anonymous():\n- IStatusMessage(\n- self.request\n- ).addStatusMessage(\n- _(\n- \'statusmessage_logged_out\',\n- default=\'You are now logged out.\'\n- ),\n- \'info\',\n- )\n- self.request.response.redirect(\n- portal_state.navigation_root_url()\n+ IStatusMessage(self.request).addStatusMessage(\n+ _("statusmessage_logged_out", default="You are now logged out."),\n+ "info",\n )\n+ self.request.response.redirect(portal_state.navigation_root_url())\n return\n return self.index()\ndiff --git a/Products/CMFPlone/browser/login/mail_password.py b/Products/CMFPlone/browser/login/mail_password.py\nindex ada0ac13e6..6db3b8b03f 100644\n--- a/Products/CMFPlone/browser/login/mail_password.py\n+++ b/Products/CMFPlone/browser/login/mail_password.py\n@@ -5,12 +5,11 @@\n \n \n class MailPasswordView(BrowserView):\n-\n def __call__(self):\n response = None\n try:\n response = self.context.portal_registration.mailPassword(\n- self.request.form.get(\'userid\', \'\'),\n+ self.request.form.get("userid", ""),\n self.request,\n )\n except ValueError as e:\n@@ -22,6 +21,6 @@ def __call__(self):\n raise e\n IStatusMessage(self.request).add(msg)\n self.request.response.redirect(\n- self.context.absolute_url() + \'/mail_password_form\'\n+ self.context.absolute_url() + "/mail_password_form"\n )\n return response\ndiff --git a/Products/CMFPlone/browser/login/password_reset.py b/Products/CMFPlone/browser/login/password_reset.py\nindex 6039d58ba7..df65e3d200 100644\n--- a/Products/CMFPlone/browser/login/password_reset.py\n+++ b/Products/CMFPlone/browser/login/password_reset.py\n@@ -30,20 +30,17 @@\n \n @implementer(IPasswordResetToolView)\n class PasswordResetToolView(BrowserView):\n-\n @view.memoize_contextless\n def portal_state(self):\n- """ return portal_state of plone.app.layout\n- """\n- return getMultiAdapter((self.context, self.request),\n- name="plone_portal_state")\n+ """return portal_state of plone.app.layout"""\n+ return getMultiAdapter((self.context, self.request), name="plone_portal_state")\n \n def encode_mail_header(self, text):\n- """ Encodes text into correctly encoded email header """\n- return Header(safe_text(text), \'utf-8\')\n+ """Encodes text into correctly encoded email header"""\n+ return Header(safe_text(text), "utf-8")\n \n def encoded_mail_sender(self):\n- """ returns encoded version of Portal name """\n+ """returns encoded version of Portal name """\n registry = getUtility(IRegistry)\n mail_settings = registry.forInterface(IMailSchema, prefix="plone")\n from_ = mail_settings.email_from_name\n@@ -54,9 +51,9 @@ def registered_notify_subject(self):\n portal_name = self.portal_state().portal_title()\n return translate(\n _(\n- \'mailtemplate_user_account_info\',\n- default=\'User Account Information for ${portal_name}\',\n- mapping={\'portal_name\': safe_text(portal_name)},\n+ "mailtemplate_user_account_info",\n+ default="User Account Information for ${portal_name}",\n+ mapping={"portal_name": safe_text(portal_name)},\n ),\n context=self.request,\n )\n@@ -64,18 +61,19 @@ def registered_notify_subject(self):\n def mail_password_subject(self):\n return translate(\n _(\n- \'mailtemplate_subject_resetpasswordrequest\',\n- default=\'Password reset request\',\n+ "mailtemplate_subject_resetpasswordrequest",\n+ default="Password reset request",\n ),\n context=self.request,\n )\n \n def construct_url(self, randomstring):\n- return \'{}/passwordreset/{}\'.format(\n- self.portal_state().navigation_root_url(), randomstring)\n+ return "{}/passwordreset/{}".format(\n+ self.portal_state().navigation_root_url(), randomstring\n+ )\n \n def expiration_timeout(self):\n- pw_tool = getToolByName(self.context, \'portal_password_reset\')\n+ pw_tool = getToolByName(self.context, "portal_password_reset")\n timeout = int(pw_tool.getExpirationTimeout() or 0)\n return timeout * 24 # timeout is in days, but templates want in hours.\n \n@@ -84,21 +82,18 @@ def expiration_timeout(self):\n class PasswordResetView(BrowserView):\n """ """\n \n- invalid = ViewPageTemplateFile(\'templates/pwreset_invalid.pt\')\n- expired = ViewPageTemplateFile(\'templates/pwreset_expired.pt\')\n- finish = ViewPageTemplateFile(\'templates/pwreset_finish.pt\')\n- form = ViewPageTemplateFile(\'templates/pwreset_form.pt\')\n+ invalid = ViewPageTemplateFile("templates/pwreset_invalid.pt")\n+ expired = ViewPageTemplateFile("templates/pwreset_expired.pt")\n+ finish = ViewPageTemplateFile("templates/pwreset_finish.pt")\n+ form = ViewPageTemplateFile("templates/pwreset_form.pt")\n subpath = None\n \n def _auto_login(self, userid, password):\n context = self.context\n- aclu = getToolByName(context, \'acl_users\')\n+ aclu = getToolByName(context, "acl_users")\n for name, plugin in aclu.plugins.listPlugins(ICredentialsUpdatePlugin):\n plugin.updateCredentials(\n- self.request,\n- self.request.response,\n- userid,\n- password\n+ self.request, self.request.response, userid, password\n )\n \n is_initial_login = False\n@@ -110,10 +105,10 @@ def _auto_login(self, userid, password):\n self.request.response.redirect(self.context.absolute_url())\n IStatusMessage(self.request).addStatusMessage(\n _(\n- \'password_reset_failed\',\n- default=\'Password reset failed.\',\n+ "password_reset_failed",\n+ default="Password reset failed.",\n ),\n- \'info\',\n+ "info",\n )\n return\n \n@@ -124,11 +119,10 @@ def _auto_login(self, userid, password):\n is_initial_login = self._post_login()\n IStatusMessage(self.request).addStatusMessage(\n _(\n- \'password_reset_successful\',\n- default=\'Password reset successful, \'\n- \'you are logged in now!\',\n+ "password_reset_successful",\n+ default="Password reset successful, " "you are logged in now!",\n ),\n- \'info\',\n+ "info",\n )\n self.redirect_after_login(is_initial_login=is_initial_login)\n finally:\n@@ -137,9 +131,9 @@ def _auto_login(self, userid, password):\n return\n \n def _post_login(self):\n- membership_tool = getToolByName(self.context, \'portal_membership\')\n+ membership_tool = getToolByName(self.context, "portal_membership")\n member = membership_tool.getAuthenticatedMember()\n- login_time = member.getProperty(\'login_time\', None)\n+ login_time = member.getProperty("login_time", None)\n is_initial_login = not has_logged_in(login_time)\n membership_tool.loginUser(self.request)\n if is_initial_login:\n@@ -155,10 +149,7 @@ def redirect_after_login(self, came_from=None, is_initial_login=False):\n # Note: for password reset a came_from parameter seems illogical.\n # But let\'s allow it, to be the same as in login.py.\n # The default implementation does not pass it in though.\n- adapter = queryMultiAdapter(\n- (self.context, self.request),\n- IRedirectAfterLogin\n- )\n+ adapter = queryMultiAdapter((self.context, self.request), IRedirectAfterLogin)\n if adapter:\n came_from = adapter(came_from, is_initial_login)\n if not came_from:\n@@ -170,8 +161,8 @@ def _reset_password(self, pw_tool, randomstring):\n state = self.getErrors()\n if state:\n return self.form()\n- userid = self.request.form.get(\'userid\')\n- password = self.request.form.get(\'password\')\n+ userid = self.request.form.get("userid")\n+ password = self.request.form.get("password")\n try:\n pw_tool.resetPassword(userid, randomstring, password)\n except ExpiredRequestError:\n@@ -181,7 +172,7 @@ def _reset_password(self, pw_tool, randomstring):\n except RuntimeError:\n return self.invalid()\n registry = getUtility(IRegistry)\n- if registry.get(\'plone.autologin_after_password_reset\', False):\n+ if registry.get("plone.autologin_after_password_reset", False):\n return self._auto_login(userid, password)\n return self.finish()\n \n@@ -190,10 +181,10 @@ def __call__(self):\n # Try traverse subpath first:\n randomstring = self.subpath[0]\n else:\n- randomstring = self.request.get(\'key\', None)\n+ randomstring = self.request.get("key", None)\n \n- pw_tool = getToolByName(self.context, \'portal_password_reset\')\n- if self.request.method == \'POST\':\n+ pw_tool = getToolByName(self.context, "portal_password_reset")\n+ if self.request.method == "POST":\n return self._reset_password(pw_tool, randomstring)\n try:\n pw_tool.verifyKey(randomstring)\n@@ -210,42 +201,41 @@ def publishTraverse(self, request, name):\n return self\n \n def getErrors(self):\n- if self.request.method != \'POST\':\n+ if self.request.method != "POST":\n return\n- password = self.request.form.get(\'password\')\n- password2 = self.request.form.get(\'password2\')\n- userid = self.request.form.get(\'userid\')\n- reg_tool = getToolByName(self.context, \'portal_registration\')\n+ password = self.request.form.get("password")\n+ password2 = self.request.form.get("password2")\n+ userid = self.request.form.get("userid")\n+ reg_tool = getToolByName(self.context, "portal_registration")\n pw_fail = reg_tool.testPasswordValidity(password, password2)\n state = {}\n if pw_fail:\n- state[\'password\'] = pw_fail\n+ state["password"] = pw_fail\n \n # Determine if we\'re checking userids or not\n- pw_tool = getToolByName(self.context, \'portal_password_reset\')\n+ pw_tool = getToolByName(self.context, "portal_password_reset")\n if not pw_tool.checkUser():\n return state\n \n if not userid:\n- state[\'userid\'] = _(\n- \'This field is required, please provide some information.\',\n+ state["userid"] = _(\n+ "This field is required, please provide some information.",\n )\n if state:\n- state[\'status\'] = \'failure\'\n- state[\'portal_status_message\'] = _(\n- \'Please correct the indicated errors.\'\n- )\n+ state["status"] = "failure"\n+ state["portal_status_message"] = _("Please correct the indicated errors.")\n return state\n \n def login_url(self):\n- portal_state = getMultiAdapter((self.context, self.request),\n- name="plone_portal_state")\n- return \'{}/login?__ac_name={}\'.format(\n- portal_state.navigation_root_url(),\n- self.request.form.get(\'userid\', \'\'))\n+ portal_state = getMultiAdapter(\n+ (self.context, self.request), name="plone_portal_state"\n+ )\n+ return "{}/login?__ac_name={}".format(\n+ portal_state.navigation_root_url(), self.request.form.get("userid", "")\n+ )\n \n def expiration_timeout(self):\n- pw_tool = getToolByName(self.context, \'portal_password_reset\')\n+ pw_tool = getToolByName(self.context, "portal_password_reset")\n timeout = int(pw_tool.getExpirationTimeout() or 0)\n return timeout * 24 # timeout is in days, but templates want in hours.\n \n@@ -257,7 +247,7 @@ def timeout_days(self):\n return self.context.getExpirationTimeout()\n \n def user_check(self):\n- return self.context._user_check and \'checked\' or None\n+ return self.context._user_check and "checked" or None\n \n @property\n def stats(self):\n@@ -266,17 +256,22 @@ def stats(self):\n about the number of open and expired reset requests.\n """\n # count expired reset requests by creating a list of it\n- bad = len([1 for expiry in self.context._requests.values()\n- if self.context.expired(expiry)])\n+ bad = len(\n+ [\n+ 1\n+ for expiry in self.context._requests.values()\n+ if self.context.expired(expiry)\n+ ]\n+ )\n # open reset requests are all requests without the expired ones\n good = len(self.context._requests) - bad\n return {"open": good, "expired": bad}\n \n def __call__(self):\n- if self.request.method == \'POST\':\n- timeout_days = safeToInt(self.request.get(\'timeout_days\'), 7)\n+ if self.request.method == "POST":\n+ timeout_days = safeToInt(self.request.get("timeout_days"), 7)\n self.context.setExpirationTimeout(timeout_days)\n self.context._user_check = bool(\n- self.request.get(\'user_check\', False),\n+ self.request.get("user_check", False),\n )\n return self.index()\ndiff --git a/Products/CMFPlone/browser/login/utils.py b/Products/CMFPlone/browser/login/utils.py\nindex 3d347c8c9c..83a68a1e42 100644\n--- a/Products/CMFPlone/browser/login/utils.py\n+++ b/Products/CMFPlone/browser/login/utils.py\n@@ -20,9 +20,9 @@ def has_logged_in(login_time):\n login_time = DateTime(login_time)\n except DateTimeSyntaxError:\n # https://github.com/plone/Products.CMFPlone/issues/3656\n- logger.warning(\'%r is not a valid login_time.\', login_time)\n+ logger.warning("%r is not a valid login_time.", login_time)\n return False\n # We used to compare login_time with DateTime(\'2000/01/01\'),\n # but it may have a timezone: I have seen both UTC and GTM+1.\n # So compare only the date part.\n- return login_time.Date() != \'2000/01/01\'\n+ return login_time.Date() != "2000/01/01"\ndiff --git a/Products/CMFPlone/browser/main_template.py b/Products/CMFPlone/browser/main_template.py\nindex b68867268e..4f815dba33 100644\n--- a/Products/CMFPlone/browser/main_template.py\n+++ b/Products/CMFPlone/browser/main_template.py\n@@ -6,16 +6,15 @@\n \n @implementer(IMainTemplate)\n class MainTemplate(BrowserView):\n-\n- ajax_template_name = \'templates/ajax_main_template.pt\'\n- main_template_name = \'templates/main_template.pt\'\n+ ajax_template_name = "templates/ajax_main_template.pt"\n+ main_template_name = "templates/main_template.pt"\n \n def __call__(self):\n return ViewPageTemplateFile(self.template_name)\n \n @property\n def template_name(self):\n- if self.request.form.get(\'ajax_load\'):\n+ if self.request.form.get("ajax_load"):\n return self.ajax_template_name\n else:\n return self.main_template_name\ndiff --git a/Products/CMFPlone/browser/navtree.py b/Products/CMFPlone/browser/navtree.py\nindex bba401a21b..d83d8b6a5e 100644\n--- a/Products/CMFPlone/browser/navtree.py\n+++ b/Products/CMFPlone/browser/navtree.py\n@@ -24,22 +24,20 @@\n # subclasses to buildFolderTree().\n \n security = ModuleSecurityInfo()\n-security.declarePrivate(\'plone\')\n-security.declarePrivate(\'utils\')\n+security.declarePrivate("plone")\n+security.declarePrivate("utils")\n \n \n @implementer(INavigationQueryBuilder)\n class NavtreeQueryBuilder:\n- """Build a navtree query based on the settings in navtree_properties\n- """\n+ """Build a navtree query based on the settings in navtree_properties"""\n \n def __init__(self, context):\n registry = getUtility(IRegistry)\n- navigation_settings = registry.forInterface(INavigationSchema,\n- prefix="plone")\n+ navigation_settings = registry.forInterface(INavigationSchema, prefix="plone")\n \n # Acquire a custom nav query if available\n- customQuery = getattr(context, \'getCustomNavQuery\', None)\n+ customQuery = getattr(context, "getCustomNavQuery", None)\n if customQuery is not None and utils.safe_callable(customQuery):\n query = customQuery()\n else:\n@@ -48,37 +46,37 @@ def __init__(self, context):\n # Construct the path query\n \n rootPath = getNavigationRoot(context)\n- currentPath = \'/\'.join(context.getPhysicalPath())\n+ currentPath = "/".join(context.getPhysicalPath())\n \n # If we are above the navigation root, a navtree query would return\n # nothing (since we explicitly start from the root always). Hence,\n # use a regular depth-1 query in this case.\n \n if not currentPath.startswith(rootPath):\n- query[\'path\'] = {\'query\': rootPath, \'depth\': 1}\n+ query["path"] = {"query": rootPath, "depth": 1}\n else:\n- query[\'path\'] = {\'query\': currentPath, \'navtree\': 1}\n+ query["path"] = {"query": currentPath, "navtree": 1}\n \n- query[\'path\'][\'navtree_start\'] = 0\n+ query["path"]["navtree_start"] = 0\n \n # XXX: It\'d make sense to use \'depth\' for bottomLevel, but it doesn\'t\n # seem to work with EPI.\n \n # Only list the applicable types\n- query[\'portal_type\'] = utils.typesToList(context)\n+ query["portal_type"] = utils.typesToList(context)\n \n # Apply the desired sort\n sortAttribute = navigation_settings.sort_tabs_on\n if sortAttribute is not None:\n- query[\'sort_on\'] = sortAttribute\n+ query["sort_on"] = sortAttribute\n if navigation_settings.sort_tabs_reversed:\n- query[\'sort_order\'] = \'desc\'\n+ query["sort_order"] = "desc"\n else:\n- query[\'sort_order\'] = \'asc\'\n+ query["sort_order"] = "asc"\n \n # Filter on workflow states, if enabled\n if navigation_settings.filter_on_workflow:\n- query[\'review_state\'] = navigation_settings.workflow_states_to_show\n+ query["review_state"] = navigation_settings.workflow_states_to_show\n \n self.query = query\n \n@@ -87,16 +85,17 @@ def __call__(self):\n \n \n class SitemapQueryBuilder(NavtreeQueryBuilder):\n- """Build a folder tree query suitable for a sitemap\n- """\n+ """Build a folder tree query suitable for a sitemap"""\n \n def __init__(self, context):\n NavtreeQueryBuilder.__init__(self, context)\n- portal_url = getToolByName(context, \'portal_url\')\n+ portal_url = getToolByName(context, "portal_url")\n registry = getUtility(IRegistry)\n- sitemap_depth = registry.get(\'plone.sitemap_depth\', 3)\n- self.query[\'path\'] = {\'query\': portal_url.getPortalPath(),\n- \'depth\': sitemap_depth}\n+ sitemap_depth = registry.get("plone.sitemap_depth", 3)\n+ self.query["path"] = {\n+ "query": portal_url.getPortalPath(),\n+ "depth": sitemap_depth,\n+ }\n \n \n @implementer(INavtreeStrategy)\n@@ -108,25 +107,25 @@ class SitemapNavtreeStrategy(NavtreeStrategyBase):\n def __init__(self, context, view=None):\n self.context = context\n \n- portal_url = getToolByName(context, \'portal_url\')\n+ portal_url = getToolByName(context, "portal_url")\n self.portal = portal_url.getPortalObject()\n registry = getUtility(IRegistry)\n- self.parentTypesNQ = registry.get(\n- \'plone.parent_types_not_to_query\', [])\n+ self.parentTypesNQ = registry.get("plone.parent_types_not_to_query", [])\n self.viewActionTypes = registry.get(\n- \'plone.types_use_view_action_in_listings\', [])\n+ "plone.types_use_view_action_in_listings", []\n+ )\n \n self.showAllParents = True\n self.rootPath = getNavigationRoot(context)\n \n- membership = getToolByName(context, \'portal_membership\')\n+ membership = getToolByName(context, "portal_membership")\n self.memberId = membership.getAuthenticatedMember().getId()\n \n def nodeFilter(self, node):\n- return not getattr(node[\'item\'], \'exclude_from_nav\', False)\n+ return not getattr(node["item"], "exclude_from_nav", False)\n \n def subtreeFilter(self, node):\n- portalType = getattr(node[\'item\'], \'portal_type\', None)\n+ portalType = getattr(node["item"], "portal_type", None)\n return portalType is None or portalType not in self.parentTypesNQ\n \n def decoratorFactory(self, node):\n@@ -134,58 +133,57 @@ def decoratorFactory(self, node):\n request = context.REQUEST\n \n newNode = node.copy()\n- item = node[\'item\']\n+ item = node["item"]\n \n- portalType = getattr(item, \'portal_type\', None)\n+ portalType = getattr(item, "portal_type", None)\n itemUrl = item.getURL()\n if portalType is not None and portalType in self.viewActionTypes:\n- itemUrl += \'/view\'\n+ itemUrl += "/view"\n \n useRemoteUrl = False\n- getRemoteUrl = getattr(item, \'getRemoteUrl\', None)\n- isCreator = self.memberId == getattr(item, \'Creator\', None)\n+ getRemoteUrl = getattr(item, "getRemoteUrl", None)\n+ isCreator = self.memberId == getattr(item, "Creator", None)\n if getRemoteUrl and not isCreator:\n useRemoteUrl = True\n \n- isFolderish = getattr(item, \'is_folderish\', None)\n+ isFolderish = getattr(item, "is_folderish", None)\n showChildren = False\n- if isFolderish and \\\n- (portalType is None or portalType not in self.parentTypesNQ):\n+ if isFolderish and (portalType is None or portalType not in self.parentTypesNQ):\n showChildren = True\n \n- layout_view = getMultiAdapter((context, request), name=\'plone_layout\')\n-\n- newNode[\'Title\'] = utils.pretty_title_or_id(context, item)\n- newNode[\'id\'] = item.getId\n- newNode[\'UID\'] = item.UID\n- newNode[\'absolute_url\'] = itemUrl\n- newNode[\'getURL\'] = itemUrl\n- newNode[\'path\'] = item.getPath()\n- newNode[\'Creator\'] = getattr(item, \'Creator\', None)\n- newNode[\'creation_date\'] = getattr(item, \'CreationDate\', None)\n- newNode[\'portal_type\'] = portalType\n- newNode[\'review_state\'] = getattr(item, \'review_state\', None)\n- newNode[\'Description\'] = getattr(item, \'Description\', None)\n- newNode[\'show_children\'] = showChildren\n- newNode[\'no_display\'] = False # We sort this out with the nodeFilter\n+ layout_view = getMultiAdapter((context, request), name="plone_layout")\n+\n+ newNode["Title"] = utils.pretty_title_or_id(context, item)\n+ newNode["id"] = item.getId\n+ newNode["UID"] = item.UID\n+ newNode["absolute_url"] = itemUrl\n+ newNode["getURL"] = itemUrl\n+ newNode["path"] = item.getPath()\n+ newNode["Creator"] = getattr(item, "Creator", None)\n+ newNode["creation_date"] = getattr(item, "CreationDate", None)\n+ newNode["portal_type"] = portalType\n+ newNode["review_state"] = getattr(item, "review_state", None)\n+ newNode["Description"] = getattr(item, "Description", None)\n+ newNode["show_children"] = showChildren\n+ newNode["no_display"] = False # We sort this out with the nodeFilter\n # BBB getRemoteUrl and link_remote are deprecated, remove in Plone 4\n- newNode[\'getRemoteUrl\'] = getattr(item, \'getRemoteUrl\', None)\n- newNode[\'useRemoteUrl\'] = useRemoteUrl\n- newNode[\'link_remote\'] = (\n- newNode[\'getRemoteUrl\'] and newNode[\'Creator\'] != self.memberId\n+ newNode["getRemoteUrl"] = getattr(item, "getRemoteUrl", None)\n+ newNode["useRemoteUrl"] = useRemoteUrl\n+ newNode["link_remote"] = (\n+ newNode["getRemoteUrl"] and newNode["Creator"] != self.memberId\n )\n \n idnormalizer = queryUtility(IIDNormalizer)\n- newNode[\'normalized_portal_type\'] = idnormalizer.normalize(portalType)\n- newNode[\'normalized_review_state\'] = idnormalizer.normalize(\n- newNode[\'review_state\']\n+ newNode["normalized_portal_type"] = idnormalizer.normalize(portalType)\n+ newNode["normalized_review_state"] = idnormalizer.normalize(\n+ newNode["review_state"]\n )\n- newNode[\'normalized_id\'] = idnormalizer.normalize(newNode[\'id\'])\n+ newNode["normalized_id"] = idnormalizer.normalize(newNode["id"])\n \n return newNode\n \n def showChildrenOf(self, object):\n- getTypeInfo = getattr(object, \'getTypeInfo\', None)\n+ getTypeInfo = getattr(object, "getTypeInfo", None)\n if getTypeInfo is not None:\n portal_type = getTypeInfo().getId()\n if portal_type in self.parentTypesNQ:\n@@ -195,8 +193,7 @@ def showChildrenOf(self, object):\n \n @implementer(INavtreeStrategy)\n class DefaultNavtreeStrategy(SitemapNavtreeStrategy):\n- """The navtree strategy used for the default navigation portlet\n- """\n+ """The navtree strategy used for the default navigation portlet"""\n \n def __init__(self, context, view=None):\n SitemapNavtreeStrategy.__init__(self, context, view)\n@@ -209,7 +206,7 @@ def subtreeFilter(self, node):\n sitemapDecision = SitemapNavtreeStrategy.subtreeFilter(self, node)\n if not sitemapDecision:\n return False\n- depth = node.get(\'depth\', 0)\n+ depth = node.get("depth", 0)\n if depth > 0 and self.bottomLevel > 0 and depth >= self.bottomLevel:\n return False\n return True\ndiff --git a/Products/CMFPlone/browser/okay.py b/Products/CMFPlone/browser/okay.py\nindex eeaae619ab..63c036a42d 100644\n--- a/Products/CMFPlone/browser/okay.py\n+++ b/Products/CMFPlone/browser/okay.py\n@@ -20,7 +20,7 @@ def __call__(self):\n # plone/app/caching/operations/utils.py does in the doNotCache\n # function.\n set_header = self.request.response.setHeader\n- set_header(\'Expires\', \'Sat, 1 Jan 2000 00:00:00 GMT\')\n- set_header(\'Cache-Control\', \'max-age=0, must-revalidate, private\')\n+ set_header("Expires", "Sat, 1 Jan 2000 00:00:00 GMT")\n+ set_header("Cache-Control", "max-age=0, must-revalidate, private")\n # Return a short and simple message.\n- return \'OK\'\n+ return "OK"\ndiff --git a/Products/CMFPlone/browser/ploneview.py b/Products/CMFPlone/browser/ploneview.py\nindex 4b4c5fe297..47c2bcd582 100644\n--- a/Products/CMFPlone/browser/ploneview.py\n+++ b/Products/CMFPlone/browser/ploneview.py\n@@ -18,7 +18,6 @@\n \n @implementer(IPlone)\n class Plone(BrowserView):\n-\n # Utility methods\n \n @memoize\ndiff --git a/Products/CMFPlone/browser/robots.py b/Products/CMFPlone/browser/robots.py\nindex a80557d91d..776ee8f009 100644\n--- a/Products/CMFPlone/browser/robots.py\n+++ b/Products/CMFPlone/browser/robots.py\n@@ -19,7 +19,8 @@ class Robots(BrowserView):\n \n def __call__(self):\n portal_state = getMultiAdapter(\n- (self.context, self.request), name=\'plone_portal_state\')\n+ (self.context, self.request), name="plone_portal_state"\n+ )\n portal_url = portal_state.portal_url()\n registry = getUtility(IRegistry)\n settings = registry.forInterface(ISiteSchema, prefix="plone")\ndiff --git a/Products/CMFPlone/browser/search.py b/Products/CMFPlone/browser/search.py\nindex fa74d78782..956a5311ad 100644\n--- a/Products/CMFPlone/browser/search.py\n+++ b/Products/CMFPlone/browser/search.py\n@@ -20,37 +20,37 @@\n import re\n \n \n-_ = MessageFactory(\'plone\')\n+_ = MessageFactory("plone")\n \n # We should accept both a simple space, unicode u\'\\u0020 but also a\n # multi-space, so called \'waji-kankaku\', unicode u\'\\u3000\'\n-MULTISPACE = \'\\u3000\'\n-BAD_CHARS = (\'?\', \'-\', \'+\', \'*\', MULTISPACE)\n-EVER = DateTime(\'1970-01-03\')\n+MULTISPACE = "\\u3000"\n+BAD_CHARS = ("?", "-", "+", "*", MULTISPACE)\n+EVER = DateTime("1970-01-03")\n \n \n def quote_chars(s):\n # We need to quote parentheses when searching text indices\n- if \'(\' in s:\n- s = s.replace(\'(\', \'"("\')\n- if \')\' in s:\n- s = s.replace(\')\', \'")"\')\n+ if "(" in s:\n+ s = s.replace("(", \'"("\')\n+ if ")" in s:\n+ s = s.replace(")", \'")"\')\n if MULTISPACE in s:\n- s = s.replace(MULTISPACE, \' \')\n+ s = s.replace(MULTISPACE, " ")\n return s\n \n \n def quote(term):\n # The terms and, or and not must be wrapped in quotes to avoid\n # being parsed as logical query atoms.\n- if term.lower() in (\'and\', \'or\', \'not\'):\n+ if term.lower() in ("and", "or", "not"):\n term = \'"%s"\' % term\n return term\n \n \n def munge_search_term(query):\n for char in BAD_CHARS:\n- query = query.replace(char, \' \')\n+ query = query.replace(char, " ")\n \n # extract quoted phrases first\n quoted_phrases = re.findall(r\'"([^"]*)"\', query)\n@@ -67,31 +67,31 @@ def munge_search_term(query):\n \n r += map(quote, query.strip().split())\n r = " AND ".join(r)\n- r = quote_chars(r) + (\'*\' if r and not r.endswith(\'"\') else \'\')\n+ r = quote_chars(r) + ("*" if r and not r.endswith(\'"\') else "")\n return r\n \n \n class Search(BrowserView):\n+ valid_keys = ("sort_on", "sort_order", "sort_limit", "fq", "fl", "facet")\n \n- valid_keys = (\'sort_on\', \'sort_order\', \'sort_limit\', \'fq\', \'fl\', \'facet\')\n-\n- def results(self, query=None, batch=True, b_size=10, b_start=0,\n- use_content_listing=True):\n- """ Get properly wrapped search results from the catalog.\n+ def results(\n+ self, query=None, batch=True, b_size=10, b_start=0, use_content_listing=True\n+ ):\n+ """Get properly wrapped search results from the catalog.\n Everything in Plone that performs searches should go through this view.\n \'query\' should be a dictionary of catalog parameters.\n """\n if query is None:\n query = {}\n if batch:\n- query[\'b_start\'] = b_start = int(b_start)\n- query[\'b_size\'] = b_size\n+ query["b_start"] = b_start = int(b_start)\n+ query["b_size"] = b_size\n query = self.filter_query(query)\n \n if query is None:\n results = []\n else:\n- catalog = getToolByName(self.context, \'portal_catalog\')\n+ catalog = getToolByName(self.context, "portal_catalog")\n try:\n results = catalog(**query)\n except ParseError:\n@@ -106,55 +106,56 @@ def results(self, query=None, batch=True, b_size=10, b_start=0,\n def _filter_query(self, query):\n request = self.request\n \n- catalog = getToolByName(self.context, \'portal_catalog\')\n+ catalog = getToolByName(self.context, "portal_catalog")\n valid_indexes = tuple(catalog.indexes())\n valid_keys = self.valid_keys + valid_indexes\n \n- text = query.get(\'SearchableText\', None)\n+ text = query.get("SearchableText", None)\n if text is None:\n- text = request.form.get(\'SearchableText\', \'\')\n+ text = request.form.get("SearchableText", "")\n if not text:\n # Without text, must provide a meaningful non-empty search\n- valid = set(valid_indexes).intersection(request.form.keys()) or \\\n- set(valid_indexes).intersection(query.keys())\n+ valid = set(valid_indexes).intersection(request.form.keys()) or set(\n+ valid_indexes\n+ ).intersection(query.keys())\n if not valid:\n return\n \n for k, v in request.form.items():\n- if v and ((k in valid_keys) or k.startswith(\'facet.\')):\n+ if v and ((k in valid_keys) or k.startswith("facet.")):\n query[k] = v\n if text:\n- query[\'SearchableText\'] = munge_search_term(text)\n+ query["SearchableText"] = munge_search_term(text)\n \n # don\'t filter on created at all if we want all results\n- created = query.get(\'created\')\n+ created = query.get("created")\n if created:\n try:\n- if created.get(\'query\', EVER) <= EVER:\n- del query[\'created\']\n+ if created.get("query", EVER) <= EVER:\n+ del query["created"]\n except AttributeError:\n # created not a mapping\n- del query[\'created\']\n+ del query["created"]\n \n # respect `types_not_searched` setting\n- types = query.get(\'portal_type\', [])\n- if \'query\' in types:\n- types = types[\'query\']\n- query[\'portal_type\'] = self.filter_types(types)\n+ types = query.get("portal_type", [])\n+ if "query" in types:\n+ types = types["query"]\n+ query["portal_type"] = self.filter_types(types)\n # respect effective/expiration date\n- query[\'show_inactive\'] = False\n+ query["show_inactive"] = False\n # respect navigation root if we\'re not at the site root.\n- if \'path\' not in query and not IPloneSiteRoot.providedBy(self.context):\n- query[\'path\'] = getNavigationRoot(self.context)\n+ if "path" not in query and not IPloneSiteRoot.providedBy(self.context):\n+ query["path"] = getNavigationRoot(self.context)\n \n- if \'sort_order\' in query and not query[\'sort_order\']:\n- del query[\'sort_order\']\n+ if "sort_order" in query and not query["sort_order"]:\n+ del query["sort_order"]\n return query\n \n @lazy_property\n def default_sort_on(self):\n registry = getUtility(IRegistry)\n- search_settings = registry.forInterface(ISearchSchema, prefix=\'plone\')\n+ search_settings = registry.forInterface(ISearchSchema, prefix="plone")\n return search_settings.sort_on\n \n def filter_query(self, query):\n@@ -163,69 +164,67 @@ def filter_query(self, query):\n query = {}\n # explicitly set a sort; if no `sort_on` is present, the catalog sorts\n # by relevance\n- if \'sort_on\' not in query:\n+ if "sort_on" not in query:\n self.default_sort_on\n- if self.default_sort_on != \'relevance\':\n- query[\'sort_on\'] = self.default_sort_on\n- elif query[\'sort_on\'] == \'relevance\':\n- del query[\'sort_on\']\n- if query.get(\'sort_on\', \'\') == \'Date\':\n- query[\'sort_order\'] = \'reverse\'\n- elif \'sort_order\' in query:\n- del query[\'sort_order\']\n+ if self.default_sort_on != "relevance":\n+ query["sort_on"] = self.default_sort_on\n+ elif query["sort_on"] == "relevance":\n+ del query["sort_on"]\n+ if query.get("sort_on", "") == "Date":\n+ query["sort_order"] = "reverse"\n+ elif "sort_order" in query:\n+ del query["sort_order"]\n if not query:\n return None\n return query\n \n def filter_types(self, types):\n- plone_utils = getToolByName(self.context, \'plone_utils\')\n+ plone_utils = getToolByName(self.context, "plone_utils")\n if not isinstance(types, list):\n types = [types]\n return plone_utils.getUserFriendlyTypes(types)\n \n def types_list(self):\n # only show those types that have any content\n- catalog = getToolByName(self.context, \'portal_catalog\')\n- used_types = catalog._catalog.getIndex(\'portal_type\').uniqueValues()\n+ catalog = getToolByName(self.context, "portal_catalog")\n+ used_types = catalog._catalog.getIndex("portal_type").uniqueValues()\n return self.filter_types(list(used_types))\n \n def sort_options(self):\n- """ Sorting options for search results view. """\n- if \'sort_on\' not in self.request.form:\n- self.request.form[\'sort_on\'] = self.default_sort_on\n+ """Sorting options for search results view."""\n+ if "sort_on" not in self.request.form:\n+ self.request.form["sort_on"] = self.default_sort_on\n return (\n- SortOption(self.request, _(\'relevance\'), \'relevance\'),\n- SortOption(\n- self.request, _(\'date (newest first)\'), \'Date\', reverse=True\n- ),\n- SortOption(self.request, _(\'alphabetically\'), \'sortable_title\'),\n+ SortOption(self.request, _("relevance"), "relevance"),\n+ SortOption(self.request, _("date (newest first)"), "Date", reverse=True),\n+ SortOption(self.request, _("alphabetically"), "sortable_title"),\n )\n \n def show_advanced_search(self):\n """Whether we need to show advanced search options a.k.a. filters?"""\n- show = self.request.get(\'advanced_search\', None)\n- if not show or show == \'False\':\n+ show = self.request.get("advanced_search", None)\n+ if not show or show == "False":\n return False\n return True\n \n def advanced_search_trigger(self):\n """URL builder for show/close advanced search filters."""\n- query = self.request.get(\'QUERY_STRING\', None)\n- url = self.request.get(\'ACTUAL_URL\', self.context.absolute_url())\n+ query = self.request.get("QUERY_STRING", None)\n+ url = self.request.get("ACTUAL_URL", self.context.absolute_url())\n if not query:\n return url\n- if \'advanced_search\' in query:\n- if \'advanced_search=True\' in query:\n- query = query.replace(\'advanced_search=True\', \'\')\n- if \'advanced_search=False\' in query:\n- query = query.replace(\'advanced_search=False\', \'\')\n+ if "advanced_search" in query:\n+ if "advanced_search=True" in query:\n+ query = query.replace("advanced_search=True", "")\n+ if "advanced_search=False" in query:\n+ query = query.replace("advanced_search=False", "")\n else:\n- query = query + \'&advanced_search=True\'\n- return url + \'?\' + query\n+ query = query + "&advanced_search=True"\n+ return url + "?" + query\n \n def breadcrumbs(self, item):\n obj = item.getObject()\n- view = getMultiAdapter((obj, self.request), name=\'breadcrumbs_view\')\n+ view = getMultiAdapter((obj, self.request), name="breadcrumbs_view")\n # cut off the item itself\n breadcrumbs = list(view.breadcrumbs())[:-1]\n if len(breadcrumbs) == 0:\n@@ -233,37 +232,36 @@ def breadcrumbs(self, item):\n return None\n if len(breadcrumbs) > 3:\n # if we have too long breadcrumbs, emit the middle elements\n- empty = {\'absolute_url\': \'\', \'Title\': \'\xe2\x80\xa6\'}\n+ empty = {"absolute_url": "", "Title": "\xe2\x80\xa6"}\n breadcrumbs = [breadcrumbs[0], empty] + breadcrumbs[-2:]\n return breadcrumbs\n \n def navroot_url(self):\n- if not hasattr(self, \'_navroot_url\'):\n- state = self.context.unrestrictedTraverse(\'@@plone_portal_state\')\n+ if not hasattr(self, "_navroot_url"):\n+ state = self.context.unrestrictedTraverse("@@plone_portal_state")\n self._navroot_url = state.navigation_root_url()\n return self._navroot_url\n \n @property\n def show_images(self):\n registry = queryUtility(IRegistry)\n- return registry.get(\'plone.search_show_images\')\n+ return registry.get("plone.search_show_images")\n \n @property\n def search_image_scale(self):\n registry = queryUtility(IRegistry)\n- return registry.get(\'plone.search_image_scale\')\n+ return registry.get("plone.search_image_scale")\n \n \n class AjaxSearch(Search):\n-\n def __call__(self):\n items = []\n try:\n- per_page = int(self.request.form.get(\'perPage\'))\n+ per_page = int(self.request.form.get("perPage"))\n except:\n per_page = 10\n try:\n- page = int(self.request.form.get(\'page\'))\n+ page = int(self.request.form.get("page"))\n except:\n page = 1\n \n@@ -271,61 +269,60 @@ def __call__(self):\n batch = Batch(results, per_page, start=(page - 1) * per_page)\n \n registry = queryUtility(IRegistry)\n- length = registry.get(\'plone.search_results_description_length\')\n- show_images = registry.get(\'plone.search_show_images\')\n+ length = registry.get("plone.search_results_description_length")\n+ show_images = registry.get("plone.search_show_images")\n if show_images:\n- image_scale = registry.get(\'plone.search_image_scale\')\n+ image_scale = registry.get("plone.search_image_scale")\n # image_scaling = getMultiAdapter((self.context, self.request), name=\'image_scale\')\n- self.image_scaling = getMultiAdapter((INavigationRoot(self.context), self.request), name=\'image_scale\')\n- plone_view = getMultiAdapter(\n- (self.context, self.request), name=\'plone\')\n- view_action_types = registry.get(\n- \'plone.types_use_view_action_in_listings\', [])\n+ self.image_scaling = getMultiAdapter(\n+ (INavigationRoot(self.context), self.request), name="image_scale"\n+ )\n+ plone_view = getMultiAdapter((self.context, self.request), name="plone")\n+ view_action_types = registry.get("plone.types_use_view_action_in_listings", [])\n for item in batch:\n url = item.getURL()\n if item.portal_type in view_action_types:\n- url = \'%s/view\' % url\n+ url = "%s/view" % url\n img_tag = None\n if show_images:\n img_tag = self.get_image_tag(item, image_scale)\n- items.append({\n- \'id\': item.UID,\n- \'title\': item.Title,\n- \'description\': plone_view.cropText(item.Description, length),\n- \'url\': url,\n- \'state\': item.review_state if item.review_state else None,\n- \'img_tag\': img_tag,\n- })\n- return json.dumps({\n- \'total\': len(results),\n- \'items\': items\n- })\n+ items.append(\n+ {\n+ "id": item.UID,\n+ "title": item.Title,\n+ "description": plone_view.cropText(item.Description, length),\n+ "url": url,\n+ "state": item.review_state if item.review_state else None,\n+ "img_tag": img_tag,\n+ }\n+ )\n+ return json.dumps({"total": len(results), "items": items})\n \n def get_image_tag(self, item, image_scale):\n return self.image_scaling.tag(item, "image", scale=image_scale)\n \n-class SortOption:\n \n- def __init__(self, request, title, sortkey=\'\', reverse=False):\n+class SortOption:\n+ def __init__(self, request, title, sortkey="", reverse=False):\n self.request = request\n self.title = title\n self.sortkey = sortkey\n self.reverse = reverse\n \n def selected(self):\n- sort_on = self.request.get(\'sort_on\', \'\')\n- return sort_on == self.sortkey and sort_on != \'\'\n+ sort_on = self.request.get("sort_on", "")\n+ return sort_on == self.sortkey and sort_on != ""\n \n def url(self):\n q = {}\n q.update(self.request.form)\n- if \'sort_on\' in q.keys():\n- del q[\'sort_on\']\n- if \'sort_order\' in q.keys():\n- del q[\'sort_order\']\n- q[\'sort_on\'] = self.sortkey\n+ if "sort_on" in q.keys():\n+ del q["sort_on"]\n+ if "sort_order" in q.keys():\n+ del q["sort_order"]\n+ q["sort_on"] = self.sortkey\n if self.reverse:\n- q[\'sort_order\'] = \'reverse\'\n+ q["sort_order"] = "reverse"\n \n base_url = self.request.URL\n- return base_url + \'?\' + make_query(q)\n+ return base_url + "?" + make_query(q)\ndiff --git a/Products/CMFPlone/browser/sendto.py b/Products/CMFPlone/browser/sendto.py\nindex 95d63034a4..d3a6116036 100644\n--- a/Products/CMFPlone/browser/sendto.py\n+++ b/Products/CMFPlone/browser/sendto.py\n@@ -20,38 +20,37 @@\n \n \n class SendToForm(form.Form):\n- label = _(\'heading_send_page_to\',\n- default=\'Send this page to someone\')\n+ label = _("heading_send_page_to", default="Send this page to someone")\n \n- description = _(\'description_send_page_url_to\',\n- default=\'Fill in the email address of your \'\n- \'friend, and we will send an email \'\n- \'that contains a link to this page.\')\n+ description = _(\n+ "description_send_page_url_to",\n+ default="Fill in the email address of your "\n+ "friend, and we will send an email "\n+ "that contains a link to this page.",\n+ )\n \n fields = field.Fields(ISendToForm)\n ignoreContext = True\n \n- mail_template = ViewPageTemplateFile(\'templates/sendto_template.pt\')\n+ mail_template = ViewPageTemplateFile("templates/sendto_template.pt")\n \n- @button.buttonAndHandler(_(\'label_send\', default=\'Send\'),\n- name=\'send\')\n+ @button.buttonAndHandler(_("label_send", default="Send"), name="send")\n def handle_send(self, action):\n data, errors = self.extractData()\n if errors:\n IStatusMessage(self.request).addStatusMessage(\n- self.formErrorsMessage,\n- type=\'error\'\n+ self.formErrorsMessage, type="error"\n )\n return\n \n- send_from_address = data.get(\'send_from_address\')\n- send_to_address = data.get(\'send_to_address\')\n+ send_from_address = data.get("send_from_address")\n+ send_to_address = data.get("send_to_address")\n subject = pretty_title_or_id(self, self.context)\n title = pretty_title_or_id(self, self.context)\n description = self.context.Description()\n- comment = data.get(\'comment\', None)\n+ comment = data.get("comment", None)\n registry = getUtility(IRegistry)\n- mail_settings = registry.forInterface(IMailSchema, prefix=\'plone\')\n+ mail_settings = registry.forInterface(IMailSchema, prefix="plone")\n envelope_from = mail_settings.email_from_address\n email_from_name = mail_settings.email_from_name\n \n@@ -59,7 +58,7 @@ def handle_send(self, action):\n # Sends a link of a page to someone.\n host = getUtility(IMailHost)\n registry = getUtility(IRegistry)\n- encoding = registry.get(\'plone.email_charset\', \'utf-8\')\n+ encoding = registry.get("plone.email_charset", "utf-8")\n \n if not envelope_from:\n envelope_from = send_from_address\n@@ -73,7 +72,7 @@ def handle_send(self, action):\n subject=subject,\n title=title,\n description=description,\n- email_from_name=email_from_name\n+ email_from_name=email_from_name,\n )\n \n message = message.encode(encoding)\n@@ -83,7 +82,7 @@ def handle_send(self, action):\n mto=send_to_address,\n mfrom=envelope_from,\n subject=subject,\n- charset=\'utf-8\'\n+ charset="utf-8",\n )\n \n except ConflictError:\n@@ -92,14 +91,11 @@ def handle_send(self, action):\n # TODO To many things could possibly go wrong. So we catch all.\n logger.info("Unable to send mail: " + str(e))\n IStatusMessage(self.request).addStatusMessage(\n- _(\'Unable to send mail.\'),\n- type=\'error\'\n+ _("Unable to send mail."), type="error"\n )\n return\n \n- IStatusMessage(self.request).addStatusMessage(\n- _(\'Mail sent.\'),\n- type=\'info\'\n- )\n+ IStatusMessage(self.request).addStatusMessage(_("Mail sent."), type="info")\n+\n \n send_to_form = layout.wrap_form(SendToForm)\ndiff --git a/Products/CMFPlone/browser/sitelogo.py b/Products/CMFPlone/browser/sitelogo.py\nindex cb816a6b48..2a4c954db0 100644\n--- a/Products/CMFPlone/browser/sitelogo.py\n+++ b/Products/CMFPlone/browser/sitelogo.py\n@@ -7,7 +7,6 @@\n \n \n class SiteLogo(Download):\n-\n def __init__(self, context, request):\n super().__init__(context, request)\n self.filename = None\n@@ -15,7 +14,7 @@ def __init__(self, context, request):\n \n registry = getUtility(IRegistry)\n settings = registry.forInterface(ISiteSchema, prefix="plone")\n- if getattr(settings, \'site_logo\', False):\n+ if getattr(settings, "site_logo", False):\n filename, data = b64decode_file(settings.site_logo)\n data = NamedImage(data=data, filename=filename)\n self.data = data\ndiff --git a/Products/CMFPlone/browser/sitemap.py b/Products/CMFPlone/browser/sitemap.py\nindex b835a89ea2..4628d6784c 100644\n--- a/Products/CMFPlone/browser/sitemap.py\n+++ b/Products/CMFPlone/browser/sitemap.py\n@@ -8,26 +8,25 @@\n \n @implementer(ISitemapView)\n class SitemapView(BrowserView):\n-\n- item_template = ViewPageTemplateFile(\'templates/sitemap-item.pt\')\n+ item_template = ViewPageTemplateFile("templates/sitemap-item.pt")\n \n def createSiteMap(self):\n context = aq_inner(self.context)\n- view = getMultiAdapter((context, self.request),\n- name=\'sitemap_builder_view\')\n+ view = getMultiAdapter((context, self.request), name="sitemap_builder_view")\n data = view.siteMap()\n- return self._renderLevel(children=data.get(\'children\', []))\n+ return self._renderLevel(children=data.get("children", []))\n \n def _renderLevel(self, children=[], level=2):\n- output = \'\'\n+ output = ""\n for node in children:\n output += \'\\n\'\n+ output += \'\\n\' % (\n+ level,\n+ self._renderLevel(children, level + 1),\n+ )\n+ output += "\\n"\n \n return output\ndiff --git a/Products/CMFPlone/browser/syndication/adapters.py b/Products/CMFPlone/browser/syndication/adapters.py\nindex aa7c48a47e..8cf927290e 100644\n--- a/Products/CMFPlone/browser/syndication/adapters.py\n+++ b/Products/CMFPlone/browser/syndication/adapters.py\n@@ -24,16 +24,16 @@\n \n \n class BaseFeedData:\n-\n def __init__(self, context):\n self.context = context\n self.settings = IFeedSettings(context)\n self.site = getSite()\n if self.show_about:\n- self.pm = getToolByName(self.context, \'portal_membership\')\n+ self.pm = getToolByName(self.context, "portal_membership")\n registry = getUtility(IRegistry)\n self.view_action_types = registry.get(\n- \'plone.types_use_view_action_in_listings\', [])\n+ "plone.types_use_view_action_in_listings", []\n+ )\n \n @lazy_property\n def show_about(self):\n@@ -50,7 +50,8 @@ def base_url(self):\n @lazy_property\n def canonical_url(self):\n pcs = getMultiAdapter(\n- (self.context, self.context.REQUEST), name=\'plone_context_state\')\n+ (self.context, self.context.REQUEST), name="plone_context_state"\n+ )\n return pcs.canonical_object_url()\n \n @property\n@@ -68,7 +69,7 @@ def categories(self):\n @property\n def published(self):\n date = self.context.EffectiveDate()\n- if date and date != \'None\':\n+ if date and date != "None":\n return DateTime(date)\n \n @property\n@@ -80,7 +81,7 @@ def modified(self):\n @property\n def uid(self):\n uuid = IUUID(self.context, None)\n- if uuid is None and hasattr(self.context, \'UID\'):\n+ if uuid is None and hasattr(self.context, "UID"):\n return self.context.UID()\n return uuid\n \n@@ -90,14 +91,13 @@ def rights(self):\n \n @property\n def publisher(self):\n- if hasattr(self.context, \'Publisher\'):\n+ if hasattr(self.context, "Publisher"):\n return self.context.Publisher()\n- return \'No Publisher\'\n+ return "No Publisher"\n \n \n @implementer(IFeed)\n class FolderFeed(BaseFeedData):\n-\n @lazy_property\n def author(self):\n if self.show_about:\n@@ -108,12 +108,12 @@ def author(self):\n @property\n def author_name(self):\n if self.author:\n- return self.author.getProperty(\'fullname\')\n+ return self.author.getProperty("fullname")\n \n @property\n def author_email(self):\n if self.author:\n- return self.author.getProperty(\'email\')\n+ return self.author.getProperty("email")\n \n @property\n def logo(self):\n@@ -121,14 +121,13 @@ def logo(self):\n \n @property\n def icon(self):\n- return \'%s/favicon.ico\' % self.site.absolute_url()\n+ return "%s/favicon.ico" % self.site.absolute_url()\n \n def _brains(self):\n- catalog = getToolByName(self.context, \'portal_catalog\')\n- return catalog(path={\n- \'query\': \'/\'.join(self.context.getPhysicalPath()),\n- \'depth\': 1\n- })\n+ catalog = getToolByName(self.context, "portal_catalog")\n+ return catalog(\n+ path={"query": "/".join(self.context.getPhysicalPath()), "depth": 1}\n+ )\n \n def _items(self):\n """\n@@ -138,7 +137,7 @@ def _items(self):\n \n @property\n def items(self):\n- for item in self._items()[:self.limit]:\n+ for item in self._items()[: self.limit]:\n # look for custom adapter\n # otherwise, just use default\n adapter = queryMultiAdapter((item, self), IFeedItem)\n@@ -152,29 +151,27 @@ def limit(self):\n \n @property\n def language(self):\n- langtool = getToolByName(self.context, \'portal_languages\')\n+ langtool = getToolByName(self.context, "portal_languages")\n return langtool.getDefaultLanguage()\n \n \n class CollectionFeed(FolderFeed):\n-\n def _brains(self):\n- return self.context.queryCatalog(batch=False)[:self.limit]\n+ return self.context.queryCatalog(batch=False)[: self.limit]\n \n \n @implementer(ISearchFeed)\n class SearchFeed(FolderFeed):\n-\n def _brains(self):\n max_items = self.limit\n request = self.context.REQUEST\n- start = int(request.get(\'b_start\', 0))\n- end = int(request.get(\'b_end\', start + max_items))\n- request.set(\'sort_order\', \'reverse\')\n- request.set(\'sort_on\', request.get(\'sort_on\', \'effective\'))\n+ start = int(request.get("b_start", 0))\n+ end = int(request.get("b_end", start + max_items))\n+ request.set("sort_order", "reverse")\n+ request.set("sort_on", request.get("sort_on", "effective"))\n return self.context.queryCatalog(\n- show_all=1, use_types_blacklist=True,\n- use_navigation_root=True)[start:end]\n+ show_all=1, use_types_blacklist=True, use_navigation_root=True\n+ )[start:end]\n \n \n @implementer(IFeedItem)\n@@ -187,7 +184,7 @@ def __init__(self, context, feed):\n \n @lazy_property\n def creator(self):\n- if hasattr(self.context, \'Creator\'):\n+ if hasattr(self.context, "Creator"):\n return self.context.Creator()\n \n @lazy_property\n@@ -195,30 +192,30 @@ def author(self):\n if self.feed.show_about:\n creator = self.context.Creator()\n member = self.feed.pm.getMemberById(creator)\n- return member and member.getProperty(\'fullname\') or creator\n+ return member and member.getProperty("fullname") or creator\n \n @property\n def author_name(self):\n author = self.author\n- if author and hasattr(author, \'getProperty\'):\n- return author.getProperty(\'fullname\')\n+ if author and hasattr(author, "getProperty"):\n+ return author.getProperty("fullname")\n \n @property\n def author_email(self):\n author = self.author\n- if author and hasattr(author, \'getProperty\'):\n- return author.getProperty(\'email\')\n+ if author and hasattr(author, "getProperty"):\n+ return author.getProperty("email")\n \n @property\n def body(self):\n- if hasattr(self.context, \'getText\'):\n+ if hasattr(self.context, "getText"):\n value = self.context.getText()\n- elif hasattr(self.context, \'text\'):\n+ elif hasattr(self.context, "text"):\n value = self.context.text\n else:\n value = self.description\n if not isinstance(value, str):\n- if hasattr(value, \'output\'):\n+ if hasattr(value, "output"):\n # could be RichTextValue object, needs transform\n value = value.output\n return value\n@@ -233,7 +230,7 @@ def render_content_core(self):\n def link(self):\n url = self.base_url\n if self.context.portal_type in self.feed.view_action_types:\n- url = url + \'/view\'\n+ url = url + "/view"\n else:\n url = self.canonical_url\n return url\n@@ -256,7 +253,7 @@ def file_url(self):\n if fi is not None:\n filename = fi.getFilename()\n if filename:\n- url += \'/@@download/file/%s\' % filename\n+ url += "/@@download/file/%s" % filename\n return url\n \n @property\n@@ -272,24 +269,28 @@ class DexterityItem(BaseItem):\n adapts(IDexterityContent, IFeed)\n \n file = None\n- field_name = \'\'\n+ field_name = ""\n \n def __init__(self, context, feed):\n super().__init__(context, feed)\n self.dexterity = IDexterityContent.providedBy(context)\n lead = ILeadImage(self.context, None)\n if lead:\n- if (lead.image\n- and hasattr(lead.image, \'getSize\')\n- and lead.image.getSize() > 0):\n+ if (\n+ lead.image\n+ and hasattr(lead.image, "getSize")\n+ and lead.image.getSize() > 0\n+ ):\n self.file = lead.image\n- self.field_name = \'image\'\n+ self.field_name = "image"\n if self.file is None:\n try:\n primary = IPrimaryFieldInfo(self.context, None)\n- if (INamedField.providedBy(primary.field)\n- and hasattr(primary.value, \'getSize\')\n- and primary.value.getSize() > 0):\n+ if (\n+ INamedField.providedBy(primary.field)\n+ and hasattr(primary.value, "getSize")\n+ and primary.value.getSize() > 0\n+ ):\n self.file = primary.value\n self.field_name = primary.fieldname\n except TypeError:\n@@ -302,8 +303,7 @@ def file_url(self):\n if fi is not None:\n filename = fi.filename\n if filename:\n- url += \'/@@download/{}/{}\'.format(\n- self.field_name, filename)\n+ url += "/@@download/{}/{}".format(self.field_name, filename)\n return url\n \n @property\ndiff --git a/Products/CMFPlone/browser/syndication/settings.py b/Products/CMFPlone/browser/syndication/settings.py\nindex da4daca293..179f55e6f0 100644\n--- a/Products/CMFPlone/browser/syndication/settings.py\n+++ b/Products/CMFPlone/browser/syndication/settings.py\n@@ -9,7 +9,7 @@\n from zope.interface import implementer\n \n \n-FEED_SETTINGS_KEY = \'syndication_settings\'\n+FEED_SETTINGS_KEY = "syndication_settings"\n \n \n @implementer(IFeedSettings)\n@@ -27,8 +27,9 @@ def __init__(self, context):\n self.needs_saving = True\n \n registry = getUtility(IRegistry)\n- self.site_settings = registry.forInterface(ISiteSyndicationSettings,\n- check=False)\n+ self.site_settings = registry.forInterface(\n+ ISiteSyndicationSettings, check=False\n+ )\n \n def _set(self):\n """\n@@ -40,8 +41,13 @@ def _set(self):\n self.annotations[FEED_SETTINGS_KEY] = self._metadata\n \n def __setattr__(self, name, value):\n- if name in (\'context\', \'_metadata\', \'site_settings\', \'annotations\',\n- \'needs_saving\'):\n+ if name in (\n+ "context",\n+ "_metadata",\n+ "site_settings",\n+ "annotations",\n+ "needs_saving",\n+ ):\n self.__dict__[name] = value\n else:\n self._metadata[name] = value\n@@ -51,7 +57,7 @@ def __getattr__(self, name):\n default = None\n if name in ISiteSyndicationSettings.names():\n default = getattr(self.site_settings, name)\n- elif name == \'enabled\' and self.site_settings.default_enabled:\n+ elif name == "enabled" and self.site_settings.default_enabled:\n default = True\n elif name in IFeedSettings.names():\n default = IFeedSettings[name].default\ndiff --git a/Products/CMFPlone/browser/syndication/tool.py b/Products/CMFPlone/browser/syndication/tool.py\nindex 94a93823e0..b94456229b 100644\n--- a/Products/CMFPlone/browser/syndication/tool.py\n+++ b/Products/CMFPlone/browser/syndication/tool.py\n@@ -22,8 +22,14 @@ class SyndicationTool:\n backwards compatibility.\n """\n \n- def editProperties(self, updatePeriod=None, updateFrequency=None,\n- updateBase=None, isAllowed=None, max_items=None):\n+ def editProperties(\n+ self,\n+ updatePeriod=None,\n+ updateFrequency=None,\n+ updateBase=None,\n+ isAllowed=None,\n+ max_items=None,\n+ ):\n """\n Edit the properties for the SystemWide defaults on the\n SyndicationTool.\n@@ -78,4 +84,5 @@ def disableSyndication(self, obj):\n settings = IFeedSettings(obj)\n settings.enabled = False\n \n-registerToolInterface(\'portal_syndication\', ISyndicationTool)\n+\n+registerToolInterface("portal_syndication", ISyndicationTool)\ndiff --git a/Products/CMFPlone/browser/syndication/utils.py b/Products/CMFPlone/browser/syndication/utils.py\nindex 2fac9a8d9b..4d50da66c5 100644\n--- a/Products/CMFPlone/browser/syndication/utils.py\n+++ b/Products/CMFPlone/browser/syndication/utils.py\n@@ -13,16 +13,16 @@\n \n @implementer(ISyndicationUtil)\n class SyndicationUtil(BrowserView):\n-\n def allowed_feed_types(self):\n settings = IFeedSettings(self.context)\n- factory = getUtility(IVocabularyFactory,\n- "plone.app.vocabularies.SyndicationFeedTypes")\n+ factory = getUtility(\n+ IVocabularyFactory, "plone.app.vocabularies.SyndicationFeedTypes"\n+ )\n vocabulary = factory(self.context)\n types = []\n for typ in settings.feed_types:\n types.append(vocabulary.getTerm(typ))\n- return [{\'path\': t.value, \'title\': t.title} for t in types]\n+ return [{"path": t.value, "title": t.title} for t in types]\n \n def rss_url(self):\n settings = IFeedSettings(self.context)\n@@ -31,7 +31,7 @@ def rss_url(self):\n if len(types) == 0:\n return url\n _type = types[0]\n- return f\'{url}/{_type}\'\n+ return f"{url}/{_type}"\n \n def context_allowed(self):\n if not ISyndicatable.providedBy(self.context):\ndiff --git a/Products/CMFPlone/browser/syndication/views.py b/Products/CMFPlone/browser/syndication/views.py\nindex e1e0969cc5..f165c80024 100644\n--- a/Products/CMFPlone/browser/syndication/views.py\n+++ b/Products/CMFPlone/browser/syndication/views.py\n@@ -17,8 +17,7 @@\n \n \n class FeedView(BrowserView):\n-\n- content_type = \'application/atom+xml\'\n+ content_type = "application/atom+xml"\n \n def feed(self):\n f = queryAdapter(self.context, IFeed)\n@@ -27,20 +26,19 @@ def feed(self):\n return f\n \n def __call__(self):\n- util = getMultiAdapter((self.context, self.request),\n- name=\'syndication-util\')\n- context_state = getMultiAdapter((self.context, self.request),\n- name=\'plone_context_state\')\n+ util = getMultiAdapter((self.context, self.request), name="syndication-util")\n+ context_state = getMultiAdapter(\n+ (self.context, self.request), name="plone_context_state"\n+ )\n if context_state.is_portal_root() or util.context_enabled(raise404=True):\n settings = IFeedSettings(self.context)\n if self.__name__ not in settings.feed_types:\n raise NotFound\n- self.request.response.setHeader(\'Content-Type\', self.content_type)\n+ self.request.response.setHeader("Content-Type", self.content_type)\n return self.index()\n \n \n class SearchFeedView(FeedView):\n-\n def feed(self):\n f = queryAdapter(self.context, ISearchFeed)\n if f is None:\n@@ -48,16 +46,14 @@ def feed(self):\n return f\n \n def __call__(self):\n- util = getMultiAdapter((self.context, self.request),\n- name=\'syndication-util\')\n+ util = getMultiAdapter((self.context, self.request), name="syndication-util")\n if util.search_rss_enabled(raise404=True):\n- self.request.response.setHeader(\'Content-Type\',\n- \'application/atom+xml\')\n+ self.request.response.setHeader("Content-Type", "application/atom+xml")\n return self.index()\n \n \n class NewsMLFeedView(FeedView):\n- content_type = \'application/vnd.iptc.g2.newsitem+xml\'\n+ content_type = "application/vnd.iptc.g2.newsitem+xml"\n \n @lazy_property\n def current_date(self):\n@@ -68,26 +64,25 @@ def duid(self, item, value):\n return uid.hex\n \n def get_image(self, item):\n- scales = item.context.restrictedTraverse(\'@@images\')\n+ scales = item.context.restrictedTraverse("@@images")\n if scales:\n try:\n- return scales.scale(\'image\')\n+ return scales.scale("image")\n except AttributeError:\n pass\n return None\n \n \n class SettingsForm(form.EditForm):\n- label = _(\'heading_syndication_properties\',\n- default=\'Syndication Properties\')\n+ label = _("heading_syndication_properties", default="Syndication Properties")\n description = _(\n- \'description_syndication_properties\',\n- default=\'Syndication enables you to syndicate this folder so it can\'\n- \'be synchronized from other web sites.\',\n+ "description_syndication_properties",\n+ default="Syndication enables you to syndicate this folder so it can"\n+ "be synchronized from other web sites.",\n )\n fields = field.Fields(IFeedSettings)\n \n- @button.buttonAndHandler(_(\'Save\'), name=\'save\')\n+ @button.buttonAndHandler(_("Save"), name="save")\n def handleSave(self, action):\n data, errors = self.extractData()\n if errors:\ndiff --git a/Products/CMFPlone/browser/test_rendering.py b/Products/CMFPlone/browser/test_rendering.py\nindex b4c42e9cc0..2864227d86 100644\n--- a/Products/CMFPlone/browser/test_rendering.py\n+++ b/Products/CMFPlone/browser/test_rendering.py\n@@ -3,30 +3,27 @@\n \n \n class TestRenderingView(BrowserView):\n-\n- template = ViewPageTemplateFile(\'templates/test_rendering.pt\')\n+ template = ViewPageTemplateFile("templates/test_rendering.pt")\n \n def __call__(self):\n- self.request.set(\'disable_plone.rightcolumn\', 1)\n- self.request.set(\'disable_plone.leftcolumn\', 1)\n+ self.request.set("disable_plone.rightcolumn", 1)\n+ self.request.set("disable_plone.leftcolumn", 1)\n return self.template()\n \n \n class TestRenderingCheatsheetView(BrowserView):\n-\n- template = ViewPageTemplateFile(\'templates/test_rendering_cheatsheet.pt\')\n+ template = ViewPageTemplateFile("templates/test_rendering_cheatsheet.pt")\n \n def __call__(self):\n- self.request.set(\'disable_plone.rightcolumn\', 1)\n- self.request.set(\'disable_plone.leftcolumn\', 1)\n+ self.request.set("disable_plone.rightcolumn", 1)\n+ self.request.set("disable_plone.leftcolumn", 1)\n return self.template()\n \n \n class TestRenderingIconsView(BrowserView):\n-\n- template = ViewPageTemplateFile(\'templates/test_rendering_icons.pt\')\n+ template = ViewPageTemplateFile("templates/test_rendering_icons.pt")\n \n def __call__(self):\n- self.request.set(\'disable_plone.rightcolumn\', 1)\n- self.request.set(\'disable_plone.leftcolumn\', 1)\n+ self.request.set("disable_plone.rightcolumn", 1)\n+ self.request.set("disable_plone.leftcolumn", 1)\n return self.template()\ndiff --git a/Products/CMFPlone/controlpanel/bbb/editing.py b/Products/CMFPlone/controlpanel/bbb/editing.py\nindex f5614a8cd9..c3feaacd46 100644\n--- a/Products/CMFPlone/controlpanel/bbb/editing.py\n+++ b/Products/CMFPlone/controlpanel/bbb/editing.py\n@@ -8,12 +8,11 @@\n \n @implementer(IEditingSchema)\n class EditingControlPanelAdapter:\n-\n adapts(IPloneSiteRoot)\n \n def __init__(self, context):\n registry = getUtility(IRegistry)\n- self.settings = registry.forInterface(IEditingSchema, prefix=\'plone\')\n+ self.settings = registry.forInterface(IEditingSchema, prefix="plone")\n \n def get_visible_ids(self):\n return self.settings.visible_ids\n@@ -47,8 +46,7 @@ def set_lock_on_ttw_edit(self, value):\n \n visible_ids = property(get_visible_ids, set_visible_ids)\n enable_link_integrity_checks = property(\n- get_enable_link_integrity_checks,\n- set_enable_link_integrity_checks\n+ get_enable_link_integrity_checks, set_enable_link_integrity_checks\n )\n ext_editor = property(get_ext_editor, set_ext_editor)\n default_editor = property(get_default_editor, set_default_editor)\ndiff --git a/Products/CMFPlone/controlpanel/bbb/filter.py b/Products/CMFPlone/controlpanel/bbb/filter.py\nindex 2da1d3dcb5..bd96a3d563 100644\n--- a/Products/CMFPlone/controlpanel/bbb/filter.py\n+++ b/Products/CMFPlone/controlpanel/bbb/filter.py\n@@ -8,12 +8,11 @@\n \n @implementer(IFilterSchema)\n class FilterControlPanelAdapter:\n-\n adapts(IPloneSiteRoot)\n \n def __init__(self, context):\n registry = getUtility(IRegistry)\n- self.settings = registry.forInterface(IFilterSchema, prefix=\'plone\')\n+ self.settings = registry.forInterface(IFilterSchema, prefix="plone")\n \n def get_disable_filtering(self):\n return self.settings.disable_filtering\n@@ -39,8 +38,7 @@ def get_custom_attributes(self):\n def set_custom_attributes(self, value):\n self.settings.custom_attributes = value\n \n- custom_attributes = property(\n- get_custom_attributes, set_custom_attributes)\n+ custom_attributes = property(get_custom_attributes, set_custom_attributes)\n valid_tags = property(get_valid_tags, set_valid_tags)\n nasty_tags = property(get_nasty_tags, set_nasty_tags)\n disable_filtering = property(get_disable_filtering, set_disable_filtering)\ndiff --git a/Products/CMFPlone/controlpanel/bbb/language.py b/Products/CMFPlone/controlpanel/bbb/language.py\nindex 8085b28cfb..56569adf91 100644\n--- a/Products/CMFPlone/controlpanel/bbb/language.py\n+++ b/Products/CMFPlone/controlpanel/bbb/language.py\n@@ -8,14 +8,12 @@\n \n @implementer(ILanguageSchema)\n class LanguageControlPanelAdapter:\n-\n adapts(IPloneSiteRoot)\n \n def __init__(self, context):\n self.context = context\n registry = getUtility(IRegistry)\n- self.settings = registry.forInterface(\n- ILanguageSchema, prefix="plone")\n+ self.settings = registry.forInterface(ILanguageSchema, prefix="plone")\n \n def get_default_language(self):\n return self.settings.default_language\n@@ -23,8 +21,7 @@ def get_default_language(self):\n def set_default_language(self, value):\n self.settings.default_language = value\n \n- default_language = property(get_default_language,\n- set_default_language)\n+ default_language = property(get_default_language, set_default_language)\n \n def get_available_languages(self):\n return self.settings.available_languages\n@@ -32,8 +29,7 @@ def get_available_languages(self):\n def set_available_languages(self, value):\n self.settings.available_languages = value\n \n- available_languages = property(get_available_languages,\n- set_available_languages)\n+ available_languages = property(get_available_languages, set_available_languages)\n \n def get_use_combined_language_codes(self):\n return self.settings.use_combined_language_codes\n@@ -41,8 +37,9 @@ def get_use_combined_language_codes(self):\n def set_use_combined_language_codes(self, value):\n self.settings.use_combined_language_codes = value\n \n- use_combined_language_codes = property(get_use_combined_language_codes,\n- set_use_combined_language_codes)\n+ use_combined_language_codes = property(\n+ get_use_combined_language_codes, set_use_combined_language_codes\n+ )\n \n def get_display_flags(self):\n return self.settings.display_flags\n@@ -50,8 +47,7 @@ def get_display_flags(self):\n def set_display_flags(self, value):\n self.settings.display_flags = value\n \n- display_flags = property(get_display_flags,\n- set_display_flags)\n+ display_flags = property(get_display_flags, set_display_flags)\n \n def get_always_show_selector(self):\n return self.settings.always_show_selector\n@@ -59,8 +55,7 @@ def get_always_show_selector(self):\n def set_always_show_selector(self, value):\n self.settings.always_show_selector = value\n \n- always_show_selector = property(get_always_show_selector,\n- set_always_show_selector)\n+ always_show_selector = property(get_always_show_selector, set_always_show_selector)\n \n def get_use_content_negotiation(self):\n return self.settings.use_content_negotiation\n@@ -68,8 +63,9 @@ def get_use_content_negotiation(self):\n def set_use_content_negotiation(self, value):\n self.settings.use_content_negotiation = value\n \n- use_content_negotiation = property(get_use_content_negotiation,\n- set_use_content_negotiation)\n+ use_content_negotiation = property(\n+ get_use_content_negotiation, set_use_content_negotiation\n+ )\n \n def get_use_path_negotiation(self):\n return self.settings.use_path_negotiation\n@@ -77,8 +73,7 @@ def get_use_path_negotiation(self):\n def set_use_path_negotiation(self, value):\n self.settings.use_path_negotiation = value\n \n- use_path_negotiation = property(get_use_path_negotiation,\n- set_use_path_negotiation)\n+ use_path_negotiation = property(get_use_path_negotiation, set_use_path_negotiation)\n \n def get_use_cookie_negotiation(self):\n return self.settings.use_cookie_negotiation\n@@ -86,8 +81,9 @@ def get_use_cookie_negotiation(self):\n def set_use_cookie_negotiation(self, value):\n self.settings.use_cookie_negotiation = value\n \n- use_cookie_negotiation = property(get_use_cookie_negotiation,\n- set_use_cookie_negotiation)\n+ use_cookie_negotiation = property(\n+ get_use_cookie_negotiation, set_use_cookie_negotiation\n+ )\n \n def get_authenticated_users_only(self):\n return self.settings.authenticated_users_only\n@@ -95,8 +91,9 @@ def get_authenticated_users_only(self):\n def set_authenticated_users_only(self, value):\n self.settings.authenticated_users_only = value\n \n- authenticated_users_only = property(get_authenticated_users_only,\n- set_authenticated_users_only)\n+ authenticated_users_only = property(\n+ get_authenticated_users_only, set_authenticated_users_only\n+ )\n \n def get_set_cookie_always(self):\n return self.settings.set_cookie_always\n@@ -104,8 +101,7 @@ def get_set_cookie_always(self):\n def set_set_cookie_always(self, value):\n self.settings.set_cookie_always = value\n \n- set_cookie_always = property(get_set_cookie_always,\n- set_set_cookie_always)\n+ set_cookie_always = property(get_set_cookie_always, set_set_cookie_always)\n \n def get_use_subdomain_negotiation(self):\n return self.settings.use_subdomain_negotiation\n@@ -113,8 +109,9 @@ def get_use_subdomain_negotiation(self):\n def set_use_subdomain_negotiation(self, value):\n self.settings.use_subdomain_negotiation = value\n \n- use_subdomain_negotiation = property(get_use_subdomain_negotiation,\n- set_use_subdomain_negotiation)\n+ use_subdomain_negotiation = property(\n+ get_use_subdomain_negotiation, set_use_subdomain_negotiation\n+ )\n \n def get_use_cctld_negotiation(self):\n return self.settings.use_cctld_negotiation\n@@ -122,8 +119,9 @@ def get_use_cctld_negotiation(self):\n def set_use_cctld_negotiation(self, value):\n self.settings.use_cctld_negotiation = value\n \n- use_cctld_negotiation = property(get_use_cctld_negotiation,\n- set_use_cctld_negotiation)\n+ use_cctld_negotiation = property(\n+ get_use_cctld_negotiation, set_use_cctld_negotiation\n+ )\n \n def get_use_request_negotiation(self):\n return self.settings.use_request_negotiation\n@@ -131,5 +129,6 @@ def get_use_request_negotiation(self):\n def set_use_request_negotiation(self, value):\n self.settings.use_request_negotiation = value\n \n- use_request_negotiation = property(get_use_request_negotiation,\n- set_use_request_negotiation)\n+ use_request_negotiation = property(\n+ get_use_request_negotiation, set_use_request_negotiation\n+ )\ndiff --git a/Products/CMFPlone/controlpanel/bbb/mail.py b/Products/CMFPlone/controlpanel/bbb/mail.py\nindex 15ab993922..f1c89d8682 100644\n--- a/Products/CMFPlone/controlpanel/bbb/mail.py\n+++ b/Products/CMFPlone/controlpanel/bbb/mail.py\n@@ -10,63 +10,67 @@\n \n @implementer(IMailSchema)\n class MailControlPanelAdapter:\n-\n adapts(IPloneSiteRoot)\n \n def __init__(self, context):\n self.context = context\n self.portal = getSite()\n registry = getUtility(IRegistry)\n- self.encoding = \'utf-8\'\n- self.mail_settings = registry.forInterface(\n- IMailSchema, prefix="plone")\n+ self.encoding = "utf-8"\n+ self.mail_settings = registry.forInterface(IMailSchema, prefix="plone")\n \n def get_smtp_host(self):\n return self.mail_settings.smtp_host\n \n def set_smtp_host(self, value):\n- if safe_hasattr(self.mail_settings, \'smtp_host\'):\n+ if safe_hasattr(self.mail_settings, "smtp_host"):\n self.mail_settings.smtp_host = value\n \n smtp_host = property(get_smtp_host, set_smtp_host)\n \n def get_smtp_port(self):\n- return getattr(self.mail_settings, \'smtp_port\', None)\n+ return getattr(self.mail_settings, "smtp_port", None)\n \n def set_smtp_port(self, value):\n- if safe_hasattr(self.mail_settings, \'smtp_port\'):\n+ if safe_hasattr(self.mail_settings, "smtp_port"):\n self.mail_settings.smtp_port = value\n \n smtp_port = property(get_smtp_port, set_smtp_port)\n \n def get_smtp_userid(self):\n- return getattr(self.mail_settings, \'smtp_userid\',\n- getattr(self.mail_settings, \'smtp_userid\', None))\n+ return getattr(\n+ self.mail_settings,\n+ "smtp_userid",\n+ getattr(self.mail_settings, "smtp_userid", None),\n+ )\n \n def set_smtp_userid(self, value):\n- if safe_hasattr(self.mail_settings, \'smtp_userid\'):\n+ if safe_hasattr(self.mail_settings, "smtp_userid"):\n self.mail_settings.smtp_userid = value\n # SecureMailhost 1.x also uses this:\n- if safe_hasattr(self.mail_settings, \'_smtp_userid\'):\n+ if safe_hasattr(self.mail_settings, "_smtp_userid"):\n self.mail_settings._smtp_userid = value\n- elif safe_hasattr(self.mail_settings, \'smtp_userid\'):\n+ elif safe_hasattr(self.mail_settings, "smtp_userid"):\n self.mail_settings.smtp_uid = value\n \n smtp_userid = property(get_smtp_userid, set_smtp_userid)\n \n def get_smtp_pass(self):\n- return getattr(self.mail_settings, \'smtp_pass\',\n- getattr(self.mail_settings, \'smtp_pwd\', None))\n+ return getattr(\n+ self.mail_settings,\n+ "smtp_pass",\n+ getattr(self.mail_settings, "smtp_pwd", None),\n+ )\n \n def set_smtp_pass(self, value):\n # Don\'t update the value, if we don\'t get a new one\n if value is not None:\n- if safe_hasattr(self.mail_settings, \'smtp_pass\'):\n+ if safe_hasattr(self.mail_settings, "smtp_pass"):\n self.mail_settings.smtp_pass = value\n # SecureMailhost 1.x also uses this:\n- if safe_hasattr(self.mail_settings, \'_smtp_pass\'):\n+ if safe_hasattr(self.mail_settings, "_smtp_pass"):\n self.mail_settings._smtp_pass = value\n- elif safe_hasattr(self.mail_settings, \'smtp_pwd\'):\n+ elif safe_hasattr(self.mail_settings, "smtp_pwd"):\n self.mail_settings.smtp_pwd = value\n \n smtp_pass = property(get_smtp_pass, set_smtp_pass)\n@@ -85,5 +89,4 @@ def get_email_from_address(self):\n def set_email_from_address(self, value):\n self.mail_settings.email_from_address = value\n \n- email_from_address = property(get_email_from_address,\n- set_email_from_address)\n+ email_from_address = property(get_email_from_address, set_email_from_address)\ndiff --git a/Products/CMFPlone/controlpanel/bbb/maintenance.py b/Products/CMFPlone/controlpanel/bbb/maintenance.py\nindex 941fea458b..500008a2a0 100644\n--- a/Products/CMFPlone/controlpanel/bbb/maintenance.py\n+++ b/Products/CMFPlone/controlpanel/bbb/maintenance.py\n@@ -8,14 +8,14 @@\n \n @implementer(IMaintenanceSchema)\n class MaintenanceControlPanelAdapter:\n-\n adapts(IPloneSiteRoot)\n \n def __init__(self, context):\n self.context = context\n registry = getUtility(IRegistry)\n self.maintenance_settings = registry.forInterface(\n- IMaintenanceSchema, prefix="plone")\n+ IMaintenanceSchema, prefix="plone"\n+ )\n \n def get_days(self):\n return self.maintenance_settings.days\ndiff --git a/Products/CMFPlone/controlpanel/bbb/markup.py b/Products/CMFPlone/controlpanel/bbb/markup.py\nindex 2434f6b84b..1f9814a3b7 100644\n--- a/Products/CMFPlone/controlpanel/bbb/markup.py\n+++ b/Products/CMFPlone/controlpanel/bbb/markup.py\n@@ -8,7 +8,6 @@\n \n @implementer(IMarkupSchema)\n class MarkupControlPanelAdapter:\n-\n adapts(IPloneSiteRoot)\n \n def __init__(self, context):\ndiff --git a/Products/CMFPlone/controlpanel/bbb/navigation.py b/Products/CMFPlone/controlpanel/bbb/navigation.py\nindex 05705ccb77..f6ed1860c9 100644\n--- a/Products/CMFPlone/controlpanel/bbb/navigation.py\n+++ b/Products/CMFPlone/controlpanel/bbb/navigation.py\n@@ -9,13 +9,11 @@\n @adapter(IPloneSiteRoot)\n @implementer(INavigationSchema)\n class NavigationControlPanelAdapter:\n-\n def __init__(self, context):\n self.context = context\n registry = getUtility(IRegistry)\n self.navigation_settings = registry.forInterface(\n- INavigationSchema,\n- prefix="plone"\n+ INavigationSchema, prefix="plone"\n )\n \n def get_generate_tabs(self):\n@@ -40,10 +38,7 @@ def get_show_excluded_items(self):\n def set_show_excluded_items(self, value):\n self.navigation_settings.show_excluded_items = value\n \n- show_excluded_items = property(\n- get_show_excluded_items,\n- set_show_excluded_items\n- )\n+ show_excluded_items = property(get_show_excluded_items, set_show_excluded_items)\n \n def get_displayed_types(self):\n return self.navigation_settings.displayed_types\n@@ -59,10 +54,7 @@ def get_filter_on_workflow(self):\n def set_filter_on_workflow(self, value):\n self.navigation_settings.filter_on_workflow = value\n \n- filter_on_workflow = property(\n- get_filter_on_workflow,\n- set_filter_on_workflow\n- )\n+ filter_on_workflow = property(get_filter_on_workflow, set_filter_on_workflow)\n \n def get_workflow_states_to_show(self):\n return self.navigation_settings.workflow_states_to_show\n@@ -71,8 +63,8 @@ def set_workflow_states_to_show(self, value):\n self.navigation_settings.workflow_states_to_show = value\n \n workflow_states_to_show = property(\n- get_workflow_states_to_show,\n- set_workflow_states_to_show)\n+ get_workflow_states_to_show, set_workflow_states_to_show\n+ )\n \n @property\n def root(self):\ndiff --git a/Products/CMFPlone/controlpanel/bbb/search.py b/Products/CMFPlone/controlpanel/bbb/search.py\nindex 784a30d448..9f0562ad68 100644\n--- a/Products/CMFPlone/controlpanel/bbb/search.py\n+++ b/Products/CMFPlone/controlpanel/bbb/search.py\n@@ -9,14 +9,12 @@\n \n @implementer(ISearchSchema)\n class SearchControlPanelAdapter:\n-\n adapts(IPloneSiteRoot)\n \n def __init__(self, context):\n self.portal = getSite()\n registry = getUtility(IRegistry)\n- self.search_settings = registry.forInterface(\n- ISearchSchema, prefix="plone")\n+ self.search_settings = registry.forInterface(ISearchSchema, prefix="plone")\n \n def get_enable_livesearch(self):\n return self.search_settings.enable_livesearch\n@@ -35,10 +33,7 @@ def get_types_not_searched(self):\n def set_types_not_searched(self, value):\n self.search_settings.types_not_searched = value\n \n- types_not_searched = property(\n- get_types_not_searched,\n- set_types_not_searched\n- )\n+ types_not_searched = property(get_types_not_searched, set_types_not_searched)\n \n @property\n def sort_on(self):\ndiff --git a/Products/CMFPlone/controlpanel/bbb/security.py b/Products/CMFPlone/controlpanel/bbb/security.py\nindex b1b48f16ae..7450b9a4a9 100644\n--- a/Products/CMFPlone/controlpanel/bbb/security.py\n+++ b/Products/CMFPlone/controlpanel/bbb/security.py\n@@ -10,15 +10,13 @@\n \n @implementer(ISecuritySchema)\n class SecurityControlPanelAdapter:\n-\n adapts(IPloneSiteRoot)\n \n def __init__(self, context):\n self.portal = getSite()\n- self.pmembership = getToolByName(context, \'portal_membership\')\n+ self.pmembership = getToolByName(context, "portal_membership")\n registry = getUtility(IRegistry)\n- self.settings = registry.forInterface(\n- ISecuritySchema, prefix="plone")\n+ self.settings = registry.forInterface(ISecuritySchema, prefix="plone")\n \n def get_enable_self_reg(self):\n return self.settings.enable_self_reg\n@@ -35,8 +33,9 @@ def get_enable_user_pwd_choice(self):\n def set_enable_user_pwd_choice(self, value):\n self.settings.enable_user_pwd_choice = value\n \n- enable_user_pwd_choice = property(get_enable_user_pwd_choice,\n- set_enable_user_pwd_choice)\n+ enable_user_pwd_choice = property(\n+ get_enable_user_pwd_choice, set_enable_user_pwd_choice\n+ )\n \n def get_enable_user_folders(self):\n return self.settings.enable_user_folders\n@@ -45,8 +44,7 @@ def set_enable_user_folders(self, value):\n # additional processing in the event handler\n self.settings.enable_user_folders = value\n \n- enable_user_folders = property(get_enable_user_folders,\n- set_enable_user_folders)\n+ enable_user_folders = property(get_enable_user_folders, set_enable_user_folders)\n \n def get_allow_anon_views_about(self):\n return self.settings.allow_anon_views_about\n@@ -54,8 +52,9 @@ def get_allow_anon_views_about(self):\n def set_allow_anon_views_about(self, value):\n self.settings.allow_anon_views_about = value\n \n- allow_anon_views_about = property(get_allow_anon_views_about,\n- set_allow_anon_views_about)\n+ allow_anon_views_about = property(\n+ get_allow_anon_views_about, set_allow_anon_views_about\n+ )\n \n def get_use_email_as_login(self):\n return self.settings.use_email_as_login\n@@ -64,8 +63,7 @@ def set_use_email_as_login(self, value):\n # additional processing in the event handler\n self.settings.use_email_as_login = value\n \n- use_email_as_login = property(get_use_email_as_login,\n- set_use_email_as_login)\n+ use_email_as_login = property(get_use_email_as_login, set_use_email_as_login)\n \n def get_use_uuid_as_userid(self):\n return self.settings.use_uuid_as_userid\n@@ -73,5 +71,4 @@ def get_use_uuid_as_userid(self):\n def set_use_uuid_as_userid(self, value):\n self.settings.use_uuid_as_userid = value\n \n- use_uuid_as_userid = property(get_use_uuid_as_userid,\n- set_use_uuid_as_userid)\n+ use_uuid_as_userid = property(get_use_uuid_as_userid, set_use_uuid_as_userid)\ndiff --git a/Products/CMFPlone/controlpanel/bbb/site.py b/Products/CMFPlone/controlpanel/bbb/site.py\nindex 73402b154d..c80e918be1 100644\n--- a/Products/CMFPlone/controlpanel/bbb/site.py\n+++ b/Products/CMFPlone/controlpanel/bbb/site.py\n@@ -9,7 +9,6 @@\n \n @implementer(ISiteSchema)\n class SiteControlPanelAdapter:\n-\n adapts(IPloneSiteRoot)\n \n def __init__(self, context):\n@@ -31,6 +30,6 @@ def set_webstats_js(self, value):\n site_title = property(get_site_title, set_site_title)\n webstats_js = property(get_webstats_js, set_webstats_js)\n \n- site_logo = FieldProperty(ISiteSchema[\'site_logo\'])\n- enable_sitemap = FieldProperty(ISiteSchema[\'enable_sitemap\'])\n- exposeDCMetaTags = FieldProperty(ISiteSchema[\'exposeDCMetaTags\'])\n+ site_logo = FieldProperty(ISiteSchema["site_logo"])\n+ enable_sitemap = FieldProperty(ISiteSchema["enable_sitemap"])\n+ exposeDCMetaTags = FieldProperty(ISiteSchema["exposeDCMetaTags"])\ndiff --git a/Products/CMFPlone/controlpanel/bbb/usergroups.py b/Products/CMFPlone/controlpanel/bbb/usergroups.py\nindex 0c819c7136..4330421011 100644\n--- a/Products/CMFPlone/controlpanel/bbb/usergroups.py\n+++ b/Products/CMFPlone/controlpanel/bbb/usergroups.py\n@@ -9,7 +9,6 @@\n \n @implementer(IUserGroupsSettingsSchema)\n class UserGroupsSettingsControlPanelAdapter:\n-\n adapts(IPloneSiteRoot)\n \n def __init__(self, context):\n@@ -17,7 +16,8 @@ def __init__(self, context):\n self.portal = getSite()\n registry = getUtility(IRegistry)\n self.usergroups_settings = registry.forInterface(\n- IUserGroupsSettingsSchema, prefix="plone")\n+ IUserGroupsSettingsSchema, prefix="plone"\n+ )\n \n def get_many_groups(self):\n return self.usergroups_settings.many_groups\ndiff --git a/Products/CMFPlone/controlpanel/browser/actions.py b/Products/CMFPlone/controlpanel/browser/actions.py\nindex ced92e851c..9c361e6462 100644\n--- a/Products/CMFPlone/controlpanel/browser/actions.py\n+++ b/Products/CMFPlone/controlpanel/browser/actions.py\n@@ -26,50 +26,52 @@ class ActionListControlPanel(BrowserView):\n def __init__(self, context, request):\n self.context = context\n self.request = request\n- self.portal_actions = getToolByName(self.context, \'portal_actions\')\n+ self.portal_actions = getToolByName(self.context, "portal_actions")\n \n def display(self):\n actions = []\n for category in self.portal_actions.objectValues():\n- if category.id == \'controlpanel\':\n+ if category.id == "controlpanel":\n continue\n if not IActionCategory.providedBy(category):\n continue\n cat_infos = {\n- \'id\': category.id,\n- \'title\': category.title or category.id,\n+ "id": category.id,\n+ "title": category.title or category.id,\n }\n action_list = []\n for action in category.objectValues():\n if IAction.providedBy(action):\n- action_list.append({\n- \'id\': action.id,\n- \'title\': action.title,\n- \'url\': action.absolute_url(),\n- \'visible\': action.visible,\n- })\n- cat_infos[\'actions\'] = action_list\n+ action_list.append(\n+ {\n+ "id": action.id,\n+ "title": action.title,\n+ "url": action.absolute_url(),\n+ "visible": action.visible,\n+ }\n+ )\n+ cat_infos["actions"] = action_list\n actions.append(cat_infos)\n \n self.actions = actions\n return self.template()\n \n def __call__(self):\n- if self.request.get(\'delete\'):\n- action_id = self.request[\'actionid\']\n- category = self.portal_actions[self.request[\'category\']]\n+ if self.request.get("delete"):\n+ action_id = self.request["actionid"]\n+ category = self.portal_actions[self.request["category"]]\n category.manage_delObjects([action_id])\n- self.request.RESPONSE.redirect(\'@@actions-controlpanel\')\n- if self.request.get(\'hide\'):\n- action_id = self.request[\'actionid\']\n- category = self.portal_actions[self.request[\'category\']]\n+ self.request.RESPONSE.redirect("@@actions-controlpanel")\n+ if self.request.get("hide"):\n+ action_id = self.request["actionid"]\n+ category = self.portal_actions[self.request["category"]]\n category[action_id].visible = False\n- self.request.RESPONSE.redirect(\'@@actions-controlpanel\')\n- if self.request.get(\'show\'):\n- action_id = self.request[\'actionid\']\n- category = self.portal_actions[self.request[\'category\']]\n+ self.request.RESPONSE.redirect("@@actions-controlpanel")\n+ if self.request.get("show"):\n+ action_id = self.request["actionid"]\n+ category = self.portal_actions[self.request["category"]]\n category[action_id].visible = True\n- self.request.RESPONSE.redirect(\'@@actions-controlpanel\')\n+ self.request.RESPONSE.redirect("@@actions-controlpanel")\n return self.display()\n \n \n@@ -87,7 +89,7 @@ def get_category(self):\n return self.current_category.id\n \n def set_category(self, value):\n- portal_actions = getToolByName(self.context, \'portal_actions\')\n+ portal_actions = getToolByName(self.context, "portal_actions")\n new_category = portal_actions.get(value)\n cookie = self.current_category.manage_cutObjects(ids=[self.context.id])\n new_category.manage_pasteObjects(cookie)\n@@ -98,7 +100,7 @@ def get_title(self):\n return self.context.title\n \n def set_title(self, value):\n- self.context._setPropValue(\'title\', value)\n+ self.context._setPropValue("title", value)\n \n title = property(get_title, set_title)\n \n@@ -106,7 +108,7 @@ def get_description(self):\n return self.context.description\n \n def set_description(self, value):\n- self.context._setPropValue(\'description\', value)\n+ self.context._setPropValue("description", value)\n \n description = property(get_description, set_description)\n \n@@ -114,7 +116,7 @@ def get_i18n_domain(self):\n return self.context.i18n_domain\n \n def set_i18n_domain(self, value):\n- self.context._setPropValue(\'i18n_domain\', value)\n+ self.context._setPropValue("i18n_domain", value)\n \n i18n_domain = property(get_i18n_domain, set_i18n_domain)\n \n@@ -122,7 +124,7 @@ def get_url_expr(self):\n return self.context.url_expr\n \n def set_url_expr(self, value):\n- self.context._setPropValue(\'url_expr\', value)\n+ self.context._setPropValue("url_expr", value)\n \n url_expr = property(get_url_expr, set_url_expr)\n \n@@ -130,7 +132,7 @@ def get_available_expr(self):\n return self.context.available_expr\n \n def set_available_expr(self, value):\n- self.context._setPropValue(\'available_expr\', value)\n+ self.context._setPropValue("available_expr", value)\n \n available_expr = property(get_available_expr, set_available_expr)\n \n@@ -138,7 +140,7 @@ def get_permissions(self):\n return self.context.permissions\n \n def set_permissions(self, value):\n- self.context._setPropValue(\'permissions\', value)\n+ self.context._setPropValue("permissions", value)\n \n permissions = property(get_permissions, set_permissions)\n \n@@ -146,7 +148,7 @@ def get_visible(self):\n return self.context.visible\n \n def set_visible(self, value):\n- self.context._setPropValue(\'visible\', value)\n+ self.context._setPropValue("visible", value)\n \n visible = property(get_visible, set_visible)\n \n@@ -155,13 +157,13 @@ def get_position(self):\n return position + 1\n \n def set_position(self, value):\n- current_position = self.current_category.objectIds().index(\n- self.context.id)\n+ current_position = self.current_category.objectIds().index(self.context.id)\n all_actions = list(self.current_category._objects)\n current_action = all_actions.pop(current_position)\n new_position = value - 1\n- all_actions = all_actions[0:new_position] + [current_action] + \\\n- all_actions[new_position:]\n+ all_actions = (\n+ all_actions[0:new_position] + [current_action] + all_actions[new_position:]\n+ )\n self.current_category._objects = tuple(all_actions)\n \n position = property(get_position, set_position)\n@@ -176,9 +178,9 @@ def set_modal(self, value):\n # We cannot define a property when an attribute with the same\n # name already exists.\n delattr(self.context, "modal")\n- self.context._setProperty(\'modal\', value, \'string\')\n+ self.context._setProperty("modal", value, "string")\n else:\n- self.context._setPropValue(\'modal\', value)\n+ self.context._setPropValue("modal", value)\n \n modal = property(get_modal, set_modal)\n \n@@ -188,7 +190,7 @@ class ActionControlPanel(AutoExtensibleForm, form.EditForm):\n \n schema = IActionSchema\n ignoreContext = False\n- label = _(\'Action Settings\')\n+ label = _("Action Settings")\n \n \n class NewActionControlPanel(AutoExtensibleForm, form.AddForm):\n@@ -196,17 +198,17 @@ class NewActionControlPanel(AutoExtensibleForm, form.AddForm):\n \n schema = INewActionSchema\n ignoreContext = True\n- label = _(\'New action\')\n+ label = _("New action")\n \n def createAndAdd(self, data):\n- portal_actions = getToolByName(self.context, \'portal_actions\')\n- category = portal_actions.get(data[\'category\'])\n- action_id = data[\'id\']\n+ portal_actions = getToolByName(self.context, "portal_actions")\n+ category = portal_actions.get(data["category"])\n+ action_id = data["id"]\n action = Action(\n action_id,\n title=action_id,\n- i18n_domain=\'plone\',\n- permissions=[\'View\'],\n+ i18n_domain="plone",\n+ permissions=["View"],\n )\n category[action_id] = action\n notify(ObjectCreatedEvent(action))\ndiff --git a/Products/CMFPlone/controlpanel/browser/dateandtime.py b/Products/CMFPlone/controlpanel/browser/dateandtime.py\nindex d9d606e825..9683308fb1 100644\n--- a/Products/CMFPlone/controlpanel/browser/dateandtime.py\n+++ b/Products/CMFPlone/controlpanel/browser/dateandtime.py\n@@ -5,7 +5,6 @@\n \n \n class DateAndTimeControlPanelForm(RegistryEditForm):\n-\n id = "DateAndTimeControlPanel"\n schema = IDateAndTimeSchema\n schema_prefix = "plone"\n@@ -13,7 +12,7 @@ class DateAndTimeControlPanelForm(RegistryEditForm):\n label = _("label_dateandtime_settings", default="Date and Time Settings")\n description = _(\n "help_event_settings",\n- default="Date and Time related settings like timezone(s), etc."\n+ default="Date and Time related settings like timezone(s), etc.",\n )\n \n \ndiff --git a/Products/CMFPlone/controlpanel/browser/editing.py b/Products/CMFPlone/controlpanel/browser/editing.py\nindex 3c48883959..8778eaef65 100644\n--- a/Products/CMFPlone/controlpanel/browser/editing.py\n+++ b/Products/CMFPlone/controlpanel/browser/editing.py\n@@ -5,7 +5,6 @@\n \n \n class EditingControlPanelForm(controlpanel.RegistryEditForm):\n-\n id = "EditingControlPanel"\n label = _("Editing Settings")\n schema = IEditingSchema\n@@ -14,7 +13,7 @@ class EditingControlPanelForm(controlpanel.RegistryEditForm):\n def updateWidgets(self):\n super().updateWidgets()\n # hide the available_editors field/widgets\n- self.widgets[\'available_editors\'].mode = interfaces.HIDDEN_MODE\n+ self.widgets["available_editors"].mode = interfaces.HIDDEN_MODE\n \n \n class EditingControlPanel(controlpanel.ControlPanelFormWrapper):\ndiff --git a/Products/CMFPlone/controlpanel/browser/error_log_form.py b/Products/CMFPlone/controlpanel/browser/error_log_form.py\nindex 7bd67ac821..b91169ff4c 100644\n--- a/Products/CMFPlone/controlpanel/browser/error_log_form.py\n+++ b/Products/CMFPlone/controlpanel/browser/error_log_form.py\n@@ -7,41 +7,53 @@\n \n \n class ErrorLogUpdate(BrowserView):\n-\n def __call__(self):\n member = api.user.get_current()\n \n- if getattr(self.request, \'form.button.search\', None) is not None:\n- search = self.request.form.get(\'search_entry\')\n- if search == \'\':\n+ if getattr(self.request, "form.button.search", None) is not None:\n+ search = self.request.form.get("search_entry")\n+ if search == "":\n member.setProperties(error_log_update=0.0)\n- self.context.plone_utils.addPortalMessage(_(\'Showing all entries\'))\n- return self.request.RESPONSE.redirect(self.context.absolute_url() + \'/@@error-log-form\')\n- return self.request.RESPONSE.redirect(self.context.absolute_url() + \'/@@error-log-show-entry?id=%s\' % search)\n-\n- elif getattr(self.request, \'form.button.showall\', None) is not None:\n+ self.context.plone_utils.addPortalMessage(_("Showing all entries"))\n+ return self.request.RESPONSE.redirect(\n+ self.context.absolute_url() + "/@@error-log-form"\n+ )\n+ return self.request.RESPONSE.redirect(\n+ self.context.absolute_url() + "/@@error-log-show-entry?id=%s" % search\n+ )\n+\n+ elif getattr(self.request, "form.button.showall", None) is not None:\n member.setProperties(error_log_update=0.0)\n- self.context.plone_utils.addPortalMessage(_(\'Showing all entries\'))\n- return self.request.RESPONSE.redirect(self.context.absolute_url() + \'/@@error-log-form\')\n+ self.context.plone_utils.addPortalMessage(_("Showing all entries"))\n+ return self.request.RESPONSE.redirect(\n+ self.context.absolute_url() + "/@@error-log-form"\n+ )\n \n- elif getattr(self.request, \'form.button.clear\', None) is not None:\n+ elif getattr(self.request, "form.button.clear", None) is not None:\n member.setProperties(error_log_update=DateTime().timeTime())\n- self.context.plone_utils.addPortalMessage(_(\'Entries cleared\'))\n- return self.request.RESPONSE.redirect(self.context.absolute_url() + \'/@@error-log-form\')\n+ self.context.plone_utils.addPortalMessage(_("Entries cleared"))\n+ return self.request.RESPONSE.redirect(\n+ self.context.absolute_url() + "/@@error-log-form"\n+ )\n \n else:\n- return self.request.RESPONSE.redirect(self.context.absolute_url() + \'/@@error-log-form\')\n+ return self.request.RESPONSE.redirect(\n+ self.context.absolute_url() + "/@@error-log-form"\n+ )\n \n \n class ErrorLogSetProperties(BrowserView):\n-\n def __call__(self):\n- keep_entries = self.request.form.get(\'keep_entries\')\n- ignored_exceptions = self.request.form.get(\'ignored_exceptions\')\n- copy_to_zlog = self.request.form.get(\'copy_to_zlog\', 0)\n+ keep_entries = self.request.form.get("keep_entries")\n+ ignored_exceptions = self.request.form.get("ignored_exceptions")\n+ copy_to_zlog = self.request.form.get("copy_to_zlog", 0)\n \n ignored_exceptions = map(safe_nativestring, ignored_exceptions)\n- self.context.error_log.setProperties(keep_entries, copy_to_zlog, ignored_exceptions)\n- self.context.plone_utils.addPortalMessage(_(\'Changes made.\'))\n-\n- return self.request.RESPONSE.redirect(self.context.absolute_url() + \'/@@error-log-form\')\n+ self.context.error_log.setProperties(\n+ keep_entries, copy_to_zlog, ignored_exceptions\n+ )\n+ self.context.plone_utils.addPortalMessage(_("Changes made."))\n+\n+ return self.request.RESPONSE.redirect(\n+ self.context.absolute_url() + "/@@error-log-form"\n+ )\ndiff --git a/Products/CMFPlone/controlpanel/browser/filter.py b/Products/CMFPlone/controlpanel/browser/filter.py\nindex 09a3e8209f..d9210e96f3 100644\n--- a/Products/CMFPlone/controlpanel/browser/filter.py\n+++ b/Products/CMFPlone/controlpanel/browser/filter.py\n@@ -10,14 +10,15 @@\n class FilterControlPanel(controlpanel.RegistryEditForm):\n id = "FilterControlPanel"\n label = _("HTML Filtering Settings")\n- description = _("Keep in mind that editors like TinyMCE might have "\n- "additional filters.")\n+ description = _(\n+ "Keep in mind that editors like TinyMCE might have " "additional filters."\n+ )\n schema = IFilterSchema\n schema_prefix = "plone"\n form_name = _("HTML Filtering Settings")\n control_panel_view = "filter-controlpanel"\n \n- @button.buttonAndHandler(_("Save"), name=\'save\')\n+ @button.buttonAndHandler(_("Save"), name="save")\n def handleSave(self, action): # NOQA\n data, errors = self.extractData()\n if errors:\n@@ -25,32 +26,31 @@ def handleSave(self, action): # NOQA\n return\n \n self.applyChanges(data)\n+ IStatusMessage(self.request).addStatusMessage(_("Changes saved."), "info")\n IStatusMessage(self.request).addStatusMessage(\n- _("Changes saved."),\n- "info")\n- IStatusMessage(self.request).addStatusMessage(\n- _("HTML generation is heavily cached across Plone. You may "\n- "have to edit existing content or restart your server to see "\n- "the changes."),\n- "warning")\n+ _(\n+ "HTML generation is heavily cached across Plone. You may "\n+ "have to edit existing content or restart your server to see "\n+ "the changes."\n+ ),\n+ "warning",\n+ )\n self.request.response.redirect(self.request.getURL())\n \n- @button.buttonAndHandler(_("Cancel"), name=\'cancel\')\n+ @button.buttonAndHandler(_("Cancel"), name="cancel")\n def handleCancel(self, action):\n- IStatusMessage(self.request).addStatusMessage(\n- _("Changes canceled."),\n- "info")\n- self.request.response.redirect("{}/{}".format(\n- self.context.absolute_url(),\n- self.control_panel_view))\n+ IStatusMessage(self.request).addStatusMessage(_("Changes canceled."), "info")\n+ self.request.response.redirect(\n+ "{}/{}".format(self.context.absolute_url(), self.control_panel_view)\n+ )\n \n \n class ControlPanelFormWrapper(layout.FormWrapper):\n """Use this form as the plone.z3cform layout wrapper to get the control\n panel layout.\n """\n- index = ViewPageTemplateFile(\'filter_controlpanel.pt\')\n+\n+ index = ViewPageTemplateFile("filter_controlpanel.pt")\n \n \n-FilterControlPanelView = layout.wrap_form(\n- FilterControlPanel, ControlPanelFormWrapper)\n+FilterControlPanelView = layout.wrap_form(FilterControlPanel, ControlPanelFormWrapper)\ndiff --git a/Products/CMFPlone/controlpanel/browser/imaging.py b/Products/CMFPlone/controlpanel/browser/imaging.py\nindex a5cb3e943c..be12bb0345 100644\n--- a/Products/CMFPlone/controlpanel/browser/imaging.py\n+++ b/Products/CMFPlone/controlpanel/browser/imaging.py\n@@ -4,11 +4,10 @@\n from plone.base.interfaces.controlpanel import IImagingSchema\n \n \n-log = getLogger(\'Plone\')\n+log = getLogger("Plone")\n \n \n class ImagingControlPanelForm(controlpanel.RegistryEditForm):\n-\n id = "ImagingSettings"\n label = _("Image Handling Settings")\n schema = IImagingSchema\ndiff --git a/Products/CMFPlone/controlpanel/browser/language.py b/Products/CMFPlone/controlpanel/browser/language.py\nindex 289715aa02..fa9b12ff68 100644\n--- a/Products/CMFPlone/controlpanel/browser/language.py\n+++ b/Products/CMFPlone/controlpanel/browser/language.py\n@@ -6,47 +6,46 @@\n \n \n class LanguageControlPanelForm(controlpanel.RegistryEditForm):\n-\n id = "LanguageControlPanel"\n label = _("heading_language_settings", default="Language Settings")\n- description = _("description_language_settings",\n- default="Settings related to interface languages and "\n- "content translations.")\n+ description = _(\n+ "description_language_settings",\n+ default="Settings related to interface languages and " "content translations.",\n+ )\n \n schema = ILanguageSchema\n schema_prefix = "plone"\n \n- @button.buttonAndHandler(_("Save"), name=\'save\')\n+ @button.buttonAndHandler(_("Save"), name="save")\n def handleSave(self, action):\n data, errors = self.extractData()\n if errors:\n self.status = self.formErrorsMessage\n return\n # We need to check if the default language is in available languages\n- if \'default_language\' in data and \'available_languages\' in data and \\\n- data[\'default_language\'] not in data[\'available_languages\']:\n+ if (\n+ "default_language" in data\n+ and "available_languages" in data\n+ and data["default_language"] not in data["available_languages"]\n+ ):\n IStatusMessage(self.request).addStatusMessage(\n- _("Default language not in available languages"),\n- "error")\n+ _("Default language not in available languages"), "error"\n+ )\n \n # e = Invalid(_(u"Default language not in available languages"))\n # raise WidgetActionExecutionError(\'default_language\', e)\n return\n \n self.applyChanges(data)\n- IStatusMessage(self.request).addStatusMessage(\n- _("Changes saved."),\n- "info")\n+ IStatusMessage(self.request).addStatusMessage(_("Changes saved."), "info")\n self.request.response.redirect(self.request.getURL())\n \n- @button.buttonAndHandler(_("Cancel"), name=\'cancel\')\n+ @button.buttonAndHandler(_("Cancel"), name="cancel")\n def handleCancel(self, action):\n- IStatusMessage(self.request).addStatusMessage(\n- _("Changes canceled."),\n- "info")\n- self.request.response.redirect("{}/{}".format(\n- self.context.absolute_url(),\n- self.control_panel_view))\n+ IStatusMessage(self.request).addStatusMessage(_("Changes canceled."), "info")\n+ self.request.response.redirect(\n+ "{}/{}".format(self.context.absolute_url(), self.control_panel_view)\n+ )\n \n \n class LanguageControlPanel(controlpanel.ControlPanelFormWrapper):\ndiff --git a/Products/CMFPlone/controlpanel/browser/mail.py b/Products/CMFPlone/controlpanel/browser/mail.py\nindex 4bb7c97ff2..caf29a899a 100644\n--- a/Products/CMFPlone/controlpanel/browser/mail.py\n+++ b/Products/CMFPlone/controlpanel/browser/mail.py\n@@ -14,21 +14,20 @@\n import sys\n \n \n-log = getLogger(\'Plone\')\n+log = getLogger("Plone")\n \n \n class MailControlPanelForm(controlpanel.RegistryEditForm):\n-\n id = "MailControlPanel"\n label = _("Mail Settings")\n schema = IMailSchema\n schema_prefix = "plone"\n \n- @button.buttonAndHandler(_(\'Save\'), name=None)\n+ @button.buttonAndHandler(_("Save"), name=None)\n def handleSave(self, action):\n self.save()\n \n- @button.buttonAndHandler(_(\'Cancel\'), name=\'cancel\')\n+ @button.buttonAndHandler(_("Cancel"), name="cancel")\n def handleCancel(self, action):\n super().handleCancel(self, action)\n \n@@ -38,34 +37,36 @@ def save(self):\n self.status = self.formErrorsMessage\n return False\n # keep password field\n- smtp_user_id = (data.get(\'smtp_userid\') or \'\').strip()\n- smtp_pass = (data.get(\'smtp_pass\') or \'\').strip()\n+ smtp_user_id = (data.get("smtp_userid") or "").strip()\n+ smtp_pass = (data.get("smtp_pass") or "").strip()\n if smtp_user_id and not smtp_pass:\n- del data[\'smtp_pass\']\n+ del data["smtp_pass"]\n \n self.applyChanges(data)\n return True\n \n @button.buttonAndHandler(\n- _(\'label_smtp_test\', default=\'Save and send test e-mail\'),\n- name=\'test\')\n+ _("label_smtp_test", default="Save and send test e-mail"), name="test"\n+ )\n def handle_test_action(self, action):\n # Save data first\n if not self.save():\n return\n- mailhost = getToolByName(self.context, \'MailHost\')\n+ mailhost = getToolByName(self.context, "MailHost")\n \n registry = getUtility(IRegistry)\n- mail_settings = registry.forInterface(IMailSchema, prefix=\'plone\')\n+ mail_settings = registry.forInterface(IMailSchema, prefix="plone")\n fromaddr = mail_settings.email_from_address\n \n- message = ("Hi,\\n\\nThis is a test message sent from the Plone "\n- "\'Mail settings\' control panel. Your receipt of this "\n- "message (at the address specified in the Site \'From\' "\n- "address field) indicates that your e-mail server is "\n- "working!\\n\\n"\n- "Have a nice day.\\n\\n"\n- "Love,\\n\\nPlone")\n+ message = (\n+ "Hi,\\n\\nThis is a test message sent from the Plone "\n+ "\'Mail settings\' control panel. Your receipt of this "\n+ "message (at the address specified in the Site \'From\' "\n+ "address field) indicates that your e-mail server is "\n+ "working!\\n\\n"\n+ "Have a nice day.\\n\\n"\n+ "Love,\\n\\nPlone"\n+ )\n email_charset = mail_settings.email_charset\n subject = "Test e-mail from Plone"\n \n@@ -77,25 +78,28 @@ def handle_test_action(self, action):\n try:\n socket.setdefaulttimeout(3)\n try:\n- mailhost.send(message,\n- mto=fromaddr,\n- mfrom=fromaddr,\n- subject=subject,\n- charset=email_charset,\n- immediate=True)\n+ mailhost.send(\n+ message,\n+ mto=fromaddr,\n+ mfrom=fromaddr,\n+ subject=subject,\n+ charset=email_charset,\n+ immediate=True,\n+ )\n \n except (OSError, MailHostError, smtplib.SMTPException):\n # Connection refused or timeout.\n- log.exception(\'Unable to send test e-mail.\')\n+ log.exception("Unable to send test e-mail.")\n value = sys.exc_info()[1]\n- msg = _(\'Unable to send test e-mail ${error}.\',\n- mapping={\'error\': str(value)})\n- IStatusMessage(self.request).addStatusMessage(\n- msg, type=\'error\')\n+ msg = _(\n+ "Unable to send test e-mail ${error}.",\n+ mapping={"error": str(value)},\n+ )\n+ IStatusMessage(self.request).addStatusMessage(msg, type="error")\n else:\n IStatusMessage(self.request).addStatusMessage(\n- _(\'Success! Check your mailbox for the test message.\'),\n- type=\'info\')\n+ _("Success! Check your mailbox for the test message."), type="info"\n+ )\n finally:\n # Restore timeout to default value\n socket.setdefaulttimeout(timeout)\ndiff --git a/Products/CMFPlone/controlpanel/browser/maintenance.py b/Products/CMFPlone/controlpanel/browser/maintenance.py\nindex c9baf3b9d3..f429f3cbae 100644\n--- a/Products/CMFPlone/controlpanel/browser/maintenance.py\n+++ b/Products/CMFPlone/controlpanel/browser/maintenance.py\n@@ -38,20 +38,20 @@ class MaintenanceControlPanel(AutoExtensibleForm, form.EditForm):\n \n schema = IMaintenanceSchema\n id = "maintenance-control-panel"\n- label = _(\'Maintenance Settings\')\n+ label = _("Maintenance Settings")\n description = _("Zope server and site maintenance options.")\n- form_name = _(\'Zope Database Packing\')\n+ form_name = _("Zope Database Packing")\n control_panel_view = "maintenance-controlpanel"\n- template = ViewPageTemplateFile(\'maintenance.pt\')\n+ template = ViewPageTemplateFile("maintenance.pt")\n \n @memoize\n def portal(self):\n portal_state = getMultiAdapter(\n- (aq_inner(self.context), self.request),\n- name=\'plone_portal_state\')\n+ (aq_inner(self.context), self.request), name="plone_portal_state"\n+ )\n return portal_state.portal()\n \n- @button.buttonAndHandler(_(\'Pack database now\'), name=\'pack\')\n+ @button.buttonAndHandler(_("Pack database now"), name="pack")\n def handle_pack_action(self, action):\n data, errors = self.extractData()\n if errors:\n@@ -60,69 +60,71 @@ def handle_pack_action(self, action):\n CheckAuthenticator(self.request)\n if not self.available():\n self.status = _(\n- \'text_not_allowed_manage_server\',\n- default=\'You are not allowed to manage the Zope server.\'\n+ "text_not_allowed_manage_server",\n+ default="You are not allowed to manage the Zope server.",\n )\n return\n \n- days = data.get(\'days\', None)\n+ days = data.get("days", None)\n # skip the actual pack method in tests\n if days is not None and isinstance(days, int) and days >= 0:\n db = self.portal()._p_jar.db()\n t = time.time() - (days * 86400)\n db.pack(t)\n- self.status = _(\'Packed the database.\')\n+ self.status = _("Packed the database.")\n \n- @button.buttonAndHandler(_(\'Shut down\'), name=\'shutdown\')\n+ @button.buttonAndHandler(_("Shut down"), name="shutdown")\n def handle_shutdown_action(self, action):\n CheckAuthenticator(self.request)\n if not self.available():\n self.status = _(\n- \'text_not_allowed_manage_server\',\n- default=\'You are not allowed to manage the Zope server.\'\n+ "text_not_allowed_manage_server",\n+ default="You are not allowed to manage the Zope server.",\n )\n return\n try:\n user = \'"%s"\' % getSecurityManager().getUser().getUserName()\n except:\n- user = \'unknown user\'\n+ user = "unknown user"\n logger.info("Shutdown requested by %s" % user)\n if LIFETIME:\n shutdown(0)\n else:\n raise\n # TODO: returning html has no effect in button handlers\n- self.request.response.setHeader(\'X-Theme-Disabled\', \'True\')\n+ self.request.response.setHeader("X-Theme-Disabled", "True")\n return """{}""".format(\n- _(\'plone_shutdown\', default="Zope is shutting down.")\n+ _("plone_shutdown", default="Zope is shutting down.")\n )\n \n- @button.buttonAndHandler(_(\'Restart\'), name=\'restart\')\n+ @button.buttonAndHandler(_("Restart"), name="restart")\n def handle_restart_action(self, action):\n CheckAuthenticator(self.request)\n if not self.available():\n self.status = _(\n- \'text_not_allowed_manage_server\',\n- default=\'You are not allowed to manage the Zope server.\'\n+ "text_not_allowed_manage_server",\n+ default="You are not allowed to manage the Zope server.",\n )\n return\n \n try:\n user = \'"%s"\' % getSecurityManager().getUser().getUserName()\n except:\n- user = \'unknown user\'\n+ user = "unknown user"\n logger.info("Restart requested by %s" % user)\n shutdown(1)\n- url = self.request.get(\'URL\')\n+ url = self.request.get("URL")\n # TODO: returning html has no effect in button handlers\n- self.request.response.setHeader(\'X-Theme-Disabled\', \'True\')\n+ self.request.response.setHeader("X-Theme-Disabled", "True")\n return """\n \n {}""".format(\n escape(url, 1),\n- _(\'plone_restarting\',\n+ _(\n+ "plone_restarting",\n default="Zope is restarting. This page will refresh in 30"\n- " seconds...")\n+ " seconds...",\n+ ),\n )\n \n def available(self):\n@@ -131,7 +133,7 @@ def available(self):\n return sm.checkPermission(view_management_screens, root)\n \n def isRestartable(self):\n- if \'ZMANAGED\' in os.environ:\n+ if "ZMANAGED" in os.environ:\n return True\n return False\n \n@@ -139,9 +141,9 @@ def isDevelopmentMode(self):\n return bool(getConfiguration().debug_mode)\n \n def coreVersions(self):\n- mt = getToolByName(self.context, \'portal_migration\')\n+ mt = getToolByName(self.context, "portal_migration")\n versions = mt.coreVersions()\n- versions[\'Instance\'] = versions[\'Plone Instance\']\n+ versions["Instance"] = versions["Plone Instance"]\n return versions\n \n def dbName(self):\n@@ -155,5 +157,5 @@ def dbSize(self):\n return size\n \n if size >= 1048576.0:\n- return \'%.1f MB\' % (size / 1048576.0)\n- return \'%.1f kB\' % (size / 1024.0)\n+ return "%.1f MB" % (size / 1048576.0)\n+ return "%.1f kB" % (size / 1024.0)\ndiff --git a/Products/CMFPlone/controlpanel/browser/markup.py b/Products/CMFPlone/controlpanel/browser/markup.py\nindex e6e7949401..e628160e78 100644\n--- a/Products/CMFPlone/controlpanel/browser/markup.py\n+++ b/Products/CMFPlone/controlpanel/browser/markup.py\n@@ -5,7 +5,6 @@\n \n \n class MarkupControlPanelForm(controlpanel.RegistryEditForm):\n-\n id = "MarkupControlPanel"\n label = _("Markup Settings")\n schema = IMarkupSchema\n@@ -13,8 +12,7 @@ class MarkupControlPanelForm(controlpanel.RegistryEditForm):\n \n def updateFields(self):\n super().updateFields()\n- self.fields[\'allowed_types\'].widgetFactory = \\\n- CheckBoxFieldWidget\n+ self.fields["allowed_types"].widgetFactory = CheckBoxFieldWidget\n \n \n class MarkupControlPanel(controlpanel.ControlPanelFormWrapper):\ndiff --git a/Products/CMFPlone/controlpanel/browser/navigation.py b/Products/CMFPlone/controlpanel/browser/navigation.py\nindex e005fc6771..ab0a59e0a2 100644\n--- a/Products/CMFPlone/controlpanel/browser/navigation.py\n+++ b/Products/CMFPlone/controlpanel/browser/navigation.py\n@@ -5,24 +5,22 @@\n \n \n class NavigationControlPanelForm(controlpanel.RegistryEditForm):\n-\n id = "NavigationControlPanel"\n label = _("Navigation Settings")\n description = _(\n- "Lets you control how navigation is constructed in your site. " +\n- "Note that to control how the navigation tree is displayed, you " +\n- "should go to \'Manage portlets\' at the root of the site (or " +\n- "wherever a navigation tree portlet has been added) and change " +\n- "its settings directly.")\n+ "Lets you control how navigation is constructed in your site. "\n+ + "Note that to control how the navigation tree is displayed, you "\n+ + "should go to \'Manage portlets\' at the root of the site (or "\n+ + "wherever a navigation tree portlet has been added) and change "\n+ + "its settings directly."\n+ )\n schema = INavigationSchema\n schema_prefix = "plone"\n \n def updateFields(self):\n super().updateFields()\n- self.fields[\'displayed_types\'].widgetFactory = \\\n- CheckBoxFieldWidget\n- self.fields[\'workflow_states_to_show\'].widgetFactory = \\\n- CheckBoxFieldWidget\n+ self.fields["displayed_types"].widgetFactory = CheckBoxFieldWidget\n+ self.fields["workflow_states_to_show"].widgetFactory = CheckBoxFieldWidget\n \n \n class NavigationControlPanel(controlpanel.ControlPanelFormWrapper):\ndiff --git a/Products/CMFPlone/controlpanel/browser/overview.py b/Products/CMFPlone/controlpanel/browser/overview.py\nindex ab5be04ade..e0c68ece71 100644\n--- a/Products/CMFPlone/controlpanel/browser/overview.py\n+++ b/Products/CMFPlone/controlpanel/browser/overview.py\n@@ -25,7 +25,6 @@\n \n \n class OverviewControlPanel(controlpanel.RegistryEditForm):\n-\n template = ViewPageTemplateFile("overview.pt")\n \n base_category = "controlpanel"\n@@ -76,7 +75,6 @@ def server_info(self):\n }\n \n def version_overview(self):\n-\n core_versions = self.core_versions()\n versions = [\n "Plone {} ({})".format(\ndiff --git a/Products/CMFPlone/controlpanel/browser/prefsmaintemplate.py b/Products/CMFPlone/controlpanel/browser/prefsmaintemplate.py\nindex 5423716bc0..2699b7752a 100644\n--- a/Products/CMFPlone/controlpanel/browser/prefsmaintemplate.py\n+++ b/Products/CMFPlone/controlpanel/browser/prefsmaintemplate.py\n@@ -3,8 +3,7 @@\n \n \n class PrefsMainTemplate(BrowserView):\n-\n- prefs_main_template_name = \'prefsmaintemplate.pt\'\n+ prefs_main_template_name = "prefsmaintemplate.pt"\n \n def __call__(self):\n return ViewPageTemplateFile(self.prefs_main_template_name)\ndiff --git a/Products/CMFPlone/controlpanel/browser/quickinstaller.py b/Products/CMFPlone/controlpanel/browser/quickinstaller.py\nindex 6e59ecbe9a..37733f302e 100644\n--- a/Products/CMFPlone/controlpanel/browser/quickinstaller.py\n+++ b/Products/CMFPlone/controlpanel/browser/quickinstaller.py\n@@ -14,16 +14,15 @@\n import transaction\n \n \n-logger = logging.getLogger(\'Plone\')\n+logger = logging.getLogger("Plone")\n \n \n class InstallerView(BrowserView):\n- """View on all contexts for installing and uninstalling products.\n- """\n+ """View on all contexts for installing and uninstalling products."""\n \n def __init__(self, *args, **kwargs):\n super().__init__(*args, **kwargs)\n- self.ps = getToolByName(self.context, \'portal_setup\')\n+ self.ps = getToolByName(self.context, "portal_setup")\n self.errors = {}\n \n def is_profile_installed(self, profile_id):\n@@ -33,19 +32,20 @@ def is_product_installed(self, product_id):\n profile = self.get_install_profile(product_id, allow_hidden=True)\n if not profile:\n return False\n- return self.is_profile_installed(profile[\'id\'])\n+ return self.is_profile_installed(profile["id"])\n \n def _install_profile_info(self, product_id):\n- """List extension profile infos of a given product.\n- """\n+ """List extension profile infos of a given product."""\n profiles = self.ps.listProfileInfo()\n # We are only interested in extension profiles for the product.\n # TODO Remove the manual Products.* check here. It is still needed.\n profiles = [\n- prof for prof in profiles\n- if prof[\'type\'] == EXTENSION and (\n- prof[\'product\'] == product_id or\n- prof[\'product\'] == \'Products.%s\' % product_id\n+ prof\n+ for prof in profiles\n+ if prof["type"] == EXTENSION\n+ and (\n+ prof["product"] == product_id\n+ or prof["product"] == "Products.%s" % product_id\n )\n ]\n return profiles\n@@ -55,7 +55,7 @@ def get_install_profiles(self, product_id):\n \n TODO Might be superfluous.\n """\n- return [prof[\'id\'] for prof in self._install_profile_info(product_id)]\n+ return [prof["id"] for prof in self._install_profile_info(product_id)]\n \n def _get_profile(self, product_id, name, strict=True, allow_hidden=False):\n """Return profile with given name.\n@@ -83,7 +83,7 @@ def _get_profile(self, product_id, name, strict=True, allow_hidden=False):\n utils = getAllUtilitiesRegisteredFor(INonInstallable)\n hidden = []\n for util in utils:\n- gnip = getattr(util, \'getNonInstallableProfiles\', None)\n+ gnip = getattr(util, "getNonInstallableProfiles", None)\n if gnip is None:\n continue\n hidden.extend(gnip())\n@@ -93,8 +93,8 @@ def _get_profile(self, product_id, name, strict=True, allow_hidden=False):\n prime_candidates = []\n hidden_candidates = []\n for profile in profiles:\n- profile_id = profile[\'id\']\n- profile_id_parts = profile_id.split(\':\')\n+ profile_id = profile["id"]\n+ profile_id_parts = profile_id.split(":")\n if len(profile_id_parts) != 2:\n logger.error("Profile with id \'%s\' is invalid." % profile_id)\n continue\n@@ -131,8 +131,9 @@ def get_install_profile(self, product_id, allow_hidden=False):\n :returns: True on success, False otherwise.\n :rtype: boolean\n """\n- return self._get_profile(product_id, \'default\', strict=False,\n- allow_hidden=allow_hidden)\n+ return self._get_profile(\n+ product_id, "default", strict=False, allow_hidden=allow_hidden\n+ )\n \n def get_uninstall_profile(self, product_id):\n """Return the uninstall profile.\n@@ -140,7 +141,8 @@ def get_uninstall_profile(self, product_id):\n Note: not used yet.\n """\n return self._get_profile(\n- product_id, \'uninstall\', strict=True, allow_hidden=True)\n+ product_id, "uninstall", strict=True, allow_hidden=True\n+ )\n \n def is_product_installable(self, product_id, allow_hidden=False):\n """Does a product have an installation profile?\n@@ -157,19 +159,18 @@ def is_product_installable(self, product_id, allow_hidden=False):\n not_installable = []\n utils = getAllUtilitiesRegisteredFor(INonInstallable)\n for util in utils:\n- gnip = getattr(util, \'getNonInstallableProducts\', None)\n+ gnip = getattr(util, "getNonInstallableProducts", None)\n if gnip is None:\n continue\n not_installable.extend(gnip())\n if product_id in not_installable:\n return False\n \n- profile = self.get_install_profile(\n- product_id, allow_hidden=allow_hidden)\n+ profile = self.get_install_profile(product_id, allow_hidden=allow_hidden)\n if profile is None:\n return\n try:\n- self.ps.getProfileDependencyChain(profile[\'id\'])\n+ self.ps.getProfileDependencyChain(profile["id"])\n except KeyError as e:\n # Don\'t show twice the same error: old install and profile\n # oldinstall is test in first in other methods we may have an extra\n@@ -181,45 +182,38 @@ def is_product_installable(self, product_id, allow_hidden=False):\n # 3. Make sense of the next five lines: they remove \'Products.\'\n # when it is there, and add it when it is not???\n checkname = product_id\n- if checkname.startswith(\'Products.\'):\n+ if checkname.startswith("Products."):\n checkname = checkname[9:]\n else:\n- checkname = \'Products.\' + checkname\n+ checkname = "Products." + checkname\n if checkname in self.errors:\n- if self.errors[checkname][\'value\'] == e.args[0]:\n+ if self.errors[checkname]["value"] == e.args[0]:\n return False\n # A new error is found, register it\n self.errors[product_id] = dict(\n- type=_(\n- "dependency_missing",\n- default="Missing dependency"\n- ),\n+ type=_("dependency_missing", default="Missing dependency"),\n value=e.args[0],\n- product_id=product_id\n+ product_id=product_id,\n )\n else:\n self.errors[product_id] = dict(\n- type=_(\n- "dependency_missing",\n- default="Missing dependency"\n- ),\n+ type=_("dependency_missing", default="Missing dependency"),\n value=e.args[0],\n- product_id=product_id\n+ product_id=product_id,\n )\n return False\n return True\n \n def get_product_version(self, product_id):\n- """Return the version of the product (package).\n- """\n+ """Return the version of the product (package)."""\n try:\n dist = pkg_resources.get_distribution(product_id)\n return dist.version\n except pkg_resources.DistributionNotFound:\n- if \'.\' in product_id:\n- return \'\'\n+ if "." in product_id:\n+ return ""\n # For CMFPlacefulWorkflow we need to try Products.CMFPlacefulWorkflow.\n- return self.get_product_version(\'Products.\' + product_id)\n+ return self.get_product_version("Products." + product_id)\n \n def get_latest_upgrade_step(self, profile_id):\n """Get highest ordered upgrade step for profile.\n@@ -232,8 +226,7 @@ def get_latest_upgrade_step(self, profile_id):\n available = self.ps.listUpgrades(profile_id, True)\n if available: # could return empty sequence\n latest = available[-1]\n- profile_version = max(latest[\'dest\'],\n- key=pkg_resources.parse_version)\n+ profile_version = max(latest["dest"], key=pkg_resources.parse_version)\n except Exception:\n pass\n return profile_version\n@@ -256,21 +249,19 @@ def upgrade_info(self, product_id):\n if profile is None:\n # No GS profile, not supported.\n return {}\n- profile_id = profile[\'id\']\n+ profile_id = profile["id"]\n if not self.is_profile_installed(profile_id):\n return {}\n profile_version = str(self.ps.getVersionForProfile(profile_id))\n- if profile_version == \'latest\':\n+ if profile_version == "latest":\n profile_version = self.get_latest_upgrade_step(profile_id)\n if profile_version == UNKNOWN:\n # If a profile doesn\'t have a metadata.xml use the package version.\n profile_version = self.get_product_version(product_id)\n- installed_profile_version = self.ps.getLastVersionForProfile(\n- profile_id)\n+ installed_profile_version = self.ps.getLastVersionForProfile(profile_id)\n # getLastVersionForProfile returns the version as a tuple or unknown.\n if installed_profile_version != UNKNOWN:\n- installed_profile_version = str(\n- \'.\'.join(installed_profile_version))\n+ installed_profile_version = str(".".join(installed_profile_version))\n return dict(\n required=profile_version != installed_profile_version,\n available=len(self.ps.listUpgrades(profile_id)) > 0,\n@@ -288,7 +279,7 @@ def upgrade_product(self, product_id):\n if profile is None:\n logger.error("Could not upgrade %s, no profile.", product_id)\n return False\n- self.ps.upgradeProfile(profile[\'id\'])\n+ self.ps.upgradeProfile(profile["id"])\n return True\n \n def install_product(self, product_id, allow_hidden=False):\n@@ -304,26 +295,28 @@ def install_product(self, product_id, allow_hidden=False):\n :returns: True on success, False otherwise.\n :rtype: boolean\n """\n- profile = self.get_install_profile(\n- product_id, allow_hidden=allow_hidden)\n+ profile = self.get_install_profile(product_id, allow_hidden=allow_hidden)\n if not profile:\n logger.error("Could not install %s: no profile found.", product_id)\n # TODO Possibly raise an error.\n return False\n \n if self.is_product_installed(product_id):\n- logger.error("Could not install %s: profile already installed.",\n- product_id)\n+ logger.error("Could not install %s: profile already installed.", product_id)\n return False\n \n # Okay, actually install the profile.\n- profile_id = profile[\'id\']\n- self.ps.runAllImportStepsFromProfile(\'profile-%s\' % profile_id)\n+ profile_id = profile["id"]\n+ self.ps.runAllImportStepsFromProfile("profile-%s" % profile_id)\n \n if not self.is_profile_installed(profile_id):\n version = self.get_product_version(product_id)\n- logger.warning(\'Profile %s has no metadata.xml version. Falling back \'\n- \'to package version %s\', profile_id, version)\n+ logger.warning(\n+ "Profile %s has no metadata.xml version. Falling back "\n+ "to package version %s",\n+ profile_id,\n+ version,\n+ )\n self.ps.setLastVersionForProfile(profile_id, version)\n \n # No problems encountered.\n@@ -336,18 +329,17 @@ def uninstall_product(self, product_id):\n """\n profile = self.get_uninstall_profile(product_id)\n if not profile:\n- logger.error("Could not uninstall %s: no uninstall profile "\n- "found.", product_id)\n+ logger.error(\n+ "Could not uninstall %s: no uninstall profile " "found.", product_id\n+ )\n return False\n \n- self.ps.runAllImportStepsFromProfile(\n- \'profile-%s\' % profile[\'id\'])\n+ self.ps.runAllImportStepsFromProfile("profile-%s" % profile["id"])\n \n # Unmark the install profile.\n- install_profile = self.get_install_profile(\n- product_id, allow_hidden=True)\n+ install_profile = self.get_install_profile(product_id, allow_hidden=True)\n if install_profile:\n- self.ps.unsetLastVersionForProfile(install_profile[\'id\'])\n+ self.ps.unsetLastVersionForProfile(install_profile["id"])\n return True\n \n \n@@ -368,10 +360,10 @@ def marshall_addons(self):\n ignore_products = []\n utils = getAllUtilitiesRegisteredFor(INonInstallable)\n for util in utils:\n- ni_profiles = getattr(util, \'getNonInstallableProfiles\', None)\n+ ni_profiles = getattr(util, "getNonInstallableProfiles", None)\n if ni_profiles is not None:\n ignore_profiles.extend(ni_profiles())\n- ni_products = getattr(util, \'getNonInstallableProducts\', None)\n+ ni_products = getattr(util, "getNonInstallableProducts", None)\n if ni_products is not None:\n ignore_products.extend(ni_products())\n \n@@ -381,17 +373,17 @@ def marshall_addons(self):\n # applied already).\n # profiles_with_upgrades = self.ps.listProfilesWithUpgrades()\n for profile in profiles:\n- if profile[\'type\'] != EXTENSION:\n+ if profile["type"] != EXTENSION:\n continue\n \n- pid = profile[\'id\']\n+ pid = profile["id"]\n if pid in ignore_profiles:\n continue\n- pid_parts = pid.split(\':\')\n+ pid_parts = pid.split(":")\n if len(pid_parts) != 2:\n logger.error("Profile with id \'%s\' is invalid." % pid)\n # Which package (product) is this from?\n- product_id = profile[\'product\']\n+ product_id = profile["product"]\n if product_id in ignore_products:\n continue\n profile_type = pid_parts[-1]\n@@ -404,44 +396,46 @@ def marshall_addons(self):\n elif not self.is_product_installable(product_id):\n continue\n addons[product_id] = {\n- \'id\': product_id,\n- \'version\': self.get_product_version(product_id),\n- \'title\': product_id,\n- \'description\': \'\',\n- \'upgrade_profiles\': {},\n- \'other_profiles\': [],\n- \'install_profile\': None,\n- \'install_profile_id\': \'\',\n- \'uninstall_profile\': None,\n- \'uninstall_profile_id\': \'\',\n- \'is_installed\': installed,\n- \'upgrade_info\': upgrade_info,\n- \'profile_type\': profile_type,\n+ "id": product_id,\n+ "version": self.get_product_version(product_id),\n+ "title": product_id,\n+ "description": "",\n+ "upgrade_profiles": {},\n+ "other_profiles": [],\n+ "install_profile": None,\n+ "install_profile_id": "",\n+ "uninstall_profile": None,\n+ "uninstall_profile_id": "",\n+ "is_installed": installed,\n+ "upgrade_info": upgrade_info,\n+ "profile_type": profile_type,\n }\n # Add info on install and uninstall profile.\n product = addons[product_id]\n install_profile = self.get_install_profile(product_id)\n if install_profile is not None:\n- product[\'title\'] = install_profile[\'title\']\n- product[\'description\'] = install_profile[\'description\']\n- product[\'install_profile\'] = install_profile\n- product[\'install_profile_id\'] = install_profile[\'id\']\n- product[\'profile_type\'] = \'default\'\n+ product["title"] = install_profile["title"]\n+ product["description"] = install_profile["description"]\n+ product["install_profile"] = install_profile\n+ product["install_profile_id"] = install_profile["id"]\n+ product["profile_type"] = "default"\n uninstall_profile = self.get_uninstall_profile(product_id)\n if uninstall_profile is not None:\n- product[\'uninstall_profile\'] = uninstall_profile\n- product[\'uninstall_profile_id\'] = uninstall_profile[\'id\']\n+ product["uninstall_profile"] = uninstall_profile\n+ product["uninstall_profile_id"] = uninstall_profile["id"]\n # Do not override profile_type.\n- if not product[\'profile_type\']:\n- product[\'profile_type\'] = \'uninstall\'\n- if profile[\'id\'] in (product[\'install_profile_id\'],\n- product[\'uninstall_profile_id\']):\n+ if not product["profile_type"]:\n+ product["profile_type"] = "uninstall"\n+ if profile["id"] in (\n+ product["install_profile_id"],\n+ product["uninstall_profile_id"],\n+ ):\n # Everything has been done.\n continue\n- elif \'version\' in profile:\n- product[\'upgrade_profiles\'][profile[\'version\']] = profile\n+ elif "version" in profile:\n+ product["upgrade_profiles"][profile["version"]] = profile\n else:\n- product[\'other_profiles\'].append(profile)\n+ product["other_profiles"].append(profile)\n return addons\n \n def get_addons(self, apply_filter=None, product_name=None):\n@@ -462,27 +456,27 @@ def get_addons(self, apply_filter=None, product_name=None):\n """\n addons = self.marshall_addons()\n filtered = {}\n- if apply_filter == \'broken\':\n+ if apply_filter == "broken":\n all_broken = self.errors.values()\n for broken in all_broken:\n- filtered[broken[\'product_id\']] = broken\n+ filtered[broken["product_id"]] = broken\n else:\n for product_id, addon in addons.items():\n- if product_name and addon[\'id\'] != product_name:\n+ if product_name and addon["id"] != product_name:\n continue\n \n- installed = addon[\'is_installed\']\n- if apply_filter in [\'installed\', \'upgrades\'] and not installed:\n+ installed = addon["is_installed"]\n+ if apply_filter in ["installed", "upgrades"] and not installed:\n continue\n- elif apply_filter == \'available\':\n+ elif apply_filter == "available":\n if installed:\n continue\n # filter out upgrade profiles\n- if addon[\'profile_type\'] != \'default\':\n+ if addon["profile_type"] != "default":\n continue\n- elif apply_filter == \'upgrades\':\n- upgrade_info = addon[\'upgrade_info\']\n- if not upgrade_info.get(\'available\'):\n+ elif apply_filter == "upgrades":\n+ upgrade_info = addon["upgrade_info"]\n+ if not upgrade_info.get("available"):\n continue\n \n filtered[product_id] = addon\n@@ -491,22 +485,25 @@ def get_addons(self, apply_filter=None, product_name=None):\n \n def get_sorted_addon_values(self, apply_filter=None, product_name=None):\n values = self.get_addons(apply_filter, product_name).values()\n- return sorted(values, key=lambda x: translate(x.get(\'title\', \'\'), context=self.request).upper())\n+ return sorted(\n+ values,\n+ key=lambda x: translate(x.get("title", ""), context=self.request).upper(),\n+ )\n \n def get_upgrades(self):\n """\n Return a list of products that have upgrades on tap\n """\n- return self.get_sorted_addon_values(apply_filter=\'upgrades\')\n+ return self.get_sorted_addon_values(apply_filter="upgrades")\n \n def get_installed(self):\n- return self.get_sorted_addon_values(apply_filter=\'installed\')\n+ return self.get_sorted_addon_values(apply_filter="installed")\n \n def get_available(self):\n- return self.get_sorted_addon_values(apply_filter=\'available\')\n+ return self.get_sorted_addon_values(apply_filter="available")\n \n def get_broken(self):\n- return self.get_sorted_addon_values(apply_filter=\'broken\')\n+ return self.get_sorted_addon_values(apply_filter="broken")\n \n \n class UpgradeProductsView(InstallerView):\n@@ -515,73 +512,76 @@ class UpgradeProductsView(InstallerView):\n """\n \n def __call__(self):\n- products = self.request.get(\'prefs_reinstallProducts\', None)\n+ products = self.request.get("prefs_reinstallProducts", None)\n if products:\n messages = IStatusMessage(self.request)\n for product_id in products:\n result = self.upgrade_product(product_id)\n if not result:\n messages.addStatusMessage(\n- _(\'Error upgrading ${product}.\',\n- mapping={\'product\': product_id}), type="error")\n+ _(\n+ "Error upgrading ${product}.",\n+ mapping={"product": product_id},\n+ ),\n+ type="error",\n+ )\n # Abort changes for all upgrades.\n transaction.abort()\n break\n else:\n- messages.addStatusMessage(\n- _(\'Upgraded products.\'), type="info")\n+ messages.addStatusMessage(_("Upgraded products."), type="info")\n \n- purl = getToolByName(self.context, \'portal_url\')()\n- self.request.response.redirect(purl + \'/prefs_install_products_form\')\n+ purl = getToolByName(self.context, "portal_url")()\n+ self.request.response.redirect(purl + "/prefs_install_products_form")\n \n \n class InstallProductsView(InstallerView):\n-\n def __call__(self):\n- product_id = self.request.get(\'install_product\')\n+ product_id = self.request.get("install_product")\n if product_id:\n messages = IStatusMessage(self.request)\n- msg_type = \'info\'\n+ msg_type = "info"\n result = self.install_product(product_id)\n if result:\n- msg = _(\'Installed ${product}!\',\n- mapping={\'product\': product_id})\n+ msg = _("Installed ${product}!", mapping={"product": product_id})\n else:\n # Only reason should be that between loading the page and\n # clicking to install a product, another user has already\n # installed this product.\n- msg_type = \'error\'\n- msg = _(\'Failed to install ${product}.\',\n- mapping={\'product\': product_id})\n+ msg_type = "error"\n+ msg = _(\n+ "Failed to install ${product}.", mapping={"product": product_id}\n+ )\n messages.addStatusMessage(msg, type=msg_type)\n \n- purl = getToolByName(self.context, \'portal_url\')()\n- self.request.response.redirect(purl + \'/prefs_install_products_form\')\n+ purl = getToolByName(self.context, "portal_url")()\n+ self.request.response.redirect(purl + "/prefs_install_products_form")\n \n \n class UninstallProductsView(InstallerView):\n-\n def __call__(self):\n- product_id = self.request.get(\'uninstall_product\')\n+ product_id = self.request.get("uninstall_product")\n if product_id:\n messages = IStatusMessage(self.request)\n try:\n result = self.uninstall_product(product_id)\n except Exception as e:\n logger.error("Could not uninstall %s: %s", product_id, e)\n- msg_type = \'error\'\n- msg = _(\'Error uninstalling ${product}.\', mapping={\n- \'product\': product_id})\n+ msg_type = "error"\n+ msg = _(\n+ "Error uninstalling ${product}.", mapping={"product": product_id}\n+ )\n else:\n if result:\n- msg_type = \'info\'\n- msg = _(\'Uninstalled ${product}.\',\n- mapping={\'product\': product_id})\n+ msg_type = "info"\n+ msg = _("Uninstalled ${product}.", mapping={"product": product_id})\n else:\n- msg_type = \'error\'\n- msg = _(\'Could not uninstall ${product}.\',\n- mapping={\'product\': product_id})\n+ msg_type = "error"\n+ msg = _(\n+ "Could not uninstall ${product}.",\n+ mapping={"product": product_id},\n+ )\n messages.addStatusMessage(msg, type=msg_type)\n \n- purl = getToolByName(self.context, \'portal_url\')()\n- self.request.response.redirect(purl + \'/prefs_install_products_form\')\n+ purl = getToolByName(self.context, "portal_url")()\n+ self.request.response.redirect(purl + "/prefs_install_products_form")\ndiff --git a/Products/CMFPlone/controlpanel/browser/redirects.py b/Products/CMFPlone/controlpanel/browser/redirects.py\nindex 7216c4520c..5817ed038d 100644\n--- a/Products/CMFPlone/controlpanel/browser/redirects.py\n+++ b/Products/CMFPlone/controlpanel/browser/redirects.py\n@@ -28,7 +28,7 @@\n filestream_iterator = None\n \n \n-_ = MessageFactory(\'plone\')\n+_ = MessageFactory("plone")\n logger = logging.getLogger(__name__)\n \n \n@@ -56,18 +56,18 @@ def absolutize_path(path, is_source=True):\n err = _("You have to enter an alternative url.")\n else:\n err = _("You have to enter a target.")\n- elif not path.startswith(\'/\'):\n+ elif not path.startswith("/"):\n if is_source:\n err = _("Alternative url path must start with a slash.")\n else:\n # For targets, we accept external urls.\n # Do basic check.\n parsed = urlparse(path)\n- if parsed.scheme in (\'https\', \'http\') and parsed.netloc:\n+ if parsed.scheme in ("https", "http") and parsed.netloc:\n is_external_url = True\n else:\n err = _("Target path must start with a slash.")\n- elif \'@@\' in path:\n+ elif "@@" in path:\n if is_source:\n err = _("Alternative url path must not be a view.")\n else:\n@@ -76,7 +76,7 @@ def absolutize_path(path, is_source=True):\n context_path = "/".join(portal.getPhysicalPath())\n path = f"{context_path}{path}"\n if not err and not is_external_url:\n- catalog = getToolByName(portal, \'portal_catalog\')\n+ catalog = getToolByName(portal, "portal_catalog")\n if is_source:\n # Check whether already exists in storage\n storage = getUtility(IRedirectionStorage)\n@@ -105,13 +105,11 @@ def redirects(self):\n redirects = storage.redirects(context_path)\n for redirect in redirects:\n path = redirect[len(portal_path) :]\n- yield {\'redirect\': redirect, \'path\': path}\n+ yield {"redirect": redirect, "path": path}\n \n def edit_for_navigation_root(self, redirection):\n # Check navigation root\n- pps = getMultiAdapter(\n- (self.context, self.request), name=\'plone_portal_state\'\n- )\n+ pps = getMultiAdapter((self.context, self.request), name="plone_portal_state")\n nav_url = pps.navigation_root_url()\n portal_url = pps.portal_url()\n if nav_url != portal_url:\n@@ -119,7 +117,7 @@ def edit_for_navigation_root(self, redirection):\n # Update the path accordingly, unless the user already did this.\n extra = nav_url[len(portal_url) :]\n if not redirection.startswith(extra):\n- redirection = f\'{extra}{redirection}\'\n+ redirection = f"{extra}{redirection}"\n # Finally, return the (possibly edited) redirection\n return redirection\n \n@@ -130,52 +128,46 @@ def __call__(self):\n status = IStatusMessage(self.request)\n errors = {}\n \n- if \'form.button.Add\' in form:\n- redirection = form.get(\'redirection\')\n- if redirection and redirection.startswith(\'/\'):\n+ if "form.button.Add" in form:\n+ redirection = form.get("redirection")\n+ if redirection and redirection.startswith("/"):\n # Check navigation root\n redirection = self.edit_for_navigation_root(redirection)\n \n redirection, err = absolutize_path(redirection, is_source=True)\n if err:\n- errors[\'redirection\'] = err\n- status.addStatusMessage(err, type=\'error\')\n+ errors["redirection"] = err\n+ status.addStatusMessage(err, type="error")\n else:\n- del form[\'redirection\']\n+ del form["redirection"]\n storage.add(\n redirection,\n "/".join(self.context.getPhysicalPath()),\n manual=True,\n )\n- status.addStatusMessage(\n- _("Alternative url added."), type=\'info\'\n- )\n- elif \'form.button.Remove\' in form:\n- redirects = form.get(\'redirects\', ())\n+ status.addStatusMessage(_("Alternative url added."), type="info")\n+ elif "form.button.Remove" in form:\n+ redirects = form.get("redirects", ())\n for redirect in redirects:\n storage.remove(redirect)\n if len(redirects) > 1:\n- status.addStatusMessage(\n- _("Alternative urls removed."), type=\'info\'\n- )\n+ status.addStatusMessage(_("Alternative urls removed."), type="info")\n else:\n- status.addStatusMessage(\n- _("Alternative url removed."), type=\'info\'\n- )\n+ status.addStatusMessage(_("Alternative url removed."), type="info")\n \n return self.index(errors=errors)\n \n @memoize\n def view_url(self):\n- return self.context.absolute_url() + \'/@@manage-aliases\'\n+ return self.context.absolute_url() + "/@@manage-aliases"\n \n \n class RedirectionSet:\n- def __init__(self, query=\'\', created=\'\', manual=\'\'):\n+ def __init__(self, query="", created="", manual=""):\n self.storage = getUtility(IRedirectionStorage)\n \n portal = getSite()\n- self.portal_path = \'/\'.join(portal.getPhysicalPath())\n+ self.portal_path = "/".join(portal.getPhysicalPath())\n self.portal_path_len = len(self.portal_path)\n \n # noinspection PyProtectedMember\n@@ -184,34 +176,30 @@ def __init__(self, query=\'\', created=\'\', manual=\'\'):\n # min_k is /Plone/news and\n # max_k is /Plone/newt\n # Apparently that is the way to minize the keys we ask.\n- min_k = \'{:s}/{:s}\'.format(self.portal_path, query.strip(\'/\'))\n+ min_k = "{:s}/{:s}".format(self.portal_path, query.strip("/"))\n max_k = min_k[:-1] + chr(ord(min_k[-1]) + 1)\n- self.data = self.storage._paths.keys(\n- min=min_k, max=max_k, excludemax=True\n- )\n+ self.data = self.storage._paths.keys(min=min_k, max=max_k, excludemax=True)\n else:\n self.data = self.storage._paths.keys()\n if manual:\n # either \'yes\' or \'no\', otherwise we ignore the filter\n- if manual == \'yes\':\n+ if manual == "yes":\n manual = True\n- elif manual == \'no\':\n+ elif manual == "no":\n manual = False\n else:\n- manual = \'\'\n+ manual = ""\n if created:\n try:\n created = DateTime(created)\n except DateTimeError:\n- logger.warning(\n- \'Failed to parse as DateTime: %s\', created\n- )\n- created = \'\'\n- if created or manual != \'\':\n+ logger.warning("Failed to parse as DateTime: %s", created)\n+ created = ""\n+ if created or manual != "":\n chosen = []\n for redirect in self.data:\n info = self.storage.get_full(redirect)\n- if manual != \'\':\n+ if manual != "":\n if info[2] != manual:\n continue\n if created and info[1]:\n@@ -235,22 +223,20 @@ def __getitem__(self, item):\n if redirect_to.startswith(self.portal_path):\n redirect_to = redirect_to[self.portal_path_len :]\n return {\n- \'redirect\': redirect,\n- \'path\': path,\n- \'redirect-to\': redirect_to,\n- \'datetime\': info[1],\n- \'manual\': info[2],\n+ "redirect": redirect,\n+ "path": path,\n+ "redirect-to": redirect_to,\n+ "datetime": info[1],\n+ "manual": info[2],\n }\n \n \n class RedirectsBatchView(PloneBatchView):\n def make_link(self, pagenumber=None, omit_params=None):\n if omit_params is None:\n- omit_params = [\'ajax_load\']\n- url = super().make_link(\n- pagenumber, omit_params\n- )\n- return f\'{url:s}#manage-existing-aliases\'\n+ omit_params = ["ajax_load"]\n+ url = super().make_link(pagenumber, omit_params)\n+ return f"{url:s}#manage-existing-aliases"\n \n \n class RedirectsControlPanel(BrowserView):\n@@ -259,21 +245,21 @@ def batching(self):\n \n @memoize\n def redirects(self):\n- """ Get existing redirects from the redirection storage.\n- Return dict with the strings redirect, path and redirect-to.\n- Strip the id of the instance from path and redirect-to if\n- it is present. (Seems to be always true)\n- If id of instance is not present in path the var \'path\' and\n- \'redirect\' are equal.\n+ """Get existing redirects from the redirection storage.\n+ Return dict with the strings redirect, path and redirect-to.\n+ Strip the id of the instance from path and redirect-to if\n+ it is present. (Seems to be always true)\n+ If id of instance is not present in path the var \'path\' and\n+ \'redirect\' are equal.\n """\n return Batch(\n RedirectionSet(\n- query=self.request.form.get(\'q\', \'\'),\n- created=self.request.form.get(\'datetime\', \'\'),\n- manual=self.request.form.get(\'manual\', \'\'),\n+ query=self.request.form.get("q", ""),\n+ created=self.request.form.get("datetime", ""),\n+ manual=self.request.form.get("manual", ""),\n ),\n- int(self.request.form.get(\'b_size\', \'15\')),\n- int(self.request.form.get(\'b_start\', \'0\')),\n+ int(self.request.form.get("b_size", "15")),\n+ int(self.request.form.get("b_start", "0")),\n orphan=1,\n )\n \n@@ -288,17 +274,15 @@ def __call__(self):\n self.csv_errors = []\n self.form_errors = {}\n \n- if \'form.button.Remove\' in form or \'form.button.MatchRemove\' in form:\n- if \'form.button.Remove\' in form:\n- redirects = form.get(\'redirects\', ())\n+ if "form.button.Remove" in form or "form.button.MatchRemove" in form:\n+ if "form.button.Remove" in form:\n+ redirects = form.get("redirects", ())\n else:\n- query = self.request.form.get(\'q\', \'\')\n- created = self.request.form.get(\'datetime\', \'\')\n- manual = self.request.form.get(\'manual\', \'\')\n- if created or manual or (query and query != \'/\'):\n- rset = RedirectionSet(\n- query=query, created=created, manual=manual\n- )\n+ query = self.request.form.get("q", "")\n+ created = self.request.form.get("datetime", "")\n+ manual = self.request.form.get("manual", "")\n+ if created or manual or (query and query != "/"):\n+ rset = RedirectionSet(query=query, created=created, manual=manual)\n redirects = list(rset.data)\n else:\n redirects = []\n@@ -306,31 +290,27 @@ def __call__(self):\n storage.remove(redirect)\n if len(redirects) == 0:\n err = _("No alternative urls selected for removal.")\n- status.addStatusMessage(err, type=\'error\')\n- self.form_errors[\'remove_redirects\'] = err\n+ status.addStatusMessage(err, type="error")\n+ self.form_errors["remove_redirects"] = err\n elif len(redirects) > 1:\n- status.addStatusMessage(\n- _("Alternative urls removed."), type=\'info\'\n- )\n+ status.addStatusMessage(_("Alternative urls removed."), type="info")\n else:\n- status.addStatusMessage(\n- _("Alternative url removed."), type=\'info\'\n- )\n- elif \'form.button.Add\' in form:\n+ status.addStatusMessage(_("Alternative url removed."), type="info")\n+ elif "form.button.Add" in form:\n err = self.add(\n- form[\'redirection\'],\n- form[\'target_path\'],\n+ form["redirection"],\n+ form["target_path"],\n portal,\n storage,\n status,\n )\n if not err:\n # clear our the form\n- del form[\'redirection\']\n- del form[\'target_path\']\n- elif \'form.button.Upload\' in form:\n- self.upload(form[\'file\'], portal, storage, status)\n- elif \'form.button.Download\' in form:\n+ del form["redirection"]\n+ del form["target_path"]\n+ elif "form.button.Upload" in form:\n+ self.upload(form["file"], portal, storage, status)\n+ elif "form.button.Download" in form:\n return self.download()\n \n return self.index()\n@@ -342,10 +322,10 @@ def add(self, redirection, target, portal, storage, status):\n """\n abs_redirection, err = absolutize_path(redirection, is_source=True)\n if err:\n- self.form_errors[\'redirection\'] = err\n+ self.form_errors["redirection"] = err\n abs_target, target_err = absolutize_path(target, is_source=False)\n if target_err:\n- self.form_errors[\'target_path\'] = target_err\n+ self.form_errors["target_path"] = target_err\n \n if err and target_err:\n err = f"{err} {target_err}"\n@@ -360,14 +340,14 @@ def add(self, redirection, target, portal, storage, status):\n # TODO: detect indirect recursion\n \n if err:\n- status.addStatusMessage(_(err), type=\'error\')\n+ status.addStatusMessage(_(err), type="error")\n else:\n storage.add(abs_redirection, abs_target, manual=True)\n status.addStatusMessage(\n _("Alternative url from {0} to {1} added.").format(\n abs_redirection, abs_target\n ),\n- type=\'info\',\n+ type="info",\n )\n return err\n \n@@ -377,13 +357,13 @@ def upload(self, file, portal, storage, status):\n # No file picked. Theres gotta be a better way to handle this.\n if not file.filename:\n err = _("Please pick a file to upload.")\n- status.addStatusMessage(err, type=\'error\')\n- self.form_errors[\'file\'] = err\n+ status.addStatusMessage(err, type="error")\n+ self.form_errors["file"] = err\n return\n # Turn all kinds of newlines into LF ones. The csv module doesn\'t do\n # its own newline sniffing and requires either \\n or \\r.\n contents = safe_text(file.read()).splitlines()\n- file = StringIO(\'\\n\'.join(contents))\n+ file = StringIO("\\n".join(contents))\n \n # Use first two lines as a representative sample for guessing format,\n # in case one is a bunch of headers.\n@@ -406,28 +386,22 @@ def upload(self, file, portal, storage, status):\n try:\n now = DateTime(dt)\n except DateTimeError:\n- logger.warning(\n- \'Failed to parse as DateTime: %s\', dt\n- )\n+ logger.warning("Failed to parse as DateTime: %s", dt)\n now = None\n if len(fields) >= 4:\n manual = fields[3].lower()\n # Compare first character with false, no, 0.\n- if manual and manual[0] in \'fn0\':\n+ if manual and manual[0] in "fn0":\n manual = False\n else:\n manual = True\n- abs_redirection, err = absolutize_path(\n- redirection, is_source=True\n- )\n- abs_target, target_err = absolutize_path(\n- target, is_source=False\n- )\n+ abs_redirection, err = absolutize_path(redirection, is_source=True)\n+ abs_target, target_err = absolutize_path(target, is_source=False)\n if err and target_err:\n if (\n i == 0\n- and not redirection.startswith(\'/\')\n- and not target.startswith(\'/\')\n+ and not redirection.startswith("/")\n+ and not target.startswith("/")\n ):\n # First line is a header. Ignore this.\n continue\n@@ -462,20 +436,20 @@ def upload(self, file, portal, storage, status):\n status.addStatusMessage(\n _(\n "${count} alternative urls added.",\n- mapping={\'count\': len(successes)},\n+ mapping={"count": len(successes)},\n ),\n- type=\'info\',\n+ type="info",\n )\n else:\n self.csv_errors.insert(\n 0,\n dict(\n line_number=0,\n- line=\'\',\n+ line="",\n message=_(\n- \'msg_delimiter\',\n+ "msg_delimiter",\n default="Delimiter detected: ${delimiter}",\n- mapping={\'delimiter\': dialect.delimiter},\n+ mapping={"delimiter": dialect.delimiter},\n ),\n ),\n )\n@@ -490,11 +464,11 @@ def download(self):\n portal_path = "/".join(portal.getPhysicalPath())\n len_portal_path = len(portal_path)\n file_descriptor, file_path = tempfile.mkstemp(\n- suffix=\'.csv\', prefix=\'redirects_\'\n+ suffix=".csv", prefix="redirects_"\n )\n- with open(file_path, \'w\') as stream:\n+ with open(file_path, "w") as stream:\n csv_writer = writer(stream)\n- csv_writer.writerow((\'old path\', \'new path\', \'datetime\', \'manual\'))\n+ csv_writer.writerow(("old path", "new path", "datetime", "manual"))\n storage = getUtility(IRedirectionStorage)\n paths = storage._paths\n # Note that the old and new paths start with /plone-site-id.\n@@ -517,18 +491,16 @@ def download(self):\n length = len(contents)\n \n response = self.request.response\n- response.setHeader(\'Content-Type\', \'text/csv\')\n- response.setHeader(\'Content-Length\', length)\n- response.setHeader(\n- \'Content-Disposition\', \'attachment; filename=redirects.csv\'\n- )\n+ response.setHeader("Content-Type", "text/csv")\n+ response.setHeader("Content-Length", length)\n+ response.setHeader("Content-Disposition", "attachment; filename=redirects.csv")\n if filestream_iterator is None:\n return contents\n # TODO: this is not enough to really stream the file.\n # I think we would need to handle Request-Range, like in the old\n # plone.app.blob.download.handleRequestRange\n- return filestream_iterator(file_path, \'rb\')\n+ return filestream_iterator(file_path, "rb")\n \n @memoize\n def view_url(self):\n- return self.context.absolute_url() + \'/@@redirection-controlpanel\'\n+ return self.context.absolute_url() + "/@@redirection-controlpanel"\ndiff --git a/Products/CMFPlone/controlpanel/browser/relations.py b/Products/CMFPlone/controlpanel/browser/relations.py\nindex 843623f4aa..1cbf677b02 100644\n--- a/Products/CMFPlone/controlpanel/browser/relations.py\n+++ b/Products/CMFPlone/controlpanel/browser/relations.py\n@@ -20,38 +20,40 @@\n \n \n class RelationsRebuildControlpanel(BrowserView):\n-\n def __call__(self, rebuild=False, flush_and_rebuild_intids=False):\n self.done = False\n if rebuild:\n rebuild_relations(flush_and_rebuild_intids=flush_and_rebuild_intids)\n self.done = True\n IStatusMessage(self.request).addStatusMessage(\n- _(\'Finished! See log for details.\'), \'info\')\n+ _("Finished! See log for details."), "info"\n+ )\n \n self.relations_stats, self.broken = get_relations_stats()\n return self.index()\n \n \n class RelationsInspectControlpanel(BrowserView):\n-\n def __call__(self, relation=None, inspect_backrelation=False):\n- self.relation = relation or self.request.get(\'relation\')\n- self.inspect_backrelation = inspect_backrelation or self.request.get(\'inspect_backrelation\')\n+ self.relation = relation or self.request.get("relation")\n+ self.inspect_backrelation = inspect_backrelation or self.request.get(\n+ "inspect_backrelation"\n+ )\n \n self.relations = []\n self.relations_stats, self.broken = get_relations_stats()\n registry = getUtility(IRegistry)\n- view_action = registry[\'plone.types_use_view_action_in_listings\']\n+ view_action = registry["plone.types_use_view_action_in_listings"]\n \n if not self.relation:\n IStatusMessage(self.request).addStatusMessage(\n- _(\'Please select a relation\'), \'info\')\n+ _("Please select a relation"), "info"\n+ )\n return self.index()\n \n intids = queryUtility(IIntIds)\n relation_catalog = getUtility(ICatalog)\n- query = {\'from_attribute\': self.relation}\n+ query = {"from_attribute": self.relation}\n info = defaultdict(list)\n \n # relations: column_1 = source, column_2 = target(s)\n@@ -60,8 +62,8 @@ def __call__(self, relation=None, inspect_backrelation=False):\n if rel.isBroken():\n continue\n try:\n- hasattr(rel, \'from_id\')\n- hasattr(rel, \'to_id\')\n+ hasattr(rel, "from_id")\n+ hasattr(rel, "to_id")\n except IntIdMissingError:\n continue\n if self.inspect_backrelation:\n@@ -72,23 +74,31 @@ def __call__(self, relation=None, inspect_backrelation=False):\n for column_1_intid in info:\n obj = intids.getObject(column_1_intid)\n use_view_action = obj.portal_type in view_action\n- url = obj.absolute_url() + \'/view\' if use_view_action else obj.absolute_url()\n+ url = (\n+ obj.absolute_url() + "/view" if use_view_action else obj.absolute_url()\n+ )\n item = {}\n- item[\'column_1\'] = {\n- \'title\': obj.title_or_id(),\n- \'url\': url,\n- \'portal_type\': obj.portal_type,\n+ item["column_1"] = {\n+ "title": obj.title_or_id(),\n+ "url": url,\n+ "portal_type": obj.portal_type,\n }\n- item[\'column_2\'] = []\n+ item["column_2"] = []\n for column_2_intid in info[column_1_intid]:\n obj = intids.getObject(column_2_intid)\n use_view_action = obj.portal_type in view_action\n- url = obj.absolute_url() + \'/view\' if use_view_action else obj.absolute_url()\n- item[\'column_2\'].append({\n- \'title\': obj.title_or_id(),\n- \'url\': url,\n- \'portal_type\': obj.portal_type,\n- })\n+ url = (\n+ obj.absolute_url() + "/view"\n+ if use_view_action\n+ else obj.absolute_url()\n+ )\n+ item["column_2"].append(\n+ {\n+ "title": obj.title_or_id(),\n+ "url": url,\n+ "portal_type": obj.portal_type,\n+ }\n+ )\n self.relations.append(item)\n- self.relations.sort(key=lambda x: x[\'column_1\'][\'title\'])\n+ self.relations.sort(key=lambda x: x["column_1"]["title"])\n return self.index()\ndiff --git a/Products/CMFPlone/controlpanel/browser/resourceregistry.py b/Products/CMFPlone/controlpanel/browser/resourceregistry.py\nindex 4277e9d221..9cca60a22f 100644\n--- a/Products/CMFPlone/controlpanel/browser/resourceregistry.py\n+++ b/Products/CMFPlone/controlpanel/browser/resourceregistry.py\n@@ -94,7 +94,11 @@ def _update(self):\n return\n if new_name in bundles:\n IStatusMessage(self.request).addStatusMessage(\n- _("Record name ${new_name} already taken.", mapping=dict(new_name=new_name)), "error"\n+ _(\n+ "Record name ${new_name} already taken.",\n+ mapping=dict(new_name=new_name),\n+ ),\n+ "error",\n )\n return\n record = bundles[original_name]\ndiff --git a/Products/CMFPlone/controlpanel/browser/search.py b/Products/CMFPlone/controlpanel/browser/search.py\nindex 063e893c18..d87c285463 100644\n--- a/Products/CMFPlone/controlpanel/browser/search.py\n+++ b/Products/CMFPlone/controlpanel/browser/search.py\n@@ -7,7 +7,6 @@\n \n \n class SearchControlPanelForm(controlpanel.RegistryEditForm):\n-\n id = "SearchControlPanel"\n label = _("Search Settings")\n schema = ISearchSchema\n@@ -15,35 +14,38 @@ class SearchControlPanelForm(controlpanel.RegistryEditForm):\n \n def updateFields(self):\n super().updateFields()\n- self.fields[\'types_not_searched\'].widgetFactory = \\\n- CheckBoxFieldWidget\n+ self.fields["types_not_searched"].widgetFactory = CheckBoxFieldWidget\n \n def updateWidgets(self):\n super().updateWidgets()\n # Replace vocabulary for \'types_not_searched\' with user friendly types\n # to hide "bad" types in control panel.\n vocab = self._friendly_types_vocabulary()\n- self.widgets[\'types_not_searched\'].terms.terms = vocab(self.context)\n- self.widgets[\'types_not_searched\'].update()\n+ self.widgets["types_not_searched"].terms.terms = vocab(self.context)\n+ self.widgets["types_not_searched"].update()\n \n def applyChanges(self, data):\n # We only get "friendly" types. Add "bad" types from current settings.\n- current_types = self.fields[\'types_not_searched\'].field.get(\n- self.getContent())\n- all_vocab = queryUtility(IVocabularyFactory,\n- \'plone.app.vocabularies.PortalTypes\')\n+ current_types = self.fields["types_not_searched"].field.get(self.getContent())\n+ all_vocab = queryUtility(\n+ IVocabularyFactory, "plone.app.vocabularies.PortalTypes"\n+ )\n all_types = [t.value for t in all_vocab(self.context)]\n friendly_vocab = self._friendly_types_vocabulary()\n friendly_types = [t.value for t in friendly_vocab(self.context)]\n- submitted_types = data[\'types_not_searched\'] or []\n- new_types = [t for t in all_types if t in submitted_types\n- or (t in current_types and t not in friendly_types)]\n- data[\'types_not_searched\'] = tuple(new_types)\n+ submitted_types = data["types_not_searched"] or []\n+ new_types = [\n+ t\n+ for t in all_types\n+ if t in submitted_types or (t in current_types and t not in friendly_types)\n+ ]\n+ data["types_not_searched"] = tuple(new_types)\n super().applyChanges(data)\n \n def _friendly_types_vocabulary(self):\n- return queryUtility(IVocabularyFactory,\n- \'plone.app.vocabularies.ReallyUserFriendlyTypes\')\n+ return queryUtility(\n+ IVocabularyFactory, "plone.app.vocabularies.ReallyUserFriendlyTypes"\n+ )\n \n \n class SearchControlPanel(controlpanel.ControlPanelFormWrapper):\ndiff --git a/Products/CMFPlone/controlpanel/browser/security.py b/Products/CMFPlone/controlpanel/browser/security.py\nindex 170457ef2c..5a2241346e 100644\n--- a/Products/CMFPlone/controlpanel/browser/security.py\n+++ b/Products/CMFPlone/controlpanel/browser/security.py\n@@ -11,11 +11,10 @@\n import logging\n \n \n-logger = logging.getLogger(\'Products.CMFPlone\')\n+logger = logging.getLogger("Products.CMFPlone")\n \n \n class SecurityControlPanelForm(controlpanel.RegistryEditForm):\n-\n id = "SecurityControlPanel"\n label = _("Security Settings")\n schema = ISecuritySchema\n@@ -37,33 +36,32 @@ class EmailLogin(BrowserView):\n duplicates = []\n \n def __call__(self):\n- if self.request.form.get(\'check_email\'):\n+ if self.request.form.get("check_email"):\n self.duplicates = self.check_email()\n- elif self.request.form.get(\'check_userid\'):\n+ elif self.request.form.get("check_userid"):\n self.duplicates = self.check_userid()\n return self.index()\n \n @property\n def _email_list(self):\n context = aq_inner(self.context)\n- pas = getToolByName(context, \'acl_users\')\n+ pas = getToolByName(context, "acl_users")\n emails = defaultdict(list)\n orig_transform = pas.login_transform\n try:\n if not orig_transform:\n # Temporarily set this to lower, as that will happen\n # when turning emaillogin on.\n- pas.login_transform = \'lower\'\n+ pas.login_transform = "lower"\n for user in pas.getUsers():\n if user is None:\n # Created in the ZMI?\n continue\n- email = user.getProperty(\'email\', \'\')\n+ email = user.getProperty("email", "")\n if email:\n email = pas.applyTransform(email)\n else:\n- logger.warning("User %s has no email address.",\n- user.getUserId())\n+ logger.warning("User %s has no email address.", user.getUserId())\n # Add the normal login name anyway.\n email = pas.applyTransform(user.getUserName())\n emails[email].append(user.getUserId())\n@@ -75,8 +73,9 @@ def check_email(self):\n duplicates = []\n for email, userids in self._email_list.items():\n if len(userids) > 1:\n- logger.warning("Duplicate accounts for email address %s: %r",\n- email, userids)\n+ logger.warning(\n+ "Duplicate accounts for email address %s: %r", email, userids\n+ )\n duplicates.append((email, userids))\n \n return duplicates\n@@ -86,14 +85,14 @@ def _userid_list(self):\n # user ids are unique, but their lowercase version might not\n # be unique.\n context = aq_inner(self.context)\n- pas = getToolByName(context, \'acl_users\')\n+ pas = getToolByName(context, "acl_users")\n userids = defaultdict(list)\n orig_transform = pas.login_transform\n try:\n if not orig_transform:\n # Temporarily set this to lower, as that will happen\n # when turning emaillogin on.\n- pas.login_transform = \'lower\'\n+ pas.login_transform = "lower"\n for user in pas.getUsers():\n if user is None:\n continue\n@@ -107,8 +106,11 @@ def check_userid(self):\n duplicates = []\n for login_name, userids in self._userid_list.items():\n if len(userids) > 1:\n- logger.warning("Duplicate accounts for lower case user id "\n- "%s: %r", login_name, userids)\n+ logger.warning(\n+ "Duplicate accounts for lower case user id " "%s: %r",\n+ login_name,\n+ userids,\n+ )\n duplicates.append((login_name, userids))\n \n return duplicates\ndiff --git a/Products/CMFPlone/controlpanel/browser/site.py b/Products/CMFPlone/controlpanel/browser/site.py\nindex 0d17b21558..f5f1bc0c21 100644\n--- a/Products/CMFPlone/controlpanel/browser/site.py\n+++ b/Products/CMFPlone/controlpanel/browser/site.py\n@@ -6,7 +6,6 @@\n \n \n class SiteControlPanelForm(controlpanel.RegistryEditForm):\n-\n id = "SiteControlPanel"\n label = _("Site Settings")\n description = _("Site-wide settings.")\n@@ -15,13 +14,13 @@ class SiteControlPanelForm(controlpanel.RegistryEditForm):\n \n def updateFields(self):\n super().updateFields()\n- self.fields[\'site_logo\'].widgetFactory = NamedImageFieldWidget\n- self.fields[\'site_favicon\'].widgetFactory = NamedImageFieldWidget\n+ self.fields["site_logo"].widgetFactory = NamedImageFieldWidget\n+ self.fields["site_favicon"].widgetFactory = NamedImageFieldWidget\n \n def updateWidgets(self):\n super().updateWidgets()\n # hide the default_page field/widgets\n- self.widgets[\'default_page\'].mode = interfaces.HIDDEN_MODE\n+ self.widgets["default_page"].mode = interfaces.HIDDEN_MODE\n \n \n class SiteControlPanel(controlpanel.ControlPanelFormWrapper):\ndiff --git a/Products/CMFPlone/controlpanel/browser/socialmedia.py b/Products/CMFPlone/controlpanel/browser/socialmedia.py\nindex 6cdb1ef2ed..aed9800f74 100644\n--- a/Products/CMFPlone/controlpanel/browser/socialmedia.py\n+++ b/Products/CMFPlone/controlpanel/browser/socialmedia.py\n@@ -4,7 +4,6 @@\n \n \n class SocialControlPanelForm(controlpanel.RegistryEditForm):\n-\n id = "SocialControlPanel"\n label = _("Social Media Settings")\n description = _("Social media sharing settings.")\ndiff --git a/Products/CMFPlone/controlpanel/browser/syndication.py b/Products/CMFPlone/controlpanel/browser/syndication.py\nindex 452ec185da..a34305772e 100644\n--- a/Products/CMFPlone/controlpanel/browser/syndication.py\n+++ b/Products/CMFPlone/controlpanel/browser/syndication.py\n@@ -7,45 +7,47 @@\n from zope.i18nmessageid import MessageFactory\n \n \n-_ = MessageFactory(\'plone\')\n+_ = MessageFactory("plone")\n \n \n class SyndicationControlPanelForm(controlpanel.RegistryEditForm):\n schema = ISiteSyndicationSettings\n- label = _(\'Syndication Settings\')\n- description = _(\'Default syndication settings.\')\n+ label = _("Syndication Settings")\n+ description = _("Default syndication settings.")\n \n def updateFields(self):\n super().updateFields()\n- self.fields[\'site_rss_items\'].widgetFactory = SelectFieldWidget\n+ self.fields["site_rss_items"].widgetFactory = SelectFieldWidget\n \n def getSyndicationSettingsButtonShown(self):\n- actions = getToolByName(self.context, \'portal_actions\')\n- if \'syndication\' in actions.object.objectIds():\n- return actions.object.syndication.getProperty(\'visible\')\n+ actions = getToolByName(self.context, "portal_actions")\n+ if "syndication" in actions.object.objectIds():\n+ return actions.object.syndication.getProperty("visible")\n else:\n IStatusMessage(self.request).addStatusMessage(\n- _("Missing syndication settings action."), "warn")\n+ _("Missing syndication settings action."), "warn"\n+ )\n \n def getSyndicationLinkShown(self):\n- actions = getToolByName(self.context, \'portal_actions\')\n- if \'rss\' in actions.document_actions.objectIds():\n- return actions.document_actions.rss.getProperty(\'visible\')\n+ actions = getToolByName(self.context, "portal_actions")\n+ if "rss" in actions.document_actions.objectIds():\n+ return actions.document_actions.rss.getProperty("visible")\n else:\n IStatusMessage(self.request).addStatusMessage(\n- _("Missing rss link action."), "warn")\n+ _("Missing rss link action."), "warn"\n+ )\n \n def forceCheckboxValue(self, widget, checked):\n if checked:\n- widget.value = [\'selected\']\n+ widget.value = ["selected"]\n else:\n widget.value = []\n for item in widget.items:\n- if \'checked\' in item:\n+ if "checked" in item:\n if checked:\n- item[\'checked\'] = True\n+ item["checked"] = True\n else:\n- item[\'checked\'] = False\n+ item["checked"] = False\n \n def update(self):\n super().update()\n@@ -56,22 +58,26 @@ def update(self):\n show_settings_btn = self.getSyndicationSettingsButtonShown()\n if show_settings_btn != content.show_syndication_button:\n self.forceCheckboxValue(\n- self.widgets[\'show_syndication_button\'], show_settings_btn)\n+ self.widgets["show_syndication_button"], show_settings_btn\n+ )\n show_link_btn = self.getSyndicationLinkShown()\n if show_link_btn != content.show_syndication_link:\n self.forceCheckboxValue(\n- self.widgets[\'show_syndication_link\'], show_link_btn)\n+ self.widgets["show_syndication_link"], show_link_btn\n+ )\n \n def setSyndicationActionSettings(self, data):\n- actions = getToolByName(self.context, \'portal_actions\')\n- if \'syndication\' in actions.object.objectIds():\n+ actions = getToolByName(self.context, "portal_actions")\n+ if "syndication" in actions.object.objectIds():\n actions.object.syndication._setPropValue(\n- \'visible\', data[\'show_syndication_button\'])\n- if \'rss\' in actions.document_actions.objectIds():\n+ "visible", data["show_syndication_button"]\n+ )\n+ if "rss" in actions.document_actions.objectIds():\n actions.document_actions.rss._setPropValue(\n- \'visible\', data[\'show_syndication_link\'])\n+ "visible", data["show_syndication_link"]\n+ )\n \n- @button.buttonAndHandler(_("Save"), name=\'save\')\n+ @button.buttonAndHandler(_("Save"), name="save")\n def handleSave(self, action):\n """\n Again, we\'re customizing this to handle saving\n@@ -84,14 +90,12 @@ def handleSave(self, action):\n \n self.setSyndicationActionSettings(data)\n self.applyChanges(data)\n- IStatusMessage(self.request).addStatusMessage(\n- _("Changes saved."), "info")\n+ IStatusMessage(self.request).addStatusMessage(_("Changes saved."), "info")\n self.request.response.redirect(self.request.getURL())\n \n- @button.buttonAndHandler(_("Cancel"), name=\'cancel\')\n+ @button.buttonAndHandler(_("Cancel"), name="cancel")\n def handleCancel(self, action):\n- IStatusMessage(self.request).addStatusMessage(\n- _("Edit cancelled."), "info")\n+ IStatusMessage(self.request).addStatusMessage(_("Edit cancelled."), "info")\n self.request.response.redirect(self.request.getURL())\n \n \ndiff --git a/Products/CMFPlone/controlpanel/browser/tinymce.py b/Products/CMFPlone/controlpanel/browser/tinymce.py\nindex b286e71464..a7cd3e97ee 100644\n--- a/Products/CMFPlone/controlpanel/browser/tinymce.py\n+++ b/Products/CMFPlone/controlpanel/browser/tinymce.py\n@@ -32,18 +32,21 @@ class TinyMCEAdvancedForm(group.GroupForm):\n \n \n class TinyMCEControlPanelForm(controlpanel.RegistryEditForm):\n-\n id = "TinyMCEControlPanel"\n label = _("TinyMCE Settings")\n schema = ITinyMCESchema\n schema_prefix = "plone"\n fields = field.Fields(ITinyMCELayoutSchema)\n- groups = (TinyMCEPluginForm, TinyMCESpellCheckerForm,\n- TinyMCEResourceTypesForm, TinyMCEAdvancedForm)\n+ groups = (\n+ TinyMCEPluginForm,\n+ TinyMCESpellCheckerForm,\n+ TinyMCEResourceTypesForm,\n+ TinyMCEAdvancedForm,\n+ )\n \n def updateFields(self):\n super().updateFields()\n- self.groups[0].fields[\'plugins\'].widgetFactory = CheckBoxFieldWidget\n+ self.groups[0].fields["plugins"].widgetFactory = CheckBoxFieldWidget\n \n \n class TinyMCEControlPanel(controlpanel.ControlPanelFormWrapper):\ndiff --git a/Products/CMFPlone/controlpanel/browser/types.py b/Products/CMFPlone/controlpanel/browser/types.py\nindex b98fe6c347..c992fbc1ec 100644\n--- a/Products/CMFPlone/controlpanel/browser/types.py\n+++ b/Products/CMFPlone/controlpanel/browser/types.py\n@@ -23,26 +23,23 @@\n \n def format_description(text, request=None):\n # We expect the workflow to be a text of \'- \' divided bullet points.\n- text = translate(text.strip(), domain=\'plone\', context=request)\n- return [s.strip() for s in text.split(\'- \') if s]\n+ text = translate(text.strip(), domain="plone", context=request)\n+ return [s.strip() for s in text.split("- ") if s]\n \n \n # These are convenient / user friendly versioning policies.\n VERSION_POLICIES = [\n- dict(id="off",\n- policy=(),\n- title=_("versioning_off",\n- default="No versioning")),\n-\n- dict(id="manual",\n- policy=("version_on_revert",),\n- title=_("versioning_manual",\n- default="Manual")),\n-\n- dict(id="automatic",\n- policy=("at_edit_autoversion", "version_on_revert"),\n- title=_("versioning_automatic",\n- default="Automatic")),\n+ dict(id="off", policy=(), title=_("versioning_off", default="No versioning")),\n+ dict(\n+ id="manual",\n+ policy=("version_on_revert",),\n+ title=_("versioning_manual", default="Manual"),\n+ ),\n+ dict(\n+ id="automatic",\n+ policy=("at_edit_autoversion", "version_on_revert"),\n+ title=_("versioning_automatic", default="Automatic"),\n+ ),\n ]\n \n \n@@ -53,38 +50,36 @@ class TypesControlPanel(AutoExtensibleForm, form.EditForm):\n description = _("General types settings.")\n form_name = _("Types settings")\n control_panel_view = "content-controlpanel"\n- template = ViewPageTemplateFile(\'types.pt\')\n- behavior_name = \'plone.versioning\'\n+ template = ViewPageTemplateFile("types.pt")\n+ behavior_name = "plone.versioning"\n \n- @button.buttonAndHandler(_(\'Save\'), name=\'save\')\n+ @button.buttonAndHandler(_("Save"), name="save")\n def handleSave(self, action):\n data, errors = self.extractData()\n if errors:\n self.status = self.formErrorsMessage\n return\n- IStatusMessage(self.request).addStatusMessage(\n- _("Changes saved"), "info")\n+ IStatusMessage(self.request).addStatusMessage(_("Changes saved"), "info")\n self.request.response.redirect("@@content-controlpanel")\n \n- @button.buttonAndHandler(_("Cancel"), name=\'cancel\')\n+ @button.buttonAndHandler(_("Cancel"), name="cancel")\n def handleCancel(self, action):\n- IStatusMessage(self.request).addStatusMessage(\n- _("Changes canceled."), "info")\n+ IStatusMessage(self.request).addStatusMessage(_("Changes canceled."), "info")\n self.request.response.redirect("@@overview-controlpanel")\n \n @property\n @memoize\n def type_id(self):\n- type_id = self.request.get(\'type_id\', None)\n+ type_id = self.request.get("type_id", None)\n if type_id is None:\n- type_id = \'\'\n+ type_id = ""\n return type_id\n \n @property\n @memoize\n def fti(self):\n type_id = self.type_id\n- portal_types = getToolByName(self.context, \'portal_types\')\n+ portal_types = getToolByName(self.context, "portal_types")\n return getattr(portal_types, type_id)\n \n def add_versioning_behavior(self, fti):\n@@ -94,7 +89,7 @@ def add_versioning_behavior(self, fti):\n if self.behavior_name not in behaviors:\n behaviors.append(self.behavior_name)\n # locking must be turned on for versioning support on the type\n- locking = \'plone.locking\'\n+ locking = "plone.locking"\n if locking not in behaviors:\n behaviors.append(locking)\n \n@@ -110,40 +105,37 @@ def remove_versioning_behavior(self, fti):\n fti.behaviors = behaviors\n \n def __call__(self):\n- """Perform the update and redirect if necessary, or render the page\n- """\n+ """Perform the update and redirect if necessary, or render the page"""\n postback = True\n context = aq_inner(self.context)\n \n form = self.request.form\n- submitted = form.get(\'form.submitted\', False)\n- save_button = form.get(\'form.button.Save\', None) is not None\n- cancel_button = form.get(\'form.button.Cancel\', None) is not None\n- type_id = form.get(\'old_type_id\', None)\n+ submitted = form.get("form.submitted", False)\n+ save_button = form.get("form.button.Save", None) is not None\n+ cancel_button = form.get("form.button.Cancel", None) is not None\n+ type_id = form.get("old_type_id", None)\n \n if save_button and submitted and not cancel_button:\n if type_id:\n- portal_types = getToolByName(self.context, \'portal_types\')\n- portal_repository = getToolByName(self.context,\n- \'portal_repository\')\n+ portal_types = getToolByName(self.context, "portal_types")\n+ portal_repository = getToolByName(self.context, "portal_repository")\n \n fti = getattr(portal_types, type_id)\n \n # Set FTI properties\n \n- addable = form.get(\'addable\', False)\n- allow_discussion = form.get(\'allow_discussion\', False)\n+ addable = form.get("addable", False)\n+ allow_discussion = form.get("allow_discussion", False)\n \n fti.manage_changeProperties(\n- global_allow=bool(addable),\n- allow_discussion=bool(allow_discussion)\n+ global_allow=bool(addable), allow_discussion=bool(allow_discussion)\n )\n \n- version_policy = form.get(\'versionpolicy\', "off")\n+ version_policy = form.get("versionpolicy", "off")\n if version_policy != self.current_versioning_policy():\n newpolicy = [\n- p for p in VERSION_POLICIES\n- if p["id"] == version_policy][0]\n+ p for p in VERSION_POLICIES if p["id"] == version_policy\n+ ][0]\n \n versionable_types = list(\n portal_repository.getVersionableContentTypes()\n@@ -163,25 +155,20 @@ def __call__(self):\n policy_id = policy.getId()\n if policy_id in newpolicy["policy"]:\n portal_repository.addPolicyForContentType(\n- type_id,\n- policy_id\n+ type_id, policy_id\n )\n else:\n portal_repository.removePolicyFromContentType(\n- type_id,\n- policy_id\n+ type_id, policy_id\n )\n \n- portal_repository.setVersionableContentTypes(\n- versionable_types\n- )\n+ portal_repository.setVersionableContentTypes(versionable_types)\n \n # Set Registry-entries\n registry = getUtility(IRegistry)\n \n- searchable = form.get(\'searchable\', False)\n- site_settings = registry.forInterface(\n- ISearchSchema, prefix="plone")\n+ searchable = form.get("searchable", False)\n+ site_settings = registry.forInterface(ISearchSchema, prefix="plone")\n blacklisted = [i for i in site_settings.types_not_searched]\n if searchable and type_id in blacklisted:\n blacklisted.remove(type_id)\n@@ -189,88 +176,86 @@ def __call__(self):\n blacklisted.append(type_id)\n site_settings.types_not_searched = tuple(blacklisted)\n \n- default_page_type = form.get(\'default_page_type\', False)\n- types_settings = registry.forInterface(\n- ITypesSchema, prefix="plone")\n+ default_page_type = form.get("default_page_type", False)\n+ types_settings = registry.forInterface(ITypesSchema, prefix="plone")\n default_page_types = [\n- safe_text(i) for i in types_settings.default_page_types]\n+ safe_text(i) for i in types_settings.default_page_types\n+ ]\n if default_page_type and type_id not in default_page_types:\n default_page_types.append(safe_text(type_id))\n elif not default_page_type and type_id in default_page_types:\n default_page_types.remove(type_id)\n types_settings.default_page_types = default_page_types\n- if type_id == \'Link\':\n- redirect_links = form.get(\'redirect_links\', False)\n+ if type_id == "Link":\n+ redirect_links = form.get("redirect_links", False)\n types_settings.redirect_links = redirect_links\n \n # Update workflow\n- if self.have_new_workflow() \\\n- and form.get(\'form.workflow.submitted\', False) \\\n- and save_button:\n+ if (\n+ self.have_new_workflow()\n+ and form.get("form.workflow.submitted", False)\n+ and save_button\n+ ):\n if self.new_workflow_is_different():\n new_wf = self.new_workflow()\n- if new_wf == \'[none]\':\n+ if new_wf == "[none]":\n chain = ()\n- elif new_wf == \'(Default)\':\n+ elif new_wf == "(Default)":\n chain = new_wf\n else:\n chain = (new_wf,)\n state_map = {\n- s[\'old_state\']: s[\'new_state\']\n- for s in form.get(\'new_wfstates\', [])\n+ s["old_state"]: s["new_state"]\n+ for s in form.get("new_wfstates", [])\n }\n- if \'[none]\' in state_map:\n- state_map[None] = state_map[\'[none]\']\n- del state_map[\'[none]\']\n+ if "[none]" in state_map:\n+ state_map[None] = state_map["[none]"]\n+ del state_map["[none]"]\n if type_id:\n type_ids = (type_id,)\n else:\n- wt = getToolByName(self.context, \'portal_workflow\')\n- tt = getToolByName(self.context, \'portal_types\')\n- nondefault = [\n- info[0] for info in wt.listChainOverrides()\n- ]\n+ wt = getToolByName(self.context, "portal_workflow")\n+ tt = getToolByName(self.context, "portal_types")\n+ nondefault = [info[0] for info in wt.listChainOverrides()]\n type_ids = [\n- type for type in tt.listContentTypes()\n+ type\n+ for type in tt.listContentTypes()\n if type not in nondefault\n ]\n- wt.setChainForPortalTypes(\n- type_ids,\n- wt.getDefaultChain()\n- )\n- wt.setDefaultChain(\',\'.join(chain))\n- chain = \'(Default)\'\n+ wt.setChainForPortalTypes(type_ids, wt.getDefaultChain())\n+ wt.setDefaultChain(",".join(chain))\n+ chain = "(Default)"\n \n- remap_workflow(context, type_ids=type_ids, chain=chain,\n- state_map=state_map)\n+ remap_workflow(\n+ context, type_ids=type_ids, chain=chain, state_map=state_map\n+ )\n \n- data = {\'workflow\': new_wf}\n+ data = {"workflow": new_wf}\n notify(ConfigurationChangedEvent(self, data))\n \n else:\n- portal_workflow = getToolByName(context, \'portal_workflow\')\n- if self.new_workflow() == \'(Default)\':\n+ portal_workflow = getToolByName(context, "portal_workflow")\n+ if self.new_workflow() == "(Default)":\n # The WorkflowTool API can not handle this sanely\n cbt = portal_workflow._chains_by_type\n if type_id in cbt:\n del cbt[type_id]\n else:\n portal_workflow.setChainForPortalTypes(\n- (type_id,),\n- self.new_workflow()\n+ (type_id,), self.new_workflow()\n )\n \n self.request.response.redirect(\n- \'{}/@@content-controlpanel?type_id={}\'.format(\n- context.absolute_url(),\n- type_id\n+ "{}/@@content-controlpanel?type_id={}".format(\n+ context.absolute_url(), type_id\n )\n )\n postback = False\n \n elif cancel_button:\n self.request.response.redirect(\n- self.context.absolute_url() + \'/@@overview-controlpanel\')\n+ self.context.absolute_url() + "/@@overview-controlpanel"\n+ )\n postback = False\n \n if postback:\n@@ -284,22 +269,17 @@ def versioning_policies(self):\n @memoize\n def selectable_types(self):\n vocab_factory = getUtility(\n- IVocabularyFactory,\n- name="plone.app.vocabularies.ReallyUserFriendlyTypes"\n+ IVocabularyFactory, name="plone.app.vocabularies.ReallyUserFriendlyTypes"\n )\n types = []\n for v in vocab_factory(self.context):\n if v.title:\n title = translate(v.title, context=self.request)\n else:\n- title = translate(\n- v.token,\n- domain=\'plone\',\n- context=self.request\n- )\n+ title = translate(v.token, domain="plone", context=self.request)\n types.append(dict(id=v.value, title=title))\n \n- types.sort(key=itemgetter(\'title\'))\n+ types.sort(key=itemgetter("title"))\n return types\n \n def selected_type_title(self):\n@@ -309,13 +289,13 @@ def selected_type_description(self):\n return self.fti.Description()\n \n def is_addable(self):\n- return self.fti.getProperty(\'global_allow\', False)\n+ return self.fti.getProperty("global_allow", False)\n \n def is_discussion_allowed(self):\n- return self.fti.getProperty(\'allow_discussion\', False)\n+ return self.fti.getProperty("allow_discussion", False)\n \n def current_versioning_policy(self):\n- portal_repository = getToolByName(self.context, \'portal_repository\')\n+ portal_repository = getToolByName(self.context, "portal_repository")\n if self.type_id not in portal_repository.getVersionableContentTypes():\n return "off"\n policy = set(portal_repository.getPolicyMap().get(self.type_id, ()))\n@@ -328,7 +308,7 @@ def is_searchable(self):\n registry = getUtility(IRegistry)\n settings = registry.forInterface(ISearchSchema, prefix="plone")\n blacklisted = settings.types_not_searched\n- return (self.type_id not in blacklisted)\n+ return self.type_id not in blacklisted\n \n def is_default_page_type(self):\n registry = getUtility(IRegistry)\n@@ -336,7 +316,7 @@ def is_default_page_type(self):\n return self.type_id in settings.default_page_types\n \n def is_redirect_links_enabled(self):\n- if self.type_id == \'Link\':\n+ if self.type_id == "Link":\n registry = getUtility(IRegistry)\n settings = registry.forInterface(ITypesSchema, prefix="plone")\n return settings.redirect_links\n@@ -345,19 +325,21 @@ def is_redirect_links_enabled(self):\n @memoize\n def current_workflow(self):\n context = aq_inner(self.context)\n- portal_workflow = getToolByName(context, \'portal_workflow\')\n+ portal_workflow = getToolByName(context, "portal_workflow")\n default_workflow = self.default_workflow(False)\n nondefault = [info[0] for info in portal_workflow.listChainOverrides()]\n chain = portal_workflow.getChainForPortalType(self.type_id)\n empty_workflow_dict = dict(\n- id=\'[none]\',\n+ id="[none]",\n title=_("label_no_workflow"),\n- description=[_(\n- "description_no_workflow",\n- default="This type has no workflow. The visibilty "\n- "of items of this type is determined by "\n- "the folder they are in.")\n- ]\n+ description=[\n+ _(\n+ "description_no_workflow",\n+ default="This type has no workflow. The visibilty "\n+ "of items of this type is determined by "\n+ "the folder they are in.",\n+ )\n+ ],\n )\n \n if self.type_id in nondefault:\n@@ -365,105 +347,96 @@ def current_workflow(self):\n wf_id = chain[0]\n wf = getattr(portal_workflow, wf_id)\n title = translate(\n- safe_text(wf.title),\n- domain=\'plone\',\n- context=self.request\n+ safe_text(wf.title), domain="plone", context=self.request\n )\n return dict(\n id=wf.id,\n title=title,\n description=format_description(\n- safe_text(wf.description),\n- self.request\n- )\n+ safe_text(wf.description), self.request\n+ ),\n )\n else:\n return empty_workflow_dict\n \n- if default_workflow == \'[none]\':\n+ if default_workflow == "[none]":\n return empty_workflow_dict\n \n default_title = translate(\n- safe_text(default_workflow.title),\n- domain=\'plone\',\n- context=self.request\n+ safe_text(default_workflow.title), domain="plone", context=self.request\n+ )\n+ return dict(\n+ id="(Default)",\n+ title=_(\n+ "label_default_workflow_title",\n+ default="Default workflow (${title})",\n+ mapping=dict(title=default_title),\n+ ),\n+ description=format_description(default_workflow.description, self.request),\n )\n- return dict(id=\'(Default)\',\n- title=_(\n- "label_default_workflow_title",\n- default="Default workflow (${title})",\n- mapping=dict(title=default_title)),\n- description=format_description(\n- default_workflow.description,\n- self.request)\n- )\n \n def available_workflows(self):\n- vocab_factory = getUtility(IVocabularyFactory,\n- name="plone.app.vocabularies.Workflows")\n+ vocab_factory = getUtility(\n+ IVocabularyFactory, name="plone.app.vocabularies.Workflows"\n+ )\n workflows = []\n for v in vocab_factory(self.context):\n if v.title:\n title = translate(v.title, context=self.request)\n else:\n- title = translate(\n- v.token,\n- domain=\'plone\',\n- context=self.request\n- )\n+ title = translate(v.token, domain="plone", context=self.request)\n workflows.append(dict(id=v.value, title=title))\n \n- workflows.sort(key=itemgetter(\'title\'))\n+ workflows.sort(key=itemgetter("title"))\n \n default_workflow = self.default_workflow(False)\n- if self.type_id and default_workflow != \'[none]\':\n+ if self.type_id and default_workflow != "[none]":\n # Only offer a default workflow option on a real type\n default_workflow = self.default_workflow(False)\n default_title = translate(\n- safe_text(default_workflow.title),\n- domain=\'plone\',\n- context=self.request\n+ safe_text(default_workflow.title), domain="plone", context=self.request\n )\n workflows.insert(\n 0,\n dict(\n- id=\'(Default)\',\n- title=_("label_default_workflow_title",\n- default="Default workflow (${title})",\n- mapping=dict(title=default_title)),\n+ id="(Default)",\n+ title=_(\n+ "label_default_workflow_title",\n+ default="Default workflow (${title})",\n+ mapping=dict(title=default_title),\n+ ),\n description=format_description(\n- default_workflow.description,\n- self.request\n- )\n- )\n+ default_workflow.description, self.request\n+ ),\n+ ),\n )\n \n return workflows\n \n @memoize\n def new_workflow(self):\n- current_workflow = self.current_workflow()[\'id\']\n- if self.type_id == \'\':\n+ current_workflow = self.current_workflow()["id"]\n+ if self.type_id == "":\n # If we are looking at the default workflow we need to show\n # the real workflow\n current_workflow = self.real_workflow(current_workflow)\n- old_type_id = self.request.form.get(\'old_type_id\', self.type_id)\n+ old_type_id = self.request.form.get("old_type_id", self.type_id)\n if old_type_id != self.type_id:\n return current_workflow\n else:\n- return self.request.form.get(\'new_workflow\', current_workflow)\n+ return self.request.form.get("new_workflow", current_workflow)\n \n @memoize\n def have_new_workflow(self):\n- return self.current_workflow()[\'id\'] != self.new_workflow()\n+ return self.current_workflow()["id"] != self.new_workflow()\n \n @memoize\n def default_workflow(self, id_only=True):\n- portal_workflow = getToolByName(self.context, \'portal_workflow\')\n+ portal_workflow = getToolByName(self.context, "portal_workflow")\n default_chain = portal_workflow.getDefaultChain()\n if not default_chain:\n # There is no default workflow\n- return \'[none]\'\n+ return "[none]"\n id = default_chain[0]\n if id_only:\n return id\n@@ -472,7 +445,7 @@ def default_workflow(self, id_only=True):\n \n @memoize\n def real_workflow(self, wf):\n- if wf == \'(Default)\':\n+ if wf == "(Default)":\n return self.default_workflow()\n else:\n return wf\n@@ -480,26 +453,28 @@ def real_workflow(self, wf):\n @memoize\n def new_workflow_is_different(self):\n new_workflow = self.new_workflow()\n- current_workflow = self.current_workflow()[\'id\']\n+ current_workflow = self.current_workflow()["id"]\n \n- return self.real_workflow(new_workflow) != self.real_workflow(\n- current_workflow)\n+ return self.real_workflow(new_workflow) != self.real_workflow(current_workflow)\n \n @memoize\n def new_workflow_is_none(self):\n- return self.new_workflow() == \'[none]\'\n+ return self.new_workflow() == "[none]"\n \n def new_workflow_description(self):\n- portal_workflow = getToolByName(self.context, \'portal_workflow\')\n+ portal_workflow = getToolByName(self.context, "portal_workflow")\n new_workflow = self.new_workflow()\n \n if self.new_workflow_is_different():\n if self.new_workflow_is_none():\n- return [_(\n- "description_no_workflow",\n- default="This type has no workflow. The visibilty of "\n- "items of this type is determined by the "\n- "folder they are in.")]\n+ return [\n+ _(\n+ "description_no_workflow",\n+ default="This type has no workflow. The visibilty of "\n+ "items of this type is determined by the "\n+ "folder they are in.",\n+ )\n+ ]\n new_workflow = self.real_workflow(self.new_workflow())\n wf = getattr(portal_workflow, new_workflow)\n return format_description(wf.description, self.request)\n@@ -509,32 +484,32 @@ def new_workflow_description(self):\n def new_workflow_available_states(self):\n if self.new_workflow_is_different():\n new_workflow = self.real_workflow(self.new_workflow())\n- portal_workflow = getToolByName(self.context, \'portal_workflow\')\n+ portal_workflow = getToolByName(self.context, "portal_workflow")\n wf = getattr(portal_workflow, new_workflow)\n states = []\n for s in wf.states.objectValues():\n- title = translate(\n- s.title,\n- domain=\'plone\',\n- context=self.request\n- )\n+ title = translate(s.title, domain="plone", context=self.request)\n states.append(dict(id=s.id, title=title))\n return states\n else:\n return []\n \n def suggested_state_map(self):\n- current_workflow = self.real_workflow(self.current_workflow()[\'id\'])\n+ current_workflow = self.real_workflow(self.current_workflow()["id"])\n new_workflow = self.real_workflow(self.new_workflow())\n \n- portal_workflow = getToolByName(self.context, \'portal_workflow\')\n+ portal_workflow = getToolByName(self.context, "portal_workflow")\n \n- if current_workflow == \'[none]\':\n+ if current_workflow == "[none]":\n new_wf = getattr(portal_workflow, new_workflow)\n default_state = new_wf.initial_state\n- return [dict(old_id=\'[none]\',\n- old_title=_("No workflow"),\n- suggested_id=default_state)]\n+ return [\n+ dict(\n+ old_id="[none]",\n+ old_title=_("No workflow"),\n+ suggested_id=default_state,\n+ )\n+ ]\n \n elif self.new_workflow_is_different():\n old_wf = getattr(portal_workflow, current_workflow)\n@@ -545,16 +520,14 @@ def suggested_state_map(self):\n \n states = []\n for old in old_wf.states.objectValues():\n- title = translate(\n- old.title,\n- domain=\'plone\',\n- context=self.request\n+ title = translate(old.title, domain="plone", context=self.request)\n+ states.append(\n+ dict(\n+ old_id=old.id,\n+ old_title=title,\n+ suggested_id=(old.id in new_states and old.id or default_state),\n+ )\n )\n- states.append(dict(\n- old_id=old.id,\n- old_title=title,\n- suggested_id=(old.id in new_states and\n- old.id or default_state)))\n return states\n else:\n return []\ndiff --git a/Products/CMFPlone/controlpanel/browser/usergroups.py b/Products/CMFPlone/controlpanel/browser/usergroups.py\nindex 330194ac64..446cc3ccf4 100644\n--- a/Products/CMFPlone/controlpanel/browser/usergroups.py\n+++ b/Products/CMFPlone/controlpanel/browser/usergroups.py\n@@ -25,14 +25,14 @@ class UserGroupsSettingsControlPanel(AutoExtensibleForm, form.EditForm):\n form_name = _("User/Groups settings")\n control_panel_view = "usergroups-controlpanel"\n \n- @button.buttonAndHandler(_(\'label_save\', default="Save"), name=\'save\')\n+ @button.buttonAndHandler(_("label_save", default="Save"), name="save")\n def handleApply(self, action):\n super().handleApply(self, action)\n \n def updateActions(self):\n super().updateActions()\n- if self.actions and \'save\' in self.actions:\n- self.actions[\'save\'].addClass(\'btn-primary\')\n+ if self.actions and "save" in self.actions:\n+ self.actions["save"].addClass("btn-primary")\n \n \n class ControlPanelFormWrapper(layout.FormWrapper):\n@@ -40,7 +40,7 @@ class ControlPanelFormWrapper(layout.FormWrapper):\n panel layout.\n """\n \n- index = ViewPageTemplateFile(\'controlpanel_usergroups_layout.pt\')\n+ index = ViewPageTemplateFile("controlpanel_usergroups_layout.pt")\n \n \n UserGroupsSettingsPanelView = layout.wrap_form(\n@@ -49,11 +49,10 @@ class ControlPanelFormWrapper(layout.FormWrapper):\n \n \n class UsersGroupsControlPanelView(BrowserView):\n-\n @property\n def portal_roles(self):\n- pmemb = getToolByName(aq_inner(self.context), \'portal_membership\')\n- return [r for r in pmemb.getPortalRoles() if r != \'Owner\']\n+ pmemb = getToolByName(aq_inner(self.context), "portal_membership")\n+ return [r for r in pmemb.getPortalRoles() if r != "Owner"]\n \n @property\n def many_users(self):\n@@ -65,37 +64,67 @@ def many_groups(self):\n \n @property\n def email_as_username(self):\n- return getAdapter(aq_inner(self.context), ISecuritySchema).get_use_email_as_login()\n+ return getAdapter(\n+ aq_inner(self.context), ISecuritySchema\n+ ).get_use_email_as_login()\n \n def makeQuery(self, **kw):\n return make_query(**kw)\n \n- def membershipSearch(self, searchString=\'\', searchUsers=True, searchGroups=True, ignore=[]):\n+ def membershipSearch(\n+ self, searchString="", searchUsers=True, searchGroups=True, ignore=[]\n+ ):\n """Search for users and/or groups, returning actual member and group items\n- Replaces the now-deprecated prefs_user_groups_search.py script"""\n+ Replaces the now-deprecated prefs_user_groups_search.py script"""\n groupResults = userResults = []\n \n- gtool = getToolByName(self, \'portal_groups\')\n- mtool = getToolByName(self, \'portal_membership\')\n+ gtool = getToolByName(self, "portal_groups")\n+ mtool = getToolByName(self, "portal_membership")\n \n searchView = getMultiAdapter(\n- (aq_inner(self.context), self.request), name=\'pas_search\')\n+ (aq_inner(self.context), self.request), name="pas_search"\n+ )\n \n if searchGroups:\n- groupResults = searchView.merge(chain(\n- *[searchView.searchGroups(**{field: searchString}) for field in [\'id\', \'title\']]), \'groupid\')\n- groupResults = [gtool.getGroupById(g[\'id\']) for g in groupResults if g[\n- \'id\'] not in ignore]\n- groupResults.sort(key=lambda x: x is not None and normalizeString(\n- x.getGroupTitleOrName()))\n+ groupResults = searchView.merge(\n+ chain(\n+ *[\n+ searchView.searchGroups(**{field: searchString})\n+ for field in ["id", "title"]\n+ ]\n+ ),\n+ "groupid",\n+ )\n+ groupResults = [\n+ gtool.getGroupById(g["id"])\n+ for g in groupResults\n+ if g["id"] not in ignore\n+ ]\n+ groupResults.sort(\n+ key=lambda x: x is not None and normalizeString(x.getGroupTitleOrName())\n+ )\n \n if searchUsers:\n- userResults = searchView.merge(chain(*[searchView.searchUsers(\n- **{field: searchString}) for field in [\'login\', \'fullname\', \'email\']]), \'userid\')\n- userResults = [mtool.getMemberById(u[\'id\']) for u in userResults if u[\n- \'id\'] not in ignore]\n- userResults.sort(key=lambda x: x is not None and x.getProperty(\n- \'fullname\') is not None and normalizeString(x.getProperty(\'fullname\')) or \'\')\n+ userResults = searchView.merge(\n+ chain(\n+ *[\n+ searchView.searchUsers(**{field: searchString})\n+ for field in ["login", "fullname", "email"]\n+ ]\n+ ),\n+ "userid",\n+ )\n+ userResults = [\n+ mtool.getMemberById(u["id"])\n+ for u in userResults\n+ if u["id"] not in ignore\n+ ]\n+ userResults.sort(\n+ key=lambda x: x is not None\n+ and x.getProperty("fullname") is not None\n+ and normalizeString(x.getProperty("fullname"))\n+ or ""\n+ )\n \n return groupResults + userResults\n \n@@ -128,7 +157,7 @@ def is_zope_manager(self):\n @property\n def show_group_listing_warning(self):\n if not self.searchString:\n- acl = getToolByName(self, \'acl_users\')\n+ acl = getToolByName(self, "acl_users")\n if acl.canListAllGroups():\n if self.many_groups:\n return True\n@@ -137,7 +166,7 @@ def show_group_listing_warning(self):\n @property\n def show_users_listing_warning(self):\n if not self.searchString:\n- acl = getToolByName(self, \'acl_users\')\n+ acl = getToolByName(self, "acl_users")\n # XXX Huh? Is canListAllUsers broken?\n if not acl.canListAllUsers():\n if self.many_users:\ndiff --git a/Products/CMFPlone/controlpanel/browser/usergroups_groupdetails.py b/Products/CMFPlone/controlpanel/browser/usergroups_groupdetails.py\nindex 53d6591743..70216f6c31 100644\n--- a/Products/CMFPlone/controlpanel/browser/usergroups_groupdetails.py\n+++ b/Products/CMFPlone/controlpanel/browser/usergroups_groupdetails.py\n@@ -9,7 +9,6 @@\n \n \n class GroupDetailsControlPanel(UsersGroupsControlPanelView):\n-\n def get_group_property(self, prop_id):\n try:\n return self.group.getProperty(prop_id, None)\n@@ -19,61 +18,69 @@ def get_group_property(self, prop_id):\n def __call__(self):\n context = aq_inner(self.context)\n \n- self.gtool = getToolByName(context, \'portal_groups\')\n- self.gdtool = getToolByName(context, \'portal_groupdata\')\n- self.regtool = getToolByName(context, \'portal_registration\')\n- self.groupname = getattr(self.request, \'groupname\', None)\n- self.grouproles = self.request.set(\'grouproles\', [])\n+ self.gtool = getToolByName(context, "portal_groups")\n+ self.gdtool = getToolByName(context, "portal_groupdata")\n+ self.regtool = getToolByName(context, "portal_registration")\n+ self.groupname = getattr(self.request, "groupname", None)\n+ self.grouproles = self.request.set("grouproles", [])\n self.group = self.gtool.getGroupById(self.groupname)\n self.grouptitle = self.groupname\n if self.group is not None:\n self.grouptitle = self.group.getGroupTitleOrName()\n \n- self.request.set(\'grouproles\', self.group.getRoles()\n- if self.group else [])\n+ self.request.set("grouproles", self.group.getRoles() if self.group else [])\n \n- submitted = self.request.form.get(\'form.submitted\', False)\n+ submitted = self.request.form.get("form.submitted", False)\n if submitted:\n CheckAuthenticator(self.request)\n \n- msg = _(\'No changes made.\')\n+ msg = _("No changes made.")\n self.group = None\n \n- title = self.request.form.get(\'title\', None)\n- description = self.request.form.get(\'description\', None)\n- addname = self.request.form.get(\'addname\', None)\n+ title = self.request.form.get("title", None)\n+ description = self.request.form.get("description", None)\n+ addname = self.request.form.get("addname", None)\n \n if addname:\n if not self.regtool.isMemberIdAllowed(addname):\n- msg = _(\'The group name you entered is not valid.\')\n- IStatusMessage(self.request).add(msg, \'error\')\n+ msg = _("The group name you entered is not valid.")\n+ IStatusMessage(self.request).add(msg, "error")\n return self.index()\n \n- success = self.gtool.addGroup(addname, (), (), title=title,\n- description=description,\n- REQUEST=self.request)\n+ success = self.gtool.addGroup(\n+ addname,\n+ (),\n+ (),\n+ title=title,\n+ description=description,\n+ REQUEST=self.request,\n+ )\n if not success:\n msg = _(\n- \'Could not add group ${name}, perhaps a user or \'\n- \'group with this name already exists.\',\n- mapping={\'name\': addname}\n+ "Could not add group ${name}, perhaps a user or "\n+ "group with this name already exists.",\n+ mapping={"name": addname},\n )\n- IStatusMessage(self.request).add(msg, \'error\')\n+ IStatusMessage(self.request).add(msg, "error")\n return self.index()\n \n self.group = self.gtool.getGroupById(addname)\n- msg = _(\'Group ${name} has been added.\',\n- mapping={\'name\': addname})\n+ msg = _("Group ${name} has been added.", mapping={"name": addname})\n \n elif self.groupname:\n- self.gtool.editGroup(self.groupname, roles=None, groups=None,\n- title=title, description=description,\n- REQUEST=context.REQUEST)\n+ self.gtool.editGroup(\n+ self.groupname,\n+ roles=None,\n+ groups=None,\n+ title=title,\n+ description=description,\n+ REQUEST=context.REQUEST,\n+ )\n self.group = self.gtool.getGroupById(self.groupname)\n- msg = _(\'Changes saved.\')\n+ msg = _("Changes saved.")\n \n else:\n- msg = _(\'Group name required.\')\n+ msg = _("Group name required.")\n \n processed = {}\n for id, property in self.gdtool.propertyItems():\n@@ -84,12 +91,12 @@ def __call__(self):\n # exist\n self.group.setGroupProperties(processed)\n \n- IStatusMessage(self.request).add(\n- msg, type=self.group and \'info\' or \'error\')\n+ IStatusMessage(self.request).add(msg, type=self.group and "info" or "error")\n if self.group and not self.groupname:\n- target_url = \'{}/{}\'.format(self.context.absolute_url(),\n- \'@@usergroup-groupprefs\')\n+ target_url = "{}/{}".format(\n+ self.context.absolute_url(), "@@usergroup-groupprefs"\n+ )\n self.request.response.redirect(target_url)\n- return \'\'\n+ return ""\n \n return self.index()\ndiff --git a/Products/CMFPlone/controlpanel/browser/usergroups_groupmembership.py b/Products/CMFPlone/controlpanel/browser/usergroups_groupmembership.py\nindex 2cd097703d..27b817a144 100644\n--- a/Products/CMFPlone/controlpanel/browser/usergroups_groupmembership.py\n+++ b/Products/CMFPlone/controlpanel/browser/usergroups_groupmembership.py\n@@ -8,72 +8,64 @@\n \n \n class GroupMembershipControlPanel(UsersGroupsControlPanelView):\n-\n def update(self):\n- self.groupname = getattr(self.request, \'groupname\')\n- self.gtool = getToolByName(self, \'portal_groups\')\n- self.mtool = getToolByName(self, \'portal_membership\')\n+ self.groupname = getattr(self.request, "groupname")\n+ self.gtool = getToolByName(self, "portal_groups")\n+ self.mtool = getToolByName(self, "portal_membership")\n self.group = self.gtool.getGroupById(self.groupname)\n if self.group is None:\n return\n \n self.grouptitle = self.group.getGroupTitleOrName() or self.groupname\n \n- self.request.set(\'grouproles\', self.group.getRoles()\n- if self.group else [])\n+ self.request.set("grouproles", self.group.getRoles() if self.group else [])\n self.canAddUsers = True\n- if \'Manager\' in self.request.get(\'grouproles\') and not self.is_zope_manager:\n+ if "Manager" in self.request.get("grouproles") and not self.is_zope_manager:\n self.canAddUsers = False\n \n self.groupquery = self.makeQuery(groupname=self.groupname)\n self.groupkeyquery = self.makeQuery(key=self.groupname)\n \n form = self.request.form\n- submitted = form.get(\'form.submitted\', False)\n+ submitted = form.get("form.submitted", False)\n \n self.searchResults = []\n- self.searchString = \'\'\n+ self.searchString = ""\n self.newSearch = False\n \n if submitted:\n # add/delete before we search so we don\'t show stale results\n- toAdd = form.get(\'add\', [])\n+ toAdd = form.get("add", [])\n if toAdd:\n if not self.canAddUsers:\n raise Forbidden\n \n for u in toAdd:\n- self.gtool.addPrincipalToGroup(\n- u, self.groupname, self.request)\n- self.context.plone_utils.addPortalMessage(_(\'Changes made.\'))\n+ self.gtool.addPrincipalToGroup(u, self.groupname, self.request)\n+ self.context.plone_utils.addPortalMessage(_("Changes made."))\n \n- toDelete = form.get(\'delete\', [])\n+ toDelete = form.get("delete", [])\n if toDelete:\n for u in toDelete:\n- self.gtool.removePrincipalFromGroup(\n- u, self.groupname, self.request)\n- self.context.plone_utils.addPortalMessage(_(\'Changes made.\'))\n+ self.gtool.removePrincipalFromGroup(u, self.groupname, self.request)\n+ self.context.plone_utils.addPortalMessage(_("Changes made."))\n \n- search = form.get(\'form.button.Search\', None) is not None\n- edit = form.get(\'form.button.Edit\', None) is not None and toDelete\n- add = form.get(\'form.button.Add\', None) is not None and toAdd\n+ search = form.get("form.button.Search", None) is not None\n+ edit = form.get("form.button.Edit", None) is not None and toDelete\n+ add = form.get("form.button.Add", None) is not None and toAdd\n isBatched = form.get("b_start", None) is not None\n findAll = (\n- form.get(\'form.button.FindAll\', None) is not None\n- and not self.many_users\n- )\n- unbatchedAll = (\n- form.get("showAll", "") == "y"\n+ form.get("form.button.FindAll", None) is not None\n and not self.many_users\n )\n+ unbatchedAll = form.get("showAll", "") == "y" and not self.many_users\n # The search string should be cleared when one of the\n # non-search buttons has been clicked.\n if findAll or unbatchedAll or edit or add:\n- form[\'searchstring\'] = \'\'\n- self.searchString = form.get(\'searchstring\', \'\')\n+ form["searchstring"] = ""\n+ self.searchString = form.get("searchstring", "")\n if findAll or isBatched or unbatchedAll or bool(self.searchString):\n- self.searchResults = self.getPotentialMembers(\n- self.searchString)\n+ self.searchResults = self.getPotentialMembers(self.searchString)\n \n if search or findAll:\n self.newSearch = True\n@@ -102,11 +94,17 @@ def getMembers(self):\n userResults.append(principal)\n \n groupResults.sort(key=lambda x: normalizeString(x.getGroupTitleOrName()))\n- userResults.sort(key=lambda x: normalizeString(x.getProperty(\'fullname\') or \'\'))\n+ userResults.sort(key=lambda x: normalizeString(x.getProperty("fullname") or ""))\n \n return groupResults + userResults\n \n def getPotentialMembers(self, searchString):\n ignoredUsersGroups = [\n- x.id for x in self.getMembers() + [self.group, ] if x is not None]\n+ x.id\n+ for x in self.getMembers()\n+ + [\n+ self.group,\n+ ]\n+ if x is not None\n+ ]\n return self.membershipSearch(searchString, ignore=ignoredUsersGroups)\ndiff --git a/Products/CMFPlone/controlpanel/browser/usergroups_groupsoverview.py b/Products/CMFPlone/controlpanel/browser/usergroups_groupsoverview.py\nindex 532050ffdd..4dad8f81bf 100644\n--- a/Products/CMFPlone/controlpanel/browser/usergroups_groupsoverview.py\n+++ b/Products/CMFPlone/controlpanel/browser/usergroups_groupsoverview.py\n@@ -12,13 +12,12 @@\n \n \n class GroupsOverviewControlPanel(UsersGroupsControlPanelView):\n-\n def __call__(self):\n form = self.request.form\n- submitted = form.get(\'form.submitted\', False)\n- search = form.get(\'form.button.Search\', None) is not None\n- findAll = form.get(\'form.button.FindAll\', None) is not None\n- self.searchString = not findAll and form.get(\'searchstring\', \'\') or \'\'\n+ submitted = form.get("form.submitted", False)\n+ search = form.get("form.button.Search", None) is not None\n+ findAll = form.get("form.button.FindAll", None) is not None\n+ self.searchString = not findAll and form.get("searchstring", "") or ""\n self.searchResults = []\n self.newSearch = False\n \n@@ -26,37 +25,50 @@ def __call__(self):\n self.newSearch = True\n \n if submitted:\n- if form.get(\'form.button.Modify\', None) is not None:\n- self.manageGroup([group[len(\'group_\'):] for group in self.request.keys() if group.startswith(\'group_\')],\n- form.get(\'delete\', []))\n+ if form.get("form.button.Modify", None) is not None:\n+ self.manageGroup(\n+ [\n+ group[len("group_") :]\n+ for group in self.request.keys()\n+ if group.startswith("group_")\n+ ],\n+ form.get("delete", []),\n+ )\n \n # Only search for all (\'\') if the many_users flag is not set.\n- if not(self.many_groups) or bool(self.searchString):\n+ if not (self.many_groups) or bool(self.searchString):\n self.searchResults = self.doSearch(self.searchString)\n \n return self.index()\n \n def doSearch(self, searchString):\n- """ Search for a group by id or title"""\n- acl = getToolByName(self, \'acl_users\')\n+ """Search for a group by id or title"""\n+ acl = getToolByName(self, "acl_users")\n rolemakers = acl.plugins.listPlugins(IRolesPlugin)\n \n searchView = getMultiAdapter(\n- (aq_inner(self.context), self.request), name=\'pas_search\')\n+ (aq_inner(self.context), self.request), name="pas_search"\n+ )\n \n # First, search for inherited roles assigned to each group.\n # We push this in the request so that IRoles plugins are told provide\n # the roles inherited from the groups to which the principal belongs.\n- self.request.set(\'__ignore_group_roles__\', False)\n- self.request.set(\'__ignore_direct_roles__\', True)\n- inheritance_enabled_groups = searchView.merge(chain(\n- *[searchView.searchGroups(**{field: searchString}) for field in [\'id\', \'title\']]), \'id\')\n+ self.request.set("__ignore_group_roles__", False)\n+ self.request.set("__ignore_direct_roles__", True)\n+ inheritance_enabled_groups = searchView.merge(\n+ chain(\n+ *[\n+ searchView.searchGroups(**{field: searchString})\n+ for field in ["id", "title"]\n+ ]\n+ ),\n+ "id",\n+ )\n allInheritedRoles = {}\n for group_info in inheritance_enabled_groups:\n- groupId = group_info[\'id\']\n+ groupId = group_info["id"]\n group = acl.getGroupById(groupId)\n- group_info[\'title\'] = group.getProperty(\n- \'title\', group_info[\'title\'])\n+ group_info["title"] = group.getProperty("title", group_info["title"])\n allAssignedRoles = []\n for rolemaker_id, rolemaker in rolemakers:\n # getRolesForPrincipal can return None\n@@ -67,20 +79,26 @@ def doSearch(self, searchString):\n # Now, search for all roles explicitly assigned to each group.\n # We push this in the request so that IRoles plugins don\'t provide\n # the roles inherited from the groups to which the principal belongs.\n- self.request.set(\'__ignore_group_roles__\', True)\n- self.request.set(\'__ignore_direct_roles__\', False)\n- explicit_groups = searchView.merge(chain(\n- *[searchView.searchGroups(**{field: searchString}) for field in [\'id\', \'title\']]), \'id\')\n+ self.request.set("__ignore_group_roles__", True)\n+ self.request.set("__ignore_direct_roles__", False)\n+ explicit_groups = searchView.merge(\n+ chain(\n+ *[\n+ searchView.searchGroups(**{field: searchString})\n+ for field in ["id", "title"]\n+ ]\n+ ),\n+ "id",\n+ )\n \n # Tack on some extra data, including whether each role is explicitly\n # assigned (\'explicit\'), inherited (\'inherited\'), or not assigned at\n # all (None).\n results = []\n for group_info in explicit_groups:\n- groupId = group_info[\'id\']\n+ groupId = group_info["id"]\n group = acl.getGroupById(groupId)\n- group_info[\'title\'] = group.getProperty(\n- \'title\', group_info[\'title\'])\n+ group_info["title"] = group.getProperty("title", group_info["title"])\n \n explicitlyAssignedRoles = []\n for rolemaker_id, rolemaker in rolemakers:\n@@ -91,26 +109,30 @@ def doSearch(self, searchString):\n roleList = {}\n for role in self.portal_roles:\n canAssign = group.canAssignRole(role)\n- if role == \'Manager\' and not self.is_zope_manager:\n+ if role == "Manager" and not self.is_zope_manager:\n canAssign = False\n- roleList[role] = {\'canAssign\': canAssign,\n- \'explicit\': role in explicitlyAssignedRoles,\n- \'inherited\': role in allInheritedRoles.get(groupId, [])}\n+ roleList[role] = {\n+ "canAssign": canAssign,\n+ "explicit": role in explicitlyAssignedRoles,\n+ "inherited": role in allInheritedRoles.get(groupId, []),\n+ }\n \n canDelete = group.canDelete()\n- if (\'Manager\' in explicitlyAssignedRoles or\n- \'Manager\' in allInheritedRoles.get(groupId, [])):\n+ if (\n+ "Manager" in explicitlyAssignedRoles\n+ or "Manager" in allInheritedRoles.get(groupId, [])\n+ ):\n if not self.is_zope_manager:\n canDelete = False\n \n- group_info[\'roles\'] = roleList\n- group_info[\'can_delete\'] = canDelete\n+ group_info["roles"] = roleList\n+ group_info["can_delete"] = canDelete\n results.append(group_info)\n # Sort the groups by title\n- sortedResults = searchView.sort(results, \'title\')\n+ sortedResults = searchView.sort(results, "title")\n \n # Reset the request variable, just in case.\n- self.request.set(\'__ignore_group_roles__\', False)\n+ self.request.set("__ignore_group_roles__", False)\n return sortedResults\n \n def manageGroup(self, groups=None, delete=None):\n@@ -122,30 +144,30 @@ def manageGroup(self, groups=None, delete=None):\n context = aq_inner(self.context)\n \n groupstool = context.portal_groups\n- utils = getToolByName(context, \'plone_utils\')\n- groupstool = getToolByName(context, \'portal_groups\')\n+ utils = getToolByName(context, "plone_utils")\n+ groupstool = getToolByName(context, "portal_groups")\n \n- message = _(\'No changes made.\')\n+ message = _("No changes made.")\n \n for group in groups:\n- roles = [r for r in self.request.form[\'group_\' + group] if r]\n+ roles = [r for r in self.request.form["group_" + group] if r]\n group_obj = groupstool.getGroupById(group)\n current_roles = group_obj.getRoles()\n if not self.is_zope_manager:\n # don\'t allow adding or removing the Manager role\n- if (\'Manager\' in roles) != (\'Manager\' in current_roles):\n+ if ("Manager" in roles) != ("Manager" in current_roles):\n raise Forbidden\n \n groupstool.editGroup(group, roles=roles, groups=())\n- message = _(\'Changes saved.\')\n+ message = _("Changes saved.")\n \n if delete:\n for group_id in delete:\n group = groupstool.getGroupById(group_id)\n- if \'Manager\' in group.getRoles() and not self.is_zope_manager:\n+ if "Manager" in group.getRoles() and not self.is_zope_manager:\n raise Forbidden\n \n groupstool.removeGroups(delete)\n- message = _(\'Group(s) deleted.\')\n+ message = _("Group(s) deleted.")\n \n utils.addPortalMessage(message)\ndiff --git a/Products/CMFPlone/controlpanel/browser/usergroups_usermembership.py b/Products/CMFPlone/controlpanel/browser/usergroups_usermembership.py\nindex 71a4e123b1..57ea21eeed 100644\n--- a/Products/CMFPlone/controlpanel/browser/usergroups_usermembership.py\n+++ b/Products/CMFPlone/controlpanel/browser/usergroups_usermembership.py\n@@ -8,44 +8,44 @@\n \n \n class UserMembershipControlPanel(UsersGroupsControlPanelView):\n-\n def update(self):\n- self.userid = getattr(self.request, \'userid\')\n- self.gtool = getToolByName(self, \'portal_groups\')\n- self.mtool = getToolByName(self, \'portal_membership\')\n+ self.userid = getattr(self.request, "userid")\n+ self.gtool = getToolByName(self, "portal_groups")\n+ self.mtool = getToolByName(self, "portal_membership")\n self.member = self.mtool.getMemberById(self.userid)\n \n form = self.request.form\n \n self.searchResults = []\n- self.searchString = \'\'\n+ self.searchString = ""\n self.newSearch = False\n \n- if form.get(\'form.submitted\', False):\n- delete = form.get(\'delete\', [])\n+ if form.get("form.submitted", False):\n+ delete = form.get("delete", [])\n if delete:\n for groupname in delete:\n self.gtool.removePrincipalFromGroup(\n- self.userid, groupname, self.request)\n- self.context.plone_utils.addPortalMessage(_(\'Changes made.\'))\n+ self.userid, groupname, self.request\n+ )\n+ self.context.plone_utils.addPortalMessage(_("Changes made."))\n \n- add = form.get(\'add\', [])\n+ add = form.get("add", [])\n if add:\n for groupname in add:\n group = self.gtool.getGroupById(groupname)\n- if \'Manager\' in group.getRoles() and not self.is_zope_manager:\n+ if "Manager" in group.getRoles() and not self.is_zope_manager:\n raise Forbidden\n \n- self.gtool.addPrincipalToGroup(\n- self.userid, groupname, self.request)\n- self.context.plone_utils.addPortalMessage(_(\'Changes made.\'))\n+ self.gtool.addPrincipalToGroup(self.userid, groupname, self.request)\n+ self.context.plone_utils.addPortalMessage(_("Changes made."))\n \n- search = form.get(\'form.button.Search\', None) is not None\n- findAll = form.get(\'form.button.FindAll\',\n- None) is not None and not self.many_groups\n- self.searchString = not findAll and form.get(\'searchstring\', \'\') or \'\'\n+ search = form.get("form.button.Search", None) is not None\n+ findAll = (\n+ form.get("form.button.FindAll", None) is not None and not self.many_groups\n+ )\n+ self.searchString = not findAll and form.get("searchstring", "") or ""\n \n- if findAll or not self.many_groups or self.searchString != \'\':\n+ if findAll or not self.many_groups or self.searchString != "":\n self.searchResults = self.getPotentialGroups(self.searchString)\n \n if search or findAll:\n@@ -58,12 +58,17 @@ def __call__(self):\n return self.index()\n \n def getGroups(self):\n- groupResults = [self.gtool.getGroupById(\n- m) for m in self.gtool.getGroupsForPrincipal(self.member)]\n- groupResults.sort(key=lambda x: x is not None and normalizeString(\n- x.getGroupTitleOrName()))\n+ groupResults = [\n+ self.gtool.getGroupById(m)\n+ for m in self.gtool.getGroupsForPrincipal(self.member)\n+ ]\n+ groupResults.sort(\n+ key=lambda x: x is not None and normalizeString(x.getGroupTitleOrName())\n+ )\n return [i for i in groupResults if i]\n \n def getPotentialGroups(self, searchString):\n ignoredGroups = [x.id for x in self.getGroups() if x is not None]\n- return self.membershipSearch(searchString, searchUsers=False, ignore=ignoredGroups)\n+ return self.membershipSearch(\n+ searchString, searchUsers=False, ignore=ignoredGroups\n+ )\ndiff --git a/Products/CMFPlone/controlpanel/browser/usergroups_usersoverview.py b/Products/CMFPlone/controlpanel/browser/usergroups_usersoverview.py\nindex 8c14b9ad82..e102111e40 100644\n--- a/Products/CMFPlone/controlpanel/browser/usergroups_usersoverview.py\n+++ b/Products/CMFPlone/controlpanel/browser/usergroups_usersoverview.py\n@@ -16,18 +16,16 @@\n import logging\n \n \n-logger = logging.getLogger(\'Products.CMFPlone\')\n+logger = logging.getLogger("Products.CMFPlone")\n \n \n class UsersOverviewControlPanel(UsersGroupsControlPanelView):\n-\n def __call__(self):\n-\n form = self.request.form\n- submitted = form.get(\'form.submitted\', False)\n- search = form.get(\'form.button.Search\', None) is not None\n- findAll = form.get(\'form.button.FindAll\', None) is not None\n- self.searchString = not findAll and form.get(\'searchstring\', \'\') or \'\'\n+ submitted = form.get("form.submitted", False)\n+ search = form.get("form.button.Search", None) is not None\n+ findAll = form.get("form.button.FindAll", None) is not None\n+ self.searchString = not findAll and form.get("searchstring", "") or ""\n self.searchResults = []\n self.newSearch = False\n \n@@ -35,43 +33,50 @@ def __call__(self):\n self.newSearch = True\n \n if submitted:\n- if form.get(\'form.button.Modify\', None) is not None:\n- self.manageUser(form.get(\'users\', None),\n- form.get(\'resetpassword\', []),\n- form.get(\'delete\', []))\n+ if form.get("form.button.Modify", None) is not None:\n+ self.manageUser(\n+ form.get("users", None),\n+ form.get("resetpassword", []),\n+ form.get("delete", []),\n+ )\n \n # Only search for all (\'\') if the many_users flag is not set.\n- if not(self.many_users) or bool(self.searchString):\n+ if not (self.many_users) or bool(self.searchString):\n self.searchResults = self.doSearch(self.searchString)\n \n return self.index()\n \n def doSearch(self, searchString):\n- acl = getToolByName(self, \'acl_users\')\n+ acl = getToolByName(self, "acl_users")\n rolemakers = acl.plugins.listPlugins(IRolesPlugin)\n \n- mtool = getToolByName(self, \'portal_membership\')\n+ mtool = getToolByName(self, "portal_membership")\n \n- searchView = getMultiAdapter((\n- aq_inner(self.context),\n- self.request\n- ), name=\'pas_search\')\n+ searchView = getMultiAdapter(\n+ (aq_inner(self.context), self.request), name="pas_search"\n+ )\n \n # First, search for all inherited roles assigned to each group.\n # We push this in the request so that IRoles plugins are told provide\n # the roles inherited from the groups to which the principal belongs.\n- self.request.set(\'__ignore_group_roles__\', False)\n- self.request.set(\'__ignore_direct_roles__\', True)\n+ self.request.set("__ignore_group_roles__", False)\n+ self.request.set("__ignore_direct_roles__", True)\n inheritance_enabled_users = searchView.merge(\n- chain(*[searchView.searchUsers(**{field: searchString}) for field in [\'login\', \'fullname\', \'email\']]), \'userid\')\n+ chain(\n+ *[\n+ searchView.searchUsers(**{field: searchString})\n+ for field in ["login", "fullname", "email"]\n+ ]\n+ ),\n+ "userid",\n+ )\n allInheritedRoles = {}\n for user_info in inheritance_enabled_users:\n- userId = user_info[\'id\']\n+ userId = user_info["id"]\n user = acl.getUserById(userId)\n # play safe, though this should never happen\n if user is None:\n- logger.warning(\n- \'Skipped user without principal object: %s\' % userId)\n+ logger.warning("Skipped user without principal object: %s" % userId)\n continue\n allAssignedRoles = []\n for rolemaker_id, rolemaker in rolemakers:\n@@ -80,11 +85,16 @@ def doSearch(self, searchString):\n \n # We push this in the request such IRoles plugins don\'t provide\n # the roles from the groups the principal belongs.\n- self.request.set(\'__ignore_group_roles__\', True)\n- self.request.set(\'__ignore_direct_roles__\', False)\n+ self.request.set("__ignore_group_roles__", True)\n+ self.request.set("__ignore_direct_roles__", False)\n explicit_users = searchView.merge(\n- chain(*[searchView.searchUsers(**{field: searchString})\n- for field in [\'login\', \'fullname\', \'email\']]), \'userid\'\n+ chain(\n+ *[\n+ searchView.searchUsers(**{field: searchString})\n+ for field in ["login", "fullname", "email"]\n+ ]\n+ ),\n+ "userid",\n )\n \n # Tack on some extra data, including whether each role is explicitly\n@@ -92,48 +102,52 @@ def doSearch(self, searchString):\n # all (None).\n results = []\n for user_info in explicit_users:\n- userId = user_info[\'id\']\n+ userId = user_info["id"]\n user = mtool.getMemberById(userId)\n # play safe, though this should never happen\n if user is None:\n- logger.warning(\n- \'Skipped user without principal object: %s\' % userId)\n+ logger.warning("Skipped user without principal object: %s" % userId)\n continue\n explicitlyAssignedRoles = []\n for rolemaker_id, rolemaker in rolemakers:\n- explicitlyAssignedRoles.extend(\n- rolemaker.getRolesForPrincipal(user))\n+ explicitlyAssignedRoles.extend(rolemaker.getRolesForPrincipal(user))\n \n roleList = {}\n for role in self.portal_roles:\n canAssign = user.canAssignRole(role)\n- if role == \'Manager\' and not self.is_zope_manager:\n+ if role == "Manager" and not self.is_zope_manager:\n canAssign = False\n- roleList[role] = {\'canAssign\': canAssign,\n- \'explicit\': role in explicitlyAssignedRoles,\n- \'inherited\': role in allInheritedRoles.get(userId, ())}\n+ roleList[role] = {\n+ "canAssign": canAssign,\n+ "explicit": role in explicitlyAssignedRoles,\n+ "inherited": role in allInheritedRoles.get(userId, ()),\n+ }\n \n canDelete = user.canDelete()\n canPasswordSet = user.canPasswordSet()\n- if roleList[\'Manager\'][\'explicit\'] or roleList[\'Manager\'][\'inherited\']:\n+ if roleList["Manager"]["explicit"] or roleList["Manager"]["inherited"]:\n if not self.is_zope_manager:\n canDelete = False\n canPasswordSet = False\n \n- user_info[\'roles\'] = roleList\n- user_info[\'fullname\'] = user.getProperty(\'fullname\', \'\')\n- user_info[\'email\'] = user.getProperty(\'email\', \'\')\n- user_info[\'can_delete\'] = canDelete\n- user_info[\'can_set_email\'] = user.canWriteProperty(\'email\')\n- user_info[\'can_set_password\'] = canPasswordSet\n+ user_info["roles"] = roleList\n+ user_info["fullname"] = user.getProperty("fullname", "")\n+ user_info["email"] = user.getProperty("email", "")\n+ user_info["can_delete"] = canDelete\n+ user_info["can_set_email"] = user.canWriteProperty("email")\n+ user_info["can_set_password"] = canPasswordSet\n results.append(user_info)\n \n # Sort the users by fullname\n- results.sort(key=lambda x: x is not None and x[\n- \'fullname\'] is not None and normalizeString(x[\'fullname\']) or \'\')\n+ results.sort(\n+ key=lambda x: x is not None\n+ and x["fullname"] is not None\n+ and normalizeString(x["fullname"])\n+ or ""\n+ )\n \n # Reset the request variable, just in case.\n- self.request.set(\'__ignore_group_roles__\', False)\n+ self.request.set("__ignore_group_roles__", False)\n return results\n \n def manageUser(self, users=[], resetpassword=[], delete=[]):\n@@ -141,11 +155,11 @@ def manageUser(self, users=[], resetpassword=[], delete=[]):\n \n if users:\n context = aq_inner(self.context)\n- acl_users = getToolByName(context, \'acl_users\')\n- mtool = getToolByName(context, \'portal_membership\')\n- regtool = getToolByName(context, \'portal_registration\')\n+ acl_users = getToolByName(context, "acl_users")\n+ mtool = getToolByName(context, "portal_membership")\n+ regtool = getToolByName(context, "portal_registration")\n \n- utils = getToolByName(context, \'plone_utils\')\n+ utils = getToolByName(context, "plone_utils")\n \n users_with_reset_passwords = []\n \n@@ -157,35 +171,41 @@ def manageUser(self, users=[], resetpassword=[], delete=[]):\n member = mtool.getMemberById(user.id)\n current_roles = member.getRoles()\n # If email address was changed, set the new one\n- if hasattr(user, \'email\'):\n+ if hasattr(user, "email"):\n # If the email field was disabled (ie: non-writeable), the\n # property might not exist.\n- if user.email != member.getProperty(\'email\'):\n+ if user.email != member.getProperty("email"):\n utils.setMemberProperties(\n- member, REQUEST=context.REQUEST, email=user.email)\n- utils.addPortalMessage(_(\'Changes applied.\'))\n+ member, REQUEST=context.REQUEST, email=user.email\n+ )\n+ utils.addPortalMessage(_("Changes applied."))\n \n # If reset password has been checked email user a new password\n pw = None\n- if hasattr(user, \'resetpassword\'):\n- if \'Manager\' in current_roles and not self.is_zope_manager:\n+ if hasattr(user, "resetpassword"):\n+ if "Manager" in current_roles and not self.is_zope_manager:\n raise Forbidden\n- if not context.unrestrictedTraverse(\'@@overview-controlpanel\').mailhost_warning():\n+ if not context.unrestrictedTraverse(\n+ "@@overview-controlpanel"\n+ ).mailhost_warning():\n pw = regtool.generatePassword()\n else:\n utils.addPortalMessage(\n- _(\'No mailhost defined. Unable to reset passwords.\'), type=\'error\')\n+ _("No mailhost defined. Unable to reset passwords."),\n+ type="error",\n+ )\n \n- roles = user.get(\'roles\', [])\n+ roles = user.get("roles", [])\n if not self.is_zope_manager:\n # don\'t allow adding or removing the Manager role\n- if (\'Manager\' in roles) != (\'Manager\' in current_roles):\n+ if ("Manager" in roles) != ("Manager" in current_roles):\n raise Forbidden\n \n acl_users.userFolderEditUser(\n- user.id, pw, roles, member.getDomains(), REQUEST=context.REQUEST)\n+ user.id, pw, roles, member.getDomains(), REQUEST=context.REQUEST\n+ )\n if pw:\n- context.REQUEST.form[\'new_password\'] = pw\n+ context.REQUEST.form["new_password"] = pw\n regtool.mailPassword(user.id, context.REQUEST)\n users_with_reset_passwords.append(user.id)\n \n@@ -196,17 +216,17 @@ def manageUser(self, users=[], resetpassword=[], delete=[]):\n "reset_passwords_msg",\n default="The following users have been sent an e-mail with link to reset their password: ${user_ids}",\n mapping={\n- "user_ids": \', \'.join(users_with_reset_passwords),\n+ "user_ids": ", ".join(users_with_reset_passwords),\n },\n )\n utils.addPortalMessage(reset_passwords_message)\n- utils.addPortalMessage(_(\'Changes applied.\'))\n+ utils.addPortalMessage(_("Changes applied."))\n \n def deleteMembers(self, member_ids):\n # this method exists to bypass the \'Manage Users\' permission check\n # in the CMF member tool\'s version\n context = aq_inner(self.context)\n- mtool = getToolByName(self.context, \'portal_membership\')\n+ mtool = getToolByName(self.context, "portal_membership")\n \n # Delete members in acl_users.\n acl_users = context.acl_users\n@@ -220,24 +240,22 @@ def deleteMembers(self, member_ids):\n else:\n if not member.canDelete():\n raise Forbidden\n- if \'Manager\' in member.getRoles() and not self.is_zope_manager:\n+ if "Manager" in member.getRoles() and not self.is_zope_manager:\n raise Forbidden\n try:\n acl_users.userFolderDelUsers(member_ids)\n except (AttributeError, NotImplementedError):\n- raise NotImplementedError(\'The underlying User Folder \'\n- \'doesn\\\'t support deleting members.\')\n+ raise NotImplementedError(\n+ "The underlying User Folder " "doesn\'t support deleting members."\n+ )\n \n # Delete member data in portal_memberdata.\n- mdtool = getToolByName(context, \'portal_memberdata\', None)\n+ mdtool = getToolByName(context, "portal_memberdata", None)\n if mdtool is not None:\n for member_id in member_ids:\n mdtool.deleteMemberData(member_id)\n \n # Delete members\' local roles.\n mtool.deleteLocalRoles(\n- getUtility(ISiteRoot),\n- member_ids,\n- reindex=1,\n- recursive=1\n+ getUtility(ISiteRoot), member_ids, reindex=1, recursive=1\n )\ndiff --git a/Products/CMFPlone/controlpanel/events.py b/Products/CMFPlone/controlpanel/events.py\nindex 4d4d34df0f..b7fbc26cd8 100644\n--- a/Products/CMFPlone/controlpanel/events.py\n+++ b/Products/CMFPlone/controlpanel/events.py\n@@ -16,7 +16,6 @@\n \n @implementer(IConfigurationChangedEvent)\n class ConfigurationChangedEvent:\n-\n def __init__(self, context, data):\n self.context = context\n self.data = data\n@@ -38,25 +37,23 @@ def handle_enable_self_reg(obj, event):\n added to ``Anonymous`` role to allow self registration for anonymous\n users. If the setting is disabled, this permission is removed.\n """\n- if event.record.fieldName != \'enable_self_reg\':\n+ if event.record.fieldName != "enable_self_reg":\n return\n \n portal = getSite()\n value = event.newValue\n- app_perms = portal.rolesOfPermission(\n- permission=\'Add portal member\')\n+ app_perms = portal.rolesOfPermission(permission="Add portal member")\n reg_roles = []\n \n for app_perm in app_perms:\n- if app_perm[\'selected\'] == \'SELECTED\':\n- reg_roles.append(app_perm[\'name\'])\n- if value is True and \'Anonymous\' not in reg_roles:\n- reg_roles.append(\'Anonymous\')\n- if value is False and \'Anonymous\' in reg_roles:\n- reg_roles.remove(\'Anonymous\')\n+ if app_perm["selected"] == "SELECTED":\n+ reg_roles.append(app_perm["name"])\n+ if value is True and "Anonymous" not in reg_roles:\n+ reg_roles.append("Anonymous")\n+ if value is False and "Anonymous" in reg_roles:\n+ reg_roles.remove("Anonymous")\n \n- portal.manage_permission(\'Add portal member\', roles=reg_roles,\n- acquire=0)\n+ portal.manage_permission("Add portal member", roles=reg_roles, acquire=0)\n \n \n @adapter(ISecuritySchema, IRecordModifiedEvent)\n@@ -67,42 +64,42 @@ def handle_enable_user_folders(obj, event):\n If the setting is enabled, a new user action is added with a link to\n the personal folder. If the setting is disabled, the action is hidden.\n """\n- if event.record.fieldName != \'enable_user_folders\':\n+ if event.record.fieldName != "enable_user_folders":\n return\n \n portal = getSite()\n value = event.newValue\n \n- membership = getToolByName(portal, \'portal_membership\')\n+ membership = getToolByName(portal, "portal_membership")\n membership.memberareaCreationFlag = value\n \n # support the \'my folder\' user action #8417\n- portal_actions = getToolByName(portal, \'portal_actions\', None)\n+ portal_actions = getToolByName(portal, "portal_actions", None)\n if portal_actions is not None:\n- object_category = getattr(portal_actions, \'user\', None)\n- if value and not safe_hasattr(object_category, \'mystuff\'):\n+ object_category = getattr(portal_actions, "user", None)\n+ if value and not safe_hasattr(object_category, "mystuff"):\n # add action\n _add_mystuff_action(object_category)\n- elif safe_hasattr(object_category, \'mystuff\'):\n- a = getattr(object_category, \'mystuff\')\n- a.visible = bool(value) # show/hide action\n+ elif safe_hasattr(object_category, "mystuff"):\n+ a = getattr(object_category, "mystuff")\n+ a.visible = bool(value) # show/hide action\n \n \n def _add_mystuff_action(object_category):\n new_action = Action(\n- \'mystuff\',\n- title=_(\'My Folder\'),\n- description=\'\',\n- url_expr=\'string:${portal/portal_membership/getHomeUrl}\',\n- available_expr=\'python:(member is not None) and \\\n- (portal.portal_membership.getHomeFolder() is not None) \',\n- permissions=(\'View\',),\n+ "mystuff",\n+ title=_("My Folder"),\n+ description="",\n+ url_expr="string:${portal/portal_membership/getHomeUrl}",\n+ available_expr="python:(member is not None) and \\\n+ (portal.portal_membership.getHomeFolder() is not None) ",\n+ permissions=("View",),\n visible=True,\n- i18n_domain=\'plone\'\n+ i18n_domain="plone",\n )\n- object_category._setObject(\'mystuff\', new_action)\n+ object_category._setObject("mystuff", new_action)\n # move action to top, at least before the logout action\n- object_category.moveObjectsToTop(\'mystuff\')\n+ object_category.moveObjectsToTop("mystuff")\n \n \n @adapter(ISecuritySchema, IRecordModifiedEvent)\n@@ -114,7 +111,7 @@ def handle_use_email_as_login(obj, event):\n to email. If the setting is disabled, then the login names are migrated\n back to user ids.\n """\n- if event.record.fieldName != \'use_email_as_login\':\n+ if event.record.fieldName != "use_email_as_login":\n return\n \n value = event.newValue\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_actions.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_actions.py\nindex 4261a8e4e8..09f688a586 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_actions.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_actions.py\n@@ -11,29 +11,28 @@ class PortalActionsIntegrationTest(unittest.TestCase):\n layer = PRODUCTS_CMFPLONE_INTEGRATION_TESTING\n \n def setUp(self): # NOQA\n- self.portal = self.layer[\'portal\']\n- self.request = self.layer[\'request\']\n- self.portal_actions = getToolByName(self.portal, \'portal_actions\')\n+ self.portal = self.layer["portal"]\n+ self.request = self.layer["request"]\n+ self.portal_actions = getToolByName(self.portal, "portal_actions")\n \n def test_actions_controlpanel_view(self):\n- view = getMultiAdapter((self.portal, self.portal.REQUEST),\n- name="actions-controlpanel")\n+ view = getMultiAdapter(\n+ (self.portal, self.portal.REQUEST), name="actions-controlpanel"\n+ )\n self.assertTrue(view())\n \n def test_actions_in_controlpanel(self):\n self.controlpanel = getToolByName(self.portal, "portal_controlpanel")\n- self.assertTrue(\'ActionSettings\' in [\n- a.getAction(self)[\'id\']\n- for a in self.controlpanel.listActions()\n- ])\n+ self.assertTrue(\n+ "ActionSettings"\n+ in [a.getAction(self)["id"] for a in self.controlpanel.listActions()]\n+ )\n \n def test_edit_action_controlpanel_view(self):\n action = self.portal_actions.site_actions.sitemap\n- view = getMultiAdapter((action, self.portal.REQUEST),\n- name="action-form")\n+ view = getMultiAdapter((action, self.portal.REQUEST), name="action-form")\n self.assertTrue(view())\n \n def test_new_action_controlpanel_view(self):\n- view = getMultiAdapter((self.portal, self.portal.REQUEST),\n- name="new-action")\n+ view = getMultiAdapter((self.portal, self.portal.REQUEST), name="new-action")\n self.assertTrue(view())\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_editing_adapter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_editing_adapter.py\nindex 4cb4c82690..a44d63465a 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_editing_adapter.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_editing_adapter.py\n@@ -10,103 +10,70 @@\n \n \n class EditingControlPanelAdapterTest(unittest.TestCase):\n-\n layer = PRODUCTS_CMFPLONE_INTEGRATION_TESTING\n \n def setUp(self):\n- self.portal = self.layer[\'portal\']\n- self.request = self.layer[\'request\']\n- setRoles(self.portal, TEST_USER_ID, [\'Manager\'])\n+ self.portal = self.layer["portal"]\n+ self.request = self.layer["request"]\n+ setRoles(self.portal, TEST_USER_ID, ["Manager"])\n registry = getUtility(IRegistry)\n- self.settings = registry.forInterface(IEditingSchema, prefix=\'plone\')\n+ self.settings = registry.forInterface(IEditingSchema, prefix="plone")\n \n def test_adapter_lookup(self):\n self.assertTrue(getAdapter(self.portal, IEditingSchema))\n \n def test_get_enable_link_integrity_checks_setting(self):\n self.assertEqual(\n- getAdapter(self.portal, IEditingSchema).enable_link_integrity_checks, # noqa\n- True\n+ getAdapter(\n+ self.portal, IEditingSchema\n+ ).enable_link_integrity_checks, # noqa\n+ True,\n )\n self.settings.enable_link_integrity_checks = False\n self.assertEqual(\n- getAdapter(self.portal, IEditingSchema).enable_link_integrity_checks, # noqa\n- False\n+ getAdapter(\n+ self.portal, IEditingSchema\n+ ).enable_link_integrity_checks, # noqa\n+ False,\n )\n \n def test_set_enable_link_integrity_checks_setting(self):\n- self.assertEqual(\n- self.settings.enable_link_integrity_checks,\n- True\n- )\n- getAdapter(self.portal, IEditingSchema).enable_link_integrity_checks = False # noqa\n- self.assertEqual(\n- self.settings.enable_link_integrity_checks,\n- False\n- )\n+ self.assertEqual(self.settings.enable_link_integrity_checks, True)\n+ getAdapter(\n+ self.portal, IEditingSchema\n+ ).enable_link_integrity_checks = False # noqa\n+ self.assertEqual(self.settings.enable_link_integrity_checks, False)\n \n def test_get_ext_editor_setting(self):\n- self.assertEqual(\n- getAdapter(self.portal, IEditingSchema).ext_editor,\n- False\n- )\n+ self.assertEqual(getAdapter(self.portal, IEditingSchema).ext_editor, False)\n self.settings.ext_editor = True\n- self.assertEqual(\n- getAdapter(self.portal, IEditingSchema).ext_editor,\n- True\n- )\n+ self.assertEqual(getAdapter(self.portal, IEditingSchema).ext_editor, True)\n \n def test_set_ext_editor_setting(self):\n- self.assertEqual(\n- self.settings.ext_editor,\n- False\n- )\n+ self.assertEqual(self.settings.ext_editor, False)\n getAdapter(self.portal, IEditingSchema).ext_editor = True\n- self.assertEqual(\n- self.settings.ext_editor,\n- True\n- )\n+ self.assertEqual(self.settings.ext_editor, True)\n \n def test_get_default_editor_setting(self):\n self.assertEqual(\n- getAdapter(self.portal, IEditingSchema).default_editor,\n- \'TinyMCE\'\n- )\n- self.settings.default_editor = \'None\'\n- self.assertEqual(\n- getAdapter(self.portal, IEditingSchema).default_editor,\n- \'None\'\n+ getAdapter(self.portal, IEditingSchema).default_editor, "TinyMCE"\n )\n+ self.settings.default_editor = "None"\n+ self.assertEqual(getAdapter(self.portal, IEditingSchema).default_editor, "None")\n \n def test_set_default_editor_setting(self):\n- self.assertEqual(\n- self.settings.default_editor,\n- \'TinyMCE\'\n- )\n- getAdapter(self.portal, IEditingSchema).default_editor = \'None\'\n- self.assertEqual(\n- self.settings.default_editor,\n- \'None\'\n- )\n+ self.assertEqual(self.settings.default_editor, "TinyMCE")\n+ getAdapter(self.portal, IEditingSchema).default_editor = "None"\n+ self.assertEqual(self.settings.default_editor, "None")\n \n def test_get_lock_on_ttw_edit_setting(self):\n- self.assertEqual(\n- getAdapter(self.portal, IEditingSchema).lock_on_ttw_edit,\n- True\n- )\n+ self.assertEqual(getAdapter(self.portal, IEditingSchema).lock_on_ttw_edit, True)\n self.settings.lock_on_ttw_edit = False\n self.assertEqual(\n- getAdapter(self.portal, IEditingSchema).lock_on_ttw_edit,\n- False\n+ getAdapter(self.portal, IEditingSchema).lock_on_ttw_edit, False\n )\n \n def test_set_lock_on_ttw_edit_setting(self):\n- self.assertEqual(\n- self.settings.lock_on_ttw_edit,\n- True\n- )\n+ self.assertEqual(self.settings.lock_on_ttw_edit, True)\n getAdapter(self.portal, IEditingSchema).lock_on_ttw_edit = False\n- self.assertEqual(\n- self.settings.lock_on_ttw_edit,\n- False\n- )\n+ self.assertEqual(self.settings.lock_on_ttw_edit, False)\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_filter_adapter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_filter_adapter.py\nindex 1558e1d814..f6f3794f91 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_filter_adapter.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_filter_adapter.py\n@@ -10,13 +10,12 @@\n \n \n class FilterControlPanelAdapterTest(unittest.TestCase):\n-\n layer = PRODUCTS_CMFPLONE_INTEGRATION_TESTING\n \n def setUp(self):\n- self.portal = self.layer[\'portal\']\n- self.request = self.layer[\'request\']\n- setRoles(self.portal, TEST_USER_ID, [\'Manager\'])\n+ self.portal = self.layer["portal"]\n+ self.request = self.layer["request"]\n+ setRoles(self.portal, TEST_USER_ID, ["Manager"])\n registry = getUtility(IRegistry)\n self.settings = registry.forInterface(IFilterSchema, prefix="plone")\n \n@@ -24,45 +23,31 @@ def test_adapter_lookup(self):\n self.assertTrue(getAdapter(self.portal, IFilterSchema))\n \n def test_get_nasty_tags(self):\n- self.settings.nasty_tags = [\'foo\', \'bar\']\n+ self.settings.nasty_tags = ["foo", "bar"]\n self.assertEqual(\n- getAdapter(self.portal, IFilterSchema).nasty_tags,\n- [\'foo\', \'bar\']\n+ getAdapter(self.portal, IFilterSchema).nasty_tags, ["foo", "bar"]\n )\n \n def test_set_nasty_tags(self):\n- getAdapter(self.portal, IFilterSchema).nasty_tags = [\'foo\', \'bar\']\n- self.assertEqual(\n- self.settings.nasty_tags,\n- [\'foo\', \'bar\']\n- )\n+ getAdapter(self.portal, IFilterSchema).nasty_tags = ["foo", "bar"]\n+ self.assertEqual(self.settings.nasty_tags, ["foo", "bar"])\n \n def test_get_valid_tags(self):\n- self.settings.valid_tags = [\'foo\', \'bar\']\n+ self.settings.valid_tags = ["foo", "bar"]\n self.assertEqual(\n- getAdapter(self.portal, IFilterSchema).valid_tags,\n- [\'foo\', \'bar\']\n+ getAdapter(self.portal, IFilterSchema).valid_tags, ["foo", "bar"]\n )\n \n def test_set_valid_tags(self):\n- getAdapter(self.portal, IFilterSchema).valid_tags = [\'foo\', \'bar\']\n- self.assertEqual(\n- self.settings.valid_tags,\n- [\'foo\', \'bar\']\n- )\n+ getAdapter(self.portal, IFilterSchema).valid_tags = ["foo", "bar"]\n+ self.assertEqual(self.settings.valid_tags, ["foo", "bar"])\n \n def test_get_custom_attributes(self):\n- self.settings.custom_attributes = [\'foo\', \'bar\']\n+ self.settings.custom_attributes = ["foo", "bar"]\n self.assertEqual(\n- getAdapter(self.portal, IFilterSchema).custom_attributes,\n- [\'foo\', \'bar\']\n+ getAdapter(self.portal, IFilterSchema).custom_attributes, ["foo", "bar"]\n )\n \n def test_set_custom_attributes(self):\n- getAdapter(self.portal, IFilterSchema).custom_attributes = [\n- \'foo\', \'bar\'\n- ]\n- self.assertEqual(\n- self.settings.custom_attributes,\n- [\'foo\', \'bar\']\n- )\n+ getAdapter(self.portal, IFilterSchema).custom_attributes = ["foo", "bar"]\n+ self.assertEqual(self.settings.custom_attributes, ["foo", "bar"])\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_language_adapter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_language_adapter.py\nindex 724b1f20f4..410d94f812 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_language_adapter.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_language_adapter.py\n@@ -10,302 +10,178 @@\n \n \n class LanguageControlPanelAdapterTest(unittest.TestCase):\n-\n layer = PRODUCTS_CMFPLONE_INTEGRATION_TESTING\n \n def setUp(self):\n- self.portal = self.layer[\'portal\']\n- self.request = self.layer[\'request\']\n- setRoles(self.portal, TEST_USER_ID, [\'Manager\'])\n+ self.portal = self.layer["portal"]\n+ self.request = self.layer["request"]\n+ setRoles(self.portal, TEST_USER_ID, ["Manager"])\n registry = getUtility(IRegistry)\n- self.settings = registry.forInterface(\n- ILanguageSchema, prefix="plone")\n+ self.settings = registry.forInterface(ILanguageSchema, prefix="plone")\n \n def test_adapter_lookup(self):\n self.assertTrue(getAdapter(self.portal, ILanguageSchema))\n \n def test_get_default_language(self):\n self.assertEqual(\n- getAdapter(self.portal, ILanguageSchema).default_language,\n- \'en\'\n+ getAdapter(self.portal, ILanguageSchema).default_language, "en"\n )\n- self.settings.default_language = \'de\'\n+ self.settings.default_language = "de"\n self.assertEqual(\n- getAdapter(self.portal, ILanguageSchema).default_language,\n- \'de\'\n+ getAdapter(self.portal, ILanguageSchema).default_language, "de"\n )\n \n def test_set_default_language(self):\n- self.assertEqual(\n- self.settings.default_language,\n- \'en\'\n- )\n- getAdapter(self.portal, ILanguageSchema).default_language = \'de\'\n- self.assertEqual(\n- self.settings.default_language,\n- \'de\'\n- )\n+ self.assertEqual(self.settings.default_language, "en")\n+ getAdapter(self.portal, ILanguageSchema).default_language = "de"\n+ self.assertEqual(self.settings.default_language, "de")\n \n def test_get_available_languages(self):\n self.assertEqual(\n- getAdapter(self.portal, ILanguageSchema).available_languages,\n- [\'en\']\n+ getAdapter(self.portal, ILanguageSchema).available_languages, ["en"]\n )\n- self.settings.available_languages = [\'en\', \'de\']\n+ self.settings.available_languages = ["en", "de"]\n self.assertEqual(\n- getAdapter(self.portal, ILanguageSchema).available_languages,\n- [\'en\', \'de\']\n+ getAdapter(self.portal, ILanguageSchema).available_languages, ["en", "de"]\n )\n \n def test_set_available_languages(self):\n- self.assertEqual(\n- self.settings.available_languages,\n- [\'en\']\n- )\n- getAdapter(self.portal, ILanguageSchema).available_languages = [\n- \'de\', \'en\']\n- self.assertEqual(\n- self.settings.available_languages,\n- [\'de\', \'en\']\n- )\n+ self.assertEqual(self.settings.available_languages, ["en"])\n+ getAdapter(self.portal, ILanguageSchema).available_languages = ["de", "en"]\n+ self.assertEqual(self.settings.available_languages, ["de", "en"])\n \n def test_get_use_combined_language_codes(self):\n self.assertEqual(\n- getAdapter(\n- self.portal, ILanguageSchema).use_combined_language_codes,\n- True\n+ getAdapter(self.portal, ILanguageSchema).use_combined_language_codes, True\n )\n self.settings.use_combined_language_codes = False\n self.assertEqual(\n- getAdapter(\n- self.portal, ILanguageSchema).use_combined_language_codes,\n- False\n+ getAdapter(self.portal, ILanguageSchema).use_combined_language_codes, False\n )\n \n def test_set_use_combined_language_codes(self):\n- self.assertEqual(\n- self.settings.use_combined_language_codes,\n- True\n- )\n- getAdapter(\n- self.portal, ILanguageSchema).use_combined_language_codes = False\n- self.assertEqual(\n- self.settings.use_combined_language_codes,\n- False\n- )\n+ self.assertEqual(self.settings.use_combined_language_codes, True)\n+ getAdapter(self.portal, ILanguageSchema).use_combined_language_codes = False\n+ self.assertEqual(self.settings.use_combined_language_codes, False)\n \n def test_get_display_flags(self):\n- self.assertEqual(\n- getAdapter(\n- self.portal, ILanguageSchema).display_flags,\n- False\n- )\n+ self.assertEqual(getAdapter(self.portal, ILanguageSchema).display_flags, False)\n self.settings.display_flags = True\n- self.assertEqual(\n- getAdapter(self.portal, ILanguageSchema).display_flags,\n- True\n- )\n+ self.assertEqual(getAdapter(self.portal, ILanguageSchema).display_flags, True)\n \n def test_set_display_flags(self):\n- self.assertEqual(\n- self.settings.display_flags,\n- False\n- )\n- getAdapter(\n- self.portal, ILanguageSchema).display_flags = True\n- self.assertEqual(\n- self.settings.display_flags,\n- True\n- )\n+ self.assertEqual(self.settings.display_flags, False)\n+ getAdapter(self.portal, ILanguageSchema).display_flags = True\n+ self.assertEqual(self.settings.display_flags, True)\n \n def test_get_use_content_negotiation(self):\n self.assertEqual(\n- getAdapter(\n- self.portal, ILanguageSchema).use_content_negotiation,\n- False\n+ getAdapter(self.portal, ILanguageSchema).use_content_negotiation, False\n )\n self.settings.use_content_negotiation = True\n self.assertEqual(\n- getAdapter(self.portal, ILanguageSchema).use_content_negotiation,\n- True\n+ getAdapter(self.portal, ILanguageSchema).use_content_negotiation, True\n )\n \n def test_set_use_content_negotiation(self):\n- self.assertEqual(\n- self.settings.use_content_negotiation,\n- False\n- )\n- getAdapter(\n- self.portal, ILanguageSchema).use_content_negotiation = True\n- self.assertEqual(\n- self.settings.use_content_negotiation,\n- True\n- )\n+ self.assertEqual(self.settings.use_content_negotiation, False)\n+ getAdapter(self.portal, ILanguageSchema).use_content_negotiation = True\n+ self.assertEqual(self.settings.use_content_negotiation, True)\n \n def test_get_use_path_negotiation(self):\n self.assertEqual(\n- getAdapter(\n- self.portal, ILanguageSchema).use_path_negotiation,\n- False\n+ getAdapter(self.portal, ILanguageSchema).use_path_negotiation, False\n )\n self.settings.use_path_negotiation = True\n self.assertEqual(\n- getAdapter(self.portal, ILanguageSchema).use_path_negotiation,\n- True\n+ getAdapter(self.portal, ILanguageSchema).use_path_negotiation, True\n )\n \n def test_set_use_path_negotiation(self):\n- self.assertEqual(\n- self.settings.use_path_negotiation,\n- False\n- )\n- getAdapter(\n- self.portal, ILanguageSchema).use_path_negotiation = True\n- self.assertEqual(\n- self.settings.use_path_negotiation,\n- True\n- )\n+ self.assertEqual(self.settings.use_path_negotiation, False)\n+ getAdapter(self.portal, ILanguageSchema).use_path_negotiation = True\n+ self.assertEqual(self.settings.use_path_negotiation, True)\n \n def test_get_use_cookie_negotiation(self):\n self.assertEqual(\n- getAdapter(\n- self.portal, ILanguageSchema).use_cookie_negotiation,\n- False\n+ getAdapter(self.portal, ILanguageSchema).use_cookie_negotiation, False\n )\n self.settings.use_cookie_negotiation = True\n self.assertEqual(\n- getAdapter(self.portal, ILanguageSchema).use_cookie_negotiation,\n- True\n+ getAdapter(self.portal, ILanguageSchema).use_cookie_negotiation, True\n )\n \n def test_set_use_cookie_negotiation(self):\n- self.assertEqual(\n- self.settings.use_cookie_negotiation,\n- False\n- )\n- getAdapter(\n- self.portal, ILanguageSchema).use_cookie_negotiation = True\n- self.assertEqual(\n- self.settings.use_cookie_negotiation,\n- True\n- )\n+ self.assertEqual(self.settings.use_cookie_negotiation, False)\n+ getAdapter(self.portal, ILanguageSchema).use_cookie_negotiation = True\n+ self.assertEqual(self.settings.use_cookie_negotiation, True)\n \n def test_get_authenticated_users_only(self):\n self.assertEqual(\n- getAdapter(\n- self.portal, ILanguageSchema).authenticated_users_only,\n- False\n+ getAdapter(self.portal, ILanguageSchema).authenticated_users_only, False\n )\n self.settings.authenticated_users_only = True\n self.assertEqual(\n- getAdapter(self.portal, ILanguageSchema).authenticated_users_only,\n- True\n+ getAdapter(self.portal, ILanguageSchema).authenticated_users_only, True\n )\n \n def test_set_authenticated_users_only(self):\n- self.assertEqual(\n- self.settings.authenticated_users_only,\n- False\n- )\n- getAdapter(\n- self.portal, ILanguageSchema).authenticated_users_only = True\n- self.assertEqual(\n- self.settings.authenticated_users_only,\n- True\n- )\n+ self.assertEqual(self.settings.authenticated_users_only, False)\n+ getAdapter(self.portal, ILanguageSchema).authenticated_users_only = True\n+ self.assertEqual(self.settings.authenticated_users_only, True)\n \n def test_get_set_cookie_always(self):\n self.assertEqual(\n- getAdapter(\n- self.portal, ILanguageSchema).set_cookie_always,\n- False\n+ getAdapter(self.portal, ILanguageSchema).set_cookie_always, False\n )\n self.settings.set_cookie_always = True\n self.assertEqual(\n- getAdapter(self.portal, ILanguageSchema).set_cookie_always,\n- True\n+ getAdapter(self.portal, ILanguageSchema).set_cookie_always, True\n )\n \n def test_set_set_cookie_always(self):\n- self.assertEqual(\n- self.settings.set_cookie_always,\n- False\n- )\n- getAdapter(\n- self.portal, ILanguageSchema).set_cookie_always = True\n- self.assertEqual(\n- self.settings.set_cookie_always,\n- True\n- )\n+ self.assertEqual(self.settings.set_cookie_always, False)\n+ getAdapter(self.portal, ILanguageSchema).set_cookie_always = True\n+ self.assertEqual(self.settings.set_cookie_always, True)\n \n def test_get_use_subdomain_negotiation(self):\n self.assertEqual(\n- getAdapter(\n- self.portal, ILanguageSchema).use_subdomain_negotiation,\n- False\n+ getAdapter(self.portal, ILanguageSchema).use_subdomain_negotiation, False\n )\n self.settings.use_subdomain_negotiation = True\n self.assertEqual(\n- getAdapter(self.portal, ILanguageSchema).use_subdomain_negotiation,\n- True\n+ getAdapter(self.portal, ILanguageSchema).use_subdomain_negotiation, True\n )\n \n def test_set_use_subdomain_negotiation(self):\n- self.assertEqual(\n- self.settings.use_subdomain_negotiation,\n- False\n- )\n- getAdapter(\n- self.portal, ILanguageSchema).use_subdomain_negotiation = True\n- self.assertEqual(\n- self.settings.use_subdomain_negotiation,\n- True\n- )\n+ self.assertEqual(self.settings.use_subdomain_negotiation, False)\n+ getAdapter(self.portal, ILanguageSchema).use_subdomain_negotiation = True\n+ self.assertEqual(self.settings.use_subdomain_negotiation, True)\n \n def test_get_use_cctld_negotiation(self):\n self.assertEqual(\n- getAdapter(\n- self.portal, ILanguageSchema).use_cctld_negotiation,\n- False\n+ getAdapter(self.portal, ILanguageSchema).use_cctld_negotiation, False\n )\n self.settings.use_cctld_negotiation = True\n self.assertEqual(\n- getAdapter(self.portal, ILanguageSchema).use_cctld_negotiation,\n- True\n+ getAdapter(self.portal, ILanguageSchema).use_cctld_negotiation, True\n )\n \n def test_set_use_cctld_negotiation(self):\n- self.assertEqual(\n- self.settings.use_cctld_negotiation,\n- False\n- )\n- getAdapter(\n- self.portal, ILanguageSchema).use_cctld_negotiation = True\n- self.assertEqual(\n- self.settings.use_cctld_negotiation,\n- True\n- )\n+ self.assertEqual(self.settings.use_cctld_negotiation, False)\n+ getAdapter(self.portal, ILanguageSchema).use_cctld_negotiation = True\n+ self.assertEqual(self.settings.use_cctld_negotiation, True)\n \n def test_get_use_request_negotiation(self):\n self.assertEqual(\n- getAdapter(\n- self.portal, ILanguageSchema).use_request_negotiation,\n- False\n+ getAdapter(self.portal, ILanguageSchema).use_request_negotiation, False\n )\n self.settings.use_request_negotiation = True\n self.assertEqual(\n- getAdapter(self.portal, ILanguageSchema).use_request_negotiation,\n- True\n+ getAdapter(self.portal, ILanguageSchema).use_request_negotiation, True\n )\n \n def test_set_use_request_negotiation(self):\n- self.assertEqual(\n- self.settings.use_request_negotiation,\n- False\n- )\n- getAdapter(\n- self.portal, ILanguageSchema).use_request_negotiation = True\n- self.assertEqual(\n- self.settings.use_request_negotiation,\n- True\n- )\n+ self.assertEqual(self.settings.use_request_negotiation, False)\n+ getAdapter(self.portal, ILanguageSchema).use_request_negotiation = True\n+ self.assertEqual(self.settings.use_request_negotiation, True)\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_mail_adapter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_mail_adapter.py\nindex ecf2feb855..9eef6ce6f8 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_mail_adapter.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_mail_adapter.py\n@@ -10,149 +10,78 @@\n \n \n class MailControlPanelAdapterTest(unittest.TestCase):\n-\n layer = PRODUCTS_CMFPLONE_INTEGRATION_TESTING\n \n def setUp(self):\n- self.portal = self.layer[\'portal\']\n- self.request = self.layer[\'request\']\n- setRoles(self.portal, TEST_USER_ID, [\'Manager\'])\n+ self.portal = self.layer["portal"]\n+ self.request = self.layer["request"]\n+ setRoles(self.portal, TEST_USER_ID, ["Manager"])\n registry = getUtility(IRegistry)\n- self.mail_settings = registry.forInterface(\n- IMailSchema, prefix="plone")\n+ self.mail_settings = registry.forInterface(IMailSchema, prefix="plone")\n \n def test_adapter_lookup(self):\n self.assertTrue(getAdapter(self.portal, IMailSchema))\n \n def test_get_smtp_host(self):\n- self.assertEqual(\n- getAdapter(self.portal, IMailSchema).smtp_host,\n- \'localhost\'\n- )\n- self.mail_settings.smtp_host = \'example.com\'\n- self.assertEqual(\n- getAdapter(self.portal, IMailSchema).smtp_host,\n- \'example.com\'\n- )\n+ self.assertEqual(getAdapter(self.portal, IMailSchema).smtp_host, "localhost")\n+ self.mail_settings.smtp_host = "example.com"\n+ self.assertEqual(getAdapter(self.portal, IMailSchema).smtp_host, "example.com")\n \n def test_set_smtp_host(self):\n- self.assertEqual(\n- self.mail_settings.smtp_host,\n- \'localhost\'\n- )\n- getAdapter(self.portal, IMailSchema).smtp_host = \'example.com\'\n- self.assertEqual(\n- self.mail_settings.smtp_host,\n- \'example.com\'\n- )\n+ self.assertEqual(self.mail_settings.smtp_host, "localhost")\n+ getAdapter(self.portal, IMailSchema).smtp_host = "example.com"\n+ self.assertEqual(self.mail_settings.smtp_host, "example.com")\n \n def test_get_smtp_port(self):\n- self.assertEqual(\n- getAdapter(self.portal, IMailSchema).smtp_port,\n- 25\n- )\n+ self.assertEqual(getAdapter(self.portal, IMailSchema).smtp_port, 25)\n self.mail_settings.smtp_port = 88\n- self.assertEqual(\n- getAdapter(self.portal, IMailSchema).smtp_port,\n- 88\n- )\n+ self.assertEqual(getAdapter(self.portal, IMailSchema).smtp_port, 88)\n \n def test_set_smtp_port(self):\n- self.assertEqual(\n- self.mail_settings.smtp_port,\n- 25\n- )\n+ self.assertEqual(self.mail_settings.smtp_port, 25)\n getAdapter(self.portal, IMailSchema).smtp_port = 88\n- self.assertEqual(\n- self.mail_settings.smtp_port,\n- 88\n- )\n+ self.assertEqual(self.mail_settings.smtp_port, 88)\n \n def test_get_smtp_userid(self):\n+ self.assertEqual(getAdapter(self.portal, IMailSchema).smtp_userid, None)\n+ self.mail_settings.smtp_userid = "john@example.com"\n self.assertEqual(\n- getAdapter(self.portal, IMailSchema).smtp_userid,\n- None\n- )\n- self.mail_settings.smtp_userid = \'john@example.com\'\n- self.assertEqual(\n- getAdapter(self.portal, IMailSchema).smtp_userid,\n- \'john@example.com\'\n+ getAdapter(self.portal, IMailSchema).smtp_userid, "john@example.com"\n )\n \n def test_set_smtp_userid(self):\n- self.assertEqual(\n- self.mail_settings.smtp_userid,\n- None\n- )\n- getAdapter(self.portal, IMailSchema).smtp_userid = \'john@example.com\'\n- self.assertEqual(\n- self.mail_settings.smtp_userid,\n- \'john@example.com\'\n- )\n+ self.assertEqual(self.mail_settings.smtp_userid, None)\n+ getAdapter(self.portal, IMailSchema).smtp_userid = "john@example.com"\n+ self.assertEqual(self.mail_settings.smtp_userid, "john@example.com")\n \n def test_get_smtp_pass(self):\n- self.assertEqual(\n- getAdapter(self.portal, IMailSchema).smtp_pass,\n- None\n- )\n- self.mail_settings.smtp_pass = \'secret\'\n- self.assertEqual(\n- getAdapter(self.portal, IMailSchema).smtp_pass,\n- \'secret\'\n- )\n+ self.assertEqual(getAdapter(self.portal, IMailSchema).smtp_pass, None)\n+ self.mail_settings.smtp_pass = "secret"\n+ self.assertEqual(getAdapter(self.portal, IMailSchema).smtp_pass, "secret")\n \n def test_set_smtp_pass(self):\n- self.assertEqual(\n- self.mail_settings.smtp_pass,\n- None\n- )\n- getAdapter(self.portal, IMailSchema).smtp_pass = \'secret\'\n- self.assertEqual(\n- self.mail_settings.smtp_pass,\n- \'secret\'\n- )\n+ self.assertEqual(self.mail_settings.smtp_pass, None)\n+ getAdapter(self.portal, IMailSchema).smtp_pass = "secret"\n+ self.assertEqual(self.mail_settings.smtp_pass, "secret")\n \n def test_get_email_from_name(self):\n- self.assertEqual(\n- getAdapter(self.portal, IMailSchema).email_from_name,\n- None\n- )\n- self.mail_settings.email_from_name = \'John\'\n- self.assertEqual(\n- getAdapter(self.portal, IMailSchema).email_from_name,\n- \'John\'\n- )\n+ self.assertEqual(getAdapter(self.portal, IMailSchema).email_from_name, None)\n+ self.mail_settings.email_from_name = "John"\n+ self.assertEqual(getAdapter(self.portal, IMailSchema).email_from_name, "John")\n \n def test_set_email_from_name(self):\n- self.assertEqual(\n- self.mail_settings.email_from_name,\n- None\n- )\n- getAdapter(self.portal, IMailSchema).email_from_name = \'John\'\n- self.assertEqual(\n- self.mail_settings.email_from_name,\n- \'John\'\n- )\n+ self.assertEqual(self.mail_settings.email_from_name, None)\n+ getAdapter(self.portal, IMailSchema).email_from_name = "John"\n+ self.assertEqual(self.mail_settings.email_from_name, "John")\n \n def test_get_email_from_address(self):\n+ self.assertEqual(getAdapter(self.portal, IMailSchema).email_from_address, None)\n+ self.mail_settings.email_from_address = "john@example.com"\n self.assertEqual(\n- getAdapter(self.portal, IMailSchema).email_from_address,\n- None\n- )\n- self.mail_settings.email_from_address = \'john@example.com\'\n- self.assertEqual(\n- getAdapter(self.portal, IMailSchema).email_from_address,\n- \'john@example.com\'\n+ getAdapter(self.portal, IMailSchema).email_from_address, "john@example.com"\n )\n \n def test_set_email_from_address(self):\n- self.assertEqual(\n- self.mail_settings.email_from_address,\n- None\n- )\n- getAdapter(self.portal, IMailSchema).email_from_address = \\\n- \'john@example.com\'\n- self.assertEqual(\n- self.mail_settings.email_from_address,\n- \'john@example.com\'\n- )\n+ self.assertEqual(self.mail_settings.email_from_address, None)\n+ getAdapter(self.portal, IMailSchema).email_from_address = "john@example.com"\n+ self.assertEqual(self.mail_settings.email_from_address, "john@example.com")\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_maintenance_adapter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_maintenance_adapter.py\nindex ab48904965..5df474be72 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_maintenance_adapter.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_maintenance_adapter.py\n@@ -10,40 +10,26 @@\n \n \n class MaintenanceControlPanelAdapterTest(unittest.TestCase):\n-\n layer = PRODUCTS_CMFPLONE_INTEGRATION_TESTING\n \n def setUp(self):\n- self.portal = self.layer[\'portal\']\n- self.request = self.layer[\'request\']\n- setRoles(self.portal, TEST_USER_ID, [\'Manager\'])\n+ self.portal = self.layer["portal"]\n+ self.request = self.layer["request"]\n+ setRoles(self.portal, TEST_USER_ID, ["Manager"])\n registry = getUtility(IRegistry)\n self.maintenance_settings = registry.forInterface(\n- IMaintenanceSchema, prefix="plone")\n+ IMaintenanceSchema, prefix="plone"\n+ )\n \n def test_adapter_lookup(self):\n- self.assertTrue(\n- getAdapter(self.portal, IMaintenanceSchema)\n- )\n+ self.assertTrue(getAdapter(self.portal, IMaintenanceSchema))\n \n def test_get_days(self):\n- self.assertEqual(\n- getAdapter(self.portal, IMaintenanceSchema).days,\n- 7\n- )\n+ self.assertEqual(getAdapter(self.portal, IMaintenanceSchema).days, 7)\n self.maintenance_settings.days = 4\n- self.assertEqual(\n- getAdapter(self.portal, IMaintenanceSchema).days,\n- 4\n- )\n+ self.assertEqual(getAdapter(self.portal, IMaintenanceSchema).days, 4)\n \n def test_set_days(self):\n- self.assertEqual(\n- self.maintenance_settings.days,\n- 7\n- )\n+ self.assertEqual(self.maintenance_settings.days, 7)\n getAdapter(self.portal, IMaintenanceSchema).days = 4\n- self.assertEqual(\n- self.maintenance_settings.days,\n- 4\n- )\n+ self.assertEqual(self.maintenance_settings.days, 4)\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_markup_adapter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_markup_adapter.py\nindex 7ec8e09c4e..7c24212ad0 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_markup_adapter.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_markup_adapter.py\n@@ -10,13 +10,12 @@\n \n \n class MarkupControlPanelAdapterTest(unittest.TestCase):\n-\n layer = PRODUCTS_CMFPLONE_INTEGRATION_TESTING\n \n def setUp(self):\n- self.app = self.layer[\'app\']\n- self.portal = self.layer[\'portal\']\n- setRoles(self.portal, TEST_USER_ID, [\'Manager\'])\n+ self.app = self.layer["app"]\n+ self.portal = self.layer["portal"]\n+ setRoles(self.portal, TEST_USER_ID, ["Manager"])\n registry = getUtility(IRegistry)\n self.settings = registry.forInterface(IMarkupSchema, prefix="plone")\n \n@@ -24,30 +23,27 @@ def test_adapter_lookup(self):\n self.assertTrue(getAdapter(self.portal, IMarkupSchema))\n \n def test_get_default_type(self):\n- self.settings.default_type = \'text/plain\'\n+ self.settings.default_type = "text/plain"\n self.assertEqual(\n- getAdapter(self.portal, IMarkupSchema).default_type,\n- \'text/plain\'\n+ getAdapter(self.portal, IMarkupSchema).default_type, "text/plain"\n )\n \n def test_set_default_type(self):\n- getAdapter(self.portal, IMarkupSchema).default_type = \'text/plain\' # noqa\n- self.assertEqual(\n- self.settings.default_type,\n- \'text/plain\'\n- )\n+ getAdapter(self.portal, IMarkupSchema).default_type = "text/plain" # noqa\n+ self.assertEqual(self.settings.default_type, "text/plain")\n \n def test_get_allowed_types(self):\n- self.settings.allowed_types = (\'text/plain\', \'text/x-web-textile\')\n+ self.settings.allowed_types = ("text/plain", "text/x-web-textile")\n self.assertEqual(\n getAdapter(self.portal, IMarkupSchema).allowed_types,\n- (\'text/plain\', \'text/x-web-textile\')\n+ ("text/plain", "text/x-web-textile"),\n )\n \n def test_set_allowed_types(self):\n- getAdapter(self.portal, IMarkupSchema).allowed_types =\\\n- (\'text/plain\', \'text/x-web-textile\')\n+ getAdapter(self.portal, IMarkupSchema).allowed_types = (\n+ "text/plain",\n+ "text/x-web-textile",\n+ )\n self.assertEqual(\n- self.settings.allowed_types,\n- (\'text/plain\', \'text/x-web-textile\')\n+ self.settings.allowed_types, ("text/plain", "text/x-web-textile")\n )\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_navigation_adapter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_navigation_adapter.py\nindex 819c4a8ebb..4be9b02790 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_navigation_adapter.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_navigation_adapter.py\n@@ -10,147 +10,98 @@\n \n \n class NavigationControlPanelAdapterTest(unittest.TestCase):\n-\n layer = PRODUCTS_CMFPLONE_INTEGRATION_TESTING\n \n def setUp(self):\n- self.portal = self.layer[\'portal\']\n- self.request = self.layer[\'request\']\n- setRoles(self.portal, TEST_USER_ID, [\'Manager\'])\n+ self.portal = self.layer["portal"]\n+ self.request = self.layer["request"]\n+ setRoles(self.portal, TEST_USER_ID, ["Manager"])\n registry = getUtility(IRegistry)\n self.navigation_settings = registry.forInterface(\n- INavigationSchema, prefix="plone")\n+ INavigationSchema, prefix="plone"\n+ )\n \n def test_adapter_lookup(self):\n self.assertTrue(getAdapter(self.portal, INavigationSchema))\n \n def test_get_generate_tabs(self):\n- self.assertEqual(\n- getAdapter(self.portal, INavigationSchema).generate_tabs,\n- True\n- )\n+ self.assertEqual(getAdapter(self.portal, INavigationSchema).generate_tabs, True)\n self.navigation_settings.generate_tabs = False\n self.assertEqual(\n- getAdapter(self.portal, INavigationSchema).generate_tabs,\n- False\n+ getAdapter(self.portal, INavigationSchema).generate_tabs, False\n )\n \n def test_set_generate_tabs(self):\n- self.assertEqual(\n- self.navigation_settings.generate_tabs,\n- True\n- )\n+ self.assertEqual(self.navigation_settings.generate_tabs, True)\n getAdapter(self.portal, INavigationSchema).generate_tabs = False\n- self.assertEqual(\n- self.navigation_settings.generate_tabs,\n- False\n- )\n+ self.assertEqual(self.navigation_settings.generate_tabs, False)\n \n def test_get_nonfolderish_tabs(self):\n self.assertEqual(\n- getAdapter(self.portal, INavigationSchema).nonfolderish_tabs,\n- True\n+ getAdapter(self.portal, INavigationSchema).nonfolderish_tabs, True\n )\n self.navigation_settings.nonfolderish_tabs = False\n self.assertEqual(\n- getAdapter(self.portal, INavigationSchema).nonfolderish_tabs,\n- False\n+ getAdapter(self.portal, INavigationSchema).nonfolderish_tabs, False\n )\n \n def test_set_nonfolderish_tabs(self):\n- self.assertEqual(\n- self.navigation_settings.nonfolderish_tabs,\n- True\n- )\n+ self.assertEqual(self.navigation_settings.nonfolderish_tabs, True)\n getAdapter(self.portal, INavigationSchema).nonfolderish_tabs = False\n- self.assertEqual(\n- self.navigation_settings.nonfolderish_tabs,\n- False\n- )\n+ self.assertEqual(self.navigation_settings.nonfolderish_tabs, False)\n \n def test_get_displayed_types(self):\n- self.navigation_settings.displayed_types = (\'Folder\',)\n+ self.navigation_settings.displayed_types = ("Folder",)\n self.assertEqual(\n- getAdapter(self.portal, INavigationSchema).displayed_types,\n- (\'Folder\',)\n+ getAdapter(self.portal, INavigationSchema).displayed_types, ("Folder",)\n )\n \n def test_set_displayed_types(self):\n- getAdapter(\n- self.portal,\n- INavigationSchema\n- ).displayed_types = (\'Folder\',)\n- self.assertEqual(\n- self.navigation_settings.displayed_types,\n- (\'Folder\',)\n- )\n+ getAdapter(self.portal, INavigationSchema).displayed_types = ("Folder",)\n+ self.assertEqual(self.navigation_settings.displayed_types, ("Folder",))\n \n def test_get_filter_on_workflow(self):\n self.assertEqual(\n- getAdapter(self.portal, INavigationSchema).filter_on_workflow,\n- False\n+ getAdapter(self.portal, INavigationSchema).filter_on_workflow, False\n )\n self.navigation_settings.filter_on_workflow = True\n self.assertEqual(\n- getAdapter(self.portal, INavigationSchema).filter_on_workflow,\n- True\n+ getAdapter(self.portal, INavigationSchema).filter_on_workflow, True\n )\n \n def test_set_filter_on_workflow(self):\n- self.assertEqual(\n- self.navigation_settings.filter_on_workflow,\n- False\n- )\n+ self.assertEqual(self.navigation_settings.filter_on_workflow, False)\n getAdapter(self.portal, INavigationSchema).filter_on_workflow = True\n- self.assertEqual(\n- self.navigation_settings.filter_on_workflow,\n- True\n- )\n+ self.assertEqual(self.navigation_settings.filter_on_workflow, True)\n \n def test_get_workflow_states_to_show(self):\n self.assertEqual(\n- getAdapter(self.portal, INavigationSchema).workflow_states_to_show,\n- ()\n+ getAdapter(self.portal, INavigationSchema).workflow_states_to_show, ()\n )\n \n- self.navigation_settings.workflow_states_to_show = (\'private\',)\n+ self.navigation_settings.workflow_states_to_show = ("private",)\n self.assertEqual(\n getAdapter(self.portal, INavigationSchema).workflow_states_to_show,\n- (\'private\',)\n+ ("private",),\n )\n \n def test_set_workflow_states_to_show(self):\n- self.assertEqual(\n- self.navigation_settings.workflow_states_to_show,\n- ()\n- )\n- getAdapter(\n- self.portal,\n- INavigationSchema\n- ).workflow_states_to_show = (\'private\',)\n- self.assertEqual(\n- self.navigation_settings.workflow_states_to_show,\n- (\'private\',)\n+ self.assertEqual(self.navigation_settings.workflow_states_to_show, ())\n+ getAdapter(self.portal, INavigationSchema).workflow_states_to_show = (\n+ "private",\n )\n+ self.assertEqual(self.navigation_settings.workflow_states_to_show, ("private",))\n \n def test_get_show_excluded_items(self):\n self.assertEqual(\n- getAdapter(self.portal, INavigationSchema).show_excluded_items,\n- False\n+ getAdapter(self.portal, INavigationSchema).show_excluded_items, False\n )\n self.navigation_settings.show_excluded_items = True\n self.assertEqual(\n- getAdapter(self.portal, INavigationSchema).show_excluded_items,\n- True\n+ getAdapter(self.portal, INavigationSchema).show_excluded_items, True\n )\n \n def test_set_show_excluded_items(self):\n- self.assertEqual(\n- self.navigation_settings.show_excluded_items,\n- False\n- )\n+ self.assertEqual(self.navigation_settings.show_excluded_items, False)\n getAdapter(self.portal, INavigationSchema).show_excluded_items = True\n- self.assertEqual(\n- self.navigation_settings.show_excluded_items,\n- True\n- )\n+ self.assertEqual(self.navigation_settings.show_excluded_items, True)\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_search_adapter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_search_adapter.py\nindex 28905f2dec..c980f31083 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_search_adapter.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_search_adapter.py\n@@ -10,58 +10,40 @@\n \n \n class SearchControlPanelAdapterTest(unittest.TestCase):\n-\n layer = PRODUCTS_CMFPLONE_INTEGRATION_TESTING\n \n def setUp(self):\n- self.portal = self.layer[\'portal\']\n- self.request = self.layer[\'request\']\n- setRoles(self.portal, TEST_USER_ID, [\'Manager\'])\n+ self.portal = self.layer["portal"]\n+ self.request = self.layer["request"]\n+ setRoles(self.portal, TEST_USER_ID, ["Manager"])\n registry = getUtility(IRegistry)\n- self.search_settings = registry.forInterface(\n- ISearchSchema, prefix="plone")\n+ self.search_settings = registry.forInterface(ISearchSchema, prefix="plone")\n \n def test_adapter_lookup(self):\n self.assertTrue(getAdapter(self.portal, ISearchSchema))\n \n def test_get_enable_livesearch(self):\n- self.assertEqual(\n- getAdapter(self.portal, ISearchSchema).enable_livesearch,\n- True\n- )\n+ self.assertEqual(getAdapter(self.portal, ISearchSchema).enable_livesearch, True)\n self.search_settings.enable_livesearch = False\n self.assertEqual(\n- getAdapter(self.portal, ISearchSchema).enable_livesearch,\n- False\n+ getAdapter(self.portal, ISearchSchema).enable_livesearch, False\n )\n \n def test_set_enable_livesearch(self):\n- self.assertEqual(\n- self.search_settings.enable_livesearch,\n- True\n- )\n+ self.assertEqual(self.search_settings.enable_livesearch, True)\n getAdapter(self.portal, ISearchSchema).enable_livesearch = False\n- self.assertEqual(\n- self.search_settings.enable_livesearch,\n- False\n- )\n+ self.assertEqual(self.search_settings.enable_livesearch, False)\n \n def test_get_types_not_searched(self):\n self.assertTrue(\n- \'Folder\' not in\n- getAdapter(self.portal, ISearchSchema).types_not_searched\n+ "Folder" not in getAdapter(self.portal, ISearchSchema).types_not_searched\n )\n- self.search_settings.types_not_searched = (\'Folder\',)\n+ self.search_settings.types_not_searched = ("Folder",)\n self.assertTrue(\n- \'Folder\' in\n- getAdapter(self.portal, ISearchSchema).types_not_searched\n+ "Folder" in getAdapter(self.portal, ISearchSchema).types_not_searched\n )\n \n def test_set_types_not_searched(self):\n- self.assertTrue(\n- \'Folder\' not in self.search_settings.types_not_searched\n- )\n- getAdapter(self.portal, ISearchSchema).types_not_searched = (\'Folder\',)\n- self.assertTrue(\n- \'Folder\' in self.search_settings.types_not_searched\n- )\n+ self.assertTrue("Folder" not in self.search_settings.types_not_searched)\n+ getAdapter(self.portal, ISearchSchema).types_not_searched = ("Folder",)\n+ self.assertTrue("Folder" in self.search_settings.types_not_searched)\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_security_adapter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_security_adapter.py\nindex 8be6d76154..5e16b2b579 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_security_adapter.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_security_adapter.py\n@@ -8,122 +8,67 @@\n \n \n class SecurityControlPanelAdapterTest(unittest.TestCase):\n-\n layer = PRODUCTS_CMFPLONE_INTEGRATION_TESTING\n \n def setUp(self):\n- self.portal = self.layer[\'portal\']\n- self.request = self.layer[\'request\']\n- setRoles(self.portal, TEST_USER_ID, [\'Manager\'])\n+ self.portal = self.layer["portal"]\n+ self.request = self.layer["request"]\n+ setRoles(self.portal, TEST_USER_ID, ["Manager"])\n self.security_settings = getAdapter(self.portal, ISecuritySchema)\n \n def test_adapter_lookup(self):\n self.assertTrue(getAdapter(self.portal, ISecuritySchema))\n \n def test_get_enable_self_reg_setting(self):\n- self.assertEqual(\n- self.security_settings.enable_self_reg,\n- False\n- )\n+ self.assertEqual(self.security_settings.enable_self_reg, False)\n \n def test_set_enable_self_reg_setting(self):\n self.security_settings.enable_self_reg = False\n- self.assertEqual(\n- self.security_settings.enable_self_reg,\n- False\n- )\n+ self.assertEqual(self.security_settings.enable_self_reg, False)\n self.security_settings.enable_self_reg = True\n- self.assertEqual(\n- self.security_settings.enable_self_reg,\n- True\n- )\n+ self.assertEqual(self.security_settings.enable_self_reg, True)\n \n def test_get_enable_user_pwd_choice_setting(self):\n- self.assertEqual(\n- self.security_settings.enable_user_pwd_choice,\n- False\n- )\n+ self.assertEqual(self.security_settings.enable_user_pwd_choice, False)\n \n def test_set_enable_user_pwd_choice_setting(self):\n self.security_settings.enable_user_pwd_choice = False\n- self.assertEqual(\n- self.security_settings.enable_user_pwd_choice,\n- False\n- )\n+ self.assertEqual(self.security_settings.enable_user_pwd_choice, False)\n self.security_settings.enable_user_pwd_choice = True\n- self.assertEqual(\n- self.security_settings.enable_user_pwd_choice,\n- True\n- )\n+ self.assertEqual(self.security_settings.enable_user_pwd_choice, True)\n \n def test_get_enable_user_folders_setting(self):\n- self.assertEqual(\n- self.security_settings.enable_user_folders,\n- False\n- )\n+ self.assertEqual(self.security_settings.enable_user_folders, False)\n \n def test_set_enable_user_folders_setting(self):\n self.security_settings.enable_user_folders = False\n- self.assertEqual(\n- self.security_settings.enable_user_folders,\n- False\n- )\n+ self.assertEqual(self.security_settings.enable_user_folders, False)\n self.security_settings.enable_user_folders = True\n- self.assertEqual(\n- self.security_settings.enable_user_folders,\n- True\n- )\n+ self.assertEqual(self.security_settings.enable_user_folders, True)\n \n def test_get_allow_anon_views_about_setting(self):\n- self.assertEqual(\n- self.security_settings.allow_anon_views_about,\n- False\n- )\n+ self.assertEqual(self.security_settings.allow_anon_views_about, False)\n \n def test_set_allow_anon_views_about_setting(self):\n self.security_settings.allow_anon_views_about = False\n- self.assertEqual(\n- self.security_settings.allow_anon_views_about,\n- False\n- )\n+ self.assertEqual(self.security_settings.allow_anon_views_about, False)\n self.security_settings.allow_anon_views_about = True\n- self.assertEqual(\n- self.security_settings.allow_anon_views_about,\n- True\n- )\n+ self.assertEqual(self.security_settings.allow_anon_views_about, True)\n \n def test_get_use_email_as_login_setting(self):\n- self.assertEqual(\n- self.security_settings.use_email_as_login,\n- False\n- )\n+ self.assertEqual(self.security_settings.use_email_as_login, False)\n \n def test_set_use_email_as_login_setting(self):\n self.security_settings.use_email_as_login = False\n- self.assertEqual(\n- self.security_settings.use_email_as_login,\n- False\n- )\n+ self.assertEqual(self.security_settings.use_email_as_login, False)\n self.security_settings.use_email_as_login = True\n- self.assertEqual(\n- self.security_settings.use_email_as_login,\n- True\n- )\n+ self.assertEqual(self.security_settings.use_email_as_login, True)\n \n def test_get_use_uuid_as_userid_setting(self):\n- self.assertEqual(\n- self.security_settings.use_uuid_as_userid,\n- False\n- )\n+ self.assertEqual(self.security_settings.use_uuid_as_userid, False)\n \n def test_set_use_uuid_as_userid_setting(self):\n self.security_settings.use_uuid_as_userid = False\n- self.assertEqual(\n- self.security_settings.use_uuid_as_userid,\n- False\n- )\n+ self.assertEqual(self.security_settings.use_uuid_as_userid, False)\n self.security_settings.use_uuid_as_userid = True\n- self.assertEqual(\n- self.security_settings.use_uuid_as_userid,\n- True\n- )\n+ self.assertEqual(self.security_settings.use_uuid_as_userid, True)\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_site_adapter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_site_adapter.py\nindex 5901222888..1f5f2e9a6e 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_site_adapter.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_site_adapter.py\n@@ -10,13 +10,12 @@\n \n \n class SiteControlPanelAdapterTest(unittest.TestCase):\n-\n layer = PRODUCTS_CMFPLONE_INTEGRATION_TESTING\n \n def setUp(self):\n- self.portal = self.layer[\'portal\']\n- self.request = self.layer[\'request\']\n- setRoles(self.portal, TEST_USER_ID, [\'Manager\'])\n+ self.portal = self.layer["portal"]\n+ self.request = self.layer["request"]\n+ setRoles(self.portal, TEST_USER_ID, ["Manager"])\n registry = getUtility(IRegistry)\n self.settings = registry.forInterface(ISiteSchema, prefix="plone")\n \n@@ -24,43 +23,25 @@ def test_adapter_lookup(self):\n self.assertTrue(getAdapter(self.portal, ISiteSchema))\n \n def test_get_site_title(self):\n- self.settings.site_title = \'Great Site\'\n- self.assertEqual(\n- getAdapter(self.portal, ISiteSchema).site_title,\n- \'Great Site\'\n- )\n+ self.settings.site_title = "Great Site"\n+ self.assertEqual(getAdapter(self.portal, ISiteSchema).site_title, "Great Site")\n \n def test_set_site_title(self):\n- getAdapter(self.portal, ISiteSchema).site_title = \'Good Site\'\n- self.assertEqual(\n- self.settings.site_title,\n- \'Good Site\'\n- )\n+ getAdapter(self.portal, ISiteSchema).site_title = "Good Site"\n+ self.assertEqual(self.settings.site_title, "Good Site")\n \n def test_set_site_title_string(self):\n- getAdapter(self.portal, ISiteSchema).site_title = \'Good Site\'\n- self.assertEqual(\n- self.settings.site_title,\n- \'Good Site\'\n- )\n+ getAdapter(self.portal, ISiteSchema).site_title = "Good Site"\n+ self.assertEqual(self.settings.site_title, "Good Site")\n \n def test_get_webstats_js(self):\n- self.settings.webstats_js = \'Script Tag\'\n- self.assertEqual(\n- getAdapter(self.portal, ISiteSchema).webstats_js,\n- \'Script Tag\'\n- )\n+ self.settings.webstats_js = "Script Tag"\n+ self.assertEqual(getAdapter(self.portal, ISiteSchema).webstats_js, "Script Tag")\n \n def test_set_webstats_js(self):\n- getAdapter(self.portal, ISiteSchema).webstats_js = \'Script Tag\'\n- self.assertEqual(\n- self.settings.webstats_js,\n- \'Script Tag\'\n- )\n+ getAdapter(self.portal, ISiteSchema).webstats_js = "Script Tag"\n+ self.assertEqual(self.settings.webstats_js, "Script Tag")\n \n def test_set_webstats_js_string(self):\n- getAdapter(self.portal, ISiteSchema).webstats_js = \'Script Tag\'\n- self.assertEqual(\n- self.settings.webstats_js,\n- \'Script Tag\'\n- )\n+ getAdapter(self.portal, ISiteSchema).webstats_js = "Script Tag"\n+ self.assertEqual(self.settings.webstats_js, "Script Tag")\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_usergroups_adapter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_usergroups_adapter.py\nindex 7140b64110..c99edf9000 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_usergroups_adapter.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_usergroups_adapter.py\n@@ -10,33 +10,28 @@\n \n \n class UserGroupsControlPanelAdapterTest(unittest.TestCase):\n-\n layer = PRODUCTS_CMFPLONE_INTEGRATION_TESTING\n \n def setUp(self):\n- self.portal = self.layer[\'portal\']\n- self.request = self.layer[\'request\']\n- setRoles(self.portal, TEST_USER_ID, [\'Manager\'])\n+ self.portal = self.layer["portal"]\n+ self.request = self.layer["request"]\n+ setRoles(self.portal, TEST_USER_ID, ["Manager"])\n registry = getUtility(IRegistry)\n self.usergroups_settings = registry.forInterface(\n- IUserGroupsSettingsSchema, prefix="plone")\n+ IUserGroupsSettingsSchema, prefix="plone"\n+ )\n \n def test_adapter_lookup(self):\n- self.assertTrue(\n- getAdapter(self.portal, IUserGroupsSettingsSchema)\n- )\n+ self.assertTrue(getAdapter(self.portal, IUserGroupsSettingsSchema))\n \n def test_many_groups(self):\n getAdapter(self.portal, IUserGroupsSettingsSchema).set_many_groups(True)\n self.assertEqual(\n- getAdapter(\n- self.portal, IUserGroupsSettingsSchema).get_many_groups(),\n- True\n+ getAdapter(self.portal, IUserGroupsSettingsSchema).get_many_groups(), True\n )\n \n def test_many_users(self):\n getAdapter(self.portal, IUserGroupsSettingsSchema).set_many_users(True)\n self.assertEqual(\n- getAdapter(self.portal, IUserGroupsSettingsSchema).get_many_users(),\n- True\n+ getAdapter(self.portal, IUserGroupsSettingsSchema).get_many_users(), True\n )\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_editing.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_editing.py\nindex 2157771f56..f89b45c258 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_editing.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_editing.py\n@@ -18,48 +18,41 @@ class EditingControlPanelFunctionalTest(unittest.TestCase):\n layer = PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING\n \n def setUp(self):\n- self.app = self.layer[\'app\']\n- self.request = self.layer[\'request\']\n- self.portal = self.layer[\'portal\']\n+ self.app = self.layer["app"]\n+ self.request = self.layer["request"]\n+ self.portal = self.layer["portal"]\n self.portal_url = self.portal.absolute_url()\n \n registry = getUtility(IRegistry)\n- self.settings = registry.forInterface(IEditingSchema, prefix=\'plone\')\n+ self.settings = registry.forInterface(IEditingSchema, prefix="plone")\n \n self.browser = Browser(self.app)\n self.browser.handleErrors = False\n self.browser.addHeader(\n- \'Authorization\',\n- f\'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}\'\n+ "Authorization", f"Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}"\n )\n \n def test_editing_control_panel_link(self):\n- self.browser.open(\n- "%s/@@overview-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Editing\').click()\n+ self.browser.open("%s/@@overview-controlpanel" % self.portal_url)\n+ self.browser.getLink("Editing").click()\n \n def test_editing_control_panel_backlink(self):\n- self.browser.open(\n- "%s/@@editing-controlpanel" % self.portal_url)\n+ self.browser.open("%s/@@editing-controlpanel" % self.portal_url)\n self.assertTrue("Content" in self.browser.contents)\n \n def test_editing_control_panel_sidebar(self):\n- self.browser.open(\n- "%s/@@editing-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Site Setup\').click()\n- self.assertTrue(\n- self.browser.url.endswith(\'/plone/@@overview-controlpanel\')\n- )\n+ self.browser.open("%s/@@editing-controlpanel" % self.portal_url)\n+ self.browser.getLink("Site Setup").click()\n+ self.assertTrue(self.browser.url.endswith("/plone/@@overview-controlpanel"))\n \n @unittest.skip("TODO: Not implemented yet.")\n def test_visible_ids_active(self):\n pass\n \n def test_default_editor(self):\n- self.browser.open(\n- "%s/@@editing-controlpanel" % self.portal_url)\n+ self.browser.open("%s/@@editing-controlpanel" % self.portal_url)\n self.browser.getControl("Default editor").value = ["None"]\n- self.browser.getControl(\'Save\').click()\n+ self.browser.getControl("Save").click()\n \n self.assertEqual(self.settings.default_editor, "None")\n \n@@ -68,16 +61,13 @@ def test_default_editor_active(self):\n pass\n \n def test_available_editors_hidden(self):\n- self.browser.open(\n- "%s/@@editing-controlpanel" % self.portal_url)\n- self.assertTrue(\'Available editors\' not in self.browser.contents)\n+ self.browser.open("%s/@@editing-controlpanel" % self.portal_url)\n+ self.assertTrue("Available editors" not in self.browser.contents)\n \n def test_ext_editor(self):\n- self.browser.open(\n- "%s/@@editing-controlpanel" % self.portal_url)\n- self.browser.getControl("Enable External Editor feature")\\\n- .selected = True\n- self.browser.getControl(\'Save\').click()\n+ self.browser.open("%s/@@editing-controlpanel" % self.portal_url)\n+ self.browser.getControl("Enable External Editor feature").selected = True\n+ self.browser.getControl("Save").click()\n \n self.assertEqual(self.settings.ext_editor, True)\n \n@@ -86,28 +76,24 @@ def test_ext_editor_active(self):\n pass\n \n def test_enable_link_integrity_checks(self):\n- self.browser.open(\n- "%s/@@editing-controlpanel" % self.portal_url)\n- self.browser.getControl("Enable link integrity checks")\\\n- .selected = True\n- self.browser.getControl(\'Save\').click()\n+ self.browser.open("%s/@@editing-controlpanel" % self.portal_url)\n+ self.browser.getControl("Enable link integrity checks").selected = True\n+ self.browser.getControl("Save").click()\n \n self.assertEqual(self.settings.enable_link_integrity_checks, True)\n \n def test_enable_link_integrity_checks_active(self):\n- self.browser.open(\n- "%s/@@editing-controlpanel" % self.portal_url)\n- self.browser.getControl("Enable link integrity checks")\\\n- .selected = True\n- self.browser.getControl(\'Save\').click()\n+ self.browser.open("%s/@@editing-controlpanel" % self.portal_url)\n+ self.browser.getControl("Enable link integrity checks").selected = True\n+ self.browser.getControl("Save").click()\n self.assertTrue(linkintegrity_enabled())\n \n def test_lock_on_ttw_edit(self):\n- self.browser.open(\n- "%s/@@editing-controlpanel" % self.portal_url)\n- self.browser.getControl("Enable locking for through-the-web edits")\\\n- .selected = True\n- self.browser.getControl(\'Save\').click()\n+ self.browser.open("%s/@@editing-controlpanel" % self.portal_url)\n+ self.browser.getControl(\n+ "Enable locking for through-the-web edits"\n+ ).selected = True\n+ self.browser.getControl("Save").click()\n \n self.assertEqual(self.settings.lock_on_ttw_edit, True)\n \ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_error_log.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_error_log.py\nindex 2ec0ca1b1b..af3ba9975f 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_error_log.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_error_log.py\n@@ -8,16 +8,15 @@\n \n \n class ErrorLogControlPanelFunctionalTest(unittest.TestCase):\n- """Test for Controlpanel Error Log\n- """\n+ """Test for Controlpanel Error Log"""\n \n layer = PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING\n error_log_properties = None\n \n def setUp(self):\n- self.app = self.layer[\'app\']\n- self.request = self.layer[\'request\']\n- self.portal = self.layer[\'portal\']\n+ self.app = self.layer["app"]\n+ self.request = self.layer["request"]\n+ self.portal = self.layer["portal"]\n self.portal_url = self.portal.absolute_url()\n \n # keep initial error_log_properties to reset them\n@@ -26,39 +25,46 @@ def setUp(self):\n self.browser = Browser(self.app)\n self.browser.handleErrors = False\n self.browser.addHeader(\n- \'Authorization\',\n- f\'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}\'\n+ "Authorization", f"Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}"\n )\n \n def tearDown(self):\n # reset error log properties\n- keep_entries = self.error_log_properties[\'keep_entries\']\n- copy_to_zlog = self.error_log_properties[\'copy_to_zlog\']\n- ignored_exceptions = self.error_log_properties[\'ignored_exceptions\']\n- self.portal.error_log.setProperties(keep_entries, copy_to_zlog, ignored_exceptions)\n+ keep_entries = self.error_log_properties["keep_entries"]\n+ copy_to_zlog = self.error_log_properties["copy_to_zlog"]\n+ ignored_exceptions = self.error_log_properties["ignored_exceptions"]\n+ self.portal.error_log.setProperties(\n+ keep_entries, copy_to_zlog, ignored_exceptions\n+ )\n \n def test_error_log_control_panel_link(self):\n self.browser.open("%s/@@overview-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Errors\').click()\n+ self.browser.getLink("Errors").click()\n \n self.assertEqual(self.browser.url, "%s/@@error-log-form" % self.portal_url)\n- self.assertIn(\'

Error log

\', self.browser.contents)\n+ self.assertIn("

Error log

", self.browser.contents)\n \n def test_error_log_set_properties(self):\n- self.assertEqual(self.error_log_properties[\'keep_entries\'], 20)\n- self.assertEqual(self.error_log_properties[\'copy_to_zlog\'], True)\n- self.assertEqual(self.error_log_properties[\'ignored_exceptions\'], (\'Unauthorized\', \'NotFound\', \'Redirect\'))\n+ self.assertEqual(self.error_log_properties["keep_entries"], 20)\n+ self.assertEqual(self.error_log_properties["copy_to_zlog"], True)\n+ self.assertEqual(\n+ self.error_log_properties["ignored_exceptions"],\n+ ("Unauthorized", "NotFound", "Redirect"),\n+ )\n \n self.request.form = {\n- \'keep_entries\': 40,\n- \'ignored_exceptions\': [\'NotFound\', \'Redirect\']\n+ "keep_entries": 40,\n+ "ignored_exceptions": ["NotFound", "Redirect"],\n }\n \n- set_properties_view = getMultiAdapter((self.portal, self.request),\n- name=\'error-log-set-properties\')\n+ set_properties_view = getMultiAdapter(\n+ (self.portal, self.request), name="error-log-set-properties"\n+ )\n set_properties_view()\n \n error_log_properties = self.portal.error_log.getProperties()\n- self.assertEqual(error_log_properties[\'keep_entries\'], 40)\n- self.assertEqual(error_log_properties[\'copy_to_zlog\'], False)\n- self.assertEqual(error_log_properties[\'ignored_exceptions\'], (\'NotFound\', \'Redirect\'))\n+ self.assertEqual(error_log_properties["keep_entries"], 40)\n+ self.assertEqual(error_log_properties["copy_to_zlog"], False)\n+ self.assertEqual(\n+ error_log_properties["ignored_exceptions"], ("NotFound", "Redirect")\n+ )\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_filter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_filter.py\nindex 60eb00aaf8..bc5b57ae1a 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_filter.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_filter.py\n@@ -20,90 +20,74 @@ class FilterControlPanelFunctionalTest(unittest.TestCase):\n layer = PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING\n \n def setUp(self):\n- self.app = self.layer[\'app\']\n- self.portal = self.layer[\'portal\']\n- self.request = self.layer[\'request\']\n+ self.app = self.layer["app"]\n+ self.portal = self.layer["portal"]\n+ self.request = self.layer["request"]\n self.portal_url = self.portal.absolute_url()\n registry = getUtility(IRegistry)\n- self.settings = registry.forInterface(\n- IFilterSchema, prefix="plone")\n+ self.settings = registry.forInterface(IFilterSchema, prefix="plone")\n self.browser = Browser(self.app)\n self.browser.handleErrors = False\n self.browser.addHeader(\n- \'Authorization\',\n- f\'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}\'\n+ "Authorization", f"Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}"\n )\n self.safe_html = getattr(\n- getToolByName(self.portal, \'portal_transforms\'),\n- \'safe_html\',\n- None)\n+ getToolByName(self.portal, "portal_transforms"), "safe_html", None\n+ )\n \n def test_filter_control_panel_link(self):\n- self.browser.open(\n- "%s/@@overview-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Site\').click()\n+ self.browser.open("%s/@@overview-controlpanel" % self.portal_url)\n+ self.browser.getLink("Site").click()\n \n def test_filter_control_panel_backlink(self):\n- self.browser.open(\n- "%s/@@filter-controlpanel" % self.portal_url)\n+ self.browser.open("%s/@@filter-controlpanel" % self.portal_url)\n self.assertTrue("Security" in self.browser.contents)\n \n def test_filter_control_panel_sidebar(self):\n- self.browser.open(\n- "%s/@@filter-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Site Setup\').click()\n- self.assertTrue(\n- self.browser.url.endswith(\'/plone/@@overview-controlpanel\')\n- )\n+ self.browser.open("%s/@@filter-controlpanel" % self.portal_url)\n+ self.browser.getLink("Site Setup").click()\n+ self.assertTrue(self.browser.url.endswith("/plone/@@overview-controlpanel"))\n \n def test_filter_controlpanel_view(self):\n- view = getMultiAdapter((self.portal, self.portal.REQUEST),\n- name="filter-controlpanel")\n+ view = getMultiAdapter(\n+ (self.portal, self.portal.REQUEST), name="filter-controlpanel"\n+ )\n self.assertTrue(view())\n \n def test_disable_filtering(self):\n- self.browser.open(\n- "%s/@@filter-controlpanel" % self.portal_url)\n+ self.browser.open("%s/@@filter-controlpanel" % self.portal_url)\n self.browser.getControl(\n- name=\'form.widgets.disable_filtering:list\').value = "selected"\n- self.browser.getControl(\'Save\').click()\n+ name="form.widgets.disable_filtering:list"\n+ ).value = "selected"\n+ self.browser.getControl("Save").click()\n \n # test that the transform is disabled\n- self.assertEqual(\n- self.settings.disable_filtering,\n- 1)\n+ self.assertEqual(self.settings.disable_filtering, 1)\n \n # anything passes\n- nasty_html = \'\'\n- ds = datastream(\'dummy_name\')\n- self.assertEqual(\n- nasty_html,\n- str(self.safe_html.convert(nasty_html, ds))\n- )\n+ nasty_html = ""\n+ ds = datastream("dummy_name")\n+ self.assertEqual(nasty_html, str(self.safe_html.convert(nasty_html, ds)))\n \n def test_nasty_tags(self):\n- self.browser.open(\n- "%s/@@filter-controlpanel" % self.portal_url)\n+ self.browser.open("%s/@@filter-controlpanel" % self.portal_url)\n self.assertEqual(\n- self.browser.getControl(name=\'form.widgets.nasty_tags\').value,\n- \'style\\nobject\\nembed\\napplet\\nscript\\nmeta\')\n- self.browser.getControl(\n- name=\'form.widgets.nasty_tags\').value = \'div\\na\'\n- valid_tags = self.browser.getControl(\n- name=\'form.widgets.valid_tags\').value\n- self.assertTrue(valid_tags.startswith(\'a\\nabbr\\nacronym\\naddress\'))\n- valid_tags = valid_tags.replace(\'a\\n\', \'\')\n+ self.browser.getControl(name="form.widgets.nasty_tags").value,\n+ "style\\nobject\\nembed\\napplet\\nscript\\nmeta",\n+ )\n+ self.browser.getControl(name="form.widgets.nasty_tags").value = "div\\na"\n+ valid_tags = self.browser.getControl(name="form.widgets.valid_tags").value\n+ self.assertTrue(valid_tags.startswith("a\\nabbr\\nacronym\\naddress"))\n+ valid_tags = valid_tags.replace("a\\n", "")\n valid_tags = self.browser.getControl(\n- name=\'form.widgets.valid_tags\').value = valid_tags\n- self.browser.getControl(\'Save\').click()\n- self.assertEqual(self.settings.nasty_tags, [\'div\', \'a\'])\n- self.assertNotIn(\'a\', self.settings.valid_tags)\n+ name="form.widgets.valid_tags"\n+ ).value = valid_tags\n+ self.browser.getControl("Save").click()\n+ self.assertEqual(self.settings.nasty_tags, ["div", "a"])\n+ self.assertNotIn("a", self.settings.valid_tags)\n \n # test that is filtered\n self.assertFalse(self.settings.disable_filtering)\n good_html = \'

harmless link

\'\n- ds = datastream(\'dummy_name\')\n- self.assertEqual(\n- self.safe_html.convert(good_html, ds).getData(),\n- \'

\'\n- )\n+ ds = datastream("dummy_name")\n+ self.assertEqual(self.safe_html.convert(good_html, ds).getData(), "

")\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_installer.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_installer.py\nindex 67192a3a60..214b2e95ed 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_installer.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_installer.py\n@@ -13,71 +13,62 @@ class AddonsControlPanelFunctionalTest(unittest.TestCase):\n layer = PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING\n \n def setUp(self):\n- self.app = self.layer[\'app\']\n- self.portal = self.layer[\'portal\']\n+ self.app = self.layer["app"]\n+ self.portal = self.layer["portal"]\n self.portal_url = self.portal.absolute_url()\n self.browser = Browser(self.app)\n self.browser.handleErrors = False\n self.browser.addHeader(\n- \'Authorization\',\n- f\'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}\'\n+ "Authorization", f"Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}"\n )\n \n def test_addons_controlpanel_link(self):\n- self.browser.open(\n- \'%s/@@overview-controlpanel\' % self.portal_url)\n- self.browser.getLink(\'Add-ons\').click()\n+ self.browser.open("%s/@@overview-controlpanel" % self.portal_url)\n+ self.browser.getLink("Add-ons").click()\n \n def test_addons_controlpanel_backlink(self):\n- self.browser.open(\n- \'%s/prefs_install_products_form\' % self.portal_url)\n- self.assertTrue(\'General\' in self.browser.contents)\n+ self.browser.open("%s/prefs_install_products_form" % self.portal_url)\n+ self.assertTrue("General" in self.browser.contents)\n \n def test_addons_controlpanel_sidebar(self):\n- self.browser.open(\n- \'%s/prefs_install_products_form\' % self.portal_url)\n- self.browser.getLink(\'Site Setup\').click()\n- self.assertTrue(\n- self.browser.url.endswith(\'/plone/@@overview-controlpanel\')\n- )\n+ self.browser.open("%s/prefs_install_products_form" % self.portal_url)\n+ self.browser.getLink("Site Setup").click()\n+ self.assertTrue(self.browser.url.endswith("/plone/@@overview-controlpanel"))\n \n def test_addons_controlpanel_view(self):\n- view = getMultiAdapter((self.portal, self.portal.REQUEST),\n- name=\'prefs_install_products_form\')\n+ view = getMultiAdapter(\n+ (self.portal, self.portal.REQUEST), name="prefs_install_products_form"\n+ )\n self.assertTrue(view())\n \n def test_addons_controlpanel_no_upgrades(self):\n- self.browser.open(\n- \'%s/prefs_install_products_form\' % self.portal_url)\n- self.assertIn(\'No upgrades in this corner\', self.browser.contents)\n+ self.browser.open("%s/prefs_install_products_form" % self.portal_url)\n+ self.assertIn("No upgrades in this corner", self.browser.contents)\n \n def test_addons_controlpanel_installable(self):\n- self.browser.open(\n- \'%s/prefs_install_products_form\' % self.portal_url)\n+ self.browser.open("%s/prefs_install_products_form" % self.portal_url)\n # We expect a few standard add-ons.\n- self.assertIn(\'Workflow Policy Support\', self.browser.contents)\n- self.assertIn(\'Multilingual Support\', self.browser.contents)\n- self.assertIn(\'plone.session\', self.browser.contents)\n+ self.assertIn("Workflow Policy Support", self.browser.contents)\n+ self.assertIn("Multilingual Support", self.browser.contents)\n+ self.assertIn("plone.session", self.browser.contents)\n \n def test_addons_controlpanel_not_installable(self):\n- self.browser.open(\n- \'%s/prefs_install_products_form\' % self.portal_url)\n+ self.browser.open("%s/prefs_install_products_form" % self.portal_url)\n # We do not expect some other add-ons.\n- self.assertNotIn(\'plone.app.upgrade\', self.browser.contents)\n- self.assertNotIn(\'Products.CMFPlone\', self.browser.contents)\n+ self.assertNotIn("plone.app.upgrade", self.browser.contents)\n+ self.assertNotIn("Products.CMFPlone", self.browser.contents)\n \n def test_addons_controlpanel_install_and_uninstall_all(self):\n- self.browser.open(\n- \'%s/prefs_install_products_form\' % self.portal_url)\n- self.assertNotIn(\'Installed\', self.browser.contents)\n- self.assertNotIn(\'Uninstalled\', self.browser.contents)\n+ self.browser.open("%s/prefs_install_products_form" % self.portal_url)\n+ self.assertNotIn("Installed", self.browser.contents)\n+ self.assertNotIn("Uninstalled", self.browser.contents)\n \n # In a fresh site there should be no uninstall buttons.\n # If there is one, it is likely an upgrade profile that should be hidden.\n # This could change: we might for example install a theme by default\n # but make it uninstallable. The logic in this test should be updated then.\n try:\n- button = self.browser.getControl(\'Uninstall\', index=0)\n+ button = self.browser.getControl("Uninstall", index=0)\n except LookupError:\n # This is good.\n pass\n@@ -93,29 +84,29 @@ def test_addons_controlpanel_install_and_uninstall_all(self):\n # We install all available products.\n for buttons in range(12):\n try:\n- self.browser.getControl(\'Install\', index=buttons)\n+ self.browser.getControl("Install", index=buttons)\n except LookupError:\n break\n else:\n # Either our test logic is off, or the code that determines\n # which products are installable is actually wrong.\n- raise AssertionError(\'Too many Install buttons.\')\n+ raise AssertionError("Too many Install buttons.")\n # Click all install buttons.\n for button in range(buttons):\n # Always install the first.\n- self.browser.getControl(\'Install\', index=0).click()\n- self.assertIn(\'Installed\', self.browser.contents)\n+ self.browser.getControl("Install", index=0).click()\n+ self.assertIn("Installed", self.browser.contents)\n # There are no more install buttons.\n with self.assertRaises(LookupError):\n- self.browser.getControl(\'Install\', index=0)\n+ self.browser.getControl("Install", index=0)\n # There should now be just as many Uninstall buttons.\n- self.browser.getControl(\'Uninstall\', index=buttons - 1)\n+ self.browser.getControl("Uninstall", index=buttons - 1)\n for button in range(buttons):\n # Always uninstall the first.\n- self.browser.getControl(\'Uninstall\', index=0).click()\n- self.assertIn(\'Uninstalled\', self.browser.contents)\n+ self.browser.getControl("Uninstall", index=0).click()\n+ self.assertIn("Uninstalled", self.browser.contents)\n # There are no more uninstall buttons.\n with self.assertRaises(LookupError):\n- self.browser.getControl(\'Uninstall\', index=0)\n+ self.browser.getControl("Uninstall", index=0)\n # Instead, we could install all again if we want.\n- self.browser.getControl(\'Install\', index=buttons - 1)\n+ self.browser.getControl("Install", index=buttons - 1)\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_language.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_language.py\nindex 35ebc885fc..cf137ed88a 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_language.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_language.py\n@@ -19,70 +19,57 @@ class LanguageControlPanelFunctionalTest(unittest.TestCase):\n layer = PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING\n \n def setUp(self):\n- self.app = self.layer[\'app\']\n- self.portal = self.layer[\'portal\']\n+ self.app = self.layer["app"]\n+ self.portal = self.layer["portal"]\n self.portal_url = self.portal.absolute_url()\n self.browser = Browser(self.app)\n self.browser.handleErrors = False\n self.browser.addHeader(\n- \'Authorization\',\n- f\'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}\'\n+ "Authorization", f"Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}"\n )\n \n def _inject_available_languages_field(self, value):\n """The in-and-out widget does not work without javascript, therefore\n- we have to inject some values in order to make saving the form work.\n+ we have to inject some values in order to make saving the form work.\n """\n- form = self.browser.getForm(id=\'LanguageControlPanel\')\n- name = \'form.widgets.available_languages:list\'\n- field = webtest.forms.Hidden(form._form, \'input\', name, 0, value=value)\n+ form = self.browser.getForm(id="LanguageControlPanel")\n+ name = "form.widgets.available_languages:list"\n+ field = webtest.forms.Hidden(form._form, "input", name, 0, value=value)\n form._form.field_order.append((name, field))\n- self.browser.getControl(\'Save\').click()\n+ self.browser.getControl("Save").click()\n \n def test_language_control_panel_link(self):\n- self.browser.open(\n- "%s/@@overview-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Language\').click()\n+ self.browser.open("%s/@@overview-controlpanel" % self.portal_url)\n+ self.browser.getLink("Language").click()\n self.assertTrue("Language Settings" in self.browser.contents)\n \n def test_language_control_panel_backlink(self):\n- self.browser.open(\n- "%s/@@language-controlpanel" % self.portal_url)\n+ self.browser.open("%s/@@language-controlpanel" % self.portal_url)\n self.assertTrue("General" in self.browser.contents)\n \n def test_language_control_panel_sidebar(self):\n- self.browser.open(\n- "%s/@@language-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Site Setup\').click()\n- self.assertTrue(\n- self.browser.url.endswith(\'/plone/@@overview-controlpanel\')\n- )\n+ self.browser.open("%s/@@language-controlpanel" % self.portal_url)\n+ self.browser.getLink("Site Setup").click()\n+ self.assertTrue(self.browser.url.endswith("/plone/@@overview-controlpanel"))\n \n def test_language_controlpanel_view(self):\n- view = getMultiAdapter((self.portal, self.portal.REQUEST),\n- name="language-controlpanel")\n+ view = getMultiAdapter(\n+ (self.portal, self.portal.REQUEST), name="language-controlpanel"\n+ )\n self.assertTrue(view())\n \n def test_default_language(self):\n registry = getUtility(IRegistry)\n- settings = registry.forInterface(ILanguageSchema, prefix=\'plone\')\n- self.browser.open(\n- "%s/@@language-controlpanel" % self.portal_url)\n- self.assertEqual(settings.default_language, \'en\')\n- self.assertEqual(\n- self.browser.getControl(\n- \'Site language\'\n- ).value,\n- [\'en\']\n- )\n- self.browser.getControl(\n- \'Site language\'\n- ).value = [\'de\']\n- self._inject_available_languages_field(\'en\')\n- self._inject_available_languages_field(\'de\')\n- self.browser.getControl(name=\'form.buttons.save\').click()\n+ settings = registry.forInterface(ILanguageSchema, prefix="plone")\n+ self.browser.open("%s/@@language-controlpanel" % self.portal_url)\n+ self.assertEqual(settings.default_language, "en")\n+ self.assertEqual(self.browser.getControl("Site language").value, ["en"])\n+ self.browser.getControl("Site language").value = ["de"]\n+ self._inject_available_languages_field("en")\n+ self._inject_available_languages_field("de")\n+ self.browser.getControl(name="form.buttons.save").click()\n \n- self.assertEqual(settings.default_language, \'de\')\n+ self.assertEqual(settings.default_language, "de")\n \n # def test_available_languages(self):\n # registry = getUtility(IRegistry)\n@@ -105,191 +92,148 @@ def test_default_language(self):\n def test_use_combined_language_codes(self):\n """This checks swithing combined languages codes support off/on."""\n registry = getUtility(IRegistry)\n- settings = registry.forInterface(ILanguageSchema, prefix=\'plone\')\n- self.browser.open(\n- "%s/@@language-controlpanel" % self.portal_url)\n+ settings = registry.forInterface(ILanguageSchema, prefix="plone")\n+ self.browser.open("%s/@@language-controlpanel" % self.portal_url)\n self.assertEqual(settings.use_combined_language_codes, True)\n self.assertEqual(\n- self.browser.getControl(\n- \'Show country-specific language variants\'\n- ).selected,\n- True\n+ self.browser.getControl("Show country-specific language variants").selected,\n+ True,\n )\n self.browser.getControl(\n- \'Show country-specific language variants\'\n+ "Show country-specific language variants"\n ).selected = False\n \n- self._inject_available_languages_field(\'en\')\n- self.browser.getControl(\'Save\').click()\n+ self._inject_available_languages_field("en")\n+ self.browser.getControl("Save").click()\n \n self.assertEqual(settings.use_combined_language_codes, False)\n \n def test_display_flags(self):\n registry = getUtility(IRegistry)\n- settings = registry.forInterface(ILanguageSchema, prefix=\'plone\')\n- self.browser.open(\n- "%s/@@language-controlpanel" % self.portal_url)\n+ settings = registry.forInterface(ILanguageSchema, prefix="plone")\n+ self.browser.open("%s/@@language-controlpanel" % self.portal_url)\n self.assertEqual(settings.display_flags, False)\n- self.assertEqual(\n- self.browser.getControl(\n- \'Show language flags\'\n- ).selected,\n- False\n- )\n- self.browser.getControl(\n- \'Show language flags\'\n- ).selected = True\n+ self.assertEqual(self.browser.getControl("Show language flags").selected, False)\n+ self.browser.getControl("Show language flags").selected = True\n \n- self._inject_available_languages_field(\'en\')\n- self.browser.getControl(\'Save\').click()\n+ self._inject_available_languages_field("en")\n+ self.browser.getControl("Save").click()\n \n self.assertEqual(settings.display_flags, True)\n \n def test_use_content_negotiation(self):\n registry = getUtility(IRegistry)\n- settings = registry.forInterface(ILanguageSchema, prefix=\'plone\')\n- self.browser.open(\n- "%s/@@language-controlpanel" % self.portal_url)\n+ settings = registry.forInterface(ILanguageSchema, prefix="plone")\n+ self.browser.open("%s/@@language-controlpanel" % self.portal_url)\n self.assertEqual(settings.use_content_negotiation, False)\n self.assertEqual(\n- self.browser.getControl(\n- \'Use the language of the content item\'\n- ).selected,\n- False\n+ self.browser.getControl("Use the language of the content item").selected,\n+ False,\n )\n- self.browser.getControl(\n- \'Use the language of the content item\'\n- ).selected = True\n+ self.browser.getControl("Use the language of the content item").selected = True\n \n- self._inject_available_languages_field(\'en\')\n- self.browser.getControl(\'Save\').click()\n+ self._inject_available_languages_field("en")\n+ self.browser.getControl("Save").click()\n \n self.assertEqual(settings.use_content_negotiation, True)\n \n def test_use_path_negotiation(self):\n registry = getUtility(IRegistry)\n- settings = registry.forInterface(ILanguageSchema, prefix=\'plone\')\n- self.browser.open(\n- "%s/@@language-controlpanel" % self.portal_url)\n+ settings = registry.forInterface(ILanguageSchema, prefix="plone")\n+ self.browser.open("%s/@@language-controlpanel" % self.portal_url)\n self.assertEqual(settings.use_path_negotiation, False)\n self.assertEqual(\n self.browser.getControl(\n- \'Use language codes in URL path for manual override\'\n+ "Use language codes in URL path for manual override"\n ).selected,\n- False\n+ False,\n )\n self.browser.getControl(\n- \'Use language codes in URL path for manual override\'\n+ "Use language codes in URL path for manual override"\n ).selected = True\n \n- self._inject_available_languages_field(\'en\')\n- self.browser.getControl(\'Save\').click()\n+ self._inject_available_languages_field("en")\n+ self.browser.getControl("Save").click()\n \n self.assertEqual(settings.use_path_negotiation, True)\n \n def test_use_cookie_negotiation(self):\n registry = getUtility(IRegistry)\n- settings = registry.forInterface(ILanguageSchema, prefix=\'plone\')\n- self.browser.open(\n- "%s/@@language-controlpanel" % self.portal_url)\n+ settings = registry.forInterface(ILanguageSchema, prefix="plone")\n+ self.browser.open("%s/@@language-controlpanel" % self.portal_url)\n self.assertEqual(settings.use_cookie_negotiation, False)\n self.assertEqual(\n- self.browser.getControl(\n- \'Use cookie for manual override\'\n- ).selected,\n- False\n+ self.browser.getControl("Use cookie for manual override").selected, False\n )\n- self.browser.getControl(\n- \'Use cookie for manual override\'\n- ).selected = True\n+ self.browser.getControl("Use cookie for manual override").selected = True\n \n- self._inject_available_languages_field(\'en\')\n- self.browser.getControl(\'Save\').click()\n+ self._inject_available_languages_field("en")\n+ self.browser.getControl("Save").click()\n \n self.assertEqual(settings.use_cookie_negotiation, True)\n \n def test_authenticated_users_only(self):\n control_label = "Authenticated users only"\n registry = getUtility(IRegistry)\n- settings = registry.forInterface(ILanguageSchema, prefix=\'plone\')\n- self.browser.open(\n- "%s/@@language-controlpanel" % self.portal_url)\n+ settings = registry.forInterface(ILanguageSchema, prefix="plone")\n+ self.browser.open("%s/@@language-controlpanel" % self.portal_url)\n self.assertEqual(settings.authenticated_users_only, False)\n- self.assertEqual(\n- self.browser.getControl(control_label).selected,\n- False\n- )\n+ self.assertEqual(self.browser.getControl(control_label).selected, False)\n self.browser.getControl(control_label).selected = True\n \n- self._inject_available_languages_field(\'en\')\n- self.browser.getControl(\'Save\').click()\n+ self._inject_available_languages_field("en")\n+ self.browser.getControl("Save").click()\n \n self.assertEqual(settings.authenticated_users_only, True)\n \n def test_set_cookie_always(self):\n control_label = "Set the language cookie always"\n registry = getUtility(IRegistry)\n- settings = registry.forInterface(ILanguageSchema, prefix=\'plone\')\n- self.browser.open(\n- "%s/@@language-controlpanel" % self.portal_url)\n+ settings = registry.forInterface(ILanguageSchema, prefix="plone")\n+ self.browser.open("%s/@@language-controlpanel" % self.portal_url)\n self.assertEqual(settings.set_cookie_always, False)\n- self.assertEqual(\n- self.browser.getControl(control_label).selected,\n- False\n- )\n+ self.assertEqual(self.browser.getControl(control_label).selected, False)\n self.browser.getControl(control_label).selected = True\n- self._inject_available_languages_field(\'en\')\n- self.browser.getControl(\'Save\').click()\n+ self._inject_available_languages_field("en")\n+ self.browser.getControl("Save").click()\n \n self.assertEqual(settings.set_cookie_always, True)\n \n def test_use_subdomain_negotiation(self):\n control_label = "Use subdomain"\n registry = getUtility(IRegistry)\n- settings = registry.forInterface(ILanguageSchema, prefix=\'plone\')\n- self.browser.open(\n- "%s/@@language-controlpanel" % self.portal_url)\n+ settings = registry.forInterface(ILanguageSchema, prefix="plone")\n+ self.browser.open("%s/@@language-controlpanel" % self.portal_url)\n self.assertEqual(settings.use_subdomain_negotiation, False)\n- self.assertEqual(\n- self.browser.getControl(control_label).selected,\n- False\n- )\n+ self.assertEqual(self.browser.getControl(control_label).selected, False)\n self.browser.getControl(control_label).selected = True\n- self._inject_available_languages_field(\'en\')\n- self.browser.getControl(\'Save\').click()\n+ self._inject_available_languages_field("en")\n+ self.browser.getControl("Save").click()\n \n self.assertEqual(settings.use_subdomain_negotiation, True)\n \n def test_use_cctld_negotiation(self):\n control_label = "Use top-level domain"\n registry = getUtility(IRegistry)\n- settings = registry.forInterface(ILanguageSchema, prefix=\'plone\')\n- self.browser.open(\n- "%s/@@language-controlpanel" % self.portal_url)\n+ settings = registry.forInterface(ILanguageSchema, prefix="plone")\n+ self.browser.open("%s/@@language-controlpanel" % self.portal_url)\n self.assertEqual(settings.use_cctld_negotiation, False)\n- self.assertEqual(\n- self.browser.getControl(control_label).selected,\n- False\n- )\n+ self.assertEqual(self.browser.getControl(control_label).selected, False)\n self.browser.getControl(control_label).selected = True\n- self._inject_available_languages_field(\'en\')\n- self.browser.getControl(\'Save\').click()\n+ self._inject_available_languages_field("en")\n+ self.browser.getControl("Save").click()\n \n self.assertEqual(settings.use_cctld_negotiation, True)\n \n def test_use_request_negotiation(self):\n control_label = "Use browser language request negotiation"\n registry = getUtility(IRegistry)\n- settings = registry.forInterface(ILanguageSchema, prefix=\'plone\')\n- self.browser.open(\n- "%s/@@language-controlpanel" % self.portal_url)\n+ settings = registry.forInterface(ILanguageSchema, prefix="plone")\n+ self.browser.open("%s/@@language-controlpanel" % self.portal_url)\n self.assertEqual(settings.use_request_negotiation, False)\n- self.assertEqual(\n- self.browser.getControl(control_label).selected,\n- False\n- )\n+ self.assertEqual(self.browser.getControl(control_label).selected, False)\n self.browser.getControl(control_label).selected = True\n- self._inject_available_languages_field(\'en\')\n- self.browser.getControl(\'Save\').click()\n+ self._inject_available_languages_field("en")\n+ self.browser.getControl("Save").click()\n \n self.assertEqual(settings.use_request_negotiation, True)\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_mail.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_mail.py\nindex 23b62dec2f..67fb796f9d 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_mail.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_mail.py\n@@ -18,194 +18,164 @@ class MailControlPanelFunctionalTest(unittest.TestCase):\n layer = PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING\n \n def setUp(self):\n- self.app = self.layer[\'app\']\n- self.portal = self.layer[\'portal\']\n+ self.app = self.layer["app"]\n+ self.portal = self.layer["portal"]\n self.portal_url = self.portal.absolute_url()\n self.browser = Browser(self.app)\n self.browser.handleErrors = False\n self.browser.addHeader(\n- \'Authorization\',\n- f\'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}\'\n+ "Authorization", f"Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}"\n )\n \n def test_mail_controlpanel_link(self):\n- self.browser.open(\n- "%s/@@overview-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Mail\').click()\n+ self.browser.open("%s/@@overview-controlpanel" % self.portal_url)\n+ self.browser.getLink("Mail").click()\n \n def test_mail_controlpanel_backlink(self):\n- self.browser.open(\n- "%s/@@mail-controlpanel" % self.portal_url)\n+ self.browser.open("%s/@@mail-controlpanel" % self.portal_url)\n self.assertTrue("General" in self.browser.contents)\n \n def test_mail_controlpanel_sidebar(self):\n- self.browser.open(\n- "%s/@@mail-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Site Setup\').click()\n- self.assertTrue(\n- self.browser.url.endswith(\'/plone/@@overview-controlpanel\')\n- )\n+ self.browser.open("%s/@@mail-controlpanel" % self.portal_url)\n+ self.browser.getLink("Site Setup").click()\n+ self.assertTrue(self.browser.url.endswith("/plone/@@overview-controlpanel"))\n \n def test_mail_controlpanel_view(self):\n- view = getMultiAdapter((self.portal, self.portal.REQUEST),\n- name="mail-controlpanel")\n+ view = getMultiAdapter(\n+ (self.portal, self.portal.REQUEST), name="mail-controlpanel"\n+ )\n self.assertTrue(view())\n \n def test_mail_controlpanel_smtp_host(self):\n- self.browser.open(\n- "%s/@@mail-controlpanel" % self.portal_url)\n- self.browser.getControl(\n- name=\'form.widgets.smtp_host\').value = \'example.com\'\n+ self.browser.open("%s/@@mail-controlpanel" % self.portal_url)\n+ self.browser.getControl(name="form.widgets.smtp_host").value = "example.com"\n+ self.browser.getControl(name="form.widgets.email_from_name").value = "John"\n self.browser.getControl(\n- name=\'form.widgets.email_from_name\').value = \'John\'\n- self.browser.getControl(\n- name=\'form.widgets.email_from_address\').value = \\\n- \'john@example.com\'\n- self.browser.getControl(name=\'form.buttons.save\').click()\n+ name="form.widgets.email_from_address"\n+ ).value = "john@example.com"\n+ self.browser.getControl(name="form.buttons.save").click()\n \n registry = getUtility(IRegistry)\n settings = registry.forInterface(IMailSchema, prefix="plone")\n- self.assertEqual(settings.smtp_host, \'example.com\')\n+ self.assertEqual(settings.smtp_host, "example.com")\n \n def test_mail_controlpanel_smtp_port(self):\n- self.browser.open(\n- "%s/@@mail-controlpanel" % self.portal_url)\n- self.browser.getControl(\n- name=\'form.widgets.smtp_port\').value = \'88\'\n+ self.browser.open("%s/@@mail-controlpanel" % self.portal_url)\n+ self.browser.getControl(name="form.widgets.smtp_port").value = "88"\n+ self.browser.getControl(name="form.widgets.email_from_name").value = "John"\n self.browser.getControl(\n- name=\'form.widgets.email_from_name\').value = \'John\'\n- self.browser.getControl(\n- name=\'form.widgets.email_from_address\').value = \\\n- \'john@example.com\'\n- self.browser.getControl(name=\'form.buttons.save\').click()\n+ name="form.widgets.email_from_address"\n+ ).value = "john@example.com"\n+ self.browser.getControl(name="form.buttons.save").click()\n \n registry = getUtility(IRegistry)\n settings = registry.forInterface(IMailSchema, prefix="plone")\n- self.assertEqual(str(settings.smtp_port), \'88\')\n+ self.assertEqual(str(settings.smtp_port), "88")\n \n def test_mail_controlpanel_smtp_userid(self):\n- self.browser.open(\n- "%s/@@mail-controlpanel" % self.portal_url)\n- self.browser.getControl(\n- name=\'form.widgets.smtp_userid\').value = \'john@example.com\'\n+ self.browser.open("%s/@@mail-controlpanel" % self.portal_url)\n self.browser.getControl(\n- name=\'form.widgets.email_from_name\').value = \'John\'\n+ name="form.widgets.smtp_userid"\n+ ).value = "john@example.com"\n+ self.browser.getControl(name="form.widgets.email_from_name").value = "John"\n self.browser.getControl(\n- name=\'form.widgets.email_from_address\').value = \\\n- \'john@example.com\'\n- self.browser.getControl(name=\'form.buttons.save\').click()\n+ name="form.widgets.email_from_address"\n+ ).value = "john@example.com"\n+ self.browser.getControl(name="form.buttons.save").click()\n \n registry = getUtility(IRegistry)\n settings = registry.forInterface(IMailSchema, prefix="plone")\n- self.assertEqual(settings.smtp_userid, \'john@example.com\')\n+ self.assertEqual(settings.smtp_userid, "john@example.com")\n \n def test_mail_controlpanel_smtp_pass(self):\n- self.browser.open(\n- "%s/@@mail-controlpanel" % self.portal_url)\n+ self.browser.open("%s/@@mail-controlpanel" % self.portal_url)\n+ self.browser.getControl(name="form.widgets.smtp_pass").value = "secret"\n+ self.browser.getControl(name="form.widgets.email_from_name").value = "John"\n self.browser.getControl(\n- name=\'form.widgets.smtp_pass\').value = \'secret\'\n- self.browser.getControl(\n- name=\'form.widgets.email_from_name\').value = \'John\'\n- self.browser.getControl(\n- name=\'form.widgets.email_from_address\').value = \\\n- \'john@example.com\'\n- self.browser.getControl(name=\'form.buttons.save\').click()\n+ name="form.widgets.email_from_address"\n+ ).value = "john@example.com"\n+ self.browser.getControl(name="form.buttons.save").click()\n \n registry = getUtility(IRegistry)\n settings = registry.forInterface(IMailSchema, prefix="plone")\n- self.assertEqual(settings.smtp_pass, \'secret\')\n+ self.assertEqual(settings.smtp_pass, "secret")\n \n def test_mail_controlpanel_smtp_pass_keep_on_saving(self):\n- self.browser.open(\n- "%s/@@mail-controlpanel" % self.portal_url)\n- self.browser.getControl(\n- name=\'form.widgets.smtp_userid\').value = \'john@example.com\'\n- self.browser.getControl(\n- name=\'form.widgets.smtp_pass\').value = \'secret\'\n+ self.browser.open("%s/@@mail-controlpanel" % self.portal_url)\n self.browser.getControl(\n- name=\'form.widgets.email_from_name\').value = \'John\'\n+ name="form.widgets.smtp_userid"\n+ ).value = "john@example.com"\n+ self.browser.getControl(name="form.widgets.smtp_pass").value = "secret"\n+ self.browser.getControl(name="form.widgets.email_from_name").value = "John"\n self.browser.getControl(\n- name=\'form.widgets.email_from_address\').value = \\\n- \'john@example.com\'\n- self.browser.getControl(name=\'form.buttons.save\').click()\n- self.browser.getControl(name=\'form.buttons.save\').click()\n+ name="form.widgets.email_from_address"\n+ ).value = "john@example.com"\n+ self.browser.getControl(name="form.buttons.save").click()\n+ self.browser.getControl(name="form.buttons.save").click()\n \n registry = getUtility(IRegistry)\n settings = registry.forInterface(IMailSchema, prefix="plone")\n- self.assertEqual(settings.smtp_pass, \'secret\')\n+ self.assertEqual(settings.smtp_pass, "secret")\n \n def test_mail_controlpanel_email_from_name(self):\n- self.browser.open(\n- "%s/@@mail-controlpanel" % self.portal_url)\n+ self.browser.open("%s/@@mail-controlpanel" % self.portal_url)\n+ self.browser.getControl(name="form.widgets.email_from_name").value = "John"\n self.browser.getControl(\n- name=\'form.widgets.email_from_name\').value = \'John\'\n- self.browser.getControl(\n- name=\'form.widgets.email_from_address\').value = \\\n- \'john@example.com\'\n- self.browser.getControl(name=\'form.buttons.save\').click()\n+ name="form.widgets.email_from_address"\n+ ).value = "john@example.com"\n+ self.browser.getControl(name="form.buttons.save").click()\n \n registry = getUtility(IRegistry)\n settings = registry.forInterface(IMailSchema, prefix="plone")\n- self.assertEqual(settings.email_from_name, \'John\')\n+ self.assertEqual(settings.email_from_name, "John")\n \n def test_mail_controlpanel_email_from_address(self):\n- self.browser.open(\n- "%s/@@mail-controlpanel" % self.portal_url)\n- self.browser.getControl(\n- name=\'form.widgets.email_from_name\').value = \'John\'\n+ self.browser.open("%s/@@mail-controlpanel" % self.portal_url)\n+ self.browser.getControl(name="form.widgets.email_from_name").value = "John"\n self.browser.getControl(\n- name=\'form.widgets.email_from_address\').value = \\\n- \'john@example.com\'\n- self.browser.getControl(name=\'form.buttons.save\').click()\n+ name="form.widgets.email_from_address"\n+ ).value = "john@example.com"\n+ self.browser.getControl(name="form.buttons.save").click()\n \n registry = getUtility(IRegistry)\n settings = registry.forInterface(IMailSchema, prefix="plone")\n- self.assertEqual(settings.email_from_address, \'john@example.com\')\n+ self.assertEqual(settings.email_from_address, "john@example.com")\n \n def test_mail_controlpanel_contactinfo_page(self):\n- self.browser.open(\n- "%s/@@mail-controlpanel" % self.portal_url)\n+ self.browser.open("%s/@@mail-controlpanel" % self.portal_url)\n+ self.browser.getControl(name="form.widgets.email_from_name").value = "John"\n self.browser.getControl(\n- name=\'form.widgets.email_from_name\').value = \'John\'\n- self.browser.getControl(\n- name=\'form.widgets.email_from_address\').value = \\\n- \'john@example.com\'\n- self.browser.getControl(name=\'form.buttons.save\').click()\n+ name="form.widgets.email_from_address"\n+ ).value = "john@example.com"\n+ self.browser.getControl(name="form.buttons.save").click()\n \n- self.browser.open(\n- "%s/contact-info" % self.portal_url)\n+ self.browser.open("%s/contact-info" % self.portal_url)\n self.assertTrue(\n- \'Message\' in self.browser.contents,\n- \'Message exists not in the contact-info form!\'\n+ "Message" in self.browser.contents,\n+ "Message exists not in the contact-info form!",\n )\n \n- def test_controlpanel_overview_shows_no_unconfigured_mailhost_warning(\n- self):\n- self.browser.open(\n- "%s/@@mail-controlpanel" % self.portal_url)\n- self.browser.getControl(\n- name=\'form.widgets.email_from_name\').value = \'John\'\n+ def test_controlpanel_overview_shows_no_unconfigured_mailhost_warning(self):\n+ self.browser.open("%s/@@mail-controlpanel" % self.portal_url)\n+ self.browser.getControl(name="form.widgets.email_from_name").value = "John"\n self.browser.getControl(\n- name=\'form.widgets.email_from_address\').value = \\\n- \'john@example.com\'\n- self.browser.getControl(name=\'form.buttons.save\').click()\n+ name="form.widgets.email_from_address"\n+ ).value = "john@example.com"\n+ self.browser.getControl(name="form.buttons.save").click()\n \n- self.browser.open(\n- "%s/overview-controlpanel" % self.portal_url)\n+ self.browser.open("%s/overview-controlpanel" % self.portal_url)\n self.assertFalse(\n- \'not configured a mail host\' in self.browser.contents,\n- \'There should not be a warning for unconfigured mailhost!\'\n+ "not configured a mail host" in self.browser.contents,\n+ "There should not be a warning for unconfigured mailhost!",\n )\n \n- def test_controlpanel_overview_shows_unconfigured_mailhost_warning(\n- self):\n+ def test_controlpanel_overview_shows_unconfigured_mailhost_warning(self):\n registry = getUtility(IRegistry)\n settings = registry.forInterface(IMailSchema, prefix="plone")\n settings.email_from_name = None\n settings.email_from_address = None\n- self.browser.open(\n- "%s/overview-controlpanel" % self.portal_url)\n+ self.browser.open("%s/overview-controlpanel" % self.portal_url)\n self.assertTrue(\n- \'not configured a mail host\' in self.browser.contents,\n- \'There should be a warning for unconfigured mailhost!\'\n+ "not configured a mail host" in self.browser.contents,\n+ "There should be a warning for unconfigured mailhost!",\n )\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_maintenance.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_maintenance.py\nindex c8add25703..2dc5de75bb 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_maintenance.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_maintenance.py\n@@ -9,7 +9,7 @@\n import unittest\n \n \n-has_zope4 = get_distribution(\'Zope2\').version.startswith(\'4\')\n+has_zope4 = get_distribution("Zope2").version.startswith("4")\n \n \n class MaintenanceControlPanelFunctionalTest(unittest.TestCase):\n@@ -20,71 +20,68 @@ class MaintenanceControlPanelFunctionalTest(unittest.TestCase):\n layer = PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING\n \n def setUp(self):\n- self.app = self.layer[\'app\']\n- self.request = self.layer[\'request\']\n- self.portal = self.layer[\'portal\']\n+ self.app = self.layer["app"]\n+ self.request = self.layer["request"]\n+ self.portal = self.layer["portal"]\n self.portal_url = self.portal.absolute_url()\n self.browser = Browser(self.app)\n self.browser.handleErrors = False\n # we have to create a user on the zope root. this just does not work\n # with plone.app.testing and TEST_USER or SITE_OWNER\n- self.app.acl_users.userFolderAddUser(\'app\', TEST_USER_PASSWORD, [\'Manager\'], [])\n- login(self.app[\'acl_users\'], \'app\')\n+ self.app.acl_users.userFolderAddUser("app", TEST_USER_PASSWORD, ["Manager"], [])\n+ login(self.app["acl_users"], "app")\n \n import transaction\n+\n transaction.commit()\n self.browser.addHeader(\n- \'Authorization\',\n- \'Basic {}:{}\'.format(\'app\', TEST_USER_PASSWORD)\n+ "Authorization", "Basic {}:{}".format("app", TEST_USER_PASSWORD)\n )\n \n self.site_administrator_browser = Browser(self.app)\n self.site_administrator_browser.handleErrors = False\n self.site_administrator_browser.addHeader(\n- \'Authorization\',\n- f\'Basic {TEST_USER_NAME}:{TEST_USER_PASSWORD}\'\n+ "Authorization", f"Basic {TEST_USER_NAME}:{TEST_USER_PASSWORD}"\n )\n \n def test_maintenance_control_panel_link(self):\n- self.browser.open(\n- "%s/@@overview-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Editing\').click()\n+ self.browser.open("%s/@@overview-controlpanel" % self.portal_url)\n+ self.browser.getLink("Editing").click()\n \n def test_maintenance_control_panel_backlink(self):\n- self.browser.open(\n- "%s/@@maintenance-controlpanel" % self.portal_url)\n+ self.browser.open("%s/@@maintenance-controlpanel" % self.portal_url)\n self.assertTrue("Advanced" in self.browser.contents)\n \n def test_maintenance_control_panel_sidebar(self):\n- self.browser.open(\n- "%s/@@maintenance-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Site Setup\').click()\n- self.assertTrue(\n- self.browser.url.endswith(\'/plone/@@overview-controlpanel\')\n- )\n+ self.browser.open("%s/@@maintenance-controlpanel" % self.portal_url)\n+ self.browser.getLink("Site Setup").click()\n+ self.assertTrue(self.browser.url.endswith("/plone/@@overview-controlpanel"))\n \n def test_maintenance_control_panel_raises_unauthorized(self):\n self.site_administrator_browser.open(\n- self.portal_url + \'/@@maintenance-controlpanel\')\n+ self.portal_url + "/@@maintenance-controlpanel"\n+ )\n self.assertTrue(\n- \'You are not allowed to manage the Zope server.\'\n- in self.site_administrator_browser.contents)\n+ "You are not allowed to manage the Zope server."\n+ in self.site_administrator_browser.contents\n+ )\n \n def test_maintenance_pack_database(self):\n """While we cannot test the actual packaging during tests, we can skip\n- the actual manage_pack method by providing a negative value for\n- days.\n+ the actual manage_pack method by providing a negative value for\n+ days.\n """\n- self.browser.open(self.portal_url + \'/@@maintenance-controlpanel\')\n+ self.browser.open(self.portal_url + "/@@maintenance-controlpanel")\n db = self.portal._p_jar.db()\n original_pack = db.pack\n \n def pack(self, t=None, days=0):\n pass\n+\n db.pack = pack\n \n- self.browser.getControl(name=\'form.widgets.days\').value = \'0\'\n+ self.browser.getControl(name="form.widgets.days").value = "0"\n self.browser.getControl(name="form.buttons.pack").click()\n- self.assertTrue(self.browser.url.endswith(\'maintenance-controlpanel\'))\n- self.assertTrue(\'Packed the database.\' in self.browser.contents)\n+ self.assertTrue(self.browser.url.endswith("maintenance-controlpanel"))\n+ self.assertTrue("Packed the database." in self.browser.contents)\n db.pack = original_pack\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_markup.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_markup.py\nindex 8436d3fb3f..18b726dc32 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_markup.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_markup.py\n@@ -18,87 +18,80 @@ class MarkupControlPanelFunctionalTest(unittest.TestCase):\n layer = PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING\n \n def setUp(self):\n- self.app = self.layer[\'app\']\n- self.portal = self.layer[\'portal\']\n+ self.app = self.layer["app"]\n+ self.portal = self.layer["portal"]\n self.portal_url = self.portal.absolute_url()\n self.browser = Browser(self.app)\n self.browser.handleErrors = False\n self.browser.addHeader(\n- \'Authorization\',\n- f\'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}\'\n+ "Authorization", f"Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}"\n )\n \n def test_markup_control_panel_link(self):\n- self.browser.open(\n- "%s/@@overview-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Markup\').click()\n+ self.browser.open("%s/@@overview-controlpanel" % self.portal_url)\n+ self.browser.getLink("Markup").click()\n \n def test_markup_control_panel_backlink(self):\n- self.browser.open(\n- "%s/@@markup-controlpanel" % self.portal_url)\n+ self.browser.open("%s/@@markup-controlpanel" % self.portal_url)\n self.assertTrue("Content" in self.browser.contents)\n \n def test_markup_control_panel_sidebar(self):\n- self.browser.open(\n- "%s/@@markup-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Site Setup\').click()\n- self.assertTrue(\n- self.browser.url.endswith(\'/plone/@@overview-controlpanel\')\n- )\n+ self.browser.open("%s/@@markup-controlpanel" % self.portal_url)\n+ self.browser.getLink("Site Setup").click()\n+ self.assertTrue(self.browser.url.endswith("/plone/@@overview-controlpanel"))\n \n def test_markup_controlpanel_view(self):\n- view = getMultiAdapter((self.portal, self.portal.REQUEST),\n- name="markup-controlpanel")\n+ view = getMultiAdapter(\n+ (self.portal, self.portal.REQUEST), name="markup-controlpanel"\n+ )\n self.assertTrue(view())\n \n def test_default_type(self):\n- self.browser.open(\n- "%s/@@markup-controlpanel" % self.portal_url)\n- self.browser.getControl(\'Default format\').value = [\'text/plain\']\n- self.browser.getControl(\'Save\').click()\n+ self.browser.open("%s/@@markup-controlpanel" % self.portal_url)\n+ self.browser.getControl("Default format").value = ["text/plain"]\n+ self.browser.getControl("Save").click()\n \n registry = getUtility(IRegistry)\n- settings = registry.forInterface(IMarkupSchema, prefix=\'plone\')\n- self.assertEqual(settings.default_type, \'text/plain\')\n+ settings = registry.forInterface(IMarkupSchema, prefix="plone")\n+ self.assertEqual(settings.default_type, "text/plain")\n \n def test_allowed_types(self):\n- self.browser.open(\n- "%s/@@markup-controlpanel" % self.portal_url)\n- self.browser.getControl(\n- name=\'form.widgets.allowed_types:list\'\n- ).value = [\'text/html\', \'text/x-web-textile\']\n- self.browser.getControl(\'Save\').click()\n+ self.browser.open("%s/@@markup-controlpanel" % self.portal_url)\n+ self.browser.getControl(name="form.widgets.allowed_types:list").value = [\n+ "text/html",\n+ "text/x-web-textile",\n+ ]\n+ self.browser.getControl("Save").click()\n \n registry = getUtility(IRegistry)\n- settings = registry.forInterface(IMarkupSchema, prefix=\'plone\')\n- self.assertEqual(settings.allowed_types,\n- (\'text/html\', \'text/x-web-textile\'))\n+ settings = registry.forInterface(IMarkupSchema, prefix="plone")\n+ self.assertEqual(settings.allowed_types, ("text/html", "text/x-web-textile"))\n \n def test_markdown_extensions(self):\n- self.browser.open(\n- "%s/@@markup-controlpanel" % self.portal_url)\n+ self.browser.open("%s/@@markup-controlpanel" % self.portal_url)\n self.assertEqual(\n- self.browser.getControl(\n- name=\'form.widgets.markdown_extensions\'\n- ).value,\n- \'markdown.extensions.fenced_code\\nmarkdown.extensions.nl2br\')\n+ self.browser.getControl(name="form.widgets.markdown_extensions").value,\n+ "markdown.extensions.fenced_code\\nmarkdown.extensions.nl2br",\n+ )\n \n self.browser.getControl(\n- name=\'form.widgets.markdown_extensions\'\n- ).value = \'\\n\'.join([\n- \'markdown.extensions.fenced_code\',\n- \'markdown.extensions.nl2br\',\n- \'markdown.extensions.extra\',\n- ])\n- self.browser.getControl(\'Save\').click()\n+ name="form.widgets.markdown_extensions"\n+ ).value = "\\n".join(\n+ [\n+ "markdown.extensions.fenced_code",\n+ "markdown.extensions.nl2br",\n+ "markdown.extensions.extra",\n+ ]\n+ )\n+ self.browser.getControl("Save").click()\n \n registry = getUtility(IRegistry)\n- settings = registry.forInterface(IMarkupSchema, prefix=\'plone\')\n+ settings = registry.forInterface(IMarkupSchema, prefix="plone")\n self.assertEqual(\n settings.markdown_extensions,\n [\n- \'markdown.extensions.fenced_code\',\n- \'markdown.extensions.nl2br\',\n- \'markdown.extensions.extra\',\n- ]\n+ "markdown.extensions.fenced_code",\n+ "markdown.extensions.nl2br",\n+ "markdown.extensions.extra",\n+ ],\n )\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_navigation.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_navigation.py\nindex 93f614c828..bfc28b52f4 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_navigation.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_navigation.py\n@@ -18,134 +18,128 @@ class NavigationControlPanelFunctionalTest(unittest.TestCase):\n layer = PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING\n \n def setUp(self):\n- self.app = self.layer[\'app\']\n- self.portal = self.layer[\'portal\']\n+ self.app = self.layer["app"]\n+ self.portal = self.layer["portal"]\n self.portal_url = self.portal.absolute_url()\n self.browser = Browser(self.app)\n self.browser.handleErrors = False\n self.browser.addHeader(\n- \'Authorization\',\n- f\'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}\'\n+ "Authorization", f"Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}"\n )\n \n def test_navigation_control_panel_link(self):\n- self.browser.open(\n- "%s/@@overview-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Navigation\').click()\n+ self.browser.open("%s/@@overview-controlpanel" % self.portal_url)\n+ self.browser.getLink("Navigation").click()\n self.assertTrue("Navigation Settings" in self.browser.contents)\n \n def test_navigation_control_panel_backlink(self):\n- self.browser.open(\n- "%s/@@navigation-controlpanel" % self.portal_url)\n+ self.browser.open("%s/@@navigation-controlpanel" % self.portal_url)\n self.assertTrue("General" in self.browser.contents)\n \n def test_navigation_control_panel_sidebar(self):\n- self.browser.open(\n- "%s/@@navigation-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Site Setup\').click()\n- self.assertTrue(\n- self.browser.url.endswith(\'/plone/@@overview-controlpanel\')\n- )\n+ self.browser.open("%s/@@navigation-controlpanel" % self.portal_url)\n+ self.browser.getLink("Site Setup").click()\n+ self.assertTrue(self.browser.url.endswith("/plone/@@overview-controlpanel"))\n \n def test_navigation_controlpanel_view(self):\n- view = getMultiAdapter((self.portal, self.portal.REQUEST),\n- name="navigation-controlpanel")\n+ view = getMultiAdapter(\n+ (self.portal, self.portal.REQUEST), name="navigation-controlpanel"\n+ )\n self.assertTrue(view())\n \n def test_generate_tabs(self):\n registry = getUtility(IRegistry)\n- settings = registry.forInterface(INavigationSchema, prefix=\'plone\')\n- self.browser.open(\n- "%s/@@navigation-controlpanel" % self.portal_url)\n+ settings = registry.forInterface(INavigationSchema, prefix="plone")\n+ self.browser.open("%s/@@navigation-controlpanel" % self.portal_url)\n self.assertEqual(settings.generate_tabs, True)\n self.assertEqual(\n- self.browser.getControl(\'Automatically generate tabs\').selected,\n- True\n+ self.browser.getControl("Automatically generate tabs").selected, True\n )\n- self.browser.getControl(\'Automatically generate tabs\').selected = False\n- self.browser.getControl(\'Save\').click()\n+ self.browser.getControl("Automatically generate tabs").selected = False\n+ self.browser.getControl("Save").click()\n \n self.assertEqual(settings.generate_tabs, False)\n \n def test_nonfolderish_tabs(self):\n registry = getUtility(IRegistry)\n- settings = registry.forInterface(INavigationSchema, prefix=\'plone\')\n- self.browser.open(\n- "%s/@@navigation-controlpanel" % self.portal_url)\n+ settings = registry.forInterface(INavigationSchema, prefix="plone")\n+ self.browser.open("%s/@@navigation-controlpanel" % self.portal_url)\n self.assertEqual(settings.generate_tabs, True)\n self.assertEqual(\n- self.browser.getControl(\'Automatically generate tabs\').selected,\n- True\n+ self.browser.getControl("Automatically generate tabs").selected, True\n )\n self.browser.getControl(\n- \'Generate tabs for items other than folders\').selected = False\n- self.browser.getControl(\'Save\').click()\n+ "Generate tabs for items other than folders"\n+ ).selected = False\n+ self.browser.getControl("Save").click()\n \n self.assertEqual(settings.nonfolderish_tabs, False)\n \n def test_displayed_types(self):\n registry = getUtility(IRegistry)\n- settings = registry.forInterface(INavigationSchema, prefix=\'plone\')\n- self.browser.open(\n- "%s/@@navigation-controlpanel" % self.portal_url)\n- self.browser.getControl(\'Collection\', index=0).selected = True\n- self.browser.getControl(\'Comment\').selected = True\n- self.browser.getControl(\'Event\').selected = True\n- self.browser.getControl(\'File\').selected = True\n- self.browser.getControl(\'Folder\').selected = True\n- self.browser.getControl(\'Image\').selected = True\n- self.browser.getControl(\'Link\').selected = True\n- self.browser.getControl(\'News Item\').selected = True\n- self.browser.getControl(\'Page\').selected = True\n- self.browser.getControl(\'Save\').click()\n-\n- self.assertTrue(\'Collection\' in settings.displayed_types)\n- self.assertTrue(\'Discussion Item\' in settings.displayed_types)\n- self.assertTrue(\'Event\' in settings.displayed_types)\n- self.assertTrue(\'File\' in settings.displayed_types)\n- self.assertTrue(\'Folder\' in settings.displayed_types)\n- self.assertTrue(\'Image\' in settings.displayed_types)\n- self.assertTrue(\'Link\' in settings.displayed_types)\n- self.assertTrue(\'News Item\' in settings.displayed_types)\n- self.assertTrue(\'Document\' in settings.displayed_types)\n+ settings = registry.forInterface(INavigationSchema, prefix="plone")\n+ self.browser.open("%s/@@navigation-controlpanel" % self.portal_url)\n+ self.browser.getControl("Collection", index=0).selected = True\n+ self.browser.getControl("Comment").selected = True\n+ self.browser.getControl("Event").selected = True\n+ self.browser.getControl("File").selected = True\n+ self.browser.getControl("Folder").selected = True\n+ self.browser.getControl("Image").selected = True\n+ self.browser.getControl("Link").selected = True\n+ self.browser.getControl("News Item").selected = True\n+ self.browser.getControl("Page").selected = True\n+ self.browser.getControl("Save").click()\n+\n+ self.assertTrue("Collection" in settings.displayed_types)\n+ self.assertTrue("Discussion Item" in settings.displayed_types)\n+ self.assertTrue("Event" in settings.displayed_types)\n+ self.assertTrue("File" in settings.displayed_types)\n+ self.assertTrue("Folder" in settings.displayed_types)\n+ self.assertTrue("Image" in settings.displayed_types)\n+ self.assertTrue("Link" in settings.displayed_types)\n+ self.assertTrue("News Item" in settings.displayed_types)\n+ self.assertTrue("Document" in settings.displayed_types)\n \n def test_workflow_settings(self):\n registry = getUtility(IRegistry)\n- settings = registry.forInterface(INavigationSchema, prefix=\'plone\')\n- self.browser.open(\n- "%s/@@navigation-controlpanel" % self.portal_url)\n-\n- self.browser.getControl(\'Filter on workflow state\').selected = True\n- self.browser.getControl(\'Externally visible [external]\').selected = True # noqa\n- self.browser.getControl(\'Internal draft [internal]\').selected = True\n- self.browser.getControl(\'Internally published [internally_published]\').selected = True # noqa\n- self.browser.getControl(\'Pending [pending]\').selected = True\n- self.browser.getControl(\'Private [private]\').selected = True\n- self.browser.getControl(\'Public draft [visible]\').selected = True\n- self.browser.getControl(\'Published [published]\').selected = True\n+ settings = registry.forInterface(INavigationSchema, prefix="plone")\n+ self.browser.open("%s/@@navigation-controlpanel" % self.portal_url)\n+\n+ self.browser.getControl("Filter on workflow state").selected = True\n+ self.browser.getControl("Externally visible [external]").selected = True # noqa\n+ self.browser.getControl("Internal draft [internal]").selected = True\n+ self.browser.getControl(\n+ "Internally published [internally_published]"\n+ ).selected = True # noqa\n+ self.browser.getControl("Pending [pending]").selected = True\n+ self.browser.getControl("Private [private]").selected = True\n+ self.browser.getControl("Public draft [visible]").selected = True\n+ self.browser.getControl("Published [published]").selected = True\n self.browser.getControl("Save").click()\n \n- self.assertTrue(self.browser.url.endswith(\'navigation-controlpanel\'))\n- self.assertTrue(\'Changes saved.\' in self.browser.contents)\n+ self.assertTrue(self.browser.url.endswith("navigation-controlpanel"))\n+ self.assertTrue("Changes saved." in self.browser.contents)\n \n self.assertTrue(settings.filter_on_workflow)\n \n- self.assertTrue(\'external\' in settings.workflow_states_to_show)\n- self.assertTrue(\'internal\' in settings.workflow_states_to_show)\n- self.assertTrue(\'internally_published\' in settings.workflow_states_to_show) # noqa\n- self.assertTrue(\'pending\' in settings.workflow_states_to_show)\n- self.assertTrue(\'private\' in settings.workflow_states_to_show)\n- self.assertTrue(\'visible\' in settings.workflow_states_to_show)\n- self.assertTrue(\'published\' in settings.workflow_states_to_show)\n+ self.assertTrue("external" in settings.workflow_states_to_show)\n+ self.assertTrue("internal" in settings.workflow_states_to_show)\n+ self.assertTrue(\n+ "internally_published" in settings.workflow_states_to_show\n+ ) # noqa\n+ self.assertTrue("pending" in settings.workflow_states_to_show)\n+ self.assertTrue("private" in settings.workflow_states_to_show)\n+ self.assertTrue("visible" in settings.workflow_states_to_show)\n+ self.assertTrue("published" in settings.workflow_states_to_show)\n \n def test_show_excluded_items(self):\n registry = getUtility(IRegistry)\n- settings = registry.forInterface(INavigationSchema, prefix=\'plone\')\n- self.browser.open(\n- "%s/@@navigation-controlpanel" % self.portal_url)\n+ settings = registry.forInterface(INavigationSchema, prefix="plone")\n+ self.browser.open("%s/@@navigation-controlpanel" % self.portal_url)\n \n self.browser.getControl(\n- \'Show items normally excluded from navigation if viewing their children.\').selected = False # noqa\n+ "Show items normally excluded from navigation if viewing their children."\n+ ).selected = False # noqa\n self.browser.getControl("Save").click()\n \n self.assertFalse(settings.show_excluded_items)\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_redirection.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_redirection.py\nindex ffc779744c..3a219f5e57 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_redirection.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_redirection.py\n@@ -24,19 +24,19 @@ class RedirectionControlPanelFunctionalTest(unittest.TestCase):\n layer = PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING\n \n def setUp(self):\n- self.app = self.layer[\'app\']\n- self.portal = self.layer[\'portal\']\n+ self.app = self.layer["app"]\n+ self.portal = self.layer["portal"]\n self.portal_url = self.portal.absolute_url()\n self.browser = Browser(self.app)\n self.browser.handleErrors = False\n self.browser.addHeader(\n- \'Authorization\',\n- f\'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}\',\n+ "Authorization",\n+ f"Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}",\n )\n \n def test_redirection_controlpanel_link(self):\n self.browser.open("%s/@@overview-controlpanel" % self.portal_url)\n- self.browser.getLink(\'URL Management\').click()\n+ self.browser.getLink("URL Management").click()\n \n def test_redirection_controlpanel_backlink(self):\n self.browser.open("%s/@@redirection-controlpanel" % self.portal_url)\n@@ -44,10 +44,8 @@ def test_redirection_controlpanel_backlink(self):\n \n def test_redirection_controlpanel_sidebar(self):\n self.browser.open("%s/@@redirection-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Site Setup\').click()\n- self.assertTrue(\n- self.browser.url.endswith(\'/plone/@@overview-controlpanel\')\n- )\n+ self.browser.getLink("Site Setup").click()\n+ self.assertTrue(self.browser.url.endswith("/plone/@@overview-controlpanel"))\n \n def test_redirection_controlpanel_view(self):\n view = getMultiAdapter(\n@@ -57,14 +55,14 @@ def test_redirection_controlpanel_view(self):\n \n def test_redirection_controlpanel_add_redirect(self):\n storage = getUtility(IRedirectionStorage)\n- redirection_path = \'/alias-folder\'\n- target_path = \'/test-folder\'\n- storage_path = \'/plone/alias-folder\'\n+ redirection_path = "/alias-folder"\n+ target_path = "/test-folder"\n+ storage_path = "/plone/alias-folder"\n \n self.browser.open("%s/@@redirection-controlpanel" % self.portal_url)\n- self.browser.getControl(name=\'redirection\').value = redirection_path\n- self.browser.getControl(name=\'target_path\').value = target_path\n- self.browser.getControl(name=\'form.button.Add\').click()\n+ self.browser.getControl(name="redirection").value = redirection_path\n+ self.browser.getControl(name="target_path").value = target_path\n+ self.browser.getControl(name="form.button.Add").click()\n \n self.assertTrue(\n storage.has_path(storage_path),\n@@ -74,73 +72,72 @@ def test_redirection_controlpanel_add_redirect(self):\n def test_redirection_controlpanel_remove_redirects(self):\n storage = getUtility(IRedirectionStorage)\n for i in range(31):\n- storage[f\'/plone/alias{i}\'] = \'/plone/test-folder\'\n+ storage[f"/plone/alias{i}"] = "/plone/test-folder"\n transaction.commit()\n \n self.browser.open("%s/@@redirection-controlpanel" % self.portal_url)\n # A batch of 15 is shown, so some are missing.\n- self.assertTrue(\'/plone/alias1\' in self.browser.contents)\n- self.assertTrue(\'/plone/alias10\' in self.browser.contents)\n- self.assertTrue(\'/plone/alias19\' in self.browser.contents)\n- self.assertTrue(\'/plone/alias2\' in self.browser.contents)\n- self.assertFalse(\'/plone/alias29\' in self.browser.contents)\n+ self.assertTrue("/plone/alias1" in self.browser.contents)\n+ self.assertTrue("/plone/alias10" in self.browser.contents)\n+ self.assertTrue("/plone/alias19" in self.browser.contents)\n+ self.assertTrue("/plone/alias2" in self.browser.contents)\n+ self.assertFalse("/plone/alias29" in self.browser.contents)\n # query aliases starting with /alias2\n- self.browser.getControl(name=\'q\').value = \'/alias2\'\n- self.browser.getControl(name=\'form.button.filter\').click()\n- self.assertFalse(\'/plone/alias1\' in self.browser.contents)\n- self.assertTrue(\'/plone/alias2\' in self.browser.contents)\n- self.assertTrue(\'/plone/alias29\' in self.browser.contents)\n+ self.browser.getControl(name="q").value = "/alias2"\n+ self.browser.getControl(name="form.button.filter").click()\n+ self.assertFalse("/plone/alias1" in self.browser.contents)\n+ self.assertTrue("/plone/alias2" in self.browser.contents)\n+ self.assertTrue("/plone/alias29" in self.browser.contents)\n # The filter could return one value too much.\n # This tests that we have excludemax=True in the RedirectionSet.\n- self.assertFalse(\'/plone/alias3\' in self.browser.contents)\n- self.assertFalse(\'/plone/alias30\' in self.browser.contents)\n+ self.assertFalse("/plone/alias3" in self.browser.contents)\n+ self.assertFalse("/plone/alias30" in self.browser.contents)\n # Remove two.\n- self.browser.getControl(name=\'redirects:tuple\').value = [\n- \'/plone/alias2\',\n- \'/plone/alias20\',\n+ self.browser.getControl(name="redirects:tuple").value = [\n+ "/plone/alias2",\n+ "/plone/alias20",\n ]\n- self.browser.getControl(name=\'form.button.Remove\').click()\n- self.assertFalse(\'/plone/alias2\' in storage)\n- self.assertFalse(\'/plone/alias20\' in storage)\n- self.assertTrue(\'/plone/alias1\' in storage)\n- self.assertTrue(\'/plone/alias29\' in storage)\n- self.assertEqual(storage.get(\'/plone/alias29\'), \'/plone/test-folder\')\n+ self.browser.getControl(name="form.button.Remove").click()\n+ self.assertFalse("/plone/alias2" in storage)\n+ self.assertFalse("/plone/alias20" in storage)\n+ self.assertTrue("/plone/alias1" in storage)\n+ self.assertTrue("/plone/alias29" in storage)\n+ self.assertEqual(storage.get("/plone/alias29"), "/plone/test-folder")\n \n def test_redirection_controlpanel_remove_matching_redirects(self):\n storage = getUtility(IRedirectionStorage)\n for i in range(30):\n- storage[f\'/plone/alias{i}\'] = \'/plone/test-folder\'\n+ storage[f"/plone/alias{i}"] = "/plone/test-folder"\n transaction.commit()\n \n # Removing matching redirects can only happen when a filter is selected.\n self.browser.open("%s/@@redirection-controlpanel" % self.portal_url)\n- self.browser.getControl(name=\'form.button.MatchRemove\').click()\n+ self.browser.getControl(name="form.button.MatchRemove").click()\n self.assertTrue(\n- \'No alternative urls selected for removal.\'\n- in self.browser.contents\n+ "No alternative urls selected for removal." in self.browser.contents\n )\n self.assertEqual(len(storage), 30)\n # query aliases starting with /alias2\n- self.browser.getControl(name=\'q\').value = \'/alias2\'\n+ self.browser.getControl(name="q").value = "/alias2"\n # The filter is immediately taken into account,\n # without first explicitly clicking filter.\n # self.browser.getControl(name=\'form.button.filter\').click()\n- self.browser.getControl(name=\'form.button.MatchRemove\').click()\n+ self.browser.getControl(name="form.button.MatchRemove").click()\n self.assertEqual(len(storage), 19)\n- self.assertFalse(\'/plone/alias2\' in storage)\n- self.assertFalse(\'/plone/alias20\' in storage)\n- self.assertFalse(\'/plone/alias29\' in storage)\n- self.assertTrue(\'/plone/alias1\' in storage)\n- self.assertTrue(\'/plone/alias12\' in storage)\n+ self.assertFalse("/plone/alias2" in storage)\n+ self.assertFalse("/plone/alias20" in storage)\n+ self.assertFalse("/plone/alias29" in storage)\n+ self.assertTrue("/plone/alias1" in storage)\n+ self.assertTrue("/plone/alias12" in storage)\n \n def test_redirection_controlpanel_set(self):\n storage = getUtility(IRedirectionStorage)\n- portal_path = self.layer[\'portal\'].absolute_url_path()\n- now = DateTime(\'2022-02-03\')\n+ portal_path = self.layer["portal"].absolute_url_path()\n+ now = DateTime("2022-02-03")\n for i in range(1000):\n storage.add(\n- f\'{portal_path:s}/foo/{str(i):s}\',\n- f\'{portal_path:s}/bar/{str(i):s}\',\n+ f"{portal_path:s}/foo/{str(i):s}",\n+ f"{portal_path:s}/bar/{str(i):s}",\n now=now,\n )\n redirects = RedirectionSet()\n@@ -148,148 +145,147 @@ def test_redirection_controlpanel_set(self):\n self.assertDictEqual(\n redirects[0],\n {\n- \'datetime\': DateTime(\'2022-02-03\'),\n- \'manual\': False,\n- \'path\': \'/foo/0\',\n- \'redirect\': f\'{portal_path:s}/foo/0\',\n- \'redirect-to\': \'/bar/0\',\n+ "datetime": DateTime("2022-02-03"),\n+ "manual": False,\n+ "path": "/foo/0",\n+ "redirect": f"{portal_path:s}/foo/0",\n+ "redirect-to": "/bar/0",\n },\n )\n self.assertDictEqual(\n redirects[999],\n {\n- \'datetime\': DateTime(\'2022-02-03\'),\n- \'manual\': False,\n- \'path\': \'/foo/999\',\n- \'redirect\': f\'{portal_path:s}/foo/999\',\n- \'redirect-to\': \'/bar/999\',\n+ "datetime": DateTime("2022-02-03"),\n+ "manual": False,\n+ "path": "/foo/999",\n+ "redirect": f"{portal_path:s}/foo/999",\n+ "redirect-to": "/bar/999",\n },\n )\n self.assertEqual(len(list(iter(redirects))), 1000)\n self.assertDictEqual(\n list(iter(redirects))[0],\n {\n- \'datetime\': DateTime(\'2022-02-03\'),\n- \'manual\': False,\n- \'path\': \'/foo/0\',\n- \'redirect\': f\'{portal_path:s}/foo/0\',\n- \'redirect-to\': \'/bar/0\',\n+ "datetime": DateTime("2022-02-03"),\n+ "manual": False,\n+ "path": "/foo/0",\n+ "redirect": f"{portal_path:s}/foo/0",\n+ "redirect-to": "/bar/0",\n },\n )\n \n def test_redirection_controlpanel_batching(self):\n storage = getUtility(IRedirectionStorage)\n- portal_path = self.layer[\'portal\'].absolute_url_path()\n+ portal_path = self.layer["portal"].absolute_url_path()\n for i in range(1000):\n storage.add(\n- f\'{portal_path:s}/foo/{str(i):s}\',\n- f\'{portal_path:s}/bar/{str(i):s}\',\n+ f"{portal_path:s}/foo/{str(i):s}",\n+ f"{portal_path:s}/bar/{str(i):s}",\n )\n view = getMultiAdapter(\n- (self.layer[\'portal\'], self.layer[\'request\']),\n- name=\'redirection-controlpanel\',\n+ (self.layer["portal"], self.layer["request"]),\n+ name="redirection-controlpanel",\n )\n # Test that view/redirects returns batch\n self.assertIsInstance(view.redirects(), Batch)\n \n # Test that view/batching returns batching with anchor in urls\n batching = view.batching()\n- self.assertIn(\'?b_start:int=990#manage-existing-aliases\', batching)\n+ self.assertIn("?b_start:int=990#manage-existing-aliases", batching)\n \n def test_redirection_controlpanel_redirect_alias_exists(self):\n- path_alias = \'/alias\'\n- path_target = \'/test-folder\'\n- storage_alias = f\'/plone{path_alias}\'\n- storage_target = f\'/plone{path_target}\'\n+ path_alias = "/alias"\n+ path_target = "/test-folder"\n+ storage_alias = f"/plone{path_alias}"\n+ storage_target = f"/plone{path_target}"\n storage = getUtility(IRedirectionStorage)\n storage.add(storage_alias, storage_target)\n transaction.commit()\n \n self.browser.open("%s/@@redirection-controlpanel" % self.portal_url)\n- self.browser.getControl(name=\'redirection\').value = path_alias\n- self.browser.getControl(name=\'target_path\').value = path_target\n- self.browser.getControl(name=\'form.button.Add\').click()\n+ self.browser.getControl(name="redirection").value = path_alias\n+ self.browser.getControl(name="target_path").value = path_target\n+ self.browser.getControl(name="form.button.Add").click()\n \n self.assertTrue(\n storage.get(storage_alias) == storage_target,\n- f\'{storage_target} not target of alternative url!\',\n+ f"{storage_target} not target of alternative url!",\n )\n self.assertTrue(\n- \'The provided alternative url already exists!\'\n- in self.browser.contents,\n+ "The provided alternative url already exists!" in self.browser.contents,\n \'Message "alternative url already exists" not in page!\',\n )\n \n def test_redirection_controlpanel_filtering(self):\n storage = getUtility(IRedirectionStorage)\n- portal_path = self.layer[\'portal\'].absolute_url_path()\n+ portal_path = self.layer["portal"].absolute_url_path()\n for i in range(1000):\n storage.add(\n- f\'{portal_path:s}/foo1/{str(i):s}\',\n- f\'{portal_path:s}/bar/{str(i):s}\',\n+ f"{portal_path:s}/foo1/{str(i):s}",\n+ f"{portal_path:s}/bar/{str(i):s}",\n )\n for i in range(1000):\n storage.add(\n- f\'{portal_path:s}/foo2/{str(i):s}\',\n- f\'{portal_path:s}/bar/{str(i):s}\',\n+ f"{portal_path:s}/foo2/{str(i):s}",\n+ f"{portal_path:s}/bar/{str(i):s}",\n )\n \n redirects = RedirectionSet()\n self.assertEqual(len(redirects), 2000)\n- redirects = RedirectionSet(query=\'/foo\')\n+ redirects = RedirectionSet(query="/foo")\n self.assertEqual(len(redirects), 2000)\n- redirects = RedirectionSet(query=\'/foo1\')\n+ redirects = RedirectionSet(query="/foo1")\n self.assertEqual(len(redirects), 1000)\n- redirects = RedirectionSet(query=\'/foo2\')\n+ redirects = RedirectionSet(query="/foo2")\n self.assertEqual(len(redirects), 1000)\n # this should return one and not two (we need excludemax=True)\n- redirects = RedirectionSet(query=\'/foo1/777\')\n+ redirects = RedirectionSet(query="/foo1/777")\n self.assertEqual(len(redirects), 1)\n \n- request = self.layer[\'request\'].clone()\n- request.form[\'q\'] = \'/foo\'\n+ request = self.layer["request"].clone()\n+ request.form["q"] = "/foo"\n view = getMultiAdapter(\n- (self.layer[\'portal\'], request), name=\'redirection-controlpanel\'\n+ (self.layer["portal"], request), name="redirection-controlpanel"\n )\n self.assertEqual(view.redirects().numpages, math.ceil(2000 / 15.0))\n \n- request = self.layer[\'request\'].clone()\n- request.form[\'q\'] = \'/foo1\'\n+ request = self.layer["request"].clone()\n+ request.form["q"] = "/foo1"\n view = getMultiAdapter(\n- (self.layer[\'portal\'], request), name=\'redirection-controlpanel\'\n+ (self.layer["portal"], request), name="redirection-controlpanel"\n )\n self.assertEqual(view.redirects().numpages, math.ceil(1000 / 15.0))\n \n- request = self.layer[\'request\'].clone()\n- request.form[\'q\'] = \'/foo2\'\n+ request = self.layer["request"].clone()\n+ request.form["q"] = "/foo2"\n view = getMultiAdapter(\n- (self.layer[\'portal\'], request), name=\'redirection-controlpanel\'\n+ (self.layer["portal"], request), name="redirection-controlpanel"\n )\n self.assertEqual(view.redirects().numpages, math.ceil(1000 / 15.0))\n \n- request = self.layer[\'request\'].clone()\n+ request = self.layer["request"].clone()\n view = getMultiAdapter(\n- (self.layer[\'portal\'], request), name=\'redirection-controlpanel\'\n+ (self.layer["portal"], request), name="redirection-controlpanel"\n )\n self.assertEqual(view.redirects().numpages, math.ceil(2000 / 15.0))\n \n # Filtering without new request does not have effect because memoize\n- request.form[\'q\'] = \'/foo2\'\n+ request.form["q"] = "/foo2"\n self.assertEqual(view.redirects().numpages, math.ceil(2000 / 15.0))\n \n def test_redirection_controlpanel_filter_manual(self):\n storage = getUtility(IRedirectionStorage)\n- portal_path = self.layer[\'portal\'].absolute_url_path()\n+ portal_path = self.layer["portal"].absolute_url_path()\n for i in range(100):\n storage.add(\n- f\'{portal_path:s}/foo/{str(i):s}\',\n- f\'{portal_path:s}/bar/{str(i):s}\',\n+ f"{portal_path:s}/foo/{str(i):s}",\n+ f"{portal_path:s}/bar/{str(i):s}",\n manual=False,\n )\n for i in range(100, 300):\n storage.add(\n- f\'{portal_path:s}/foo/{str(i):s}\',\n- f\'{portal_path:s}/bar/{str(i):s}\',\n+ f"{portal_path:s}/foo/{str(i):s}",\n+ f"{portal_path:s}/bar/{str(i):s}",\n manual=True,\n )\n \n@@ -297,44 +293,44 @@ def test_redirection_controlpanel_filter_manual(self):\n self.assertEqual(len(redirects), 300)\n # Form has yes, no, or empty string, anything else is ignored\n # (so treated as empty string).\n- redirects = RedirectionSet(manual=\'yes\')\n+ redirects = RedirectionSet(manual="yes")\n self.assertEqual(len(redirects), 200)\n- redirects = RedirectionSet(manual=\'no\')\n+ redirects = RedirectionSet(manual="no")\n self.assertEqual(len(redirects), 100)\n- redirects = RedirectionSet(manual=\'\')\n+ redirects = RedirectionSet(manual="")\n self.assertEqual(len(redirects), 300)\n- redirects = RedirectionSet(manual=\'badvalue\')\n+ redirects = RedirectionSet(manual="badvalue")\n self.assertEqual(len(redirects), 300)\n \n- request = self.layer[\'request\'].clone()\n- request.form[\'manual\'] = \'\'\n+ request = self.layer["request"].clone()\n+ request.form["manual"] = ""\n view = getMultiAdapter(\n- (self.layer[\'portal\'], request), name=\'redirection-controlpanel\'\n+ (self.layer["portal"], request), name="redirection-controlpanel"\n )\n self.assertEqual(view.redirects().numpages, math.ceil(300 / 15.0))\n \n- request = self.layer[\'request\'].clone()\n- request.form[\'manual\'] = \'yes\'\n+ request = self.layer["request"].clone()\n+ request.form["manual"] = "yes"\n view = getMultiAdapter(\n- (self.layer[\'portal\'], request), name=\'redirection-controlpanel\'\n+ (self.layer["portal"], request), name="redirection-controlpanel"\n )\n self.assertEqual(view.redirects().numpages, math.ceil(200 / 15.0))\n \n- request = self.layer[\'request\'].clone()\n- request.form[\'manual\'] = \'no\'\n+ request = self.layer["request"].clone()\n+ request.form["manual"] = "no"\n view = getMultiAdapter(\n- (self.layer[\'portal\'], request), name=\'redirection-controlpanel\'\n+ (self.layer["portal"], request), name="redirection-controlpanel"\n )\n self.assertEqual(view.redirects().numpages, math.ceil(100 / 15.0))\n \n def test_redirection_controlpanel_filter_date(self):\n storage = getUtility(IRedirectionStorage)\n- portal_path = self.layer[\'portal\'].absolute_url_path()\n- time0 = DateTime(\'2001-01-01\')\n+ portal_path = self.layer["portal"].absolute_url_path()\n+ time0 = DateTime("2001-01-01")\n for i in range(400):\n storage.add(\n- f\'{portal_path:s}/foo/{str(i):s}\',\n- f\'{portal_path:s}/bar/{str(i):s}\',\n+ f"{portal_path:s}/foo/{str(i):s}",\n+ f"{portal_path:s}/bar/{str(i):s}",\n now=time0 + i,\n )\n \n@@ -342,170 +338,162 @@ def test_redirection_controlpanel_filter_date(self):\n self.assertEqual(len(redirects), 400)\n # created can be anything that can be parsed by DateTime.\n # Otherwise it is ignored.\n- self.assertEqual(len(RedirectionSet(created=\'2019-01-01\')), 400)\n- self.assertEqual(len(RedirectionSet(created=\'1999-01-01\')), 0)\n- self.assertEqual(len(RedirectionSet(created=\'2001-01-01\')), 0)\n- self.assertEqual(len(RedirectionSet(created=\'2001-01-02\')), 1)\n- self.assertEqual(len(RedirectionSet(created=\'2001-02-01\')), 31)\n- self.assertEqual(len(RedirectionSet(created=\'2001-02-01 00:00:00\')), 31)\n- self.assertEqual(len(RedirectionSet(created=\'2001-02-01 00:00:01\')), 32)\n- self.assertEqual(len(RedirectionSet(created=\'badvalue\')), 400)\n+ self.assertEqual(len(RedirectionSet(created="2019-01-01")), 400)\n+ self.assertEqual(len(RedirectionSet(created="1999-01-01")), 0)\n+ self.assertEqual(len(RedirectionSet(created="2001-01-01")), 0)\n+ self.assertEqual(len(RedirectionSet(created="2001-01-02")), 1)\n+ self.assertEqual(len(RedirectionSet(created="2001-02-01")), 31)\n+ self.assertEqual(len(RedirectionSet(created="2001-02-01 00:00:00")), 31)\n+ self.assertEqual(len(RedirectionSet(created="2001-02-01 00:00:01")), 32)\n+ self.assertEqual(len(RedirectionSet(created="badvalue")), 400)\n \n # DateTime(\'2002-01-01\') results in a timezone GMT+0\n- self.assertEqual(len(RedirectionSet(created=\'2002-01-01\')), 365)\n+ self.assertEqual(len(RedirectionSet(created="2002-01-01")), 365)\n # DateTime(\'2002/01/01\') results in a timezone GMT+1 for me,\n # or a different zone depending on where in the world you are.\n # So we need to be lenient in the tests.\n- self.assertGreaterEqual(len(RedirectionSet(created=\'2002/01/01\')), 364)\n- self.assertLessEqual(len(RedirectionSet(created=\'2002/01/01\')), 366)\n+ self.assertGreaterEqual(len(RedirectionSet(created="2002/01/01")), 364)\n+ self.assertLessEqual(len(RedirectionSet(created="2002/01/01")), 366)\n \n- request = self.layer[\'request\'].clone()\n- request.form[\'datetime\'] = \'\'\n+ request = self.layer["request"].clone()\n+ request.form["datetime"] = ""\n view = getMultiAdapter(\n- (self.layer[\'portal\'], request), name=\'redirection-controlpanel\'\n+ (self.layer["portal"], request), name="redirection-controlpanel"\n )\n self.assertEqual(view.redirects().numpages, math.ceil(400 / 15.0))\n \n- request = self.layer[\'request\'].clone()\n- request.form[\'datetime\'] = \'2001-01-27\'\n+ request = self.layer["request"].clone()\n+ request.form["datetime"] = "2001-01-27"\n view = getMultiAdapter(\n- (self.layer[\'portal\'], request), name=\'redirection-controlpanel\'\n+ (self.layer["portal"], request), name="redirection-controlpanel"\n )\n self.assertEqual(view.redirects().numpages, math.ceil(27 / 15.0))\n \n- request = self.layer[\'request\'].clone()\n- request.form[\'datetime\'] = \'2002-01-01\'\n+ request = self.layer["request"].clone()\n+ request.form["datetime"] = "2002-01-01"\n view = getMultiAdapter(\n- (self.layer[\'portal\'], request), name=\'redirection-controlpanel\'\n+ (self.layer["portal"], request), name="redirection-controlpanel"\n )\n self.assertEqual(view.redirects().numpages, math.ceil(365 / 15.0))\n \n- request = self.layer[\'request\'].clone()\n- request.form[\'datetime\'] = \'2019-01-01\'\n+ request = self.layer["request"].clone()\n+ request.form["datetime"] = "2019-01-01"\n view = getMultiAdapter(\n- (self.layer[\'portal\'], request), name=\'redirection-controlpanel\'\n+ (self.layer["portal"], request), name="redirection-controlpanel"\n )\n self.assertEqual(view.redirects().numpages, math.ceil(400 / 15.0))\n \n def test_redirection_controlpanel_redirect_no_target(self):\n- path_alias = \'/alias\'\n- path_target = \'/not-existing\'\n+ path_alias = "/alias"\n+ path_target = "/not-existing"\n \n self.browser.open("%s/@@redirection-controlpanel" % self.portal_url)\n- self.browser.getControl(name=\'redirection\').value = path_alias\n- self.browser.getControl(name=\'target_path\').value = path_target\n- self.browser.getControl(name=\'form.button.Add\').click()\n+ self.browser.getControl(name="redirection").value = path_alias\n+ self.browser.getControl(name="target_path").value = path_target\n+ self.browser.getControl(name="form.button.Add").click()\n \n self.assertTrue(\n- \'The provided target object does not exist.\'\n- in self.browser.contents,\n+ "The provided target object does not exist." in self.browser.contents,\n \'Message "target does not exist" not in page!\',\n )\n \n def test_redirection_controlpanel_missing_slash_target(self):\n- path_alias = \'/alias\'\n- path_target = \'Members\'\n+ path_alias = "/alias"\n+ path_target = "Members"\n \n self.browser.open("%s/@@redirection-controlpanel" % self.portal_url)\n- self.browser.getControl(name=\'redirection\').value = path_alias\n- self.browser.getControl(name=\'target_path\').value = path_target\n- self.browser.getControl(name=\'form.button.Add\').click()\n+ self.browser.getControl(name="redirection").value = path_alias\n+ self.browser.getControl(name="target_path").value = path_target\n+ self.browser.getControl(name="form.button.Add").click()\n \n self.assertTrue(\n- \'Target path must start with a slash.\' in self.browser.contents,\n- \'Errormessage for missing slash on target path missing\',\n+ "Target path must start with a slash." in self.browser.contents,\n+ "Errormessage for missing slash on target path missing",\n )\n \n def test_redirection_controlpanel_missing_slash_alias(self):\n- path_alias = \'alias\'\n- path_target = \'/Members\'\n+ path_alias = "alias"\n+ path_target = "/Members"\n \n self.browser.open("%s/@@redirection-controlpanel" % self.portal_url)\n- self.browser.getControl(name=\'redirection\').value = path_alias\n- self.browser.getControl(name=\'target_path\').value = path_target\n- self.browser.getControl(name=\'form.button.Add\').click()\n+ self.browser.getControl(name="redirection").value = path_alias\n+ self.browser.getControl(name="target_path").value = path_target\n+ self.browser.getControl(name="form.button.Add").click()\n \n self.assertTrue(\n- \'Alternative url path must start with a slash.\'\n- in self.browser.contents,\n- \'Errormessage for missing slash on alternative url missing\',\n+ "Alternative url path must start with a slash." in self.browser.contents,\n+ "Errormessage for missing slash on alternative url missing",\n )\n \n def test_manage_aliases_standard(self):\n storage = getUtility(IRedirectionStorage)\n- folder = self.portal[\'test-folder\']\n+ folder = self.portal["test-folder"]\n \n self.browser.open("%s/@@manage-aliases" % folder.absolute_url())\n- self.browser.getControl(name=\'redirection\').value = \'/alias\'\n- self.browser.getControl(name=\'form.button.Add\').click()\n+ self.browser.getControl(name="redirection").value = "/alias"\n+ self.browser.getControl(name="form.button.Add").click()\n \n self.assertTrue(\n- \'Alternative url added.\' in self.browser.contents,\n- \'Message for added alternative url missing\',\n+ "Alternative url added." in self.browser.contents,\n+ "Message for added alternative url missing",\n )\n- self.assertTrue(storage.has_path(\'/plone/alias\'))\n- self.assertEqual(storage.get(\'/plone/alias\'), \'/plone/test-folder\')\n+ self.assertTrue(storage.has_path("/plone/alias"))\n+ self.assertEqual(storage.get("/plone/alias"), "/plone/test-folder")\n \n def test_manage_aliases_remove(self):\n storage = getUtility(IRedirectionStorage)\n- folder = self.portal[\'test-folder\']\n- storage[\'/plone/alias1\'] = \'/plone/test-folder\'\n- storage[\'/plone/alias2\'] = \'/plone/test-folder\'\n- storage[\'/plone/alias3\'] = \'/plone/test-folder\'\n+ folder = self.portal["test-folder"]\n+ storage["/plone/alias1"] = "/plone/test-folder"\n+ storage["/plone/alias2"] = "/plone/test-folder"\n+ storage["/plone/alias3"] = "/plone/test-folder"\n transaction.commit()\n \n self.browser.open("%s/@@manage-aliases" % folder.absolute_url())\n- self.browser.getControl(name=\'redirects:tuple\').value = [\n- \'/plone/alias1\',\n- \'/plone/alias2\',\n+ self.browser.getControl(name="redirects:tuple").value = [\n+ "/plone/alias1",\n+ "/plone/alias2",\n ]\n- self.browser.getControl(name=\'form.button.Remove\').click()\n+ self.browser.getControl(name="form.button.Remove").click()\n \n self.assertTrue(\n- \'Alternative urls removed.\' in self.browser.contents,\n- \'Message for removed alternative url missing\',\n+ "Alternative urls removed." in self.browser.contents,\n+ "Message for removed alternative url missing",\n )\n- self.assertFalse(\'/plone/alias1\' in storage)\n- self.assertFalse(\'/plone/alias2\' in storage)\n- self.assertTrue(\'/plone/alias3\' in storage)\n- self.assertEqual(storage.get(\'/plone/alias3\'), \'/plone/test-folder\')\n+ self.assertFalse("/plone/alias1" in storage)\n+ self.assertFalse("/plone/alias2" in storage)\n+ self.assertTrue("/plone/alias3" in storage)\n+ self.assertEqual(storage.get("/plone/alias3"), "/plone/test-folder")\n \n def test_manage_aliases_navigation_root(self):\n from plone.app.layout.navigation.interfaces import INavigationRoot\n from zope.interface import alsoProvides\n \n storage = getUtility(IRedirectionStorage)\n- folder = self.portal[\'test-folder\']\n+ folder = self.portal["test-folder"]\n alsoProvides(folder, INavigationRoot)\n transaction.commit()\n \n self.browser.open("%s/@@manage-aliases" % folder.absolute_url())\n- self.browser.getControl(name=\'redirection\').value = \'/alias\'\n- self.browser.getControl(name=\'form.button.Add\').click()\n+ self.browser.getControl(name="redirection").value = "/alias"\n+ self.browser.getControl(name="form.button.Add").click()\n \n self.assertTrue(\n- \'Alternative url added.\' in self.browser.contents,\n- \'Message for added alternative url missing\',\n- )\n- self.assertTrue(storage.has_path(\'/plone/test-folder/alias\'))\n- self.assertEqual(\n- storage.get(\'/plone/test-folder/alias\'), \'/plone/test-folder\'\n+ "Alternative url added." in self.browser.contents,\n+ "Message for added alternative url missing",\n )\n+ self.assertTrue(storage.has_path("/plone/test-folder/alias"))\n+ self.assertEqual(storage.get("/plone/test-folder/alias"), "/plone/test-folder")\n \n # Add the navigation root path explicitly.\n- self.browser.getControl(\n- name=\'redirection\'\n- ).value = \'/test-folder/alias2\'\n- self.browser.getControl(name=\'form.button.Add\').click()\n+ self.browser.getControl(name="redirection").value = "/test-folder/alias2"\n+ self.browser.getControl(name="form.button.Add").click()\n \n self.assertTrue(\n- \'Alternative url added.\' in self.browser.contents,\n- \'Message for added alternative url missing\',\n- )\n- self.assertTrue(storage.has_path(\'/plone/test-folder/alias2\'))\n- self.assertEqual(\n- storage.get(\'/plone/test-folder/alias2\'), \'/plone/test-folder\'\n+ "Alternative url added." in self.browser.contents,\n+ "Message for added alternative url missing",\n )\n+ self.assertTrue(storage.has_path("/plone/test-folder/alias2"))\n+ self.assertEqual(storage.get("/plone/test-folder/alias2"), "/plone/test-folder")\n \n def test_absolutize_path(self):\n # absolutize_path is a helper function that returns a tuple\n@@ -515,59 +503,57 @@ def test_absolutize_path(self):\n )\n \n # A path is required.\n- self.assertEqual(ap(\'\'), (\'\', \'You have to enter an alternative url.\'))\n- self.assertEqual(\n- ap(\'\', is_source=False), (\'\', \'You have to enter a target.\')\n- )\n+ self.assertEqual(ap(""), ("", "You have to enter an alternative url."))\n+ self.assertEqual(ap("", is_source=False), ("", "You have to enter a target."))\n \n # relative paths are not accepted\n self.assertEqual(\n- ap(\'foo\'), (\'foo\', \'Alternative url path must start with a slash.\')\n+ ap("foo"), ("foo", "Alternative url path must start with a slash.")\n )\n self.assertEqual(\n- ap(\'foo\', is_source=True),\n- (\'foo\', \'Alternative url path must start with a slash.\'),\n+ ap("foo", is_source=True),\n+ ("foo", "Alternative url path must start with a slash."),\n )\n self.assertEqual(\n- ap(\'foo\', is_source=False),\n- (\'foo\', \'Target path must start with a slash.\'),\n+ ap("foo", is_source=False),\n+ ("foo", "Target path must start with a slash."),\n )\n \n # absolute paths are good\n- self.assertEqual(ap(\'/foo\'), (\'/plone/foo\', None))\n- self.assertEqual(ap(\'/foo\', is_source=True), (\'/plone/foo\', None))\n+ self.assertEqual(ap("/foo"), ("/plone/foo", None))\n+ self.assertEqual(ap("/foo", is_source=True), ("/plone/foo", None))\n \n # for targets, an object must exist on the path\n self.assertEqual(\n- ap(\'/foo\', is_source=False),\n- (\'/plone/foo\', \'The provided target object does not exist.\'),\n+ ap("/foo", is_source=False),\n+ ("/plone/foo", "The provided target object does not exist."),\n )\n self.assertEqual(\n- ap(\'/test-folder\', is_source=False), (\'/plone/test-folder\', None)\n+ ap("/test-folder", is_source=False), ("/plone/test-folder", None)\n )\n self.assertEqual(\n- ap(\'/test-folder/@@sharing\', is_source=False),\n- (\'/test-folder/@@sharing\', \'Target path must not be a view.\'),\n+ ap("/test-folder/@@sharing", is_source=False),\n+ ("/test-folder/@@sharing", "Target path must not be a view."),\n )\n \n # A source must not exist.\n self.assertEqual(\n- ap(\'/test-folder\'),\n+ ap("/test-folder"),\n (\n- \'/plone/test-folder\',\n- \'Cannot use a working path as alternative url.\',\n+ "/plone/test-folder",\n+ "Cannot use a working path as alternative url.",\n ),\n )\n # More general: a source must not be traversable already.\n self.assertEqual(\n- ap(\'/view\'),\n- (\'/plone/view\', \'Cannot use a working path as alternative url.\'),\n+ ap("/view"),\n+ ("/plone/view", "Cannot use a working path as alternative url."),\n )\n self.assertEqual(\n- ap(\'/@@overview-controlpanel\'),\n+ ap("/@@overview-controlpanel"),\n (\n- \'/@@overview-controlpanel\',\n- \'Alternative url path must not be a view.\',\n+ "/@@overview-controlpanel",\n+ "Alternative url path must not be a view.",\n ),\n )\n \n@@ -575,12 +561,12 @@ def test_absolutize_path(self):\n # We might *want* to allow this, but such a redirect would not have effect,\n # because acquisition happens earlier.\n # See https://github.com/collective/Products.RedirectionTool/issues/12\n- self.portal.invokeFactory(\'Document\', \'doc\')\n+ self.portal.invokeFactory("Document", "doc")\n self.assertEqual(\n- ap(\'/test-folder/doc\'),\n+ ap("/test-folder/doc"),\n (\n- \'/plone/test-folder/doc\',\n- \'Cannot use a working path as alternative url.\',\n+ "/plone/test-folder/doc",\n+ "Cannot use a working path as alternative url.",\n ),\n )\n \n@@ -588,43 +574,43 @@ def test_absolutize_path(self):\n storage = getUtility(IRedirectionStorage)\n portal_path = self.portal.absolute_url_path()\n storage.add(\n- f\'{portal_path:s}/foo\',\n- f\'{portal_path:s}/test-folder\',\n+ f"{portal_path:s}/foo",\n+ f"{portal_path:s}/test-folder",\n )\n self.assertEqual(\n- ap(\'/foo\', is_source=True),\n- (\'/plone/foo\', \'The provided alternative url already exists!\'),\n+ ap("/foo", is_source=True),\n+ ("/plone/foo", "The provided alternative url already exists!"),\n )\n \n # For targets, we now accept external urls.\n # Note that this can only be done on the control panel,\n # so by default only by Site Administrators or Managers.\n self.assertEqual(\n- ap(\'https://example.org\', is_source=False),\n- (\'https://example.org\', None),\n+ ap("https://example.org", is_source=False),\n+ ("https://example.org", None),\n )\n self.assertEqual(\n- ap(\'http://example.org\', is_source=False),\n- (\'http://example.org\', None),\n+ ap("http://example.org", is_source=False),\n+ ("http://example.org", None),\n )\n self.assertEqual(\n ap(\n- \'https://example.org/some/path?foo=bar&bar=foo\',\n+ "https://example.org/some/path?foo=bar&bar=foo",\n is_source=False,\n ),\n- (\'https://example.org/some/path?foo=bar&bar=foo\', None),\n+ ("https://example.org/some/path?foo=bar&bar=foo", None),\n )\n self.assertEqual(\n- ap(\'http://\', is_source=False),\n- (\'http://\', \'Target path must start with a slash.\'),\n+ ap("http://", is_source=False),\n+ ("http://", "Target path must start with a slash."),\n )\n # Using \'//\' to ignore http/https differences seems useless,\n # as we don\'t include content but only link to it.\n self.assertEqual(\n- ap(\'//example.org\', is_source=False),\n+ ap("//example.org", is_source=False),\n (\n- \'/plone//example.org\',\n- \'The provided target object does not exist.\',\n+ "/plone//example.org",\n+ "The provided target object does not exist.",\n ),\n )\n \n@@ -632,30 +618,24 @@ def test_upload_two_columns(self):\n self.browser.open("%s/@@redirection-controlpanel" % self.portal_url)\n # Note: the targets must exist as actual content.\n data = [\n- (b\'/old-home-page.asp\', b\'/test-folder\'),\n- (b\'/people/JoeT\', b\'/Members\'),\n+ (b"/old-home-page.asp", b"/test-folder"),\n+ (b"/people/JoeT", b"/Members"),\n ]\n- csv = b\'\\n\'.join([b\',\'.join(d) for d in data])\n- self.browser.getControl(name=\'file\').add_file(\n- io.BytesIO(csv), \'text/plain\', \'redirects.csv\'\n- )\n- self.browser.getControl(name=\'form.button.Upload\').click()\n- self.assertNotIn(\n- \'Please pick a file to upload.\', self.browser.contents\n- )\n- self.assertNotIn(\n- \'No alternative urls were added.\', self.browser.contents\n- )\n- self.assertNotIn(\'Please correct these errors\', self.browser.contents)\n+ csv = b"\\n".join([b",".join(d) for d in data])\n+ self.browser.getControl(name="file").add_file(\n+ io.BytesIO(csv), "text/plain", "redirects.csv"\n+ )\n+ self.browser.getControl(name="form.button.Upload").click()\n+ self.assertNotIn("Please pick a file to upload.", self.browser.contents)\n+ self.assertNotIn("No alternative urls were added.", self.browser.contents)\n+ self.assertNotIn("Please correct these errors", self.browser.contents)\n storage = getUtility(IRedirectionStorage)\n self.assertEqual(len(storage), 2)\n- self.assertEqual(\n- storage.get(\'/plone/old-home-page.asp\'), \'/plone/test-folder\'\n- )\n- self.assertEqual(storage.get(\'/plone/people/JoeT\'), \'/plone/Members\')\n+ self.assertEqual(storage.get("/plone/old-home-page.asp"), "/plone/test-folder")\n+ self.assertEqual(storage.get("/plone/people/JoeT"), "/plone/Members")\n # Test the internals.\n- redirect = storage._paths[\'/plone/old-home-page.asp\']\n- self.assertEqual(redirect[0], \'/plone/test-folder\')\n+ redirect = storage._paths["/plone/old-home-page.asp"]\n+ self.assertEqual(redirect[0], "/plone/test-folder")\n self.assertIsInstance(redirect[1], DateTime)\n self.assertEqual(redirect[2], True) # manual\n \n@@ -671,96 +651,92 @@ def test_upload_four_columns(self):\n # We can first have a header, which should be ignored.\n # Second one should have the same number of columns,\n # otherwise the delimiter detection can get it wrong.\n- (b\'old path\', b\'new path\', b\'datetime\', b\'manual\'),\n+ (b"old path", b"new path", b"datetime", b"manual"),\n # bad dates are silently ignored\n- (b\'/baddate\', b\'/test-folder\', b\'2006-13-62\', b\'yes\'),\n+ (b"/baddate", b"/test-folder", b"2006-13-62", b"yes"),\n # two columns:\n- (b\'/two\', b\'/test-folder\'),\n+ (b"/two", b"/test-folder"),\n # third column with date:\n- (b\'/three\', b\'/test-folder\', b\'2003-01-31\'),\n+ (b"/three", b"/test-folder", b"2003-01-31"),\n # fourth column with manual:\n (\n- b\'/four\',\n- b\'/test-folder\',\n- b\'2004/01/27 10:00:00 GMT-3\',\n- b\'False\',\n+ b"/four",\n+ b"/test-folder",\n+ b"2004/01/27 10:00:00 GMT-3",\n+ b"False",\n ),\n # fifth column is ignored:\n- (b\'/five\', b\'/test-folder\', b\'2005-01-31\', b\'True\', b\'ignored\'),\n+ (b"/five", b"/test-folder", b"2005-01-31", b"True", b"ignored"),\n # manual can be \'0\' (or anything starting with f/F/n/N/0)\n- (b\'/zero\', b\'/test-folder\', b\'2000-01-31\', b\'0\'),\n+ (b"/zero", b"/test-folder", b"2000-01-31", b"0"),\n ]\n- csv = b\'\\n\'.join([b\',\'.join(d) for d in data])\n- self.browser.getControl(name=\'file\').add_file(\n- io.BytesIO(csv), \'text/plain\', \'redirects.csv\'\n- )\n- self.browser.getControl(name=\'form.button.Upload\').click()\n- self.assertNotIn(\n- \'Please pick a file to upload.\', self.browser.contents\n+ csv = b"\\n".join([b",".join(d) for d in data])\n+ self.browser.getControl(name="file").add_file(\n+ io.BytesIO(csv), "text/plain", "redirects.csv"\n )\n- self.assertNotIn(\n- \'No alternative urls were added.\', self.browser.contents\n- )\n- self.assertNotIn(\'Please correct these errors\', self.browser.contents)\n+ self.browser.getControl(name="form.button.Upload").click()\n+ self.assertNotIn("Please pick a file to upload.", self.browser.contents)\n+ self.assertNotIn("No alternative urls were added.", self.browser.contents)\n+ self.assertNotIn("Please correct these errors", self.browser.contents)\n \n # All five lines have been added.\n storage = getUtility(IRedirectionStorage)\n self.assertEqual(len(storage), 6)\n- self.assertEqual(storage.get(\'/plone/two\'), \'/plone/test-folder\')\n+ self.assertEqual(storage.get("/plone/two"), "/plone/test-folder")\n old_paths = [\n- \'/plone/baddate\',\n- \'/plone/five\',\n- \'/plone/four\',\n- \'/plone/three\',\n- \'/plone/two\',\n- \'/plone/zero\',\n+ "/plone/baddate",\n+ "/plone/five",\n+ "/plone/four",\n+ "/plone/three",\n+ "/plone/two",\n+ "/plone/zero",\n ]\n self.assertListEqual(sorted(list(storage)), old_paths)\n self.assertListEqual(\n- sorted(list(storage.redirects(\'/plone/test-folder\'))), old_paths\n+ sorted(list(storage.redirects("/plone/test-folder"))), old_paths\n )\n # Test the internals.\n \n # two columns:\n # (b\'/two\', b\'/test-folder\'),\n- redirect = storage._paths[\'/plone/two\']\n- self.assertEqual(redirect[0], \'/plone/test-folder\')\n+ redirect = storage._paths["/plone/two"]\n+ self.assertEqual(redirect[0], "/plone/test-folder")\n self.assertIsInstance(redirect[1], DateTime)\n self.assertGreater(redirect[1], now)\n self.assertEqual(redirect[2], True) # manual\n \n # third column with date:\n # (b\'/three\', b\'/test-folder\', b\'2003-01-31\'),\n- redirect = storage._paths[\'/plone/three\']\n- self.assertEqual(redirect[0], \'/plone/test-folder\')\n- self.assertEqual(redirect[1], DateTime(\'2003-01-31\'))\n+ redirect = storage._paths["/plone/three"]\n+ self.assertEqual(redirect[0], "/plone/test-folder")\n+ self.assertEqual(redirect[1], DateTime("2003-01-31"))\n self.assertEqual(redirect[2], True)\n \n # fourth column with manual:\n # (b\'/four\', b\'/test-folder\', b\'2004/01/27 10:00:00 GMT-3\', b\'False\'),\n- redirect = storage._paths[\'/plone/four\']\n- self.assertEqual(redirect[0], \'/plone/test-folder\')\n- self.assertEqual(redirect[1], DateTime(\'2004/01/27 10:00:00 GMT-3\'))\n+ redirect = storage._paths["/plone/four"]\n+ self.assertEqual(redirect[0], "/plone/test-folder")\n+ self.assertEqual(redirect[1], DateTime("2004/01/27 10:00:00 GMT-3"))\n self.assertEqual(redirect[2], False)\n \n # fifth column is ignored:\n # (b\'/five\', b\'/test-folder\', b\'2005-01-31\', b\'True\', b\'ignored\'),\n- redirect = storage._paths[\'/plone/five\']\n- self.assertEqual(redirect[0], \'/plone/test-folder\')\n- self.assertEqual(redirect[1], DateTime(\'2005-01-31\'))\n+ redirect = storage._paths["/plone/five"]\n+ self.assertEqual(redirect[0], "/plone/test-folder")\n+ self.assertEqual(redirect[1], DateTime("2005-01-31"))\n self.assertEqual(redirect[2], True)\n \n # manual can be \'0\' (or anything starting with f/F/n/N/0)\n # (b\'/zero\', b\'/test-folder\', b\'2000-01-31\', b\'0\'),\n- redirect = storage._paths[\'/plone/zero\']\n- self.assertEqual(redirect[0], \'/plone/test-folder\')\n- self.assertEqual(redirect[1], DateTime(\'2000-01-31\'))\n+ redirect = storage._paths["/plone/zero"]\n+ self.assertEqual(redirect[0], "/plone/test-folder")\n+ self.assertEqual(redirect[1], DateTime("2000-01-31"))\n self.assertEqual(redirect[2], False)\n \n # bad dates are silently ignored\n # (b\'/baddate\', b\'/test-folder\', b\'2006-13-62\', b\'yes\'),\n- redirect = storage._paths[\'/plone/baddate\']\n- self.assertEqual(redirect[0], \'/plone/test-folder\')\n+ redirect = storage._paths["/plone/baddate"]\n+ self.assertEqual(redirect[0], "/plone/test-folder")\n self.assertGreater(redirect[1], now)\n self.assertEqual(redirect[2], True)\n \n@@ -769,65 +745,61 @@ def test_upload_bad(self):\n # The targets must exist as actual content.\n # We try a good one and one that does not exist.\n data = [\n- (b\'/old-home-page.asp\', b\'/test-folder\'),\n- (b\'/people/JoeT\', b\'/no-such-content\'),\n+ (b"/old-home-page.asp", b"/test-folder"),\n+ (b"/people/JoeT", b"/no-such-content"),\n ]\n- csv = b\'\\n\'.join([b\',\'.join(d) for d in data])\n- self.browser.getControl(name=\'file\').add_file(\n- io.BytesIO(csv), \'text/plain\', \'redirects.csv\'\n- )\n- self.browser.getControl(name=\'form.button.Upload\').click()\n- self.assertNotIn(\n- \'Please pick a file to upload.\', self.browser.contents\n- )\n- self.assertIn(\'No alternative urls were added.\', self.browser.contents)\n- self.assertIn(\'Please correct these errors\', self.browser.contents)\n+ csv = b"\\n".join([b",".join(d) for d in data])\n+ self.browser.getControl(name="file").add_file(\n+ io.BytesIO(csv), "text/plain", "redirects.csv"\n+ )\n+ self.browser.getControl(name="form.button.Upload").click()\n+ self.assertNotIn("Please pick a file to upload.", self.browser.contents)\n+ self.assertIn("No alternative urls were added.", self.browser.contents)\n+ self.assertIn("Please correct these errors", self.browser.contents)\n storage = getUtility(IRedirectionStorage)\n self.assertEqual(len(storage), 0)\n \n def test_download_empty(self):\n self.browser.open("%s/@@redirection-controlpanel" % self.portal_url)\n- self.browser.getControl(name=\'form.button.Download\').click()\n+ self.browser.getControl(name="form.button.Download").click()\n self.assertEqual(\n- self.browser.headers[\'Content-Disposition\'],\n- \'attachment; filename=redirects.csv\',\n+ self.browser.headers["Content-Disposition"],\n+ "attachment; filename=redirects.csv",\n )\n contents = self.browser.contents.splitlines()\n self.assertEqual(len(contents), 1)\n- self.assertEqual(contents[0], \'old path,new path,datetime,manual\')\n+ self.assertEqual(contents[0], "old path,new path,datetime,manual")\n \n def test_download_bigger(self):\n storage = getUtility(IRedirectionStorage)\n- portal_path = self.layer[\'portal\'].absolute_url_path()\n- now = DateTime(\'2019/01/27 10:00:00 GMT-3\')\n+ portal_path = self.layer["portal"].absolute_url_path()\n+ now = DateTime("2019/01/27 10:00:00 GMT-3")\n for i in range(2000):\n storage.add(\n- f\'{portal_path:s}/foo/{str(i):s}\',\n- f\'{portal_path:s}/bar/{str(i):s}\',\n+ f"{portal_path:s}/foo/{str(i):s}",\n+ f"{portal_path:s}/bar/{str(i):s}",\n now=now,\n manual=True,\n )\n transaction.commit()\n self.browser.open("%s/@@redirection-controlpanel" % self.portal_url)\n- self.browser.getControl(name=\'form.button.Download\').click()\n+ self.browser.getControl(name="form.button.Download").click()\n self.assertEqual(\n- self.browser.headers[\'Content-Disposition\'],\n- \'attachment; filename=redirects.csv\',\n+ self.browser.headers["Content-Disposition"],\n+ "attachment; filename=redirects.csv",\n )\n contents = self.browser.contents.splitlines()\n # pop the header\n- self.assertEqual(contents.pop(0), \'old path,new path,datetime,manual\')\n+ self.assertEqual(contents.pop(0), "old path,new path,datetime,manual")\n self.assertEqual(len(contents), 2000)\n # The order is probably the alphabetical order of the old path,\n # but that is not important and may change,\n # so let\'s sort it in the tests for good measure.\n # Note that \'999\' sorts alphabetically after \'1999\'.\n contents.sort()\n+ self.assertEqual(contents[0], "/foo/0,/bar/0,2019/01/27 10:00:00 GMT-3,True")\n self.assertEqual(\n- contents[0], \'/foo/0,/bar/0,2019/01/27 10:00:00 GMT-3,True\'\n- )\n- self.assertEqual(\n- contents[1999], \'/foo/999,/bar/999,2019/01/27 10:00:00 GMT-3,True\'\n+ contents[1999], "/foo/999,/bar/999,2019/01/27 10:00:00 GMT-3,True"\n )\n \n def test_download_upload(self):\n@@ -835,12 +807,12 @@ def test_download_upload(self):\n \n # 1. Manually add some redirects.\n storage = getUtility(IRedirectionStorage)\n- portal_path = self.layer[\'portal\'].absolute_url_path()\n- now = DateTime(\'2019/01/27 10:00:00 GMT-3\')\n+ portal_path = self.layer["portal"].absolute_url_path()\n+ now = DateTime("2019/01/27 10:00:00 GMT-3")\n for i in range(10):\n storage.add(\n- f\'{portal_path:s}/foo/{str(i):s}\',\n- f\'{portal_path:s}/test-folder\',\n+ f"{portal_path:s}/foo/{str(i):s}",\n+ f"{portal_path:s}/test-folder",\n now=now,\n manual=True,\n )\n@@ -848,58 +820,54 @@ def test_download_upload(self):\n \n # 2. Download the redirects.\n self.browser.open("%s/@@redirection-controlpanel" % self.portal_url)\n- self.browser.getControl(name=\'form.button.Download\').click()\n+ self.browser.getControl(name="form.button.Download").click()\n self.assertEqual(\n- self.browser.headers[\'Content-Disposition\'],\n- \'attachment; filename=redirects.csv\',\n+ self.browser.headers["Content-Disposition"],\n+ "attachment; filename=redirects.csv",\n )\n downloaded_contents = self.browser.contents\n contents = downloaded_contents.splitlines()\n- self.assertEqual(contents.pop(0), \'old path,new path,datetime,manual\')\n+ self.assertEqual(contents.pop(0), "old path,new path,datetime,manual")\n self.assertEqual(len(contents), 10)\n contents.sort()\n self.assertEqual(\n- contents[0], \'/foo/0,/test-folder,2019/01/27 10:00:00 GMT-3,True\'\n+ contents[0], "/foo/0,/test-folder,2019/01/27 10:00:00 GMT-3,True"\n )\n \n # 3. clear the redirect storage\n storage.clear()\n transaction.commit()\n self.browser.open("%s/@@redirection-controlpanel" % self.portal_url)\n- self.browser.getControl(name=\'form.button.Download\').click()\n+ self.browser.getControl(name="form.button.Download").click()\n contents = self.browser.contents.splitlines()\n self.assertEqual(len(contents), 1)\n- self.assertEqual(contents[0], \'old path,new path,datetime,manual\')\n+ self.assertEqual(contents[0], "old path,new path,datetime,manual")\n \n # 4. upload the original download\n self.browser.open("%s/@@redirection-controlpanel" % self.portal_url)\n- self.browser.getControl(name=\'file\').add_file(\n+ self.browser.getControl(name="file").add_file(\n io.BytesIO(safe_bytes(downloaded_contents)),\n- \'text/plain\',\n- \'redirects.csv\',\n- )\n- self.browser.getControl(name=\'form.button.Upload\').click()\n- self.assertNotIn(\n- \'Please pick a file to upload.\', self.browser.contents\n- )\n- self.assertNotIn(\n- \'The provided target object does not exist.\', self.browser.contents\n+ "text/plain",\n+ "redirects.csv",\n )\n+ self.browser.getControl(name="form.button.Upload").click()\n+ self.assertNotIn("Please pick a file to upload.", self.browser.contents)\n self.assertNotIn(\n- \'No alternative urls were added.\', self.browser.contents\n+ "The provided target object does not exist.", self.browser.contents\n )\n- self.assertNotIn(\'Please correct these errors\', self.browser.contents)\n+ self.assertNotIn("No alternative urls were added.", self.browser.contents)\n+ self.assertNotIn("Please correct these errors", self.browser.contents)\n self.assertEqual(len(storage), 10)\n \n # 5. download the upload\n- self.browser.getControl(name=\'form.button.Download\').click()\n+ self.browser.getControl(name="form.button.Download").click()\n new_downloaded_contents = self.browser.contents\n contents = downloaded_contents.splitlines()\n- self.assertEqual(contents.pop(0), \'old path,new path,datetime,manual\')\n+ self.assertEqual(contents.pop(0), "old path,new path,datetime,manual")\n self.assertEqual(len(contents), 10)\n contents.sort()\n self.assertEqual(\n- contents[0], \'/foo/0,/test-folder,2019/01/27 10:00:00 GMT-3,True\'\n+ contents[0], "/foo/0,/test-folder,2019/01/27 10:00:00 GMT-3,True"\n )\n # and it is actually the same as the original download\n self.assertEqual(new_downloaded_contents, downloaded_contents)\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_search.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_search.py\nindex ebcf1f3b02..f2cc9bf507 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_search.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_search.py\n@@ -18,58 +18,52 @@ class SearchControlPanelFunctionalTest(unittest.TestCase):\n layer = PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING\n \n def setUp(self):\n- self.app = self.layer[\'app\']\n- self.portal = self.layer[\'portal\']\n+ self.app = self.layer["app"]\n+ self.portal = self.layer["portal"]\n self.portal_url = self.portal.absolute_url()\n self.browser = Browser(self.app)\n self.browser.handleErrors = False\n self.browser.addHeader(\n- \'Authorization\',\n- f\'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}\'\n+ "Authorization", f"Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}"\n )\n \n def test_search_control_panel_link(self):\n- self.browser.open(\n- "%s/@@overview-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Search\').click()\n+ self.browser.open("%s/@@overview-controlpanel" % self.portal_url)\n+ self.browser.getLink("Search").click()\n \n def test_search_control_panel_backlink(self):\n- self.browser.open(\n- "%s/@@search-controlpanel" % self.portal_url)\n+ self.browser.open("%s/@@search-controlpanel" % self.portal_url)\n self.assertTrue("General" in self.browser.contents)\n \n def test_search_control_panel_sidebar(self):\n- self.browser.open(\n- "%s/@@search-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Site Setup\').click()\n- self.assertTrue(\n- self.browser.url.endswith(\'/plone/@@overview-controlpanel\')\n- )\n+ self.browser.open("%s/@@search-controlpanel" % self.portal_url)\n+ self.browser.getLink("Site Setup").click()\n+ self.assertTrue(self.browser.url.endswith("/plone/@@overview-controlpanel"))\n \n def test_search_controlpanel_view(self):\n- view = getMultiAdapter((self.portal, self.portal.REQUEST),\n- name="search-controlpanel")\n+ view = getMultiAdapter(\n+ (self.portal, self.portal.REQUEST), name="search-controlpanel"\n+ )\n self.assertTrue(view())\n \n def test_enable_livesearch(self):\n- self.browser.open(\n- "%s/@@search-controlpanel" % self.portal_url)\n- self.browser.getControl(\'Enable LiveSearch\').selected = True\n- self.browser.getControl(\'Save\').click()\n+ self.browser.open("%s/@@search-controlpanel" % self.portal_url)\n+ self.browser.getControl("Enable LiveSearch").selected = True\n+ self.browser.getControl("Save").click()\n \n registry = getUtility(IRegistry)\n settings = registry.forInterface(ISearchSchema, prefix="plone")\n self.assertEqual(settings.enable_livesearch, True)\n \n def test_types_not_searched(self):\n- self.browser.open(\n- "%s/@@search-controlpanel" % self.portal_url)\n- self.browser.getControl(\n- name=\'form.widgets.types_not_searched:list\'\n- ).value = [\'Discussion Item\', \'News Item\']\n- self.browser.getControl(\'Save\').click()\n+ self.browser.open("%s/@@search-controlpanel" % self.portal_url)\n+ self.browser.getControl(name="form.widgets.types_not_searched:list").value = [\n+ "Discussion Item",\n+ "News Item",\n+ ]\n+ self.browser.getControl("Save").click()\n \n registry = getUtility(IRegistry)\n settings = registry.forInterface(ISearchSchema, prefix="plone")\n- self.assertTrue(\'Discussion Item\' in settings.types_not_searched)\n- self.assertTrue(\'News Item\' in settings.types_not_searched)\n+ self.assertTrue("Discussion Item" in settings.types_not_searched)\n+ self.assertTrue("News Item" in settings.types_not_searched)\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_security.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_security.py\nindex fb1f64ecf9..fef6b62e37 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_security.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_security.py\n@@ -17,86 +17,70 @@ class SecurityControlPanelFunctionalTest(unittest.TestCase):\n layer = PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING\n \n def setUp(self):\n- self.app = self.layer[\'app\']\n- self.portal = self.layer[\'portal\']\n+ self.app = self.layer["app"]\n+ self.portal = self.layer["portal"]\n self.portal_url = self.portal.absolute_url()\n registry = getUtility(IRegistry)\n- self.settings = registry.forInterface(\n- ISecuritySchema, prefix="plone")\n+ self.settings = registry.forInterface(ISecuritySchema, prefix="plone")\n self.browser = Browser(self.app)\n self.browser.handleErrors = False\n self.browser.addHeader(\n- \'Authorization\',\n- f\'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}\'\n+ "Authorization", f"Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}"\n )\n \n def test_security_control_panel_link(self):\n- self.browser.open(\n- "%s/@@overview-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Security\').click()\n+ self.browser.open("%s/@@overview-controlpanel" % self.portal_url)\n+ self.browser.getLink("Security").click()\n \n def test_security_control_panel_backlink(self):\n- self.browser.open(\n- "%s/@@security-controlpanel" % self.portal_url)\n+ self.browser.open("%s/@@security-controlpanel" % self.portal_url)\n self.assertTrue("Security" in self.browser.contents)\n \n def test_security_control_panel_sidebar(self):\n- self.browser.open(\n- "%s/@@security-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Site Setup\').click()\n- self.assertTrue(\n- self.browser.url.endswith(\'/plone/@@overview-controlpanel\')\n- )\n+ self.browser.open("%s/@@security-controlpanel" % self.portal_url)\n+ self.browser.getLink("Site Setup").click()\n+ self.assertTrue(self.browser.url.endswith("/plone/@@overview-controlpanel"))\n \n def test_enable_self_reg(self):\n- self.browser.open(\n- "%s/@@security-controlpanel" % self.portal_url)\n- self.browser.getControl(\'Enable self-registration\').selected = True\n- self.browser.getControl(\'Save\').click()\n+ self.browser.open("%s/@@security-controlpanel" % self.portal_url)\n+ self.browser.getControl("Enable self-registration").selected = True\n+ self.browser.getControl("Save").click()\n \n self.assertEqual(self.settings.enable_self_reg, True)\n \n def test_enable_user_pwd_choice(self):\n- self.browser.open(\n- "%s/@@security-controlpanel" % self.portal_url)\n- self.browser.getControl(\n- \'Let users select their own passwords\').selected = True\n- self.browser.getControl(\'Save\').click()\n+ self.browser.open("%s/@@security-controlpanel" % self.portal_url)\n+ self.browser.getControl("Let users select their own passwords").selected = True\n+ self.browser.getControl("Save").click()\n \n self.assertEqual(self.settings.enable_user_pwd_choice, True)\n \n def test_enable_user_folders(self):\n- self.browser.open(\n- "%s/@@security-controlpanel" % self.portal_url)\n- self.browser.getControl(\n- \'Enable User Folders\').selected = True\n- self.browser.getControl(\'Save\').click()\n+ self.browser.open("%s/@@security-controlpanel" % self.portal_url)\n+ self.browser.getControl("Enable User Folders").selected = True\n+ self.browser.getControl("Save").click()\n \n self.assertEqual(self.settings.enable_user_folders, True)\n \n def test_allow_anon_views_about(self):\n- self.browser.open(\n- "%s/@@security-controlpanel" % self.portal_url)\n+ self.browser.open("%s/@@security-controlpanel" % self.portal_url)\n self.browser.getControl(\n- "Allow anyone to view \'about\' information").selected = True\n- self.browser.getControl(\'Save\').click()\n+ "Allow anyone to view \'about\' information"\n+ ).selected = True\n+ self.browser.getControl("Save").click()\n \n self.assertEqual(self.settings.allow_anon_views_about, True)\n \n def test_use_email_as_login(self):\n- self.browser.open(\n- "%s/@@security-controlpanel" % self.portal_url)\n- self.browser.getControl(\n- "Use email address as login name").selected = True\n- self.browser.getControl(\'Save\').click()\n+ self.browser.open("%s/@@security-controlpanel" % self.portal_url)\n+ self.browser.getControl("Use email address as login name").selected = True\n+ self.browser.getControl("Save").click()\n \n self.assertEqual(self.settings.use_email_as_login, True)\n \n def test_use_uuid_as_userid(self):\n- self.browser.open(\n- "%s/@@security-controlpanel" % self.portal_url)\n- self.browser.getControl(\n- "Use UUID user ids").selected = True\n- self.browser.getControl(\'Save\').click()\n+ self.browser.open("%s/@@security-controlpanel" % self.portal_url)\n+ self.browser.getControl("Use UUID user ids").selected = True\n+ self.browser.getControl("Save").click()\n \n self.assertEqual(self.settings.use_uuid_as_userid, True)\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_site.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_site.py\nindex 3bf8436942..9d581b7d0a 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_site.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_site.py\n@@ -12,14 +12,18 @@\n \n \n # Red pixel with filename pixel.png\n-SITE_LOGO_BASE64 = b\'filenameb64:cGl4ZWwucG5n;datab64:iVBORw0KGgoAAAANSUhEUgA\'\\\n- b\'AAAEAAAABCAIAAACQd1PeAAAADElEQVQI12P4z8AAAAMBAQAY3Y2wAAA\'\\\n- b\'AAElFTkSuQmCC\'\n+SITE_LOGO_BASE64 = (\n+ b"filenameb64:cGl4ZWwucG5n;datab64:iVBORw0KGgoAAAANSUhEUgA"\n+ b"AAAEAAAABCAIAAACQd1PeAAAADElEQVQI12P4z8AAAAMBAQAY3Y2wAAA"\n+ b"AAElFTkSuQmCC"\n+)\n \n-SITE_LOGO_HEX = b\'\\x89PNG\\r\\n\\x1a\\n\\x00\\x00\\x00\\rIHDR\\x00\\x00\\x00\\x01\\x00\\x00\'\\\n- b\'\\x00\\x01\\x08\\x02\\x00\\x00\\x00\\x90wS\\xde\\x00\\x00\\x00\\x0cIDAT\'\\\n- b\'\\x08\\xd7c\\xf8\\xcf\\xc0\\x00\\x00\\x03\\x01\\x01\\x00\\x18\\xdd\\x8d\'\\\n- b\'\\xb0\\x00\\x00\\x00\\x00IEND\\xaeB`\\x82\'\n+SITE_LOGO_HEX = (\n+ b"\\x89PNG\\r\\n\\x1a\\n\\x00\\x00\\x00\\rIHDR\\x00\\x00\\x00\\x01\\x00\\x00"\n+ b"\\x00\\x01\\x08\\x02\\x00\\x00\\x00\\x90wS\\xde\\x00\\x00\\x00\\x0cIDAT"\n+ b"\\x08\\xd7c\\xf8\\xcf\\xc0\\x00\\x00\\x03\\x01\\x01\\x00\\x18\\xdd\\x8d"\n+ b"\\xb0\\x00\\x00\\x00\\x00IEND\\xaeB`\\x82"\n+)\n \n \n class SiteControlPanelFunctionalTest(unittest.TestCase):\n@@ -30,153 +34,135 @@ class SiteControlPanelFunctionalTest(unittest.TestCase):\n layer = PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING\n \n def setUp(self):\n- self.app = self.layer[\'app\']\n- self.portal = self.layer[\'portal\']\n- self.request = self.layer[\'request\']\n+ self.app = self.layer["app"]\n+ self.portal = self.layer["portal"]\n+ self.request = self.layer["request"]\n self.portal_url = self.portal.absolute_url()\n self.browser = Browser(self.app)\n self.browser.handleErrors = False\n self.browser.addHeader(\n- \'Authorization\',\n- f\'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}\'\n+ "Authorization", f"Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}"\n )\n \n def test_site_control_panel_link(self):\n- self.browser.open(\n- "%s/@@overview-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Site\').click()\n+ self.browser.open("%s/@@overview-controlpanel" % self.portal_url)\n+ self.browser.getLink("Site").click()\n \n def test_site_control_panel_backlink(self):\n- self.browser.open(\n- "%s/@@site-controlpanel" % self.portal_url)\n+ self.browser.open("%s/@@site-controlpanel" % self.portal_url)\n self.assertTrue("General" in self.browser.contents)\n \n def test_site_control_panel_sidebar(self):\n- self.browser.open(\n- "%s/@@site-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Site Setup\').click()\n- self.assertTrue(\n- self.browser.url.endswith(\'/plone/@@overview-controlpanel\')\n- )\n+ self.browser.open("%s/@@site-controlpanel" % self.portal_url)\n+ self.browser.getLink("Site Setup").click()\n+ self.assertTrue(self.browser.url.endswith("/plone/@@overview-controlpanel"))\n \n def test_site_controlpanel_view(self):\n- view = getMultiAdapter((self.portal, self.portal.REQUEST),\n- name="site-controlpanel")\n+ view = getMultiAdapter(\n+ (self.portal, self.portal.REQUEST), name="site-controlpanel"\n+ )\n self.assertTrue(view())\n \n def test_site_title_is_stored_in_registry(self):\n- self.browser.open(\n- "%s/@@site-controlpanel" % self.portal_url)\n- self.browser.getControl(\'Site title\').value = "My Site"\n- self.browser.getControl(\'Save\').click()\n+ self.browser.open("%s/@@site-controlpanel" % self.portal_url)\n+ self.browser.getControl("Site title").value = "My Site"\n+ self.browser.getControl("Save").click()\n \n registry = getUtility(IRegistry)\n settings = registry.forInterface(ISiteSchema, prefix="plone")\n self.assertEqual(settings.site_title, "My Site")\n \n def test_site_title_can_be_looked_up_by_plone_portal_state(self):\n- self.browser.open(\n- "%s/@@site-controlpanel" % self.portal_url)\n- self.browser.getControl(\'Site title\').value = "My Site"\n- self.browser.getControl(\'Save\').click()\n+ self.browser.open("%s/@@site-controlpanel" % self.portal_url)\n+ self.browser.getControl("Site title").value = "My Site"\n+ self.browser.getControl("Save").click()\n \n portal_state = getMultiAdapter(\n- (self.portal, self.request),\n- name=\'plone_portal_state\'\n+ (self.portal, self.request), name="plone_portal_state"\n )\n- self.assertEqual(portal_state.portal_title(), \'My Site\')\n+ self.assertEqual(portal_state.portal_title(), "My Site")\n \n @unittest.skip("XXX: TODO! We have to patch CMFDefault for this.")\n def test_site_title_can_be_looked_up_by_portal_title(self):\n- self.browser.open(\n- "%s/@@site-controlpanel" % self.portal_url)\n- self.browser.getControl(\'Site title\').value = "My Site"\n- self.browser.getControl(\'Save\').click()\n+ self.browser.open("%s/@@site-controlpanel" % self.portal_url)\n+ self.browser.getControl("Site title").value = "My Site"\n+ self.browser.getControl("Save").click()\n \n- self.assertEqual(self.portal.title, \'My Site\')\n- self.assertEqual(self.portal.Title(), \'My Site\')\n+ self.assertEqual(self.portal.title, "My Site")\n+ self.assertEqual(self.portal.Title(), "My Site")\n \n def test_site_logo_is_stored_in_registry(self):\n- self.browser.open(\n- "%s/@@site-controlpanel" % self.portal_url)\n+ self.browser.open("%s/@@site-controlpanel" % self.portal_url)\n ctrl = self.browser.getControl(name="form.widgets.site_logo")\n- ctrl.add_file(BytesIO(SITE_LOGO_HEX), \'image/png\', \'pixel.png\')\n- self.browser.getControl(\'Save\').click()\n+ ctrl.add_file(BytesIO(SITE_LOGO_HEX), "image/png", "pixel.png")\n+ self.browser.getControl("Save").click()\n \n registry = getUtility(IRegistry)\n- settings = registry.forInterface(ISiteSchema, prefix=\'plone\')\n+ settings = registry.forInterface(ISiteSchema, prefix="plone")\n self.assertEqual(settings.site_logo, SITE_LOGO_BASE64)\n \n def test_exposeDCMetaTags(self):\n- self.browser.open(\n- "%s/@@site-controlpanel" % self.portal_url)\n- self.browser.getControl(\'Site title\').value = "Plone Site"\n- self.browser.getControl(\'Expose Dublin Core metadata\').selected = True\n- self.browser.getControl(\'Save\').click()\n+ self.browser.open("%s/@@site-controlpanel" % self.portal_url)\n+ self.browser.getControl("Site title").value = "Plone Site"\n+ self.browser.getControl("Expose Dublin Core metadata").selected = True\n+ self.browser.getControl("Save").click()\n \n registry = getUtility(IRegistry)\n settings = registry.forInterface(ISiteSchema, prefix="plone")\n self.assertEqual(settings.exposeDCMetaTags, True)\n \n def test_exposeDCMetaTags_exposes_meta_tags(self):\n- self.browser.open(\n- "%s/@@site-controlpanel" % self.portal_url)\n- self.browser.getControl(\'Site title\').value = "Plone Site"\n- self.browser.getControl(\'Expose Dublin Core metadata\').selected = True\n- self.browser.getControl(\'Save\').click()\n+ self.browser.open("%s/@@site-controlpanel" % self.portal_url)\n+ self.browser.getControl("Site title").value = "Plone Site"\n+ self.browser.getControl("Expose Dublin Core metadata").selected = True\n+ self.browser.getControl("Save").click()\n \n self.browser.open(self.portal_url)\n \n- self.assertTrue(\'DC.type\' in self.browser.contents)\n+ self.assertTrue("DC.type" in self.browser.contents)\n \n def test_enable_sitemap(self):\n- self.browser.open(\n- "%s/@@site-controlpanel" % self.portal_url)\n- self.browser.getControl(\'Site title\').value = "Plone Site"\n- self.browser.getControl(\'Expose sitemap.xml.gz\').selected = True\n- self.browser.getControl(\'Save\').click()\n+ self.browser.open("%s/@@site-controlpanel" % self.portal_url)\n+ self.browser.getControl("Site title").value = "Plone Site"\n+ self.browser.getControl("Expose sitemap.xml.gz").selected = True\n+ self.browser.getControl("Save").click()\n \n registry = getUtility(IRegistry)\n settings = registry.forInterface(ISiteSchema, prefix="plone")\n self.assertEqual(settings.enable_sitemap, True)\n \n def test_enable_sitemap_enables_the_sitemap(self):\n- self.browser.open(\n- "%s/@@site-controlpanel" % self.portal_url)\n- self.browser.getControl(\'Site title\').value = "Plone Site"\n- self.browser.getControl(\'Expose sitemap.xml.gz\').selected = True\n- self.browser.getControl(\'Save\').click()\n+ self.browser.open("%s/@@site-controlpanel" % self.portal_url)\n+ self.browser.getControl("Site title").value = "Plone Site"\n+ self.browser.getControl("Expose sitemap.xml.gz").selected = True\n+ self.browser.getControl("Save").click()\n \n self.browser.open("%s/sitemap.xml.gz" % self.portal_url)\n \n+ self.assertEqual(self.browser.headers["status"].lower(), "200 ok")\n self.assertEqual(\n- self.browser.headers[\'status\'].lower(),\n- \'200 ok\'\n- )\n- self.assertEqual(\n- self.browser.headers[\'content-type\'],\n- \'application/octet-stream\'\n+ self.browser.headers["content-type"], "application/octet-stream"\n )\n \n def test_webstats_js(self):\n- self.browser.open(\n- "%s/@@site-controlpanel" % self.portal_url)\n- self.browser.getControl(\'Site title\').value = "Plone Site"\n- self.browser.getControl(name=\'form.widgets.webstats_js\').value = \\\n- ""\n- self.browser.getControl(\'Save\').click()\n+ self.browser.open("%s/@@site-controlpanel" % self.portal_url)\n+ self.browser.getControl("Site title").value = "Plone Site"\n+ self.browser.getControl(\n+ name="form.widgets.webstats_js"\n+ ).value = ""\n+ self.browser.getControl("Save").click()\n \n registry = getUtility(IRegistry)\n settings = registry.forInterface(ISiteSchema, prefix="plone")\n self.assertEqual(settings.webstats_js, "")\n \n def test_webstat_js_shows_up_on_site(self):\n- self.browser.open(\n- "%s/@@site-controlpanel" % self.portal_url)\n- self.browser.getControl(\'Site title\').value = "Plone Site"\n- self.browser.getControl(name=\'form.widgets.webstats_js\').value = \\\n- ""\n- self.browser.getControl(\'Save\').click()\n+ self.browser.open("%s/@@site-controlpanel" % self.portal_url)\n+ self.browser.getControl("Site title").value = "Plone Site"\n+ self.browser.getControl(\n+ name="form.widgets.webstats_js"\n+ ).value = ""\n+ self.browser.getControl("Save").click()\n \n registry = getUtility(IRegistry)\n settings = registry.forInterface(ISiteSchema, prefix="plone")\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_syndication.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_syndication.py\nindex 60da102499..98f799eef2 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_syndication.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_syndication.py\n@@ -9,104 +9,90 @@\n \n \n class SyndicationControlPanelFunctionalTest(unittest.TestCase):\n-\n layer = PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING\n \n def setUp(self):\n- self.app = self.layer[\'app\']\n- self.portal = self.layer[\'portal\']\n+ self.app = self.layer["app"]\n+ self.portal = self.layer["portal"]\n self.portal_url = self.portal.absolute_url()\n self.browser = Browser(self.app)\n self.browser.handleErrors = False\n self.browser.addHeader(\n- \'Authorization\',\n- f\'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}\'\n+ "Authorization", f"Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}"\n )\n \n def test_syndication_controlpanel_link(self):\n- self.browser.open(\n- "%s/@@overview-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Syndication\').click()\n+ self.browser.open("%s/@@overview-controlpanel" % self.portal_url)\n+ self.browser.getLink("Syndication").click()\n \n def test_syndication_controlpanel_backlink(self):\n- self.browser.open(\n- "%s/@@syndication-controlpanel" % self.portal_url)\n+ self.browser.open("%s/@@syndication-controlpanel" % self.portal_url)\n self.assertTrue("General" in self.browser.contents)\n \n def test_syndication_controlpanel_sidebar(self):\n- self.browser.open(\n- "%s/@@syndication-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Site Setup\').click()\n- self.assertTrue(\n- self.browser.url.endswith(\'/plone/@@overview-controlpanel\')\n- )\n+ self.browser.open("%s/@@syndication-controlpanel" % self.portal_url)\n+ self.browser.getLink("Site Setup").click()\n+ self.assertTrue(self.browser.url.endswith("/plone/@@overview-controlpanel"))\n \n def test_syndication_controlpanel_view(self):\n- view = getMultiAdapter((self.portal, self.portal.REQUEST),\n- name="syndication-controlpanel")\n+ view = getMultiAdapter(\n+ (self.portal, self.portal.REQUEST), name="syndication-controlpanel"\n+ )\n self.assertTrue(view())\n \n def test_syndication_controlpanel_enabled(self):\n- self.browser.open(\n- "%s/@@syndication-controlpanel" % self.portal_url)\n+ self.browser.open("%s/@@syndication-controlpanel" % self.portal_url)\n+ self.browser.getControl(name="form.widgets.default_enabled:list").value = True\n+ self.browser.getControl(name="form.widgets.show_author_info:list").value = False\n self.browser.getControl(\n- name=\'form.widgets.default_enabled:list\').value = True\n- self.browser.getControl(\n- name=\'form.widgets.show_author_info:list\').value = False\n- self.browser.getControl(\n- name=\'form.widgets.show_syndication_link:list\').value = True\n- self.browser.getControl(\'Save\').click()\n+ name="form.widgets.show_syndication_link:list"\n+ ).value = True\n+ self.browser.getControl("Save").click()\n \n- self.assertTrue(\'Changes saved\' in self.browser.contents)\n- self.browser.open(\n- "%s/@@syndication-controlpanel" % self.portal_url)\n+ self.assertTrue("Changes saved" in self.browser.contents)\n+ self.browser.open("%s/@@syndication-controlpanel" % self.portal_url)\n \n self.assertEqual(\n- self.browser.getControl(\n- name=\'form.widgets.default_enabled:list\'\n- ).value,\n- [\'selected\']\n+ self.browser.getControl(name="form.widgets.default_enabled:list").value,\n+ ["selected"],\n )\n self.assertEqual(\n- self.browser.getControl(\n- name=\'form.widgets.show_author_info:list\').value,\n- []\n+ self.browser.getControl(name="form.widgets.show_author_info:list").value, []\n )\n self.assertEqual(\n self.browser.getControl(\n- name=\'form.widgets.show_syndication_link:list\'\n+ name="form.widgets.show_syndication_link:list"\n ).value,\n- [\'selected\']\n+ ["selected"],\n )\n \n def test_create_collection(self):\n- """Create collection and check if synPropertiesForm link is present.\n- """\n+ """Create collection and check if synPropertiesForm link is present."""\n # create collection\n- self.portal.invokeFactory(\'Collection\', \'collection\')\n+ self.portal.invokeFactory("Collection", "collection")\n self.portal.collection.query = [\n {\n "i": "portal_type",\n "o": "plone.app.querystring.operation.selection.any",\n- "v": ["News Item"]\n+ "v": ["News Item"],\n },\n {\n "i": "review_state",\n "o": "plone.app.querystring.operation.selection.any",\n- "v": ["published"]\n- }\n+ "v": ["published"],\n+ },\n ]\n transaction.commit()\n # Enable syndication\n- self.browser.open(\n- "%s/@@syndication-controlpanel" % self.portal_url)\n- self.browser.getControl(\n- name=\'form.widgets.default_enabled:list\').value = [\'selected\']\n+ self.browser.open("%s/@@syndication-controlpanel" % self.portal_url)\n+ self.browser.getControl(name="form.widgets.default_enabled:list").value = [\n+ "selected"\n+ ]\n self.browser.getControl(\n- name=\'form.widgets.show_syndication_link:list\'\n- ).value = [\'selected\']\n- self.browser.getControl(\'Save\').click()\n- self.assertTrue(\'Changes saved\' in self.browser.contents)\n+ name="form.widgets.show_syndication_link:list"\n+ ).value = ["selected"]\n+ self.browser.getControl("Save").click()\n+ self.assertTrue("Changes saved" in self.browser.contents)\n \n- self.browser.open(self.portal_url + \'/collection\')\n- self.assertTrue(\'/RSS\' in self.browser.contents)\n+ self.browser.open(self.portal_url + "/collection")\n+ self.assertTrue("/RSS" in self.browser.contents)\ndiff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_types.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_types.py\nindex 0cf2a5624f..565b8f8a04 100644\n--- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_types.py\n+++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_types.py\n@@ -14,216 +14,179 @@ class TypesControlPanelFunctionalTest(unittest.TestCase):\n layer = PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING\n \n def setUp(self):\n- self.app = self.layer[\'app\']\n- self.portal = self.layer[\'portal\']\n+ self.app = self.layer["app"]\n+ self.portal = self.layer["portal"]\n self.portal_url = self.portal.absolute_url()\n self.types_url = "%s/@@content-controlpanel" % self.portal_url\n self.browser = Browser(self.app)\n self.browser.handleErrors = False\n self.browser.addHeader(\n- \'Authorization\',\n- f\'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}\'\n+ "Authorization", f"Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}"\n )\n \n def test_types_control_panel_link(self):\n- self.browser.open(\n- "%s/@@overview-controlpanel" % self.portal_url)\n- self.browser.getLink(\'Editing\').click()\n+ self.browser.open("%s/@@overview-controlpanel" % self.portal_url)\n+ self.browser.getLink("Editing").click()\n \n def test_standard_type_select(self):\n self.browser.open(self.types_url)\n- self.browser.getControl(name=\'type_id\').value = [\'Link\']\n+ self.browser.getControl(name="type_id").value = ["Link"]\n self.browser.getForm(action=self.types_url).submit()\n- self.assertIn(\'content-controlpanel\', self.browser.url)\n+ self.assertIn("content-controlpanel", self.browser.url)\n \n def test_standard_type_cancel(self):\n self.browser.open(self.types_url)\n- self.browser.getControl(name=\'type_id\').value = [\'Link\']\n- self.browser.getControl(\'Cancel\').click()\n- self.assertIn(\'@@overview-controlpanel\', self.browser.url)\n+ self.browser.getControl(name="type_id").value = ["Link"]\n+ self.browser.getControl("Cancel").click()\n+ self.assertIn("@@overview-controlpanel", self.browser.url)\n \n def test_standard_type_allow_commenting(self):\n self.browser.open(self.types_url)\n- self.browser.getControl(name=\'type_id\').value = [\'Link\']\n+ self.browser.getControl(name="type_id").value = ["Link"]\n self.browser.getForm(action=self.types_url).submit()\n- self.browser.getControl(\'Allow comments\').selected = True\n- self.browser.getControl(\'Save\').click()\n+ self.browser.getControl("Allow comments").selected = True\n+ self.browser.getControl("Save").click()\n \n # Check if settings got saved correctly\n self.browser.open(self.types_url)\n- self.browser.getControl(name=\'type_id\').value = [\'Link\']\n+ self.browser.getControl(name="type_id").value = ["Link"]\n self.browser.getForm(action=self.types_url).submit()\n- self.assertIn(\'Globally addable\', self.browser.contents)\n- self.assertIn(\'Allow comments\', self.browser.contents)\n- self.assertEqual(\n- self.browser.getControl(\'Allow comments\').selected,\n- True\n- )\n- self.assertIn(\'Visible in searches\', self.browser.contents)\n+ self.assertIn("Globally addable", self.browser.contents)\n+ self.assertIn("Allow comments", self.browser.contents)\n+ self.assertEqual(self.browser.getControl("Allow comments").selected, True)\n+ self.assertIn("Visible in searches", self.browser.contents)\n self.assertIn(\n \'\',\n- self.browser.contents)\n+ self.browser.contents,\n+ )\n self.assertIn(\n \'