From 778d541c2c5e12617b7680afb55843ec54d1fbdb Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Fri, 22 Jun 2018 23:38:56 +0200 Subject: [PATCH 001/127] DX based Plone Site --- Products/CMFPlone/Portal.py | 91 +++++++++++++----- Products/CMFPlone/configure.zcml | 1 + Products/CMFPlone/profiles/default/types.xml | 3 +- .../profiles/default/types/Plone_Site.xml | 93 ++++++++++++++----- 4 files changed, 140 insertions(+), 48 deletions(-) diff --git a/Products/CMFPlone/Portal.py b/Products/CMFPlone/Portal.py index 245cfbc0bd..36ccbbf17c 100644 --- a/Products/CMFPlone/Portal.py +++ b/Products/CMFPlone/Portal.py @@ -34,19 +34,59 @@ from webdav.NullResource import NullResource -@implementer(IPloneSiteRoot, ISyndicatable) -class PloneSite(PortalObjectBase, DefaultDublinCoreImpl, OrderedContainer, - BrowserDefaultMixin, UniqueObject): +from zope.interface import classImplementsOnly, implementedBy + +# hackydihack +from plone.dexterity.content import Container +from five.localsitemanager.registry import PersistentComponents +from Products.CMFCore.interfaces import ISiteRoot, IContentish +from Products.Five.component.interfaces import IObjectManagerSite +from Products.CMFCore.permissions import AddPortalMember +from Products.CMFCore.permissions import SetOwnPassword +from Products.CMFCore.permissions import SetOwnProperties +from Products.CMFCore.permissions import MailForgottenPassword +from Products.CMFCore.permissions import RequestReview +from Products.CMFCore.permissions import ReviewPortalContent +from Products.CMFCore.Skinnable import SkinnableObjectManager + +from zope.event import notify +from zope.component.interfaces import ComponentLookupError + +from zope.traversing.interfaces import BeforeTraverseEvent + + +PORTAL_SKINS_TOOL_ID = 'portal_skins' + +@implementer(IPloneSiteRoot, ISiteRoot, ISyndicatable, IObjectManagerSite) +class PloneSite(Container, SkinnableObjectManager, UniqueObject): """ The Plone site object. """ security = ClassSecurityInfo() meta_type = portal_type = 'Plone Site' + # Ensure certain attributes come from the correct base class. + _checkId = SkinnableObjectManager._checkId + + def __getattr__(self, name): + try: + return SkinnableObjectManager.__getattr__(self, name) + except AttributeError: + return super(PloneSite, self).__getattr__(name) + + # Removes the 'Components Folder' + manage_options = ( - PortalObjectBase.manage_options[:2] + - PortalObjectBase.manage_options[3:]) + Container.manage_options[:2] + + Container.manage_options[3:]) __ac_permissions__ = ( + (AddPortalMember, ()), + (SetOwnPassword, ()), + (SetOwnProperties, ()), + (MailForgottenPassword, ()), + (RequestReview, ()), + (ReviewPortalContent, ()), + (AddPortalContent, ()), (AddPortalFolders, ()), (ListPortalMembers, ()), @@ -71,14 +111,36 @@ class PloneSite(PortalObjectBase, DefaultDublinCoreImpl, OrderedContainer, _properties = ( {'id': 'title', 'type': 'string', 'mode': 'w'}, {'id': 'description', 'type': 'text', 'mode': 'w'}, + {'id': 'add_permission', 'type': 'text', 'mode': 'w'}, ) title = '' description = '' icon = 'misc_/CMFPlone/tool.gif' + # From PortalObjectBase.__init__ def __init__(self, id, title=''): - PortalObjectBase.__init__(self, id, title) - DefaultDublinCoreImpl.__init__(self) + super(PloneSite, self).__init__(id, title=title) + components = PersistentComponents('++etc++site') + components.__parent__ = self + self.setSiteManager(components) + + # From PortalObjectBase.__init__ + def getSkinsFolderName(self): + return PORTAL_SKINS_TOOL_ID + + # From PortalObjectBase.__init__ + def __before_publishing_traverse__(self, arg1, arg2=None): + """ Pre-traversal hook. + """ + # XXX hack around a bug(?) in BeforeTraverse.MultiHook + REQUEST = arg2 or arg1 + + try: + notify(BeforeTraverseEvent(self, REQUEST)) + except ComponentLookupError: + # allow ZMI access, even if the portal's site manager is missing + pass + self.setupCurrentSkin(REQUEST) def __browser_default__(self, request): """ Set default so we can return whatever we want instead @@ -111,21 +173,6 @@ def manage_beforeDelete(self, container, item): PloneSite.inheritedAttribute('manage_beforeDelete')(self, container, item) - security.declareProtected(permissions.DeleteObjects, 'manage_delObjects') - - def manage_delObjects(self, ids=None, REQUEST=None): - """We need to enforce security.""" - if ids is None: - ids = [] - if isinstance(ids, six.string_types): - ids = [ids] - for id in ids: - item = self._getOb(id) - if not _checkPermission(permissions.DeleteObjects, item): - raise Unauthorized( - "Do not have permissions to remove this object") - return PortalObjectBase.manage_delObjects(self, ids, REQUEST=REQUEST) - def view(self): """ Ensure that we get a plain view of the object, via a delegation to __call__(), which is defined in BrowserDefaultMixin diff --git a/Products/CMFPlone/configure.zcml b/Products/CMFPlone/configure.zcml index 97b3b34848..df848729f0 100644 --- a/Products/CMFPlone/configure.zcml +++ b/Products/CMFPlone/configure.zcml @@ -29,6 +29,7 @@ + diff --git a/Products/CMFPlone/profiles/default/types.xml b/Products/CMFPlone/profiles/default/types.xml index 93d91d8054..adf6b19d73 100644 --- a/Products/CMFPlone/profiles/default/types.xml +++ b/Products/CMFPlone/profiles/default/types.xml @@ -3,7 +3,6 @@ Controls the available content types in your portal - + diff --git a/Products/CMFPlone/profiles/default/types/Plone_Site.xml b/Products/CMFPlone/profiles/default/types/Plone_Site.xml index 8cdc3035c2..46bcbbd235 100644 --- a/Products/CMFPlone/profiles/default/types/Plone_Site.xml +++ b/Products/CMFPlone/profiles/default/types/Plone_Site.xml @@ -1,29 +1,63 @@ - - - The root object in a Plone site. - - Plone Site - CMFPlone - manage_addSite - folder_listing - False - False - - False - folder_listing - - - - - - - + + + + Plone Site + + + False + manage_addSite + + + + + + False + False + + + cmf.AddPortalContent + Products.CMFPlone.Portal.PloneSite + plone.app.contenttypes.schema:folder.xml + + + + + + + + + + + + + + + + string:${folder_url}/addPlone Site + listing_view + False + view + + + + + + + + + + - + + + + + From 1dbbebefc53495766c356f3d9a4ce5b5034503b3 Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Sat, 23 Jun 2018 13:53:25 +0200 Subject: [PATCH 002/127] Use /@@edit as /edit doesn't work Need to figure out why it is a 204. --- Products/CMFPlone/profiles/default/types/Plone_Site.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Products/CMFPlone/profiles/default/types/Plone_Site.xml b/Products/CMFPlone/profiles/default/types/Plone_Site.xml index 46bcbbd235..5dc870b616 100644 --- a/Products/CMFPlone/profiles/default/types/Plone_Site.xml +++ b/Products/CMFPlone/profiles/default/types/Plone_Site.xml @@ -71,7 +71,7 @@ condition_expr="not:object/@@plone_lock_info/is_locked_for_current_user|python:True" i18n:attributes="title" title="Edit" - url_expr="string:${object_url}/edit" + url_expr="string:${object_url}/@@edit" visible="True"> From d44f2d54d18089308d833a261f388ef331f7532c Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Sat, 23 Jun 2018 23:42:01 +0200 Subject: [PATCH 003/127] Fix a bunch of tests --- Products/CMFPlone/Portal.py | 18 +++++++++--------- Products/CMFPlone/factory.py | 8 +++++++- Products/CMFPlone/tests/testActionsTool.py | 2 +- Products/CMFPlone/tests/testNextPrevious.py | 4 ++-- Products/CMFPlone/tests/testPortalCreation.py | 6 ++++-- 5 files changed, 23 insertions(+), 15 deletions(-) diff --git a/Products/CMFPlone/Portal.py b/Products/CMFPlone/Portal.py index 36ccbbf17c..ec47655fd1 100644 --- a/Products/CMFPlone/Portal.py +++ b/Products/CMFPlone/Portal.py @@ -69,9 +69,11 @@ class PloneSite(Container, SkinnableObjectManager, UniqueObject): def __getattr__(self, name): try: - return SkinnableObjectManager.__getattr__(self, name) - except AttributeError: + # Try DX return super(PloneSite, self).__getattr__(name) + except AttributeError: + # Check portal_skins + return SkinnableObjectManager.__getattr__(self, name) # Removes the 'Components Folder' @@ -96,13 +98,6 @@ def __getattr__(self, name): 'manage_renameForm', 'manage_renameObject', 'manage_renameObjects'))) - security.declareProtected(Permissions.copy_or_move, 'manage_copyObjects') - - manage_renameObject = OrderedContainer.manage_renameObject - - moveObject = OrderedContainer.moveObject - moveObjectsByDelta = OrderedContainer.moveObjectsByDelta - # Switch off ZMI ordering interface as it assumes a slightly # different functionality has_order_support = 0 @@ -219,4 +214,9 @@ def reindexObject(self, idxs=None): def reindexObjectSecurity(self, skip_self=False): pass + +# Remove the IContentish interface so we don't listen to events that won't +# apply to the site root, ie handleUidAnnotationEvent +classImplementsOnly(PloneSite, implementedBy(PloneSite) - IContentish) + InitializeClass(PloneSite) diff --git a/Products/CMFPlone/factory.py b/Products/CMFPlone/factory.py index c7bf9ea89b..a8b17a4cdd 100644 --- a/Products/CMFPlone/factory.py +++ b/Products/CMFPlone/factory.py @@ -4,9 +4,11 @@ from Products.CMFPlone.interfaces import INonInstallable from Products.GenericSetup.tool import SetupTool from plone.registry.interfaces import IRegistry +from plone.uuid.handlers import addAttributeUUID from zope.component import queryUtility from zope.event import notify from zope.interface import implementer +from zope.lifecycleevent import ObjectCreatedEvent from zope.site.hooks import setSite _TOOL_ID = 'portal_setup' @@ -125,7 +127,11 @@ def addPloneSite(context, site_id, title='Plone site', description='', extension_ids=(), setup_content=True, default_language='en', portal_timezone='UTC'): """Add a PloneSite to the context.""" - context._setObject(site_id, PloneSite(site_id)) + + site = PloneSite(site_id) + notify(ObjectCreatedEvent(site)) + context._setObject(site_id, site) + site = context._getOb(site_id) site.setLanguage(default_language) # Set the accepted language for the rest of the request. This makes sure diff --git a/Products/CMFPlone/tests/testActionsTool.py b/Products/CMFPlone/tests/testActionsTool.py index 6a44881d97..48a44327a7 100644 --- a/Products/CMFPlone/tests/testActionsTool.py +++ b/Products/CMFPlone/tests/testActionsTool.py @@ -65,7 +65,7 @@ def testMissingActionProvider(self): self.fail_tb('Should not bomb out if a provider is missing') def testBrokenActionProvider(self): - self.portal.portal_types = None + self.portal.portal_types = self.portal.portal_catalog try: self.actions.listFilteredActionsFor(self.portal) except: diff --git a/Products/CMFPlone/tests/testNextPrevious.py b/Products/CMFPlone/tests/testNextPrevious.py index e74ed9b761..df2d55e6ef 100644 --- a/Products/CMFPlone/tests/testNextPrevious.py +++ b/Products/CMFPlone/tests/testNextPrevious.py @@ -79,8 +79,8 @@ def testAdapterOnPortal(self): None) self.assertTrue(view) self.assertFalse(view.enabled()) - self.assertEqual(None, view.next()) - self.assertEqual(None, view.previous()) + self.assertNotEqual(None, view.next()) + self.assertNotEqual(None, view.previous()) def testNextPreviousItems(self): self.folder.invokeFactory('Folder', 'case3') diff --git a/Products/CMFPlone/tests/testPortalCreation.py b/Products/CMFPlone/tests/testPortalCreation.py index 5aa1d6b1b6..7c6c9c465b 100644 --- a/Products/CMFPlone/tests/testPortalCreation.py +++ b/Products/CMFPlone/tests/testPortalCreation.py @@ -1023,8 +1023,10 @@ def test_addsite_en_as_nl(self): self.request.form['default_language'] = 'en' self.addsite() plonesite = self.app.plonesite1 - fp = plonesite['front-page'] # Unfortunately, the next test passes even without the fix (overriding # HTTP_ACCEPT_LANGUAGE on the request in factory.py). This seems to be # because translations are not available in the tests. - self.assertIn('Learn more about Plone', fp.text.raw) + self.assertIn('Learn more about Plone', plonesite.text.raw) + + # This works around a transaction abort failure. + import transaction; transaction.commit() From aaeda50936853c61aaae59659f7fa6eb45457060 Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Sun, 24 Jun 2018 15:40:41 +0200 Subject: [PATCH 004/127] DX uses zExceptions's Unauthorized, not AccessControl's --- Products/CMFPlone/tests/testPloneFolder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Products/CMFPlone/tests/testPloneFolder.py b/Products/CMFPlone/tests/testPloneFolder.py index a10c05d248..12a2936c3b 100644 --- a/Products/CMFPlone/tests/testPloneFolder.py +++ b/Products/CMFPlone/tests/testPloneFolder.py @@ -4,7 +4,7 @@ from Products.CMFPlone.utils import _createObjectByType -from AccessControl import Unauthorized +from zExceptions import Unauthorized from Products.CMFCore.permissions import DeleteObjects from zExceptions import BadRequest From 26b2f746be2f76e2acaa5ee8e0f29c78c4181dc0 Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Sun, 24 Jun 2018 17:09:24 +0200 Subject: [PATCH 005/127] Fix method aliasses --- Products/CMFPlone/Portal.py | 8 +++++--- Products/CMFPlone/tests/testPortalCreation.py | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Products/CMFPlone/Portal.py b/Products/CMFPlone/Portal.py index ec47655fd1..cc730e3f38 100644 --- a/Products/CMFPlone/Portal.py +++ b/Products/CMFPlone/Portal.py @@ -112,18 +112,18 @@ def __getattr__(self, name): description = '' icon = 'misc_/CMFPlone/tool.gif' - # From PortalObjectBase.__init__ + # From PortalObjectBase def __init__(self, id, title=''): super(PloneSite, self).__init__(id, title=title) components = PersistentComponents('++etc++site') components.__parent__ = self self.setSiteManager(components) - # From PortalObjectBase.__init__ + # From PortalObjectBase def getSkinsFolderName(self): return PORTAL_SKINS_TOOL_ID - # From PortalObjectBase.__init__ + # From PortalObjectBase def __before_publishing_traverse__(self, arg1, arg2=None): """ Pre-traversal hook. """ @@ -137,6 +137,8 @@ def __before_publishing_traverse__(self, arg1, arg2=None): pass self.setupCurrentSkin(REQUEST) + super(PloneSite, self).__before_publishing_traverse__(arg1, arg2) + def __browser_default__(self, request): """ Set default so we can return whatever we want instead of index_html """ diff --git a/Products/CMFPlone/tests/testPortalCreation.py b/Products/CMFPlone/tests/testPortalCreation.py index 7c6c9c465b..a2e82bbc94 100644 --- a/Products/CMFPlone/tests/testPortalCreation.py +++ b/Products/CMFPlone/tests/testPortalCreation.py @@ -437,7 +437,7 @@ def testPloneSiteFTIHasMethodAliases(self): expected_aliases = { '(Default)': '(dynamic view)', 'view': '(selected layout)', - 'edit': '@@site-controlpanel', + 'edit': '@@edit', 'sharing': '@@sharing', } fti = self.portal.getTypeInfo() From 56ee59ab285ba64f4933cf33ce0764b2ad83f492 Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Sun, 24 Jun 2018 17:12:05 +0200 Subject: [PATCH 006/127] Aliasses work again --- Products/CMFPlone/profiles/default/types/Plone_Site.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Products/CMFPlone/profiles/default/types/Plone_Site.xml b/Products/CMFPlone/profiles/default/types/Plone_Site.xml index 5dc870b616..46bcbbd235 100644 --- a/Products/CMFPlone/profiles/default/types/Plone_Site.xml +++ b/Products/CMFPlone/profiles/default/types/Plone_Site.xml @@ -71,7 +71,7 @@ condition_expr="not:object/@@plone_lock_info/is_locked_for_current_user|python:True" i18n:attributes="title" title="Edit" - url_expr="string:${object_url}/@@edit" + url_expr="string:${object_url}/edit" visible="True"> From 3d7db01adeac475953cb720240bfb1be1942b976 Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Sun, 24 Jun 2018 17:25:53 +0200 Subject: [PATCH 007/127] Plone Site's FTI did actually change --- Products/CMFPlone/tests/testPortalCreation.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Products/CMFPlone/tests/testPortalCreation.py b/Products/CMFPlone/tests/testPortalCreation.py index a2e82bbc94..e9f5e54819 100644 --- a/Products/CMFPlone/tests/testPortalCreation.py +++ b/Products/CMFPlone/tests/testPortalCreation.py @@ -426,11 +426,9 @@ def testTTWLockableProperty(self): self.assertEqual(True, registry['plone.lock_on_ttw_edit']) def testPortalFTIIsDynamicFTI(self): - # Plone Site FTI should be a DynamicView FTI + # Plone Site FTI should be a Dexterity FTI fti = self.portal.getTypeInfo() - self.assertEqual( - fti.meta_type, 'Factory-based Type Information with dynamic views' - ) + self.assertEqual(fti.meta_type, 'Dexterity FTI') def testPloneSiteFTIHasMethodAliases(self): # Should add method aliases to the Plone Site FTI From e7c7f0c91efd793205488b3a41ebbf20d29d3e8c Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Mon, 9 Jul 2018 12:56:29 +0200 Subject: [PATCH 008/127] Short circuit empty name in __getattr__ --- Products/CMFPlone/Portal.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Products/CMFPlone/Portal.py b/Products/CMFPlone/Portal.py index cc730e3f38..4760575adb 100644 --- a/Products/CMFPlone/Portal.py +++ b/Products/CMFPlone/Portal.py @@ -68,6 +68,8 @@ class PloneSite(Container, SkinnableObjectManager, UniqueObject): _checkId = SkinnableObjectManager._checkId def __getattr__(self, name): + if not name: + raise AttributeError(name) try: # Try DX return super(PloneSite, self).__getattr__(name) From cb0bd8990f6825737c03151f23649bc6435e70f5 Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Mon, 9 Jul 2018 12:59:23 +0200 Subject: [PATCH 009/127] PROPFIND is an acceptable method. --- Products/CMFPlone/Portal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Products/CMFPlone/Portal.py b/Products/CMFPlone/Portal.py index 4760575adb..f55b6f856f 100644 --- a/Products/CMFPlone/Portal.py +++ b/Products/CMFPlone/Portal.py @@ -155,7 +155,7 @@ def index_html(self): if bbb.HAS_ZSERVER and method in ('PUT', ): # Very likely a WebDAV client trying to create something return ReplaceableWrapper(NullResource(self, 'index_html')) - elif method in ('GET', 'HEAD', 'POST'): + elif method in ('GET', 'HEAD', 'POST', 'PROPFIND'): # Do nothing, let it go and acquire. pass else: From df2b4626c8821713ca4ef369997c4b0318e00f76 Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Tue, 17 Jul 2018 12:43:29 +0200 Subject: [PATCH 010/127] Remove index_html from skins. We use the DX container default view instead. --- .../skins/plone_templates/index_html.pt | 24 ------------------- .../plone_templates/index_html.pt.metadata | 2 -- Products/CMFPlone/tests/testWebDAV.py | 2 -- 3 files changed, 28 deletions(-) delete mode 100644 Products/CMFPlone/skins/plone_templates/index_html.pt delete mode 100644 Products/CMFPlone/skins/plone_templates/index_html.pt.metadata diff --git a/Products/CMFPlone/skins/plone_templates/index_html.pt b/Products/CMFPlone/skins/plone_templates/index_html.pt deleted file mode 100644 index 7b5e09fb7e..0000000000 --- a/Products/CMFPlone/skins/plone_templates/index_html.pt +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - -

Welcome to - Portal title -

- -

- Portal description -

- -
- - - diff --git a/Products/CMFPlone/skins/plone_templates/index_html.pt.metadata b/Products/CMFPlone/skins/plone_templates/index_html.pt.metadata deleted file mode 100644 index 6660362fbc..0000000000 --- a/Products/CMFPlone/skins/plone_templates/index_html.pt.metadata +++ /dev/null @@ -1,2 +0,0 @@ -[default] -title=Default frontpage diff --git a/Products/CMFPlone/tests/testWebDAV.py b/Products/CMFPlone/tests/testWebDAV.py index c3b7db5d1b..710cd9a21e 100644 --- a/Products/CMFPlone/tests/testWebDAV.py +++ b/Products/CMFPlone/tests/testWebDAV.py @@ -304,8 +304,6 @@ def testPUTIndexHtml(self): def testPUTIndexHtmlIntoPortal(self): # Create an index_html document in the portal via FTP/DAV self.assertFalse('index_html' in self.portal) - self.assertEqual(self.portal.index_html.meta_type, - 'Filesystem Page Template') self.setRoles(['Manager']) response = self.publish( From c7925bd9d73406f1408f70439d99bcf49005b20d Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Tue, 17 Jul 2018 12:45:03 +0200 Subject: [PATCH 011/127] =?UTF-8?q?Remove=20index=5Fhtml=20for=20Portal=20?= =?UTF-8?q?class.=20We=E2=80=99ll=20use=20the=20DX=20variant=20instead.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Products/CMFPlone/Portal.py | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/Products/CMFPlone/Portal.py b/Products/CMFPlone/Portal.py index f55b6f856f..591a00cc28 100644 --- a/Products/CMFPlone/Portal.py +++ b/Products/CMFPlone/Portal.py @@ -146,26 +146,6 @@ def __browser_default__(self, request): of index_html """ return getToolByName(self, 'plone_utils').browserDefault(self) - def index_html(self): - """ Acquire if not present. """ - request = getattr(self, 'REQUEST', None) - if request is not None and 'REQUEST_METHOD' in request: - if request.maybe_webdav_client: - method = request['REQUEST_METHOD'] - if bbb.HAS_ZSERVER and method in ('PUT', ): - # Very likely a WebDAV client trying to create something - return ReplaceableWrapper(NullResource(self, 'index_html')) - elif method in ('GET', 'HEAD', 'POST', 'PROPFIND'): - # Do nothing, let it go and acquire. - pass - else: - raise AttributeError('index_html') - # Acquire from skin. - _target = self.__getattr__('index_html') - return ReplaceableWrapper(aq_base(_target).__of__(self)) - - index_html = ComputedAttribute(index_html, 1) - def manage_beforeDelete(self, container, item): # Should send out an Event before Site is being deleted. self.removal_inprogress = 1 From 72cfb2145ab7d66c52bff6a5af8cceae1cd5cfde Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Tue, 17 Jul 2018 15:48:44 +0200 Subject: [PATCH 012/127] Make Plone Site a navigation root. This enabled the dashboard view --- Products/CMFPlone/Portal.py | 1 + Products/CMFPlone/factory.py | 4 ++-- Products/CMFPlone/profiles/default/types/Plone_Site.xml | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Products/CMFPlone/Portal.py b/Products/CMFPlone/Portal.py index 591a00cc28..6c741fdced 100644 --- a/Products/CMFPlone/Portal.py +++ b/Products/CMFPlone/Portal.py @@ -57,6 +57,7 @@ PORTAL_SKINS_TOOL_ID = 'portal_skins' + @implementer(IPloneSiteRoot, ISiteRoot, ISyndicatable, IObjectManagerSite) class PloneSite(Container, SkinnableObjectManager, UniqueObject): """ The Plone site object. """ diff --git a/Products/CMFPlone/factory.py b/Products/CMFPlone/factory.py index a8b17a4cdd..82e6009dac 100644 --- a/Products/CMFPlone/factory.py +++ b/Products/CMFPlone/factory.py @@ -130,9 +130,9 @@ def addPloneSite(context, site_id, title='Plone site', description='', site = PloneSite(site_id) notify(ObjectCreatedEvent(site)) - context._setObject(site_id, site) + context[site_id] = site - site = context._getOb(site_id) + site = context[site_id] site.setLanguage(default_language) # Set the accepted language for the rest of the request. This makes sure # the front-page text gets the correct translation also when your browser diff --git a/Products/CMFPlone/profiles/default/types/Plone_Site.xml b/Products/CMFPlone/profiles/default/types/Plone_Site.xml index 46bcbbd235..a6c55618ce 100644 --- a/Products/CMFPlone/profiles/default/types/Plone_Site.xml +++ b/Products/CMFPlone/profiles/default/types/Plone_Site.xml @@ -39,6 +39,7 @@ +
From f60a93b27173de3a5dc4e28a89bfe0dae2f27b67 Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Mon, 30 Jul 2018 21:40:09 +0200 Subject: [PATCH 013/127] We need INavigationRoot earlier in the IRO, or we'll get the dashboard namespace traverser. --- Products/CMFPlone/Portal.py | 3 ++- Products/CMFPlone/profiles/default/types/Plone_Site.xml | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Products/CMFPlone/Portal.py b/Products/CMFPlone/Portal.py index 6c741fdced..728dbff729 100644 --- a/Products/CMFPlone/Portal.py +++ b/Products/CMFPlone/Portal.py @@ -48,6 +48,7 @@ from Products.CMFCore.permissions import RequestReview from Products.CMFCore.permissions import ReviewPortalContent from Products.CMFCore.Skinnable import SkinnableObjectManager +from plone.app.layout.navigation.interfaces import INavigationRoot from zope.event import notify from zope.component.interfaces import ComponentLookupError @@ -58,7 +59,7 @@ PORTAL_SKINS_TOOL_ID = 'portal_skins' -@implementer(IPloneSiteRoot, ISiteRoot, ISyndicatable, IObjectManagerSite) +@implementer(IPloneSiteRoot, INavigationRoot, ISiteRoot, ISyndicatable, IObjectManagerSite) class PloneSite(Container, SkinnableObjectManager, UniqueObject): """ The Plone site object. """ diff --git a/Products/CMFPlone/profiles/default/types/Plone_Site.xml b/Products/CMFPlone/profiles/default/types/Plone_Site.xml index a6c55618ce..46bcbbd235 100644 --- a/Products/CMFPlone/profiles/default/types/Plone_Site.xml +++ b/Products/CMFPlone/profiles/default/types/Plone_Site.xml @@ -39,7 +39,6 @@ - From 85f8eab3d05bd64e5ec8610600c0cdd2317a19c2 Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Thu, 16 Aug 2018 20:03:33 +0200 Subject: [PATCH 014/127] Wait a bit until the elements are visible --- Products/CMFPlone/tests/robot/test_tinymce.robot | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Products/CMFPlone/tests/robot/test_tinymce.robot b/Products/CMFPlone/tests/robot/test_tinymce.robot index 0f1b38817f..c4f617e8aa 100644 --- a/Products/CMFPlone/tests/robot/test_tinymce.robot +++ b/Products/CMFPlone/tests/robot/test_tinymce.robot @@ -59,6 +59,7 @@ insert link Click Button css=div[aria-label="Insert/edit link"] button Click Button css=.pattern-relateditems-container button.favorites Click Link css=.pattern-relateditems-container .favorites a.fav[href='/'] + Wait Until Element Is Visible css=.pattern-relateditems-result-select.selectable Click Link css=.pattern-relateditems-result-select.selectable Input Text css=.plone-modal-body [name="title"] SomeTitle Click Button css=.plone-modal-footer .plone-btn-primary @@ -71,6 +72,7 @@ insert image Click Button css=div[aria-label="Insert/edit image"] button Click Button css=.pattern-relateditems-container button.favorites Click Link css=.pattern-relateditems-container .favorites a.fav[href='/'] + Wait Until Element Is Visible css=.pattern-relateditems-result-select.selectable Click Link css=.pattern-relateditems-result-select.selectable Input Text css=.plone-modal-body [name="title"] SomeTitle Input Text css=.plone-modal-body [name="alt"] SomeAlt From 6afc0204528b0c94c425d56e7bf3dbf278361b23 Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Thu, 21 Feb 2019 21:40:43 +0100 Subject: [PATCH 015/127] Remove 'Plone Site' the initial types.xml so don't trigger a modifiedevent when the actual content's types.xml is imported --- Products/CMFPlone/profiles/default/types.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/Products/CMFPlone/profiles/default/types.xml b/Products/CMFPlone/profiles/default/types.xml index adf6b19d73..85a523194a 100644 --- a/Products/CMFPlone/profiles/default/types.xml +++ b/Products/CMFPlone/profiles/default/types.xml @@ -3,6 +3,5 @@ Controls the available content types in your portal - From 24d4c7a6c17da8d5557988af1d6b014b4d33227e Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Sun, 3 Mar 2019 12:17:42 +0100 Subject: [PATCH 016/127] Fix creatng a new Plone Site --- Products/CMFPlone/factory.py | 3 +++ Products/CMFPlone/profiles/default/types.xml | 1 + 2 files changed, 4 insertions(+) diff --git a/Products/CMFPlone/factory.py b/Products/CMFPlone/factory.py index 82e6009dac..609978b0e9 100644 --- a/Products/CMFPlone/factory.py +++ b/Products/CMFPlone/factory.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from Products.CMFCore.interfaces import ISiteRoot from Products.CMFPlone.Portal import PloneSite from Products.CMFPlone.events import SiteManagerCreatedEvent from Products.CMFPlone.interfaces import INonInstallable @@ -147,6 +148,8 @@ def addPloneSite(context, site_id, title='Plone site', description='', notify(SiteManagerCreatedEvent(site)) setSite(site) + site.getSiteManager().registerUtility(site, ISiteRoot) + setup_tool.setBaselineContext('profile-%s' % profile_id) setup_tool.runAllImportStepsFromProfile('profile-%s' % profile_id) diff --git a/Products/CMFPlone/profiles/default/types.xml b/Products/CMFPlone/profiles/default/types.xml index 85a523194a..324c5fa186 100644 --- a/Products/CMFPlone/profiles/default/types.xml +++ b/Products/CMFPlone/profiles/default/types.xml @@ -4,4 +4,5 @@ name="title">Controls the available content types in your portal + From 999e03ab7c71e2a21263a39fb2415173139f0d1a Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Sun, 3 Mar 2019 17:37:39 +0100 Subject: [PATCH 017/127] add __delattr__ to try del item first. --- Products/CMFPlone/Portal.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Products/CMFPlone/Portal.py b/Products/CMFPlone/Portal.py index 728dbff729..0f7ecc8477 100644 --- a/Products/CMFPlone/Portal.py +++ b/Products/CMFPlone/Portal.py @@ -79,6 +79,12 @@ def __getattr__(self, name): # Check portal_skins return SkinnableObjectManager.__getattr__(self, name) + def __delattr__(self, name): + try: + del self[name] + except AttributeError: + super(PloneSite, self).__delattr__(name) + # Removes the 'Components Folder' manage_options = ( From f6c525475719efd55a4adc3f8fd18e7957d01fea Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Sun, 3 Mar 2019 22:38:02 +0100 Subject: [PATCH 018/127] __delattr__ should live in DX container --- Products/CMFPlone/Portal.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Products/CMFPlone/Portal.py b/Products/CMFPlone/Portal.py index 0f7ecc8477..728dbff729 100644 --- a/Products/CMFPlone/Portal.py +++ b/Products/CMFPlone/Portal.py @@ -79,12 +79,6 @@ def __getattr__(self, name): # Check portal_skins return SkinnableObjectManager.__getattr__(self, name) - def __delattr__(self, name): - try: - del self[name] - except AttributeError: - super(PloneSite, self).__delattr__(name) - # Removes the 'Components Folder' manage_options = ( From f8574f688ed678194fac5a84fed285faec798c3b Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Tue, 5 Mar 2019 11:32:41 +0100 Subject: [PATCH 019/127] We don't have front-page anumore --- Products/CMFPlone/tests/testCatalogTool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Products/CMFPlone/tests/testCatalogTool.py b/Products/CMFPlone/tests/testCatalogTool.py index f3fa4adc1b..e9d406dc87 100644 --- a/Products/CMFPlone/tests/testCatalogTool.py +++ b/Products/CMFPlone/tests/testCatalogTool.py @@ -33,7 +33,7 @@ group2 = 'g2' base_content = ['Members', 'aggregator', 'aggregator', - 'events', 'news', TEST_USER_ID, 'front-page', 'doc'] + 'events', 'news', TEST_USER_ID, 'doc'] class TestCatalogSetup(PloneTestCase): From c897100fdc81fb98c67071bbe08f0118a3cbe76f Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Tue, 5 Mar 2019 15:32:02 +0100 Subject: [PATCH 020/127] Add workaround for https://github.com/zopefoundation/Zope/issues/397 / IBrowserPublisher on BrowserView --- Products/CMFPlone/__init__.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Products/CMFPlone/__init__.py b/Products/CMFPlone/__init__.py index da9bd44fcf..b15533ffc9 100644 --- a/Products/CMFPlone/__init__.py +++ b/Products/CMFPlone/__init__.py @@ -216,3 +216,13 @@ def initialize(context): # Apply early monkey patches. For these patches, it is too late if we do this # in the initialize method. from Products.CMFPlone import earlypatches # noqa + +# https://github.com/zopefoundation/Zope/issues/397 +import zope.interface +import zope.browserpage.metaconfigure +import zope.publisher.interfaces.browser + +zope.interface.classImplementsOnly( + zope.browserpage.metaconfigure.simple, + zope.interface.implementedBy(zope.browserpage.metaconfigure.simple) - zope.publisher.interfaces.browser.IBrowserPublisher +) From 20b7f78d175c10b5c23cac51d89b10449f9b8148 Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Tue, 5 Mar 2019 15:42:11 +0100 Subject: [PATCH 021/127] Remove no lonnger correct test testObjectButtonActionsInvisibleOnPortalRoot --- Products/CMFPlone/tests/testPortalCreation.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Products/CMFPlone/tests/testPortalCreation.py b/Products/CMFPlone/tests/testPortalCreation.py index fa2527e4ba..bc10ce9cf5 100644 --- a/Products/CMFPlone/tests/testPortalCreation.py +++ b/Products/CMFPlone/tests/testPortalCreation.py @@ -531,13 +531,6 @@ def testSyndicationTabDisabled(self): "Actions tool still has visible 'syndication' action" ) - def testObjectButtonActionsInvisibleOnPortalRoot(self): - # only a manager would have proper permissions - self.setRoles(['Manager', 'Member']) - acts = self.actions.listFilteredActionsFor(self.portal) - buttons = acts.get('object_buttons', []) - self.assertEqual(0, len(buttons)) - def testObjectButtonActionsInvisibleOnPortalDefaultDocument(self): # only a manager would have proper permissions self.setRoles(['Manager', 'Member']) From 33143ef6a2a56cb89fd96056aeffdf5a6ef0d140 Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Tue, 5 Mar 2019 16:39:29 +0100 Subject: [PATCH 022/127] Update tests, title did change. --- Products/CMFPlone/tests/test_safe_formatter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Products/CMFPlone/tests/test_safe_formatter.py b/Products/CMFPlone/tests/test_safe_formatter.py index d597f206cd..031872f8f4 100644 --- a/Products/CMFPlone/tests/test_safe_formatter.py +++ b/Products/CMFPlone/tests/test_safe_formatter.py @@ -120,7 +120,7 @@ def test_cook_zope2_page_templates_good_format_attr_str(self): hack_pt(pt, self.portal) self.assertEqual( pt.pt_render().strip(), - '

title of <PloneSite at plone> is Plone site

') + '

title of <PloneSite at plone> is Welcome to Plone

') def test_cook_zope2_page_templates_good_format_attr_unicode(self): from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate @@ -128,7 +128,7 @@ def test_cook_zope2_page_templates_good_format_attr_unicode(self): hack_pt(pt, self.portal) self.assertEqual( pt.pt_render().strip(), - '

title of <PloneSite at plone> is Plone site

') + '

title of <PloneSite at plone> is Welcome to Plone

') def test_access_to_private_content_not_allowed_via_rich_text(self): try: From aad7c296972b0bdaed215bd6d133e55adb4c8bcb Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Tue, 5 Mar 2019 17:27:42 +0100 Subject: [PATCH 023/127] We don't have front-page anymore --- Products/CMFPlone/tests/testCSRFProtection.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Products/CMFPlone/tests/testCSRFProtection.py b/Products/CMFPlone/tests/testCSRFProtection.py index de3116eb1c..895b0f76db 100644 --- a/Products/CMFPlone/tests/testCSRFProtection.py +++ b/Products/CMFPlone/tests/testCSRFProtection.py @@ -43,11 +43,11 @@ def test_PloneTool_deleteObjectsByPaths(self): def test_PloneTool_transitionObjectsByPaths(self): infoFor = self.portal.portal_workflow.getInfoFor - frontpage = self.portal['front-page'] + frontpage = self.portal['news'] self.assertEqual(infoFor(frontpage, 'review_state'), 'published') self.checkAuthenticator( '/plone_utils/transitionObjectsByPaths', - 'workflow_action=retract&paths:list=front-page', status=302) + 'workflow_action=retract&paths:list=news', status=302) self.assertEqual(infoFor(frontpage, 'review_state'), 'visible') def test_PloneTool_renameObjectsByPaths(self): From 3c4411bc69051e48183480217109d4ee4bcb90f1 Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Tue, 5 Mar 2019 19:37:59 +0100 Subject: [PATCH 024/127] Revert "Add workaround for https://github.com/zopefoundation/Zope/issues/397 / IBrowserPublisher on BrowserView" no bueno This reverts commit c897100fdc81fb98c67071bbe08f0118a3cbe76f. --- Products/CMFPlone/__init__.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Products/CMFPlone/__init__.py b/Products/CMFPlone/__init__.py index b15533ffc9..da9bd44fcf 100644 --- a/Products/CMFPlone/__init__.py +++ b/Products/CMFPlone/__init__.py @@ -216,13 +216,3 @@ def initialize(context): # Apply early monkey patches. For these patches, it is too late if we do this # in the initialize method. from Products.CMFPlone import earlypatches # noqa - -# https://github.com/zopefoundation/Zope/issues/397 -import zope.interface -import zope.browserpage.metaconfigure -import zope.publisher.interfaces.browser - -zope.interface.classImplementsOnly( - zope.browserpage.metaconfigure.simple, - zope.interface.implementedBy(zope.browserpage.metaconfigure.simple) - zope.publisher.interfaces.browser.IBrowserPublisher -) From ee743869bcf893eaf97710e2ef755ffc8b8df451 Mon Sep 17 00:00:00 2001 From: krissik Date: Mon, 13 May 2019 14:10:55 +0200 Subject: [PATCH 025/127] Prevent loading of css at nav_root_url If 'tinymce-content-css' is missing in themes manifest.cfg its default value is ''. --- Products/CMFPlone/patterns/tinymce.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Products/CMFPlone/patterns/tinymce.py b/Products/CMFPlone/patterns/tinymce.py index 7283055d07..a858e7fe3d 100644 --- a/Products/CMFPlone/patterns/tinymce.py +++ b/Products/CMFPlone/patterns/tinymce.py @@ -49,7 +49,7 @@ def get_content_css(self, style_css=''): files.append('/'.join([self.nav_root_url, url.strip()])) theme = self.get_theme() tinymce_content_css = getattr(theme, 'tinymce_content_css', None) - if tinymce_content_css is not None: + if tinymce_content_css is not None and tinymce_content_css != '': for path in theme.tinymce_content_css.split(','): if path.startswith('http://') or path.startswith('https://'): files.append(path) From fd9596a26ce762e7d4660108a4e80b5dde90cbbd Mon Sep 17 00:00:00 2001 From: Kristin Kuche Date: Mon, 13 May 2019 16:03:09 +0200 Subject: [PATCH 026/127] Add changelog entry --- news/2861.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 news/2861.bugfix diff --git a/news/2861.bugfix b/news/2861.bugfix new file mode 100644 index 0000000000..3a04299ce9 --- /dev/null +++ b/news/2861.bugfix @@ -0,0 +1 @@ + If 'tinymce-content-css' option is missing in themes manifest.cfg prevent unnecessary loading of a css at nav_root_url while editing a page. [krissik] \ No newline at end of file From ce1621f24993270eec92ada004789e35d9b874ed Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Sat, 22 Jun 2019 10:14:35 +0200 Subject: [PATCH 027/127] don't need this --- Products/CMFPlone/factory.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Products/CMFPlone/factory.py b/Products/CMFPlone/factory.py index d3d3e8e3eb..4fd5845dcc 100644 --- a/Products/CMFPlone/factory.py +++ b/Products/CMFPlone/factory.py @@ -153,8 +153,6 @@ def addPloneSite(context, site_id, title='Plone site', description='', notify(SiteManagerCreatedEvent(site)) setSite(site) - site.getSiteManager().registerUtility(site, ISiteRoot) - setup_tool.setBaselineContext('profile-%s' % profile_id) setup_tool.runAllImportStepsFromProfile('profile-%s' % profile_id) From 9d305f4ed6800a0384ff01787c64f78ef6ecb8de Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Sat, 26 Oct 2019 18:10:17 +0200 Subject: [PATCH 028/127] Fix TTW Bundle compilation broken. Fixes #2969 --- .../CMFPlone/controlpanel/browser/resourceregistry.py | 10 ++-------- news/2969.bugfix | 2 ++ 2 files changed, 4 insertions(+), 8 deletions(-) create mode 100644 news/2969.bugfix diff --git a/Products/CMFPlone/controlpanel/browser/resourceregistry.py b/Products/CMFPlone/controlpanel/browser/resourceregistry.py index 9d502889cc..8b070c2919 100644 --- a/Products/CMFPlone/controlpanel/browser/resourceregistry.py +++ b/Products/CMFPlone/controlpanel/browser/resourceregistry.py @@ -409,14 +409,8 @@ def config(self): base_url = self.context.absolute_url() resources = self.get_resources() - try: - less_url = self.registry['plone.resources.lessc'] - except KeyError: - less_url = '++plone++static/components/less/dist/less-1.7.4.min.js' - try: - rjs_url = resources['rjs'].js - except KeyError: - rjs_url = '++plone++static/components/r.js/dist/r.js' + less_url = self.registry['plone.resources.lessc'] + rjs_url = self.registry['plone.resources.rjs'] data = { 'development': self.registry['plone.resources.development'], diff --git a/news/2969.bugfix b/news/2969.bugfix new file mode 100644 index 0000000000..42a9f9353b --- /dev/null +++ b/news/2969.bugfix @@ -0,0 +1,2 @@ +Fix TTW Bundle compilation broken. +[thet] From 977fdd1b73b174e491b841bc6a78d8e3a5b02c5d Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Sun, 3 Nov 2019 14:27:14 +0100 Subject: [PATCH 029/127] Add plone.staticresources to list of addons which are automatically upgraded if upgrade steps are available. --- Products/CMFPlone/MigrationTool.py | 1 + news/2976.feature | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 news/2976.feature diff --git a/Products/CMFPlone/MigrationTool.py b/Products/CMFPlone/MigrationTool.py index 8b4cf341ed..9e34155f80 100644 --- a/Products/CMFPlone/MigrationTool.py +++ b/Products/CMFPlone/MigrationTool.py @@ -99,6 +99,7 @@ def upgrade_all(self, context): Addon(profile_id=u'plone.app.querystring:default'), Addon(profile_id=u'plone.app.theming:default'), Addon(profile_id=u'plone.app.users:default'), + Addon(profile_id=u'plone.staticresources:default'), ]) diff --git a/news/2976.feature b/news/2976.feature new file mode 100644 index 0000000000..85570f37f7 --- /dev/null +++ b/news/2976.feature @@ -0,0 +1,2 @@ +Add plone.staticresources to list of addons which are automatically upgraded if upgrade steps are available. +[thet] From 8db341ba2b0538dcd3988ad96c49f36e47cac4c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Andrei?= Date: Wed, 6 Nov 2019 14:26:15 +0100 Subject: [PATCH 030/127] Fix #1318: Always install default content types on Plone site creation (#2971) * Fix #1318: Always install default content types on Plone site creation * Update changelog entry --- Products/CMFPlone/factory.py | 9 ++++++--- Products/CMFPlone/tests/test_factory.py | 20 ++++++++++++++++++++ news/1318.bugfix | 2 ++ 3 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 news/1318.bugfix diff --git a/Products/CMFPlone/factory.py b/Products/CMFPlone/factory.py index c25e9aec92..516ce95985 100644 --- a/Products/CMFPlone/factory.py +++ b/Products/CMFPlone/factory.py @@ -14,6 +14,7 @@ _TOOL_ID = 'portal_setup' _DEFAULT_PROFILE = 'Products.CMFPlone:plone' +_TYPES_PROFILE = 'plone.app.contenttypes:default' _CONTENT_PROFILE = 'plone.app.contenttypes:plone-content' # A little hint for PloneTestCase @@ -155,9 +156,11 @@ def addPloneSite(context, site_id, title='Plone site', description='', reg['plone.default_language'] = default_language reg['plone.available_languages'] = [default_language] - if setup_content: - setup_tool.runAllImportStepsFromProfile( - 'profile-%s' % content_profile_id) + # Install default content types profile if user do not select "example content" + # during site creation. + content_types_profile = content_profile_id if setup_content else _TYPES_PROFILE + + setup_tool.runAllImportStepsFromProfile('profile-{0}'.format(content_types_profile)) props = dict( title=title, diff --git a/Products/CMFPlone/tests/test_factory.py b/Products/CMFPlone/tests/test_factory.py index b22fb4a0b4..e3c776f881 100644 --- a/Products/CMFPlone/tests/test_factory.py +++ b/Products/CMFPlone/tests/test_factory.py @@ -1,15 +1,20 @@ # -*- coding: utf-8 -*- +from plone.dexterity.interfaces import IDexterityFTI from Products.CMFPlone.factory import addPloneSite +from Products.CMFPlone.utils import get_installer from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING +from zope.component import queryUtility import unittest + class TestFactoryPloneSite(unittest.TestCase): layer = PRODUCTS_CMFPLONE_INTEGRATION_TESTING def setUp(self): self.app = self.layer['app'] + self.request = self.layer['request'] def testPlonesiteWithUnicodeTitle(self): TITLE = 'Ploné' @@ -34,3 +39,18 @@ def testPlonesiteWithoutUnicodeTitle(self): ploneSiteTitle = ploneSite.Title() self.assertTrue(isinstance(ploneSiteTitle, str)) self.assertEqual(ploneSiteTitle, TITLE) + + def test_site_creation_without_content_but_with_dexterity(self): + """Test site creation without example content have dexterity installed.""" + ploneSite = addPloneSite( + self.app, 'ploneFoo', title='Foo', setup_content=False) + qi = get_installer(ploneSite, self.request) + self.assertTrue(qi.is_product_installed('plone.app.dexterity')) + + def test_site_creation_without_content_but_with_content_types(self): + """Test site creation without example content have content types.""" + ploneSite = addPloneSite( + self.app, 'ploneFoo', title='Foo', setup_content=False) + # Folder + fti = queryUtility(IDexterityFTI, name='Folder') + self.assertIsNotNone(fti) diff --git a/news/1318.bugfix b/news/1318.bugfix new file mode 100644 index 0000000000..06ce93b806 --- /dev/null +++ b/news/1318.bugfix @@ -0,0 +1,2 @@ +fix creation of Plone site not adding default Dexterity content types if example content not explicitily selected by user. +[ericof] From fd7224f2b539a149df7aa545245049c0d40c4455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Andrei?= Date: Tue, 3 Dec 2019 18:22:48 +0100 Subject: [PATCH 031/127] Correctly fire events when user auto login after the password has been reset (#2994) * Test if events fired after auto login have the correct principal * At this point the user is not logged in yet, so we get it from the membership_tool. * Update changelog * Remove adapter registration for IUserLoggedInEvent * Fix unregistering of adapter * Deal with cases where username/email were not the userid --- .../CMFPlone/browser/login/password_reset.py | 15 ++++++++-- Products/CMFPlone/tests/pwreset_browser.rst | 29 +++++++++++++++++++ news/2993.bugfix | 2 ++ 3 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 news/2993.bugfix diff --git a/Products/CMFPlone/browser/login/password_reset.py b/Products/CMFPlone/browser/login/password_reset.py index c56810c857..54610c2f28 100644 --- a/Products/CMFPlone/browser/login/password_reset.py +++ b/Products/CMFPlone/browser/login/password_reset.py @@ -10,6 +10,7 @@ from Products.CMFPlone.interfaces.controlpanel import IMailSchema from Products.CMFPlone.PasswordResetTool import ExpiredRequestError from Products.CMFPlone.PasswordResetTool import InvalidRequestError +from Products.CMFPlone.RegistrationTool import get_member_by_login_name from Products.CMFPlone.utils import safe_unicode from Products.CMFPlone.utils import safeToInt from Products.Five import BrowserView @@ -89,7 +90,8 @@ class PasswordResetView(BrowserView): subpath = None def _auto_login(self, userid, password): - aclu = getToolByName(self.context, 'acl_users') + context = self.context + aclu = getToolByName(context, 'acl_users') for name, plugin in aclu.plugins.listPlugins(ICredentialsUpdatePlugin): plugin.updateCredentials( self.request, @@ -97,7 +99,16 @@ def _auto_login(self, userid, password): userid, password ) - user = getSecurityManager().getUser() + + member = get_member_by_login_name(context, userid, False) + + if member: + user = member.getUser() + else: + # Fallback in case we cannot find a user + # with the given userid + user = getSecurityManager().getUser() + login_time = user.getProperty('login_time', None) if login_time is None: notify(UserInitialLoginInEvent(user)) diff --git a/Products/CMFPlone/tests/pwreset_browser.rst b/Products/CMFPlone/tests/pwreset_browser.rst index 922468f087..65bd1d1315 100644 --- a/Products/CMFPlone/tests/pwreset_browser.rst +++ b/Products/CMFPlone/tests/pwreset_browser.rst @@ -343,6 +343,19 @@ What we do here is quite similiar to 1A, but instead of typing in the password ourselves, we will be sent an e-mail with the URL to set our password. +We will setup an adapter to capture IUserLoggedInEvent events: + + >>> from zope.component import adapter + >>> from Products.PluggableAuthService.interfaces.events import IUserLoggedInEvent + >>> from zope.component import getGlobalSiteManager + >>> events_fired = [] + >>> @adapter(IUserLoggedInEvent) + ... def got_user_logged_in_event(event): + ... events_fired.append(event) + >>> gsm = getGlobalSiteManager() + >>> gsm.registerHandler(got_user_logged_in_event) + + First off, we need to set ``validate_mail`` to False: >>> browser.open('http://nohost/plone/login') @@ -389,6 +402,10 @@ We should have received an e-mail at this point: 3 >>> msg = str(mailhost.messages[-1]) +Let's clear the events storage: + + >>> events_fired = [] + Now that we have the message, we want to look at its contents, and then we extract the address that lets us reset our password: @@ -415,12 +432,24 @@ Now that we have the address, we will reset our password: >>> "Password reset successful, you are logged in now!" in browser.contents True +User is logged in, let's check the event fired for the correct user: + + >>> len(events_fired) == 1 + True + >>> events_fired[0].principal + + Log out again: >>> browser.getLink('Log out').click() >>> "You are now logged out" in browser.contents True +Remove got_user_logged_in_event registration: + + >>> gsm.unregisterHandler(got_user_logged_in_event) + True + 2B. Administrator adds user with email validation enabled --------------------------------------------------------- diff --git a/news/2993.bugfix b/news/2993.bugfix new file mode 100644 index 0000000000..f4be72869c --- /dev/null +++ b/news/2993.bugfix @@ -0,0 +1,2 @@ +Correctly fire events when user autologin after the password has been reset. +[ericof] From 9ac9295a486dc0f02e1a093147b7235a74647dfa Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Tue, 10 Dec 2019 17:32:12 +0100 Subject: [PATCH 032/127] saves me, but after all --- Products/CMFPlone/Portal.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/Products/CMFPlone/Portal.py b/Products/CMFPlone/Portal.py index 728dbff729..4a2d4c793a 100644 --- a/Products/CMFPlone/Portal.py +++ b/Products/CMFPlone/Portal.py @@ -72,6 +72,8 @@ class PloneSite(Container, SkinnableObjectManager, UniqueObject): def __getattr__(self, name): if not name: raise AttributeError(name) + # if name[0] != '_': + # print('PloneSite.__getattr__', self, name) try: # Try DX return super(PloneSite, self).__getattr__(name) @@ -79,6 +81,39 @@ def __getattr__(self, name): # Check portal_skins return SkinnableObjectManager.__getattr__(self, name) + + # def __getattr__(self, name): + # # if name[0] != '_': + # # print('Container.__getattr__', self, name) + # try: + # return DexterityContent.__getattr__(self, name) + # except AttributeError: + # pass + + # # Be specific about the implementation we use + # return CMFOrderedBTreeFolderBase.__getattr__(self, name) + + # def __delattr__(self, name): + # try: + # super(Container, self).__delattr__(name) + # except AttributeError: # delete the item instead + # del self[name] + + # def __setattr__(self, name, value): + # # If we have an existing attribute, just set it. + # # We'll check this first, so we don't check the tree unneeded. + # if name in self.__dict__: + # super(Container, self).__setattr__(name, value) + + # # if we have a n item, set that + # elif '_tree' in self.__dict__ and name in self: + # del self[name] + # self[name] = value + + # # else we'll set an attribute. + # else: + # super(Container, self).__setattr__(name, value) + # Removes the 'Components Folder' manage_options = ( From 40aa12f7652b4f1e3091aa0a70e2baf35eb61405 Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Wed, 11 Dec 2019 12:46:40 +0100 Subject: [PATCH 033/127] you could be happy --- Products/CMFPlone/Portal.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/Products/CMFPlone/Portal.py b/Products/CMFPlone/Portal.py index 4a2d4c793a..8e8add426f 100644 --- a/Products/CMFPlone/Portal.py +++ b/Products/CMFPlone/Portal.py @@ -60,7 +60,7 @@ @implementer(IPloneSiteRoot, INavigationRoot, ISiteRoot, ISyndicatable, IObjectManagerSite) -class PloneSite(Container, SkinnableObjectManager, UniqueObject): +class PloneSite(SkinnableObjectManager, Container, UniqueObject): """ The Plone site object. """ security = ClassSecurityInfo() @@ -70,16 +70,20 @@ class PloneSite(Container, SkinnableObjectManager, UniqueObject): _checkId = SkinnableObjectManager._checkId def __getattr__(self, name): - if not name: - raise AttributeError(name) - # if name[0] != '_': - # print('PloneSite.__getattr__', self, name) try: - # Try DX - return super(PloneSite, self).__getattr__(name) - except AttributeError: - # Check portal_skins return SkinnableObjectManager.__getattr__(self, name) + except AttributeError: + return Container.__getattr__(self, name) + # if not name: + # raise AttributeError(name) + # # if name[0] != '_': + # # print('PloneSite.__getattr__', self, name) + # try: + # # Try DX + # return super(PloneSite, self).__getattr__(name) + # except AttributeError: + # # Check portal_skins + # return SkinnableObjectManager.__getattr__(self, name) # def __getattr__(self, name): From ac6a6b8c3ab24df0aa591860f51831c7519f8ee9 Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Mon, 30 Dec 2019 22:51:46 +0100 Subject: [PATCH 034/127] get back to a working setup --- Products/CMFPlone/Portal.py | 57 +++++-------------------------------- 1 file changed, 7 insertions(+), 50 deletions(-) diff --git a/Products/CMFPlone/Portal.py b/Products/CMFPlone/Portal.py index 8e8add426f..7730adab55 100644 --- a/Products/CMFPlone/Portal.py +++ b/Products/CMFPlone/Portal.py @@ -60,7 +60,7 @@ @implementer(IPloneSiteRoot, INavigationRoot, ISiteRoot, ISyndicatable, IObjectManagerSite) -class PloneSite(SkinnableObjectManager, Container, UniqueObject): +class PloneSite(Container, SkinnableObjectManager, UniqueObject): """ The Plone site object. """ security = ClassSecurityInfo() @@ -70,53 +70,14 @@ class PloneSite(SkinnableObjectManager, Container, UniqueObject): _checkId = SkinnableObjectManager._checkId def __getattr__(self, name): + if not name: + raise AttributeError(name) try: - return SkinnableObjectManager.__getattr__(self, name) + # Try DX + return super(PloneSite, self).__getattr__(name) except AttributeError: - return Container.__getattr__(self, name) - # if not name: - # raise AttributeError(name) - # # if name[0] != '_': - # # print('PloneSite.__getattr__', self, name) - # try: - # # Try DX - # return super(PloneSite, self).__getattr__(name) - # except AttributeError: - # # Check portal_skins - # return SkinnableObjectManager.__getattr__(self, name) - - - # def __getattr__(self, name): - # # if name[0] != '_': - # # print('Container.__getattr__', self, name) - # try: - # return DexterityContent.__getattr__(self, name) - # except AttributeError: - # pass - - # # Be specific about the implementation we use - # return CMFOrderedBTreeFolderBase.__getattr__(self, name) - - # def __delattr__(self, name): - # try: - # super(Container, self).__delattr__(name) - # except AttributeError: # delete the item instead - # del self[name] - - # def __setattr__(self, name, value): - # # If we have an existing attribute, just set it. - # # We'll check this first, so we don't check the tree unneeded. - # if name in self.__dict__: - # super(Container, self).__setattr__(name, value) - - # # if we have a n item, set that - # elif '_tree' in self.__dict__ and name in self: - # del self[name] - # self[name] = value - - # # else we'll set an attribute. - # else: - # super(Container, self).__setattr__(name, value) + # Check portal_skins + return SkinnableObjectManager.__getattr__(self, name) # Removes the 'Components Folder' @@ -240,8 +201,4 @@ def reindexObjectSecurity(self, skip_self=False): pass -# Remove the IContentish interface so we don't listen to events that won't -# apply to the site root, ie handleUidAnnotationEvent -classImplementsOnly(PloneSite, implementedBy(PloneSite) - IContentish) - InitializeClass(PloneSite) From 594127183c7aadeb3135b9056c850d545cea93cb Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Mon, 30 Dec 2019 23:04:15 +0100 Subject: [PATCH 035/127] because CMFEditions does del self.portal.portal_purgepolicy --- Products/CMFPlone/Portal.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Products/CMFPlone/Portal.py b/Products/CMFPlone/Portal.py index 7730adab55..6c01065860 100644 --- a/Products/CMFPlone/Portal.py +++ b/Products/CMFPlone/Portal.py @@ -123,6 +123,16 @@ def __init__(self, id, title=''): components.__parent__ = self self.setSiteManager(components) + def __delattr__(self, name): + # because CMFEditions does del self.portal.portal_purgepolicy + try: + super().__delattr__(name) + except AttributeError: + try: + del self[name] + except KeyError: + raise AttributeError(name) + # From PortalObjectBase def getSkinsFolderName(self): return PORTAL_SKINS_TOOL_ID From 016459fd9d023017e9dc0a0b635bd66099826db1 Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Mon, 30 Dec 2019 23:14:08 +0100 Subject: [PATCH 036/127] so we do need this --- Products/CMFPlone/Portal.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Products/CMFPlone/Portal.py b/Products/CMFPlone/Portal.py index 6c01065860..802b03d627 100644 --- a/Products/CMFPlone/Portal.py +++ b/Products/CMFPlone/Portal.py @@ -211,4 +211,8 @@ def reindexObjectSecurity(self, skip_self=False): pass +# Remove the IContentish interface so we don't listen to events that won't +# apply to the site root, ie handleUidAnnotationEvent +classImplementsOnly(PloneSite, implementedBy(PloneSite) - IContentish) + InitializeClass(PloneSite) From fc45ebf97b5f10aa690e405c9acd5cfde65a5616 Mon Sep 17 00:00:00 2001 From: "T. Kim Nguyen" Date: Wed, 1 Jan 2020 11:26:20 -0600 Subject: [PATCH 037/127] Create FUNDING.yml --- .github/FUNDING.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000000..84f022c5ff --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,3 @@ +# These are supported funding model platforms + +custom: ['https://plone.org/sponsors'] From dedb74361fd4b9782939525d6cbece83dfcb9366 Mon Sep 17 00:00:00 2001 From: ale-rt Date: Sat, 8 Feb 2020 18:31:01 +0100 Subject: [PATCH 038/127] Improve tests for the workflow tool method listWFStatesByTitle Refs #3032 --- Products/CMFPlone/tests/testWorkflowTool.py | 90 ++++++++++++--------- news/3032.bugfix | 1 + 2 files changed, 52 insertions(+), 39 deletions(-) create mode 100644 news/3032.bugfix diff --git a/Products/CMFPlone/tests/testWorkflowTool.py b/Products/CMFPlone/tests/testWorkflowTool.py index 64df3c1ef5..a7081b229f 100644 --- a/Products/CMFPlone/tests/testWorkflowTool.py +++ b/Products/CMFPlone/tests/testWorkflowTool.py @@ -14,26 +14,6 @@ class IDocument(Interface): """ Dummy document interface """ -# INFO - Ugh...Rather than use and update ambiguous numbers, -# we maintain a mapping of the various workflows to states -# though there are some obvious downsides to this, it's better than just -# asserting that there are X published states in all workflows, etc. -workflow_dict = { - 'folder_workflow': ('private', 'published', 'visible',), - 'intranet_folder_workflow': ('internal', 'private',), - 'intranet_workflow': ('internal', 'internally_published', 'pending', - 'private', 'external',), - 'one_state_workflow': ('published',), - 'plone_workflow': ('pending', 'private', 'published', 'visible',), - 'simple_publication_workflow': ('private', 'published', 'pending',), - 'comment_one_state_workflow': ('published',), - 'comment_review_workflow': ('pending', 'published',) -} -# then we join all states into one master list -all_states = [] -for states in workflow_dict.values(): - all_states += list(states) - class TestWorkflowTool(PloneTestCase.PloneTestCase): @@ -111,25 +91,57 @@ def testGetTitleForTransitionOnTypeSucceedsWithNonString(self): self.assertEqual(state_title, state_id) def testListWFStatesByTitle(self): - states = self.workflow.listWFStatesByTitle() - self.assertEqual(len(states), len(all_states)) - pub_states = [s for s in states if s[1] == 'published'] - priv_states = [s for s in states if s[1] == 'private'] - pend_states = [s for s in states if s[1] == 'pending'] - vis_states = [s for s in states if s[1] == 'visible'] - external_states = [s for s in states if s[1] == 'external'] - internal_states = [s for s in states if s[1] == 'internal'] - internal_pub_states = [s for s in states - if s[1] == 'internally_published'] - - self.assertEqual(len(pub_states), all_states.count('published')) - self.assertEqual(len(priv_states), all_states.count('private')) - self.assertEqual(len(pend_states), all_states.count('pending')) - self.assertEqual(len(vis_states), all_states.count('visible')) - self.assertEqual(len(external_states), all_states.count('external')) - self.assertEqual(len(internal_states), all_states.count('internal')) - self.assertEqual(len(internal_pub_states), - all_states.count('internally_published')) + from Products.CMFPlone.WorkflowTool import WorkflowTool + from Products.DCWorkflow.DCWorkflow import DCWorkflowDefinition + from Products.DCWorkflow.States import StateDefinition + + tool = WorkflowTool() + + # Test without workflows + self.assertListEqual(tool.listWFStatesByTitle(), []) + self.assertListEqual(tool.listWFStatesByTitle(filter_similar=True), []) + + # Test with an empty workflow + tool["foo"] = DCWorkflowDefinition("foo") + + self.assertListEqual(tool.listWFStatesByTitle(), []) + self.assertListEqual(tool.listWFStatesByTitle(filter_similar=True), []) + + # Test with dummy states + tool["foo"].states["private"] = StateDefinition("private") + tool["foo"].states["published"] = StateDefinition("published") + + expected = [("", "private",), ("", "published")] + self.assertListEqual(tool.listWFStatesByTitle(), expected) + self.assertListEqual( + tool.listWFStatesByTitle(filter_similar=True), expected + ) + + # Test with concurrent states + tool["bar"] = DCWorkflowDefinition("bar") + tool["bar"].states["private"] = StateDefinition("private") + tool["bar"].states["pending"] = StateDefinition("pending") + tool["bar"].states["published"] = StateDefinition("published") + tool["bar"].states["published"].setProperties(title="Published") + expected = [ + ("", "private",), + ("", "published"), + ("", "private",), + ("", "pending"), + ("Published", "published"), + ] + self.assertListEqual(tool.listWFStatesByTitle(), expected) + expected = [ + ("", "private",), + ("", "published"), + ("", "pending"), + ("Published", "published"), + ] + self.assertListEqual( + tool.listWFStatesByTitle(filter_similar=True), expected + ) + + def testAdaptationBasedWorkflowOverride(self): # We take a piece of dummy content and register a dummy diff --git a/news/3032.bugfix b/news/3032.bugfix new file mode 100644 index 0000000000..b39fbdbd46 --- /dev/null +++ b/news/3032.bugfix @@ -0,0 +1 @@ +Improve tests for the workflow tool method listWFStatesByTitle From 993af19daa4739230918597cd50984bc94e58983 Mon Sep 17 00:00:00 2001 From: tschorr Date: Tue, 11 Feb 2020 14:15:18 +0100 Subject: [PATCH 039/127] require Zope wsgi extra (because of Paste) depending on Python version --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index a004c2c852..eee0b5ce44 100644 --- a/setup.py +++ b/setup.py @@ -117,7 +117,8 @@ 'transaction', 'z3c.autoinclude', 'ZODB3', - 'Zope >= 4.0b5', + 'Zope >= 4.0b5 ; python_version<"3"', + 'Zope[wsgi] >= 4.0b5 ; python_version>="3"', 'zope.app.locales >= 3.6.0', 'zope.cachedescriptors', 'zope.component', From 951778ba57210581911a764b9976b249550da806 Mon Sep 17 00:00:00 2001 From: tschorr Date: Tue, 11 Feb 2020 14:22:26 +0100 Subject: [PATCH 040/127] add changelog entry --- news/3039.bugfix | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 news/3039.bugfix diff --git a/news/3039.bugfix b/news/3039.bugfix new file mode 100644 index 0000000000..b6bbf9b03a --- /dev/null +++ b/news/3039.bugfix @@ -0,0 +1,2 @@ +A default WSGI configuration requires Paste which is only installed with the Zope[wsgi] extra.. +[tschorr] From 3a124330caa7d5d5bc693eb0e5a04c89be46741c Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Tue, 11 Feb 2020 14:32:54 +0100 Subject: [PATCH 041/127] Make setup.py reflect to be Plone 6 and Py3 only --- news/3041.breaking | 4 ++++ setup.py | 15 +++------------ 2 files changed, 7 insertions(+), 12 deletions(-) create mode 100644 news/3041.breaking diff --git a/news/3041.breaking b/news/3041.breaking new file mode 100644 index 0000000000..35dd0001eb --- /dev/null +++ b/news/3041.breaking @@ -0,0 +1,4 @@ +A part of "Drop Python 2 Support for Plone 6" #2812: +Reflect dropping of Python 2 support in setup.py. +Bump version to 6.0 +[jensens] \ No newline at end of file diff --git a/setup.py b/setup.py index eee0b5ce44..5a379b9764 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup from setuptools import find_packages -version = '5.2.1.dev0' +version = '6.0a1.dev0' setup( @@ -15,13 +15,12 @@ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Plone", - "Framework :: Plone :: 5.2", + "Framework :: Plone :: 6.0", "Framework :: Zope", "Framework :: Zope :: 4", "License :: OSI Approved :: GNU General Public License v2 (GPLv2)", "Operating System :: OS Independent", "Programming Language :: Python", - "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", @@ -100,7 +99,6 @@ 'Products.CMFUid', 'Products.DCWorkflow', 'Products.ExtendedPathIndex', - 'Products.ExternalEditor ; python_version<"3"', 'Products.GenericSetup >= 2.0.dev0', 'Products.MimetypesRegistry', 'Products.PlonePAS', @@ -117,8 +115,7 @@ 'transaction', 'z3c.autoinclude', 'ZODB3', - 'Zope >= 4.0b5 ; python_version<"3"', - 'Zope[wsgi] >= 4.0b5 ; python_version>="3"', + 'Zope[wsgi] >= 4.0b5', 'zope.app.locales >= 3.6.0', 'zope.cachedescriptors', 'zope.component', @@ -138,14 +135,8 @@ 'zope.tal', 'zope.tales', 'zope.traversing', - 'ZServer ; python_version<"3"', ], extras_require={ - 'archetypes': [ - 'Products.ATContentTypes ; python_version<"3"', - 'archetypes.multilingual ; python_version<"3"', - 'plone.app.contenttypes[archetypes,atrefs] ; python_version<"3"', - ], 'test': [ 'lxml', 'mock', From d134ef7bb285a51b115889b075ce9b999f68e636 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Tue, 11 Feb 2020 23:34:57 +0100 Subject: [PATCH 042/127] Include changelog of 5.2.1. Removed related news snippets. There are now no differences between master and 5.2.x, except basically in setup.py. [ci skip] --- CHANGES.rst | 32 ++++++++++++++++++++++++++++++++ news/1318.bugfix | 2 -- news/2790.bugfix | 2 -- news/2917.bugfix | 2 -- news/2935.bugfix | 1 - news/2956.bugfix | 2 -- news/2958.bugfix | 1 - news/2969.bugfix | 2 -- news/2976.feature | 2 -- news/2986.bugfix | 2 -- news/2993.bugfix | 2 -- news/frontpage-fix.trivial | 1 - 12 files changed, 32 insertions(+), 19 deletions(-) delete mode 100644 news/1318.bugfix delete mode 100644 news/2790.bugfix delete mode 100644 news/2917.bugfix delete mode 100644 news/2935.bugfix delete mode 100644 news/2956.bugfix delete mode 100644 news/2958.bugfix delete mode 100644 news/2969.bugfix delete mode 100644 news/2976.feature delete mode 100644 news/2986.bugfix delete mode 100644 news/2993.bugfix delete mode 100644 news/frontpage-fix.trivial diff --git a/CHANGES.rst b/CHANGES.rst index 9a1beab660..2a398c43e6 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -12,6 +12,38 @@ Changelog .. towncrier release notes start + +5.2.1 (2020-01-13) +------------------ + +New features: + + +- Add plone.staticresources to list of addons which are automatically upgraded if upgrade steps are available. + [thet] (#2976) + + +Bug fixes: + + +- fix creation of Plone site not adding default Dexterity content types if example content not explicitily selected by user. + [ericof] (#1318) +- fix default value for email msgid + [erral] (#2790) +- Fix: PasswordResetView::getErrors is called, this ensures password is validated through RegistrationTool before attempting to reset password. + [nazrulword] (#2917) +- Breadcrumbs: consider hidden folders when creating urls [ksuess] (#2935) +- Add Collection to the default_page_types list + [erral] (#2956) +- Fix localization of "Site setup" in some control panels [vincentfretin] (#2958) +- Fix TTW Bundle compilation broken. + [thet] (#2969) +- Do not save type settings in "content-controlpanel" when switching between types. + [cekk] (#2986) +- Correctly fire events when user autologin after the password has been reset. + [ericof] (#2993) + + 5.2.0 (2019-07-10) ------------------ diff --git a/news/1318.bugfix b/news/1318.bugfix deleted file mode 100644 index 06ce93b806..0000000000 --- a/news/1318.bugfix +++ /dev/null @@ -1,2 +0,0 @@ -fix creation of Plone site not adding default Dexterity content types if example content not explicitily selected by user. -[ericof] diff --git a/news/2790.bugfix b/news/2790.bugfix deleted file mode 100644 index 00db2e4a6b..0000000000 --- a/news/2790.bugfix +++ /dev/null @@ -1,2 +0,0 @@ -fix default value for email msgid -[erral] diff --git a/news/2917.bugfix b/news/2917.bugfix deleted file mode 100644 index e641d46b56..0000000000 --- a/news/2917.bugfix +++ /dev/null @@ -1,2 +0,0 @@ -Fix: PasswordResetView::getErrors is called, this ensures password is validated through RegistrationTool before attempting to reset password. -[nazrulword] diff --git a/news/2935.bugfix b/news/2935.bugfix deleted file mode 100644 index 4bf7d01316..0000000000 --- a/news/2935.bugfix +++ /dev/null @@ -1 +0,0 @@ -Breadcrumbs: consider hidden folders when creating urls [ksuess] diff --git a/news/2956.bugfix b/news/2956.bugfix deleted file mode 100644 index 58973ded7a..0000000000 --- a/news/2956.bugfix +++ /dev/null @@ -1,2 +0,0 @@ -Add Collection to the default_page_types list -[erral] diff --git a/news/2958.bugfix b/news/2958.bugfix deleted file mode 100644 index 9a053de442..0000000000 --- a/news/2958.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fix localization of "Site setup" in some control panels [vincentfretin] diff --git a/news/2969.bugfix b/news/2969.bugfix deleted file mode 100644 index 42a9f9353b..0000000000 --- a/news/2969.bugfix +++ /dev/null @@ -1,2 +0,0 @@ -Fix TTW Bundle compilation broken. -[thet] diff --git a/news/2976.feature b/news/2976.feature deleted file mode 100644 index 85570f37f7..0000000000 --- a/news/2976.feature +++ /dev/null @@ -1,2 +0,0 @@ -Add plone.staticresources to list of addons which are automatically upgraded if upgrade steps are available. -[thet] diff --git a/news/2986.bugfix b/news/2986.bugfix deleted file mode 100644 index 0af4d0128b..0000000000 --- a/news/2986.bugfix +++ /dev/null @@ -1,2 +0,0 @@ -Do not save type settings in "content-controlpanel" when switching between types. -[cekk] diff --git a/news/2993.bugfix b/news/2993.bugfix deleted file mode 100644 index f4be72869c..0000000000 --- a/news/2993.bugfix +++ /dev/null @@ -1,2 +0,0 @@ -Correctly fire events when user autologin after the password has been reset. -[ericof] diff --git a/news/frontpage-fix.trivial b/news/frontpage-fix.trivial deleted file mode 100644 index 46792a1d5a..0000000000 --- a/news/frontpage-fix.trivial +++ /dev/null @@ -1 +0,0 @@ -fix links on default frontpage From 2527c38c344cfe7c0b970321fc24d567d5d5c23b Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Wed, 22 Jan 2020 10:59:55 +0100 Subject: [PATCH 043/127] Password strength checks were not always checked Include Hotfix 20200121 with tests --- Products/CMFPlone/RegistrationTool.py | 2 +- .../CMFPlone/tests/testRegistrationTool.py | 20 +++++++++++++++++++ news/3021.bugfix.1 | 1 + 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 news/3021.bugfix.1 diff --git a/Products/CMFPlone/RegistrationTool.py b/Products/CMFPlone/RegistrationTool.py index 345afc2f9a..63f39f6c5e 100644 --- a/Products/CMFPlone/RegistrationTool.py +++ b/Products/CMFPlone/RegistrationTool.py @@ -188,7 +188,7 @@ def testPasswordValidity(self, password, confirm=None): # o If the password is valid, return None. # o If not, return a string explaining why. err = self.pasValidation('password', password) - if err and (password == '' or not _checkPermission(ManagePortal, self)): + if err: return err if confirm is not None and confirm != password: diff --git a/Products/CMFPlone/tests/testRegistrationTool.py b/Products/CMFPlone/tests/testRegistrationTool.py index 5042b91102..07471f404a 100644 --- a/Products/CMFPlone/tests/testRegistrationTool.py +++ b/Products/CMFPlone/tests/testRegistrationTool.py @@ -95,6 +95,26 @@ def testTestPasswordValidityConfirm(self): self.assertFalse(self.registration.testPasswordValidity( 'validpassword', confirm='anotherpassword') is None) + def testTestPasswordValidityPolicy(self): + self.assertIsNone(self.registration.testPasswordValidity("abcde", confirm=None)) + self.assertEqual( + self.registration.testPasswordValidity("abcd", confirm=None), + "Your password must contain at least 5 characters.", + ) + # Password validity is checked with an empty password + # to get a nice help message to show for the input field. + self.assertEqual( + self.registration.testPasswordValidity("", confirm=None), + "Minimum 5 characters.", + ) + + def testPasValidation(self): + self.assertIsNone(self.registration.pasValidation("password", "abcde")) + self.assertEqual( + self.registration.pasValidation("password", "abcd"), + "Your password must contain at least 5 characters.", + ) + def testNewIdAllowed(self): self.assertEqual(self.registration.isMemberIdAllowed('newuser'), 1) diff --git a/news/3021.bugfix.1 b/news/3021.bugfix.1 new file mode 100644 index 0000000000..23fa8a5e79 --- /dev/null +++ b/news/3021.bugfix.1 @@ -0,0 +1 @@ +Merge Hotfix20200121 Check of the strength of password could be skipped. From 5b0f5bc5db68f9e8bda76e592a3b50c6702b7343 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Wed, 22 Jan 2020 11:25:00 +0100 Subject: [PATCH 044/127] Merge isURLInPortal patch from Hotfix20200121. The isURLInPortal check that is done to avoid linking to an external site could be tricked into accepting malicious links. --- Products/CMFPlone/URLTool.py | 61 ++++++++++++++++++++++++++ Products/CMFPlone/tests/testURLTool.py | 10 +++++ news/3021.bugfix.2 | 1 + 3 files changed, 72 insertions(+) create mode 100644 news/3021.bugfix.2 diff --git a/Products/CMFPlone/URLTool.py b/Products/CMFPlone/URLTool.py index 68cac6f87e..71a021c273 100644 --- a/Products/CMFPlone/URLTool.py +++ b/Products/CMFPlone/URLTool.py @@ -16,6 +16,8 @@ import html import re import six +import string +import unicodedata hp = HTMLParser() @@ -36,6 +38,62 @@ 'javascript%3a', ] +# Determine allowed ascii characters. +# We want to allow most printable characters, +# but no whitespace, and no punctuation, except for a few exceptions. +# This boils down to ascii letters plus digits plus exceptions. +# Exceptions: +# - dot and slash for relative or absolute paths. +# - @ because we have views starting with @@ +# - + because we have ++resource++ urls +allowed_ascii = string.ascii_letters + string.digits + "./@+" + +def safe_url_first_char(url): + # For character code points higher than 127, the bytes representation of a character + # is longer than the unicode representation, so url[0] may give different results + # for bytes and unicode. On Python 2: + # >>> unichr(128) + # u'\x80' + # >>> len(unichr(128)) + # 1 + # >>> unichr(128).encode("latin-1") + # '\x80' + # >>> len(unichr(128).encode("latin-1")) + # 1 + # >>> unichr(128).encode("utf-8") + # '\xc2\x80' + # >>> len(unichr(128).encode("utf-8")) + # 2 + # >>> unichr(128).encode("utf-8")[0] + # '\xc2' + # So make sure we have unicode here for comparing the first character. + if isinstance(url, bytes): + # Remember, on Python 2, bytes == str. + try: + first = url.decode("utf-8")[0] + except UnicodeDecodeError: + # We don't trust this + return False + else: + first = url[0] + if ord(first) < 128: + if first not in allowed_ascii: + # The first character of the url is ascii but not in the allowed range. + return False + else: + # This is non-ascii, which has lots of control characters, which may be dangerous. + # Check taken from django.utils.http._is_safe_url. See + # https://github.com/django/django/blob/2.1.5/django/utils/http.py#L356-L382 + # Forbid URLs that start with control characters. Some browsers (like + # Chrome) ignore quite a few control characters at the start of a + # URL and might consider the URL as scheme relative. + # For categories, see 5.7.1 General Category Values here: + # http://www.unicode.org/reports/tr44/tr44-6.html#Property_Values + # We look for Control categories here. + if unicodedata.category(first)[0] == "C": + return False + return True + class URLTool(PloneBaseTool, BaseTool): @@ -57,6 +115,9 @@ def isURLInPortal(self, url, context=None): # site_properties are also considered within the portal to allow for # single sign on. + if url and not safe_url_first_char(url): + return False + # sanitize url url = re.sub('^[\x00-\x20]+', '', url).strip() cmp_url = url.lower() diff --git a/Products/CMFPlone/tests/testURLTool.py b/Products/CMFPlone/tests/testURLTool.py index bfa1bf1185..8c6e3dcf02 100644 --- a/Products/CMFPlone/tests/testURLTool.py +++ b/Products/CMFPlone/tests/testURLTool.py @@ -68,6 +68,7 @@ def test_isURLInPortal(self): self.assertTrue(iURLiP('https://www.foobar.com/bar/foo/folder')) self.assertFalse(iURLiP('http://www.foobar.com:8080/bar/foo/folder')) self.assertFalse(iURLiP('http://www.foobar.com/bar')) + self.assertTrue(iURLiP('//www.foobar.com/bar/foo')) self.assertFalse(iURLiP('/images')) self.assertTrue(iURLiP('/bar/foo/foo')) @@ -137,6 +138,15 @@ def test_double_back_slash(self): iURLiP = url_tool.isURLInPortal self.assertFalse(iURLiP('\\\\www.example.com')) + def test_escape(self): + url_tool = self._makeOne() + iURLiP = url_tool.isURLInPortal + self.assertFalse(iURLiP('\/\/www.example.com')) + self.assertFalse(iURLiP('\%2F\%2Fwww.example.com')) + self.assertFalse(iURLiP('\%2f\%2fwww.example.com')) + self.assertFalse(iURLiP('%2F%2Fwww.example.com')) + self.assertFalse(iURLiP('%2f%2fwww.example.com')) + def test_regression_absolute_url_in_portal(self): url_tool = self._makeOne() iURLiP = url_tool.isURLInPortal diff --git a/news/3021.bugfix.2 b/news/3021.bugfix.2 new file mode 100644 index 0000000000..b48698a2db --- /dev/null +++ b/news/3021.bugfix.2 @@ -0,0 +1 @@ +Merge Hotfix20200121: isURLInPortal could be tricked into accepting malicious links. From 35904f60670a39ac5091db368e87b8ea7580892b Mon Sep 17 00:00:00 2001 From: Fred van Dijk Date: Fri, 10 Apr 2020 13:31:40 +0200 Subject: [PATCH 045/127] Fix typo causes double translation text. Same message is on line 350 --- Products/CMFPlone/controlpanel/browser/redirects.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Products/CMFPlone/controlpanel/browser/redirects.py b/Products/CMFPlone/controlpanel/browser/redirects.py index b17bc680f8..f9f599156a 100644 --- a/Products/CMFPlone/controlpanel/browser/redirects.py +++ b/Products/CMFPlone/controlpanel/browser/redirects.py @@ -433,7 +433,7 @@ def upload(self, file, portal, storage, status): # TODO: detect indirect recursion err = _( u"Alternative urls that point to themselves will cause" - u"an endless cycle of redirects." + u" an endless cycle of redirects." ) else: err = _(u"Each line must have 2 or more columns.") From 886295355ea42b53d7910bf379a4926989965557 Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Thu, 16 Apr 2020 13:18:43 +0200 Subject: [PATCH 046/127] enable custom format string i18n/l10n --- Products/CMFPlone/i18nl10n.py | 132 +++++++++++++++++----------------- news/3084.feature | 4 ++ 2 files changed, 70 insertions(+), 66 deletions(-) create mode 100644 news/3084.feature diff --git a/Products/CMFPlone/i18nl10n.py b/Products/CMFPlone/i18nl10n.py index 292adf54a1..a5c59ce9a3 100644 --- a/Products/CMFPlone/i18nl10n.py +++ b/Products/CMFPlone/i18nl10n.py @@ -2,49 +2,52 @@ """ Collection of i18n and l10n utility methods. """ -import re -import logging - -from zope.component import getUtility -from zope.i18n import translate -from zope.i18n.locales import locales -from zope.publisher.interfaces.browser import IBrowserRequest - from Acquisition import aq_acquire from DateTime import DateTime from DateTime.interfaces import IDateTime - from plone.registry.interfaces import IRegistry from Products.CMFPlone.utils import log +from zope.component import getUtility +from zope.i18n import translate +from zope.i18n.locales import locales +from zope.publisher.interfaces.browser import IBrowserRequest -# these are taken from PTS, used for format interpolation -NAME_RE = r"[a-zA-Z][a-zA-Z0-9_]*" -_interp_regex = re.compile(r'(? Date: Thu, 16 Apr 2020 22:51:38 +0200 Subject: [PATCH 047/127] fix/add suggestions from review --- Products/CMFPlone/i18nl10n.py | 8 ++++---- Products/CMFPlone/tests/test_doctests.py | 1 - Products/CMFPlone/tests/test_l18nl10n.py | 25 ++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 Products/CMFPlone/tests/test_l18nl10n.py diff --git a/Products/CMFPlone/i18nl10n.py b/Products/CMFPlone/i18nl10n.py index a5c59ce9a3..9599e3067b 100644 --- a/Products/CMFPlone/i18nl10n.py +++ b/Products/CMFPlone/i18nl10n.py @@ -30,8 +30,8 @@ # structures, so here a copy: ENGLISH_NAMES = { '_days': ( - '', 'January', 'February', 'March', 'April', 'May', 'June', - 'July', 'August', 'September', 'October', 'November', 'December' + 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', + 'Saturday', ), '_days_a': ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'), '_days_p': ('Sun.', 'Mon.', 'Tue.', 'Wed.', 'Thu.', 'Fri.', 'Sat.'), @@ -202,13 +202,13 @@ def ulocalized_time(time, long_format=None, time_only=False, context=None, # add weekday name, abbr. weekday name, month name, abbr month name name_elements = formatelements & name_formatvariables - if bool({'a', 'A'} & name_elements): + if {'a', 'A'} & name_elements: weekday = int(time.strftime('%w')) # weekday, sunday = 0 if 'a' in name_elements: mapping['a'] = weekdayname_msgid_abbr(weekday) if 'A' in name_elements: mapping['A'] = weekdayname_msgid(weekday) - if bool({'b', 'B'} & name_elements): + if {'b', 'B'} & name_elements: monthday = int(time.strftime('%m')) # month, january = 1 if 'b' in name_elements: mapping['b'] = monthname_msgid_abbr(monthday) diff --git a/Products/CMFPlone/tests/test_doctests.py b/Products/CMFPlone/tests/test_doctests.py index fec43823b5..04f0963959 100644 --- a/Products/CMFPlone/tests/test_doctests.py +++ b/Products/CMFPlone/tests/test_doctests.py @@ -21,7 +21,6 @@ def test_suite(): package='Products.CMFPlone.tests', checker=Py23DocChecker(), ), - doctest.DocTestSuite('Products.CMFPlone.i18nl10n'), doctest.DocTestSuite('Products.CMFPlone.TranslationServiceTool'), doctest.DocTestSuite('Products.CMFPlone.utils'), doctest.DocTestSuite('Products.CMFPlone.workflow'), diff --git a/Products/CMFPlone/tests/test_l18nl10n.py b/Products/CMFPlone/tests/test_l18nl10n.py new file mode 100644 index 0000000000..89086a11a9 --- /dev/null +++ b/Products/CMFPlone/tests/test_l18nl10n.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +""" Unit tests for Products.CMFPlone.i18nl10n module. """ + +import unittest + +class BasicI18nl10nTests(unittest.TestCase): + + def test_regexp_dt_format_string_regexp(self): + from Products.CMFPlone.i18nl10n import _dt_format_string_regexp + dt_string = "%Y-%m-%d %H:%M" + locales_string = "${H}:${M}" + + # test for strftime format string + self.assertTrue(bool(_dt_format_string_regexp.findall(dt_string))) + self.assertFalse(bool(_dt_format_string_regexp.findall(locales_string))) + + def test_regexp_interp_regex(self): + from Products.CMFPlone.i18nl10n import _interp_regex + locales_string = "${H}:${M}" + + # test for locale string elements: + self.assertEquals( + _interp_regex.findall(locales_string), + ["${H}", "${M}"], + ) From 547530c95cd11136b4fd5cea537b0792801e926b Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Mon, 20 Apr 2020 09:40:08 +0200 Subject: [PATCH 048/127] Use time.process_time always. Available in all relevant Python 3 versions. --- Products/CMFPlone/CatalogTool.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Products/CMFPlone/CatalogTool.py b/Products/CMFPlone/CatalogTool.py index 0ac59665a4..4556da70c1 100644 --- a/Products/CMFPlone/CatalogTool.py +++ b/Products/CMFPlone/CatalogTool.py @@ -31,6 +31,7 @@ from Products.CMFPlone.utils import safe_unicode from Products.ZCatalog.ZCatalog import ZCatalog from six.moves import urllib +from time import process_time from zExceptions import Unauthorized from zope.annotation.interfaces import IAnnotations from zope.component import queryMultiAdapter @@ -45,10 +46,6 @@ import six import time -try: - from time import clock as process_time -except ImportError: - from time import process_time logger = logging.getLogger('Plone') From 8fc08b5f473f2315e6c5ad9c0424ad4ff6a5e958 Mon Sep 17 00:00:00 2001 From: MrTango Date: Wed, 22 Apr 2020 18:31:26 +0300 Subject: [PATCH 049/127] Add custom.css resource after diazo bundle --- Products/CMFPlone/resources/browser/styles.py | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Products/CMFPlone/resources/browser/styles.py b/Products/CMFPlone/resources/browser/styles.py index 2c34ceed0e..081af3248e 100644 --- a/Products/CMFPlone/resources/browser/styles.py +++ b/Products/CMFPlone/resources/browser/styles.py @@ -1,9 +1,12 @@ # -*- coding: utf-8 -*- from plone.app.layout.viewlets.common import ViewletBase +from plone.app.theming.interfaces import IThemeSettings +from plone.registry.interfaces import IRegistry from Products.CMFPlone.resources.browser.cook import cookWhenChangingSettings from Products.CMFPlone.resources.browser.resource import ResourceBase from Products.CMFPlone.utils import get_top_request from six.moves.urllib import parse +from zope.component import getUtility class StylesBase(ResourceBase): @@ -81,6 +84,12 @@ def get_data(self, bundle, result): 'src': css_location }) + @property + def custom_css_timestamp(self): + registry = getUtility(IRegistry) + theme_settings = registry.forInterface(IThemeSettings, False) + return theme_settings.custom_css_timestamp + def styles(self): """ Get all the styles @@ -143,6 +152,18 @@ def styles(self): 'bundle': 'diazo'} result.append(data) + + # custom.css + custom_css = { + 'rel': 'stylesheet', + 'conditionalcomment': '', + 'src': "{0}/custom.css?timestamp={1}".format( + self.site_url, + self.custom_css_timestamp, + ), + 'bundle': 'custom-css' + } + result.append(custom_css) return result From ab3186f5c48b5573879048845e8ed2c4c2e2642c Mon Sep 17 00:00:00 2001 From: MrTango Date: Thu, 23 Apr 2020 10:53:51 +0300 Subject: [PATCH 050/127] Add changelog entry --- news/3039.feature | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 news/3039.feature diff --git a/news/3039.feature b/news/3039.feature new file mode 100644 index 0000000000..88622ae8f2 --- /dev/null +++ b/news/3039.feature @@ -0,0 +1,3 @@ +Insert virtual custom.css bundle into the header after diazo bundle +depends on https://github.com/plone/plone.app.theming/pull/178 +[MrTango] From f5a15b48ee2610b8f6b63f1cd0417735195d08b9 Mon Sep 17 00:00:00 2001 From: MrTango Date: Thu, 23 Apr 2020 11:24:06 +0300 Subject: [PATCH 051/127] Add issue number to changelog entry --- news/3039.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/news/3039.feature b/news/3039.feature index 88622ae8f2..382b162a38 100644 --- a/news/3039.feature +++ b/news/3039.feature @@ -1,3 +1,3 @@ -Insert virtual custom.css bundle into the header after diazo bundle +Insert virtual custom.css bundle into the header after diazo bundle [#3086] depends on https://github.com/plone/plone.app.theming/pull/178 [MrTango] From d5392e89fd051ecc29c06229069fde8df02a3d7e Mon Sep 17 00:00:00 2001 From: MrTango Date: Thu, 23 Apr 2020 18:37:09 +0300 Subject: [PATCH 052/127] set GS version to 6000 --- Products/CMFPlone/profiles/default/metadata.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Products/CMFPlone/profiles/default/metadata.xml b/Products/CMFPlone/profiles/default/metadata.xml index 59f953369f..bf392ac8e1 100644 --- a/Products/CMFPlone/profiles/default/metadata.xml +++ b/Products/CMFPlone/profiles/default/metadata.xml @@ -1,4 +1,4 @@ - 5209 + 6000 From 771115742d79f829abc4aef472b306888d4689f6 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Fri, 24 Apr 2020 09:48:54 +0200 Subject: [PATCH 053/127] Add zcml-condition plone-60 for conditional configuration. --- Products/CMFPlone/meta.zcml | 1 + 1 file changed, 1 insertion(+) diff --git a/Products/CMFPlone/meta.zcml b/Products/CMFPlone/meta.zcml index fc3411c1b4..a86e5a7783 100644 --- a/Products/CMFPlone/meta.zcml +++ b/Products/CMFPlone/meta.zcml @@ -18,6 +18,7 @@ + From 6c682bb50594ecc4061613d01ae949586b511b4a Mon Sep 17 00:00:00 2001 From: Mikel Larreategi Date: Mon, 4 May 2020 17:58:27 +0200 Subject: [PATCH 054/127] Revert "Always show the same order on the control panel" This reverts commit f831db3102f349ccd4347ca29e9048c56d6ce27d. --- Products/CMFPlone/PloneControlPanel.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Products/CMFPlone/PloneControlPanel.py b/Products/CMFPlone/PloneControlPanel.py index b749d2d51f..9e97d7c58b 100644 --- a/Products/CMFPlone/PloneControlPanel.py +++ b/Products/CMFPlone/PloneControlPanel.py @@ -143,9 +143,10 @@ def enumConfiglets(self, group=None): a['title'] = translate(title, context=self.REQUEST) - def _id(v): - return v['id'] - res.sort(key=_id) + def _title(v): + return v['title'] + + res.sort(key=_title) return res security.declareProtected(ManagePortal, 'unregisterConfiglet') From 1f37e310e996673c98a3730d7147111e9bae7c92 Mon Sep 17 00:00:00 2001 From: Mikel Larreategi Date: Mon, 4 May 2020 18:03:04 +0200 Subject: [PATCH 055/127] changelog --- news/721.bugfix | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 news/721.bugfix diff --git a/news/721.bugfix b/news/721.bugfix new file mode 100644 index 0000000000..d6b094302b --- /dev/null +++ b/news/721.bugfix @@ -0,0 +1,2 @@ +Change control panel item sorting and sort them by title +[erral] From 162a68ea44850f0c054bbec484a55cb837aad359 Mon Sep 17 00:00:00 2001 From: Peter Mathis Date: Tue, 26 May 2020 15:09:15 +0200 Subject: [PATCH 056/127] update HTMLFilter defaults to enable TinyMCE layout features --- Products/CMFPlone/interfaces/controlpanel.py | 3 ++- news/2535.bugfix | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 news/2535.bugfix diff --git a/Products/CMFPlone/interfaces/controlpanel.py b/Products/CMFPlone/interfaces/controlpanel.py index 88a5496a6b..3d5681c509 100644 --- a/Products/CMFPlone/interfaces/controlpanel.py +++ b/Products/CMFPlone/interfaces/controlpanel.py @@ -246,6 +246,7 @@ class IFilterSchema(Interface): u'head', u'header', u'hgroup', + u'hr', u'html', u'i', u'iframe', @@ -297,7 +298,7 @@ class IFilterSchema(Interface): custom_attributes = schema.List( title=_(u'Custom attributes'), description=_(u'These attributes are additionally allowed.'), - default=[], + default=['style'], value_type=schema.TextLine(), missing_value=[], required=False) diff --git a/news/2535.bugfix b/news/2535.bugfix new file mode 100644 index 0000000000..f207ddeee7 --- /dev/null +++ b/news/2535.bugfix @@ -0,0 +1,2 @@ +Update HTMLFilter settings to enable TinyMCE styling features. See #2329, #2482, #2535 +[petschki] From 82e28989582ca287fb4f43d034fa748d76484f91 Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Sun, 14 Jun 2020 13:36:28 +0200 Subject: [PATCH 057/127] I think this is nonsense --- Products/CMFPlone/Portal.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/Products/CMFPlone/Portal.py b/Products/CMFPlone/Portal.py index 29f8b3c13c..6f01b8c1a6 100644 --- a/Products/CMFPlone/Portal.py +++ b/Products/CMFPlone/Portal.py @@ -71,8 +71,6 @@ class PloneSite(Container, SkinnableObjectManager, UniqueObject): _checkId = SkinnableObjectManager._checkId def __getattr__(self, name): - if not name: - raise AttributeError(name) try: # Try DX return super(PloneSite, self).__getattr__(name) @@ -124,16 +122,6 @@ def __init__(self, id, title=''): components.__parent__ = self self.setSiteManager(components) - def __delattr__(self, name): - # because CMFEditions does del self.portal.portal_purgepolicy - try: - super().__delattr__(name) - except AttributeError: - try: - del self[name] - except KeyError: - raise AttributeError(name) - # From PortalObjectBase def getSkinsFolderName(self): return PORTAL_SKINS_TOOL_ID From 43ba60aa2671fbdd7286949815f6a9455e73ef60 Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Sun, 14 Jun 2020 15:34:36 +0200 Subject: [PATCH 058/127] all a-ok --- Products/CMFPlone/Portal.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Products/CMFPlone/Portal.py b/Products/CMFPlone/Portal.py index 6f01b8c1a6..7953061593 100644 --- a/Products/CMFPlone/Portal.py +++ b/Products/CMFPlone/Portal.py @@ -67,6 +67,12 @@ class PloneSite(Container, SkinnableObjectManager, UniqueObject): security = ClassSecurityInfo() meta_type = portal_type = 'Plone Site' + # Define zope.component's PersistentComponents so we don't go off and + # try to look them up via DX's __getattr__ or behaviours. + # This attribute *should* be replaced by + # Five's PersistentComponents `_init_registries` + utilities = None + # Ensure certain attributes come from the correct base class. _checkId = SkinnableObjectManager._checkId From c56b59521630031261dcaaf4c06723113101f8ad Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Sat, 27 Jun 2020 12:31:23 +0200 Subject: [PATCH 059/127] Unicode marker is not needed on pure Python 3. --- Products/CMFPlone/interfaces/controlpanel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Products/CMFPlone/interfaces/controlpanel.py b/Products/CMFPlone/interfaces/controlpanel.py index 729858a84a..3d5681c509 100644 --- a/Products/CMFPlone/interfaces/controlpanel.py +++ b/Products/CMFPlone/interfaces/controlpanel.py @@ -298,7 +298,7 @@ class IFilterSchema(Interface): custom_attributes = schema.List( title=_(u'Custom attributes'), description=_(u'These attributes are additionally allowed.'), - default=[u'style'], + default=['style'], value_type=schema.TextLine(), missing_value=[], required=False) From 0738d70cb7e60de3886d54a94d72e6de5d6c63a1 Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Sun, 19 Jul 2020 14:12:46 +0200 Subject: [PATCH 060/127] no longer needed --- Products/CMFPlone/tests/testPortalCreation.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/Products/CMFPlone/tests/testPortalCreation.py b/Products/CMFPlone/tests/testPortalCreation.py index 38de2f1940..6f98fa92ed 100644 --- a/Products/CMFPlone/tests/testPortalCreation.py +++ b/Products/CMFPlone/tests/testPortalCreation.py @@ -1019,6 +1019,3 @@ def test_addsite_en_as_nl(self): # HTTP_ACCEPT_LANGUAGE on the request in factory.py). This seems to be # because translations are not available in the tests. self.assertIn('Learn more about Plone', plonesite.text.raw) - - # This works around a transaction abort failure. - import transaction; transaction.commit() From cadd9d3edd4ff06bbe0313c637efd552898a1f5d Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Tue, 28 Jul 2020 00:22:54 +0200 Subject: [PATCH 061/127] Removed a few news snippets that are already in latest 5.2.2 rc. --- news/2535.bugfix | 2 -- news/2861.bugfix | 1 - news/3039.feature | 3 --- 3 files changed, 6 deletions(-) delete mode 100644 news/2535.bugfix delete mode 100644 news/2861.bugfix delete mode 100644 news/3039.feature diff --git a/news/2535.bugfix b/news/2535.bugfix deleted file mode 100644 index f207ddeee7..0000000000 --- a/news/2535.bugfix +++ /dev/null @@ -1,2 +0,0 @@ -Update HTMLFilter settings to enable TinyMCE styling features. See #2329, #2482, #2535 -[petschki] diff --git a/news/2861.bugfix b/news/2861.bugfix deleted file mode 100644 index 3a04299ce9..0000000000 --- a/news/2861.bugfix +++ /dev/null @@ -1 +0,0 @@ - If 'tinymce-content-css' option is missing in themes manifest.cfg prevent unnecessary loading of a css at nav_root_url while editing a page. [krissik] \ No newline at end of file diff --git a/news/3039.feature b/news/3039.feature deleted file mode 100644 index 382b162a38..0000000000 --- a/news/3039.feature +++ /dev/null @@ -1,3 +0,0 @@ -Insert virtual custom.css bundle into the header after diazo bundle [#3086] -depends on https://github.com/plone/plone.app.theming/pull/178 -[MrTango] From 15b70419fb37853143a41244457328870d2c2e0f Mon Sep 17 00:00:00 2001 From: Fulvio Casali Date: Thu, 13 Aug 2020 13:50:33 -0700 Subject: [PATCH 062/127] Update README.rst Small typo and grammar fixes. --- README.rst | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.rst b/README.rst index 9596041b06..65f2a83027 100644 --- a/README.rst +++ b/README.rst @@ -3,16 +3,16 @@ About Plone Plone is a mature, secure and user-friendly Content Management System (CMS). -Plone - and its OpenSource community behind - aggregates more than 15 years experience in content-management. +Plone - and the Open Source community behind it - aggregates more than 15 years experience in content management. It offers all major features expected by a modern CMS out-of-the-box. -Lots of customizations can be made trough-the-web, such as creating content-types, themes, workflows and much more. -Pushed one step further Plone can be used as a framework to build custom CMS-like solutions on. +Lots of customizations can be made trough-the-web, such as creating content types, themes, workflows and much more. +Pushed one step further Plone can be used as a framework on which to build custom CMS-like solutions. Plone works as a -- full-featured classical backend renderend CMS, -- headless CMS offering all features as a RESTapi. +- full-featured classical server-side rendered CMS, +- headless CMS offering all features as a REST API. Installing Plone @@ -30,7 +30,7 @@ Documentation Consult `the official Plone documentation `_ with information for different audiences. -For trainings `comprehensive Plone training material `_ is offered. +For trainings `comprehensive Plone training material `_ is available. What is Plone? @@ -38,13 +38,13 @@ What is Plone? Plone is a ready-to-run content management system, offering a complete set of features needed by a wide variety of organizations. -Plone is secure by architecture and offers fine grained permission control over content and actions. +Security is built into Plone's architecture from the ground up. Plone offers fine grained permission control over content and actions. Plone is easy to set up, extremely flexible, and provides you with a system for managing web content that is ideal for project groups, communities, web sites, extranets and intranets. - *Plone is easy to install.* - You can install Plone with a a click and run installer, and have a content management system running on your computer in just a few minutes. + You can install Plone with a a click-and-run installer, and have a content management system running on your computer in just a few minutes. - *Plone is easy to use.* The Plone Team includes usability experts who have made Plone easy and attractive for content managers to add, update, and maintain content. @@ -76,12 +76,12 @@ Technical overview ------------------ Plone is a content management platform written in Python. -It builds up on Zope, an Open Source web application server and development system and so on the pluggable Zope Component Architecture (ZCA). +It builds upon Zope, an Open Source web application server and development system and thus on the pluggable Zope Component Architecture (ZCA). Python is the easy-to-learn, widely-used and supported Open Source programming language. -Python can be used to add new features to Plone, and used to understand or make changes to the way that Plone work. +Python can be used to add new features to Plone, and used to understand or make changes to the way that Plone works. -Plone stores its contents in Zope's built in transactional hierachical object database, the ZODB. +Plone stores its contents in Zope's built-in transactional hierachical object database, the ZODB. The ZODB can be connected to simple file-storages, scalable ZEO-Servers or Postgres, MySQL and Oracle. There are addon and techniques, however, to share information with other sources, such as relational databases, LDAP, filesystem files, etc. From d48ec3fb9a4c1f4c4178a38923ec95515b0f8b12 Mon Sep 17 00:00:00 2001 From: Fulvio Casali Date: Thu, 13 Aug 2020 14:04:03 -0700 Subject: [PATCH 063/127] Add links to official resources --- README.rst | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 65f2a83027..a665f4aa2c 100644 --- a/README.rst +++ b/README.rst @@ -87,5 +87,16 @@ There are addon and techniques, however, to share information with other sources files, etc. -.. _plone.org product page: http://plone.org/products/plone +Official Resources +------------------ +* `plone.com `_ - Official website for decision makers and evaluators. +* `plone.org `_ - Official website for developers and community. +* `Plone support `_ - Where to find help. +* `community.plone.org `_ - Official community forum, the best place to get help. +* `docs.plone.org `_ - Official documentation for developers/integrators. +* `training.plone.org `_ - Training classes for developers/integrators/users/designers. +* `plone.api `_ - Documentation for plone.api. +* `plone.restapi `_ - Documentation for plone.restapi. +* `official Gitter chat `_ - monitored. +.. _plone.org product page: http://plone.org/products/plone From 65ad161dc4cb7c6a90b07d32bb7b7083a7323b74 Mon Sep 17 00:00:00 2001 From: Fulvio Casali Date: Thu, 13 Aug 2020 14:59:21 -0700 Subject: [PATCH 064/127] The http://plone.org/products/plone page is no longer current. --- README.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/README.rst b/README.rst index a665f4aa2c..bc191b672d 100644 --- a/README.rst +++ b/README.rst @@ -99,4 +99,3 @@ Official Resources * `plone.restapi `_ - Documentation for plone.restapi. * `official Gitter chat `_ - monitored. -.. _plone.org product page: http://plone.org/products/plone From c4fb2cde08b805b92c3c9c141d6d16c23c1795d5 Mon Sep 17 00:00:00 2001 From: Fulvio Casali Date: Fri, 14 Aug 2020 13:31:16 -0700 Subject: [PATCH 065/127] Update README.rst --- README.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index bc191b672d..4638a5788f 100644 --- a/README.rst +++ b/README.rst @@ -38,13 +38,14 @@ What is Plone? Plone is a ready-to-run content management system, offering a complete set of features needed by a wide variety of organizations. -Security is built into Plone's architecture from the ground up. Plone offers fine grained permission control over content and actions. +Security is built into Plone's architecture from the ground up. +Plone offers fine grained permission control over content and actions. Plone is easy to set up, extremely flexible, and provides you with a system for managing web content that is ideal for project groups, communities, web sites, extranets and intranets. - *Plone is easy to install.* - You can install Plone with a a click-and-run installer, and have a content management system running on your computer in just a few minutes. + Several installation options are available for either your local machine or on servers in the cloud. - *Plone is easy to use.* The Plone Team includes usability experts who have made Plone easy and attractive for content managers to add, update, and maintain content. From eb63f12dd9fe6d0cee7c39d9967b467c9dbe9f5c Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Sat, 22 Aug 2020 16:27:33 +0200 Subject: [PATCH 066/127] Move dotted behaviors to named behaviors. --- .../profiles/default/types/Plone_Site.xml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Products/CMFPlone/profiles/default/types/Plone_Site.xml b/Products/CMFPlone/profiles/default/types/Plone_Site.xml index 46bcbbd235..9b2a4136d4 100644 --- a/Products/CMFPlone/profiles/default/types/Plone_Site.xml +++ b/Products/CMFPlone/profiles/default/types/Plone_Site.xml @@ -32,13 +32,14 @@ - - - - - - - + + + + + + + + From 4fc8503608fb7316e529a407b2b5b43d7284c448 Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Sat, 22 Aug 2020 19:20:02 +0200 Subject: [PATCH 067/127] Fix 'fix tests'. If NextPrevious is disabled we, correctly, should expect view.next and view.previous to be None --- Products/CMFPlone/tests/testNextPrevious.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Products/CMFPlone/tests/testNextPrevious.py b/Products/CMFPlone/tests/testNextPrevious.py index df2d55e6ef..e74ed9b761 100644 --- a/Products/CMFPlone/tests/testNextPrevious.py +++ b/Products/CMFPlone/tests/testNextPrevious.py @@ -79,8 +79,8 @@ def testAdapterOnPortal(self): None) self.assertTrue(view) self.assertFalse(view.enabled()) - self.assertNotEqual(None, view.next()) - self.assertNotEqual(None, view.previous()) + self.assertEqual(None, view.next()) + self.assertEqual(None, view.previous()) def testNextPreviousItems(self): self.folder.invokeFactory('Folder', 'case3') From 8760ff1056e33b191a5294cf2d8b247076c5013f Mon Sep 17 00:00:00 2001 From: Roel Bruggink Date: Sat, 22 Aug 2020 21:51:20 +0200 Subject: [PATCH 068/127] MailHost is an item now --- Products/CMFPlone/testing.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Products/CMFPlone/testing.py b/Products/CMFPlone/testing.py index b7f96ed80e..a014fd096c 100644 --- a/Products/CMFPlone/testing.py +++ b/Products/CMFPlone/testing.py @@ -58,10 +58,11 @@ def setUpPloneSite(self, portal): title=u"Members" ) - portal._original_MailHost = portal.MailHost + portal._original_MailHost = portal['MailHost'] mail_host = MockMailHost('MailHost') mail_host.smtp_host = 'localhost' - portal.MailHost = mail_host + del portal['MailHost'] + portal['MailHost'] = mail_host site_manager = getSiteManager(portal) site_manager.unregisterUtility(provided=IMailHost) site_manager.registerUtility(mail_host, IMailHost) @@ -71,7 +72,8 @@ def tearDownPloneSite(self, portal): setRoles(portal, TEST_USER_ID, ['Manager']) portal.manage_delObjects(['test-folder']) - portal.MailHost = portal._original_MailHost + del portal['MailHost'] + portal['MailHost'] = portal._original_MailHost sm = getSiteManager(context=portal) sm.unregisterUtility(provided=IMailHost) sm.registerUtility( From b8aa90a8aaa71b0f3a75a280362f3cd2d59056c7 Mon Sep 17 00:00:00 2001 From: Kristin Kuche Date: Mon, 13 May 2019 16:03:09 +0200 Subject: [PATCH 069/127] Add changelog entry --- news/2861.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 news/2861.bugfix diff --git a/news/2861.bugfix b/news/2861.bugfix new file mode 100644 index 0000000000..3a04299ce9 --- /dev/null +++ b/news/2861.bugfix @@ -0,0 +1 @@ + If 'tinymce-content-css' option is missing in themes manifest.cfg prevent unnecessary loading of a css at nav_root_url while editing a page. [krissik] \ No newline at end of file From fb83f3490e9120178c4fbd16042750c432b8ca4f Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Sat, 26 Oct 2019 18:10:17 +0200 Subject: [PATCH 070/127] Fix TTW Bundle compilation broken. Fixes #2969 --- news/2969.bugfix | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 news/2969.bugfix diff --git a/news/2969.bugfix b/news/2969.bugfix new file mode 100644 index 0000000000..42a9f9353b --- /dev/null +++ b/news/2969.bugfix @@ -0,0 +1,2 @@ +Fix TTW Bundle compilation broken. +[thet] From 73f19db5091b98e567e01158eb7ac9b462d5b0d7 Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Sun, 3 Nov 2019 14:27:14 +0100 Subject: [PATCH 071/127] Add plone.staticresources to list of addons which are automatically upgraded if upgrade steps are available. --- news/2976.feature | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 news/2976.feature diff --git a/news/2976.feature b/news/2976.feature new file mode 100644 index 0000000000..85570f37f7 --- /dev/null +++ b/news/2976.feature @@ -0,0 +1,2 @@ +Add plone.staticresources to list of addons which are automatically upgraded if upgrade steps are available. +[thet] From a118b75aa92ce3389059826682df42ceb8791ad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Andrei?= Date: Wed, 6 Nov 2019 14:26:15 +0100 Subject: [PATCH 072/127] Fix #1318: Always install default content types on Plone site creation (#2971) * Fix #1318: Always install default content types on Plone site creation * Update changelog entry --- news/1318.bugfix | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 news/1318.bugfix diff --git a/news/1318.bugfix b/news/1318.bugfix new file mode 100644 index 0000000000..06ce93b806 --- /dev/null +++ b/news/1318.bugfix @@ -0,0 +1,2 @@ +fix creation of Plone site not adding default Dexterity content types if example content not explicitily selected by user. +[ericof] From 9bcdd87e1a8fe294eac36e41ed03e206e1bc36e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Andrei?= Date: Tue, 3 Dec 2019 18:22:48 +0100 Subject: [PATCH 073/127] Correctly fire events when user auto login after the password has been reset (#2994) * Test if events fired after auto login have the correct principal * At this point the user is not logged in yet, so we get it from the membership_tool. * Update changelog * Remove adapter registration for IUserLoggedInEvent * Fix unregistering of adapter * Deal with cases where username/email were not the userid --- news/2993.bugfix | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 news/2993.bugfix diff --git a/news/2993.bugfix b/news/2993.bugfix new file mode 100644 index 0000000000..f4be72869c --- /dev/null +++ b/news/2993.bugfix @@ -0,0 +1,2 @@ +Correctly fire events when user autologin after the password has been reset. +[ericof] From 9491972fda4e9c13de87ea84b34f0afd3fd98ccd Mon Sep 17 00:00:00 2001 From: Mikel Larreategi Date: Mon, 4 May 2020 18:03:04 +0200 Subject: [PATCH 074/127] changelog --- news/721.bugfix | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 news/721.bugfix diff --git a/news/721.bugfix b/news/721.bugfix new file mode 100644 index 0000000000..d6b094302b --- /dev/null +++ b/news/721.bugfix @@ -0,0 +1,2 @@ +Change control panel item sorting and sort them by title +[erral] From e8664ea1ad3d83efa5ca39fe6a436de26ae8ba16 Mon Sep 17 00:00:00 2001 From: "T. Kim Nguyen" Date: Wed, 1 Jan 2020 11:26:20 -0600 Subject: [PATCH 075/127] Create FUNDING.yml --- .github/FUNDING.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000000..84f022c5ff --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,3 @@ +# These are supported funding model platforms + +custom: ['https://plone.org/sponsors'] From 5ebdf75532aaf879f68b58bb8c12bc90291e4a47 Mon Sep 17 00:00:00 2001 From: tschorr Date: Tue, 11 Feb 2020 14:15:18 +0100 Subject: [PATCH 076/127] require Zope wsgi extra (because of Paste) depending on Python version --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 4f3d133ca6..bc5eb5b60c 100644 --- a/setup.py +++ b/setup.py @@ -119,7 +119,8 @@ 'transaction', 'z3c.autoinclude', 'ZODB3', - 'Zope >= 4.0b5', + 'Zope >= 4.0b5 ; python_version<"3"', + 'Zope[wsgi] >= 4.0b5 ; python_version>="3"', 'zope.app.locales >= 3.6.0', 'zope.cachedescriptors', 'zope.component', From b238a7d44795028453784756ba1705dd3c580788 Mon Sep 17 00:00:00 2001 From: tschorr Date: Tue, 11 Feb 2020 14:22:26 +0100 Subject: [PATCH 077/127] add changelog entry --- news/3039.bugfix | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 news/3039.bugfix diff --git a/news/3039.bugfix b/news/3039.bugfix new file mode 100644 index 0000000000..b6bbf9b03a --- /dev/null +++ b/news/3039.bugfix @@ -0,0 +1,2 @@ +A default WSGI configuration requires Paste which is only installed with the Zope[wsgi] extra.. +[tschorr] From 2afd129b02ebc755c6f0865a431d48bc5c676060 Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Tue, 11 Feb 2020 14:32:54 +0100 Subject: [PATCH 078/127] Make setup.py reflect to be Plone 6 and Py3 only --- news/3041.breaking | 4 ++++ setup.py | 16 +++------------- 2 files changed, 7 insertions(+), 13 deletions(-) create mode 100644 news/3041.breaking diff --git a/news/3041.breaking b/news/3041.breaking new file mode 100644 index 0000000000..35dd0001eb --- /dev/null +++ b/news/3041.breaking @@ -0,0 +1,4 @@ +A part of "Drop Python 2 Support for Plone 6" #2812: +Reflect dropping of Python 2 support in setup.py. +Bump version to 6.0 +[jensens] \ No newline at end of file diff --git a/setup.py b/setup.py index bc5eb5b60c..2024e91c26 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup from setuptools import find_packages -version = '5.2.3.dev0' +version = '6.0a1.dev0' setup( @@ -15,14 +15,12 @@ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Plone", - "Framework :: Plone :: 5.2", - "Framework :: Plone :: Core", + "Framework :: Plone :: 6.0", "Framework :: Zope", "Framework :: Zope :: 4", "License :: OSI Approved :: GNU General Public License v2 (GPLv2)", "Operating System :: OS Independent", "Programming Language :: Python", - "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", @@ -101,7 +99,6 @@ 'Products.CMFUid', 'Products.DCWorkflow', 'Products.ExtendedPathIndex', - 'Products.ExternalEditor ; python_version<"3"', 'Products.GenericSetup >= 2.0.dev0', 'Products.isurlinportal', 'Products.MimetypesRegistry', @@ -119,8 +116,7 @@ 'transaction', 'z3c.autoinclude', 'ZODB3', - 'Zope >= 4.0b5 ; python_version<"3"', - 'Zope[wsgi] >= 4.0b5 ; python_version>="3"', + 'Zope[wsgi] >= 4.0b5', 'zope.app.locales >= 3.6.0', 'zope.cachedescriptors', 'zope.component', @@ -140,14 +136,8 @@ 'zope.tal', 'zope.tales', 'zope.traversing', - 'ZServer ; python_version<"3"', ], extras_require={ - 'archetypes': [ - 'Products.ATContentTypes ; python_version<"3"', - 'archetypes.multilingual ; python_version<"3"', - 'plone.app.contenttypes[archetypes,atrefs] ; python_version<"3"', - ], 'test': [ 'lxml', 'mock', From 72fffd5bd9aed3bd17cc2c0a27b16c20a17c5f7f Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Tue, 11 Feb 2020 23:34:57 +0100 Subject: [PATCH 079/127] Include changelog of 5.2.1. Removed related news snippets. There are now no differences between master and 5.2.x, except basically in setup.py. [ci skip] --- CHANGES.rst | 2 +- news/1318.bugfix | 2 -- news/2969.bugfix | 2 -- news/2976.feature | 2 -- news/2993.bugfix | 2 -- 5 files changed, 1 insertion(+), 9 deletions(-) delete mode 100644 news/1318.bugfix delete mode 100644 news/2969.bugfix delete mode 100644 news/2976.feature delete mode 100644 news/2993.bugfix diff --git a/CHANGES.rst b/CHANGES.rst index 80baac78f8..a3ae16923b 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -100,7 +100,7 @@ Bug fixes: [maurits] (#3084) - Make the resource registry scripts output more robust when a bundle resource is missing. This prevents breaking your whole Plone site and access to the resource registry control panel after inserting - one missing resource. + one missing resource. [fredvd] (#3096) - Bugfix for #3103 [petschki] (#3105) diff --git a/news/1318.bugfix b/news/1318.bugfix deleted file mode 100644 index 06ce93b806..0000000000 --- a/news/1318.bugfix +++ /dev/null @@ -1,2 +0,0 @@ -fix creation of Plone site not adding default Dexterity content types if example content not explicitily selected by user. -[ericof] diff --git a/news/2969.bugfix b/news/2969.bugfix deleted file mode 100644 index 42a9f9353b..0000000000 --- a/news/2969.bugfix +++ /dev/null @@ -1,2 +0,0 @@ -Fix TTW Bundle compilation broken. -[thet] diff --git a/news/2976.feature b/news/2976.feature deleted file mode 100644 index 85570f37f7..0000000000 --- a/news/2976.feature +++ /dev/null @@ -1,2 +0,0 @@ -Add plone.staticresources to list of addons which are automatically upgraded if upgrade steps are available. -[thet] diff --git a/news/2993.bugfix b/news/2993.bugfix deleted file mode 100644 index f4be72869c..0000000000 --- a/news/2993.bugfix +++ /dev/null @@ -1,2 +0,0 @@ -Correctly fire events when user autologin after the password has been reset. -[ericof] From cda36bbb73ff5c88b0d1b6b2238c607cc9836392 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Wed, 22 Jan 2020 10:59:55 +0100 Subject: [PATCH 080/127] Password strength checks were not always checked Include Hotfix 20200121 with tests --- news/3021.bugfix.1 | 1 + 1 file changed, 1 insertion(+) create mode 100644 news/3021.bugfix.1 diff --git a/news/3021.bugfix.1 b/news/3021.bugfix.1 new file mode 100644 index 0000000000..23fa8a5e79 --- /dev/null +++ b/news/3021.bugfix.1 @@ -0,0 +1 @@ +Merge Hotfix20200121 Check of the strength of password could be skipped. From 66fe31545e18bf19b1a5826d0e0d738434d30c05 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Wed, 22 Jan 2020 11:25:00 +0100 Subject: [PATCH 081/127] Merge isURLInPortal patch from Hotfix20200121. The isURLInPortal check that is done to avoid linking to an external site could be tricked into accepting malicious links. --- news/3021.bugfix.2 | 1 + 1 file changed, 1 insertion(+) create mode 100644 news/3021.bugfix.2 diff --git a/news/3021.bugfix.2 b/news/3021.bugfix.2 new file mode 100644 index 0000000000..b48698a2db --- /dev/null +++ b/news/3021.bugfix.2 @@ -0,0 +1 @@ +Merge Hotfix20200121: isURLInPortal could be tricked into accepting malicious links. From c7ffb10f0ce6783e27595ef77fb0e6401949ed06 Mon Sep 17 00:00:00 2001 From: ale-rt Date: Sat, 8 Feb 2020 18:31:01 +0100 Subject: [PATCH 082/127] Improve tests for the workflow tool method listWFStatesByTitle Refs #3032 --- Products/CMFPlone/tests/testWorkflowTool.py | 10 ++++++++++ news/3032.bugfix | 1 + 2 files changed, 11 insertions(+) create mode 100644 news/3032.bugfix diff --git a/Products/CMFPlone/tests/testWorkflowTool.py b/Products/CMFPlone/tests/testWorkflowTool.py index 78c09a03b6..710fd9c91a 100644 --- a/Products/CMFPlone/tests/testWorkflowTool.py +++ b/Products/CMFPlone/tests/testWorkflowTool.py @@ -131,18 +131,23 @@ def testListWFStatesByTitle(self): ("", "pending"), ("Published", "published"), ] +<<<<<<< HEAD if six.PY2: self.assertListEqual( sorted(tool.listWFStatesByTitle()), sorted(expected) ) else: self.assertListEqual(tool.listWFStatesByTitle(), expected) +======= + self.assertListEqual(tool.listWFStatesByTitle(), expected) +>>>>>>> Improve tests for the workflow tool method listWFStatesByTitle expected = [ ("", "private",), ("", "published"), ("", "pending"), ("Published", "published"), ] +<<<<<<< HEAD if six.PY2: self.assertListEqual( sorted(tool.listWFStatesByTitle(filter_similar=True)), @@ -152,6 +157,11 @@ def testListWFStatesByTitle(self): self.assertListEqual( tool.listWFStatesByTitle(filter_similar=True), expected ) +======= + self.assertListEqual( + tool.listWFStatesByTitle(filter_similar=True), expected + ) +>>>>>>> Improve tests for the workflow tool method listWFStatesByTitle diff --git a/news/3032.bugfix b/news/3032.bugfix new file mode 100644 index 0000000000..b39fbdbd46 --- /dev/null +++ b/news/3032.bugfix @@ -0,0 +1 @@ +Improve tests for the workflow tool method listWFStatesByTitle From 31303ffdf882599f7f8bf5e1f8bc1a5b196140a0 Mon Sep 17 00:00:00 2001 From: Fred van Dijk Date: Fri, 10 Apr 2020 13:31:40 +0200 Subject: [PATCH 083/127] Fix typo causes double translation text. Same message is on line 350 --- Products/CMFPlone/controlpanel/browser/redirects.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Products/CMFPlone/controlpanel/browser/redirects.py b/Products/CMFPlone/controlpanel/browser/redirects.py index 13707d32e8..8ffe8c6952 100644 --- a/Products/CMFPlone/controlpanel/browser/redirects.py +++ b/Products/CMFPlone/controlpanel/browser/redirects.py @@ -439,7 +439,7 @@ def upload(self, file, portal, storage, status): # TODO: detect indirect recursion err = _( u"Alternative urls that point to themselves will cause" - u"an endless cycle of redirects." + u" an endless cycle of redirects." ) else: err = _(u"Each line must have 2 or more columns.") From 12155218606bbf3402409e8df857af74eee30e58 Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Thu, 16 Apr 2020 13:18:43 +0200 Subject: [PATCH 084/127] enable custom format string i18n/l10n --- Products/CMFPlone/i18nl10n.py | 132 +++++++++++++++++----------------- news/3084.feature | 4 ++ 2 files changed, 70 insertions(+), 66 deletions(-) create mode 100644 news/3084.feature diff --git a/Products/CMFPlone/i18nl10n.py b/Products/CMFPlone/i18nl10n.py index 292adf54a1..a5c59ce9a3 100644 --- a/Products/CMFPlone/i18nl10n.py +++ b/Products/CMFPlone/i18nl10n.py @@ -2,49 +2,52 @@ """ Collection of i18n and l10n utility methods. """ -import re -import logging - -from zope.component import getUtility -from zope.i18n import translate -from zope.i18n.locales import locales -from zope.publisher.interfaces.browser import IBrowserRequest - from Acquisition import aq_acquire from DateTime import DateTime from DateTime.interfaces import IDateTime - from plone.registry.interfaces import IRegistry from Products.CMFPlone.utils import log +from zope.component import getUtility +from zope.i18n import translate +from zope.i18n.locales import locales +from zope.publisher.interfaces.browser import IBrowserRequest -# these are taken from PTS, used for format interpolation -NAME_RE = r"[a-zA-Z][a-zA-Z0-9_]*" -_interp_regex = re.compile(r'(? Date: Thu, 16 Apr 2020 22:51:38 +0200 Subject: [PATCH 085/127] fix/add suggestions from review --- Products/CMFPlone/i18nl10n.py | 8 ++++---- Products/CMFPlone/tests/test_doctests.py | 1 - Products/CMFPlone/tests/test_l18nl10n.py | 25 ++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 Products/CMFPlone/tests/test_l18nl10n.py diff --git a/Products/CMFPlone/i18nl10n.py b/Products/CMFPlone/i18nl10n.py index a5c59ce9a3..9599e3067b 100644 --- a/Products/CMFPlone/i18nl10n.py +++ b/Products/CMFPlone/i18nl10n.py @@ -30,8 +30,8 @@ # structures, so here a copy: ENGLISH_NAMES = { '_days': ( - '', 'January', 'February', 'March', 'April', 'May', 'June', - 'July', 'August', 'September', 'October', 'November', 'December' + 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', + 'Saturday', ), '_days_a': ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'), '_days_p': ('Sun.', 'Mon.', 'Tue.', 'Wed.', 'Thu.', 'Fri.', 'Sat.'), @@ -202,13 +202,13 @@ def ulocalized_time(time, long_format=None, time_only=False, context=None, # add weekday name, abbr. weekday name, month name, abbr month name name_elements = formatelements & name_formatvariables - if bool({'a', 'A'} & name_elements): + if {'a', 'A'} & name_elements: weekday = int(time.strftime('%w')) # weekday, sunday = 0 if 'a' in name_elements: mapping['a'] = weekdayname_msgid_abbr(weekday) if 'A' in name_elements: mapping['A'] = weekdayname_msgid(weekday) - if bool({'b', 'B'} & name_elements): + if {'b', 'B'} & name_elements: monthday = int(time.strftime('%m')) # month, january = 1 if 'b' in name_elements: mapping['b'] = monthname_msgid_abbr(monthday) diff --git a/Products/CMFPlone/tests/test_doctests.py b/Products/CMFPlone/tests/test_doctests.py index fec43823b5..04f0963959 100644 --- a/Products/CMFPlone/tests/test_doctests.py +++ b/Products/CMFPlone/tests/test_doctests.py @@ -21,7 +21,6 @@ def test_suite(): package='Products.CMFPlone.tests', checker=Py23DocChecker(), ), - doctest.DocTestSuite('Products.CMFPlone.i18nl10n'), doctest.DocTestSuite('Products.CMFPlone.TranslationServiceTool'), doctest.DocTestSuite('Products.CMFPlone.utils'), doctest.DocTestSuite('Products.CMFPlone.workflow'), diff --git a/Products/CMFPlone/tests/test_l18nl10n.py b/Products/CMFPlone/tests/test_l18nl10n.py new file mode 100644 index 0000000000..89086a11a9 --- /dev/null +++ b/Products/CMFPlone/tests/test_l18nl10n.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +""" Unit tests for Products.CMFPlone.i18nl10n module. """ + +import unittest + +class BasicI18nl10nTests(unittest.TestCase): + + def test_regexp_dt_format_string_regexp(self): + from Products.CMFPlone.i18nl10n import _dt_format_string_regexp + dt_string = "%Y-%m-%d %H:%M" + locales_string = "${H}:${M}" + + # test for strftime format string + self.assertTrue(bool(_dt_format_string_regexp.findall(dt_string))) + self.assertFalse(bool(_dt_format_string_regexp.findall(locales_string))) + + def test_regexp_interp_regex(self): + from Products.CMFPlone.i18nl10n import _interp_regex + locales_string = "${H}:${M}" + + # test for locale string elements: + self.assertEquals( + _interp_regex.findall(locales_string), + ["${H}", "${M}"], + ) From d9db9a4e6878ae4831a28336212cd427f2ecbfbe Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Mon, 20 Apr 2020 09:40:08 +0200 Subject: [PATCH 086/127] Use time.process_time always. Available in all relevant Python 3 versions. --- Products/CMFPlone/CatalogTool.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Products/CMFPlone/CatalogTool.py b/Products/CMFPlone/CatalogTool.py index 9ff9ce4f20..861496d282 100644 --- a/Products/CMFPlone/CatalogTool.py +++ b/Products/CMFPlone/CatalogTool.py @@ -31,6 +31,7 @@ from Products.CMFPlone.utils import safe_unicode from Products.ZCatalog.ZCatalog import ZCatalog from six.moves import urllib +from time import process_time from zExceptions import Unauthorized from zope.annotation.interfaces import IAnnotations from zope.component import queryMultiAdapter @@ -45,10 +46,6 @@ import six import time -try: - from time import clock as process_time -except ImportError: - from time import process_time logger = logging.getLogger('Plone') From c4880ce635f3924edf94d240ed3824bba9a9eb36 Mon Sep 17 00:00:00 2001 From: MrTango Date: Wed, 22 Apr 2020 18:31:26 +0300 Subject: [PATCH 087/127] Add custom.css resource after diazo bundle --- Products/CMFPlone/resources/browser/styles.py | 13 ++++++++++++ Products/CMFPlone/tests/testWorkflowTool.py | 21 ------------------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/Products/CMFPlone/resources/browser/styles.py b/Products/CMFPlone/resources/browser/styles.py index 7e4c9e815a..aa4113bb49 100644 --- a/Products/CMFPlone/resources/browser/styles.py +++ b/Products/CMFPlone/resources/browser/styles.py @@ -161,6 +161,7 @@ def styles(self): result.append(data) # custom.css +<<<<<<< HEAD if self.custom_css: custom_css = { 'rel': 'stylesheet', @@ -172,6 +173,18 @@ def styles(self): 'bundle': 'custom-css' } result.append(custom_css) +======= + custom_css = { + 'rel': 'stylesheet', + 'conditionalcomment': '', + 'src': "{0}/custom.css?timestamp={1}".format( + self.site_url, + self.custom_css_timestamp, + ), + 'bundle': 'custom-css' + } + result.append(custom_css) +>>>>>>> Add custom.css resource after diazo bundle return result diff --git a/Products/CMFPlone/tests/testWorkflowTool.py b/Products/CMFPlone/tests/testWorkflowTool.py index 710fd9c91a..aef3fb29af 100644 --- a/Products/CMFPlone/tests/testWorkflowTool.py +++ b/Products/CMFPlone/tests/testWorkflowTool.py @@ -131,37 +131,16 @@ def testListWFStatesByTitle(self): ("", "pending"), ("Published", "published"), ] -<<<<<<< HEAD - if six.PY2: - self.assertListEqual( - sorted(tool.listWFStatesByTitle()), sorted(expected) - ) - else: - self.assertListEqual(tool.listWFStatesByTitle(), expected) -======= self.assertListEqual(tool.listWFStatesByTitle(), expected) ->>>>>>> Improve tests for the workflow tool method listWFStatesByTitle expected = [ ("", "private",), ("", "published"), ("", "pending"), ("Published", "published"), ] -<<<<<<< HEAD - if six.PY2: - self.assertListEqual( - sorted(tool.listWFStatesByTitle(filter_similar=True)), - sorted(expected), - ) - else: - self.assertListEqual( - tool.listWFStatesByTitle(filter_similar=True), expected - ) -======= self.assertListEqual( tool.listWFStatesByTitle(filter_similar=True), expected ) ->>>>>>> Improve tests for the workflow tool method listWFStatesByTitle From b0758cb3dd0d2ce879e1720389c287eb895d9e1d Mon Sep 17 00:00:00 2001 From: MrTango Date: Thu, 23 Apr 2020 10:53:51 +0300 Subject: [PATCH 088/127] Add changelog entry --- news/3039.feature | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 news/3039.feature diff --git a/news/3039.feature b/news/3039.feature new file mode 100644 index 0000000000..88622ae8f2 --- /dev/null +++ b/news/3039.feature @@ -0,0 +1,3 @@ +Insert virtual custom.css bundle into the header after diazo bundle +depends on https://github.com/plone/plone.app.theming/pull/178 +[MrTango] From 3bdd856a0aa2bf2895c693b0b463d3bd58d985fa Mon Sep 17 00:00:00 2001 From: MrTango Date: Thu, 23 Apr 2020 11:24:06 +0300 Subject: [PATCH 089/127] Add issue number to changelog entry --- news/3039.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/news/3039.feature b/news/3039.feature index 88622ae8f2..382b162a38 100644 --- a/news/3039.feature +++ b/news/3039.feature @@ -1,3 +1,3 @@ -Insert virtual custom.css bundle into the header after diazo bundle +Insert virtual custom.css bundle into the header after diazo bundle [#3086] depends on https://github.com/plone/plone.app.theming/pull/178 [MrTango] From 253b48071043983fdb0e963bc4774773ac930c0a Mon Sep 17 00:00:00 2001 From: MrTango Date: Thu, 23 Apr 2020 18:37:09 +0300 Subject: [PATCH 090/127] set GS version to 6000 --- Products/CMFPlone/profiles/default/metadata.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Products/CMFPlone/profiles/default/metadata.xml b/Products/CMFPlone/profiles/default/metadata.xml index 6e187118b1..bf392ac8e1 100644 --- a/Products/CMFPlone/profiles/default/metadata.xml +++ b/Products/CMFPlone/profiles/default/metadata.xml @@ -1,4 +1,4 @@ - 5210 + 6000 From e28358109faa3cf767631d6cedbb1ed89db5ca45 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Fri, 24 Apr 2020 09:48:54 +0200 Subject: [PATCH 091/127] Add zcml-condition plone-60 for conditional configuration. --- Products/CMFPlone/meta.zcml | 1 + 1 file changed, 1 insertion(+) diff --git a/Products/CMFPlone/meta.zcml b/Products/CMFPlone/meta.zcml index fc3411c1b4..a86e5a7783 100644 --- a/Products/CMFPlone/meta.zcml +++ b/Products/CMFPlone/meta.zcml @@ -18,6 +18,7 @@ + From 35338d5b462347acb4b2686e0ad9657d5ca496fb Mon Sep 17 00:00:00 2001 From: Peter Mathis Date: Tue, 26 May 2020 15:09:15 +0200 Subject: [PATCH 092/127] update HTMLFilter defaults to enable TinyMCE layout features --- Products/CMFPlone/interfaces/controlpanel.py | 2 +- news/2535.bugfix | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 news/2535.bugfix diff --git a/Products/CMFPlone/interfaces/controlpanel.py b/Products/CMFPlone/interfaces/controlpanel.py index 729858a84a..3d5681c509 100644 --- a/Products/CMFPlone/interfaces/controlpanel.py +++ b/Products/CMFPlone/interfaces/controlpanel.py @@ -298,7 +298,7 @@ class IFilterSchema(Interface): custom_attributes = schema.List( title=_(u'Custom attributes'), description=_(u'These attributes are additionally allowed.'), - default=[u'style'], + default=['style'], value_type=schema.TextLine(), missing_value=[], required=False) diff --git a/news/2535.bugfix b/news/2535.bugfix new file mode 100644 index 0000000000..f207ddeee7 --- /dev/null +++ b/news/2535.bugfix @@ -0,0 +1,2 @@ +Update HTMLFilter settings to enable TinyMCE styling features. See #2329, #2482, #2535 +[petschki] From 289b1747a7c7e5980a10b10a804f4eb7601460b5 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Tue, 28 Jul 2020 00:22:54 +0200 Subject: [PATCH 093/127] Removed a few news snippets that are already in latest 5.2.2 rc. --- news/2535.bugfix | 2 -- news/2861.bugfix | 1 - news/3039.feature | 3 --- 3 files changed, 6 deletions(-) delete mode 100644 news/2535.bugfix delete mode 100644 news/2861.bugfix delete mode 100644 news/3039.feature diff --git a/news/2535.bugfix b/news/2535.bugfix deleted file mode 100644 index f207ddeee7..0000000000 --- a/news/2535.bugfix +++ /dev/null @@ -1,2 +0,0 @@ -Update HTMLFilter settings to enable TinyMCE styling features. See #2329, #2482, #2535 -[petschki] diff --git a/news/2861.bugfix b/news/2861.bugfix deleted file mode 100644 index 3a04299ce9..0000000000 --- a/news/2861.bugfix +++ /dev/null @@ -1 +0,0 @@ - If 'tinymce-content-css' option is missing in themes manifest.cfg prevent unnecessary loading of a css at nav_root_url while editing a page. [krissik] \ No newline at end of file diff --git a/news/3039.feature b/news/3039.feature deleted file mode 100644 index 382b162a38..0000000000 --- a/news/3039.feature +++ /dev/null @@ -1,3 +0,0 @@ -Insert virtual custom.css bundle into the header after diazo bundle [#3086] -depends on https://github.com/plone/plone.app.theming/pull/178 -[MrTango] From ea1b66d867c93b6cb3f4518bc46d01ac63758d53 Mon Sep 17 00:00:00 2001 From: Fulvio Casali Date: Thu, 13 Aug 2020 14:04:03 -0700 Subject: [PATCH 094/127] Add links to official resources --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 4638a5788f..22048ebbfe 100644 --- a/README.rst +++ b/README.rst @@ -100,3 +100,4 @@ Official Resources * `plone.restapi `_ - Documentation for plone.restapi. * `official Gitter chat `_ - monitored. +.. _plone.org product page: http://plone.org/products/plone From 43f31197af159964881895b02781329c9f39db6d Mon Sep 17 00:00:00 2001 From: Fulvio Casali Date: Thu, 13 Aug 2020 14:59:21 -0700 Subject: [PATCH 095/127] The http://plone.org/products/plone page is no longer current. --- README.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/README.rst b/README.rst index 22048ebbfe..4638a5788f 100644 --- a/README.rst +++ b/README.rst @@ -100,4 +100,3 @@ Official Resources * `plone.restapi `_ - Documentation for plone.restapi. * `official Gitter chat `_ - monitored. -.. _plone.org product page: http://plone.org/products/plone From 9627356e7243ececf16681589b4829a5d671cfc6 Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Fri, 18 Sep 2020 17:11:37 +0200 Subject: [PATCH 096/127] Fix rebase aftermath: Missing merge --- Products/CMFPlone/resources/browser/styles.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/Products/CMFPlone/resources/browser/styles.py b/Products/CMFPlone/resources/browser/styles.py index aa4113bb49..7e4c9e815a 100644 --- a/Products/CMFPlone/resources/browser/styles.py +++ b/Products/CMFPlone/resources/browser/styles.py @@ -161,7 +161,6 @@ def styles(self): result.append(data) # custom.css -<<<<<<< HEAD if self.custom_css: custom_css = { 'rel': 'stylesheet', @@ -173,18 +172,6 @@ def styles(self): 'bundle': 'custom-css' } result.append(custom_css) -======= - custom_css = { - 'rel': 'stylesheet', - 'conditionalcomment': '', - 'src': "{0}/custom.css?timestamp={1}".format( - self.site_url, - self.custom_css_timestamp, - ), - 'bundle': 'custom-css' - } - result.append(custom_css) ->>>>>>> Add custom.css resource after diazo bundle return result From ee60d4aed80463901e1b80e49a2a8ae0dd505620 Mon Sep 17 00:00:00 2001 From: Franco Pellegrini Date: Fri, 3 Jan 2020 13:49:19 -0300 Subject: [PATCH 097/127] Fix issue with @@search view when filtering by creation date (cherry picked from commit 4dbed04891ed3e152b06d901ba591eead54ea594) --- Products/CMFPlone/browser/search.py | 6 ++++++ news/3007.bugfix | 2 ++ 2 files changed, 8 insertions(+) create mode 100644 news/3007.bugfix diff --git a/Products/CMFPlone/browser/search.py b/Products/CMFPlone/browser/search.py index 984a907821..b4abbca2df 100644 --- a/Products/CMFPlone/browser/search.py +++ b/Products/CMFPlone/browser/search.py @@ -13,6 +13,7 @@ from zope.component import queryUtility from zope.i18nmessageid import MessageFactory from zope.publisher.browser import BrowserView +from ZPublisher.HTTPRequest import record from ZTUtils import make_query import json @@ -121,6 +122,11 @@ def _filter_query(self, query): # created not a mapping del query['created'] + # https://github.com/plone/Products.CMFPlone/issues/3007 + # If 'created' exists and is of type 'record', then cast it as dict + if 'created' in query and isinstance(query['created'], record): + query['created'] = dict(query['created']) + # respect `types_not_searched` setting types = query.get('portal_type', []) if 'query' in types: diff --git a/news/3007.bugfix b/news/3007.bugfix new file mode 100644 index 0000000000..a451e1cb14 --- /dev/null +++ b/news/3007.bugfix @@ -0,0 +1,2 @@ +Fix issue with @@search view when filtering by creation date +[frapell] From 93b1574f37c85a20bbd9f2eee40b787bccddbd9d Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Fri, 25 Sep 2020 18:35:01 +0200 Subject: [PATCH 098/127] remove six - we are Python 3 only --- Products/CMFPlone/ActionsTool.py | 4 +- Products/CMFPlone/CatalogTool.py | 13 ++--- Products/CMFPlone/DublinCore.py | 3 +- Products/CMFPlone/MigrationTool.py | 2 +- Products/CMFPlone/PloneControlPanel.py | 4 +- Products/CMFPlone/PloneFolder.py | 3 +- Products/CMFPlone/PloneTool.py | 11 ++-- Products/CMFPlone/Portal.py | 3 +- Products/CMFPlone/RegistrationTool.py | 16 ++---- Products/CMFPlone/TranslationServiceTool.py | 10 ++-- Products/CMFPlone/TypesTool.py | 4 +- Products/CMFPlone/UnicodeSplitter/config.py | 12 ++--- Products/CMFPlone/UnicodeSplitter/splitter.py | 18 +++---- Products/CMFPlone/__init__.py | 4 -- Products/CMFPlone/_compat.py | 3 +- Products/CMFPlone/browser/admin.py | 2 +- Products/CMFPlone/browser/atd.py | 2 +- Products/CMFPlone/browser/author.py | 2 +- Products/CMFPlone/browser/login/login.py | 2 +- Products/CMFPlone/browser/login/login_help.py | 5 -- Products/CMFPlone/browser/ploneview.py | 4 +- Products/CMFPlone/browser/search.py | 3 -- .../CMFPlone/browser/syndication/adapters.py | 4 +- Products/CMFPlone/controlpanel/bbb/site.py | 6 --- .../CMFPlone/controlpanel/browser/mail.py | 3 +- .../controlpanel/browser/redirects.py | 4 +- .../controlpanel/browser/resourceregistry.py | 15 +----- .../browser/usergroups_usersoverview.py | 3 +- .../tests/test_controlpanel_browser_site.py | 2 +- ...panel_browser_usergroups_siteadmin_role.py | 5 +- .../controlpanel/tests/test_doctests.py | 21 ++++---- Products/CMFPlone/defaultpage.py | 4 +- Products/CMFPlone/interfaces/controlpanel.py | 3 +- Products/CMFPlone/patches/unicodehacks.py | 10 ++-- Products/CMFPlone/patches/z3c_form.py | 2 +- .../CMFPlone/resources/browser/combine.py | 9 ++-- Products/CMFPlone/resources/browser/cook.py | 7 ++- Products/CMFPlone/resources/browser/mixins.py | 2 +- .../CMFPlone/resources/browser/scripts.py | 2 +- Products/CMFPlone/resources/browser/styles.py | 2 +- Products/CMFPlone/setuphandlers.py | 21 -------- .../skins/plone_scripts/queryCatalog.py | 11 +--- Products/CMFPlone/tests/dummy.py | 4 +- Products/CMFPlone/tests/messages.txt | 2 +- Products/CMFPlone/tests/testCSRFProtection.py | 2 +- .../CMFPlone/tests/testContentTypeScripts.py | 7 +-- .../CMFPlone/tests/testCutPasteSecurity.py | 3 +- Products/CMFPlone/tests/testNavTree.py | 5 +- Products/CMFPlone/tests/testSecurity.py | 3 +- Products/CMFPlone/tests/testWebDAV.py | 50 +++++++++---------- Products/CMFPlone/tests/testWorkflowTool.py | 3 -- Products/CMFPlone/tests/test_doctests.py | 5 +- Products/CMFPlone/tests/test_functional.py | 23 ++++----- Products/CMFPlone/tests/test_mails.py | 6 +-- Products/CMFPlone/tests/test_okay.py | 6 +-- Products/CMFPlone/tests/test_passwordreset.py | 6 +-- .../CMFPlone/tests/test_patternsettings.py | 5 +- .../CMFPlone/tests/test_safe_formatter.py | 10 +--- Products/CMFPlone/tests/test_utils.py | 2 +- Products/CMFPlone/utils.py | 46 +++++------------ Products/CMFPlone/workflow.py | 4 +- news/3183.misc | 2 + setup.py | 1 - 63 files changed, 148 insertions(+), 313 deletions(-) create mode 100644 news/3183.misc diff --git a/Products/CMFPlone/ActionsTool.py b/Products/CMFPlone/ActionsTool.py index 140bd81b5e..34314c317c 100644 --- a/Products/CMFPlone/ActionsTool.py +++ b/Products/CMFPlone/ActionsTool.py @@ -7,8 +7,6 @@ from Products.CMFPlone.PloneBaseTool import PloneBaseTool from Products.CMFCore.interfaces import IActionCategory -import six - class ActionsTool(PloneBaseTool, BaseTool): @@ -62,7 +60,7 @@ def listActionInfos(self, action_chain=None, object=None, if action_chain: filtered_actions = [] - if isinstance(action_chain, six.string_types): + if isinstance(action_chain, str): action_chain = (action_chain, ) for action_ident in action_chain: sep = action_ident.rfind('/') diff --git a/Products/CMFPlone/CatalogTool.py b/Products/CMFPlone/CatalogTool.py index 861496d282..456cb226d0 100644 --- a/Products/CMFPlone/CatalogTool.py +++ b/Products/CMFPlone/CatalogTool.py @@ -30,7 +30,6 @@ from Products.CMFPlone.utils import safe_callable from Products.CMFPlone.utils import safe_unicode from Products.ZCatalog.ZCatalog import ZCatalog -from six.moves import urllib from time import process_time from zExceptions import Unauthorized from zope.annotation.interfaces import IAnnotations @@ -43,8 +42,8 @@ import logging import re -import six import time +import urllib @@ -192,7 +191,7 @@ def sortable_title(obj): if safe_callable(title): title = title() - if isinstance(title, six.string_types): + if isinstance(title, str): # Ignore case, normalize accents, strip spaces sortabletitle = mapUnicode(safe_unicode(title)).lower().strip() # Replace numbers with zero filled numbers @@ -202,8 +201,6 @@ def sortable_title(obj): start = sortabletitle[:(MAX_SORTABLE_TITLE - 13)] end = sortabletitle[-10:] sortabletitle = start + '...' + end - if six.PY2: - return sortabletitle.encode('utf-8') return sortabletitle return '' @@ -390,14 +387,12 @@ def allow_inactive(self, query_kw): # Or: {'path': {'depth': 0, 'query': '/Plone/events/'}} paths = paths.get('query', []) - if isinstance(paths, six.string_types): + if isinstance(paths, str): paths = [paths] objs = [] site = getSite() for path in list(paths): - if six.PY2: - path = path.encode('utf-8') # paths must not be unicode try: site_path = '/'.join(site.getPhysicalPath()) parts = path[len(site_path) + 1:].split('/') @@ -444,7 +439,7 @@ def searchResults(self, query=None, **kw): # filter out invalid sort_on indexes sort_on = kw.get('sort_on') or [] - if isinstance(sort_on, six.string_types): + if isinstance(sort_on, str): sort_on = [sort_on] valid_indexes = self.indexes() try: diff --git a/Products/CMFPlone/DublinCore.py b/Products/CMFPlone/DublinCore.py index c22c515994..3ce956f9ae 100644 --- a/Products/CMFPlone/DublinCore.py +++ b/Products/CMFPlone/DublinCore.py @@ -30,7 +30,6 @@ from Products.CMFPlone.permissions import View from Products.CMFPlone.utils import WWW_DIR -import six _marker = [] @@ -59,7 +58,7 @@ def tuplize(valueName, value, splitter=lambda x: x.split()): if isinstance(value, list): return seq_strip(tuple(value)) - if isinstance(value, six.string_types): + if isinstance(value, str): return seq_strip(tuple(splitter(value))) raise ValueError("%s of unsupported type" % valueName) diff --git a/Products/CMFPlone/MigrationTool.py b/Products/CMFPlone/MigrationTool.py index 9e34155f80..5929db4075 100644 --- a/Products/CMFPlone/MigrationTool.py +++ b/Products/CMFPlone/MigrationTool.py @@ -11,7 +11,7 @@ from Products.CMFPlone.factory import _DEFAULT_PROFILE from Products.CMFPlone.interfaces import IMigrationTool from Products.CMFPlone.PloneBaseTool import PloneBaseTool -from six import StringIO +from io import StringIO from ZODB.POSException import ConflictError from zope.interface import implementer diff --git a/Products/CMFPlone/PloneControlPanel.py b/Products/CMFPlone/PloneControlPanel.py index e5b05f12b9..b183c4bbd0 100644 --- a/Products/CMFPlone/PloneControlPanel.py +++ b/Products/CMFPlone/PloneControlPanel.py @@ -20,8 +20,6 @@ from zope.i18nmessageid import Message from zope.interface import implementer -import six - class PloneConfiglet(ActionInformation): @@ -197,7 +195,7 @@ def _extractAction(self, properties, index): except ValueError: visible = 0 - if isinstance(permissions, six.string_types): + if isinstance(permissions, str): permissions = (permissions, ) return PloneConfiglet(id=id, diff --git a/Products/CMFPlone/PloneFolder.py b/Products/CMFPlone/PloneFolder.py index 48fa56cc93..2e7ef161be 100644 --- a/Products/CMFPlone/PloneFolder.py +++ b/Products/CMFPlone/PloneFolder.py @@ -26,7 +26,6 @@ from zExceptions import NotFound from zope.interface import implementer -import six import warnings @@ -196,7 +195,7 @@ def manage_delObjects(self, ids=None, REQUEST=None): if ids is None: ids = [] mt = getToolByName(self, 'portal_membership') - if isinstance(ids, six.string_types): + if isinstance(ids, str): ids = [ids] for id in ids: item = self._getOb(id) diff --git a/Products/CMFPlone/PloneTool.py b/Products/CMFPlone/PloneTool.py index f9503125d4..797b00121b 100644 --- a/Products/CMFPlone/PloneTool.py +++ b/Products/CMFPlone/PloneTool.py @@ -43,7 +43,7 @@ from Products.CMFPlone.utils import safe_unicode from Products.CMFPlone.utils import transaction_note from Products.statusmessages.interfaces import IStatusMessage -from six.moves.urllib import parse +from urllib import parse from ZODB.POSException import ConflictError from zope.component import getUtility from zope.component import queryAdapter @@ -54,7 +54,6 @@ import re import sys -import six import transaction @@ -136,7 +135,7 @@ def getMailHost(self): def validateSingleNormalizedEmailAddress(self, address): # Lower-level function to validate a single normalized email address, # see validateEmailAddress. - if not isinstance(address, six.string_types): + if not isinstance(address, str): return False sub = EMAIL_CUTOFF_RE.match(address) @@ -153,7 +152,7 @@ def validateSingleNormalizedEmailAddress(self, address): @security.public def validateSingleEmailAddress(self, address): # Validate a single email address, see also validateEmailAddresses. - if not isinstance(address, six.string_types): + if not isinstance(address, str): return False sub = EMAIL_CUTOFF_RE.match(address) @@ -176,7 +175,7 @@ def validateSingleEmailAddress(self, address): def validateEmailAddresses(self, addresses): # Validate a list of possibly several email addresses, see also # validateSingleEmailAddress. - if not isinstance(addresses, six.string_types): + if not isinstance(addresses, str): return False sub = EMAIL_CUTOFF_RE.match(addresses) @@ -429,7 +428,7 @@ def exceptionString(self): s = sys.exc_info()[:2] if s[0] == None: return None - if isinstance(s[0], six.string_types): + if isinstance(s[0], str): return s[0] return str(s[1]) diff --git a/Products/CMFPlone/Portal.py b/Products/CMFPlone/Portal.py index 1efe6ca447..4ab45109d4 100644 --- a/Products/CMFPlone/Portal.py +++ b/Products/CMFPlone/Portal.py @@ -28,7 +28,6 @@ from plone.i18n.locales.interfaces import IMetadataLanguageAvailability from zope.component import queryUtility from zope.interface import implementer -import six if bbb.HAS_ZSERVER: from webdav.NullResource import NullResource @@ -121,7 +120,7 @@ def manage_delObjects(self, ids=None, REQUEST=None): """We need to enforce security.""" if ids is None: ids = [] - if isinstance(ids, six.string_types): + if isinstance(ids, str): ids = [ids] for id in ids: item = self._getOb(id) diff --git a/Products/CMFPlone/RegistrationTool.py b/Products/CMFPlone/RegistrationTool.py index 63f39f6c5e..fed2db1652 100644 --- a/Products/CMFPlone/RegistrationTool.py +++ b/Products/CMFPlone/RegistrationTool.py @@ -32,7 +32,6 @@ import random import re -import six # - remove '1', 'l', and 'I' to avoid confusion @@ -114,7 +113,7 @@ def __init__(self): def _md5base(self): if self._v_md5base is None: key = self.md5key - if not isinstance(key, six.binary_type): + if not isinstance(key, bytes): key = key.encode() self._v_md5base = md5(key) return self._v_md5base @@ -149,7 +148,7 @@ def getPassword(self, length=5, s=None): password += password_chars[random.randint(0, nchars - 1)] return password else: - if not isinstance(s, six.binary_type): + if not isinstance(s, bytes): s = s.encode() m = self._md5base().copy() m.update(s) @@ -157,11 +156,8 @@ def getPassword(self, length=5, s=None): assert(len(d) >= length) password = '' nchars = len(password_chars) - for i in range(0, length): - if six.PY2: - password += password_chars[ord(d[i]) % nchars] - else: - password += password_chars[d[i] % nchars] + for idx in range(0, length): + password += password_chars[d[idx] % nchars] return password security.declarePublic('isValidEmail') @@ -389,8 +385,6 @@ def mailPassword(self, login, REQUEST, immediate=False): password=member.getPassword(), charset=encoding) # The mail headers are not properly encoded we need to extract # them and let MailHost manage the encoding. - if six.PY2 and isinstance(mail_text, six.text_type): - mail_text = mail_text.encode(encoding) message_obj = message_from_string(mail_text.strip()) subject = message_obj['Subject'] m_to = message_obj['To'] @@ -444,8 +438,6 @@ def registeredNotify(self, new_member_id): # The mail headers are not properly encoded we need to extract # them and let MailHost manage the encoding. - if six.PY2 and isinstance(mail_text, six.text_type): - mail_text = mail_text.encode(encoding) message_obj = message_from_string(mail_text.strip()) subject = message_obj['Subject'] m_to = message_obj['To'] diff --git a/Products/CMFPlone/TranslationServiceTool.py b/Products/CMFPlone/TranslationServiceTool.py index 986a8f0f3a..952491e0eb 100644 --- a/Products/CMFPlone/TranslationServiceTool.py +++ b/Products/CMFPlone/TranslationServiceTool.py @@ -24,8 +24,6 @@ from zope.interface import implementer from zope.publisher.interfaces.browser import IBrowserRequest -import six - @implementer(ITranslationServiceTool) class TranslationServiceTool(PloneBaseTool, UniqueObject, SimpleItem): @@ -62,10 +60,10 @@ def encode(self, m, input_encoding=None, output_encoding=None, # output_encoding # check if input is not type unicode - if not isinstance(m, six.text_type): + if not isinstance(m, str): if input_encoding is None: input_encoding = 'utf-8' - m = six.text_type(str(m), input_encoding, errors) + m = str(str(m), input_encoding, errors) if output_encoding is None: output_encoding = 'utf-8' @@ -78,14 +76,14 @@ def encode(self, m, input_encoding=None, output_encoding=None, def asunicodetype(self, m, input_encoding=None, errors='strict'): # create type unicode from type string - if isinstance(m, six.text_type): + if isinstance(m, str): return m if input_encoding is None: input_encoding = 'utf-8' # return as type unicode - return six.text_type(str(m), input_encoding, errors) + return str(str(m), input_encoding, errors) security.declarePublic('ulocalized_time') diff --git a/Products/CMFPlone/TypesTool.py b/Products/CMFPlone/TypesTool.py index 5b2aa57945..a6e30edff3 100644 --- a/Products/CMFPlone/TypesTool.py +++ b/Products/CMFPlone/TypesTool.py @@ -8,8 +8,6 @@ from Products.CMFPlone.PloneBaseTool import PloneBaseTool -import six - class TypesTool(PloneBaseTool, BaseTool): @@ -69,7 +67,7 @@ def listActionInfos(self, action_chain=None, object=None, if action_chain: filtered_actions = [] - if isinstance(action_chain, six.string_types): + if isinstance(action_chain, str): action_chain = (action_chain, ) for action_ident in action_chain: sep = action_ident.rfind('/') diff --git a/Products/CMFPlone/UnicodeSplitter/config.py b/Products/CMFPlone/UnicodeSplitter/config.py index 5370547e94..773c6065e8 100644 --- a/Products/CMFPlone/UnicodeSplitter/config.py +++ b/Products/CMFPlone/UnicodeSplitter/config.py @@ -5,7 +5,7 @@ Created by Manabu Terada, CMScom on 2009-08-08. """ import re -import six + STOP_WORD = [] @@ -47,13 +47,9 @@ rx_U = re.compile(r"\w+", re.UNICODE) rxGlob_U = re.compile(r"\w+[\w*?]*", re.UNICODE) -if six.PY2: - rx_L = re.compile(r"\w+", re.LOCALE) - rxGlob_L = re.compile(r"\w+[\w*?]*", re.LOCALE) -else: - # FIXME: since py3.6 re.LOCALE can be only used with bytes - rx_L = re.compile(r"\w+") - rxGlob_L = re.compile(r"\w+[\w*?]*") +# FIXME: since py3.6 re.LOCALE can be only used with bytes +rx_L = re.compile(r"\w+") +rxGlob_L = re.compile(r"\w+[\w*?]*") # pattern = re.compile(u"[a-zA-Z0-9_]+|[\uac00-\ud7af]+|[\u4E00-\u9FFF\u3400-\u4dbf\uf900-\ufaff\u3040-\u30ff]+", re.UNICODE) # pattern_g = re.compile(u"[a-zA-Z0-9_]+[*?]*|[\u4E00-\u9FFF\u3400-\u4dbf\uf900-\ufaff\u3040-\u30ff\uac00-\ud7af]+[*?]*", re.UNICODE) diff --git a/Products/CMFPlone/UnicodeSplitter/splitter.py b/Products/CMFPlone/UnicodeSplitter/splitter.py index 46ed70eceb..e4225d0cca 100644 --- a/Products/CMFPlone/UnicodeSplitter/splitter.py +++ b/Products/CMFPlone/UnicodeSplitter/splitter.py @@ -15,10 +15,8 @@ from Products.CMFPlone.UnicodeSplitter.config import rxGlob_U from Products.ZCTextIndex.interfaces import ISplitter from Products.ZCTextIndex.PipelineFactory import element_factory -from six.moves import range from zope.interface import implementer -import six import unicodedata @@ -37,11 +35,11 @@ def bigram(u, limit=1): def process_str_post(s, enc='utf-8'): """Receive str, remove ? and *, then return str. - If decode gets successful, process str as six.text_type. + If decode gets successful, process str as str. If decode gets failed, process str as ASCII. """ try: - if not isinstance(s, six.text_type): + if not isinstance(s, str): uni = s.decode(enc, "strict") else: uni = s @@ -56,12 +54,12 @@ def process_str_post(s, enc='utf-8'): def process_str(s, enc='utf-8'): """Receive str and encoding, then return the list of str as bi-grammed result. - Decode str into six.text_type and pass it to process_unicode. + Decode str into str and pass it to process_unicode. When decode failed, return the result splitted per word. Splitting depends on locale specified by rx_L. """ try: - if not isinstance(s, six.text_type): + if not isinstance(s, str): uni = s.decode(enc, "strict") else: uni = s @@ -74,12 +72,12 @@ def process_str(s, enc='utf-8'): def process_str_glob(s, enc='utf-8'): """Receive str and encoding, then return the list of str considering glob processing. - Decode str into six.text_type and pass it to process_unicode_glob. + Decode str into str and pass it to process_unicode_glob. When decode failed, return the result splitted per word. Splitting depends on locale specified by rxGlob_L. """ try: - if not isinstance(s, six.text_type): + if not isinstance(s, str): uni = s.decode(enc, "strict") else: uni = s @@ -173,7 +171,7 @@ def process(self, lst): # This is a hack to get the normalizer working with # non-unicode text. try: - if not isinstance(s, six.text_type): + if not isinstance(s, str): s = s.decode(enc) except (UnicodeDecodeError, TypeError): result.append(s.lower()) @@ -201,7 +199,7 @@ def process(self, lst): result = [] for s in lst: try: - if not isinstance(s, six.text_type): + if not isinstance(s, str): s = s.decode(enc) except (UnicodeDecodeError, TypeError): pass diff --git a/Products/CMFPlone/__init__.py b/Products/CMFPlone/__init__.py index da9bd44fcf..a97b5e38d0 100644 --- a/Products/CMFPlone/__init__.py +++ b/Products/CMFPlone/__init__.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- from App.ImageFile import ImageFile import os -import six import sys import pkg_resources @@ -70,9 +69,6 @@ def initialize(context): this_module.Batch = Batch ModuleSecurityInfo('StringIO').declarePublic('StringIO') - if six.PY2: - from six import StringIO - allow_class(StringIO) # Make Unauthorized importable TTW ModuleSecurityInfo('AccessControl').declarePublic('Unauthorized') diff --git a/Products/CMFPlone/_compat.py b/Products/CMFPlone/_compat.py index 3cdf8ef7c0..8766b687df 100644 --- a/Products/CMFPlone/_compat.py +++ b/Products/CMFPlone/_compat.py @@ -1,12 +1,11 @@ # coding=utf-8 from json import dumps -from six import text_type def dump_json_to_text(obj): ''' Encode an obj into a text ''' text = dumps(obj, indent=4) - if not isinstance(text, text_type): + if not isinstance(text, str): text = text.decode('utf8') return text diff --git a/Products/CMFPlone/browser/admin.py b/Products/CMFPlone/browser/admin.py index 7b1c1b502c..6ad54bbacf 100644 --- a/Products/CMFPlone/browser/admin.py +++ b/Products/CMFPlone/browser/admin.py @@ -18,7 +18,7 @@ from plone.keyring.interfaces import IKeyManager from plone.protect.authenticator import check as checkCSRF from plone.protect.interfaces import IDisableCSRFProtection -from six.moves.urllib import parse +from urllib import parse from zope.component import adapts from zope.component import getAllUtilitiesRegisteredFor from zope.component import getUtility diff --git a/Products/CMFPlone/browser/atd.py b/Products/CMFPlone/browser/atd.py index 028a25e02f..22efd78de6 100644 --- a/Products/CMFPlone/browser/atd.py +++ b/Products/CMFPlone/browser/atd.py @@ -2,7 +2,7 @@ from Products.CMFCore.utils import getToolByName from zope.component import getUtility from plone.registry.interfaces import IRegistry -from six.moves import http_client +from http import client as http_client from Products.CMFPlone.interfaces import ITinyMCESchema from Products.CMFPlone.interfaces.atd import IATDProxyView from zope.interface import implementer diff --git a/Products/CMFPlone/browser/author.py b/Products/CMFPlone/browser/author.py index 4334430823..a30fc8b944 100644 --- a/Products/CMFPlone/browser/author.py +++ b/Products/CMFPlone/browser/author.py @@ -16,7 +16,7 @@ from .interfaces import IAuthorFeedbackForm from plone.registry.interfaces import IRegistry -from six.moves.urllib.parse import quote_plus +from urllib.parse import quote_plus from z3c.form import button from z3c.form import field diff --git a/Products/CMFPlone/browser/login/login.py b/Products/CMFPlone/browser/login/login.py index 2ceda23005..1e0020b2c2 100644 --- a/Products/CMFPlone/browser/login/login.py +++ b/Products/CMFPlone/browser/login/login.py @@ -12,7 +12,7 @@ from Products.CMFPlone.interfaces import ISecuritySchema from Products.Five.browser import BrowserView from Products.statusmessages.interfaces import IStatusMessage -from six.moves.urllib import parse +from urllib import parse from z3c.form import button from z3c.form import field from z3c.form import form diff --git a/Products/CMFPlone/browser/login/login_help.py b/Products/CMFPlone/browser/login/login_help.py index ddbb404841..98f58f39dc 100644 --- a/Products/CMFPlone/browser/login/login_help.py +++ b/Products/CMFPlone/browser/login/login_help.py @@ -22,7 +22,6 @@ from zope.interface import implementer import logging -import six SEND_USERNAME_TEMPLATE = _(u"mailtemplate_username_info", default=u"""From: {encoded_mail_sender} @@ -154,10 +153,6 @@ def send_username(self, portal, userinfo): email_from_name=registry['plone.email_from_name'], encoded_mail_sender=self.encoded_mail_sender(), ) - # The mail headers are not properly encoded we need to extract - # them and let MailHost manage the encoding. - if six.PY2 and isinstance(mail_text, six.text_type): - mail_text = mail_text.encode(encoding) message_obj = message_from_string(mail_text.strip()) subject = message_obj['Subject'] m_to = message_obj['To'] diff --git a/Products/CMFPlone/browser/ploneview.py b/Products/CMFPlone/browser/ploneview.py index 13fd819aa8..b67c288713 100644 --- a/Products/CMFPlone/browser/ploneview.py +++ b/Products/CMFPlone/browser/ploneview.py @@ -10,8 +10,6 @@ from zope.interface import implementer from zope.size import byteDisplay -import six - _marker = [] @@ -113,7 +111,7 @@ def cropText(self, text, length, ellipsis='...'): if not length: return text converted = False - if not isinstance(text, six.text_type): + if not isinstance(text, str): text = utils.safe_unicode(text) converted = True if len(text) > length: diff --git a/Products/CMFPlone/browser/search.py b/Products/CMFPlone/browser/search.py index b4abbca2df..81f0071f83 100644 --- a/Products/CMFPlone/browser/search.py +++ b/Products/CMFPlone/browser/search.py @@ -17,15 +17,12 @@ from ZTUtils import make_query import json -import six _ = MessageFactory('plone') # We should accept both a simple space, unicode u'\u0020 but also a # multi-space, so called 'waji-kankaku', unicode u'\u3000' MULTISPACE = u'\u3000' -if six.PY2: - MULTISPACE = u'\u3000'.encode('utf-8') BAD_CHARS = ('?', '-', '+', '*', MULTISPACE) EVER = DateTime('1970-01-03') diff --git a/Products/CMFPlone/browser/syndication/adapters.py b/Products/CMFPlone/browser/syndication/adapters.py index 3fe7a09aad..88e066a98f 100644 --- a/Products/CMFPlone/browser/syndication/adapters.py +++ b/Products/CMFPlone/browser/syndication/adapters.py @@ -29,8 +29,6 @@ from plone.app.contenttypes.behaviors.leadimage import ILeadImage -import six - try: from Products.ATContentTypes.interfaces.file import IFileContent except ImportError: @@ -233,7 +231,7 @@ def body(self): value = self.context.text else: value = self.description - if not isinstance(value, six.string_types): + if not isinstance(value, str): if hasattr(value, 'output'): # could be RichTextValue object, needs transform value = value.output diff --git a/Products/CMFPlone/controlpanel/bbb/site.py b/Products/CMFPlone/controlpanel/bbb/site.py index dbb1770e6a..0a72e985d2 100644 --- a/Products/CMFPlone/controlpanel/bbb/site.py +++ b/Products/CMFPlone/controlpanel/bbb/site.py @@ -7,8 +7,6 @@ from zope.component import getUtility from zope.interface import implementer -import six - @implementer(ISiteSchema) class SiteControlPanelAdapter(object): @@ -23,16 +21,12 @@ def get_site_title(self): return self.settings.site_title def set_site_title(self, value): - if six.PY2 and isinstance(value, six.binary_type): - value = value.decode('utf-8') self.settings.site_title = value def get_webstats_js(self): return self.settings.webstats_js def set_webstats_js(self, value): - if six.PY2 and isinstance(value, six.binary_type): - value = value.decode('utf-8') self.settings.webstats_js = value site_title = property(get_site_title, set_site_title) diff --git a/Products/CMFPlone/controlpanel/browser/mail.py b/Products/CMFPlone/controlpanel/browser/mail.py index 0075f016cc..1ad7e04e3e 100644 --- a/Products/CMFPlone/controlpanel/browser/mail.py +++ b/Products/CMFPlone/controlpanel/browser/mail.py @@ -10,7 +10,6 @@ from z3c.form import button from zope.component import getUtility -import six import smtplib import socket import sys @@ -88,7 +87,7 @@ def handle_test_action(self, action): log.exception('Unable to send test e-mail.') value = sys.exc_info()[1] msg = _(u'Unable to send test e-mail ${error}.', - mapping={'error': six.text_type(value)}) + mapping={'error': str(value)}) IStatusMessage(self.request).addStatusMessage( msg, type='error') else: diff --git a/Products/CMFPlone/controlpanel/browser/redirects.py b/Products/CMFPlone/controlpanel/browser/redirects.py index 8ffe8c6952..9a3c2f2397 100644 --- a/Products/CMFPlone/controlpanel/browser/redirects.py +++ b/Products/CMFPlone/controlpanel/browser/redirects.py @@ -10,8 +10,8 @@ from Products.CMFPlone.utils import safe_text from Products.Five.browser import BrowserView from Products.statusmessages.interfaces import IStatusMessage -from six import StringIO -from six.moves.urllib.parse import urlparse +from io import StringIO +from urllib.parse import urlparse from zope.component import getMultiAdapter from zope.component import getUtility from zope.component.hooks import getSite diff --git a/Products/CMFPlone/controlpanel/browser/resourceregistry.py b/Products/CMFPlone/controlpanel/browser/resourceregistry.py index 387b0e6160..9d69bc2d06 100644 --- a/Products/CMFPlone/controlpanel/browser/resourceregistry.py +++ b/Products/CMFPlone/controlpanel/browser/resourceregistry.py @@ -13,14 +13,13 @@ from Products.CMFPlone.resources.browser.configjs import RequireJsView from Products.CMFPlone.resources.browser.cook import cookWhenChangingSettings from Products.statusmessages.interfaces import IStatusMessage -from six.moves.urllib import parse +from urllib import parse from zExceptions import NotFound from zope.component import getUtility import json import posixpath import re -import six CSS_URL_REGEX = re.compile(r'url\(([^)]+)\)') @@ -49,13 +48,9 @@ def updateRecordFromDict(record, data): if name in data: # almost all string data needs to be str, not unicode val = data[name] - if six.PY2 and isinstance(val, six.text_type): - val = val.encode('utf-8') if isinstance(val, list): newval = [] for item in val: - if six.PY2 and isinstance(item, six.text_type): - item = item.encode('utf-8') newval.append(item) val = newval @@ -344,7 +339,7 @@ def save_less_build(self): for key, value in req.form.items(): if not key.startswith('data-'): continue - if isinstance(value, six.string_types): + if isinstance(value, str): value = [value] data += '\n'.join(value) + '\n' overrides.save_file(filepath, data) @@ -360,9 +355,6 @@ def save_less_build(self): def save_less_variables(self): data = {} for key, val in json.loads(self.request.form.get('data')).items(): - if six.PY2 and isinstance(key, six.text_type): - # need to convert to str: unicode - key = key.encode('utf8') data[key] = val self.registry['plone.lessvariables'] = data return json.dumps({ @@ -372,9 +364,6 @@ def save_less_variables(self): def save_pattern_options(self): data = {} for key, val in json.loads(self.request.form.get('data')).items(): - if six.PY2 and isinstance(key, six.text_type): - # need to convert to str: unicode - key = key.encode('utf8') data[key] = val self.registry['plone.patternoptions'] = data return json.dumps({ diff --git a/Products/CMFPlone/controlpanel/browser/usergroups_usersoverview.py b/Products/CMFPlone/controlpanel/browser/usergroups_usersoverview.py index e9795df1f5..f8dc21ef01 100644 --- a/Products/CMFPlone/controlpanel/browser/usergroups_usersoverview.py +++ b/Products/CMFPlone/controlpanel/browser/usergroups_usersoverview.py @@ -16,7 +16,6 @@ UsersGroupsControlPanelView import logging -import six logger = logging.getLogger('Products.CMFPlone') @@ -212,7 +211,7 @@ def deleteMembers(self, member_ids): # Delete members in acl_users. acl_users = context.acl_users - if isinstance(member_ids, six.string_types): + if isinstance(member_ids, str): member_ids = (member_ids,) member_ids = list(member_ids) for member_id in member_ids[:]: diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_site.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_site.py index b4050c341c..dd6c5a053c 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_site.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_site.py @@ -4,7 +4,7 @@ from plone.testing.zope import Browser from Products.CMFPlone.interfaces import ISiteSchema from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING -from six import BytesIO +from io import BytesIO from zope.component import getMultiAdapter from zope.component import getUtility diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_usergroups_siteadmin_role.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_usergroups_siteadmin_role.py index ad873ffc69..655c1fbad0 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_usergroups_siteadmin_role.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_usergroups_siteadmin_role.py @@ -8,11 +8,10 @@ from plone.testing.zope import Browser from Products.CMFCore.utils import getToolByName from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING -from six import StringIO -from six.moves.urllib.parse import urlencode +from io import StringIO +from urllib.parse import urlencode import re -import six import transaction import unittest import zExceptions diff --git a/Products/CMFPlone/controlpanel/tests/test_doctests.py b/Products/CMFPlone/controlpanel/tests/test_doctests.py index 65ef940a68..dfa3235394 100644 --- a/Products/CMFPlone/controlpanel/tests/test_doctests.py +++ b/Products/CMFPlone/controlpanel/tests/test_doctests.py @@ -4,33 +4,32 @@ import doctest import re -import six import unittest +tests = ('../README.rst',) + + class Py23DocChecker(doctest.OutputChecker): def check_output(self, want, got, optionflags): - if not six.PY2: - want = re.sub("u'(.*?)'", "'\\1'", want) - want = re.sub('u"(.*?)"', '"\\1"', want) + # TODO: Fix tests to use Python 3 syntax + want = re.sub("u'(.*?)'", "'\\1'", want) + want = re.sub('u"(.*?)"', '"\\1"', want) return doctest.OutputChecker.check_output(self, want, got, optionflags) - -tests = ('../README.rst',) - - def test_suite(): return unittest.TestSuite( [ layered( doctest.DocFileSuite( - f, + ft, optionflags=doctest.ELLIPSIS, checker=Py23DocChecker(), ), - layer=PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING + layer=PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING, + ) - for f in tests + for ft in tests ] ) diff --git a/Products/CMFPlone/defaultpage.py b/Products/CMFPlone/defaultpage.py index bd525d95ca..fd5cb7e166 100644 --- a/Products/CMFPlone/defaultpage.py +++ b/Products/CMFPlone/defaultpage.py @@ -13,8 +13,6 @@ from zope.component import queryUtility from zope.component import queryMultiAdapter -import six - def get_default_page(context): """Given a folderish item, find out if it has a default-page using @@ -74,7 +72,7 @@ def get_default_page(context): # 3.1 Test for default_page attribute in folder, no acquisition pages = getattr(aq_base(context), 'default_page', []) - if isinstance(pages, six.string_types): + if isinstance(pages, str): pages = [pages] for page in pages: if page and page in ids: diff --git a/Products/CMFPlone/interfaces/controlpanel.py b/Products/CMFPlone/interfaces/controlpanel.py index 3d5681c509..1117c6434b 100644 --- a/Products/CMFPlone/interfaces/controlpanel.py +++ b/Products/CMFPlone/interfaces/controlpanel.py @@ -15,7 +15,6 @@ from zope.schema.vocabulary import SimpleVocabulary import json -import six deprecated( @@ -67,7 +66,7 @@ def validate_json(value): class JSONError(schema.ValidationError): __doc__ = _(u"Must be empty or a valid JSON-formatted " u"configuration – ${message}.", mapping={ - 'message': six.text_type(exc)}) + 'message': str(exc)}) raise JSONError(value) diff --git a/Products/CMFPlone/patches/unicodehacks.py b/Products/CMFPlone/patches/unicodehacks.py index 86f69540dd..74ccace114 100644 --- a/Products/CMFPlone/patches/unicodehacks.py +++ b/Products/CMFPlone/patches/unicodehacks.py @@ -1,13 +1,9 @@ # -*- coding: utf-8 -*- -import six - def _unicode_replace(structure): - if isinstance(structure, six.binary_type): - text = structure.decode('utf-8', 'replace') - else: - text = six.text_type(structure) - return text + if isinstance(structure, bytes): + return structure.decode('utf-8', 'replace') + return str(structure) def _nulljoin(valuelist): diff --git a/Products/CMFPlone/patches/z3c_form.py b/Products/CMFPlone/patches/z3c_form.py index 2cf7c16a49..5440afa5b0 100644 --- a/Products/CMFPlone/patches/z3c_form.py +++ b/Products/CMFPlone/patches/z3c_form.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # This is from Products.PloneHotfix20160830. -from six.moves.urllib.parse import urlparse +from urllib.parse import urlparse from z3c.form import widget diff --git a/Products/CMFPlone/resources/browser/combine.py b/Products/CMFPlone/resources/browser/combine.py index aa410eb3c7..d08a9234bc 100644 --- a/Products/CMFPlone/resources/browser/combine.py +++ b/Products/CMFPlone/resources/browser/combine.py @@ -13,7 +13,6 @@ import logging import re -import six PRODUCTION_RESOURCE_DIRECTORY = 'production' @@ -32,7 +31,7 @@ def get_production_resource_directory(): if 'timestamp.txt' not in production_folder: return '%s/++unique++1' % PRODUCTION_RESOURCE_DIRECTORY timestamp = production_folder.readFile('timestamp.txt') - if not six.PY2 and isinstance(timestamp, six.binary_type): + if isinstance(timestamp, bytes): timestamp = timestamp.decode() return '%s/++unique++%s' % ( PRODUCTION_RESOURCE_DIRECTORY, timestamp) @@ -114,7 +113,7 @@ def write_js(context, folder, meta_bundle): fi = BytesIO() for script in resources: - if not isinstance(script, six.binary_type): + if not isinstance(script, bytes): script = script.encode() fi.write((script + b'\n')) folder.writeFile(meta_bundle + '.js', fi) @@ -139,7 +138,7 @@ def write_css(context, folder, meta_bundle): # Process relative urls: # we prefix with current resource path any url not starting with # '/' or http: or data: - if not isinstance(path, six.binary_type): + if not isinstance(path, bytes): path = path.encode() css = re.sub( br"""(url\(['"]?(?!['"]?([a-z]+:|\/)))""", @@ -149,7 +148,7 @@ def write_css(context, folder, meta_bundle): fi = BytesIO() for script in resources: - if not isinstance(script, six.binary_type): + if not isinstance(script, bytes): script = script.encode() fi.write((script + b'\n')) folder.writeFile(meta_bundle + '.css', fi) diff --git a/Products/CMFPlone/resources/browser/cook.py b/Products/CMFPlone/resources/browser/cook.py index 42fd9faee6..537fcb05e5 100644 --- a/Products/CMFPlone/resources/browser/cook.py +++ b/Products/CMFPlone/resources/browser/cook.py @@ -19,7 +19,6 @@ from zope.interface import alsoProvides import logging -import six logger = logging.getLogger('Products.CMFPlone') @@ -97,7 +96,7 @@ def cookWhenChangingSettings(context, bundle=None): css = response.getBody() if css_resource[-8:] != '.min.css': css = css_compiler.compile_string(css) - if not isinstance(css, six.text_type): + if not isinstance(css, str): css = css.decode('utf8') cooked_css += '\n/* Resource: {0} */\n{1}\n'.format( css_resource, @@ -116,7 +115,7 @@ def cookWhenChangingSettings(context, bundle=None): if response.status == 200: logger.info('Cooking js %s', resource.js) js = response.getBody() - if not isinstance(js, six.text_type): + if not isinstance(js, str): js = js.decode('utf8') try: cooked_js += '\n/* resource: {0} */\n{1}'.format( @@ -156,7 +155,7 @@ def _write_resource(resource_path, cooked_string): resource_filepath = resource_path if resource_name not in container: container.makeDirectory(resource_name) - if not isinstance(cooked_string, six.binary_type): # handle Error of OFS.Image # noqa: E501 + if not isinstance(cooked_string, bytes): # handle Error of OFS.Image # noqa: E501 cooked_string = cooked_string.encode('ascii', errors='ignore') try: folder = container[resource_name] diff --git a/Products/CMFPlone/resources/browser/mixins.py b/Products/CMFPlone/resources/browser/mixins.py index 78ec3075fd..b616f0a95e 100644 --- a/Products/CMFPlone/resources/browser/mixins.py +++ b/Products/CMFPlone/resources/browser/mixins.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from AccessControl.safe_formatter import SafeFormatter from plone.registry.interfaces import IRegistry -from six.moves.urllib.parse import urlparse +from urllib.parse import urlparse from Products.CMFPlone.interfaces import IResourceRegistry from Products.Five.browser import BrowserView from zope.component import getMultiAdapter diff --git a/Products/CMFPlone/resources/browser/scripts.py b/Products/CMFPlone/resources/browser/scripts.py index 38ecacbba7..71c8c8dff3 100644 --- a/Products/CMFPlone/resources/browser/scripts.py +++ b/Products/CMFPlone/resources/browser/scripts.py @@ -2,7 +2,7 @@ from Products.CMFPlone.resources.browser.cook import cookWhenChangingSettings from Products.CMFPlone.resources.browser.resource import ResourceView from Products.CMFPlone.utils import get_top_request -from six.moves.urllib import parse +from urllib import parse from zope.component import getMultiAdapter diff --git a/Products/CMFPlone/resources/browser/styles.py b/Products/CMFPlone/resources/browser/styles.py index 7e4c9e815a..ef163bf057 100644 --- a/Products/CMFPlone/resources/browser/styles.py +++ b/Products/CMFPlone/resources/browser/styles.py @@ -5,7 +5,7 @@ from Products.CMFPlone.resources.browser.cook import cookWhenChangingSettings from Products.CMFPlone.resources.browser.resource import ResourceBase from Products.CMFPlone.utils import get_top_request -from six.moves.urllib import parse +from urllib import parse from zope.component import getUtility diff --git a/Products/CMFPlone/setuphandlers.py b/Products/CMFPlone/setuphandlers.py index 05c8a4c96d..a72158af05 100644 --- a/Products/CMFPlone/setuphandlers.py +++ b/Products/CMFPlone/setuphandlers.py @@ -16,8 +16,6 @@ from zope.i18n.locales import LoadLocaleError from zope.i18n.locales import locales -import six - def addCacheHandlers(portal): """ Add RAM and AcceleratedHTTP cache handlers """ @@ -150,7 +148,6 @@ def importFinalSteps(context): first_weekday_setup(context) timezone_setup(context) - external_editor_permissions(site) set_zsqlmethods_permissions(site) # setup resource overrides plone.resource @@ -159,24 +156,6 @@ def importFinalSteps(context): persistentDirectory.makeDirectory(OVERRIDE_RESOURCE_DIRECTORY_NAME) -def external_editor_permissions(site): - """The permission to use Products.ExternalEditor only makes sense when - ExternalEditor is installed. In py3 it will not exists because it depends - on webdav. - The following xml was taken from rolemap.xml: - - - - - - """ - if six.PY2: - site.manage_permission( - 'Use external editor', - ['Authenticated', 'Manager', 'Site Administrator'], - False) - - def set_zsqlmethods_permissions(site): """The permission to use Products.ZSQLMethods only makes sense when ZSQLMethods is installed. In Zope 4 that is sometimes not the case. diff --git a/Products/CMFPlone/skins/plone_scripts/queryCatalog.py b/Products/CMFPlone/skins/plone_scripts/queryCatalog.py index 18681b053d..d3f3166ae8 100644 --- a/Products/CMFPlone/skins/plone_scripts/queryCatalog.py +++ b/Products/CMFPlone/skins/plone_scripts/queryCatalog.py @@ -22,16 +22,7 @@ if REQUEST is None: REQUEST = context.REQUEST -# We should accept both a simple space, unicode u'\u0020 but also a -# multi-space, so called 'waji-kankaku', unicode u'\u3000' -# Stupid hack to find py-version since importing six or sys is forbidden. -try: - # PY2 - u'foo'.decode('utf8') - multispace = u'\u3000'.encode('utf-8') -except AttributeError: - # PY3 - multispace = u'\u3000' +multispace = u'\u3000' def quotestring(s): return '"%s"' % s diff --git a/Products/CMFPlone/tests/dummy.py b/Products/CMFPlone/tests/dummy.py index 0ce801116b..88fd8cfc6c 100644 --- a/Products/CMFPlone/tests/dummy.py +++ b/Products/CMFPlone/tests/dummy.py @@ -7,8 +7,8 @@ from OFS.SimpleItem import SimpleItem from Products.CMFPlone.interfaces import INonStructuralFolder from Products.CMFPlone.interfaces import IWorkflowChain -from six import StringIO -from six import BytesIO +from io import StringIO +from io import BytesIO from zope.interface import implementer from zope.interface import Interface from ZPublisher.HTTPRequest import FileUpload diff --git a/Products/CMFPlone/tests/messages.txt b/Products/CMFPlone/tests/messages.txt index 52e471cec0..0b8320c7fb 100644 --- a/Products/CMFPlone/tests/messages.txt +++ b/Products/CMFPlone/tests/messages.txt @@ -122,7 +122,7 @@ to get the parsed and interpreted text. >>> from zope.tal.htmltalparser import HTMLTALParser >>> from zope.tal.talinterpreter import TALInterpreter - >>> from six import StringIO + >>> from io import StringIO >>> def compile(source): ... parser = HTMLTALParser() diff --git a/Products/CMFPlone/tests/testCSRFProtection.py b/Products/CMFPlone/tests/testCSRFProtection.py index de3116eb1c..a3b4b91b00 100644 --- a/Products/CMFPlone/tests/testCSRFProtection.py +++ b/Products/CMFPlone/tests/testCSRFProtection.py @@ -5,7 +5,7 @@ from plone.app.testing.bbb import PloneTestCase from plone.keyring.interfaces import IKeyManager from plone.protect.authenticator import AuthenticatorView -from six import BytesIO +from io import BytesIO from zope.component import queryUtility diff --git a/Products/CMFPlone/tests/testContentTypeScripts.py b/Products/CMFPlone/tests/testContentTypeScripts.py index ced3e7d5de..44195920a9 100644 --- a/Products/CMFPlone/tests/testContentTypeScripts.py +++ b/Products/CMFPlone/tests/testContentTypeScripts.py @@ -6,8 +6,6 @@ from Products.CMFPlone.tests import PloneTestCase from Products.CMFPlone.tests import dummy -import six - AddPortalTopics = 'Add portal topics' @@ -121,10 +119,7 @@ class TestImageProps(PloneTestCase.PloneTestCase): def testImageComputedProps(self): from OFS.Image import Image - if six.PY2: - tag = Image.tag.im_func - else: - tag = Image.tag + tag = Image.tag kw = {'_title': 'some title', '_alt': 'alt tag', 'height': 100, diff --git a/Products/CMFPlone/tests/testCutPasteSecurity.py b/Products/CMFPlone/tests/testCutPasteSecurity.py index d651481b04..92c549098e 100644 --- a/Products/CMFPlone/tests/testCutPasteSecurity.py +++ b/Products/CMFPlone/tests/testCutPasteSecurity.py @@ -6,10 +6,11 @@ from Products.CMFCore.interfaces import IContentish from zope.component import provideHandler, getGlobalSiteManager from zope.lifecycleevent.interfaces import IObjectMovedEvent +from urllib.error import HTTPError + import transaction -from six.moves.urllib.error import HTTPError class TestCutPasteSecurity(PloneTestCase): diff --git a/Products/CMFPlone/tests/testNavTree.py b/Products/CMFPlone/tests/testNavTree.py index 43add6460c..fd7a47a504 100644 --- a/Products/CMFPlone/tests/testNavTree.py +++ b/Products/CMFPlone/tests/testNavTree.py @@ -12,13 +12,12 @@ from zope.interface import directlyProvides from zope.interface import implementer -default_user = PloneTestCase.default_user from Products.CMFPlone.PloneFolder import PloneFolder from Products.CMFPlone.interfaces import INonStructuralFolder +default_user = PloneTestCase.default_user -import six @implementer(INonStructuralFolder) @@ -558,7 +557,7 @@ def testGetNavigationRootPropertyIsFolder(self): folderPath = '/'.join(self.folder.getPhysicalPath()) portalPath = '/'.join(self.portal.getPhysicalPath()) relativePath = folderPath[len(portalPath):] - self.portal.portal_registry['plone.root'] = six.text_type(relativePath) + self.portal.portal_registry['plone.root'] = str(relativePath) root = getNavigationRoot(self.portal) self.assertEqual(root, folderPath) diff --git a/Products/CMFPlone/tests/testSecurity.py b/Products/CMFPlone/tests/testSecurity.py index 45ae145396..76e5d53ce2 100644 --- a/Products/CMFPlone/tests/testSecurity.py +++ b/Products/CMFPlone/tests/testSecurity.py @@ -6,7 +6,6 @@ from zExceptions import Unauthorized import re -import six import unittest @@ -147,7 +146,7 @@ def test_ftp(self): self.setRoles(['Manager', 'Owner']) self.portal.REQUEST.PARENTS = [self.app] res = self.portal.news.manage_FTPlist(self.portal.REQUEST) - self.assertTrue(isinstance(res, six.string_types)) + self.assertTrue(isinstance(res, str)) self.portal.portal_workflow.doActionFor(self.portal.news, 'hide') self.setRoles(['Member']) from zExceptions import Unauthorized diff --git a/Products/CMFPlone/tests/testWebDAV.py b/Products/CMFPlone/tests/testWebDAV.py index c3b7db5d1b..b2d7dae797 100644 --- a/Products/CMFPlone/tests/testWebDAV.py +++ b/Products/CMFPlone/tests/testWebDAV.py @@ -8,7 +8,7 @@ from Products.CMFPlone.tests import dummy from Products.CMFPlone.tests import PloneTestCase -import six +import io html = """\ @@ -45,7 +45,7 @@ def testPUTDocument(self): response = self.publish(self.folder_path + '/new_html', env={'CONTENT_TYPE': 'text/html'}, request_method='PUT', - stdin=six.StringIO(html), + stdin=io.StringIO(html), basic=self.basic_auth) self.assertEqual(response.getStatus(), 201) @@ -59,7 +59,7 @@ def testPUTTextDocumentRSTNoContentType(self): response = self.publish(self.folder_path + '/test.rst', env={'CONTENT_LENGTH': '0'}, request_method='PUT', - stdin=six.StringIO(), + stdin=io.StringIO(), basic=self.basic_auth) self.assertEqual(response.getStatus(), 201) @@ -73,7 +73,7 @@ def testPUTTextDocumentTXTNoContentType(self): response = self.publish(self.folder_path + '/test.txt', env={'CONTENT_LENGTH': '0'}, request_method='PUT', - stdin=six.StringIO(), + stdin=io.StringIO(), basic=self.basic_auth) self.assertEqual(response.getStatus(), 201) @@ -87,7 +87,7 @@ def testPUTTextDocumentININoContentType(self): response = self.publish(self.folder_path + '/test.ini', env={'CONTENT_LENGTH': '0'}, request_method='PUT', - stdin=six.StringIO(), + stdin=io.StringIO(), basic=self.basic_auth) self.assertEqual(response.getStatus(), 201) @@ -100,7 +100,7 @@ def testPUTIndexHtmlDocument(self): response = self.publish(self.folder_path + '/index_html', env={'CONTENT_TYPE': 'text/html'}, request_method='PUT', - stdin=six.StringIO(html), + stdin=io.StringIO(html), basic=self.basic_auth) self.assertEqual(response.getStatus(), 201) @@ -114,7 +114,7 @@ def testPUTImage(self): response = self.publish(self.folder_path + '/new_image', env={'CONTENT_TYPE': 'image/gif'}, request_method='PUT', - stdin=six.StringIO(dummy.GIF), + stdin=io.StringIO(dummy.GIF), basic=self.basic_auth) self.assertEqual(response.getStatus(), 201) @@ -131,7 +131,7 @@ def testPUTImageGIFNoContentType(self): response = self.publish(self.folder_path + '/test.gif', env={'CONTENT_LENGTH': len(dummy.GIF)}, request_method='PUT', - stdin=six.StringIO(dummy.GIF), + stdin=io.StringIO(dummy.GIF), basic=self.basic_auth) self.assertEqual(response.getStatus(), 201) @@ -149,7 +149,7 @@ def testPUTImageJPGNoContentType(self): response = self.publish(self.folder_path + '/test.jpg', env={'CONTENT_LENGTH': len(dummy.GIF)}, request_method='PUT', - stdin=six.StringIO(dummy.GIF), + stdin=io.StringIO(dummy.GIF), basic=self.basic_auth) self.assertEqual(response.getStatus(), 201) @@ -167,7 +167,7 @@ def testPUTImagePNGNoContentType(self): response = self.publish(self.folder_path + '/test.png', env={'CONTENT_LENGTH': len(dummy.GIF)}, request_method='PUT', - stdin=six.StringIO(dummy.GIF), + stdin=io.StringIO(dummy.GIF), basic=self.basic_auth) self.assertEqual(response.getStatus(), 201) @@ -185,7 +185,7 @@ def testPUTImageTIFFNoContentType(self): response = self.publish(self.folder_path + '/test.tiff', env={'CONTENT_LENGTH': len(dummy.GIF)}, request_method='PUT', - stdin=six.StringIO(dummy.GIF), + stdin=io.StringIO(dummy.GIF), basic=self.basic_auth) self.assertEqual(response.getStatus(), 201) @@ -203,7 +203,7 @@ def testPUTImageICONoContentType(self): response = self.publish(self.folder_path + '/test.ico', env={'CONTENT_LENGTH': len(dummy.GIF)}, request_method='PUT', - stdin=six.StringIO(dummy.GIF), + stdin=io.StringIO(dummy.GIF), basic=self.basic_auth) self.assertEqual(response.getStatus(), 201) @@ -221,7 +221,7 @@ def testPUTIndexHtmlImage(self): response = self.publish(self.folder_path + '/index_html', env={'CONTENT_TYPE': 'image/gif'}, request_method='PUT', - stdin=six.StringIO(dummy.GIF), + stdin=io.StringIO(dummy.GIF), basic=self.basic_auth) self.assertEqual(response.getStatus(), 201) @@ -237,7 +237,7 @@ def testPUTDocumentIntoPortal(self): response = self.publish(self.portal_path + '/new_html', env={'CONTENT_TYPE': 'text/html'}, request_method='PUT', - stdin=six.StringIO(html), + stdin=io.StringIO(html), basic=self.basic_auth) self.assertEqual(response.getStatus(), 201) @@ -252,7 +252,7 @@ def testPUTIndexHtmlDocumentIntoPortal(self): response = self.publish(self.portal_path + '/index_html', env={'CONTENT_TYPE': 'text/html'}, request_method='PUT', - stdin=six.StringIO(html), + stdin=io.StringIO(html), basic=self.basic_auth) self.assertEqual(response.getStatus(), 201) @@ -293,7 +293,7 @@ def testPUTIndexHtml(self): self.folder_path + '/index_html', basic=self.basic_auth, env={'Content-Length': self.length}, - stdin=six.StringIO(self.body), + stdin=io.StringIO(self.body), request_method='PUT', handle_errors=False) @@ -312,7 +312,7 @@ def testPUTIndexHtmlIntoPortal(self): self.portal_path + '/index_html', basic=self.basic_auth, env={'Content-Length': self.length}, - stdin=six.StringIO(self.body), + stdin=io.StringIO(self.body), request_method='PUT', handle_errors=False) @@ -339,7 +339,7 @@ def test_document_propfind_index_html_exist_folder(self): response = self.publish(self.folder_path + '/sub/index_html', request_method='PROPFIND', env={'HTTP_DEPTH': '0'}, - stdin=six.StringIO(), + stdin=io.StringIO(), basic=self.basic_auth) self.assertEqual(response.getStatus(), 207, response.getBody()) @@ -353,7 +353,7 @@ def test_document_propfind_index_html_non_exist_folder(self): response = self.publish(self.folder_path + '/sub/index_html', request_method='PROPFIND', env={'HTTP_DEPTH': '0'}, - stdin=six.StringIO(), + stdin=io.StringIO(), basic=self.basic_auth) self.assertEqual(response.getStatus(), 404, response.getBody()) @@ -368,7 +368,7 @@ def test_document_propfind_index_html_exist_portal(self): response = self.publish(self.portal_path + '/index_html', request_method='PROPFIND', env={'HTTP_DEPTH': '0'}, - stdin=six.StringIO(), + stdin=io.StringIO(), basic=self.basic_auth) self.assertEqual(response.getStatus(), 207, response.getBody()) @@ -384,7 +384,7 @@ def test_document_propfind_index_html_non_exist_portal(self): response = self.publish(self.portal_path + '/index_html', request_method='PROPFIND', env={'HTTP_DEPTH': '0'}, - stdin=six.StringIO(), + stdin=io.StringIO(), basic=self.basic_auth) self.assertEqual(response.getStatus(), 404, response.getBody()) @@ -399,7 +399,7 @@ def test_propfind_portal_root_index_html_exists(self): response = self.publish(self.portal_path, request_method='PROPFIND', env={'HTTP_DEPTH': '0'}, - stdin=six.StringIO(), + stdin=io.StringIO(), basic=self.basic_auth) self.assertEqual(response.getStatus(), 207, response.getBody()) @@ -414,7 +414,7 @@ def test_propfind_portal_root_index_html_not_exists(self): response = self.publish(self.portal_path, request_method='PROPFIND', env={'HTTP_DEPTH': '0'}, - stdin=six.StringIO(), + stdin=io.StringIO(), basic=self.basic_auth) self.assertEqual(response.getStatus(), 207, response.getBody()) @@ -429,7 +429,7 @@ def test_propfind_folder_index_html_exists(self): response = self.publish(self.folder_path, request_method='PROPFIND', env={'HTTP_DEPTH': '0'}, - stdin=six.StringIO(), + stdin=io.StringIO(), basic=self.basic_auth) self.assertEqual(response.getStatus(), 207, response.getBody()) @@ -444,7 +444,7 @@ def test_propfind_folder_index_html_not_exists(self): response = self.publish(self.folder_path, request_method='PROPFIND', env={'HTTP_DEPTH': '0'}, - stdin=six.StringIO(), + stdin=io.StringIO(), basic=self.basic_auth) self.assertEqual(response.getStatus(), 207, response.getBody()) diff --git a/Products/CMFPlone/tests/testWorkflowTool.py b/Products/CMFPlone/tests/testWorkflowTool.py index aef3fb29af..0fefdd1b5d 100644 --- a/Products/CMFPlone/tests/testWorkflowTool.py +++ b/Products/CMFPlone/tests/testWorkflowTool.py @@ -1,13 +1,10 @@ # -*- coding: utf-8 -*- from zope.interface import directlyProvides, Interface from zope.component import provideAdapter, getGlobalSiteManager - from Products.CMFPlone.tests import PloneTestCase from Products.CMFPlone.tests.dummy import Dummy, DummyWorkflowChainAdapter from Products.CMFCore.interfaces import IWorkflowTool -import six - default_user = PloneTestCase.default_user diff --git a/Products/CMFPlone/tests/test_doctests.py b/Products/CMFPlone/tests/test_doctests.py index 04f0963959..0ec096194b 100644 --- a/Products/CMFPlone/tests/test_doctests.py +++ b/Products/CMFPlone/tests/test_doctests.py @@ -3,14 +3,13 @@ import doctest import re -import six class Py23DocChecker(doctest.OutputChecker): def check_output(self, want, got, optionflags): - if not six.PY2: - want = re.sub("u'(.*?)'", "'\\1'", want) + # TODO: Fix tests to check Python 3 style + want = re.sub("u'(.*?)'", "'\\1'", want) return doctest.OutputChecker.check_output(self, want, got, optionflags) diff --git a/Products/CMFPlone/tests/test_functional.py b/Products/CMFPlone/tests/test_functional.py index 2360b4b297..15c1add384 100644 --- a/Products/CMFPlone/tests/test_functional.py +++ b/Products/CMFPlone/tests/test_functional.py @@ -7,7 +7,6 @@ import glob import os import re -import six import unittest @@ -26,19 +25,15 @@ class Py23DocChecker(doctest.OutputChecker): def check_output(self, want, got, optionflags): - if six.PY2: - want = re.sub('zExceptions.Forbidden', 'Forbidden', want) - want = re.sub("b'(.*?)'", "'\\1'", want) - else: - want = re.sub("u'(.*?)'", "'\\1'", want) - # translate doctest exceptions - for dotted in ('urllib.error.HTTPError', ): - if dotted in got: - got = re.sub( - dotted, - dotted.rpartition('.')[-1], - got, - ) + # translate doctest exceptions + # TODO: fix tests to check for full path + for dotted in ('urllib.error.HTTPError', ): + if dotted in got: + got = re.sub( + dotted, + dotted.rpartition('.')[-1], + got, + ) return doctest.OutputChecker.check_output(self, want, got, optionflags) diff --git a/Products/CMFPlone/tests/test_mails.py b/Products/CMFPlone/tests/test_mails.py index 672a2f8746..15489c56ed 100644 --- a/Products/CMFPlone/tests/test_mails.py +++ b/Products/CMFPlone/tests/test_mails.py @@ -10,7 +10,6 @@ import doctest import re -import six import unittest @@ -41,10 +40,7 @@ def setUpPloneSite(self, portal): class Py23DocChecker(doctest.OutputChecker): def check_output(self, want, got, optionflags): - if six.PY2: - want = re.sub("b'(.*?)'", "'\\1'", want) - else: - want = re.sub("u'(.*?)'", "'\\1'", want) + want = re.sub("u'(.*?)'", "'\\1'", want) return doctest.OutputChecker.check_output(self, want, got, optionflags) diff --git a/Products/CMFPlone/tests/test_okay.py b/Products/CMFPlone/tests/test_okay.py index 567ed26816..b3e5a7a2ad 100644 --- a/Products/CMFPlone/tests/test_okay.py +++ b/Products/CMFPlone/tests/test_okay.py @@ -2,7 +2,6 @@ from plone.testing.zope import Browser from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING -import six import unittest @@ -29,10 +28,7 @@ def test_okay_browser(self): for url in urls: browser.open(url) self.assertEqual(browser.contents, u'OK') - if six.PY2: - get_header = browser.headers.getheader - else: - get_header = browser.headers.get + get_header = browser.headers.get self.assertEqual( get_header('Expires'), 'Sat, 1 Jan 2000 00:00:00 GMT') self.assertEqual( diff --git a/Products/CMFPlone/tests/test_passwordreset.py b/Products/CMFPlone/tests/test_passwordreset.py index 5bc66dd7d6..1635f6d86d 100644 --- a/Products/CMFPlone/tests/test_passwordreset.py +++ b/Products/CMFPlone/tests/test_passwordreset.py @@ -7,7 +7,6 @@ import doctest import re -import six import unittest @@ -19,10 +18,7 @@ class Py23DocChecker(doctest.OutputChecker): def check_output(self, want, got, optionflags): - if six.PY2: - want = re.sub("b'(.*?)'", "'\\1'", want) - else: - want = re.sub("u'(.*?)'", "'\\1'", want) + want = re.sub("u'(.*?)'", "'\\1'", want) return doctest.OutputChecker.check_output(self, want, got, optionflags) diff --git a/Products/CMFPlone/tests/test_patternsettings.py b/Products/CMFPlone/tests/test_patternsettings.py index ffd54194b8..817e7a0bd6 100644 --- a/Products/CMFPlone/tests/test_patternsettings.py +++ b/Products/CMFPlone/tests/test_patternsettings.py @@ -9,7 +9,6 @@ from zope.component import getUtility import json -import six import unittest @@ -62,8 +61,8 @@ def testShouldReturnCorrectType(self): result = settings() self.assertEqual(type(result), dict) for key, value in result.items(): - self.assertTrue(isinstance(key, six.string_types)) - self.assertTrue(isinstance(value, six.string_types)) + self.assertTrue(isinstance(key, str)) + self.assertTrue(isinstance(value, str)) def testFolderUrls(self): settings = PatternsSettingsView(self.folder, self.layer['request']) diff --git a/Products/CMFPlone/tests/test_safe_formatter.py b/Products/CMFPlone/tests/test_safe_formatter.py index d597f206cd..8142482322 100644 --- a/Products/CMFPlone/tests/test_safe_formatter.py +++ b/Products/CMFPlone/tests/test_safe_formatter.py @@ -7,8 +7,6 @@ from Products.CMFPlone.tests.PloneTestCase import PloneTestCase from zExceptions import Unauthorized -import six - BAD_ATTR_STR = """

@@ -107,7 +105,7 @@ def test_cook_zope2_page_templates_good_str(self): def test_cook_zope2_page_templates_good_unicode(self): from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate - pt = ZopePageTemplate('mytemplate', six.text_type(GOOD_UNICODE)) + pt = ZopePageTemplate('mytemplate', str(GOOD_UNICODE)) hack_pt(pt) self.assertEqual(pt.pt_render().strip(), '

none

') hack_pt(pt, self.portal) @@ -209,11 +207,7 @@ def test_access_to_private_content_not_allowed_in_any_way(self): "'access {0.foobar.Title}'.format(context)") hack_pt(pt, context=self.portal) login(self.portal, TEST_USER_NAME) - # We replace ATDocument with Document to make the tests pass - # with ATContentTypes and plone.app.contenttypes. method_name = 'DexterityContent.Title' - if six.PY2: - method_name = 'Document.Title' self.assertEqual( pt.pt_render(), u'

access >> print(safe_unicode(None)) None """ - if six.PY2: - if isinstance(value, unicode): - return value - elif isinstance(value, basestring): - try: - value = unicode(value, encoding) - except (UnicodeDecodeError): - value = value.decode('utf-8', 'replace') - return value - if isinstance(value, str): return value elif isinstance(value, bytes): @@ -514,7 +498,7 @@ def safe_text(value, encoding='utf-8'): def safe_bytes(value, encoding='utf-8'): """Convert text to bytes of the specified encoding. """ - if isinstance(value, six.text_type): + if isinstance(value, str): value = value.encode(encoding) return value @@ -525,9 +509,7 @@ def safe_bytes(value, encoding='utf-8'): def safe_nativestring(value, encoding='utf-8'): """Convert a value to str in py2 and to text in py3 """ - if six.PY2 and isinstance(value, six.text_type): - value = safe_bytes(value, encoding) - if not six.PY2 and isinstance(value, six.binary_type): + if isinstance(value, bytes): value = safe_text(value, encoding) return value @@ -700,7 +682,7 @@ def validate_json(value): class JSONError(schema.ValidationError): __doc__ = _(u"Must be empty or a valid JSON-formatted " u"configuration – ${message}.", mapping={ - 'message': six.text_type(exc)}) + 'message': str(exc)}) raise JSONError(value) @@ -821,11 +803,7 @@ def get_top_site_from_url(context, request): url_path = urlparse(context.absolute_url()).path.split('/') for idx in range(len(url_path)): _path = '/'.join(url_path[:idx + 1]) or '/' - site_path = request.physicalPathFromURL(_path) - if six.PY2: - site_path = safe_encode('/'.join(site_path)) or '/' - else: - site_path = '/'.join(site_path) or '/' + site_path = '/'.join(request.physicalPathFromURL(_path)) or '/' _site = context.restrictedTraverse(site_path) if ISite.providedBy(_site): break @@ -866,7 +844,7 @@ def human_readable_size(size): if not size: return '0 %s' % smaller - if isinstance(size, six.integer_types): + if isinstance(size, int): if size < SIZE_CONST[smaller]: return '1 %s' % smaller for c in SIZE_ORDER: diff --git a/Products/CMFPlone/workflow.py b/Products/CMFPlone/workflow.py index 158ffb78cd..912fc10391 100644 --- a/Products/CMFPlone/workflow.py +++ b/Products/CMFPlone/workflow.py @@ -5,8 +5,6 @@ from Products.CMFCore.interfaces import IWorkflowTool from Products.CMFPlone.interfaces import IWorkflowChain -import six - @adapter(Interface, IWorkflowTool) @implementer(IWorkflowChain) @@ -42,7 +40,7 @@ def ToolWorkflowChain(context, workflow_tool): () """ - if isinstance(context, six.string_types): + if isinstance(context, str): pt = context elif hasattr(aq_base(context), 'getPortalTypeName'): pt = context.getPortalTypeName() diff --git a/news/3183.misc b/news/3183.misc new file mode 100644 index 0000000000..5e033098be --- /dev/null +++ b/news/3183.misc @@ -0,0 +1,2 @@ +Remove six at all places where used. [jensens] + diff --git a/setup.py b/setup.py index 2024e91c26..bcc2499d51 100644 --- a/setup.py +++ b/setup.py @@ -112,7 +112,6 @@ 'Products.TemporaryFolder', 'pyScss', 'setuptools>=36.2', - 'six', 'transaction', 'z3c.autoinclude', 'ZODB3', From 53f5e3497a6b42c93ca2e73621d8a740eea087f6 Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Fri, 25 Sep 2020 19:25:42 +0200 Subject: [PATCH 099/127] Remove portal_utf8 and it twin utf8_portal from utils and PloneTool since its never used nowhere. --- Products/CMFPlone/PloneTool.py | 10 ---------- Products/CMFPlone/tests/test_PloneTool.py | 18 ------------------ Products/CMFPlone/utils.py | 12 ------------ news/3183.removal | 3 +++ 4 files changed, 3 insertions(+), 40 deletions(-) create mode 100644 news/3183.removal diff --git a/Products/CMFPlone/PloneTool.py b/Products/CMFPlone/PloneTool.py index 797b00121b..fa16544c40 100644 --- a/Products/CMFPlone/PloneTool.py +++ b/Products/CMFPlone/PloneTool.py @@ -116,16 +116,6 @@ def getSiteEncoding(self): """ Get the the site encoding, which is utf-8.""" return 'utf-8' - @security.public - def portal_utf8(self, str, errors='strict'): - """Transforms an string in portal encoding to utf8.""" - return utils.portal_utf8(self, str, errors) - - @security.public - def utf8_portal(self, str, errors='strict'): - """Transforms an utf8 string to portal encoding.""" - return utils.utf8_portal(self, str, errors) - @security.private def getMailHost(self): """Gets the MailHost.""" diff --git a/Products/CMFPlone/tests/test_PloneTool.py b/Products/CMFPlone/tests/test_PloneTool.py index f58b6d9d2b..88541894ec 100644 --- a/Products/CMFPlone/tests/test_PloneTool.py +++ b/Products/CMFPlone/tests/test_PloneTool.py @@ -26,24 +26,6 @@ def test_getSiteEncoding(self): 'utf-8' ) - def test_portal_utf8(self): - text = u'Eksempel \xe6\xf8\xe5' - site_text = text.encode('utf-8') - - self.assertEqual( - self.tool.portal_utf8(site_text), - text.encode('utf-8') - ) - - def test_utf8_portal(self): - text = u'Eksempel \xe6\xf8\xe5' - utf8text = text.encode('utf-8') - - self.assertEqual( - self.tool.utf8_portal(utf8text), - text.encode('utf-8') - ) - def test_getMailHost(self): self.assertTrue( IMailHost.providedBy(self.tool.getMailHost()) diff --git a/Products/CMFPlone/utils.py b/Products/CMFPlone/utils.py index 9dcc8afeed..210d8fbe77 100644 --- a/Products/CMFPlone/utils.py +++ b/Products/CMFPlone/utils.py @@ -221,18 +221,6 @@ def getSiteEncoding(context): 'currently. This method always returns "utf-8"')) -# XXX portal_utf8 and utf8_portal probably can go away -def portal_utf8(context, str_, errors='strict'): - # Test - warnings.warn("portal_utf8/utf8_portal are deprecated.") - str(str_, 'utf-8', errors) - return str - - -# XXX this is the same method as above -utf8_portal = portal_utf8 - - def getEmptyTitle(context, translated=True): """Returns string to be used for objects with no title or id""" # The default is an extra fancy unicode elipsis diff --git a/news/3183.removal b/news/3183.removal new file mode 100644 index 0000000000..c41bd0eebb --- /dev/null +++ b/news/3183.removal @@ -0,0 +1,3 @@ + +Remove ``portal_utf8`` and it twin ``utf8_portal`` from ``utils`` and ``PloneTool`` since its never used nowhere. [jensens] + From 2d91e07c2e642f3f299a26ccd80e40be30433f7c Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Sat, 26 Sep 2020 02:29:34 +0200 Subject: [PATCH 100/127] Renamed wrongly named news snippets. [ci skip] --- news/{3183.misc => 3183.breaking.1} | 0 news/{3183.removal => 3183.breaking.2} | 2 -- 2 files changed, 2 deletions(-) rename news/{3183.misc => 3183.breaking.1} (100%) rename news/{3183.removal => 3183.breaking.2} (98%) diff --git a/news/3183.misc b/news/3183.breaking.1 similarity index 100% rename from news/3183.misc rename to news/3183.breaking.1 diff --git a/news/3183.removal b/news/3183.breaking.2 similarity index 98% rename from news/3183.removal rename to news/3183.breaking.2 index c41bd0eebb..471fabfa1e 100644 --- a/news/3183.removal +++ b/news/3183.breaking.2 @@ -1,3 +1 @@ - Remove ``portal_utf8`` and it twin ``utf8_portal`` from ``utils`` and ``PloneTool`` since its never used nowhere. [jensens] - From 78ff9d076e6172881ccdd478b3a46a8a0fafb967 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Sat, 26 Sep 2020 01:28:33 +0200 Subject: [PATCH 101/127] Removed folder_publish.cpy script. Moved it to a new browser view in plone.app.content. Removed deprecated transitionObjectsByPaths. It was only used by this script, and I have now put it in the view. --- Products/CMFPlone/PloneTool.py | 38 -------- Products/CMFPlone/patches/csrf.py | 1 - .../skins/plone_scripts/folder_publish.cpy | 35 ------- .../plone_scripts/folder_publish.cpy.metadata | 4 - Products/CMFPlone/tests/testCSRFProtection.py | 9 -- .../CMFPlone/tests/testContentPublishing.py | 95 +------------------ news/3057.breaking | 4 + 7 files changed, 7 insertions(+), 179 deletions(-) delete mode 100644 Products/CMFPlone/skins/plone_scripts/folder_publish.cpy delete mode 100644 Products/CMFPlone/skins/plone_scripts/folder_publish.cpy.metadata create mode 100644 news/3057.breaking diff --git a/Products/CMFPlone/PloneTool.py b/Products/CMFPlone/PloneTool.py index fa16544c40..2111ecb648 100644 --- a/Products/CMFPlone/PloneTool.py +++ b/Products/CMFPlone/PloneTool.py @@ -1008,44 +1008,6 @@ def deleteObjectsByPaths(self, paths, handle_errors=True, REQUEST=None): return success, failure deleteObjectsByPaths = postonly(deleteObjectsByPaths) - @security.public - def transitionObjectsByPaths(self, workflow_action, paths, comment='', - expiration_date=None, effective_date=None, - include_children=False, handle_errors=True, - REQUEST=None): - log_deprecated("transitionObjectsByPaths is deprecated") - failure = {} - # use the portal for traversal in case we have relative paths - portal = getToolByName(self, 'portal_url').getPortalObject() - traverse = portal.restrictedTraverse - for path in paths: - if handle_errors: - sp = transaction.savepoint(optimistic=True) - try: - o = traverse(path, None) - if o is not None: - o.content_status_modify(workflow_action, - comment, - effective_date=effective_date, - expiration_date=expiration_date) - except ConflictError: - raise - except Exception as e: - if handle_errors: - # skip this object but continue with sub-objects. - sp.rollback() - failure[path] = e - else: - raise - if getattr(o, 'isPrincipiaFolderish', None) and include_children: - subobject_paths = ["%s/%s" % (path, id) for id in o] - self.transitionObjectsByPaths(workflow_action, subobject_paths, - comment, expiration_date, - effective_date, include_children, - handle_errors) - return failure - transitionObjectsByPaths = postonly(transitionObjectsByPaths) - @security.public def renameObjectsByPaths(self, paths, new_ids, new_titles, handle_errors=True, REQUEST=None): diff --git a/Products/CMFPlone/patches/csrf.py b/Products/CMFPlone/patches/csrf.py index ca64c03137..eda29c3c5e 100644 --- a/Products/CMFPlone/patches/csrf.py +++ b/Products/CMFPlone/patches/csrf.py @@ -13,7 +13,6 @@ def applyPatches(): PT.changeOwnershipOf = patch(PT.changeOwnershipOf) PT.acquireLocalRoles = patch(PT.acquireLocalRoles) PT.deleteObjectsByPaths = patch(PT.deleteObjectsByPaths) - PT.transitionObjectsByPaths = patch(PT.transitionObjectsByPaths) PT.renameObjectsByPaths = patch(PT.renameObjectsByPaths) from Products.CMFCore.MembershipTool import MembershipTool as MT diff --git a/Products/CMFPlone/skins/plone_scripts/folder_publish.cpy b/Products/CMFPlone/skins/plone_scripts/folder_publish.cpy deleted file mode 100644 index 8c4ab079f6..0000000000 --- a/Products/CMFPlone/skins/plone_scripts/folder_publish.cpy +++ /dev/null @@ -1,35 +0,0 @@ -## Controller Python Script "folder_publish" -##bind container=container -##bind context=context -##bind namespace= -##bind script=script -##bind state=state -##bind subpath=traverse_subpath -##parameters=workflow_action=None, paths=[], comment='No comment', expiration_date=None, effective_date=None, include_children=False -##title=Publish objects from a folder - -from Products.CMFPlone.utils import transaction_note -from Products.CMFPlone import PloneMessageFactory as _ - -plone_utils = context.plone_utils -REQUEST = context.REQUEST - -if workflow_action is None: - context.plone_utils.addPortalMessage( - _(u'You must select a publishing action.'), 'error') - return state.set(status='failure') -if not paths: - context.plone_utils.addPortalMessage( - _(u'You must select content to change.'), 'error') - return state.set(status='failure') - -failed = plone_utils.transitionObjectsByPaths( - workflow_action, paths, comment, - expiration_date, effective_date, - include_children, REQUEST=REQUEST) - -transaction_note(str(paths) + ' transitioned ' + workflow_action) - -# It is necessary to set the context to override context from content_status_modify -context.plone_utils.addPortalMessage(_(u'Item state changed.')) -return state.set(context=context) diff --git a/Products/CMFPlone/skins/plone_scripts/folder_publish.cpy.metadata b/Products/CMFPlone/skins/plone_scripts/folder_publish.cpy.metadata deleted file mode 100644 index 5db8e9c172..0000000000 --- a/Products/CMFPlone/skins/plone_scripts/folder_publish.cpy.metadata +++ /dev/null @@ -1,4 +0,0 @@ -[actions] -action.success=redirect_to:request/orig_template|string:view -action.success_no_edit=redirect_to:request/orig_template|string:view -action.failure=redirect_to:request/orig_template|string:view diff --git a/Products/CMFPlone/tests/testCSRFProtection.py b/Products/CMFPlone/tests/testCSRFProtection.py index a3b4b91b00..8c7a5cd412 100644 --- a/Products/CMFPlone/tests/testCSRFProtection.py +++ b/Products/CMFPlone/tests/testCSRFProtection.py @@ -41,15 +41,6 @@ def test_PloneTool_deleteObjectsByPaths(self): 'paths:list=news') self.assertFalse(self.portal.get('news', None)) - def test_PloneTool_transitionObjectsByPaths(self): - infoFor = self.portal.portal_workflow.getInfoFor - frontpage = self.portal['front-page'] - self.assertEqual(infoFor(frontpage, 'review_state'), 'published') - self.checkAuthenticator( - '/plone_utils/transitionObjectsByPaths', - 'workflow_action=retract&paths:list=front-page', status=302) - self.assertEqual(infoFor(frontpage, 'review_state'), 'visible') - def test_PloneTool_renameObjectsByPaths(self): self.assertFalse(self.portal.get('foo', None)) self.checkAuthenticator( diff --git a/Products/CMFPlone/tests/testContentPublishing.py b/Products/CMFPlone/tests/testContentPublishing.py index aedf3afe00..79dbcaf429 100644 --- a/Products/CMFPlone/tests/testContentPublishing.py +++ b/Products/CMFPlone/tests/testContentPublishing.py @@ -42,9 +42,8 @@ class TestContentPublishing(PloneTestCase): This testcase was written to prevent collector/2914 regressions - In addition, some more general tests of content_status_modify and - folder_publish behaviour have been added, since this seems a logical - place to keep them. + In addition, some more general tests of content_status_modify + have been added, since this seems a logical place to keep them. """ def afterSetUp(self): @@ -54,95 +53,7 @@ def afterSetUp(self): self.workflow = self.portal.portal_workflow self.setupAuthenticator() - def _checkMD(self, obj, **changes): - """ check the DublinCore Metadata on obj - it must inherit from - DublinCore """ - if changes: - _orig_props = {} - _orig_props.update(props) - props.update(changes) - - self.assertEqual(obj.Title(), props['title']) - self.assertEqual(obj.Description(), props['description']) - self.assertEqual(obj.Subject(), tuple(props['subject'])) - self.assertEqual(obj.ExpirationDate(zone='UTC'), - obj._datify(props['expiration_date']).ISO()) - self.assertEqual(obj.EffectiveDate(zone='UTC'), - obj._datify(props['effective_date']).ISO()) - self.assertEqual(obj.Format(), props['format']) - self.assertEqual(obj.Rights(), props['rights']) - self.assertEqual(obj.Language(), props['language']) - self.assertEqual(obj.Contributors(), tuple(props['contributors'])) - - if changes: - props.update(_orig_props) - - # Test the recursive behaviour of content_status_modify and folder_publish: - - def testPublishingSubobjects(self): - self.setRoles(['Manager']) # Make sure we can publish directly - self.folder.invokeFactory('Document', id='d1', title='Doc 1') - self.folder.invokeFactory('Folder', id='f1', title='Folder 1') - self.folder.f1.invokeFactory('Document', id='d2', title='Doc 2') - self.folder.f1.invokeFactory('Folder', id='f2', title='Folder 2') - paths = [] - for o in (self.folder.d1, self.folder.f1): - paths.append('/'.join(o.getPhysicalPath())) - - # folder_publish requires a non-GET request - self.setRequestMethod('POST') - self.folder.folder_publish(workflow_action='publish', - paths=paths, - include_children=True) - for o in (self.folder.d1, self.folder.f1, self.folder.f1.d2, - self.folder.f1.f2): - self.assertEqual(self.workflow.getInfoFor(o, 'review_state'), - 'published') - - def testPublishingSubobjectsAndExpireThem(self): - self.setRoles(['Manager']) # Make sure we can publish directly - self.folder.invokeFactory('Document', id='d1', title='Doc 1') - self.folder.invokeFactory('Folder', id='f1', title='Folder 1') - self.folder.f1.invokeFactory('Document', id='d2', title='Doc 2') - self.folder.f1.invokeFactory('Folder', id='f2', title='Folder 2') - paths = [] - for o in (self.folder.d1, self.folder.f1): - paths.append('/'.join(o.getPhysicalPath())) - - # folder_publish requires a non-GET request - self.setRequestMethod('POST') - self.folder.folder_publish(workflow_action='publish', - paths=paths, - effective_date='1/1/2001', - expiration_date='1/2/2001', - include_children=True) - for o in (self.folder.d1, self.folder.f1, self.folder.f1.d2, - self.folder.f1.f2): - self.assertEqual(self.workflow.getInfoFor(o, 'review_state'), - 'published') - self.assertTrue(isExpired(o)) - - def testPublishingWithoutSubobjects(self): - self.setRoles(['Manager']) # Make sure we can publish directly - self.folder.invokeFactory('Document', id='d1', title='Doc 1') - self.folder.invokeFactory('Folder', id='f1', title='Folder 1') - self.folder.f1.invokeFactory('Document', id='d2', title='Doc 2') - self.folder.f1.invokeFactory('Folder', id='f2', title='Folder 2') - paths = [] - for o in (self.folder.d1, self.folder.f1): - paths.append('/'.join(o.getPhysicalPath())) - - # folder_publish requires a non-GET request - self.setRequestMethod('POST') - self.folder.folder_publish(workflow_action='publish', - paths=paths, - include_children=False) - for o in (self.folder.d1, self.folder.f1): - self.assertEqual(self.workflow.getInfoFor(o, 'review_state'), - 'published') - for o in (self.folder.f1.d2, self.folder.f1.f2): - self.assertEqual(self.workflow.getInfoFor(o, 'review_state'), - 'visible') + # Test the recursive behaviour of content_status_modify: def testPublishingNonDefaultPageLeavesFolderAlone(self): self.setRoles(['Manager']) # Make sure we can publish directly diff --git a/news/3057.breaking b/news/3057.breaking new file mode 100644 index 0000000000..2a3f6fe38a --- /dev/null +++ b/news/3057.breaking @@ -0,0 +1,4 @@ +Removed ``folder_publish.cpy`` script. +Replaced with folder_publish browser view in ``plone.app.content``. +Removed deprecated transitionObjectsByPaths. +[maurits] From 6eec88539da85f4d0c0e0f59bc6d961abdd6937d Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Mon, 28 Sep 2020 15:35:11 +0200 Subject: [PATCH 102/127] No longer consider calling len(batch) as deprecated. The deprecation warning is unvoidable with current `Products.PageTemplates` code. Fixes https://github.com/plone/Products.CMFPlone/issues/3176 (cherry picked from commit 52a3267ead37582f49b0f0c9ddcdc2f13d2eae2e) --- Products/CMFPlone/PloneBatch.py | 15 ++++++++++----- news/3176.bugfix | 4 ++++ 2 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 news/3176.bugfix diff --git a/Products/CMFPlone/PloneBatch.py b/Products/CMFPlone/PloneBatch.py index 2f8737297c..68687dc93a 100644 --- a/Products/CMFPlone/PloneBatch.py +++ b/Products/CMFPlone/PloneBatch.py @@ -20,12 +20,17 @@ def __init__(self, sequence, size, start=0, end=0, orphan=0, self.b_start_str = b_start_str def __len__(self): + # Note: Using len() was deprecated for several years. + # It was recommended to explicitly either use the `length` attribute + # for the size of the current page, which is what we return now, + # or use the `sequence_length` attribute for the size of the + # entire sequence. + # But the deprecation was reverted for Plone 5.2.3, + # because core code in Products.PageTemplates called `len` + # on batches, making the deprecation warning unavoidable + # and thus unnecessary. + # See https://github.com/plone/Products.CMFPlone/issues/3176 return self.length - __len__ = deprecated(__len__, - ('Using len() is deprecated. Use the `length` attribute for the ' - 'size of the current page, which is what we return now. ' - 'Use the `sequence_length` attribute for the size of the ' - 'entire sequence. ')) def __bool__(self): # Without __bool__ a bool(self) would call len(self), which diff --git a/news/3176.bugfix b/news/3176.bugfix new file mode 100644 index 0000000000..56e075e5e5 --- /dev/null +++ b/news/3176.bugfix @@ -0,0 +1,4 @@ +No longer consider calling ``len(batch)`` as deprecated. +The deprecation warning is unvoidable with current ``Products.PageTemplates`` code. +Fixes `issue 3176 `_. +maurits From da9995efe9a1c9c564203ddd8d30ed1ca5b0111f Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Sat, 26 Sep 2020 19:33:43 +0200 Subject: [PATCH 103/127] find . -name "*.py" |xargs pyupgrade --py36-plus --- Products/CMFPlone/ActionsTool.py | 1 - Products/CMFPlone/CatalogTool.py | 3 +- Products/CMFPlone/DublinCore.py | 3 +- Products/CMFPlone/MigrationTool.py | 29 +- Products/CMFPlone/PasswordResetTool.py | 1 - Products/CMFPlone/PloneBaseTool.py | 1 - Products/CMFPlone/PloneBatch.py | 5 +- Products/CMFPlone/PloneControlPanel.py | 17 +- Products/CMFPlone/PloneFolder.py | 1 - Products/CMFPlone/PloneTool.py | 13 +- Products/CMFPlone/Portal.py | 4 +- Products/CMFPlone/PropertiesTool.py | 1 - Products/CMFPlone/QuickInstallerTool.py | 1 - Products/CMFPlone/RegistrationTool.py | 49 +- Products/CMFPlone/SkinsTool.py | 5 +- Products/CMFPlone/TranslationServiceTool.py | 1 - Products/CMFPlone/TypesTool.py | 1 - Products/CMFPlone/URLTool.py | 1 - Products/CMFPlone/UnicodeSplitter/__init__.py | 1 - Products/CMFPlone/UnicodeSplitter/config.py | 11 +- Products/CMFPlone/UnicodeSplitter/splitter.py | 19 +- Products/CMFPlone/WorkflowTool.py | 3 +- Products/CMFPlone/__init__.py | 1 - Products/CMFPlone/_compat.py | 1 - Products/CMFPlone/bbb.py | 1 - Products/CMFPlone/browser/__init__.py | 1 - Products/CMFPlone/browser/admin.py | 9 +- Products/CMFPlone/browser/atd.py | 3 +- Products/CMFPlone/browser/author.py | 27 +- Products/CMFPlone/browser/contact_info.py | 16 +- Products/CMFPlone/browser/defaultpage.py | 1 - Products/CMFPlone/browser/exceptions.py | 1 - .../CMFPlone/browser/global_statusmessage.py | 1 - Products/CMFPlone/browser/interfaces.py | 57 +- Products/CMFPlone/browser/login/__init__.py | 1 - Products/CMFPlone/browser/login/login.py | 37 +- Products/CMFPlone/browser/login/login_help.py | 41 +- Products/CMFPlone/browser/login/logout.py | 5 +- .../CMFPlone/browser/login/mail_password.py | 1 - .../CMFPlone/browser/login/password_reset.py | 19 +- Products/CMFPlone/browser/main_template.py | 1 - Products/CMFPlone/browser/navigation.py | 3 +- Products/CMFPlone/browser/navtree.py | 5 +- Products/CMFPlone/browser/okay.py | 3 +- Products/CMFPlone/browser/ploneview.py | 27 +- Products/CMFPlone/browser/robots.py | 1 - Products/CMFPlone/browser/search.py | 13 +- Products/CMFPlone/browser/sendto.py | 25 +- Products/CMFPlone/browser/sitelogo.py | 3 +- Products/CMFPlone/browser/sitemap.py | 1 - .../CMFPlone/browser/syndication/adapters.py | 7 +- .../CMFPlone/browser/syndication/settings.py | 3 +- Products/CMFPlone/browser/syndication/tool.py | 3 +- .../CMFPlone/browser/syndication/utils.py | 3 +- .../CMFPlone/browser/syndication/views.py | 15 +- .../CMFPlone/controlpanel/bbb/__init__.py | 1 - Products/CMFPlone/controlpanel/bbb/editing.py | 3 +- Products/CMFPlone/controlpanel/bbb/filter.py | 3 +- .../CMFPlone/controlpanel/bbb/language.py | 3 +- Products/CMFPlone/controlpanel/bbb/mail.py | 3 +- .../CMFPlone/controlpanel/bbb/maintenance.py | 3 +- Products/CMFPlone/controlpanel/bbb/markup.py | 3 +- .../CMFPlone/controlpanel/bbb/navigation.py | 3 +- Products/CMFPlone/controlpanel/bbb/search.py | 3 +- .../CMFPlone/controlpanel/bbb/security.py | 3 +- Products/CMFPlone/controlpanel/bbb/site.py | 3 +- .../CMFPlone/controlpanel/bbb/usergroups.py | 3 +- .../CMFPlone/controlpanel/browser/actions.py | 7 +- .../controlpanel/browser/dateandtime.py | 7 +- .../CMFPlone/controlpanel/browser/editing.py | 5 +- .../CMFPlone/controlpanel/browser/filter.py | 21 +- .../CMFPlone/controlpanel/browser/imaging.py | 3 +- .../CMFPlone/controlpanel/browser/language.py | 17 +- .../CMFPlone/controlpanel/browser/mail.py | 11 +- .../controlpanel/browser/maintenance.py | 39 +- .../CMFPlone/controlpanel/browser/markup.py | 5 +- .../controlpanel/browser/navigation.py | 15 +- .../CMFPlone/controlpanel/browser/overview.py | 3 +- .../controlpanel/browser/quickinstaller.py | 25 +- .../controlpanel/browser/redirects.py | 67 +- .../controlpanel/browser/resourceregistry.py | 23 +- .../CMFPlone/controlpanel/browser/search.py | 9 +- .../CMFPlone/controlpanel/browser/security.py | 3 +- .../CMFPlone/controlpanel/browser/site.py | 7 +- .../controlpanel/browser/socialmedia.py | 3 +- .../controlpanel/browser/syndication.py | 21 +- .../CMFPlone/controlpanel/browser/tinymce.py | 13 +- .../CMFPlone/controlpanel/browser/types.py | 57 +- .../controlpanel/browser/usergroups.py | 5 +- .../browser/usergroups_groupdetails.py | 21 +- .../browser/usergroups_groupmembership.py | 5 +- .../browser/usergroups_groupsoverview.py | 7 +- .../browser/usergroups_usermembership.py | 5 +- .../browser/usergroups_usersoverview.py | 13 +- Products/CMFPlone/controlpanel/events.py | 7 +- .../tests/test_controlpanel_actions.py | 1 - .../test_controlpanel_bbb_editing_adapter.py | 13 +- .../test_controlpanel_bbb_filter_adapter.py | 25 +- .../test_controlpanel_bbb_language_adapter.py | 1 - .../test_controlpanel_bbb_mail_adapter.py | 37 +- ...st_controlpanel_bbb_maintenance_adapter.py | 1 - .../test_controlpanel_bbb_markup_adapter.py | 1 - ...est_controlpanel_bbb_navigation_adapter.py | 1 - .../test_controlpanel_bbb_search_adapter.py | 1 - .../test_controlpanel_bbb_security_adapter.py | 1 - .../test_controlpanel_bbb_site_adapter.py | 21 +- ...est_controlpanel_bbb_usergroups_adapter.py | 1 - .../test_controlpanel_browser_editing.py | 3 +- .../tests/test_controlpanel_browser_filter.py | 7 +- .../test_controlpanel_browser_installer.py | 3 +- .../test_controlpanel_browser_language.py | 3 +- .../tests/test_controlpanel_browser_mail.py | 9 +- .../test_controlpanel_browser_maintenance.py | 5 +- .../tests/test_controlpanel_browser_markup.py | 3 +- .../test_controlpanel_browser_navigation.py | 3 +- .../test_controlpanel_browser_redirection.py | 77 +- .../tests/test_controlpanel_browser_search.py | 3 +- .../test_controlpanel_browser_security.py | 3 +- .../tests/test_controlpanel_browser_site.py | 39 +- .../test_controlpanel_browser_syndication.py | 3 +- .../tests/test_controlpanel_browser_types.py | 3 +- .../test_controlpanel_browser_usergroups.py | 3 +- ...panel_browser_usergroups_siteadmin_role.py | 7 +- .../tests/test_controlpanel_dateandtime.py | 1 - .../tests/test_controlpanel_doctest.py | 1 - .../tests/test_controlpanel_editing.py | 1 - .../tests/test_controlpanel_events.py | 1 - .../tests/test_controlpanel_filter.py | 1 - .../tests/test_controlpanel_installer.py | 1 - .../tests/test_controlpanel_language.py | 1 - .../tests/test_controlpanel_mail.py | 1 - .../tests/test_controlpanel_markup.py | 1 - .../tests/test_controlpanel_navigation.py | 1 - .../tests/test_controlpanel_overview.py | 3 +- .../tests/test_controlpanel_search.py | 1 - .../tests/test_controlpanel_security.py | 1 - .../tests/test_controlpanel_site.py | 1 - .../tests/test_controlpanel_types.py | 1 - .../tests/test_controlpanel_usergroups.py | 1 - .../controlpanel/tests/test_doctests.py | 1 - Products/CMFPlone/controlpanel/utils.py | 1 - Products/CMFPlone/controlpanel/widgets.py | 1 - Products/CMFPlone/defaultpage.py | 1 - Products/CMFPlone/earlypatches/security.py | 1 - Products/CMFPlone/events.py | 3 +- Products/CMFPlone/exportimport/__init__.py | 1 - .../CMFPlone/exportimport/controlpanel.py | 1 - .../exportimport/memberdata_properties.py | 1 - .../CMFPlone/exportimport/propertiestool.py | 1 - .../CMFPlone/exportimport/tests/__init__.py | 1 - Products/CMFPlone/exportimport/tests/base.py | 1 - .../exportimport/tests/testControlPanel.py | 1 - .../exportimport/tests/testPropertiesTool.py | 1 - Products/CMFPlone/factory.py | 85 +- Products/CMFPlone/i18nl10n.py | 9 +- Products/CMFPlone/interfaces/__init__.py | 1 - Products/CMFPlone/interfaces/atd.py | 1 - Products/CMFPlone/interfaces/basetool.py | 1 - Products/CMFPlone/interfaces/breadcrumbs.py | 1 - Products/CMFPlone/interfaces/constrains.py | 1 - Products/CMFPlone/interfaces/controlpanel.py | 1265 ++++++++--------- Products/CMFPlone/interfaces/defaultpage.py | 1 - Products/CMFPlone/interfaces/events.py | 1 - Products/CMFPlone/interfaces/installable.py | 1 - Products/CMFPlone/interfaces/interface.py | 1 - Products/CMFPlone/interfaces/language.py | 1 - Products/CMFPlone/interfaces/login.py | 27 +- Products/CMFPlone/interfaces/migration.py | 1 - Products/CMFPlone/interfaces/patterns.py | 1 - Products/CMFPlone/interfaces/properties.py | 1 - Products/CMFPlone/interfaces/resources.py | 77 +- Products/CMFPlone/interfaces/siteroot.py | 1 - Products/CMFPlone/interfaces/structure.py | 1 - Products/CMFPlone/interfaces/syndication.py | 79 +- .../CMFPlone/interfaces/translationservice.py | 1 - Products/CMFPlone/interfaces/workflow.py | 1 - Products/CMFPlone/log.py | 1 - Products/CMFPlone/patches/__init__.py | 1 - Products/CMFPlone/patches/addzmiplonesite.py | 1 - .../CMFPlone/patches/addzmisecuritywarning.py | 1 - Products/CMFPlone/patches/csrf.py | 1 - Products/CMFPlone/patches/dateIndexPatch.py | 1 - Products/CMFPlone/patches/gtbn.py | 1 - Products/CMFPlone/patches/iso8601.py | 1 - Products/CMFPlone/patches/publishing.py | 9 +- Products/CMFPlone/patches/sendmail.py | 1 - Products/CMFPlone/patches/speed.py | 1 - .../CMFPlone/patches/templatecookcheck.py | 1 - .../CMFPlone/patches/unicodeFallbackPatch.py | 1 - Products/CMFPlone/patches/unicodehacks.py | 10 +- Products/CMFPlone/patches/z3c_form.py | 1 - Products/CMFPlone/patterns/__init__.py | 1 - Products/CMFPlone/patterns/settings.py | 7 +- Products/CMFPlone/patterns/tinymce.py | 15 +- Products/CMFPlone/patterns/utils.py | 1 - Products/CMFPlone/patterns/view.py | 3 +- Products/CMFPlone/permissions.py | 1 - Products/CMFPlone/resources/__init__.py | 1 - .../CMFPlone/resources/browser/__init__.py | 1 - .../CMFPlone/resources/browser/combine.py | 9 +- .../CMFPlone/resources/browser/configjs.py | 7 +- Products/CMFPlone/resources/browser/cook.py | 12 +- .../CMFPlone/resources/browser/interfaces.py | 1 - Products/CMFPlone/resources/browser/mixins.py | 17 +- .../CMFPlone/resources/browser/resource.py | 5 +- .../CMFPlone/resources/browser/scripts.py | 25 +- Products/CMFPlone/resources/browser/styles.py | 15 +- Products/CMFPlone/resources/bundle.py | 5 +- .../resources/exportimport/__init__.py | 1 - .../resources/exportimport/bundles.py | 1 - .../exportimport/resourceregistry.py | 1 - Products/CMFPlone/setuphandlers.py | 3 +- .../plone_change_password.py | 12 +- .../prefs_error_log_setProperties.py | 2 +- .../plone_prefs/prefs_error_log_update.py | 6 +- .../skins/plone_scripts/external_edit.py | 4 +- .../skins/plone_scripts/queryCatalog.py | 2 +- Products/CMFPlone/testing.py | 5 +- Products/CMFPlone/tests/PloneTestCase.py | 3 +- Products/CMFPlone/tests/dummy.py | 7 +- Products/CMFPlone/tests/robot/robot_setup.py | 3 +- Products/CMFPlone/tests/robot/variables.py | 1 - Products/CMFPlone/tests/testActionsTool.py | 3 +- Products/CMFPlone/tests/testBatch.py | 3 +- Products/CMFPlone/tests/testBrowserAdmin.py | 3 +- Products/CMFPlone/tests/testBrowserDefault.py | 9 +- .../tests/testBrowserLayerPrecedence.py | 1 - Products/CMFPlone/tests/testCSRFProtection.py | 3 +- .../CMFPlone/tests/testCSSandJSRegistry.py | 1 - Products/CMFPlone/tests/testCatalogTool.py | 8 +- Products/CMFPlone/tests/testCheckId.py | 29 +- .../CMFPlone/tests/testContentPublishing.py | 1 - .../CMFPlone/tests/testContentSecurity.py | 1 - .../CMFPlone/tests/testContentTypeScripts.py | 5 +- Products/CMFPlone/tests/testControlPanel.py | 1 - .../CMFPlone/tests/testControlPanelScripts.py | 3 +- Products/CMFPlone/tests/testCookieAuth.py | 3 +- .../CMFPlone/tests/testCutPasteSecurity.py | 1 - .../CMFPlone/tests/testDateIndexRanges.py | 1 - .../CMFPlone/tests/testDateTimeIntegration.py | 1 - Products/CMFPlone/tests/testEmailLogin.py | 1 - .../tests/testExternalEditorEnabled.py | 1 - Products/CMFPlone/tests/testIImagingSchema.py | 3 +- Products/CMFPlone/tests/testInterfaces.py | 13 +- Products/CMFPlone/tests/testMigrationTool.py | 9 +- Products/CMFPlone/tests/testNavTree.py | 3 +- Products/CMFPlone/tests/testNavigationView.py | 19 +- Products/CMFPlone/tests/testNextPrevious.py | 1 - Products/CMFPlone/tests/testOrderSupport.py | 1 - Products/CMFPlone/tests/testPloneFolder.py | 1 - Products/CMFPlone/tests/testPloneTestCase.py | 1 - Products/CMFPlone/tests/testPloneTool.py | 23 +- Products/CMFPlone/tests/testPloneView.py | 11 +- Products/CMFPlone/tests/testPortalCreation.py | 15 +- Products/CMFPlone/tests/testQueryCatalog.py | 7 +- .../CMFPlone/tests/testRegistrationTool.py | 21 +- .../CMFPlone/tests/testResourceRegistries.py | 39 +- .../tests/testRestrictedAcquisition.py | 1 - Products/CMFPlone/tests/testSearch.py | 9 +- Products/CMFPlone/tests/testSecurity.py | 1 - .../tests/testSecurityDeclarations.py | 1 - Products/CMFPlone/tests/testSiteAdminRole.py | 1 - Products/CMFPlone/tests/testSyndication.py | 19 +- .../tests/testTranslationServiceTool.py | 13 +- Products/CMFPlone/tests/testURLTool.py | 1 - .../CMFPlone/tests/testUnicodeSplitter.py | 109 +- .../CMFPlone/tests/testUserFolderBasics.py | 1 - Products/CMFPlone/tests/testWebDAV.py | 7 +- Products/CMFPlone/tests/testWorkflowTool.py | 1 - Products/CMFPlone/tests/test_PloneTool.py | 7 +- Products/CMFPlone/tests/test_defaultpage.py | 21 +- Products/CMFPlone/tests/test_doctests.py | 1 - Products/CMFPlone/tests/test_error_message.py | 1 - Products/CMFPlone/tests/test_factory.py | 1 - Products/CMFPlone/tests/test_functional.py | 1 - Products/CMFPlone/tests/test_l18nl10n.py | 1 - Products/CMFPlone/tests/test_login_form.py | 15 +- Products/CMFPlone/tests/test_login_help.py | 9 +- Products/CMFPlone/tests/test_login_logout.py | 1 - Products/CMFPlone/tests/test_login_views.py | 1 - Products/CMFPlone/tests/test_mails.py | 1 - Products/CMFPlone/tests/test_metabundles.py | 1 - Products/CMFPlone/tests/test_nogopip.py | 1 - Products/CMFPlone/tests/test_okay.py | 5 +- .../CMFPlone/tests/test_patternsettings.py | 7 +- .../tests/test_redirect_after_login.py | 5 +- Products/CMFPlone/tests/test_robot.py | 1 - Products/CMFPlone/tests/test_robots_txt.py | 5 +- .../CMFPlone/tests/test_safe_formatter.py | 32 +- Products/CMFPlone/tests/test_sitelogo.py | 1 - Products/CMFPlone/tests/test_sitemap.py | 3 +- Products/CMFPlone/tests/test_utils.py | 15 +- .../CMFPlone/tests/test_z3c_form_widgets.py | 3 +- Products/CMFPlone/tests/test_zmi.py | 77 +- Products/CMFPlone/tests/utils.py | 1 - Products/CMFPlone/traversal.py | 5 +- Products/CMFPlone/unicodeconflictresolver.py | 3 +- Products/CMFPlone/utils.py | 52 +- Products/CMFPlone/workflow.py | 1 - Products/__init__.py | 1 - news/3185.misc | 3 + setup.py | 1 - 302 files changed, 1719 insertions(+), 2019 deletions(-) create mode 100644 news/3185.misc diff --git a/Products/CMFPlone/ActionsTool.py b/Products/CMFPlone/ActionsTool.py index 34314c317c..c8d4f8c92c 100644 --- a/Products/CMFPlone/ActionsTool.py +++ b/Products/CMFPlone/ActionsTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl import ClassSecurityInfo from AccessControl.class_init import InitializeClass from Products.CMFCore.ActionInformation import ActionInfo diff --git a/Products/CMFPlone/CatalogTool.py b/Products/CMFPlone/CatalogTool.py index 456cb226d0..8125b3bef1 100644 --- a/Products/CMFPlone/CatalogTool.py +++ b/Products/CMFPlone/CatalogTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl import ClassSecurityInfo from AccessControl.PermissionRole import rolesForPermissionOn from AccessControl.Permissions import manage_zcatalog_entries as ManageZCatalogEntries # noqa @@ -469,7 +468,7 @@ def search(self, query, if not self.allow_inactive(query): query['effectiveRange'] = DateTime() - return super(CatalogTool, self).search( + return super().search( query, sort_index, reverse, limit, merge) @security.protected(ManageZCatalogEntries) diff --git a/Products/CMFPlone/DublinCore.py b/Products/CMFPlone/DublinCore.py index 3ce956f9ae..8e1d12b481 100644 --- a/Products/CMFPlone/DublinCore.py +++ b/Products/CMFPlone/DublinCore.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- ############################################################################## # # Copyright (c) 2001 Zope Foundation and Contributors. @@ -47,7 +46,7 @@ def seq_strip(seq, stripper=lambda x: x.strip()): if isinstance(seq, tuple): return tuple(map(stripper, seq)) - raise ValueError("%s of unsupported sequencetype %s" % (seq, type(seq))) + raise ValueError("{} of unsupported sequencetype {}".format(seq, type(seq))) def tuplize(valueName, value, splitter=lambda x: x.split()): diff --git a/Products/CMFPlone/MigrationTool.py b/Products/CMFPlone/MigrationTool.py index 5929db4075..e3f6fac9d3 100644 --- a/Products/CMFPlone/MigrationTool.py +++ b/Products/CMFPlone/MigrationTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl import ClassSecurityInfo from AccessControl.requestmethod import postonly from AccessControl.class_init import InitializeClass @@ -24,7 +23,7 @@ _upgradePaths = {} -class Addon(object): +class Addon: """A profile or product. This is meant for core Plone packages, especially packages that @@ -47,7 +46,7 @@ def __init__(self, profile_id=None, check_module=None): self.check_module = check_module def __repr__(self): - return u'<{0} profile {1}>'.format( + return '<{} profile {}>'.format( self.__class__.__name__, self.profile_id) def safe(self): @@ -88,18 +87,18 @@ def upgrade_all(self, context): # core packages that actually have upgrade steps. # Good start is portal_setup.listProfilesWithUpgrades() ADDON_LIST = AddonList([ - Addon(profile_id=u'Products.CMFEditions:CMFEditions'), - Addon(profile_id=u'Products.CMFPlacefulWorkflow:CMFPlacefulWorkflow'), - Addon(profile_id=u'plone.app.contenttypes:default'), - Addon(profile_id=u'plone.app.dexterity:default'), - Addon(profile_id=u'plone.app.discussion:default'), - Addon(profile_id=u'plone.app.event:default'), - Addon(profile_id=u'plone.app.iterate:plone.app.iterate'), - Addon(profile_id=u'plone.app.multilingual:default'), - Addon(profile_id=u'plone.app.querystring:default'), - Addon(profile_id=u'plone.app.theming:default'), - Addon(profile_id=u'plone.app.users:default'), - Addon(profile_id=u'plone.staticresources:default'), + Addon(profile_id='Products.CMFEditions:CMFEditions'), + Addon(profile_id='Products.CMFPlacefulWorkflow:CMFPlacefulWorkflow'), + Addon(profile_id='plone.app.contenttypes:default'), + Addon(profile_id='plone.app.dexterity:default'), + Addon(profile_id='plone.app.discussion:default'), + Addon(profile_id='plone.app.event:default'), + Addon(profile_id='plone.app.iterate:plone.app.iterate'), + Addon(profile_id='plone.app.multilingual:default'), + Addon(profile_id='plone.app.querystring:default'), + Addon(profile_id='plone.app.theming:default'), + Addon(profile_id='plone.app.users:default'), + Addon(profile_id='plone.staticresources:default'), ]) diff --git a/Products/CMFPlone/PasswordResetTool.py b/Products/CMFPlone/PasswordResetTool.py index d8c57eea29..1a20755edd 100644 --- a/Products/CMFPlone/PasswordResetTool.py +++ b/Products/CMFPlone/PasswordResetTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """PasswordResetTool.py Mailback password reset product for CMF. diff --git a/Products/CMFPlone/PloneBaseTool.py b/Products/CMFPlone/PloneBaseTool.py index 514c632709..e45b6c79c1 100644 --- a/Products/CMFPlone/PloneBaseTool.py +++ b/Products/CMFPlone/PloneBaseTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl.class_init import InitializeClass from AccessControl import ClassSecurityInfo from Products.CMFPlone.interfaces import IPloneBaseTool diff --git a/Products/CMFPlone/PloneBatch.py b/Products/CMFPlone/PloneBatch.py index 68687dc93a..727a0bebff 100644 --- a/Products/CMFPlone/PloneBatch.py +++ b/Products/CMFPlone/PloneBatch.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from ZTUtils import make_query from plone.batching.batch import QuantumBatch @@ -14,7 +13,7 @@ class Batch(QuantumBatch): def __init__(self, sequence, size, start=0, end=0, orphan=0, overlap=0, pagerange=7, quantumleap=0, b_start_str='b_start'): - super(Batch, self).__init__(sequence, size, start, + super().__init__(sequence, size, start, end, orphan, overlap, pagerange, quantumleap) self.b_start_str = b_start_str @@ -41,7 +40,7 @@ def __bool__(self): __nonzero__ = __bool__ def initialize(self, start, end, size): - super(Batch, self).initialize(start, end, size) + super().initialize(start, end, size) self.pagerange, self.pagerangestart, self.pagerangeend = \ calculate_pagerange(self.pagenumber, self.numpages, self.pagerange) diff --git a/Products/CMFPlone/PloneControlPanel.py b/Products/CMFPlone/PloneControlPanel.py index b183c4bbd0..6b0d4503a7 100644 --- a/Products/CMFPlone/PloneControlPanel.py +++ b/Products/CMFPlone/PloneControlPanel.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl import ClassSecurityInfo from AccessControl.class_init import InitializeClass from App.special_dtml import DTMLFile @@ -62,16 +61,16 @@ class PloneControlPanel(PloneBaseTool, UniqueObject, group = dict( member=[ - ('Member', _(u'My Preferences')), + ('Member', _('My Preferences')), ], site=[ - ('plone-general', _(u'General')), - ('plone-content', _(u'Content')), - ('plone-users', _(u'Users')), - ('plone-security', _(u'Security')), - ('plone-advanced', _(u'Advanced')), - ('Plone', _(u'Plone Configuration')), - ('Products', _(u'Add-on Configuration')), + ('plone-general', _('General')), + ('plone-content', _('Content')), + ('plone-users', _('Users')), + ('plone-security', _('Security')), + ('plone-advanced', _('Advanced')), + ('Plone', _('Plone Configuration')), + ('Products', _('Add-on Configuration')), ] ) diff --git a/Products/CMFPlone/PloneFolder.py b/Products/CMFPlone/PloneFolder.py index 2e7ef161be..fb7624ea54 100644 --- a/Products/CMFPlone/PloneFolder.py +++ b/Products/CMFPlone/PloneFolder.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl import ClassSecurityInfo from AccessControl import Permissions from AccessControl import Unauthorized diff --git a/Products/CMFPlone/PloneTool.py b/Products/CMFPlone/PloneTool.py index 2111ecb648..5a8993c504 100644 --- a/Products/CMFPlone/PloneTool.py +++ b/Products/CMFPlone/PloneTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl import ClassSecurityInfo from AccessControl import getSecurityManager from AccessControl import Unauthorized @@ -110,8 +109,8 @@ def setMemberProperties(self, member, REQUEST=None, **properties): user.setProperties(**properties) @security.public - @deprecate(('`getSiteEncoding` is deprecated. Plone only supports UTF-8 ' - 'currently. This method always returns "utf-8"')) + @deprecate('`getSiteEncoding` is deprecated. Plone only supports UTF-8 ' + 'currently. This method always returns "utf-8"') def getSiteEncoding(self): """ Get the the site encoding, which is utf-8.""" return 'utf-8' @@ -254,7 +253,7 @@ def _renameObject(self, obj, id): parent = aq_parent(aq_inner(obj)) parent.manage_renameObject(obj.getId(), id) - def _makeTransactionNote(self, obj, msg=u''): + def _makeTransactionNote(self, obj, msg=''): # TODO Why not aq_parent()? relative_path = '/'.join( getToolByName(self, 'portal_url').getRelativeContentPath(obj)[:-1] @@ -303,7 +302,7 @@ def getIconFor(self, category, id, default=_marker, context=None): # Get an icon for an action, from its icon_expr. if context is None: context = aq_parent(self) - action_chain = '%s/%s' % (category, id) + action_chain = f'{category}/{id}' if category == 'controlpanel': tool = getToolByName(context, 'portal_controlpanel') actions = [ai for ai in tool.listActionInfos() if ai['id'] == id] @@ -908,7 +907,7 @@ def listMetaTags(self, context): exp_str = '' if eff_str or exp_str: - result['DC.date.valid_range'] = '%s - %s' % (eff_str, exp_str) + result['DC.date.valid_range'] = f'{eff_str} - {exp_str}' return result @@ -994,7 +993,7 @@ def deleteObjectsByPaths(self, paths, handle_errors=True, REQUEST=None): obj = traverse(path) obj_parent = aq_parent(aq_inner(obj)) obj_parent.manage_delObjects([obj.getId()]) - success.append('%s (%s)' % (obj.getId(), path)) + success.append(f'{obj.getId()} ({path})') except ConflictError: raise except Exception as e: diff --git a/Products/CMFPlone/Portal.py b/Products/CMFPlone/Portal.py index 4ab45109d4..60477253cb 100644 --- a/Products/CMFPlone/Portal.py +++ b/Products/CMFPlone/Portal.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from AccessControl import ClassSecurityInfo from AccessControl import Permissions from AccessControl import Unauthorized @@ -154,7 +152,7 @@ def availableLanguages(self): languages = util.getLanguageListing() languages.sort(lambda x, y: cmp(x[1], y[1])) # Put language neutral at the top. - languages.insert(0, (u'', _(u'Language neutral (site default)'))) + languages.insert(0, ('', _('Language neutral (site default)'))) return languages diff --git a/Products/CMFPlone/PropertiesTool.py b/Products/CMFPlone/PropertiesTool.py index 6412b6b85f..7ceebf2583 100644 --- a/Products/CMFPlone/PropertiesTool.py +++ b/Products/CMFPlone/PropertiesTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_parent, aq_inner from Products.CMFCore.permissions import ManagePortal from Products.CMFCore.utils import UniqueObject diff --git a/Products/CMFPlone/QuickInstallerTool.py b/Products/CMFPlone/QuickInstallerTool.py index aee3a80395..d0a4e811cd 100644 --- a/Products/CMFPlone/QuickInstallerTool.py +++ b/Products/CMFPlone/QuickInstallerTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.PloneBaseTool import PloneBaseTool import pkg_resources diff --git a/Products/CMFPlone/RegistrationTool.py b/Products/CMFPlone/RegistrationTool.py index fed2db1652..93dc132e4a 100644 --- a/Products/CMFPlone/RegistrationTool.py +++ b/Products/CMFPlone/RegistrationTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl import ClassSecurityInfo from AccessControl import getSecurityManager from AccessControl import Unauthorized @@ -80,9 +79,9 @@ def get_member_by_login_name(context, login_name, raise_exceptions=True): elif len(userids) > 1: if raise_exceptions: raise ValueError( - _(u'Multiple users found with the same login name.')) + _('Multiple users found with the same login name.')) if member is None and raise_exceptions: - raise ValueError(_(u'The username you entered could not be found.')) + raise ValueError(_('The username you entered could not be found.')) return member # seed the random number generator @@ -124,8 +123,8 @@ def _getValidEmailAddress(self, member): # assert that we can actually get an email address, otherwise # the template will be made with a blank To:, this is bad if email is None: - msg = _(u'No email address is registered for member: ' - u'${member_id}', mapping={'member_id': member.getId()}) + msg = _('No email address is registered for member: ' + '${member_id}', mapping={'member_id': member.getId()}) raise ValueError(msg) checkEmailAddress(email) @@ -188,8 +187,8 @@ def testPasswordValidity(self, password, confirm=None): return err if confirm is not None and confirm != password: - return _(u'Your password and confirmation did not match. ' - u'Please try again.') + return _('Your password and confirmation did not match. ' + 'Please try again.') return None def pasValidation(self, property, password): @@ -200,7 +199,7 @@ def pasValidation(self, property, password): if not validators: return None - err = u"" + err = "" for validator_id, validator in validators: user = None set_id = '' @@ -213,7 +212,7 @@ def pasValidation(self, property, password): if not err: err = error else: - msgid = _(u'${sentances}. ${sentance}', + msgid = _('${sentances}. ${sentance}', mapping={'sentances': err, 'sentance': error}) err = self.translate(msgid) if not err: @@ -235,20 +234,20 @@ def testPropertiesValidity(self, props, member=None): username = props.get('username', '') if not username: - return _(u'You must enter a valid name.') + return _('You must enter a valid name.') if not self.isMemberIdAllowed(username): - return _(u'The login name you selected is already in use or ' - u'is not valid. Please choose another.') + return _('The login name you selected is already in use or ' + 'is not valid. Please choose another.') email = props.get('email') if email is None: - return _(u'You must enter an email address.') + return _('You must enter an email address.') try: checkEmailAddress(email) except EmailAddressInvalid: - return _(u'You must enter a valid email address.') + return _('You must enter a valid email address.') else: # Existing member. if not hasattr(member, 'canWriteProperty') or \ @@ -261,13 +260,13 @@ def testPropertiesValidity(self, props, member=None): try: checkEmailAddress(email) except EmailAddressInvalid: - return _(u'You must enter a valid email address.') + return _('You must enter a valid email address.') # Not allowed to clear an existing non-empty email. existing = member.getProperty('email') if existing and email == '': - return _(u'You must enter a valid email address.') + return _('You must enter a valid email address.') return None @@ -334,14 +333,14 @@ def mailPassword(self, login, REQUEST, immediate=False): membership = getToolByName(self, 'portal_membership') if not membership.checkPermission('Mail forgotten password', self): raise Unauthorized( - _(u"Mailing forgotten passwords has been disabled.")) + _("Mailing forgotten passwords has been disabled.")) utils = getToolByName(self, 'plone_utils') member = get_member_by_login_name(self, login, raise_exceptions=False) if member is None: raise ValueError( - _(u'The username you entered could not be found.')) + _('The username you entered could not be found.')) # Make sure the user is allowed to set the password. portal = getToolByName(self, 'portal_url').getPortalObject() @@ -353,7 +352,7 @@ def mailPassword(self, login, REQUEST, immediate=False): tmp_sm = getSecurityManager() if not tmp_sm.checkPermission(SetOwnPassword, portal): raise Unauthorized( - _(u"Mailing forgotten passwords has been disabled.")) + _("Mailing forgotten passwords has been disabled.")) finally: setSecurityManager(orig_sm) @@ -361,11 +360,11 @@ def mailPassword(self, login, REQUEST, immediate=False): # the template will be made with a blank To:, this is bad email = member.getProperty('email') if not email: - raise ValueError(_(u'That user does not have an email address.')) + raise ValueError(_('That user does not have an email address.')) else: # add the single email address if not utils.validateSingleEmailAddress(email): - raise ValueError(_(u'The email address did not validate.')) + raise ValueError(_('The email address did not validate.')) check, msg = _checkEmail(email) if not check: raise ValueError(msg) @@ -398,7 +397,7 @@ def mailPassword(self, login, REQUEST, immediate=False): except SMTPRecipientsRefused: # Don't disclose email address on failure raise SMTPRecipientsRefused( - _(u'Recipient address rejected by server.')) + _('Recipient address rejected by server.')) except SMTPException as e: raise(e) mail_password_response = getMultiAdapter( @@ -416,12 +415,12 @@ def registeredNotify(self, new_member_id): if member and email: # add the single email address if not utils.validateSingleEmailAddress(email): - raise ValueError(_(u'The email address did not validate.')) + raise ValueError(_('The email address did not validate.')) try: checkEmailAddress(email) except EmailAddressInvalid: - raise ValueError(_(u'The email address did not validate.')) + raise ValueError(_('The email address did not validate.')) pwrt = getToolByName(self, 'portal_password_reset') reset = pwrt.requestReset(new_member_id) @@ -492,7 +491,7 @@ def editMember(self, member_id, properties=None, password=None, class EmailAddressInvalid(ValidationError): - __doc__ = _(u'Invalid email address.') + __doc__ = _('Invalid email address.') def _checkEmail(address): diff --git a/Products/CMFPlone/SkinsTool.py b/Products/CMFPlone/SkinsTool.py index e005375774..f4ade43b53 100644 --- a/Products/CMFPlone/SkinsTool.py +++ b/Products/CMFPlone/SkinsTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl import ClassSecurityInfo from AccessControl.class_init import InitializeClass from Products.CMFCore.permissions import ManagePortal @@ -19,7 +18,7 @@ class SkinsTool(PloneBaseTool, BaseTool): def addSkinSelection(self, skinname, skinpath, test=0, make_default=0): # Adds a skin selection. - super(SkinsTool, self).addSkinSelection(skinname, skinpath, + super().addSkinSelection(skinname, skinpath, test=test, make_default=make_default) security.declareProtected(ManagePortal, 'manage_skinLayers') @@ -28,7 +27,7 @@ def manage_skinLayers(self, chosen=(), add_skin=0, del_skin=0, skinname='', skinpath='', REQUEST=None): """ Change the skinLayers. """ - response = super(SkinsTool, self).manage_skinLayers(chosen=chosen, + response = super().manage_skinLayers(chosen=chosen, add_skin=add_skin, del_skin=del_skin, skinname=skinname, skinpath=skinpath, REQUEST=REQUEST) return response diff --git a/Products/CMFPlone/TranslationServiceTool.py b/Products/CMFPlone/TranslationServiceTool.py index 952491e0eb..6298e3b69e 100644 --- a/Products/CMFPlone/TranslationServiceTool.py +++ b/Products/CMFPlone/TranslationServiceTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ This tool requires a translation service which supports the translate method and the default parameter. diff --git a/Products/CMFPlone/TypesTool.py b/Products/CMFPlone/TypesTool.py index a6e30edff3..cf94213cdd 100644 --- a/Products/CMFPlone/TypesTool.py +++ b/Products/CMFPlone/TypesTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl import ClassSecurityInfo from AccessControl.class_init import InitializeClass diff --git a/Products/CMFPlone/URLTool.py b/Products/CMFPlone/URLTool.py index f8523d0177..c7d22bf174 100644 --- a/Products/CMFPlone/URLTool.py +++ b/Products/CMFPlone/URLTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl import ClassSecurityInfo from Acquisition import aq_inner from Acquisition import aq_parent diff --git a/Products/CMFPlone/UnicodeSplitter/__init__.py b/Products/CMFPlone/UnicodeSplitter/__init__.py index ed51353de2..43cc6c727f 100644 --- a/Products/CMFPlone/UnicodeSplitter/__init__.py +++ b/Products/CMFPlone/UnicodeSplitter/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ __init__.py diff --git a/Products/CMFPlone/UnicodeSplitter/config.py b/Products/CMFPlone/UnicodeSplitter/config.py index 773c6065e8..980053bb94 100644 --- a/Products/CMFPlone/UnicodeSplitter/config.py +++ b/Products/CMFPlone/UnicodeSplitter/config.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ config.py @@ -15,7 +14,7 @@ # digit=u"\d", # U+AC00-D7AF Hangul Syllables ハングル音節文字 - hangul=u"\uAC00-\uD7AF", + hangul="\uAC00-\uD7AF", # U+30A0-30FF Katakana 片仮名 # U+3040-309F Hiragana 平仮名 @@ -28,8 +27,8 @@ # U+F900-FAFF CJK Compatibility Ideographs CJK互換漢字 # ideo=u"\u4E00-\u9FFF\u3400-\u4DBF\uF900-\uFAFF", - cj=u"\u3040-\u30FF\u4E00-\u9FFF\u3400-\u4DBF\uF900-\uFAFF", - thai=u"\u0E00-\u0E7F", # U+0E00-0E7F Thai タイ文字 + cj="\u3040-\u30FF\u4E00-\u9FFF\u3400-\u4DBF\uF900-\uFAFF", + thai="\u0E00-\u0E7F", # U+0E00-0E7F Thai タイ文字 ) # End of setting. @@ -37,8 +36,8 @@ # Splitting core. ps = rangetable.values() allp = "".join(ps) -glob_true = r"[^%s]([^%s]|[\*\?])*|" % (allp, allp) + \ - "|".join(["[%s]+" % (x, ) for x in ps]) +glob_true = fr"[^{allp}]([^{allp}]|[\*\?])*|" + \ + "|".join([f"[{x}]+" for x in ps]) glob_false = r"[^%s]+|" % allp + "|".join("[%s]+" % x for x in ps) diff --git a/Products/CMFPlone/UnicodeSplitter/splitter.py b/Products/CMFPlone/UnicodeSplitter/splitter.py index e4225d0cca..22c8460e31 100644 --- a/Products/CMFPlone/UnicodeSplitter/splitter.py +++ b/Products/CMFPlone/UnicodeSplitter/splitter.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- """ splitter.py @@ -46,7 +45,7 @@ def process_str_post(s, enc='utf-8'): except UnicodeDecodeError: return s.replace("?", "").replace("*", "") try: - return uni.replace(u"?", u"").replace(u"*", u"").encode(enc, "strict") + return uni.replace("?", "").replace("*", "").encode(enc, "strict") except UnicodeEncodeError: return s.replace("?", "").replace("*", "") @@ -98,8 +97,7 @@ def process_unicode(uni): if not rx_all.match(sword[0]): yield sword else: - for x in bigram(sword, 0): - yield x + yield from bigram(sword, 0) def process_unicode_glob(uni): @@ -109,7 +107,7 @@ def process_unicode_glob(uni): normalized = unicodedata.normalize('NFKC', uni) for word in rxGlob_U.findall(normalized): swords = [g.group() for g in pattern_g.finditer(word) - if g.group() not in u"*?"] + if g.group() not in "*?"] for i, sword in enumerate(swords): if not rx_all.match(sword[0]): yield sword @@ -119,15 +117,14 @@ def process_unicode_glob(uni): else: limit = 0 if len(sword) == 1: - bigramed = [sword + u"*"] + bigramed = [sword + "*"] else: bigramed = bigram(sword, limit) - for x in bigramed: - yield x + yield from bigramed @implementer(ISplitter) -class Splitter(object): +class Splitter: def process(self, lst): """ Will be called when indexing. @@ -162,7 +159,7 @@ def process_post_glob(self, lst): pass -class CaseNormalizer(object): +class CaseNormalizer: def process(self, lst): enc = 'utf-8' @@ -192,7 +189,7 @@ def process(self, lst): pass -class I18NNormalizer(object): +class I18NNormalizer: def process(self, lst): enc = 'utf-8' diff --git a/Products/CMFPlone/WorkflowTool.py b/Products/CMFPlone/WorkflowTool.py index ae8eebbab5..31a9cf8203 100644 --- a/Products/CMFPlone/WorkflowTool.py +++ b/Products/CMFPlone/WorkflowTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.component import getMultiAdapter from Products.CMFCore.utils import getToolByName @@ -329,7 +328,7 @@ def listWFStatesByTitle(self, filter_similar=False): states.extend(state_folder.values()) else: for state in state_folder.values(): - key = '%s:%s' % (state.id, state.title) + key = f'{state.id}:{state.title}' if not key in dup_list: states.append(state) dup_list[key] = 1 diff --git a/Products/CMFPlone/__init__.py b/Products/CMFPlone/__init__.py index a97b5e38d0..b78c455324 100644 --- a/Products/CMFPlone/__init__.py +++ b/Products/CMFPlone/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from App.ImageFile import ImageFile import os import sys diff --git a/Products/CMFPlone/_compat.py b/Products/CMFPlone/_compat.py index 8766b687df..283564f68a 100644 --- a/Products/CMFPlone/_compat.py +++ b/Products/CMFPlone/_compat.py @@ -1,4 +1,3 @@ -# coding=utf-8 from json import dumps diff --git a/Products/CMFPlone/bbb.py b/Products/CMFPlone/bbb.py index 411dc19e3a..ee3d242008 100644 --- a/Products/CMFPlone/bbb.py +++ b/Products/CMFPlone/bbb.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import pkg_resources HAS_ZSERVER = True diff --git a/Products/CMFPlone/browser/__init__.py b/Products/CMFPlone/browser/__init__.py index 2bcec87d04..5a8ff9e0ad 100644 --- a/Products/CMFPlone/browser/__init__.py +++ b/Products/CMFPlone/browser/__init__.py @@ -1,2 +1 @@ -# -*- coding: utf-8 -*- # browser package diff --git a/Products/CMFPlone/browser/admin.py b/Products/CMFPlone/browser/admin.py index 6ad54bbacf..6fab229341 100644 --- a/Products/CMFPlone/browser/admin.py +++ b/Products/CMFPlone/browser/admin.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl import getSecurityManager from AccessControl.Permissions import view as View from OFS.interfaces import IApplication @@ -164,7 +163,7 @@ def profiles(self): def _key(v): # Make sure implicitly selected items come first selected = v.get('selected') and 'automatic' or 'manual' - return '%s-%s' % (selected, v.get('title', '')) + return '{}-{}'.format(selected, v.get('title', '')) extension_profiles.sort(key=_key) for info in profile_registry.listProfileInfo(): @@ -213,7 +212,7 @@ def grouped_languages(self, default='en'): langs = struct['languages'] langs.append({ 'langcode': langcode, - 'label': data.get(u'native', data.get(u'name')), + 'label': data.get('native', data.get('name')), }) grouped[lang] = struct @@ -236,7 +235,7 @@ def timezones(self): for value in tz_values: splitted = value.split('/') group = splitted.pop(0) - label = u'/'.join(splitted) + label = '/'.join(splitted) entries = grouped.get(group, []) entries.append({'label': label or group, 'value': value}) @@ -273,7 +272,7 @@ def __call__(self): portal_timezone=form.get('portal_timezone', 'UTC') ) self.request.response.redirect(site.absolute_url()) - return u'' + return '' return self.index() diff --git a/Products/CMFPlone/browser/atd.py b/Products/CMFPlone/browser/atd.py index 22efd78de6..05fe5a35c2 100644 --- a/Products/CMFPlone/browser/atd.py +++ b/Products/CMFPlone/browser/atd.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFCore.utils import getToolByName from zope.component import getUtility from plone.registry.interfaces import IRegistry @@ -9,7 +8,7 @@ @implementer(IATDProxyView) -class ATDProxyView(object): +class ATDProxyView: """ Proxy for the 'After the Deadline' spellchecker """ diff --git a/Products/CMFPlone/browser/author.py b/Products/CMFPlone/browser/author.py index a30fc8b944..3247e3585c 100644 --- a/Products/CMFPlone/browser/author.py +++ b/Products/CMFPlone/browser/author.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl import Unauthorized from Products.CMFCore.interfaces import IPropertiesTool @@ -38,12 +37,12 @@ class AuthorFeedbackForm(form.Form): fields = field.Fields(IAuthorFeedbackForm) ignoreContext = True - @button.buttonAndHandler(_(u'label_send', default='Send'), + @button.buttonAndHandler(_('label_send', default='Send'), name='send') def handle_send(self, action): self.portal_state = getMultiAdapter( (self.context, self.request), - name=u'plone_portal_state' + name='plone_portal_state' ) self.portal = self.portal_state.portal() @@ -59,7 +58,7 @@ def handle_send(self, action): if errors: IStatusMessage(self.request).addStatusMessage( self.formErrorsMessage, - type=u'error' + type='error' ) return @@ -85,12 +84,12 @@ def handle_send(self, action): if send_from_address == '': IStatusMessage(self.request).addStatusMessage( - _(u'Could not find a valid email address'), - type=u'error' + _('Could not find a valid email address'), + type='error' ) return - sender_id = "%s (%s), %s" % ( + sender_id = "{} ({}), {}".format( sender.getProperty('fullname'), sender.getId(), send_from_address @@ -120,17 +119,17 @@ def handle_send(self, action): logger.info("Unable to send mail: " + str(e)) IStatusMessage(self.request).addStatusMessage( - _(u'Unable to send mail.'), - type=u'error' + _('Unable to send mail.'), + type='error' ) return IStatusMessage(self.request).addStatusMessage( - _(u'Mail sent.'), - type=u'info' + _('Mail sent.'), + type='info' ) - self.request.response.redirect('%s/author/%s' % ( + self.request.response.redirect('{}/author/{}'.format( self.portal.absolute_url(), author or '')) return @@ -140,7 +139,7 @@ def handle_send(self, action): class AuthorView(BrowserView): def __init__(self, context, request): - super(AuthorView, self).__init__(context, request) + super().__init__(context, request) self.username = None @@ -235,7 +234,7 @@ def __call__(self): self.portal_state = getMultiAdapter( (self.context, self.request), - name=u'plone_portal_state' + name='plone_portal_state' ) self.feedback_form = AuthorFeedbackForm( diff --git a/Products/CMFPlone/browser/contact_info.py b/Products/CMFPlone/browser/contact_info.py index 72eacdb566..9d8067f323 100644 --- a/Products/CMFPlone/browser/contact_info.py +++ b/Products/CMFPlone/browser/contact_info.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from Products.CMFCore.utils import getToolByName from Products.CMFPlone import PloneMessageFactory as _ from Products.CMFPlone.browser.interfaces import IContactForm @@ -35,13 +33,13 @@ def mailhost_is_configured(self): return False return True - @button.buttonAndHandler(_(u'label_send', default='Send'), name='send') + @button.buttonAndHandler(_('label_send', default='Send'), name='send') def handle_send(self, action): data, errors = self.extractData() if errors: IStatusMessage(self.request).add( self.formErrorsMessage, - type=u'error' + type='error' ) return @@ -84,12 +82,12 @@ def send_message(self, data): log.error(e) plone_utils = getToolByName(portal, 'plone_utils') exception = plone_utils.exceptionString() - message = _(u'Unable to send mail: ${exception}', - mapping={u'exception': exception}) - IStatusMessage(self.request).add(message, type=u'error') + message = _('Unable to send mail: ${exception}', + mapping={'exception': exception}) + IStatusMessage(self.request).add(message, type='error') def send_feedback(self): IStatusMessage(self.request).add( - _(u'A mail has now been sent to the site administrator ' - u'regarding your questions and/or comments.') + _('A mail has now been sent to the site administrator ' + 'regarding your questions and/or comments.') ) diff --git a/Products/CMFPlone/browser/defaultpage.py b/Products/CMFPlone/browser/defaultpage.py index c998711046..57446ec69a 100644 --- a/Products/CMFPlone/browser/defaultpage.py +++ b/Products/CMFPlone/browser/defaultpage.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_inner from Products.CMFPlone.interfaces.defaultpage import IDefaultPage from Products.CMFPlone.defaultpage import get_default_page diff --git a/Products/CMFPlone/browser/exceptions.py b/Products/CMFPlone/browser/exceptions.py index 8ee7944bf2..7c3825c53e 100644 --- a/Products/CMFPlone/browser/exceptions.py +++ b/Products/CMFPlone/browser/exceptions.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl import getSecurityManager from plone.memoize.view import memoize from Products.Five import BrowserView diff --git a/Products/CMFPlone/browser/global_statusmessage.py b/Products/CMFPlone/browser/global_statusmessage.py index 915a399175..552bc9e4af 100644 --- a/Products/CMFPlone/browser/global_statusmessage.py +++ b/Products/CMFPlone/browser/global_statusmessage.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.interface import implementer from Products.Five import BrowserView diff --git a/Products/CMFPlone/browser/interfaces.py b/Products/CMFPlone/browser/interfaces.py index be1164f9d4..404b172258 100644 --- a/Products/CMFPlone/browser/interfaces.py +++ b/Products/CMFPlone/browser/interfaces.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope import schema from zope.interface import Interface @@ -296,26 +295,26 @@ class ISendToForm(Interface): """ Interface for describing the 'sendto' form """ send_to_address = Email( - title=_(u'label_send_to_mail', - default=u'Send to'), - description=_(u'help_send_to_mail', - default=u'The e-mail address to send this link to.'), + title=_('label_send_to_mail', + default='Send to'), + description=_('help_send_to_mail', + default='The e-mail address to send this link to.'), required=True ) send_from_address = Email( - title=_(u'label_send_from', - default=u'From'), - description=_(u'help_send_from', - default=u'Your email address.'), + title=_('label_send_from', + default='From'), + description=_('help_send_from', + default='Your email address.'), required=True ) comment = schema.Text( - title=_(u'label_comment', - default=u'Comment'), - description=_(u'help_comment_to_link', - default=u'A comment about this link.'), + title=_('label_comment', + default='Comment'), + description=_('help_comment_to_link', + default='A comment about this link.'), required=False ) @@ -324,32 +323,32 @@ class IContactForm(Interface): """ Interface for describing the contact info form """ sender_fullname = schema.TextLine( - title=_(u'label_sender_fullname', - default=u'Name'), - description=_(u'help_sender_fullname', - default=u'Please enter your full name.'), + title=_('label_sender_fullname', + default='Name'), + description=_('help_sender_fullname', + default='Please enter your full name.'), required=True ) sender_from_address = Email( - title=_(u'label_sender_from_address', - default=u'From'), - description=_(u'help_sender_from_address', - default=u'Please enter your e-mail address.'), + title=_('label_sender_from_address', + default='From'), + description=_('help_sender_from_address', + default='Please enter your e-mail address.'), required=True ) subject = schema.TextLine( - title=_(u'label_subject', - default=u'Subject'), + title=_('label_subject', + default='Subject'), required=True ) message = schema.Text( - title=_(u'label_message', - default=u'Message'), - description=_(u'help_message', - default=u'Please enter the message you want to send.'), + title=_('label_message', + default='Message'), + description=_('help_message', + default='Please enter the message you want to send.'), required=False ) @@ -358,12 +357,12 @@ class IAuthorFeedbackForm(Interface): """ Interface describing the author feedback form """ subject = schema.TextLine( - title=_('label_subject', default=u'Subject'), + title=_('label_subject', default='Subject'), required=True ) message = schema.Text( - title=_('label_message', default=u'Message'), + title=_('label_message', default='Message'), required=True ) diff --git a/Products/CMFPlone/browser/login/__init__.py b/Products/CMFPlone/browser/login/__init__.py index 40a96afc6f..e69de29bb2 100644 --- a/Products/CMFPlone/browser/login/__init__.py +++ b/Products/CMFPlone/browser/login/__init__.py @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- diff --git a/Products/CMFPlone/browser/login/login.py b/Products/CMFPlone/browser/login/login.py index 1e0020b2c2..2add8a3122 100644 --- a/Products/CMFPlone/browser/login/login.py +++ b/Products/CMFPlone/browser/login/login.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from DateTime import DateTime from plone.app.users.browser.passwordpanel import PasswordPanel from plone.registry.interfaces import IRegistry @@ -53,7 +52,7 @@ class LoginForm(form.EditForm): fields = field.Fields(ILoginFormSchema) id = 'LoginForm' - label = _('label_log_in', default=u'Log in') + label = _('label_log_in', default='Log in') ignoreContext = True prefix = '' @@ -103,11 +102,11 @@ def updateWidgets(self): self.fields['ac_name'].__name__ = fieldname_name self.fields['ac_password'].__name__ = fieldname_password - super(LoginForm, self).updateWidgets(prefix='') + super().updateWidgets(prefix='') if self.use_email_as_login(): - self.widgets[fieldname_name].label = _(u'label_email', - default=u'Email') + self.widgets[fieldname_name].label = _('label_email', + default='Email') self.widgets['came_from'].mode = HIDDEN_MODE self.widgets['came_from'].value = self.get_came_from() @@ -127,7 +126,7 @@ def get_came_from(self): return came_from def updateActions(self): - super(LoginForm, self).updateActions() + super().updateActions() self.actions['login'].addClass('context') def _post_login(self): @@ -160,16 +159,16 @@ def handleLogin(self, action): if self.use_email_as_login(): status_msg.addStatusMessage( _( - u'Login failed. Both email address and password are ' - u'case sensitive, check that caps lock is not enabled.' + 'Login failed. Both email address and password are ' + 'case sensitive, check that caps lock is not enabled.' ), 'error', ) else: status_msg.addStatusMessage( _( - u'Login failed. Both login name and password are case ' - u'sensitive, check that caps lock is not enabled.' + 'Login failed. Both login name and password are case ' + 'sensitive, check that caps lock is not enabled.' ), 'error', ) @@ -178,8 +177,8 @@ def handleLogin(self, action): is_initial_login = self._post_login() status_msg.addStatusMessage( _( - u'you_are_now_logged_in', - default=u'Welcome! You are now logged in.', + 'you_are_now_logged_in', + default='Welcome! You are now logged in.', ), 'info' ) @@ -247,12 +246,12 @@ def __call__(self): ) portal = portal_state.portal() if portal_state.anonymous(): - url = '{0:s}/login'.format(portal.absolute_url()) + url = f'{portal.absolute_url():s}/login' came_from = self.request.get('came_from', None) if came_from: - url += '?came_from={0:s}'.format(parse.quote(came_from)) + url += '?came_from={:s}'.format(parse.quote(came_from)) else: - url = '{0:s}/insufficient-privileges'.format(portal.absolute_url()) + url = f'{portal.absolute_url():s}/insufficient-privileges' self.request.response.redirect(url) @@ -269,11 +268,11 @@ def render(self): return self.index() @button.buttonAndHandler( - _(u'label_change_password', default=u'Change Password'), + _('label_change_password', default='Change Password'), name='reset_passwd', ) def action_reset_passwd(self, action): - super(InitialLoginPasswordChange, self).action_reset_passwd( + super().action_reset_passwd( self, action) if not action.form.widgets.errors: self.request.response.redirect(self.context.portal_url()) @@ -285,11 +284,11 @@ def render(self): return self.index() @button.buttonAndHandler( - _(u'label_change_password', default=u'Change Password'), + _('label_change_password', default='Change Password'), name='reset_passwd', ) def action_reset_passwd(self, action): - super(ForcedPasswordChange, self).action_reset_passwd(self, action) + super().action_reset_passwd(self, action) if not action.form.widgets.errors: membership_tool = getToolByName(self.context, 'portal_membership') member = membership_tool.getAuthenticatedMember() diff --git a/Products/CMFPlone/browser/login/login_help.py b/Products/CMFPlone/browser/login/login_help.py index 98f58f39dc..96d9b5bbbc 100644 --- a/Products/CMFPlone/browser/login/login_help.py +++ b/Products/CMFPlone/browser/login/login_help.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from email import message_from_string from email.header import Header from plone.registry.interfaces import IRegistry @@ -24,7 +23,7 @@ import logging -SEND_USERNAME_TEMPLATE = _(u"mailtemplate_username_info", default=u"""From: {encoded_mail_sender} +SEND_USERNAME_TEMPLATE = _("mailtemplate_username_info", default="""From: {encoded_mail_sender} To: {email} Subject: Your username for {portal_url} Content-Type: text/plain @@ -48,22 +47,22 @@ class RequestResetPassword(form.Form): id = 'RequestResetPassword' - label = u'' + label = '' fields = field.Fields(ILoginHelpFormSchema).select('reset_password') ignoreContext = True render = ViewPageTemplateFile('templates/subform_render.pt') def updateWidgets(self): - super(RequestResetPassword, self).updateWidgets() + super().updateWidgets() if self.use_email_as_login(): self.widgets['reset_password'].label = _( - u'label_email', - default=u'Email' + 'label_email', + default='Email' ) @button.buttonAndHandler( - _(u'button_pwreset_reset_password', default=u'Reset your password'), + _('button_pwreset_reset_password', default='Reset your password'), name='reset' ) def handleResetPassword(self, action): @@ -79,13 +78,13 @@ def handleResetPassword(self, action): # Paranoia Warning! # We act as if a message has been sent to prevent probing Plone # for valid loginnames. Instead we log the error-message. - log.info('Error while trying to send a reset-password notice to user {0}: {1}'.format(data['reset_password'], e)) # noqa: E501 + log.info('Error while trying to send a reset-password notice to user {}: {}'.format(data['reset_password'], e)) # noqa: E501 pass IStatusMessage(self.request).addStatusMessage( - _(u'statusmessage_pwreset_password_mail_sent', default=u'An ' - u'email has been sent with instructions on how to reset your ' - u'password.'), 'info') + _('statusmessage_pwreset_password_mail_sent', default='An ' + 'email has been sent with instructions on how to reset your ' + 'password.'), 'info') def use_email_as_login(self): registry = getUtility(IRegistry) @@ -97,14 +96,14 @@ def use_email_as_login(self): class RequestUsername(form.Form): id = 'RequestUsername' - label = u'' + label = '' fields = field.Fields(ILoginHelpFormSchema).select('recover_username') ignoreContext = True render = ViewPageTemplateFile('templates/subform_render.pt') @button.buttonAndHandler( - _(u'button_pwreset_get_username', default='Get your username'), + _('button_pwreset_get_username', default='Get your username'), name='get_username' ) def handleGetUsername(self, action): @@ -118,10 +117,10 @@ def handleGetUsername(self, action): results = pas.searchUsers(email=email, exact_match=True) send_email = True if not results: - log.info('No user found for {0}'.format(email)) + log.info(f'No user found for {email}') send_email = False if len(results) > 1: - log.info('More than one user found for {0}'.format(email)) + log.info(f'More than one user found for {email}') send_email = False if send_email: self.send_username(portal, results[0]) @@ -132,8 +131,8 @@ def handleGetUsername(self, action): # Because of this we always act as if that an email has been sent. # Instead we log the error-message. IStatusMessage(self.request).addStatusMessage( - _(u'statusmessage_pwreset_username_mail_sent', - default=u'An email has been sent with your username.'), + _('statusmessage_pwreset_username_mail_sent', + default='An email has been sent with your username.'), 'info' ) @@ -167,7 +166,7 @@ def send_username(self, portal, userinfo): except SMTPRecipientsRefused: # Don't disclose email address on failure raise SMTPRecipientsRefused( - _(u'Recipient address rejected by server.')) + _('Recipient address rejected by server.')) except SMTPException as e: raise(e) @@ -181,7 +180,7 @@ def encoded_mail_sender(self): mail_settings = registry.forInterface(IMailSchema, prefix="plone") from_ = mail_settings.email_from_name mail = mail_settings.email_from_address - return '"%s" <%s>' % (self.encode_mail_header(from_), mail) + return '"{}" <{}>'.format(self.encode_mail_header(from_), mail) @implementer(ILoginHelpForm) @@ -191,7 +190,7 @@ class LoginHelpForm(form.EditForm): subforms = [] id = 'LoginHelpForm' - label = _(u'heading_login_form_help', default=u'Need Help?') + label = _('heading_login_form_help', default='Need Help?') ignoreContext = True @@ -219,7 +218,7 @@ def update(self): subforms.append(form) self.subforms = subforms - super(LoginHelpForm, self).update() + super().update() def use_email_as_login(self): registry = getUtility(IRegistry) diff --git a/Products/CMFPlone/browser/login/logout.py b/Products/CMFPlone/browser/login/logout.py index 83f4e22fd0..8a986e6136 100644 --- a/Products/CMFPlone/browser/login/logout.py +++ b/Products/CMFPlone/browser/login/logout.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.registry.interfaces import IRegistry from Products.CMFCore.utils import getToolByName from Products.CMFPlone import PloneMessageFactory as _ @@ -49,8 +48,8 @@ def __call__(self): self.request ).addStatusMessage( _( - u'statusmessage_logged_out', - default=u'You are now logged out.' + 'statusmessage_logged_out', + default='You are now logged out.' ), 'info', ) diff --git a/Products/CMFPlone/browser/login/mail_password.py b/Products/CMFPlone/browser/login/mail_password.py index 670eacff48..7281d222ec 100644 --- a/Products/CMFPlone/browser/login/mail_password.py +++ b/Products/CMFPlone/browser/login/mail_password.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl import Unauthorized from Products.CMFPlone import PloneMessageFactory as _ from Products.Five import BrowserView diff --git a/Products/CMFPlone/browser/login/password_reset.py b/Products/CMFPlone/browser/login/password_reset.py index 54610c2f28..7594dc5461 100644 --- a/Products/CMFPlone/browser/login/password_reset.py +++ b/Products/CMFPlone/browser/login/password_reset.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl.SecurityManagement import getSecurityManager from email.header import Header from plone.app.layout.navigation.interfaces import INavigationRoot @@ -35,7 +34,7 @@ def portal_state(self): """ return portal_state of plone.app.layout """ return getMultiAdapter((self.context, self.request), - name=u"plone_portal_state") + name="plone_portal_state") def encode_mail_header(self, text): """ Encodes text into correctly encoded email header """ @@ -47,14 +46,14 @@ def encoded_mail_sender(self): mail_settings = registry.forInterface(IMailSchema, prefix="plone") from_ = mail_settings.email_from_name mail = mail_settings.email_from_address - return '"%s" <%s>' % (self.encode_mail_header(from_).encode(), mail) + return '"{}" <{}>'.format(self.encode_mail_header(from_).encode(), mail) def registered_notify_subject(self): portal_name = self.portal_state().portal_title() return translate( _( - u'mailtemplate_user_account_info', - default=u'User Account Information for ${portal_name}', + 'mailtemplate_user_account_info', + default='User Account Information for ${portal_name}', mapping={'portal_name': safe_unicode(portal_name)}, ), context=self.request, @@ -63,14 +62,14 @@ def registered_notify_subject(self): def mail_password_subject(self): return translate( _( - u'mailtemplate_subject_resetpasswordrequest', - default=u'Password reset request', + 'mailtemplate_subject_resetpasswordrequest', + default='Password reset request', ), context=self.request, ) def construct_url(self, randomstring): - return '%s/passwordreset/%s' % ( + return '{}/passwordreset/{}'.format( self.portal_state().navigation_root_url(), randomstring) def expiration_timeout(self): @@ -200,8 +199,8 @@ def getErrors(self): def login_url(self): portal_state = getMultiAdapter((self.context, self.request), - name=u"plone_portal_state") - return '{0}/login?__ac_name={1}'.format( + name="plone_portal_state") + return '{}/login?__ac_name={}'.format( portal_state.navigation_root_url(), self.request.form.get('userid', '')) diff --git a/Products/CMFPlone/browser/main_template.py b/Products/CMFPlone/browser/main_template.py index dc1b07de6b..707ca21284 100644 --- a/Products/CMFPlone/browser/main_template.py +++ b/Products/CMFPlone/browser/main_template.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.browser.interfaces import IMainTemplate from Products.Five import BrowserView from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile diff --git a/Products/CMFPlone/browser/navigation.py b/Products/CMFPlone/browser/navigation.py index 40c73a101a..2c57508c21 100644 --- a/Products/CMFPlone/browser/navigation.py +++ b/Products/CMFPlone/browser/navigation.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_base from Acquisition import aq_inner from plone.app.layout.navigation.interfaces import INavtreeStrategy @@ -125,7 +124,7 @@ def topLevelTabs(self, actions=None, category='portal_tabs'): if actions is None: context_state = getMultiAdapter( (context, self.request), - name=u'plone_context_state' + name='plone_context_state' ) actions = context_state.actions(category) diff --git a/Products/CMFPlone/browser/navtree.py b/Products/CMFPlone/browser/navtree.py index b6575605d6..3a0a0aee34 100644 --- a/Products/CMFPlone/browser/navtree.py +++ b/Products/CMFPlone/browser/navtree.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # This module contains a function to help build navigation-tree-like structures # from catalog queries. It also contains a standard implementation of the # strategy/filtering method that uses Plone's navtree_properties to construct @@ -28,7 +27,7 @@ @implementer(INavigationQueryBuilder) -class NavtreeQueryBuilder(object): +class NavtreeQueryBuilder: """Build a navtree query based on the settings in navtree_properties """ @@ -152,7 +151,7 @@ def decoratorFactory(self, node): (portalType is None or portalType not in self.parentTypesNQ): showChildren = True - layout_view = getMultiAdapter((context, request), name=u'plone_layout') + layout_view = getMultiAdapter((context, request), name='plone_layout') newNode['Title'] = utils.pretty_title_or_id(context, item) newNode['id'] = item.getId diff --git a/Products/CMFPlone/browser/okay.py b/Products/CMFPlone/browser/okay.py index e4cea76cc0..eeaae619ab 100644 --- a/Products/CMFPlone/browser/okay.py +++ b/Products/CMFPlone/browser/okay.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.Five.browser import BrowserView @@ -24,4 +23,4 @@ def __call__(self): set_header('Expires', 'Sat, 1 Jan 2000 00:00:00 GMT') set_header('Cache-Control', 'max-age=0, must-revalidate, private') # Return a short and simple message. - return u'OK' + return 'OK' diff --git a/Products/CMFPlone/browser/ploneview.py b/Products/CMFPlone/browser/ploneview.py index b67c288713..7bae74eb74 100644 --- a/Products/CMFPlone/browser/ploneview.py +++ b/Products/CMFPlone/browser/ploneview.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_inner from plone.memoize.view import memoize from Products.CMFCore.utils import getToolByName @@ -133,77 +132,77 @@ def site_encoding(self): def getCurrentUrl(self): context_state = getMultiAdapter( (aq_inner(self.context), self.request), - name=u'plone_context_state') + name='plone_context_state') return context_state.current_page_url() def isDefaultPageInFolder(self): context_state = getMultiAdapter( (aq_inner(self.context), self.request), - name=u'plone_context_state') + name='plone_context_state') return context_state.is_default_page() def isStructuralFolder(self): context_state = getMultiAdapter( (aq_inner(self.context), self.request), - name=u'plone_context_state') + name='plone_context_state') return context_state.is_structural_folder() def navigationRootPath(self): portal_state = getMultiAdapter( (aq_inner(self.context), self.request), - name=u'plone_portal_state') + name='plone_portal_state') return portal_state.navigation_root_path() def navigationRootUrl(self): portal_state = getMultiAdapter( (aq_inner(self.context), self.request), - name=u'plone_portal_state') + name='plone_portal_state') return portal_state.navigation_root_url() def getParentObject(self): context_state = getMultiAdapter( (aq_inner(self.context), self.request), - name=u'plone_context_state') + name='plone_context_state') return context_state.parent() def getCurrentFolder(self): context_state = getMultiAdapter( (aq_inner(self.context), self.request), - name=u'plone_context_state') + name='plone_context_state') return context_state.folder() def getCurrentFolderUrl(self): context_state = getMultiAdapter( (aq_inner(self.context), self.request), - name=u'plone_context_state') + name='plone_context_state') return context_state.folder().absolute_url() @memoize def getCurrentObjectUrl(self): context_state = getMultiAdapter( (aq_inner(self.context), self.request), - name=u'plone_context_state') + name='plone_context_state') return context_state.canonical_object_url() @memoize def isFolderOrFolderDefaultPage(self): state = getMultiAdapter( (aq_inner(self.context), self.request), - name=u'plone_context_state') + name='plone_context_state') return state.is_structural_folder() or state.is_default_page() @memoize def isPortalOrPortalDefaultPage(self): context_state = getMultiAdapter( (aq_inner(self.context), self.request), - name=u'plone_context_state') + name='plone_context_state') return context_state.is_portal_root() @memoize def getViewTemplateId(self): context_state = getMultiAdapter( (aq_inner(self.context), self.request), - name=u'plone_context_state') + name='plone_context_state') return context_state.view_template_id() @memoize @@ -211,4 +210,4 @@ def patterns_settings(self): context = aq_inner(self.context) return getMultiAdapter( (context, self.request), - name=u'plone_patterns_settings')() + name='plone_patterns_settings')() diff --git a/Products/CMFPlone/browser/robots.py b/Products/CMFPlone/browser/robots.py index 17646cf11c..9c5a0bc290 100644 --- a/Products/CMFPlone/browser/robots.py +++ b/Products/CMFPlone/browser/robots.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces.controlpanel import ISiteSchema from Products.Five.browser import BrowserView from plone.registry.interfaces import IRegistry diff --git a/Products/CMFPlone/browser/search.py b/Products/CMFPlone/browser/search.py index 81f0071f83..2be9ddf3cc 100644 --- a/Products/CMFPlone/browser/search.py +++ b/Products/CMFPlone/browser/search.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from DateTime import DateTime from plone.app.contentlisting.interfaces import IContentListing from plone.registry.interfaces import IRegistry @@ -22,7 +21,7 @@ # We should accept both a simple space, unicode u'\u0020 but also a # multi-space, so called 'waji-kankaku', unicode u'\u3000' -MULTISPACE = u'\u3000' +MULTISPACE = '\u3000' BAD_CHARS = ('?', '-', '+', '*', MULTISPACE) EVER = DateTime('1970-01-03') @@ -182,11 +181,11 @@ def sort_options(self): if 'sort_on' not in self.request.form: self.request.form['sort_on'] = self.default_sort_on return ( - SortOption(self.request, _(u'relevance'), 'relevance'), + SortOption(self.request, _('relevance'), 'relevance'), SortOption( - self.request, _(u'date (newest first)'), 'Date', reverse=True + self.request, _('date (newest first)'), 'Date', reverse=True ), - SortOption(self.request, _(u'alphabetically'), 'sortable_title'), + SortOption(self.request, _('alphabetically'), 'sortable_title'), ) def show_advanced_search(self): @@ -221,7 +220,7 @@ def breadcrumbs(self, item): return None if len(breadcrumbs) > 3: # if we have too long breadcrumbs, emit the middle elements - empty = {'absolute_url': '', 'Title': u'…'} + empty = {'absolute_url': '', 'Title': '…'} breadcrumbs = [breadcrumbs[0], empty] + breadcrumbs[-2:] return breadcrumbs @@ -272,7 +271,7 @@ def __call__(self): }) -class SortOption(object): +class SortOption: def __init__(self, request, title, sortkey='', reverse=False): self.request = request diff --git a/Products/CMFPlone/browser/sendto.py b/Products/CMFPlone/browser/sendto.py index 2b36b7b095..1f11b22084 100644 --- a/Products/CMFPlone/browser/sendto.py +++ b/Products/CMFPlone/browser/sendto.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone import PloneMessageFactory as _ from Products.CMFPlone.interfaces.controlpanel import IMailSchema from Products.CMFPlone.utils import pretty_title_or_id @@ -25,27 +24,27 @@ class SendToForm(form.Form): - label = _(u'heading_send_page_to', - default=u'Send this page to someone') + label = _('heading_send_page_to', + default='Send this page to someone') - description = _(u'description_send_page_url_to', - default=u'Fill in the email address of your ' - u'friend, and we will send an email ' - u'that contains a link to this page.') + description = _('description_send_page_url_to', + default='Fill in the email address of your ' + 'friend, and we will send an email ' + 'that contains a link to this page.') fields = field.Fields(ISendToForm) ignoreContext = True mail_template = ViewPageTemplateFile('templates/sendto_template.pt') - @button.buttonAndHandler(_(u'label_send', default='Send'), + @button.buttonAndHandler(_('label_send', default='Send'), name='send') def handle_send(self, action): data, errors = self.extractData() if errors: IStatusMessage(self.request).addStatusMessage( self.formErrorsMessage, - type=u'error' + type='error' ) return @@ -97,14 +96,14 @@ def handle_send(self, action): # TODO To many things could possibly go wrong. So we catch all. logger.info("Unable to send mail: " + str(e)) IStatusMessage(self.request).addStatusMessage( - _(u'Unable to send mail.'), - type=u'error' + _('Unable to send mail.'), + type='error' ) return IStatusMessage(self.request).addStatusMessage( - _(u'Mail sent.'), - type=u'info' + _('Mail sent.'), + type='info' ) send_to_form = layout.wrap_form(SendToForm) diff --git a/Products/CMFPlone/browser/sitelogo.py b/Products/CMFPlone/browser/sitelogo.py index 2c003b4624..2d56feebeb 100644 --- a/Products/CMFPlone/browser/sitelogo.py +++ b/Products/CMFPlone/browser/sitelogo.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import ISiteSchema from plone.formwidget.namedfile.converter import b64decode_file from plone.namedfile.browser import Download @@ -10,7 +9,7 @@ class SiteLogo(Download): def __init__(self, context, request): - super(SiteLogo, self).__init__(context, request) + super().__init__(context, request) self.filename = None self.data = None diff --git a/Products/CMFPlone/browser/sitemap.py b/Products/CMFPlone/browser/sitemap.py index 3322ddc9f0..08b7071994 100644 --- a/Products/CMFPlone/browser/sitemap.py +++ b/Products/CMFPlone/browser/sitemap.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_inner from zope.component import getMultiAdapter from zope.interface import implementer diff --git a/Products/CMFPlone/browser/syndication/adapters.py b/Products/CMFPlone/browser/syndication/adapters.py index 88e066a98f..66150efd5e 100644 --- a/Products/CMFPlone/browser/syndication/adapters.py +++ b/Products/CMFPlone/browser/syndication/adapters.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.component.hooks import getSite from zope.component import adapts from zope.interface import implementer @@ -37,7 +36,7 @@ class IFileContent(Interface): pass -class BaseFeedData(object): +class BaseFeedData: def __init__(self, context): self.context = context @@ -289,7 +288,7 @@ class DexterityItem(BaseItem): field_name = '' def __init__(self, context, feed): - super(DexterityItem, self).__init__(context, feed) + super().__init__(context, feed) self.dexterity = IDexterityContent.providedBy(context) lead = ILeadImage(self.context, None) if lead: @@ -316,7 +315,7 @@ def file_url(self): if fi is not None: filename = fi.filename if filename: - url += '/@@download/%s/%s' % ( + url += '/@@download/{}/{}'.format( self.field_name, filename) return url diff --git a/Products/CMFPlone/browser/syndication/settings.py b/Products/CMFPlone/browser/syndication/settings.py index a7a639e2ca..d74865d070 100644 --- a/Products/CMFPlone/browser/syndication/settings.py +++ b/Products/CMFPlone/browser/syndication/settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.component import adapts from zope.interface import implementer from Products.CMFPlone.interfaces.syndication import IFeedSettings @@ -13,7 +12,7 @@ @implementer(IFeedSettings) -class FeedSettings(object): +class FeedSettings: adapts(ISyndicatable) def __init__(self, context): diff --git a/Products/CMFPlone/browser/syndication/tool.py b/Products/CMFPlone/browser/syndication/tool.py index a9dfe69720..d142ebaa61 100644 --- a/Products/CMFPlone/browser/syndication/tool.py +++ b/Products/CMFPlone/browser/syndication/tool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_parent from AccessControl import Unauthorized @@ -20,7 +19,7 @@ @implementer(ISyndicationTool) -class SyndicationTool(object): +class SyndicationTool: """ Backward compatible tool. This just implements what some other packages use for now to provide diff --git a/Products/CMFPlone/browser/syndication/utils.py b/Products/CMFPlone/browser/syndication/utils.py index 27b3e6fcba..3115b10976 100644 --- a/Products/CMFPlone/browser/syndication/utils.py +++ b/Products/CMFPlone/browser/syndication/utils.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zExceptions import NotFound from Products.Five import BrowserView @@ -35,7 +34,7 @@ def rss_url(self): if len(types) == 0: return url _type = types[0] - return '%s/%s' % (url, _type) + return f'{url}/{_type}' def context_allowed(self): if not ISyndicatable.providedBy(self.context): diff --git a/Products/CMFPlone/browser/syndication/views.py b/Products/CMFPlone/browser/syndication/views.py index cf1a13d92c..47c40db01c 100644 --- a/Products/CMFPlone/browser/syndication/views.py +++ b/Products/CMFPlone/browser/syndication/views.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from DateTime import DateTime from plone.z3cform.layout import wrap_form from Products.CMFPlone import PloneMessageFactory as _ @@ -31,7 +30,7 @@ def __call__(self): util = getMultiAdapter((self.context, self.request), name='syndication-util') context_state = getMultiAdapter((self.context, self.request), - name=u'plone_context_state') + name='plone_context_state') if context_state.is_portal_root() or util.context_enabled(raise404=True): settings = IFeedSettings(self.context) if self.__name__ not in settings.feed_types: @@ -79,16 +78,16 @@ def get_image(self, item): class SettingsForm(form.EditForm): - label = _(u'heading_syndication_properties', - default=u'Syndication Properties') + label = _('heading_syndication_properties', + default='Syndication Properties') description = _( - u'description_syndication_properties', - default=u'Syndication enables you to syndicate this folder so it can' - u'be synchronized from other web sites.', + 'description_syndication_properties', + default='Syndication enables you to syndicate this folder so it can' + 'be synchronized from other web sites.', ) fields = field.Fields(IFeedSettings) - @button.buttonAndHandler(_(u'Save'), name='save') + @button.buttonAndHandler(_('Save'), name='save') def handleSave(self, action): data, errors = self.extractData() if errors: diff --git a/Products/CMFPlone/controlpanel/bbb/__init__.py b/Products/CMFPlone/controlpanel/bbb/__init__.py index 5941601bc4..e69de29bb2 100644 --- a/Products/CMFPlone/controlpanel/bbb/__init__.py +++ b/Products/CMFPlone/controlpanel/bbb/__init__.py @@ -1 +0,0 @@ -# -*- coding: utf-8 -*-` diff --git a/Products/CMFPlone/controlpanel/bbb/editing.py b/Products/CMFPlone/controlpanel/bbb/editing.py index 38600a52ef..54058116a6 100644 --- a/Products/CMFPlone/controlpanel/bbb/editing.py +++ b/Products/CMFPlone/controlpanel/bbb/editing.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.component import adapts from zope.interface import implementer from zope.component import getUtility @@ -9,7 +8,7 @@ @implementer(IEditingSchema) -class EditingControlPanelAdapter(object): +class EditingControlPanelAdapter: adapts(IPloneSiteRoot) diff --git a/Products/CMFPlone/controlpanel/bbb/filter.py b/Products/CMFPlone/controlpanel/bbb/filter.py index ed40da0423..f0d6fc7777 100644 --- a/Products/CMFPlone/controlpanel/bbb/filter.py +++ b/Products/CMFPlone/controlpanel/bbb/filter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import IFilterSchema from Products.CMFPlone.interfaces import IPloneSiteRoot from plone.registry.interfaces import IRegistry @@ -8,7 +7,7 @@ @implementer(IFilterSchema) -class FilterControlPanelAdapter(object): +class FilterControlPanelAdapter: adapts(IPloneSiteRoot) diff --git a/Products/CMFPlone/controlpanel/bbb/language.py b/Products/CMFPlone/controlpanel/bbb/language.py index 08e40adc32..43700a1cd9 100644 --- a/Products/CMFPlone/controlpanel/bbb/language.py +++ b/Products/CMFPlone/controlpanel/bbb/language.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.component import adapts from zope.interface import implementer from zope.component import getUtility @@ -9,7 +8,7 @@ @implementer(ILanguageSchema) -class LanguageControlPanelAdapter(object): +class LanguageControlPanelAdapter: adapts(IPloneSiteRoot) diff --git a/Products/CMFPlone/controlpanel/bbb/mail.py b/Products/CMFPlone/controlpanel/bbb/mail.py index 91a2bcb385..9fb79f65ba 100644 --- a/Products/CMFPlone/controlpanel/bbb/mail.py +++ b/Products/CMFPlone/controlpanel/bbb/mail.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import IPloneSiteRoot from Products.CMFPlone.interfaces.controlpanel import IMailSchema from Products.CMFPlone.utils import safe_hasattr @@ -10,7 +9,7 @@ @implementer(IMailSchema) -class MailControlPanelAdapter(object): +class MailControlPanelAdapter: adapts(IPloneSiteRoot) diff --git a/Products/CMFPlone/controlpanel/bbb/maintenance.py b/Products/CMFPlone/controlpanel/bbb/maintenance.py index f316cdcf13..491f6c5d9a 100644 --- a/Products/CMFPlone/controlpanel/bbb/maintenance.py +++ b/Products/CMFPlone/controlpanel/bbb/maintenance.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import IMaintenanceSchema from Products.CMFPlone.interfaces import IPloneSiteRoot from plone.registry.interfaces import IRegistry @@ -8,7 +7,7 @@ @implementer(IMaintenanceSchema) -class MaintenanceControlPanelAdapter(object): +class MaintenanceControlPanelAdapter: adapts(IPloneSiteRoot) diff --git a/Products/CMFPlone/controlpanel/bbb/markup.py b/Products/CMFPlone/controlpanel/bbb/markup.py index 9bf578b8c1..23b4279955 100644 --- a/Products/CMFPlone/controlpanel/bbb/markup.py +++ b/Products/CMFPlone/controlpanel/bbb/markup.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import IMarkupSchema from Products.CMFPlone.interfaces.siteroot import IPloneSiteRoot from plone.registry.interfaces import IRegistry @@ -8,7 +7,7 @@ @implementer(IMarkupSchema) -class MarkupControlPanelAdapter(object): +class MarkupControlPanelAdapter: adapts(IPloneSiteRoot) diff --git a/Products/CMFPlone/controlpanel/bbb/navigation.py b/Products/CMFPlone/controlpanel/bbb/navigation.py index ba396a72e0..0cd58b5234 100644 --- a/Products/CMFPlone/controlpanel/bbb/navigation.py +++ b/Products/CMFPlone/controlpanel/bbb/navigation.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.registry.interfaces import IRegistry from Products.CMFPlone.interfaces import INavigationSchema from Products.CMFPlone.interfaces import IPloneSiteRoot @@ -9,7 +8,7 @@ @adapter(IPloneSiteRoot) @implementer(INavigationSchema) -class NavigationControlPanelAdapter(object): +class NavigationControlPanelAdapter: def __init__(self, context): self.context = context diff --git a/Products/CMFPlone/controlpanel/bbb/search.py b/Products/CMFPlone/controlpanel/bbb/search.py index 40745cb424..c5633ed877 100644 --- a/Products/CMFPlone/controlpanel/bbb/search.py +++ b/Products/CMFPlone/controlpanel/bbb/search.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import ISearchSchema from Products.CMFPlone.interfaces.siteroot import IPloneSiteRoot from plone.registry.interfaces import IRegistry @@ -9,7 +8,7 @@ @implementer(ISearchSchema) -class SearchControlPanelAdapter(object): +class SearchControlPanelAdapter: adapts(IPloneSiteRoot) diff --git a/Products/CMFPlone/controlpanel/bbb/security.py b/Products/CMFPlone/controlpanel/bbb/security.py index 4d5dcfc6d7..977b43f81f 100644 --- a/Products/CMFPlone/controlpanel/bbb/security.py +++ b/Products/CMFPlone/controlpanel/bbb/security.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFCore.utils import getToolByName from Products.CMFPlone.interfaces.siteroot import IPloneSiteRoot from Products.CMFPlone.interfaces import ISecuritySchema @@ -10,7 +9,7 @@ @implementer(ISecuritySchema) -class SecurityControlPanelAdapter(object): +class SecurityControlPanelAdapter: adapts(IPloneSiteRoot) diff --git a/Products/CMFPlone/controlpanel/bbb/site.py b/Products/CMFPlone/controlpanel/bbb/site.py index 0a72e985d2..486c2e10c3 100644 --- a/Products/CMFPlone/controlpanel/bbb/site.py +++ b/Products/CMFPlone/controlpanel/bbb/site.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.schema.fieldproperty import FieldProperty from Products.CMFPlone.interfaces import IPloneSiteRoot from Products.CMFPlone.interfaces import ISiteSchema @@ -9,7 +8,7 @@ @implementer(ISiteSchema) -class SiteControlPanelAdapter(object): +class SiteControlPanelAdapter: adapts(IPloneSiteRoot) diff --git a/Products/CMFPlone/controlpanel/bbb/usergroups.py b/Products/CMFPlone/controlpanel/bbb/usergroups.py index 365beca9a8..7df8393eff 100644 --- a/Products/CMFPlone/controlpanel/bbb/usergroups.py +++ b/Products/CMFPlone/controlpanel/bbb/usergroups.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.component import adapts from zope.component import getUtility from zope.interface import implementer @@ -9,7 +8,7 @@ @implementer(IUserGroupsSettingsSchema) -class UserGroupsSettingsControlPanelAdapter(object): +class UserGroupsSettingsControlPanelAdapter: adapts(IPloneSiteRoot) diff --git a/Products/CMFPlone/controlpanel/browser/actions.py b/Products/CMFPlone/controlpanel/browser/actions.py index 636489b521..35a64900ce 100644 --- a/Products/CMFPlone/controlpanel/browser/actions.py +++ b/Products/CMFPlone/controlpanel/browser/actions.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.autoform.form import AutoExtensibleForm from Products.CMFCore.ActionInformation import Action from Products.CMFCore.interfaces import IAction, IActionCategory @@ -70,7 +69,7 @@ def __call__(self): @implementer(IActionSchema) -class ActionControlPanelAdapter(object): +class ActionControlPanelAdapter: """Adapter for action form.""" adapts(IAction) @@ -168,7 +167,7 @@ class ActionControlPanel(AutoExtensibleForm, form.EditForm): schema = IActionSchema ignoreContext = False - label = _(u'Action Settings') + label = _('Action Settings') class NewActionControlPanel(AutoExtensibleForm, form.AddForm): @@ -176,7 +175,7 @@ class NewActionControlPanel(AutoExtensibleForm, form.AddForm): schema = INewActionSchema ignoreContext = True - label = _(u'New action') + label = _('New action') def createAndAdd(self, data): portal_actions = getToolByName(self.context, 'portal_actions') diff --git a/Products/CMFPlone/controlpanel/browser/dateandtime.py b/Products/CMFPlone/controlpanel/browser/dateandtime.py index fcbb42d0bc..5059ec631f 100644 --- a/Products/CMFPlone/controlpanel/browser/dateandtime.py +++ b/Products/CMFPlone/controlpanel/browser/dateandtime.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone import PloneMessageFactory as _ from Products.CMFPlone.interfaces import IDateAndTimeSchema from plone.app.registry.browser.controlpanel import ControlPanelFormWrapper @@ -11,10 +10,10 @@ class DateAndTimeControlPanelForm(RegistryEditForm): schema = IDateAndTimeSchema schema_prefix = "plone" - label = _(u"label_dateandtime_settings", default=u"Date and Time Settings") + label = _("label_dateandtime_settings", default="Date and Time Settings") description = _( - u"help_event_settings", - default=u"Date and Time related settings like timezone(s), etc." + "help_event_settings", + default="Date and Time related settings like timezone(s), etc." ) diff --git a/Products/CMFPlone/controlpanel/browser/editing.py b/Products/CMFPlone/controlpanel/browser/editing.py index ca40477f8e..1ea069e011 100644 --- a/Products/CMFPlone/controlpanel/browser/editing.py +++ b/Products/CMFPlone/controlpanel/browser/editing.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone import PloneMessageFactory as _ from Products.CMFPlone.interfaces import IEditingSchema from plone.app.registry.browser import controlpanel @@ -8,12 +7,12 @@ class EditingControlPanelForm(controlpanel.RegistryEditForm): id = "EditingControlPanel" - label = _(u"Editing Settings") + label = _("Editing Settings") schema = IEditingSchema schema_prefix = "plone" def updateWidgets(self): - super(EditingControlPanelForm, self).updateWidgets() + super().updateWidgets() # hide the available_editors field/widgets self.widgets['available_editors'].mode = interfaces.HIDDEN_MODE diff --git a/Products/CMFPlone/controlpanel/browser/filter.py b/Products/CMFPlone/controlpanel/browser/filter.py index 8c822d8551..e867f340ca 100644 --- a/Products/CMFPlone/controlpanel/browser/filter.py +++ b/Products/CMFPlone/controlpanel/browser/filter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.registry.browser import controlpanel from plone.z3cform import layout from Products.CMFPlone import PloneMessageFactory as _ # NOQA @@ -10,15 +9,15 @@ class FilterControlPanel(controlpanel.RegistryEditForm): id = "FilterControlPanel" - label = _(u"HTML Filtering Settings") + label = _("HTML Filtering Settings") description = _("Keep in mind that editors like TinyMCE might have " "additional filters.") schema = IFilterSchema schema_prefix = "plone" - form_name = _(u"HTML Filtering Settings") + form_name = _("HTML Filtering Settings") control_panel_view = "filter-controlpanel" - @button.buttonAndHandler(_(u"Save"), name='save') + @button.buttonAndHandler(_("Save"), name='save') def handleSave(self, action): # NOQA data, errors = self.extractData() if errors: @@ -27,21 +26,21 @@ def handleSave(self, action): # NOQA self.applyChanges(data) IStatusMessage(self.request).addStatusMessage( - _(u"Changes saved."), + _("Changes saved."), "info") IStatusMessage(self.request).addStatusMessage( - _(u"HTML generation is heavily cached across Plone. You may " - u"have to edit existing content or restart your server to see " - u"the changes."), + _("HTML generation is heavily cached across Plone. You may " + "have to edit existing content or restart your server to see " + "the changes."), "warning") self.request.response.redirect(self.request.getURL()) - @button.buttonAndHandler(_(u"Cancel"), name='cancel') + @button.buttonAndHandler(_("Cancel"), name='cancel') def handleCancel(self, action): IStatusMessage(self.request).addStatusMessage( - _(u"Changes canceled."), + _("Changes canceled."), "info") - self.request.response.redirect("%s/%s" % ( + self.request.response.redirect("{}/{}".format( self.context.absolute_url(), self.control_panel_view)) diff --git a/Products/CMFPlone/controlpanel/browser/imaging.py b/Products/CMFPlone/controlpanel/browser/imaging.py index 368e5dfd22..71e7e58c2e 100644 --- a/Products/CMFPlone/controlpanel/browser/imaging.py +++ b/Products/CMFPlone/controlpanel/browser/imaging.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone import PloneMessageFactory as _ from Products.CMFPlone.interfaces.controlpanel import IImagingSchema from logging import getLogger @@ -10,7 +9,7 @@ class ImagingControlPanelForm(controlpanel.RegistryEditForm): id = "ImagingSettings" - label = _(u"Image Handling Settings") + label = _("Image Handling Settings") schema = IImagingSchema schema_prefix = "plone" diff --git a/Products/CMFPlone/controlpanel/browser/language.py b/Products/CMFPlone/controlpanel/browser/language.py index 644acbc974..4c8714ae9c 100644 --- a/Products/CMFPlone/controlpanel/browser/language.py +++ b/Products/CMFPlone/controlpanel/browser/language.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone import PloneMessageFactory as _ from plone.app.registry.browser import controlpanel @@ -10,15 +9,15 @@ class LanguageControlPanelForm(controlpanel.RegistryEditForm): id = "LanguageControlPanel" - label = _(u"heading_language_settings", default="Language Settings") - description = _(u"description_language_settings", + label = _("heading_language_settings", default="Language Settings") + description = _("description_language_settings", default="Settings related to interface languages and " "content translations.") schema = ILanguageSchema schema_prefix = "plone" - @button.buttonAndHandler(_(u"Save"), name='save') + @button.buttonAndHandler(_("Save"), name='save') def handleSave(self, action): data, errors = self.extractData() if errors: @@ -28,7 +27,7 @@ def handleSave(self, action): if 'default_language' in data and 'available_languages' in data and \ data['default_language'] not in data['available_languages']: IStatusMessage(self.request).addStatusMessage( - _(u"Default language not in available languages"), + _("Default language not in available languages"), "error") # e = Invalid(_(u"Default language not in available languages")) @@ -37,16 +36,16 @@ def handleSave(self, action): self.applyChanges(data) IStatusMessage(self.request).addStatusMessage( - _(u"Changes saved."), + _("Changes saved."), "info") self.request.response.redirect(self.request.getURL()) - @button.buttonAndHandler(_(u"Cancel"), name='cancel') + @button.buttonAndHandler(_("Cancel"), name='cancel') def handleCancel(self, action): IStatusMessage(self.request).addStatusMessage( - _(u"Changes canceled."), + _("Changes canceled."), "info") - self.request.response.redirect("%s/%s" % ( + self.request.response.redirect("{}/{}".format( self.context.absolute_url(), self.control_panel_view)) diff --git a/Products/CMFPlone/controlpanel/browser/mail.py b/Products/CMFPlone/controlpanel/browser/mail.py index 1ad7e04e3e..ea1769d253 100644 --- a/Products/CMFPlone/controlpanel/browser/mail.py +++ b/Products/CMFPlone/controlpanel/browser/mail.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFCore.utils import getToolByName from Products.CMFPlone import PloneMessageFactory as _ from Products.CMFPlone.interfaces.controlpanel import IMailSchema @@ -20,7 +19,7 @@ class MailControlPanelForm(controlpanel.RegistryEditForm): id = "MailControlPanel" - label = _(u"Mail Settings") + label = _("Mail Settings") schema = IMailSchema schema_prefix = "plone" @@ -30,7 +29,7 @@ def handleSave(self, action): @button.buttonAndHandler(_('Cancel'), name='cancel') def handleCancel(self, action): - super(MailControlPanelForm, self).handleCancel(self, action) + super().handleCancel(self, action) def save(self): data, errors = self.extractData() @@ -82,17 +81,17 @@ def handle_test_action(self, action): charset=email_charset, immediate=True) - except (socket.error, MailHostError, smtplib.SMTPException): + except (OSError, MailHostError, smtplib.SMTPException): # Connection refused or timeout. log.exception('Unable to send test e-mail.') value = sys.exc_info()[1] - msg = _(u'Unable to send test e-mail ${error}.', + msg = _('Unable to send test e-mail ${error}.', mapping={'error': str(value)}) IStatusMessage(self.request).addStatusMessage( msg, type='error') else: IStatusMessage(self.request).addStatusMessage( - _(u'Success! Check your mailbox for the test message.'), + _('Success! Check your mailbox for the test message.'), type='info') finally: # Restore timeout to default value diff --git a/Products/CMFPlone/controlpanel/browser/maintenance.py b/Products/CMFPlone/controlpanel/browser/maintenance.py index 275c735e12..d3b82f96c5 100644 --- a/Products/CMFPlone/controlpanel/browser/maintenance.py +++ b/Products/CMFPlone/controlpanel/browser/maintenance.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl import getSecurityManager from AccessControl.Permissions import view_management_screens from Acquisition import aq_inner @@ -38,9 +37,9 @@ class MaintenanceControlPanel(AutoExtensibleForm, form.EditForm): schema = IMaintenanceSchema id = "maintenance-control-panel" - label = _(u'Maintenance Settings') - description = _(u"Zope server and site maintenance options.") - form_name = _(u'Zope Database Packing') + label = _('Maintenance Settings') + description = _("Zope server and site maintenance options.") + form_name = _('Zope Database Packing') control_panel_view = "maintenance-controlpanel" template = ViewPageTemplateFile('maintenance.pt') @@ -48,10 +47,10 @@ class MaintenanceControlPanel(AutoExtensibleForm, form.EditForm): def portal(self): portal_state = getMultiAdapter( (aq_inner(self.context), self.request), - name=u'plone_portal_state') + name='plone_portal_state') return portal_state.portal() - @button.buttonAndHandler(_(u'Pack database now'), name='pack') + @button.buttonAndHandler(_('Pack database now'), name='pack') def handle_pack_action(self, action): data, errors = self.extractData() if errors: @@ -60,8 +59,8 @@ def handle_pack_action(self, action): CheckAuthenticator(self.request) if not self.available(): self.status = _( - u'text_not_allowed_manage_server', - default=u'You are not allowed to manage the Zope server.' + 'text_not_allowed_manage_server', + default='You are not allowed to manage the Zope server.' ) return @@ -71,15 +70,15 @@ def handle_pack_action(self, action): db = self.portal()._p_jar.db() t = time.time() - (days * 86400) db.pack(t) - self.status = _(u'Packed the database.') + self.status = _('Packed the database.') - @button.buttonAndHandler(_(u'Shut down'), name='shutdown') + @button.buttonAndHandler(_('Shut down'), name='shutdown') def handle_shutdown_action(self, action): CheckAuthenticator(self.request) if not self.available(): self.status = _( - u'text_not_allowed_manage_server', - default=u'You are not allowed to manage the Zope server.' + 'text_not_allowed_manage_server', + default='You are not allowed to manage the Zope server.' ) return try: @@ -93,17 +92,17 @@ def handle_shutdown_action(self, action): raise # TODO: returning html has no effect in button handlers self.request.response.setHeader('X-Theme-Disabled', 'True') - return """{0}""".format( + return """{}""".format( _('plone_shutdown', default="Zope is shutting down.") ) - @button.buttonAndHandler(_(u'Restart'), name='restart') + @button.buttonAndHandler(_('Restart'), name='restart') def handle_restart_action(self, action): CheckAuthenticator(self.request) if not self.available(): self.status = _( - u'text_not_allowed_manage_server', - default=u'You are not allowed to manage the Zope server.' + 'text_not_allowed_manage_server', + default='You are not allowed to manage the Zope server.' ) return @@ -117,12 +116,12 @@ def handle_restart_action(self, action): # TODO: returning html has no effect in button handlers self.request.response.setHeader('X-Theme-Disabled', 'True') return """ - - {1}""".format( + + {}""".format( escape(url, 1), _('plone_restarting', - default=u"Zope is restarting. This page will refresh in 30" - u" seconds...") + default="Zope is restarting. This page will refresh in 30" + " seconds...") ) def available(self): diff --git a/Products/CMFPlone/controlpanel/browser/markup.py b/Products/CMFPlone/controlpanel/browser/markup.py index 78be678417..c78d345d59 100644 --- a/Products/CMFPlone/controlpanel/browser/markup.py +++ b/Products/CMFPlone/controlpanel/browser/markup.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone import PloneMessageFactory as _ from Products.CMFPlone.interfaces import IMarkupSchema from plone.app.registry.browser import controlpanel @@ -8,12 +7,12 @@ class MarkupControlPanelForm(controlpanel.RegistryEditForm): id = "MarkupControlPanel" - label = _(u"Markup Settings") + label = _("Markup Settings") schema = IMarkupSchema schema_prefix = "plone" def updateFields(self): - super(MarkupControlPanelForm, self).updateFields() + super().updateFields() self.fields['allowed_types'].widgetFactory = \ CheckBoxFieldWidget diff --git a/Products/CMFPlone/controlpanel/browser/navigation.py b/Products/CMFPlone/controlpanel/browser/navigation.py index 377b2e8040..7e4955f3d5 100644 --- a/Products/CMFPlone/controlpanel/browser/navigation.py +++ b/Products/CMFPlone/controlpanel/browser/navigation.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone import PloneMessageFactory as _ from Products.CMFPlone.interfaces import INavigationSchema from plone.app.registry.browser import controlpanel @@ -8,18 +7,18 @@ class NavigationControlPanelForm(controlpanel.RegistryEditForm): id = "NavigationControlPanel" - label = _(u"Navigation Settings") + label = _("Navigation Settings") description = _( - u"Lets you control how navigation is constructed in your site. " + - u"Note that to control how the navigation tree is displayed, you " + - u"should go to 'Manage portlets' at the root of the site (or " + - u"wherever a navigation tree portlet has been added) and change " + - u"its settings directly.") + "Lets you control how navigation is constructed in your site. " + + "Note that to control how the navigation tree is displayed, you " + + "should go to 'Manage portlets' at the root of the site (or " + + "wherever a navigation tree portlet has been added) and change " + + "its settings directly.") schema = INavigationSchema schema_prefix = "plone" def updateFields(self): - super(NavigationControlPanelForm, self).updateFields() + super().updateFields() self.fields['displayed_types'].widgetFactory = \ CheckBoxFieldWidget self.fields['workflow_states_to_show'].widgetFactory = \ diff --git a/Products/CMFPlone/controlpanel/browser/overview.py b/Products/CMFPlone/controlpanel/browser/overview.py index b10a0edcbd..208fded1e9 100644 --- a/Products/CMFPlone/controlpanel/browser/overview.py +++ b/Products/CMFPlone/controlpanel/browser/overview.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl import getSecurityManager from Acquisition import aq_inner from App.config import getConfiguration @@ -73,7 +72,7 @@ def version_overview(self): core_versions = self.core_versions() versions = [ - 'Plone %s (%s)' % (core_versions['Plone'], + 'Plone {} ({})'.format(core_versions['Plone'], core_versions['Plone Instance'])] for v in ('CMF', 'Zope', 'Python'): diff --git a/Products/CMFPlone/controlpanel/browser/quickinstaller.py b/Products/CMFPlone/controlpanel/browser/quickinstaller.py index cb4b0a4ac6..44d6451acc 100644 --- a/Products/CMFPlone/controlpanel/browser/quickinstaller.py +++ b/Products/CMFPlone/controlpanel/browser/quickinstaller.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFCore.utils import getToolByName from Products.CMFPlone import PloneMessageFactory as _ from Products.CMFPlone.interfaces import INonInstallable @@ -23,7 +22,7 @@ class InstallerView(BrowserView): """ def __init__(self, *args, **kwargs): - super(InstallerView, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.ps = getToolByName(self.context, 'portal_setup') self.errors = {} @@ -254,8 +253,8 @@ def is_product_installable(self, product_id, allow_hidden=False): # A new error is found, register it self.errors[product_id] = dict( type=_( - u"dependency_missing", - default=u"Missing dependency" + "dependency_missing", + default="Missing dependency" ), value=e.args[0], product_id=product_id @@ -263,8 +262,8 @@ def is_product_installable(self, product_id, allow_hidden=False): else: self.errors[product_id] = dict( type=_( - u"dependency_missing", - default=u"Missing dependency" + "dependency_missing", + default="Missing dependency" ), value=e.args[0], product_id=product_id @@ -666,14 +665,14 @@ def __call__(self): result = self.upgrade_product(product_id) if not result: messages.addStatusMessage( - _(u'Error upgrading ${product}.', + _('Error upgrading ${product}.', mapping={'product': product_id}), type="error") # Abort changes for all upgrades. transaction.abort() break else: messages.addStatusMessage( - _(u'Upgraded products.'), type="info") + _('Upgraded products.'), type="info") purl = getToolByName(self.context, 'portal_url')() self.request.response.redirect(purl + '/prefs_install_products_form') @@ -688,14 +687,14 @@ def __call__(self): msg_type = 'info' result = self.install_product(product_id) if result: - msg = _(u'Installed ${product}!', + msg = _('Installed ${product}!', mapping={'product': product_id}) else: # Only reason should be that between loading the page and # clicking to install a product, another user has already # installed this product. msg_type = 'error' - msg = _(u'Failed to install ${product}.', + msg = _('Failed to install ${product}.', mapping={'product': product_id}) messages.addStatusMessage(msg, type=msg_type) @@ -714,16 +713,16 @@ def __call__(self): except Exception as e: logger.error("Could not uninstall %s: %s", product_id, e) msg_type = 'error' - msg = _(u'Error uninstalling ${product}.', mapping={ + msg = _('Error uninstalling ${product}.', mapping={ 'product': product_id}) else: if result: msg_type = 'info' - msg = _(u'Uninstalled ${product}.', + msg = _('Uninstalled ${product}.', mapping={'product': product_id}) else: msg_type = 'error' - msg = _(u'Could not uninstall ${product}.', + msg = _('Could not uninstall ${product}.', mapping={'product': product_id}) messages.addStatusMessage(msg, type=msg_type) diff --git a/Products/CMFPlone/controlpanel/browser/redirects.py b/Products/CMFPlone/controlpanel/browser/redirects.py index 9a3c2f2397..e4aa52ff7e 100644 --- a/Products/CMFPlone/controlpanel/browser/redirects.py +++ b/Products/CMFPlone/controlpanel/browser/redirects.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from DateTime import DateTime from DateTime.interfaces import DateTimeError from csv import writer @@ -53,12 +52,12 @@ def absolutize_path(path, is_source=True): is_external_url = False if not path: if is_source: - err = _(u"You have to enter an alternative url.") + err = _("You have to enter an alternative url.") else: - err = _(u"You have to enter a target.") + err = _("You have to enter a target.") elif not path.startswith('/'): if is_source: - err = _(u"Alternative url path must start with a slash.") + err = _("Alternative url path must start with a slash.") else: # For targets, we accept external urls. # Do basic check. @@ -66,32 +65,32 @@ def absolutize_path(path, is_source=True): if parsed.scheme in ('https', 'http') and parsed.netloc: is_external_url = True else: - err = _(u"Target path must start with a slash.") + err = _("Target path must start with a slash.") elif '@@' in path: if is_source: - err = _(u"Alternative url path must not be a view.") + err = _("Alternative url path must not be a view.") else: - err = _(u"Target path must not be a view.") + err = _("Target path must not be a view.") else: context_path = "/".join(portal.getPhysicalPath()) - path = "{0}{1}".format(context_path, path) + path = f"{context_path}{path}" if not err and not is_external_url: catalog = getToolByName(portal, 'portal_catalog') if is_source: # Check whether already exists in storage storage = getUtility(IRedirectionStorage) if storage.get(path): - err = _(u"The provided alternative url already exists!") + err = _("The provided alternative url already exists!") else: # Check whether obj exists at source path. # A redirect would be useless then. if portal.unrestrictedTraverse(path, None) is not None: - err = _(u"Cannot use a working path as alternative url.") + err = _("Cannot use a working path as alternative url.") else: # Check whether obj exists at target path result = catalog.searchResults(path={"query": path}) if len(result) == 0: - err = _(u"The provided target object does not exist.") + err = _("The provided target object does not exist.") return path, err @@ -119,7 +118,7 @@ def edit_for_navigation_root(self, redirection): # Update the path accordingly, unless the user already did this. extra = nav_url[len(portal_url) :] if not redirection.startswith(extra): - redirection = '{0}{1}'.format(extra, redirection) + redirection = f'{extra}{redirection}' # Finally, return the (possibly edited) redirection return redirection @@ -148,7 +147,7 @@ def __call__(self): manual=True, ) status.addStatusMessage( - _(u"Alternative url added."), type='info' + _("Alternative url added."), type='info' ) elif 'form.button.Remove' in form: redirects = form.get('redirects', ()) @@ -156,11 +155,11 @@ def __call__(self): storage.remove(redirect) if len(redirects) > 1: status.addStatusMessage( - _(u"Alternative urls removed."), type='info' + _("Alternative urls removed."), type='info' ) else: status.addStatusMessage( - _(u"Alternative url removed."), type='info' + _("Alternative url removed."), type='info' ) return self.index(errors=errors) @@ -170,7 +169,7 @@ def view_url(self): return self.context.absolute_url() + '/@@manage-aliases' -class RedirectionSet(object): +class RedirectionSet: def __init__(self, query='', created='', manual=''): self.storage = getUtility(IRedirectionStorage) @@ -184,7 +183,7 @@ def __init__(self, query='', created='', manual=''): # min_k is /Plone/news and # max_k is /Plone/newt # Apparently that is the way to minize the keys we ask. - min_k = u'{0:s}/{1:s}'.format(self.portal_path, query.strip('/')) + min_k = '{:s}/{:s}'.format(self.portal_path, query.strip('/')) max_k = min_k[:-1] + chr(ord(min_k[-1]) + 1) self.data = self.storage._paths.keys( min=min_k, max=max_k, excludemax=True @@ -247,10 +246,10 @@ class RedirectsBatchView(PloneBatchView): def make_link(self, pagenumber=None, omit_params=None): if omit_params is None: omit_params = ['ajax_load'] - url = super(RedirectsBatchView, self).make_link( + url = super().make_link( pagenumber, omit_params ) - return u'{0:s}#manage-existing-aliases'.format(url) + return f'{url:s}#manage-existing-aliases' class RedirectsControlPanel(BrowserView): @@ -305,16 +304,16 @@ def __call__(self): for redirect in redirects: storage.remove(redirect) if len(redirects) == 0: - err = _(u"No alternative urls selected for removal.") + err = _("No alternative urls selected for removal.") status.addStatusMessage(err, type='error') self.form_errors['remove_redirects'] = err elif len(redirects) > 1: status.addStatusMessage( - _(u"Alternative urls removed."), type='info' + _("Alternative urls removed."), type='info' ) else: status.addStatusMessage( - _(u"Alternative url removed."), type='info' + _("Alternative url removed."), type='info' ) elif 'form.button.Add' in form: err = self.add( @@ -348,14 +347,14 @@ def add(self, redirection, target, portal, storage, status): self.form_errors['target_path'] = target_err if err and target_err: - err = "{0} {1}".format(err, target_err) + err = f"{err} {target_err}" elif target_err: err = target_err else: if abs_redirection == abs_target: err = _( - u"Alternative urls that point to themselves will cause" - u" an endless cycle of redirects." + "Alternative urls that point to themselves will cause" + " an endless cycle of redirects." ) # TODO: detect indirect recursion @@ -364,7 +363,7 @@ def add(self, redirection, target, portal, storage, status): else: storage.add(abs_redirection, abs_target, manual=True) status.addStatusMessage( - _(u"Alternative url from {0} to {1} added.").format( + _("Alternative url from {0} to {1} added.").format( abs_redirection, abs_target ), type='info', @@ -376,7 +375,7 @@ def upload(self, file, portal, storage, status): # No file picked. Theres gotta be a better way to handle this. if not file.filename: - err = _(u"Please pick a file to upload.") + err = _("Please pick a file to upload.") status.addStatusMessage(err, type='error') self.form_errors['file'] = err return @@ -431,18 +430,18 @@ def upload(self, file, portal, storage, status): ): # First line is a header. Ignore this. continue - err = "%s %s" % (err, target_err) # sloppy w.r.t. i18n + err = f"{err} {target_err}" # sloppy w.r.t. i18n elif target_err: err = target_err else: if abs_redirection == abs_target: # TODO: detect indirect recursion err = _( - u"Alternative urls that point to themselves will cause" - u" an endless cycle of redirects." + "Alternative urls that point to themselves will cause" + " an endless cycle of redirects." ) else: - err = _(u"Each line must have 2 or more columns.") + err = _("Each line must have 2 or more columns.") if not err: if not had_errors: # else don't bother @@ -461,7 +460,7 @@ def upload(self, file, portal, storage, status): storage.update(successes) status.addStatusMessage( _( - u"${count} alternative urls added.", + "${count} alternative urls added.", mapping={'count': len(successes)}, ), type='info', @@ -473,8 +472,8 @@ def upload(self, file, portal, storage, status): line_number=0, line='', message=_( - u'msg_delimiter', - default=u"Delimiter detected: ${delimiter}", + 'msg_delimiter', + default="Delimiter detected: ${delimiter}", mapping={'delimiter': dialect.delimiter}, ), ), diff --git a/Products/CMFPlone/controlpanel/browser/resourceregistry.py b/Products/CMFPlone/controlpanel/browser/resourceregistry.py index 9d69bc2d06..2c0dcace27 100644 --- a/Products/CMFPlone/controlpanel/browser/resourceregistry.py +++ b/Products/CMFPlone/controlpanel/browser/resourceregistry.py @@ -1,4 +1,3 @@ -# -*- coding:utf-8 from datetime import datetime from plone.memoize.view import memoize from plone.registry import field @@ -63,12 +62,12 @@ def updateRecordFromDict(record, data): continue if type(val) == bool: record.__registry__.records[full_name] = Record( - field.Bool(title=u""), val) + field.Bool(title=""), val) else: raise -class OverrideFolderManager(object): +class OverrideFolderManager: def __init__(self, context): self.context = context @@ -112,7 +111,7 @@ def make_links_relative(self, filepath, data): """ site_url = self.context.absolute_url() - full_resource_url = '%s/++plone++%s' % (site_url, filepath) + full_resource_url = f'{site_url}/++plone++{filepath}' for css_url in CSS_URL_REGEX.findall(data): if css_url.startswith("data:"): continue @@ -178,9 +177,9 @@ def __call__(self): else: if RESOURCE_DEVELOPMENT_MODE: messages = IStatusMessage(self.request) - messages.add(u"The FEDEV environment variable is set. No matter " - u"what settings are done here, all bundles will " - u"always be in development mode.", type=u"warn") + messages.add("The FEDEV environment variable is set. No matter " + "what settings are done here, all bundles will " + "always be in development mode.", type="warn") return self.index() @property @@ -271,7 +270,7 @@ def less_build_config(self): url = parse.urlparse(css) if url.netloc == '': # Local - src = "%s/%s" % (site_url, css) + src = f"{site_url}/{css}" else: src = "%s" % (css) @@ -325,7 +324,7 @@ def save_js_build(self): bundle = self.get_bundles().get(req.form['bundle']) if bundle: bundle.last_compilation = datetime.now() - bundle.jscompilation = '++plone++{}'.format(filepath) + bundle.jscompilation = f'++plone++{filepath}' return json.dumps({ 'success': True, 'filepath': '++plone++' + filepath @@ -346,7 +345,7 @@ def save_less_build(self): bundle = self.get_bundles().get(req.form['bundle']) if bundle: bundle.last_compilation = datetime.now() - bundle.csscompilation = '++plone++{}'.format(filepath) + bundle.csscompilation = f'++plone++{filepath}' return json.dumps({ 'success': True, 'filepath': '++plone++' + filepath @@ -391,7 +390,7 @@ def _read_folder(folder): for fi in files: path = fi.getPhysicalPath() rel_path = path[len(site_path) + 2:] - results.append('++plone++%s/%s' % ( + results.append('++plone++{}/{}'.format( rel_path[0], '/'.join(rel_path[1:]))) return results @@ -411,7 +410,7 @@ def config(self): 'css': {}, 'baseUrl': base_url, 'manageUrl': '%s/@@resourceregistry-controlpanel' % base_url, - 'lessUrl': '%s/%s' % (base_url, less_url), + 'lessUrl': f'{base_url}/{less_url}', 'lessConfigUrl': '%s/less-variables.js' % base_url, 'rjsUrl': rjs_url, 'patternoptions': self.registry['plone.patternoptions'] diff --git a/Products/CMFPlone/controlpanel/browser/search.py b/Products/CMFPlone/controlpanel/browser/search.py index ee0845bbed..ddffdf4151 100644 --- a/Products/CMFPlone/controlpanel/browser/search.py +++ b/Products/CMFPlone/controlpanel/browser/search.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone import PloneMessageFactory as _ from Products.CMFPlone.interfaces import ISearchSchema from Products.CMFPlone.controlpanel.widgets import ReverseCheckBoxFieldWidget @@ -10,17 +9,17 @@ class SearchControlPanelForm(controlpanel.RegistryEditForm): id = "SearchControlPanel" - label = _(u"Search Settings") + label = _("Search Settings") schema = ISearchSchema schema_prefix = "plone" def updateFields(self): - super(SearchControlPanelForm, self).updateFields() + super().updateFields() self.fields['types_not_searched'].widgetFactory = \ ReverseCheckBoxFieldWidget def updateWidgets(self): - super(SearchControlPanelForm, self).updateWidgets() + super().updateWidgets() # Replace vocabulary for 'types_not_searched' with user friendly types # to hide "bad" types in control panel. vocab = self._friendly_types_vocabulary() @@ -40,7 +39,7 @@ def applyChanges(self, data): new_types = [t for t in all_types if t in submitted_types or (t in current_types and t not in friendly_types)] data['types_not_searched'] = tuple(new_types) - super(SearchControlPanelForm, self).applyChanges(data) + super().applyChanges(data) def _friendly_types_vocabulary(self): return queryUtility(IVocabularyFactory, diff --git a/Products/CMFPlone/controlpanel/browser/security.py b/Products/CMFPlone/controlpanel/browser/security.py index f050bc5742..4fb41d1601 100644 --- a/Products/CMFPlone/controlpanel/browser/security.py +++ b/Products/CMFPlone/controlpanel/browser/security.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_inner from Products.CMFCore.utils import getToolByName from Products.CMFPlone import PloneMessageFactory as _ @@ -17,7 +16,7 @@ class SecurityControlPanelForm(controlpanel.RegistryEditForm): id = "SecurityControlPanel" - label = _(u"Security Settings") + label = _("Security Settings") schema = ISecuritySchema schema_prefix = "plone" diff --git a/Products/CMFPlone/controlpanel/browser/site.py b/Products/CMFPlone/controlpanel/browser/site.py index a01cda50be..269fe1b029 100644 --- a/Products/CMFPlone/controlpanel/browser/site.py +++ b/Products/CMFPlone/controlpanel/browser/site.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone import PloneMessageFactory as _ from Products.CMFPlone.interfaces import ISiteSchema from plone.app.registry.browser import controlpanel @@ -9,17 +8,17 @@ class SiteControlPanelForm(controlpanel.RegistryEditForm): id = "SiteControlPanel" - label = _(u"Site Settings") + label = _("Site Settings") description = _("Site-wide settings.") schema = ISiteSchema schema_prefix = "plone" def updateFields(self): - super(SiteControlPanelForm, self).updateFields() + super().updateFields() self.fields['site_logo'].widgetFactory = NamedImageFieldWidget def updateWidgets(self): - super(SiteControlPanelForm, self).updateWidgets() + super().updateWidgets() # hide the default_page field/widgets self.widgets['default_page'].mode = interfaces.HIDDEN_MODE diff --git a/Products/CMFPlone/controlpanel/browser/socialmedia.py b/Products/CMFPlone/controlpanel/browser/socialmedia.py index 1ebea9d1d2..edb14ca1b8 100644 --- a/Products/CMFPlone/controlpanel/browser/socialmedia.py +++ b/Products/CMFPlone/controlpanel/browser/socialmedia.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone import PloneMessageFactory as _ from Products.CMFPlone.interfaces import ISocialMediaSchema from plone.app.registry.browser import controlpanel @@ -7,7 +6,7 @@ class SocialControlPanelForm(controlpanel.RegistryEditForm): id = "SocialControlPanel" - label = _(u"Social Media Settings") + label = _("Social Media Settings") description = _("Social media sharing settings.") schema = ISocialMediaSchema schema_prefix = "plone" diff --git a/Products/CMFPlone/controlpanel/browser/syndication.py b/Products/CMFPlone/controlpanel/browser/syndication.py index 122c12f5c2..f9b16303c3 100644 --- a/Products/CMFPlone/controlpanel/browser/syndication.py +++ b/Products/CMFPlone/controlpanel/browser/syndication.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFCore.utils import getToolByName from zope.i18nmessageid import MessageFactory from Products.CMFPlone.interfaces.syndication import ISiteSyndicationSettings @@ -13,11 +12,11 @@ class SyndicationControlPanelForm(controlpanel.RegistryEditForm): schema = ISiteSyndicationSettings - label = _(u'Syndication Settings') - description = _(u'Default syndication settings.') + label = _('Syndication Settings') + description = _('Default syndication settings.') def updateFields(self): - super(SyndicationControlPanelForm, self).updateFields() + super().updateFields() self.fields['site_rss_items'].widgetFactory = SelectFieldWidget def getSyndicationSettingsButtonShown(self): @@ -26,7 +25,7 @@ def getSyndicationSettingsButtonShown(self): return actions.object.syndication.getProperty('visible') else: IStatusMessage(self.request).addStatusMessage( - _(u"Missing syndication settings action."), "warn") + _("Missing syndication settings action."), "warn") def getSyndicationLinkShown(self): actions = getToolByName(self.context, 'portal_actions') @@ -34,7 +33,7 @@ def getSyndicationLinkShown(self): return actions.document_actions.rss.getProperty('visible') else: IStatusMessage(self.request).addStatusMessage( - _(u"Missing rss link action."), "warn") + _("Missing rss link action."), "warn") def forceCheckboxValue(self, widget, checked): if checked: @@ -49,7 +48,7 @@ def forceCheckboxValue(self, widget, checked): item['checked'] = False def update(self): - super(SyndicationControlPanelForm, self).update() + super().update() # We override this so we can get actual # settings for portal_actions related settings @@ -72,7 +71,7 @@ def setSyndicationActionSettings(self, data): actions.document_actions.rss._setPropValue( 'visible', data['show_syndication_link']) - @button.buttonAndHandler(_(u"Save"), name='save') + @button.buttonAndHandler(_("Save"), name='save') def handleSave(self, action): """ Again, we're customizing this to handle saving @@ -86,13 +85,13 @@ def handleSave(self, action): self.setSyndicationActionSettings(data) self.applyChanges(data) IStatusMessage(self.request).addStatusMessage( - _(u"Changes saved."), "info") + _("Changes saved."), "info") self.request.response.redirect(self.request.getURL()) - @button.buttonAndHandler(_(u"Cancel"), name='cancel') + @button.buttonAndHandler(_("Cancel"), name='cancel') def handleCancel(self, action): IStatusMessage(self.request).addStatusMessage( - _(u"Edit cancelled."), "info") + _("Edit cancelled."), "info") self.request.response.redirect(self.request.getURL()) diff --git a/Products/CMFPlone/controlpanel/browser/tinymce.py b/Products/CMFPlone/controlpanel/browser/tinymce.py index 0899d80c89..4e3d0daf25 100644 --- a/Products/CMFPlone/controlpanel/browser/tinymce.py +++ b/Products/CMFPlone/controlpanel/browser/tinymce.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone import PloneMessageFactory as _ from Products.CMFPlone.interfaces import ITinyMCELayoutSchema from Products.CMFPlone.interfaces import ITinyMCESpellCheckerSchema @@ -13,29 +12,29 @@ class TinyMCEPluginForm(group.GroupForm): - label = _(u"Plugins and Toolbar") + label = _("Plugins and Toolbar") fields = field.Fields(ITinyMCEPluginSchema) class TinyMCESpellCheckerForm(group.GroupForm): - label = _(u"Spell Checker") + label = _("Spell Checker") fields = field.Fields(ITinyMCESpellCheckerSchema) class TinyMCEResourceTypesForm(group.GroupForm): - label = _(u"Resource Types") + label = _("Resource Types") fields = field.Fields(ITinyMCEResourceTypesSchema) class TinyMCEAdvancedForm(group.GroupForm): - label = _(u"Advanced") + label = _("Advanced") fields = field.Fields(ITinyMCEAdvancedSchema) class TinyMCEControlPanelForm(controlpanel.RegistryEditForm): id = "TinyMCEControlPanel" - label = _(u"TinyMCE Settings") + label = _("TinyMCE Settings") schema = ITinyMCESchema schema_prefix = "plone" fields = field.Fields(ITinyMCELayoutSchema) @@ -43,7 +42,7 @@ class TinyMCEControlPanelForm(controlpanel.RegistryEditForm): TinyMCEResourceTypesForm, TinyMCEAdvancedForm) def updateFields(self): - super(TinyMCEControlPanelForm, self).updateFields() + super().updateFields() self.groups[0].fields['plugins'].widgetFactory = CheckBoxFieldWidget diff --git a/Products/CMFPlone/controlpanel/browser/types.py b/Products/CMFPlone/controlpanel/browser/types.py index 6d802ce221..7797b148d4 100644 --- a/Products/CMFPlone/controlpanel/browser/types.py +++ b/Products/CMFPlone/controlpanel/browser/types.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_inner from Products.CMFCore.utils import getToolByName from Products.CMFPlone import PloneMessageFactory as _ @@ -32,18 +31,18 @@ def format_description(text, request=None): VERSION_POLICIES = [ dict(id="off", policy=(), - title=_(u"versioning_off", - default=u"No versioning")), + title=_("versioning_off", + default="No versioning")), dict(id="manual", policy=("version_on_revert",), - title=_(u"versioning_manual", - default=u"Manual")), + title=_("versioning_manual", + default="Manual")), dict(id="automatic", policy=("at_edit_autoversion", "version_on_revert"), - title=_(u"versioning_automatic", - default=u"Automatic")), + title=_("versioning_automatic", + default="Automatic")), ] @@ -64,13 +63,13 @@ def handleSave(self, action): self.status = self.formErrorsMessage return IStatusMessage(self.request).addStatusMessage( - _(u"Changes saved"), "info") + _("Changes saved"), "info") self.request.response.redirect("@@content-controlpanel") - @button.buttonAndHandler(_(u"Cancel"), name='cancel') + @button.buttonAndHandler(_("Cancel"), name='cancel') def handleCancel(self, action): IStatusMessage(self.request).addStatusMessage( - _(u"Changes canceled."), "info") + _("Changes canceled."), "info") self.request.response.redirect("@@overview-controlpanel") @property @@ -216,10 +215,10 @@ def __call__(self): chain = new_wf else: chain = (new_wf,) - state_map = dict([ - (s['old_state'], s['new_state']) + state_map = { + s['old_state']: s['new_state'] for s in form.get('new_wfstates', []) - ]) + } if '[none]' in state_map: state_map[None] = state_map['[none]'] del state_map['[none]'] @@ -262,7 +261,7 @@ def __call__(self): ) self.request.response.redirect( - '%s/@@content-controlpanel?type_id=%s' % ( + '{}/@@content-controlpanel?type_id={}'.format( context.absolute_url(), type_id ) @@ -352,12 +351,12 @@ def current_workflow(self): chain = portal_workflow.getChainForPortalType(self.type_id) empty_workflow_dict = dict( id='[none]', - title=_(u"label_no_workflow"), + title=_("label_no_workflow"), description=[_( - u"description_no_workflow", - default=u"This type has no workflow. The visibilty " - u"of items of this type is determined by " - u"the folder they are in.") + "description_no_workflow", + default="This type has no workflow. The visibilty " + "of items of this type is determined by " + "the folder they are in.") ] ) @@ -391,8 +390,8 @@ def current_workflow(self): ) return dict(id='(Default)', title=_( - u"label_default_workflow_title", - default=u"Default workflow (${title})", + "label_default_workflow_title", + default="Default workflow (${title})", mapping=dict(title=default_title)), description=format_description( default_workflow.description, @@ -429,8 +428,8 @@ def available_workflows(self): 0, dict( id='(Default)', - title=_(u"label_default_workflow_title", - default=u"Default workflow (${title})", + title=_("label_default_workflow_title", + default="Default workflow (${title})", mapping=dict(title=default_title)), description=format_description( default_workflow.description, @@ -497,10 +496,10 @@ def new_workflow_description(self): if self.new_workflow_is_different(): if self.new_workflow_is_none(): return [_( - u"description_no_workflow", - default=u"This type has no workflow. The visibilty of " - u"items of this type is determined by the " - u"folder they are in.")] + "description_no_workflow", + default="This type has no workflow. The visibilty of " + "items of this type is determined by the " + "folder they are in.")] new_workflow = self.real_workflow(self.new_workflow()) wf = getattr(portal_workflow, new_workflow) return format_description(wf.description, self.request) @@ -534,14 +533,14 @@ def suggested_state_map(self): new_wf = getattr(portal_workflow, new_workflow) default_state = new_wf.initial_state return [dict(old_id='[none]', - old_title=_(u"No workflow"), + old_title=_("No workflow"), suggested_id=default_state)] elif self.new_workflow_is_different(): old_wf = getattr(portal_workflow, current_workflow) new_wf = getattr(portal_workflow, new_workflow) - new_states = set([s.id for s in new_wf.states.objectValues()]) + new_states = {s.id for s in new_wf.states.objectValues()} default_state = new_wf.initial_state states = [] diff --git a/Products/CMFPlone/controlpanel/browser/usergroups.py b/Products/CMFPlone/controlpanel/browser/usergroups.py index 0a92a0e389..40fb8894bf 100644 --- a/Products/CMFPlone/controlpanel/browser/usergroups.py +++ b/Products/CMFPlone/controlpanel/browser/usergroups.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFCore.permissions import ManagePortal from ZTUtils import make_query from itertools import chain @@ -30,10 +29,10 @@ class UserGroupsSettingsControlPanel(AutoExtensibleForm, form.EditForm): @button.buttonAndHandler(_('label_save', default="Save"), name='save') def handleApply(self, action): - super(UserGroupsSettingsControlPanel, self).handleApply(self, action) + super().handleApply(self, action) def updateActions(self): - super(UserGroupsSettingsControlPanel, self).updateActions() + super().updateActions() if self.actions and 'save' in self.actions: self.actions['save'].addClass('context') diff --git a/Products/CMFPlone/controlpanel/browser/usergroups_groupdetails.py b/Products/CMFPlone/controlpanel/browser/usergroups_groupdetails.py index 443cdbcfa9..0e405fac45 100644 --- a/Products/CMFPlone/controlpanel/browser/usergroups_groupdetails.py +++ b/Products/CMFPlone/controlpanel/browser/usergroups_groupdetails.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_inner from Products.CMFPlone.controlpanel.browser.usergroups import \ UsersGroupsControlPanelView @@ -36,7 +35,7 @@ def __call__(self): if submitted: CheckAuthenticator(self.request) - msg = _(u'No changes made.') + msg = _('No changes made.') self.group = None title = self.request.form.get('title', None) @@ -45,7 +44,7 @@ def __call__(self): if addname: if not self.regtool.isMemberIdAllowed(addname): - msg = _(u'The group name you entered is not valid.') + msg = _('The group name you entered is not valid.') IStatusMessage(self.request).add(msg, 'error') return self.index() @@ -54,26 +53,26 @@ def __call__(self): REQUEST=self.request) if not success: msg = _( - u'Could not add group ${name}, perhaps a user or ' - u'group with this name already exists.', - mapping={u'name': addname} + 'Could not add group ${name}, perhaps a user or ' + 'group with this name already exists.', + mapping={'name': addname} ) IStatusMessage(self.request).add(msg, 'error') return self.index() self.group = self.gtool.getGroupById(addname) - msg = _(u'Group ${name} has been added.', - mapping={u'name': addname}) + msg = _('Group ${name} has been added.', + mapping={'name': addname}) elif self.groupname: self.gtool.editGroup(self.groupname, roles=None, groups=None, title=title, description=description, REQUEST=context.REQUEST) self.group = self.gtool.getGroupById(self.groupname) - msg = _(u'Changes saved.') + msg = _('Changes saved.') else: - msg = _(u'Group name required.') + msg = _('Group name required.') processed = {} for id, property in self.gdtool.propertyItems(): @@ -87,7 +86,7 @@ def __call__(self): IStatusMessage(self.request).add( msg, type=self.group and 'info' or 'error') if self.group and not self.groupname: - target_url = '%s/%s' % (self.context.absolute_url(), + target_url = '{}/{}'.format(self.context.absolute_url(), '@@usergroup-groupprefs') self.request.response.redirect(target_url) return '' diff --git a/Products/CMFPlone/controlpanel/browser/usergroups_groupmembership.py b/Products/CMFPlone/controlpanel/browser/usergroups_groupmembership.py index 5720cbd01c..b2ba666721 100644 --- a/Products/CMFPlone/controlpanel/browser/usergroups_groupmembership.py +++ b/Products/CMFPlone/controlpanel/browser/usergroups_groupmembership.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone import PloneMessageFactory as _ from zExceptions import Forbidden from Products.CMFCore.utils import getToolByName @@ -45,14 +44,14 @@ def update(self): for u in toAdd: self.gtool.addPrincipalToGroup( u, self.groupname, self.request) - self.context.plone_utils.addPortalMessage(_(u'Changes made.')) + self.context.plone_utils.addPortalMessage(_('Changes made.')) toDelete = form.get('delete', []) if toDelete: for u in toDelete: self.gtool.removePrincipalFromGroup( u, self.groupname, self.request) - self.context.plone_utils.addPortalMessage(_(u'Changes made.')) + self.context.plone_utils.addPortalMessage(_('Changes made.')) search = form.get('form.button.Search', None) is not None edit = form.get('form.button.Edit', None) is not None and toDelete diff --git a/Products/CMFPlone/controlpanel/browser/usergroups_groupsoverview.py b/Products/CMFPlone/controlpanel/browser/usergroups_groupsoverview.py index 9b96224800..276ca39f40 100644 --- a/Products/CMFPlone/controlpanel/browser/usergroups_groupsoverview.py +++ b/Products/CMFPlone/controlpanel/browser/usergroups_groupsoverview.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from itertools import chain from Acquisition import aq_inner from Products.CMFPlone.controlpanel.browser.usergroups import \ @@ -125,7 +124,7 @@ def manageGroup(self, groups=None, delete=None): utils = getToolByName(context, 'plone_utils') groupstool = getToolByName(context, 'portal_groups') - message = _(u'No changes made.') + message = _('No changes made.') for group in groups: roles = [r for r in self.request.form['group_' + group] if r] @@ -137,7 +136,7 @@ def manageGroup(self, groups=None, delete=None): raise Forbidden groupstool.editGroup(group, roles=roles, groups=()) - message = _(u'Changes saved.') + message = _('Changes saved.') if delete: for group_id in delete: @@ -146,6 +145,6 @@ def manageGroup(self, groups=None, delete=None): raise Forbidden groupstool.removeGroups(delete) - message = _(u'Group(s) deleted.') + message = _('Group(s) deleted.') utils.addPortalMessage(message) diff --git a/Products/CMFPlone/controlpanel/browser/usergroups_usermembership.py b/Products/CMFPlone/controlpanel/browser/usergroups_usermembership.py index 8424b41e5a..5e46e792af 100644 --- a/Products/CMFPlone/controlpanel/browser/usergroups_usermembership.py +++ b/Products/CMFPlone/controlpanel/browser/usergroups_usermembership.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone import PloneMessageFactory as _ from zExceptions import Forbidden from Products.CMFCore.utils import getToolByName @@ -27,7 +26,7 @@ def update(self): for groupname in delete: self.gtool.removePrincipalFromGroup( self.userid, groupname, self.request) - self.context.plone_utils.addPortalMessage(_(u'Changes made.')) + self.context.plone_utils.addPortalMessage(_('Changes made.')) add = form.get('add', []) if add: @@ -38,7 +37,7 @@ def update(self): self.gtool.addPrincipalToGroup( self.userid, groupname, self.request) - self.context.plone_utils.addPortalMessage(_(u'Changes made.')) + self.context.plone_utils.addPortalMessage(_('Changes made.')) search = form.get('form.button.Search', None) is not None findAll = form.get('form.button.FindAll', diff --git a/Products/CMFPlone/controlpanel/browser/usergroups_usersoverview.py b/Products/CMFPlone/controlpanel/browser/usergroups_usersoverview.py index f8dc21ef01..2a4a97d278 100644 --- a/Products/CMFPlone/controlpanel/browser/usergroups_usersoverview.py +++ b/Products/CMFPlone/controlpanel/browser/usergroups_usersoverview.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_inner from zExceptions import Forbidden from itertools import chain @@ -164,7 +163,7 @@ def manageUser(self, users=[], resetpassword=[], delete=[]): if user.email != member.getProperty('email'): utils.setMemberProperties( member, REQUEST=context.REQUEST, email=user.email) - utils.addPortalMessage(_(u'Changes applied.')) + utils.addPortalMessage(_('Changes applied.')) # If reset password has been checked email user a new password pw = None @@ -175,7 +174,7 @@ def manageUser(self, users=[], resetpassword=[], delete=[]): pw = regtool.generatePassword() else: utils.addPortalMessage( - _(u'No mailhost defined. Unable to reset passwords.'), type='error') + _('No mailhost defined. Unable to reset passwords.'), type='error') roles = user.get('roles', []) if not self.is_zope_manager: @@ -194,14 +193,14 @@ def manageUser(self, users=[], resetpassword=[], delete=[]): self.deleteMembers(delete) if users_with_reset_passwords: reset_passwords_message = _( - u"reset_passwords_msg", - default=u"The following users have been sent an e-mail with link to reset their password: ${user_ids}", + "reset_passwords_msg", + default="The following users have been sent an e-mail with link to reset their password: ${user_ids}", mapping={ - u"user_ids": ', '.join(users_with_reset_passwords), + "user_ids": ', '.join(users_with_reset_passwords), }, ) utils.addPortalMessage(reset_passwords_message) - utils.addPortalMessage(_(u'Changes applied.')) + utils.addPortalMessage(_('Changes applied.')) def deleteMembers(self, member_ids): # this method exists to bypass the 'Manage Users' permission check diff --git a/Products/CMFPlone/controlpanel/events.py b/Products/CMFPlone/controlpanel/events.py index 267b0d9abd..1273f6297d 100644 --- a/Products/CMFPlone/controlpanel/events.py +++ b/Products/CMFPlone/controlpanel/events.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFCore.ActionInformation import Action from Products.CMFCore.utils import getToolByName from Products.CMFPlone import PloneMessageFactory as _ @@ -16,7 +15,7 @@ @implementer(IConfigurationChangedEvent) -class ConfigurationChangedEvent(object): +class ConfigurationChangedEvent: def __init__(self, context, data): self.context = context @@ -92,7 +91,7 @@ def handle_enable_user_folders(obj, event): def _add_mystuff_action(object_category): new_action = Action( 'mystuff', - title=_(u'My Folder'), + title=_('My Folder'), description='', url_expr='string:${portal/portal_membership/getHomeUrl}', available_expr='python:(member is not None) and \ @@ -103,7 +102,7 @@ def _add_mystuff_action(object_category): ) object_category._setObject('mystuff', new_action) # move action to top, at least before the logout action - object_category.moveObjectsToTop(('mystuff')) + object_category.moveObjectsToTop('mystuff') @adapter(ISecuritySchema, IRecordModifiedEvent) diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_actions.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_actions.py index 2f82822d4e..98202efb60 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_actions.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_actions.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFCore.utils import getToolByName from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING from zope.component import getMultiAdapter diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_editing_adapter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_editing_adapter.py index 3e79150800..8e48c1737c 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_editing_adapter.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_editing_adapter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import IEditingSchema from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING from plone.app.testing import TEST_USER_ID @@ -70,23 +69,23 @@ def test_set_ext_editor_setting(self): def test_get_default_editor_setting(self): self.assertEqual( getAdapter(self.portal, IEditingSchema).default_editor, - u'TinyMCE' + 'TinyMCE' ) - self.settings.default_editor = u'None' + self.settings.default_editor = 'None' self.assertEqual( getAdapter(self.portal, IEditingSchema).default_editor, - u'None' + 'None' ) def test_set_default_editor_setting(self): self.assertEqual( self.settings.default_editor, - u'TinyMCE' + 'TinyMCE' ) - getAdapter(self.portal, IEditingSchema).default_editor = u'None' + getAdapter(self.portal, IEditingSchema).default_editor = 'None' self.assertEqual( self.settings.default_editor, - u'None' + 'None' ) def test_get_lock_on_ttw_edit_setting(self): diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_filter_adapter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_filter_adapter.py index 065239c7c1..8321155c99 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_filter_adapter.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_filter_adapter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import IFilterSchema from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING from plone.app.testing import TEST_USER_ID @@ -24,45 +23,45 @@ def test_adapter_lookup(self): self.assertTrue(getAdapter(self.portal, IFilterSchema)) def test_get_nasty_tags(self): - self.settings.nasty_tags = [u'foo', u'bar'] + self.settings.nasty_tags = ['foo', 'bar'] self.assertEqual( getAdapter(self.portal, IFilterSchema).nasty_tags, - [u'foo', u'bar'] + ['foo', 'bar'] ) def test_set_nasty_tags(self): - getAdapter(self.portal, IFilterSchema).nasty_tags = [u'foo', u'bar'] + getAdapter(self.portal, IFilterSchema).nasty_tags = ['foo', 'bar'] self.assertEqual( self.settings.nasty_tags, - [u'foo', u'bar'] + ['foo', 'bar'] ) def test_get_valid_tags(self): - self.settings.valid_tags = [u'foo', u'bar'] + self.settings.valid_tags = ['foo', 'bar'] self.assertEqual( getAdapter(self.portal, IFilterSchema).valid_tags, - [u'foo', u'bar'] + ['foo', 'bar'] ) def test_set_valid_tags(self): - getAdapter(self.portal, IFilterSchema).valid_tags = [u'foo', u'bar'] + getAdapter(self.portal, IFilterSchema).valid_tags = ['foo', 'bar'] self.assertEqual( self.settings.valid_tags, - [u'foo', u'bar'] + ['foo', 'bar'] ) def test_get_custom_attributes(self): - self.settings.custom_attributes = [u'foo', u'bar'] + self.settings.custom_attributes = ['foo', 'bar'] self.assertEqual( getAdapter(self.portal, IFilterSchema).custom_attributes, - [u'foo', u'bar'] + ['foo', 'bar'] ) def test_set_custom_attributes(self): getAdapter(self.portal, IFilterSchema).custom_attributes = [ - u'foo', u'bar' + 'foo', 'bar' ] self.assertEqual( self.settings.custom_attributes, - [u'foo', u'bar'] + ['foo', 'bar'] ) diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_language_adapter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_language_adapter.py index bfb2af1cb7..ff02c08697 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_language_adapter.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_language_adapter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.testing import \ PRODUCTS_CMFPLONE_INTEGRATION_TESTING diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_mail_adapter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_mail_adapter.py index b7ed5249a3..a3227f068e 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_mail_adapter.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_mail_adapter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import IMailSchema from Products.CMFPlone.testing import \ PRODUCTS_CMFPLONE_INTEGRATION_TESTING @@ -28,23 +27,23 @@ def test_adapter_lookup(self): def test_get_smtp_host(self): self.assertEqual( getAdapter(self.portal, IMailSchema).smtp_host, - u'localhost' + 'localhost' ) - self.mail_settings.smtp_host = u'example.com' + self.mail_settings.smtp_host = 'example.com' self.assertEqual( getAdapter(self.portal, IMailSchema).smtp_host, - u'example.com' + 'example.com' ) def test_set_smtp_host(self): self.assertEqual( self.mail_settings.smtp_host, - u'localhost' + 'localhost' ) - getAdapter(self.portal, IMailSchema).smtp_host = u'example.com' + getAdapter(self.portal, IMailSchema).smtp_host = 'example.com' self.assertEqual( self.mail_settings.smtp_host, - u'example.com' + 'example.com' ) def test_get_smtp_port(self): @@ -74,10 +73,10 @@ def test_get_smtp_userid(self): getAdapter(self.portal, IMailSchema).smtp_userid, None ) - self.mail_settings.smtp_userid = u'john@example.com' + self.mail_settings.smtp_userid = 'john@example.com' self.assertEqual( getAdapter(self.portal, IMailSchema).smtp_userid, - u'john@example.com' + 'john@example.com' ) def test_set_smtp_userid(self): @@ -85,10 +84,10 @@ def test_set_smtp_userid(self): self.mail_settings.smtp_userid, None ) - getAdapter(self.portal, IMailSchema).smtp_userid = u'john@example.com' + getAdapter(self.portal, IMailSchema).smtp_userid = 'john@example.com' self.assertEqual( self.mail_settings.smtp_userid, - u'john@example.com' + 'john@example.com' ) def test_get_smtp_pass(self): @@ -96,10 +95,10 @@ def test_get_smtp_pass(self): getAdapter(self.portal, IMailSchema).smtp_pass, None ) - self.mail_settings.smtp_pass = u'secret' + self.mail_settings.smtp_pass = 'secret' self.assertEqual( getAdapter(self.portal, IMailSchema).smtp_pass, - u'secret' + 'secret' ) def test_set_smtp_pass(self): @@ -107,10 +106,10 @@ def test_set_smtp_pass(self): self.mail_settings.smtp_pass, None ) - getAdapter(self.portal, IMailSchema).smtp_pass = u'secret' + getAdapter(self.portal, IMailSchema).smtp_pass = 'secret' self.assertEqual( self.mail_settings.smtp_pass, - u'secret' + 'secret' ) def test_get_email_from_name(self): @@ -118,10 +117,10 @@ def test_get_email_from_name(self): getAdapter(self.portal, IMailSchema).email_from_name, None ) - self.mail_settings.email_from_name = u'John' + self.mail_settings.email_from_name = 'John' self.assertEqual( getAdapter(self.portal, IMailSchema).email_from_name, - u'John' + 'John' ) def test_set_email_from_name(self): @@ -129,10 +128,10 @@ def test_set_email_from_name(self): self.mail_settings.email_from_name, None ) - getAdapter(self.portal, IMailSchema).email_from_name = u'John' + getAdapter(self.portal, IMailSchema).email_from_name = 'John' self.assertEqual( self.mail_settings.email_from_name, - u'John' + 'John' ) def test_get_email_from_address(self): diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_maintenance_adapter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_maintenance_adapter.py index aeeced7926..ebcb4e1d6c 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_maintenance_adapter.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_maintenance_adapter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import IMaintenanceSchema from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING from plone.app.testing import TEST_USER_ID diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_markup_adapter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_markup_adapter.py index 11c26953c0..4e9e2cfb36 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_markup_adapter.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_markup_adapter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import IMarkupSchema from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING from plone.registry.interfaces import IRegistry diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_navigation_adapter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_navigation_adapter.py index f75651acd1..2f0d0eacfb 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_navigation_adapter.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_navigation_adapter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import INavigationSchema from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING from plone.app.testing import TEST_USER_ID, setRoles diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_search_adapter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_search_adapter.py index b88a3d2b8e..4efa771e07 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_search_adapter.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_search_adapter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import ISearchSchema from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING from plone.app.testing import TEST_USER_ID, setRoles diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_security_adapter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_security_adapter.py index 5146caf15a..139ca26bca 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_security_adapter.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_security_adapter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.testing import \ PRODUCTS_CMFPLONE_INTEGRATION_TESTING from Products.CMFPlone.interfaces import ISecuritySchema diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_site_adapter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_site_adapter.py index 867d4fcf7b..9dcc8d3a32 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_site_adapter.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_site_adapter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import ISiteSchema from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING from plone.app.testing import TEST_USER_ID @@ -24,43 +23,43 @@ def test_adapter_lookup(self): self.assertTrue(getAdapter(self.portal, ISiteSchema)) def test_get_site_title(self): - self.settings.site_title = u'Great Site' + self.settings.site_title = 'Great Site' self.assertEqual( getAdapter(self.portal, ISiteSchema).site_title, - u'Great Site' + 'Great Site' ) def test_set_site_title(self): - getAdapter(self.portal, ISiteSchema).site_title = u'Good Site' + getAdapter(self.portal, ISiteSchema).site_title = 'Good Site' self.assertEqual( self.settings.site_title, - u'Good Site' + 'Good Site' ) def test_set_site_title_string(self): getAdapter(self.portal, ISiteSchema).site_title = 'Good Site' self.assertEqual( self.settings.site_title, - u'Good Site' + 'Good Site' ) def test_get_webstats_js(self): - self.settings.webstats_js = u'Script Tag' + self.settings.webstats_js = 'Script Tag' self.assertEqual( getAdapter(self.portal, ISiteSchema).webstats_js, - u'Script Tag' + 'Script Tag' ) def test_set_webstats_js(self): - getAdapter(self.portal, ISiteSchema).webstats_js = u'Script Tag' + getAdapter(self.portal, ISiteSchema).webstats_js = 'Script Tag' self.assertEqual( self.settings.webstats_js, - u'Script Tag' + 'Script Tag' ) def test_set_webstats_js_string(self): getAdapter(self.portal, ISiteSchema).webstats_js = 'Script Tag' self.assertEqual( self.settings.webstats_js, - u'Script Tag' + 'Script Tag' ) diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_usergroups_adapter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_usergroups_adapter.py index e765208507..6c3d7801f1 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_usergroups_adapter.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_bbb_usergroups_adapter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.testing import setRoles from Products.CMFPlone.interfaces import IUserGroupsSettingsSchema from zope.component import getAdapter diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_editing.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_editing.py index 85ef148f51..81ed3de60f 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_editing.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_editing.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import IEditingSchema from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING from plone.app.linkintegrity.utils import linkintegrity_enabled @@ -30,7 +29,7 @@ def setUp(self): self.browser.handleErrors = False self.browser.addHeader( 'Authorization', - 'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD,) + f'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}' ) def test_editing_control_panel_link(self): diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_filter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_filter.py index 4378a0a29d..e6b04e0a5c 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_filter.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_filter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.testing import SITE_OWNER_NAME, SITE_OWNER_PASSWORD from plone.registry.interfaces import IRegistry from plone.testing.zope import Browser @@ -30,7 +29,7 @@ def setUp(self): self.browser.handleErrors = False self.browser.addHeader( 'Authorization', - 'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD,) + f'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}' ) self.safe_html = getattr( getToolByName(self.portal, 'portal_transforms'), @@ -95,8 +94,8 @@ def test_nasty_tags(self): valid_tags = self.browser.getControl( name='form.widgets.valid_tags').value = valid_tags self.browser.getControl('Save').click() - self.assertEqual(self.settings.nasty_tags, [u'div', u'a']) - self.assertNotIn(u'a', self.settings.valid_tags) + self.assertEqual(self.settings.nasty_tags, ['div', 'a']) + self.assertNotIn('a', self.settings.valid_tags) # test that is filtered self.assertFalse(self.settings.disable_filtering) diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_installer.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_installer.py index d848db60c1..f68c913db1 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_installer.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_installer.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.testing import SITE_OWNER_NAME from plone.app.testing import SITE_OWNER_PASSWORD from plone.testing.zope import Browser @@ -21,7 +20,7 @@ def setUp(self): self.browser.handleErrors = False self.browser.addHeader( 'Authorization', - 'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD,) + f'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}' ) def test_addons_controlpanel_link(self): diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_language.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_language.py index 6855982975..cff39080e8 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_language.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_language.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.testing import SITE_OWNER_NAME, SITE_OWNER_PASSWORD from plone.i18n.interfaces import ILanguageSchema from plone.registry.interfaces import IRegistry @@ -29,7 +28,7 @@ def setUp(self): self.browser.handleErrors = False self.browser.addHeader( 'Authorization', - 'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD,) + f'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}' ) def _inject_available_languages_field(self, value): diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_mail.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_mail.py index 105481e890..c3d306202a 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_mail.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_mail.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.testing import SITE_OWNER_NAME, SITE_OWNER_PASSWORD from plone.registry.interfaces import IRegistry from plone.testing.zope import Browser @@ -28,7 +27,7 @@ def setUp(self): self.browser.handleErrors = False self.browser.addHeader( 'Authorization', - 'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD,) + f'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}' ) def test_mail_controlpanel_link(self): @@ -179,7 +178,7 @@ def test_mail_controlpanel_contactinfo_page(self): "%s/contact-info" % self.portal_url) self.assertTrue( 'Message' in self.browser.contents, - u'Message exists not in the contact-info form!' + 'Message exists not in the contact-info form!' ) def test_controlpanel_overview_shows_no_unconfigured_mailhost_warning( @@ -197,7 +196,7 @@ def test_controlpanel_overview_shows_no_unconfigured_mailhost_warning( "%s/overview-controlpanel" % self.portal_url) self.assertFalse( 'not configured a mail host' in self.browser.contents, - u'There should not be a warning for unconfigured mailhost!' + 'There should not be a warning for unconfigured mailhost!' ) def test_controlpanel_overview_shows_unconfigured_mailhost_warning( @@ -210,5 +209,5 @@ def test_controlpanel_overview_shows_unconfigured_mailhost_warning( "%s/overview-controlpanel" % self.portal_url) self.assertTrue( 'not configured a mail host' in self.browser.contents, - u'There should be a warning for unconfigured mailhost!' + 'There should be a warning for unconfigured mailhost!' ) diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_maintenance.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_maintenance.py index 71cffa0fd5..868bf1fe6c 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_maintenance.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_maintenance.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING from plone.app.testing import TEST_USER_NAME from plone.app.testing import TEST_USER_PASSWORD @@ -34,14 +33,14 @@ def setUp(self): transaction.commit() self.browser.addHeader( 'Authorization', - 'Basic %s:%s' % ('app', 'secret') + 'Basic {}:{}'.format('app', 'secret') ) self.site_administrator_browser = Browser(self.app) self.site_administrator_browser.handleErrors = False self.site_administrator_browser.addHeader( 'Authorization', - 'Basic %s:%s' % (TEST_USER_NAME, TEST_USER_PASSWORD,) + f'Basic {TEST_USER_NAME}:{TEST_USER_PASSWORD}' ) def test_maintenance_control_panel_link(self): diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_markup.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_markup.py index f719b700e6..a4cb5ae821 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_markup.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_markup.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import IMarkupSchema from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING from plone.app.testing import SITE_OWNER_NAME, SITE_OWNER_PASSWORD @@ -24,7 +23,7 @@ def setUp(self): self.browser.handleErrors = False self.browser.addHeader( 'Authorization', - 'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD,) + f'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}' ) def test_markup_control_panel_link(self): diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_navigation.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_navigation.py index 0236a3f87d..7921dec95d 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_navigation.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_navigation.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import INavigationSchema from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING from plone.app.testing import SITE_OWNER_NAME, SITE_OWNER_PASSWORD @@ -24,7 +23,7 @@ def setUp(self): self.browser.handleErrors = False self.browser.addHeader( 'Authorization', - 'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD,) + f'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}' ) def test_navigation_control_panel_link(self): diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_redirection.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_redirection.py index 5373e52024..6bfd822039 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_redirection.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_redirection.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from DateTime import DateTime from plone.app.redirector.interfaces import IRedirectionStorage from plone.app.testing import SITE_OWNER_NAME @@ -32,7 +31,7 @@ def setUp(self): self.browser.handleErrors = False self.browser.addHeader( 'Authorization', - 'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD), + f'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}', ) def test_redirection_controlpanel_link(self): @@ -69,13 +68,13 @@ def test_redirection_controlpanel_add_redirect(self): self.assertTrue( storage.has_path(storage_path), - u'Redirection storage should have path "{0}"'.format(storage_path), + f'Redirection storage should have path "{storage_path}"', ) def test_redirection_controlpanel_remove_redirects(self): storage = getUtility(IRedirectionStorage) for i in range(31): - storage['/plone/alias{0}'.format(i)] = '/plone/test-folder' + storage[f'/plone/alias{i}'] = '/plone/test-folder' transaction.commit() self.browser.open("%s/@@redirection-controlpanel" % self.portal_url) @@ -110,7 +109,7 @@ def test_redirection_controlpanel_remove_redirects(self): def test_redirection_controlpanel_remove_matching_redirects(self): storage = getUtility(IRedirectionStorage) for i in range(30): - storage['/plone/alias{0}'.format(i)] = '/plone/test-folder' + storage[f'/plone/alias{i}'] = '/plone/test-folder' transaction.commit() # Removing matching redirects can only happen when a filter is selected. @@ -140,8 +139,8 @@ def test_redirection_controlpanel_set(self): now = DateTime('2022-02-03') for i in range(1000): storage.add( - '{0:s}/foo/{1:s}'.format(portal_path, str(i)), - '{0:s}/bar/{1:s}'.format(portal_path, str(i)), + '{:s}/foo/{:s}'.format(portal_path, str(i)), + '{:s}/bar/{:s}'.format(portal_path, str(i)), now=now, ) redirects = RedirectionSet() @@ -152,7 +151,7 @@ def test_redirection_controlpanel_set(self): 'datetime': DateTime('2022-02-03'), 'manual': False, 'path': '/foo/0', - 'redirect': '{0:s}/foo/0'.format(portal_path), + 'redirect': f'{portal_path:s}/foo/0', 'redirect-to': '/bar/0', }, ) @@ -162,7 +161,7 @@ def test_redirection_controlpanel_set(self): 'datetime': DateTime('2022-02-03'), 'manual': False, 'path': '/foo/999', - 'redirect': '{0:s}/foo/999'.format(portal_path), + 'redirect': f'{portal_path:s}/foo/999', 'redirect-to': '/bar/999', }, ) @@ -173,7 +172,7 @@ def test_redirection_controlpanel_set(self): 'datetime': DateTime('2022-02-03'), 'manual': False, 'path': '/foo/0', - 'redirect': '{0:s}/foo/0'.format(portal_path), + 'redirect': f'{portal_path:s}/foo/0', 'redirect-to': '/bar/0', }, ) @@ -183,8 +182,8 @@ def test_redirection_controlpanel_batching(self): portal_path = self.layer['portal'].absolute_url_path() for i in range(1000): storage.add( - '{0:s}/foo/{1:s}'.format(portal_path, str(i)), - '{0:s}/bar/{1:s}'.format(portal_path, str(i)), + '{:s}/foo/{:s}'.format(portal_path, str(i)), + '{:s}/bar/{:s}'.format(portal_path, str(i)), ) view = getMultiAdapter( (self.layer['portal'], self.layer['request']), @@ -200,8 +199,8 @@ def test_redirection_controlpanel_batching(self): def test_redirection_controlpanel_redirect_alias_exists(self): path_alias = '/alias' path_target = '/test-folder' - storage_alias = '/plone{0}'.format(path_alias) - storage_target = '/plone{0}'.format(path_target) + storage_alias = f'/plone{path_alias}' + storage_target = f'/plone{path_target}' storage = getUtility(IRedirectionStorage) storage.add(storage_alias, storage_target) transaction.commit() @@ -213,12 +212,12 @@ def test_redirection_controlpanel_redirect_alias_exists(self): self.assertTrue( storage.get(storage_alias) == storage_target, - '{0} not target of alternative url!'.format(storage_target), + f'{storage_target} not target of alternative url!', ) self.assertTrue( 'The provided alternative url already exists!' in self.browser.contents, - u'Message "alternative url already exists" not in page!', + 'Message "alternative url already exists" not in page!', ) def test_redirection_controlpanel_filtering(self): @@ -226,13 +225,13 @@ def test_redirection_controlpanel_filtering(self): portal_path = self.layer['portal'].absolute_url_path() for i in range(1000): storage.add( - '{0:s}/foo1/{1:s}'.format(portal_path, str(i)), - '{0:s}/bar/{1:s}'.format(portal_path, str(i)), + '{:s}/foo1/{:s}'.format(portal_path, str(i)), + '{:s}/bar/{:s}'.format(portal_path, str(i)), ) for i in range(1000): storage.add( - '{0:s}/foo2/{1:s}'.format(portal_path, str(i)), - '{0:s}/bar/{1:s}'.format(portal_path, str(i)), + '{:s}/foo2/{:s}'.format(portal_path, str(i)), + '{:s}/bar/{:s}'.format(portal_path, str(i)), ) redirects = RedirectionSet() @@ -283,14 +282,14 @@ def test_redirection_controlpanel_filter_manual(self): portal_path = self.layer['portal'].absolute_url_path() for i in range(100): storage.add( - '{0:s}/foo/{1:s}'.format(portal_path, str(i)), - '{0:s}/bar/{1:s}'.format(portal_path, str(i)), + '{:s}/foo/{:s}'.format(portal_path, str(i)), + '{:s}/bar/{:s}'.format(portal_path, str(i)), manual=False, ) for i in range(100, 300): storage.add( - '{0:s}/foo/{1:s}'.format(portal_path, str(i)), - '{0:s}/bar/{1:s}'.format(portal_path, str(i)), + '{:s}/foo/{:s}'.format(portal_path, str(i)), + '{:s}/bar/{:s}'.format(portal_path, str(i)), manual=True, ) @@ -334,8 +333,8 @@ def test_redirection_controlpanel_filter_date(self): time0 = DateTime('2001-01-01') for i in range(400): storage.add( - '{0:s}/foo/{1:s}'.format(portal_path, str(i)), - '{0:s}/bar/{1:s}'.format(portal_path, str(i)), + '{:s}/foo/{:s}'.format(portal_path, str(i)), + '{:s}/bar/{:s}'.format(portal_path, str(i)), now=time0 + i, ) @@ -400,7 +399,7 @@ def test_redirection_controlpanel_redirect_no_target(self): self.assertTrue( 'The provided target object does not exist.' in self.browser.contents, - u'Message "target does not exist" not in page!', + 'Message "target does not exist" not in page!', ) def test_redirection_controlpanel_missing_slash_target(self): @@ -414,7 +413,7 @@ def test_redirection_controlpanel_missing_slash_target(self): self.assertTrue( 'Target path must start with a slash.' in self.browser.contents, - u'Errormessage for missing slash on target path missing', + 'Errormessage for missing slash on target path missing', ) def test_redirection_controlpanel_missing_slash_alias(self): @@ -429,7 +428,7 @@ def test_redirection_controlpanel_missing_slash_alias(self): self.assertTrue( 'Alternative url path must start with a slash.' in self.browser.contents, - u'Errormessage for missing slash on alternative url missing', + 'Errormessage for missing slash on alternative url missing', ) def test_manage_aliases_standard(self): @@ -442,7 +441,7 @@ def test_manage_aliases_standard(self): self.assertTrue( 'Alternative url added.' in self.browser.contents, - u'Message for added alternative url missing', + 'Message for added alternative url missing', ) self.assertTrue(storage.has_path('/plone/alias')) self.assertEqual(storage.get('/plone/alias'), '/plone/test-folder') @@ -464,7 +463,7 @@ def test_manage_aliases_remove(self): self.assertTrue( 'Alternative urls removed.' in self.browser.contents, - u'Message for removed alternative url missing', + 'Message for removed alternative url missing', ) self.assertFalse('/plone/alias1' in storage) self.assertFalse('/plone/alias2' in storage) @@ -486,7 +485,7 @@ def test_manage_aliases_navigation_root(self): self.assertTrue( 'Alternative url added.' in self.browser.contents, - u'Message for added alternative url missing', + 'Message for added alternative url missing', ) self.assertTrue(storage.has_path('/plone/test-folder/alias')) self.assertEqual( @@ -501,7 +500,7 @@ def test_manage_aliases_navigation_root(self): self.assertTrue( 'Alternative url added.' in self.browser.contents, - u'Message for added alternative url missing', + 'Message for added alternative url missing', ) self.assertTrue(storage.has_path('/plone/test-folder/alias2')) self.assertEqual( @@ -589,8 +588,8 @@ def test_absolutize_path(self): storage = getUtility(IRedirectionStorage) portal_path = self.portal.absolute_url_path() storage.add( - '{0:s}/foo'.format(portal_path), - '{0:s}/test-folder'.format(portal_path), + f'{portal_path:s}/foo', + f'{portal_path:s}/test-folder', ) self.assertEqual( ap('/foo', is_source=True), @@ -803,8 +802,8 @@ def test_download_bigger(self): now = DateTime('2019/01/27 10:00:00 GMT-3') for i in range(2000): storage.add( - '{0:s}/foo/{1:s}'.format(portal_path, str(i)), - '{0:s}/bar/{1:s}'.format(portal_path, str(i)), + '{:s}/foo/{:s}'.format(portal_path, str(i)), + '{:s}/bar/{:s}'.format(portal_path, str(i)), now=now, manual=True, ) @@ -840,8 +839,8 @@ def test_download_upload(self): now = DateTime('2019/01/27 10:00:00 GMT-3') for i in range(10): storage.add( - '{0:s}/foo/{1:s}'.format(portal_path, str(i)), - '{0:s}/test-folder'.format(portal_path), + '{:s}/foo/{:s}'.format(portal_path, str(i)), + f'{portal_path:s}/test-folder', now=now, manual=True, ) diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_search.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_search.py index 721d2d7fa4..02358a34d0 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_search.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_search.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import ISearchSchema from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING from plone.app.testing import SITE_OWNER_NAME, SITE_OWNER_PASSWORD @@ -24,7 +23,7 @@ def setUp(self): self.browser.handleErrors = False self.browser.addHeader( 'Authorization', - 'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD,) + f'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}' ) def test_search_control_panel_link(self): diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_security.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_security.py index da811174cf..df4f58c383 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_security.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_security.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import ISecuritySchema from Products.CMFPlone.testing import \ PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING @@ -28,7 +27,7 @@ def setUp(self): self.browser.handleErrors = False self.browser.addHeader( 'Authorization', - 'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD,) + f'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}' ) def test_security_control_panel_link(self): diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_site.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_site.py index dd6c5a053c..583e5e4b83 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_site.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_site.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.testing import SITE_OWNER_NAME, SITE_OWNER_PASSWORD from plone.registry.interfaces import IRegistry from plone.testing.zope import Browser @@ -37,7 +36,7 @@ def setUp(self): self.browser.handleErrors = False self.browser.addHeader( 'Authorization', - 'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD,) + f'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}' ) def test_site_control_panel_link(self): @@ -66,34 +65,34 @@ def test_site_controlpanel_view(self): def test_site_title_is_stored_in_registry(self): self.browser.open( "%s/@@site-controlpanel" % self.portal_url) - self.browser.getControl('Site title').value = u"My Site" + self.browser.getControl('Site title').value = "My Site" self.browser.getControl('Save').click() registry = getUtility(IRegistry) settings = registry.forInterface(ISiteSchema, prefix="plone") - self.assertEqual(settings.site_title, u"My Site") + self.assertEqual(settings.site_title, "My Site") def test_site_title_can_be_looked_up_by_plone_portal_state(self): self.browser.open( "%s/@@site-controlpanel" % self.portal_url) - self.browser.getControl('Site title').value = u"My Site" + self.browser.getControl('Site title').value = "My Site" self.browser.getControl('Save').click() portal_state = getMultiAdapter( (self.portal, self.request), - name=u'plone_portal_state' + name='plone_portal_state' ) - self.assertEqual(portal_state.portal_title(), u'My Site') + self.assertEqual(portal_state.portal_title(), 'My Site') @unittest.skip("XXX: TODO! We have to patch CMFDefault for this.") def test_site_title_can_be_looked_up_by_portal_title(self): self.browser.open( "%s/@@site-controlpanel" % self.portal_url) - self.browser.getControl('Site title').value = u"My Site" + self.browser.getControl('Site title').value = "My Site" self.browser.getControl('Save').click() - self.assertEqual(self.portal.title, u'My Site') - self.assertEqual(self.portal.Title(), u'My Site') + self.assertEqual(self.portal.title, 'My Site') + self.assertEqual(self.portal.Title(), 'My Site') def test_site_logo_is_stored_in_registry(self): self.browser.open( @@ -109,7 +108,7 @@ def test_site_logo_is_stored_in_registry(self): def test_exposeDCMetaTags(self): self.browser.open( "%s/@@site-controlpanel" % self.portal_url) - self.browser.getControl('Site title').value = u"Plone Site" + self.browser.getControl('Site title').value = "Plone Site" self.browser.getControl('Expose Dublin Core metadata').selected = True self.browser.getControl('Save').click() @@ -120,7 +119,7 @@ def test_exposeDCMetaTags(self): def test_exposeDCMetaTags_exposes_meta_tags(self): self.browser.open( "%s/@@site-controlpanel" % self.portal_url) - self.browser.getControl('Site title').value = u"Plone Site" + self.browser.getControl('Site title').value = "Plone Site" self.browser.getControl('Expose Dublin Core metadata').selected = True self.browser.getControl('Save').click() @@ -131,7 +130,7 @@ def test_exposeDCMetaTags_exposes_meta_tags(self): def test_enable_sitemap(self): self.browser.open( "%s/@@site-controlpanel" % self.portal_url) - self.browser.getControl('Site title').value = u"Plone Site" + self.browser.getControl('Site title').value = "Plone Site" self.browser.getControl('Expose sitemap.xml.gz').selected = True self.browser.getControl('Save').click() @@ -142,7 +141,7 @@ def test_enable_sitemap(self): def test_enable_sitemap_enables_the_sitemap(self): self.browser.open( "%s/@@site-controlpanel" % self.portal_url) - self.browser.getControl('Site title').value = u"Plone Site" + self.browser.getControl('Site title').value = "Plone Site" self.browser.getControl('Expose sitemap.xml.gz').selected = True self.browser.getControl('Save').click() @@ -160,26 +159,26 @@ def test_enable_sitemap_enables_the_sitemap(self): def test_webstats_js(self): self.browser.open( "%s/@@site-controlpanel" % self.portal_url) - self.browser.getControl('Site title').value = u"Plone Site" + self.browser.getControl('Site title').value = "Plone Site" self.browser.getControl(name='form.widgets.webstats_js').value = \ - u"" + "" self.browser.getControl('Save').click() registry = getUtility(IRegistry) settings = registry.forInterface(ISiteSchema, prefix="plone") - self.assertEqual(settings.webstats_js, u"") + self.assertEqual(settings.webstats_js, "") def test_webstat_js_shows_up_on_site(self): self.browser.open( "%s/@@site-controlpanel" % self.portal_url) - self.browser.getControl('Site title').value = u"Plone Site" + self.browser.getControl('Site title').value = "Plone Site" self.browser.getControl(name='form.widgets.webstats_js').value = \ - u"" + "" self.browser.getControl('Save').click() registry = getUtility(IRegistry) settings = registry.forInterface(ISiteSchema, prefix="plone") - self.assertEqual(settings.webstats_js, u"") + self.assertEqual(settings.webstats_js, "") self.browser.open(self.portal_url) self.assertTrue("" in self.browser.contents) diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_syndication.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_syndication.py index eb3476674c..c014f9dfe2 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_syndication.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_syndication.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.testing import SITE_OWNER_NAME, SITE_OWNER_PASSWORD from plone.testing.zope import Browser from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING @@ -19,7 +18,7 @@ def setUp(self): self.browser.handleErrors = False self.browser.addHeader( 'Authorization', - 'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD,) + f'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}' ) def test_syndication_controlpanel_link(self): diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_types.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_types.py index 62fbbc1953..57313133f2 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_types.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_types.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING from plone.app.testing import SITE_OWNER_NAME, SITE_OWNER_PASSWORD from plone.testing.zope import Browser @@ -21,7 +20,7 @@ def setUp(self): self.browser.handleErrors = False self.browser.addHeader( 'Authorization', - 'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD,) + f'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}' ) def test_types_control_panel_link(self): diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_usergroups.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_usergroups.py index b8af1888bf..0177044722 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_usergroups.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_usergroups.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.testing import SITE_OWNER_NAME, SITE_OWNER_PASSWORD from Products.CMFCore.utils import getToolByName from plone.testing.zope import Browser @@ -152,7 +151,7 @@ def setUp(self): self.browser.handleErrors = False self.browser.addHeader( 'Authorization', - 'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD,) + f'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}' ) def test_usergroups_control_panel_link(self): diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_usergroups_siteadmin_role.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_usergroups_siteadmin_role.py index 655c1fbad0..9d42df3649 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_usergroups_siteadmin_role.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_browser_usergroups_siteadmin_role.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.testing import login from plone.app.testing import setRoles from plone.app.testing import SITE_OWNER_NAME @@ -42,7 +41,7 @@ def setUp(self): self.browser.handleErrors = False self.browser.addHeader( 'Authorization', - 'Basic %s:%s' % (TEST_USER_ID, TEST_USER_PASSWORD,) + f'Basic {TEST_USER_ID}:{TEST_USER_PASSWORD}' ) self.normal_user = 'DIispfuF' @@ -91,7 +90,7 @@ def testManagerCanDelegateManagerRoleForUsers(self): # a user with the Manager role can grant the Manager role self.browser.addHeader( 'Authorization', - 'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD,) + f'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}' ) self.browser.open(self.usergroups_url) form = { @@ -159,7 +158,7 @@ def testManagerCanDelegateManagerRoleForGroups(self): self.assertEqual(['Reviewer', 'Authenticated'], roles) self.browser.addHeader( 'Authorization', - 'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD,) + f'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}' ) self.browser.open(self.groups_url) form = { diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_dateandtime.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_dateandtime.py index be19604603..ed75bc1727 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_dateandtime.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_dateandtime.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import IDateAndTimeSchema from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING from plone.app.testing import TEST_USER_ID diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_doctest.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_doctest.py index 018dd20a01..03926c62ca 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_doctest.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_doctest.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """Functional Doctests for control panel. """ from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_editing.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_editing.py index 3158d26666..3a5f9c27c0 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_editing.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_editing.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFCore.utils import getToolByName from Products.CMFPlone.interfaces import IEditingSchema from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_events.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_events.py index e89ed55fa3..7bc43c1708 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_events.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_events.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.testing import \ PRODUCTS_CMFPLONE_INTEGRATION_TESTING from Products.CMFCore.utils import getToolByName diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_filter.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_filter.py index fd5d2f016d..c96c5e8c1a 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_filter.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_filter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFCore.utils import getToolByName from Products.CMFPlone.interfaces import IFilterSchema from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_installer.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_installer.py index b15a415298..5ebfd94772 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_installer.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_installer.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFCore.utils import getToolByName from Products.CMFPlone.controlpanel import tests from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_language.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_language.py index 96b0c865ad..b5277dd0e3 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_language.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_language.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.component import getMultiAdapter from zope.component import getUtility from plone.i18n.interfaces import ILanguageSchema diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_mail.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_mail.py index 8de368200b..2b78ace63f 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_mail.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_mail.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.component import getMultiAdapter from zope.component import getUtility from plone.registry.interfaces import IRegistry diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_markup.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_markup.py index aec1268b65..9af62e6e6b 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_markup.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_markup.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFCore.utils import getToolByName from Products.CMFPlone.interfaces import IMarkupSchema from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_navigation.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_navigation.py index a75e3ddff5..62ca94ae2f 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_navigation.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_navigation.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFCore.utils import getToolByName from Products.CMFPlone.interfaces import INavigationSchema from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_overview.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_overview.py index 2a10f997b0..55a368e5d5 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_overview.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_overview.py @@ -1,10 +1,9 @@ -# -*- coding: utf-8 -*- from plone.app.testing import PLONE_INTEGRATION_TESTING from plone.app.testing import TEST_USER_ID from plone.app.testing import setRoles from plone.registry.interfaces import IRegistry from zope.component import getUtility -import mock +from unittest import mock import unittest diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_search.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_search.py index 9cec89cae9..ccdbce6c6b 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_search.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_search.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFCore.utils import getToolByName from Products.CMFPlone.interfaces import ISearchSchema from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_security.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_security.py index 5666e0e94e..f2f39cb42f 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_security.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_security.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFCore.utils import getToolByName from Products.CMFPlone.interfaces import ISecuritySchema from Products.CMFPlone.testing import \ diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_site.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_site.py index 3d49d346ab..38ec5f45e8 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_site.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_site.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFCore.utils import getToolByName from Products.CMFPlone.interfaces import ISiteSchema from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_types.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_types.py index 5f93651cad..1294c6812e 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_types.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_types.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFCore.utils import getToolByName from Products.CMFPlone.interfaces import ITypesSchema from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING diff --git a/Products/CMFPlone/controlpanel/tests/test_controlpanel_usergroups.py b/Products/CMFPlone/controlpanel/tests/test_controlpanel_usergroups.py index 498ce5afa0..6593bfa4f8 100644 --- a/Products/CMFPlone/controlpanel/tests/test_controlpanel_usergroups.py +++ b/Products/CMFPlone/controlpanel/tests/test_controlpanel_usergroups.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.registry.interfaces import IRegistry from Products.CMFCore.utils import getToolByName from Products.CMFPlone.interfaces import IUserGroupsSettingsSchema diff --git a/Products/CMFPlone/controlpanel/tests/test_doctests.py b/Products/CMFPlone/controlpanel/tests/test_doctests.py index dfa3235394..9a93a8552e 100644 --- a/Products/CMFPlone/controlpanel/tests/test_doctests.py +++ b/Products/CMFPlone/controlpanel/tests/test_doctests.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING from plone.testing import layered diff --git a/Products/CMFPlone/controlpanel/utils.py b/Products/CMFPlone/controlpanel/utils.py index 54ee424218..50faf317ac 100644 --- a/Products/CMFPlone/controlpanel/utils.py +++ b/Products/CMFPlone/controlpanel/utils.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFCore.utils import getToolByName import logging diff --git a/Products/CMFPlone/controlpanel/widgets.py b/Products/CMFPlone/controlpanel/widgets.py index 9619c81b7c..4808edd074 100644 --- a/Products/CMFPlone/controlpanel/widgets.py +++ b/Products/CMFPlone/controlpanel/widgets.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from z3c.form.browser.checkbox import CheckBoxWidget from z3c.form.interfaces import NO_VALUE from z3c.form.widget import FieldWidget diff --git a/Products/CMFPlone/defaultpage.py b/Products/CMFPlone/defaultpage.py index fd5cb7e166..626bebb829 100644 --- a/Products/CMFPlone/defaultpage.py +++ b/Products/CMFPlone/defaultpage.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_base from Acquisition import aq_parent from Acquisition import aq_inner diff --git a/Products/CMFPlone/earlypatches/security.py b/Products/CMFPlone/earlypatches/security.py index 15367986d8..5be72b0e7a 100644 --- a/Products/CMFPlone/earlypatches/security.py +++ b/Products/CMFPlone/earlypatches/security.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # 1. make sure allow_module can't be called from restricted code import AccessControl AccessControl.allow_module.__roles__ = () diff --git a/Products/CMFPlone/events.py b/Products/CMFPlone/events.py index faad5c73f8..b9c04fd830 100644 --- a/Products/CMFPlone/events.py +++ b/Products/CMFPlone/events.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.interface import implementer from zope.interface.interfaces import ObjectEvent from Products.CMFPlone.utils import get_installer @@ -29,7 +28,7 @@ def profileImportedEventHandler(event): profile_id = profile_id.replace('profile-', '') gs = event.tool installed_version = gs.getLastVersionForProfile(profile_id) - if installed_version == (u'latest',): + if installed_version == ('latest',): qi = get_installer(gs, gs.REQUEST) actual_version = qi.get_latest_upgrade_step(profile_id) gs.setLastVersionForProfile(profile_id, actual_version) diff --git a/Products/CMFPlone/exportimport/__init__.py b/Products/CMFPlone/exportimport/__init__.py index ee30c6aedb..c9d620a1b0 100644 --- a/Products/CMFPlone/exportimport/__init__.py +++ b/Products/CMFPlone/exportimport/__init__.py @@ -1,2 +1 @@ -# -*- coding: utf-8 -*- """exportimport package""" diff --git a/Products/CMFPlone/exportimport/controlpanel.py b/Products/CMFPlone/exportimport/controlpanel.py index ce4118f9b0..ecf8107973 100644 --- a/Products/CMFPlone/exportimport/controlpanel.py +++ b/Products/CMFPlone/exportimport/controlpanel.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- ############################################################################## # # Copyright (c) 2005 Zope Corporation and Contributors. All Rights Reserved. diff --git a/Products/CMFPlone/exportimport/memberdata_properties.py b/Products/CMFPlone/exportimport/memberdata_properties.py index ee665d68bc..28583460a8 100644 --- a/Products/CMFPlone/exportimport/memberdata_properties.py +++ b/Products/CMFPlone/exportimport/memberdata_properties.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """MemberData tool properties setup handlers. $Id:$ diff --git a/Products/CMFPlone/exportimport/propertiestool.py b/Products/CMFPlone/exportimport/propertiestool.py index c22c452d2e..7d819ed58d 100644 --- a/Products/CMFPlone/exportimport/propertiestool.py +++ b/Products/CMFPlone/exportimport/propertiestool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """Plone Properties tool setup handlers. $Id:$ diff --git a/Products/CMFPlone/exportimport/tests/__init__.py b/Products/CMFPlone/exportimport/tests/__init__.py index aebf08ce44..983bbcadc8 100644 --- a/Products/CMFPlone/exportimport/tests/__init__.py +++ b/Products/CMFPlone/exportimport/tests/__init__.py @@ -1,2 +1 @@ -# -*- coding: utf-8 -*- """exportimport tests package""" diff --git a/Products/CMFPlone/exportimport/tests/base.py b/Products/CMFPlone/exportimport/tests/base.py index 0ae2fad929..fdbb490224 100644 --- a/Products/CMFPlone/exportimport/tests/base.py +++ b/Products/CMFPlone/exportimport/tests/base.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.testing.zca import UNIT_TESTING from Products.GenericSetup.testing import BodyAdapterTestCase from Products.GenericSetup.testing import NodeAdapterTestCase diff --git a/Products/CMFPlone/exportimport/tests/testControlPanel.py b/Products/CMFPlone/exportimport/tests/testControlPanel.py index c8cec8e80e..e2c7d5ba76 100644 --- a/Products/CMFPlone/exportimport/tests/testControlPanel.py +++ b/Products/CMFPlone/exportimport/tests/testControlPanel.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from OFS.Folder import Folder from Products.CMFPlone.exportimport.tests.base import BodyAdapterTestCase from Products.CMFPlone.interfaces import IControlPanel diff --git a/Products/CMFPlone/exportimport/tests/testPropertiesTool.py b/Products/CMFPlone/exportimport/tests/testPropertiesTool.py index 0d185ef413..511ebc786d 100644 --- a/Products/CMFPlone/exportimport/tests/testPropertiesTool.py +++ b/Products/CMFPlone/exportimport/tests/testPropertiesTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.exportimport.tests.base import BodyAdapterTestCase from Products.CMFPlone.PropertiesTool import PropertiesTool from Products.CMFPlone.PropertiesTool import SimpleItemWithProperties diff --git a/Products/CMFPlone/factory.py b/Products/CMFPlone/factory.py index 516ce95985..72556ffb1d 100644 --- a/Products/CMFPlone/factory.py +++ b/Products/CMFPlone/factory.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from logging import getLogger from plone.registry.interfaces import IRegistry from Products.CMFPlone import PloneMessageFactory as _ @@ -24,7 +23,7 @@ @implementer(INonInstallable) -class NonInstallable(object): +class NonInstallable: def getNonInstallableProducts(self): return [ @@ -75,46 +74,46 @@ def getNonInstallableProducts(self): def getNonInstallableProfiles(self): return [_DEFAULT_PROFILE, _CONTENT_PROFILE, - u'Products.Archetypes:Archetypes', - u'Products.ATContentTypes:default', - u'Products.CMFDiffTool:CMFDiffTool', - u'Products.CMFEditions:CMFEditions', - u'Products.CMFFormController:CMFFormController', - u'Products.CMFPlone:dependencies', - u'Products.CMFPlone:testfixture', - u'Products.CMFQuickInstallerTool:CMFQuickInstallerTool', - u'Products.NuPlone:uninstall', - u'Products.MimetypesRegistry:MimetypesRegistry', - u'Products.PasswordResetTool:PasswordResetTool', - u'Products.PortalTransforms:PortalTransforms', - u'Products.PloneLanguageTool:PloneLanguageTool', - u'Products.PlonePAS:PlonePAS', - u'borg.localrole:default', - u'plone.browserlayer:default', - u'plone.keyring:default', - u'plone.outputfilters:default', - u'plone.portlet.static:default', - u'plone.portlet.collection:default', - u'plone.protect:default', - u'plone.app.blob:default', - u'plone.app.blob:file-replacement', - u'plone.app.blob:image-replacement', - u'plone.app.blob:sample-type', - u'plone.app.collection:default', - u'plone.app.contenttypes:default', - u'plone.app.dexterity:default', - u'plone.app.discussion:default', - u'plone.app.event:default', - u'plone.app.imaging:default', - u'plone.app.linkintegrity:default', - u'plone.app.registry:default', - u'plone.app.relationfield:default', - u'plone.app.theming:default', - u'plone.app.users:default', - u'plone.app.versioningbehavior:default', - u'plone.app.z3cform:default', - u'plone.formwidget.recurrence:default', - u'plone.resource:default', + 'Products.Archetypes:Archetypes', + 'Products.ATContentTypes:default', + 'Products.CMFDiffTool:CMFDiffTool', + 'Products.CMFEditions:CMFEditions', + 'Products.CMFFormController:CMFFormController', + 'Products.CMFPlone:dependencies', + 'Products.CMFPlone:testfixture', + 'Products.CMFQuickInstallerTool:CMFQuickInstallerTool', + 'Products.NuPlone:uninstall', + 'Products.MimetypesRegistry:MimetypesRegistry', + 'Products.PasswordResetTool:PasswordResetTool', + 'Products.PortalTransforms:PortalTransforms', + 'Products.PloneLanguageTool:PloneLanguageTool', + 'Products.PlonePAS:PlonePAS', + 'borg.localrole:default', + 'plone.browserlayer:default', + 'plone.keyring:default', + 'plone.outputfilters:default', + 'plone.portlet.static:default', + 'plone.portlet.collection:default', + 'plone.protect:default', + 'plone.app.blob:default', + 'plone.app.blob:file-replacement', + 'plone.app.blob:image-replacement', + 'plone.app.blob:sample-type', + 'plone.app.collection:default', + 'plone.app.contenttypes:default', + 'plone.app.dexterity:default', + 'plone.app.discussion:default', + 'plone.app.event:default', + 'plone.app.imaging:default', + 'plone.app.linkintegrity:default', + 'plone.app.registry:default', + 'plone.app.relationfield:default', + 'plone.app.theming:default', + 'plone.app.users:default', + 'plone.app.versioningbehavior:default', + 'plone.app.z3cform:default', + 'plone.formwidget.recurrence:default', + 'plone.resource:default', ] @@ -160,7 +159,7 @@ def addPloneSite(context, site_id, title='Plone site', description='', # during site creation. content_types_profile = content_profile_id if setup_content else _TYPES_PROFILE - setup_tool.runAllImportStepsFromProfile('profile-{0}'.format(content_types_profile)) + setup_tool.runAllImportStepsFromProfile(f'profile-{content_types_profile}') props = dict( title=title, diff --git a/Products/CMFPlone/i18nl10n.py b/Products/CMFPlone/i18nl10n.py index 9599e3067b..b5fdaa64f5 100644 --- a/Products/CMFPlone/i18nl10n.py +++ b/Products/CMFPlone/i18nl10n.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Collection of i18n and l10n utility methods. """ @@ -24,7 +23,7 @@ r'(?sitemaps.org ' - u'standard. You ' - u'can submit this to compliant search engines ' - u'like Google, Yahoo and Microsoft. It allows ' - u'these search engines to more intelligently ' - u'crawl your site.'), + title=_('Expose sitemap.xml.gz'), + description=_( + 'Exposes your content as a file ' + 'according to the ' + 'sitemaps.org ' + 'standard. You ' + 'can submit this to compliant search engines ' + 'like Google, Yahoo and Microsoft. It allows ' + 'these search engines to more intelligently ' + 'crawl your site.'), default=False, required=False) webstats_js = schema.SourceText( - title=_(u'JavaScript for web statistics support'), - description=_( - u'For enabling web statistics support ' - u'from external providers (e.g. Google ' - u'Analytics). Paste the provided code snippet here. ' - u'It will be rendered as ' - u'entered near the end of the page.'), - default=u'', + title=_('JavaScript for web statistics support'), + description=_( + 'For enabling web statistics support ' + 'from external providers (e.g. Google ' + 'Analytics). Paste the provided code snippet here. ' + 'It will be rendered as ' + 'entered near the end of the page.'), + default='', required=False) display_publication_date_in_byline = schema.Bool( - title=_(u'Display publication date'), + title=_('Display publication date'), description=_( - u'Show in the byline the date a content item was published.'), + 'Show in the byline the date a content item was published.'), default=False, required=False) icon_visibility = schema.Choice( - title=_(u'Icon visibility'), - description=_(u'Show icons in listings'), - default=u'enabled', + title=_('Icon visibility'), + description=_('Show icons in listings'), + default='enabled', vocabulary=SimpleVocabulary([ - SimpleTerm('false', 'false', _(u'Never')), - SimpleTerm('enabled', 'enabled', _(u'Always')), + SimpleTerm('false', 'false', _('Never')), + SimpleTerm('enabled', 'enabled', _('Always')), SimpleTerm('authenticated', 'authenticated', _('For authenticated users only'))]), required=True) thumb_visibility = schema.Choice( - title=_(u'Thumb visibility'), - description=_(u'Show thumbnail images in listings'), - default=u'enabled', + title=_('Thumb visibility'), + description=_('Show thumbnail images in listings'), + default='enabled', vocabulary=SimpleVocabulary([ - SimpleTerm('false', 'false', _(u'Never')), - SimpleTerm('enabled', 'enabled', _(u'Always')), + SimpleTerm('false', 'false', _('Never')), + SimpleTerm('enabled', 'enabled', _('Always')), SimpleTerm('authenticated', 'authenticated', - _(u'For authenticated users only'))]), + _('For authenticated users only'))]), required=True) no_thumbs_portlet = schema.Bool( - title=_(u'No Thumbs in portlets'), + title=_('No Thumbs in portlets'), description=_( - u'Suppress thumbs in all portlets;' - u' this default can be overridden individually ' - u'in selected portlets'), + 'Suppress thumbs in all portlets;' + ' this default can be overridden individually ' + 'in selected portlets'), default=False, required=False) no_thumbs_lists = schema.Bool( - title=_(u'No thumbs in list views'), - description=_(u'Suppress thumbs in all list views; ' - u'this default can be overriden individually'), + title=_('No thumbs in list views'), + description=_('Suppress thumbs in all list views; ' + 'this default can be overriden individually'), default=False, required=False) no_thumbs_summary = schema.Bool( - title=_(u'No thumbs in summary views'), - description=_(u'Suppress thumbs in all summary views; ' - u'this default can be overriden individually'), + title=_('No thumbs in summary views'), + description=_('Suppress thumbs in all summary views; ' + 'this default can be overriden individually'), default=False, required=False) no_thumbs_tables = schema.Bool( - title=_(u'No thumbs in table views'), description=_( - u'Suppress thumbs in all tableviews and in folder contents view; ' - u'this default can be overriden individually'), + title=_('No thumbs in table views'), description=_( + 'Suppress thumbs in all tableviews and in folder contents view; ' + 'this default can be overriden individually'), default=False, required=False) thumb_scale_portlet = schema.Choice( - title=_(u'Thumb scale for portlets'), - description=_(u'This default can be overriden individually.'), - default=u'icon', + title=_('Thumb scale for portlets'), + description=_('This default can be overriden individually.'), + default='icon', vocabulary='plone.app.vocabularies.ImagesScales', required=True) thumb_scale_listing = schema.Choice( - title=_(u'Thumb scale for listings'), - description=_(u'E.g. standard view;' - u' This default can be overriden individually.'), - default=u'thumb', + title=_('Thumb scale for listings'), + description=_('E.g. standard view;' + ' This default can be overriden individually.'), + default='thumb', vocabulary='plone.app.vocabularies.ImagesScales', required=True) thumb_scale_table = schema.Choice( - title=_(u'Thumb scale for tables'), - description=_(u'E.g., tabular view, folder content listing;' - u' This default can be overriden individually.'), - default=u'tile', + title=_('Thumb scale for tables'), + description=_('E.g., tabular view, folder content listing;' + ' This default can be overriden individually.'), + default='tile', vocabulary='plone.app.vocabularies.ImagesScales', required=True) thumb_scale_summary = schema.Choice( - title=_(u'Thumb scale for summary view'), - description=_(u'This default can be overriden individually.'), - default=u'mini', + title=_('Thumb scale for summary view'), + description=_('This default can be overriden individually.'), + default='mini', vocabulary='plone.app.vocabularies.ImagesScales', required=True) toolbar_position = schema.Choice( - title=_(u'Toolbar position'), + title=_('Toolbar position'), description=_( - u'It can be on the side (vertical mode) ' - u'or on the top (horizontal mode)'), - default=u'side', + 'It can be on the side (vertical mode) ' + 'or on the top (horizontal mode)'), + default='side', vocabulary=SimpleVocabulary([ - SimpleTerm('side', 'side', _(u'Side')), - SimpleTerm('top', 'top', _(u'Top'))]), + SimpleTerm('side', 'side', _('Side')), + SimpleTerm('top', 'top', _('Top'))]), required=True) toolbar_logo = schema.TextLine( - title=_(u'Relative URL for the toolbar logo'), + title=_('Relative URL for the toolbar logo'), description=_( - u'This must be a URL relative to the site root. ' - u'By default it is /++plone++static/plone-toolbarlogo.svg'), - default=u'/++plone++static/plone-toolbarlogo.svg', + 'This must be a URL relative to the site root. ' + 'By default it is /++plone++static/plone-toolbarlogo.svg'), + default='/++plone++static/plone-toolbarlogo.svg', required=False, ) robots_txt = schema.SourceText( title=_('robots.txt'), description=_( - u'help_robots_txt', - default=u'robots.txt is read by search engines to ' - u'determine how to index your site. ' - u'For details see ' - u'http://www.robotstxt.org. ' - u'Use \'{portal_url}\' for the site URL.'), + 'help_robots_txt', + default='robots.txt is read by search engines to ' + 'determine how to index your site. ' + 'For details see ' + 'http://www.robotstxt.org. ' + 'Use \'{portal_url}\' for the site URL.'), default=ROBOTS_TXT, required=False, ) default_page = schema.List( - title=_(u'Default page IDs'), + title=_('Default page IDs'), description=_( - u'Select which IDs (short names) can act as fallback ' - u'default pages for a container.'), + 'Select which IDs (short names) can act as fallback ' + 'default pages for a container.'), required=False, default=[ - u'index_html', - u'index.html', - u'index.htm', - u'FrontPage'], + 'index_html', + 'index.html', + 'index.htm', + 'FrontPage'], missing_value=[], value_type=schema.TextLine()) roles_allowed_to_add_keywords = schema.List( - title=_(u'Roles that can add keywords'), + title=_('Roles that can add keywords'), description=_( - u'help_allow_roles_to_add_keywords', - default=u'Only the following roles can add new keywords '), + 'help_allow_roles_to_add_keywords', + default='Only the following roles can add new keywords '), required=False, default=[ - u'Manager', - u'Site Administrator', - u'Reviewer', + 'Manager', + 'Site Administrator', + 'Reviewer', ], missing_value=[], value_type=schema.Choice(vocabulary='plone.app.vocabularies.Roles'), @@ -1194,22 +1193,22 @@ class IDateAndTimeSchema(Interface): """ portal_timezone = schema.Choice( - title=_(u'Portal default timezone'), + title=_('Portal default timezone'), description=_( - u'help_portal_timezone', - default=u'The timezone setting of the portal. Users can set ' - u'their own timezone, if available timezones are ' - u'defined.'), + 'help_portal_timezone', + default='The timezone setting of the portal. Users can set ' + 'their own timezone, if available timezones are ' + 'defined.'), required=True, default=None, vocabulary='plone.app.vocabularies.CommonTimezones') available_timezones = schema.List( - title=_(u'Available timezones'), + title=_('Available timezones'), description=_( - u'help_available_timezones', - default=u'The timezones, which should be available for the ' - u'portal. Can be set for users and events'), + 'help_available_timezones', + default='The timezones, which should be available for the ' + 'portal. Can be set for users and events'), required=False, default=[], missing_value=[], @@ -1217,10 +1216,10 @@ class IDateAndTimeSchema(Interface): vocabulary='plone.app.vocabularies.Timezones')) first_weekday = schema.Choice( - title=_(u'label_first_weekday', default=u'First weekday'), + title=_('label_first_weekday', default='First weekday'), description=_( - u'help_first_weekday', - default=u'First day in the week.'), + 'help_first_weekday', + default='First day in the week.'), required=True, default=None, vocabulary='plone.app.vocabularies.Weekdays') @@ -1231,42 +1230,42 @@ class ITypesSchema(Interface): """ types_use_view_action_in_listings = schema.List( - title=_(u'Types which use the view action in listing views.'), + title=_('Types which use the view action in listing views.'), description=_( - u'help_types_use_view_action_in_listings', - default=u'When clicking items in listing views, these ' - u'types will use the \'view\' action instead of using ' - u'their default view.'), + 'help_types_use_view_action_in_listings', + default='When clicking items in listing views, these ' + 'types will use the \'view\' action instead of using ' + 'their default view.'), required=False, - default=[u'Image', - u'File'], + default=['Image', + 'File'], missing_value=[], value_type=schema.TextLine(), ) redirect_links = schema.Bool( - title=_(u'Redirect links'), + title=_('Redirect links'), description=_( - u'help_redirect_links', - default=u'When clicking on a Link type, should the user be ' - u'taken to the default view or be redirected to the ' - u'Link\'s URL?'), + 'help_redirect_links', + default='When clicking on a Link type, should the user be ' + 'taken to the default view or be redirected to the ' + 'Link\'s URL?'), required=False, default=True ) default_page_types = schema.List( - title=_(u'Types that can be set as a default page'), + title=_('Types that can be set as a default page'), description=_( - u'The content types that should be available for selection ' - u'when setting a default page.'), + 'The content types that should be available for selection ' + 'when setting a default page.'), required=False, missing_value=[], default=[ - u'Document', - u'Event', - u'News Item', - u'Collection', + 'Document', + 'Event', + 'News Item', + 'Collection', ], value_type=schema.TextLine() ) @@ -1276,76 +1275,76 @@ class IMailSchema(Interface): smtp_host = schema.TextLine( title=_( - u'label_smtp_server', - default=u'SMTP server'), - description=_( - u'help_smtp_server', - default=u'The address of your local ' - u'SMTP (outgoing e-mail) server. Usually ' - u'\'localhost\', unless you use an ' - u'external server to send e-mail.'), - default=u'localhost', + 'label_smtp_server', + default='SMTP server'), + description=_( + 'help_smtp_server', + default='The address of your local ' + 'SMTP (outgoing e-mail) server. Usually ' + '\'localhost\', unless you use an ' + 'external server to send e-mail.'), + default='localhost', required=True) smtp_port = schema.Int( - title=_(u'label_smtp_port', - default=u'SMTP port'), + title=_('label_smtp_port', + default='SMTP port'), description=_( - u'help_smtp_port', - default=u'The port of your local SMTP ' - u'(outgoing e-mail) server. Usually \'25\'.' + 'help_smtp_port', + default='The port of your local SMTP ' + '(outgoing e-mail) server. Usually \'25\'.' ), default=25, required=True) smtp_userid = schema.TextLine( title=_( - u'label_smtp_userid', - default=u'ESMTP username'), + 'label_smtp_userid', + default='ESMTP username'), description=_( - u'help_smtp_userid', - default=u'Username for authentication ' - u'to your e-mail server. Not required ' - u'unless you are using ESMTP.'), + 'help_smtp_userid', + default='Username for authentication ' + 'to your e-mail server. Not required ' + 'unless you are using ESMTP.'), default=None, required=False) smtp_pass = schema.Password( title=_( - u'label_smtp_pass', - default=u'ESMTP password'), + 'label_smtp_pass', + default='ESMTP password'), description=_( - u'help_smtp_pass', - default=u'The password for the ESMTP ' - u'user account.'), + 'help_smtp_pass', + default='The password for the ESMTP ' + 'user account.'), default=None, required=False) email_from_name = schema.TextLine( - title=_(u'Site \'From\' name'), + title=_('Site \'From\' name'), description=_( - u'Plone generates e-mail using ' - u'this name as the e-mail ' - u'sender.'), + 'Plone generates e-mail using ' + 'this name as the e-mail ' + 'sender.'), default=None, required=True) email_from_address = schema.ASCIILine( - title=_(u'Site \'From\' address'), - description=_( - u'Plone generates e-mail using ' - u'this address as the e-mail ' - u'return address. It is also ' - u'used as the destination ' - u'address for the site-wide ' - u'contact form and the \'Send test ' - u'e-mail\' feature.'), + title=_('Site \'From\' address'), + description=_( + 'Plone generates e-mail using ' + 'this address as the e-mail ' + 'return address. It is also ' + 'used as the destination ' + 'address for the site-wide ' + 'contact form and the \'Send test ' + 'e-mail\' feature.'), default=None, required=True) email_charset = schema.ASCIILine( - title=_(u'E-mail characterset'), - description=_(u'Characterset to use when sending e-mails.'), + title=_('E-mail characterset'), + description=_('Characterset to use when sending e-mails.'), default='utf-8', required=True, ) @@ -1354,24 +1353,24 @@ class IMailSchema(Interface): class IMarkupSchema(Interface): default_type = schema.Choice( - title=_(u'Default format'), + title=_('Default format'), description=_( - u'Select the default format of textfields for newly ' - u'created content objects.' + 'Select the default format of textfields for newly ' + 'created content objects.' ), - default=u'text/html', + default='text/html', vocabulary='plone.app.vocabularies.AllowableContentTypes', required=True ) allowed_types = schema.Tuple( - title=_(u'Alternative formats'), + title=_('Alternative formats'), description=_( - u'Select which formats are available for users as ' - u'alternative to the default format. Note that if new ' - u'formats are installed, they will be enabled for text ' - u'fields by default unless explicitly turned off here ' - u'or by the relevant installer.' + 'Select which formats are available for users as ' + 'alternative to the default format. Note that if new ' + 'formats are installed, they will be enabled for text ' + 'fields by default unless explicitly turned off here ' + 'or by the relevant installer.' ), required=True, default=('text/html', 'text/x-web-textile'), @@ -1387,12 +1386,12 @@ class IMarkupSchema(Interface): 'markdown.extensions.nl2br', ], description=_( - u'Look for available extensions at ' - u'https://python-markdown.github.io/extensions/ or write your own.' + 'Look for available extensions at ' + 'https://python-markdown.github.io/extensions/ or write your own.' ), missing_value=(), required=False, - title=_(u'Enabled markdown extensions'), + title=_('Enabled markdown extensions'), value_type=schema.TextLine() ) @@ -1400,28 +1399,28 @@ class IMarkupSchema(Interface): class IUserGroupsSettingsSchema(Interface): many_groups = schema.Bool( - title=_(u'Many groups?'), - description=_( - u'Determines if your Plone is optimized ' - u'for small or large sites. In environments with a ' - u'lot of groups it can be very slow or impossible ' - u'to build a list all groups. This option tunes the ' - u'user interface and behaviour of Plone for this ' - u'case by allowing you to search for groups instead ' - u'of listing all of them.'), + title=_('Many groups?'), + description=_( + 'Determines if your Plone is optimized ' + 'for small or large sites. In environments with a ' + 'lot of groups it can be very slow or impossible ' + 'to build a list all groups. This option tunes the ' + 'user interface and behaviour of Plone for this ' + 'case by allowing you to search for groups instead ' + 'of listing all of them.'), default=False ) many_users = schema.Bool( - title=_(u'Many users?'), - description=_( - u'Determines if your Plone is optimized ' - u'for small or large sites. In environments with a ' - u'lot of users it can be very slow or impossible to ' - u'build a list all users. This option tunes the user ' - u'interface and behaviour of Plone for this case by ' - u'allowing you to search for users instead of ' - u'listing all of them.'), + title=_('Many users?'), + description=_( + 'Determines if your Plone is optimized ' + 'for small or large sites. In environments with a ' + 'lot of users it can be very slow or impossible to ' + 'build a list all users. This option tunes the user ' + 'interface and behaviour of Plone for this case by ' + 'allowing you to search for users instead of ' + 'listing all of them.'), default=False ) @@ -1429,24 +1428,24 @@ class IUserGroupsSettingsSchema(Interface): def validate_twitter_username(value): if value and value.startswith('@'): raise Invalid( - u'Twitter username should not include the "@" prefix character.') + 'Twitter username should not include the "@" prefix character.') return True class ISocialMediaSchema(Interface): share_social_data = schema.Bool( - title=_(u'Share social data'), - description=_(u'Include meta tags on pages to give hints to ' - u'social media on how to better render your pages ' - u'when shared'), + title=_('Share social data'), + description=_('Include meta tags on pages to give hints to ' + 'social media on how to better render your pages ' + 'when shared'), default=True) twitter_username = schema.ASCIILine( - title=_(u'Twitter username'), + title=_('Twitter username'), description=_( - u'To identify things like Twitter Cards. ' - u'Do not include the "@" prefix character.' + 'To identify things like Twitter Cards. ' + 'Do not include the "@" prefix character.' ), required=False, default='', @@ -1454,42 +1453,42 @@ class ISocialMediaSchema(Interface): ) facebook_app_id = schema.ASCIILine( - title=_(u'Facebook App ID'), + title=_('Facebook App ID'), description=_( - u'To be used with some integrations like Open Graph data'), + 'To be used with some integrations like Open Graph data'), required=False, default='') facebook_username = schema.ASCIILine( - title=_(u'Facebook username'), - description=_(u'For linking Open Graph data to a Facebook account'), + title=_('Facebook username'), + description=_('For linking Open Graph data to a Facebook account'), required=False, default='') class IImagingSchema(Interface): allowed_sizes = schema.List( - title=_(u'Allowed image sizes'), + title=_('Allowed image sizes'), description=_( - u'Specify all allowed maximum image dimensions, one per line. The ' - u'required format is <name> <width>:<height>.' + 'Specify all allowed maximum image dimensions, one per line. The ' + 'required format is <name> <width>:<height>.' ), value_type=schema.TextLine(), default=[ - u'large 768:768', - u'preview 400:400', - u'mini 200:200', - u'thumb 128:128', - u'tile 64:64', - u'icon 32:32', - u'listing 16:16'], + 'large 768:768', + 'preview 400:400', + 'mini 200:200', + 'thumb 128:128', + 'tile 64:64', + 'icon 32:32', + 'listing 16:16'], missing_value=[], required=False, ) quality = schema.Int( - title=_(u'Scaled image quality'), - description=_(u'A value for the quality of scaled images, from 1 ' + title=_('Scaled image quality'), + description=_('A value for the quality of scaled images, from 1 ' '(lowest) to 95 (highest). A value of 0 will mean ' 'plone.scaling\'s default will be used, which is ' 'currently 88.'), @@ -1499,19 +1498,19 @@ class IImagingSchema(Interface): ) highpixeldensity_scales = schema.Choice( - title=_(u'High pixel density mode'), - description=_(u''), + title=_('High pixel density mode'), + description=_(''), default='disabled', vocabulary=SimpleVocabulary([ - SimpleTerm('disabled', 'disabled', u'Disabled'), - SimpleTerm('2x', '2x', u'Enabled (2x)'), - SimpleTerm('3x', '3x', u'Enabled (2x, 3x)') + SimpleTerm('disabled', 'disabled', 'Disabled'), + SimpleTerm('2x', '2x', 'Enabled (2x)'), + SimpleTerm('3x', '3x', 'Enabled (2x, 3x)') ]), ) quality_2x = schema.Int( - title=_(u'Image quality at 2x'), - description=_(u'A value for the quality of 2x high pixel density images, from 1 ' + title=_('Image quality at 2x'), + description=_('A value for the quality of 2x high pixel density images, from 1 ' '(lowest) to 95 (highest). A value of 0 will mean ' 'plone.scaling\'s default will be used, which is ' 'currently 62.'), @@ -1521,8 +1520,8 @@ class IImagingSchema(Interface): ) quality_3x = schema.Int( - title=_(u'Image quality at 3x'), - description=_(u'A value for the quality of 3x high pixel density images, from 1 ' + title=_('Image quality at 3x'), + description=_('A value for the quality of 3x high pixel density images, from 1 ' '(lowest) to 95 (highest). A value of 0 will mean ' 'plone.scaling\'s default will be used, which is ' 'currently 51.'), @@ -1532,10 +1531,10 @@ class IImagingSchema(Interface): ) image_captioning = schema.Bool( - title=_('image_captioning_title', u'Enable image captioning'), + title=_('image_captioning_title', 'Enable image captioning'), description=_( 'image_captioning_description', - u'Enable automatic image captioning for images set in the richtext editor based on the description of images.' + 'Enable automatic image captioning for images set in the richtext editor based on the description of images.' ), default=True, required=False @@ -1545,38 +1544,38 @@ class IImagingSchema(Interface): class ILoginSchema(Interface): auth_cookie_length = schema.Int( - title=_(u'Auth cookie length'), + title=_('Auth cookie length'), default=0, required=False ) verify_login_name = schema.Bool( - title=_(u'Verify login name'), + title=_('Verify login name'), default=True, required=False ) allow_external_login_sites = schema.Tuple( - title=_(u'Allow external login sites'), + title=_('Allow external login sites'), default=(), value_type=schema.ASCIILine(), required=False ) external_login_url = schema.ASCIILine( - title=_(u'External login url'), + title=_('External login url'), default=None, required=False ) external_logout_url = schema.ASCIILine( - title=_(u'External logout url'), + title=_('External logout url'), default=None, required=False ) external_login_iframe = schema.Bool( - title=_(u'External login iframe'), + title=_('External login iframe'), default=False, required=False ) @@ -1585,14 +1584,14 @@ class ILoginSchema(Interface): class ILinkSchema(Interface): external_links_open_new_window = schema.Bool( - title=_(u'Open external links in new a window'), - description=_(u''), + title=_('Open external links in new a window'), + description=_(''), default=False, required=False) mark_special_links = schema.Bool( - title=_(u'Mark special links'), - description=_(u'Marks external or special protocol links with class.'), + title=_('Mark special links'), + description=_('Marks external or special protocol links with class.'), default=False, required=False) @@ -1614,44 +1613,44 @@ def _check_tales_expression(value): class IActionSchema(Interface): category = schema.Choice( - title=_(u'Category'), + title=_('Category'), vocabulary='plone.app.vocabularies.PortalActionCategories', required=True) title = schema.TextLine( - title=_(u'Title'), + title=_('Title'), required=True) description = schema.Text( - title=_(u'Description'), + title=_('Description'), required=False) i18n_domain = schema.TextLine( - title=_(u'i18n_domain_heading', default=u'I18n domain'), - default=u'plone', + title=_('i18n_domain_heading', default='I18n domain'), + default='plone', required=False) url_expr = schema.ASCIILine( - title=_(u'action_url_heading', default=u'Action URL'), + title=_('action_url_heading', default='Action URL'), description=_( - u'action_url_description', - default=u'An expression producing the called URL. ' - u'Example: string:${globals_view/navigationRootUrl}/page' + 'action_url_description', + default='An expression producing the called URL. ' + 'Example: string:${globals_view/navigationRootUrl}/page' ), required=True, constraint=_check_tales_expression, ) available_expr = schema.ASCIILine( - title=_(u'action_condition_heading', default=u'Condition'), + title=_('action_condition_heading', default='Condition'), description=_( - u'action_condition_description', - default=u'A boolean expression' + 'action_condition_description', + default='A boolean expression' ), required=False) permissions = schema.List( - title=_(u'action_permissions_heading', default=u'Permissions'), + title=_('action_permissions_heading', default='Permissions'), required=True, default=['View'], missing_value=[], @@ -1661,12 +1660,12 @@ class IActionSchema(Interface): ) visible = schema.Bool( - title=_(u'action_visibility_heading', default=u'Visible?'), + title=_('action_visibility_heading', default='Visible?'), default=True, required=False) position = schema.Int( - title=_(u'action_position_heading', default=u'Position'), + title=_('action_position_heading', default='Position'), default=1, min=1, required=True) @@ -1675,12 +1674,12 @@ class IActionSchema(Interface): class INewActionSchema(Interface): category = schema.Choice( - title=_(u'Category'), + title=_('Category'), vocabulary='plone.app.vocabularies.PortalActionCategories', required=True) id = schema.ASCIILine( - title=_(u'Id'), + title=_('Id'), required=True) @invariant diff --git a/Products/CMFPlone/interfaces/defaultpage.py b/Products/CMFPlone/interfaces/defaultpage.py index 0aa7d79a67..8b869b1cdd 100644 --- a/Products/CMFPlone/interfaces/defaultpage.py +++ b/Products/CMFPlone/interfaces/defaultpage.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.interface import Interface diff --git a/Products/CMFPlone/interfaces/events.py b/Products/CMFPlone/interfaces/events.py index e0dceb5187..f83cc0430d 100644 --- a/Products/CMFPlone/interfaces/events.py +++ b/Products/CMFPlone/interfaces/events.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.interface import Attribute from zope.interface import Interface from zope.interface.interfaces import IObjectEvent diff --git a/Products/CMFPlone/interfaces/installable.py b/Products/CMFPlone/interfaces/installable.py index f0e632056c..e9994df0fa 100644 --- a/Products/CMFPlone/interfaces/installable.py +++ b/Products/CMFPlone/interfaces/installable.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.interface import Interface diff --git a/Products/CMFPlone/interfaces/interface.py b/Products/CMFPlone/interfaces/interface.py index c720a8cf14..589430c96b 100644 --- a/Products/CMFPlone/interfaces/interface.py +++ b/Products/CMFPlone/interfaces/interface.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces.basetool import IPloneBaseTool from zope.interface import Attribute diff --git a/Products/CMFPlone/interfaces/language.py b/Products/CMFPlone/interfaces/language.py index 73fa1e9731..e3838c37a9 100644 --- a/Products/CMFPlone/interfaces/language.py +++ b/Products/CMFPlone/interfaces/language.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.interface import Interface diff --git a/Products/CMFPlone/interfaces/login.py b/Products/CMFPlone/interfaces/login.py index a86278cc01..d86b1521c4 100644 --- a/Products/CMFPlone/interfaces/login.py +++ b/Products/CMFPlone/interfaces/login.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone import PloneMessageFactory as _ from plone.schema.email import Email from plone.z3cform.interfaces import IWrappedForm @@ -23,11 +22,11 @@ class ILogin(Interface): """ Login form schema """ login = schema.TextLine( - title=_(u'label_log_in', default=u'Log in'), + title=_('label_log_in', default='Log in'), ) password = schema.Password( - title=_(u'label_password', default=u'Password'), + title=_('label_password', default='Password'), ) @@ -39,17 +38,17 @@ class ILoginFormSchema(Interface): """ Login form schema """ ac_name = schema.TextLine( - title=_(u'label_login_name', default=u'Login Name'), + title=_('label_login_name', default='Login Name'), required=True, ) ac_password = schema.Password( - title=_(u'label_password', default=u'Password'), + title=_('label_password', default='Password'), required=True, ) came_from = schema.TextLine( - title=u'Came From', # not translated, hidden field + title='Came From', # not translated, hidden field required=False, ) @@ -62,21 +61,21 @@ class ILoginHelpFormSchema(Interface): """ Login Help form schema """ reset_password = schema.TextLine( - title=_(u'label_pwreset_username', default=u'Username'), + title=_('label_pwreset_username', default='Username'), description=_( - u'help_pwreset_username', - default=u'Enter your username ' - u'or email and we’ll send you a password reset link.', + 'help_pwreset_username', + default='Enter your username ' + 'or email and we’ll send you a password reset link.', ), required=True, ) recover_username = Email( - title=_(u'label_pwreset_email', default=u'Email'), + title=_('label_pwreset_email', default='Email'), description=_( - u'help_pwreset_email', - default=u'Enter your email and ' - u'we’ll send you your username.', + 'help_pwreset_email', + default='Enter your email and ' + 'we’ll send you your username.', ), required=True, ) diff --git a/Products/CMFPlone/interfaces/migration.py b/Products/CMFPlone/interfaces/migration.py index e956544e29..2ae6a851f6 100644 --- a/Products/CMFPlone/interfaces/migration.py +++ b/Products/CMFPlone/interfaces/migration.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.interface import Interface diff --git a/Products/CMFPlone/interfaces/patterns.py b/Products/CMFPlone/interfaces/patterns.py index 89e7255d04..9a7a0add78 100644 --- a/Products/CMFPlone/interfaces/patterns.py +++ b/Products/CMFPlone/interfaces/patterns.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.interface import Interface diff --git a/Products/CMFPlone/interfaces/properties.py b/Products/CMFPlone/interfaces/properties.py index 1c137a35c3..560c80b399 100644 --- a/Products/CMFPlone/interfaces/properties.py +++ b/Products/CMFPlone/interfaces/properties.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.interface import Interface from zope.interface import Attribute diff --git a/Products/CMFPlone/interfaces/resources.py b/Products/CMFPlone/interfaces/resources.py index b2ed2372d0..91a16a0d8e 100644 --- a/Products/CMFPlone/interfaces/resources.py +++ b/Products/CMFPlone/interfaces/resources.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import zope.interface import zope.component from zope import schema @@ -13,132 +12,132 @@ class IResourceRegistry(zope.interface.Interface): url = schema.ASCIILine( - title=_(u"Resources base URL"), + title=_("Resources base URL"), required=False) js = schema.ASCIILine( - title=_(u"Main js file"), + title=_("Main js file"), required=False) css = schema.List( - title=_(u"CSS/LESS files"), - value_type=schema.ASCIILine(title=_(u"URL")), + title=_("CSS/LESS files"), + value_type=schema.ASCIILine(title=_("URL")), default=[], required=False) init = schema.ASCIILine( - title=_(u"Init instruction for shim"), + title=_("Init instruction for shim"), required=False) deps = schema.ASCIILine( - title=_(u"Dependencies for shim"), - description=_(u"Comma separated values of resource for shim"), + title=_("Dependencies for shim"), + description=_("Comma separated values of resource for shim"), required=False) export = schema.ASCIILine( - title=_(u"Export vars for shim"), + title=_("Export vars for shim"), required=False) conf = schema.Text( - title=_(u"Configuration in JSON for the widget"), - description=_(u"Should be accessible on @@getWCconfig?id=name"), + title=_("Configuration in JSON for the widget"), + description=_("Should be accessible on @@getWCconfig?id=name"), required=False) class IBundleRegistry(zope.interface.Interface): jscompilation = schema.ASCIILine( - title=_(u"URL of the last js compilation"), + title=_("URL of the last js compilation"), required=False) csscompilation = schema.ASCIILine( - title=_(u"URL of the last css compilation"), + title=_("URL of the last css compilation"), required=False) last_compilation = schema.Datetime( - title=_(u"Last compiled date"), - description=_(u"Date time of the last compilation of this bundle"), + title=_("Last compiled date"), + description=_("Date time of the last compilation of this bundle"), required=False) expression = schema.ASCIILine( - title=_(u"Expression to render"), + title=_("Expression to render"), description=_( - u"In case its a bundle we can have a condition to render it (it " + "In case its a bundle we can have a condition to render it (it " "does not apply if the bundle is merged)."), required=False) conditionalcomment = schema.ASCIILine( - title=_(u"Conditional comment"), + title=_("Conditional comment"), description=_( - u"In case you want to render this resource on conditional comment " + "In case you want to render this resource on conditional comment " "(it does not apply if the bundle is merged)."), required=False) resources = schema.List( - title=_(u"Loaded resources"), + title=_("Loaded resources"), description=_( - u"The resources that are going to be loaded on this bundle in order"), - value_type=schema.ASCIILine(title=_(u"Resource name")), + "The resources that are going to be loaded on this bundle in order"), + value_type=schema.ASCIILine(title=_("Resource name")), required=False) enabled = schema.Bool( - title=_(u"It's enabled?"), + title=_("It's enabled?"), default=True, required=False) compile = schema.Bool( - title=_(u"Does your bundle contains any RequireJS or LESS file?"), + title=_("Does your bundle contains any RequireJS or LESS file?"), description=_( - u"If its true and you modify this bundle you need to build it before production"), + "If its true and you modify this bundle you need to build it before production"), default=True, required=False) depends = schema.ASCIILine( - title=_(u"Depends on another bundle"), + title=_("Depends on another bundle"), description=_( - u"In case you want to be the last: *, in case its the first should be empty"), + "In case you want to be the last: *, in case its the first should be empty"), required=False) develop_javascript = schema.Bool( - title=_(u'Develop JavaScript'), + title=_('Develop JavaScript'), default=False) develop_css = schema.Bool( - title=_(u'Develop CSS'), + title=_('Develop CSS'), default=False) stub_js_modules = schema.List( - title=_(u'Stub JavaScript modules'), - description=_(u'Define list of modules that will be defined empty ' - u'on RequireJS build steps to prevent loading modules multiple times.'), - value_type=schema.ASCIILine(title=_(u"Resource name")), + title=_('Stub JavaScript modules'), + description=_('Define list of modules that will be defined empty ' + 'on RequireJS build steps to prevent loading modules multiple times.'), + value_type=schema.ASCIILine(title=_("Resource name")), required=False, missing_value=[], default=[]) merge_with = schema.Choice( - title=_(u"Merge with"), + title=_("Merge with"), description=_( - u"In production mode, bundles are merged together to reduce the " + "In production mode, bundles are merged together to reduce the " "quantity of JS and CSS resources loaded by the browser. Choose " "'default' if this bundle must be available for all the visitors, " "choose 'logged-in' if it must be available for logged-in users " "only, or leave it empty if it must not be merged."), vocabulary=SimpleVocabulary( - [SimpleTerm('', '', _(u"")), + [SimpleTerm('', '', _("")), SimpleTerm('default', 'default', 'default'), SimpleTerm('logged-in', 'logged-in', 'logged-in')]), - default=u"", + default="", required=False) load_async = schema.Bool( - title=_(u"Load asynchronously"), + title=_("Load asynchronously"), description=_("Load the JavaScript files asynchronously by adding an ``async`` attribute to the script tag."), default=False, required=False) load_defer = schema.Bool( - title=_(u"Load deferred"), + title=_("Load deferred"), description=_("Load the JavaScript files deferred after the document has been parsed but before ``DOMContentLoaded`` by adding a ``defer`` attribute to the script tag."), default=False, required=False) diff --git a/Products/CMFPlone/interfaces/siteroot.py b/Products/CMFPlone/interfaces/siteroot.py index 1118b406f8..83c119871d 100644 --- a/Products/CMFPlone/interfaces/siteroot.py +++ b/Products/CMFPlone/interfaces/siteroot.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.interface import Interface from Products.CMFCore.interfaces import ISiteRoot from plone.app.layout.navigation.interfaces import INavigationRoot diff --git a/Products/CMFPlone/interfaces/structure.py b/Products/CMFPlone/interfaces/structure.py index 95e36f237c..ea43a111c2 100644 --- a/Products/CMFPlone/interfaces/structure.py +++ b/Products/CMFPlone/interfaces/structure.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.interface import Interface diff --git a/Products/CMFPlone/interfaces/syndication.py b/Products/CMFPlone/interfaces/syndication.py index 8892f544d0..b65465a0be 100644 --- a/Products/CMFPlone/interfaces/syndication.py +++ b/Products/CMFPlone/interfaces/syndication.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.interface import Interface from zope import schema from Products.CMFPlone import PloneMessageFactory as _ @@ -151,45 +150,45 @@ def file_type(): class ISiteSyndicationSettings(Interface): allowed = schema.Bool( - title=_(u'Allowed'), - description=_(u'Allow syndication for collections and folders ' - u'on site.'), + title=_('Allowed'), + description=_('Allow syndication for collections and folders ' + 'on site.'), default=True) default_enabled = schema.Bool( - title=_(u'Enabled by default'), - description=_(u'If syndication should be enabled by default for all ' - u'folders and collections.'), + title=_('Enabled by default'), + description=_('If syndication should be enabled by default for all ' + 'folders and collections.'), default=False) search_rss_enabled = schema.Bool( - title=_(u'Search RSS enabled'), - description=_(u'Allows users to subscribe to feeds of search results'), + title=_('Search RSS enabled'), + description=_('Allows users to subscribe to feeds of search results'), default=True) show_author_info = schema.Bool( - title=_(u'Show author info'), - description=_(u'Should feeds include author information'), + title=_('Show author info'), + description=_('Should feeds include author information'), default=True) render_body = schema.Bool( - title=_(u'Render Body'), - description=_(u'help_render_body', - default=u'If body text available for item, ' - u'render it, otherwise use description.'), + title=_('Render Body'), + description=_('help_render_body', + default='If body text available for item, ' + 'render it, otherwise use description.'), default=False) max_items = schema.Int( - title=_(u'label_syndication_max_items', - default=u'Maximum items'), - description=_(u'help_syndication_max_items', - default=u'Maximum number of items that will be syndicated.'), + title=_('label_syndication_max_items', + default='Maximum items'), + description=_('help_syndication_max_items', + default='Maximum number of items that will be syndicated.'), min=1, default=15) allowed_feed_types = schema.Tuple( - title=_(u'Allowed Feed Types'), - description=_(u"Separate view name and title by '|'"), + title=_('Allowed Feed Types'), + description=_("Separate view name and title by '|'"), required=True, missing_value=None, default=( @@ -201,9 +200,9 @@ class ISiteSyndicationSettings(Interface): ) site_rss_items = schema.Tuple( - title=_(u'Site RSS'), - description=_(u'Paths to folders and collections to link to ' - u'at the portal root.'), + title=_('Site RSS'), + description=_('Paths to folders and collections to link to ' + 'at the portal root.'), required=False, default=('/news/aggregator',), value_type=schema.Choice( @@ -211,24 +210,24 @@ class ISiteSyndicationSettings(Interface): ) show_syndication_button = schema.Bool( - title=_(u"Show settings button"), - description=_(u"Makes it possible to customize syndication settings " - u"for particular folders and collections ")) + title=_("Show settings button"), + description=_("Makes it possible to customize syndication settings " + "for particular folders and collections ")) show_syndication_link = schema.Bool( - title=_(u"Show feed link"), - description=_(u"Enable RSS link document action on the syndication " - u"content item.")) + title=_("Show feed link"), + description=_("Enable RSS link document action on the syndication " + "content item.")) class IFeedSettings(Interface): enabled = schema.Bool( - title=_(u'Enabled'), + title=_('Enabled'), default=False) feed_types = schema.Tuple( - title=_(u'Feed Types'), + title=_('Feed Types'), required=True, missing_value=None, default=("RSS", "rss.xml", "atom.xml"), @@ -237,19 +236,19 @@ class IFeedSettings(Interface): )) render_body = schema.Bool( - title=_(u'Render Body'), + title=_('Render Body'), description=_( - u'help_render_body', - default=u'If body text available for item, ' - u'render it, otherwise use description.'), + 'help_render_body', + default='If body text available for item, ' + 'render it, otherwise use description.'), default=False) max_items = schema.Int( - title=_(u'label_syndication_max_items', - default=u'Maximum items'), + title=_('label_syndication_max_items', + default='Maximum items'), description=_( - u'help_syndication_max_items', - default=u'Maximum number of items that will be syndicated.'), + 'help_syndication_max_items', + default='Maximum number of items that will be syndicated.'), default=15) diff --git a/Products/CMFPlone/interfaces/translationservice.py b/Products/CMFPlone/interfaces/translationservice.py index 83c2086910..b908e28ee8 100644 --- a/Products/CMFPlone/interfaces/translationservice.py +++ b/Products/CMFPlone/interfaces/translationservice.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.interface import Interface diff --git a/Products/CMFPlone/interfaces/workflow.py b/Products/CMFPlone/interfaces/workflow.py index fe37444984..e056c93889 100644 --- a/Products/CMFPlone/interfaces/workflow.py +++ b/Products/CMFPlone/interfaces/workflow.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.interface.common.sequence import IReadSequence diff --git a/Products/CMFPlone/log.py b/Products/CMFPlone/log.py index 5d90506106..ba2e6359dd 100644 --- a/Products/CMFPlone/log.py +++ b/Products/CMFPlone/log.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ This module resolves an import order dependency. Don't import from here, import from utils. diff --git a/Products/CMFPlone/patches/__init__.py b/Products/CMFPlone/patches/__init__.py index 8800e0bb37..2a66068710 100644 --- a/Products/CMFPlone/patches/__init__.py +++ b/Products/CMFPlone/patches/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # FIXME: This no longer works with the new ZMI # from . import addzmiplonesite # Add an explicit link to add a new Plone # site to the ZMI for faster access diff --git a/Products/CMFPlone/patches/addzmiplonesite.py b/Products/CMFPlone/patches/addzmiplonesite.py index 264167ac5a..9bf09e93ce 100644 --- a/Products/CMFPlone/patches/addzmiplonesite.py +++ b/Products/CMFPlone/patches/addzmiplonesite.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from OFS.ObjectManager import ObjectManager # FIXME: This no longer works with the new ZMI diff --git a/Products/CMFPlone/patches/addzmisecuritywarning.py b/Products/CMFPlone/patches/addzmisecuritywarning.py index 13f9f8d610..373de8a3c7 100644 --- a/Products/CMFPlone/patches/addzmisecuritywarning.py +++ b/Products/CMFPlone/patches/addzmisecuritywarning.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from OFS.role import RoleManager ADD_SECURITY_WARNING = ''' diff --git a/Products/CMFPlone/patches/csrf.py b/Products/CMFPlone/patches/csrf.py index eda29c3c5e..4c484fffcf 100644 --- a/Products/CMFPlone/patches/csrf.py +++ b/Products/CMFPlone/patches/csrf.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.protect import protect, CheckAuthenticator # apply csrf-protection decorator to the given callable diff --git a/Products/CMFPlone/patches/dateIndexPatch.py b/Products/CMFPlone/patches/dateIndexPatch.py index aa54163f79..fe8c9d6188 100644 --- a/Products/CMFPlone/patches/dateIndexPatch.py +++ b/Products/CMFPlone/patches/dateIndexPatch.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Avoid OverflowErrors in Date*Indexes from Products.PluginIndexes.DateIndex.DateIndex import DateIndex diff --git a/Products/CMFPlone/patches/gtbn.py b/Products/CMFPlone/patches/gtbn.py index cc1a30fbf0..bb2f05ff28 100644 --- a/Products/CMFPlone/patches/gtbn.py +++ b/Products/CMFPlone/patches/gtbn.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_parent, aq_base, aq_inner from Acquisition import IAcquirer from Products.CMFCore import utils diff --git a/Products/CMFPlone/patches/iso8601.py b/Products/CMFPlone/patches/iso8601.py index 5aa5a398f3..785b255d10 100644 --- a/Products/CMFPlone/patches/iso8601.py +++ b/Products/CMFPlone/patches/iso8601.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # from warnings import warn from DateTime import DateTime diff --git a/Products/CMFPlone/patches/publishing.py b/Products/CMFPlone/patches/publishing.py index 1bf50f6e62..f531190912 100644 --- a/Products/CMFPlone/patches/publishing.py +++ b/Products/CMFPlone/patches/publishing.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # From Products.PloneHotfix20160419 # Plus extras for properties. from OFS.PropertyManager import PropertyManager @@ -11,10 +10,10 @@ from plone.dexterity.content import Item from plone.dexterity.content import Container except ImportError: - class Item(object): + class Item: pass - class Container(object): + class Container: pass try: @@ -22,10 +21,10 @@ class Container(object): from Products.ATContentTypes.content.base import ATCTBTreeFolder except ImportError: - class ATCTContent(object): + class ATCTContent: pass - class ATCTBTreeFolder(object): + class ATCTBTreeFolder: pass diff --git a/Products/CMFPlone/patches/sendmail.py b/Products/CMFPlone/patches/sendmail.py index b57e698b7c..bfee534d59 100644 --- a/Products/CMFPlone/patches/sendmail.py +++ b/Products/CMFPlone/patches/sendmail.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.registry.interfaces import IRegistry from Products.CMFPlone.interfaces import IMailSchema from transaction._transaction import Status diff --git a/Products/CMFPlone/patches/speed.py b/Products/CMFPlone/patches/speed.py index 81c5c0aac5..ad73b017d1 100644 --- a/Products/CMFPlone/patches/speed.py +++ b/Products/CMFPlone/patches/speed.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.memoize import forever from os import environ diff --git a/Products/CMFPlone/patches/templatecookcheck.py b/Products/CMFPlone/patches/templatecookcheck.py index 190e0e8372..4fdb35222f 100644 --- a/Products/CMFPlone/patches/templatecookcheck.py +++ b/Products/CMFPlone/patches/templatecookcheck.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # The implementation in zope.pagetemplate always checks for # updated files unless python is run with -O, but we want to # base this on the Zope2 debug mode flag. diff --git a/Products/CMFPlone/patches/unicodeFallbackPatch.py b/Products/CMFPlone/patches/unicodeFallbackPatch.py index dd99161146..577108cb3f 100644 --- a/Products/CMFPlone/patches/unicodeFallbackPatch.py +++ b/Products/CMFPlone/patches/unicodeFallbackPatch.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # The following hacks make sure that Unicode and utf-8 encoded strings can be # mixed in all page templates and tal snippets. diff --git a/Products/CMFPlone/patches/unicodehacks.py b/Products/CMFPlone/patches/unicodehacks.py index 74ccace114..ab13277482 100644 --- a/Products/CMFPlone/patches/unicodehacks.py +++ b/Products/CMFPlone/patches/unicodehacks.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - def _unicode_replace(structure): if isinstance(structure, bytes): return structure.decode('utf-8', 'replace') @@ -8,10 +6,10 @@ def _unicode_replace(structure): def _nulljoin(valuelist): try: - return u''.join(valuelist) + return ''.join(valuelist) except UnicodeDecodeError: pass - return u''.join([_unicode_replace(value) for value in valuelist]) + return ''.join([_unicode_replace(value) for value in valuelist]) def new__call__(self, econtext): @@ -35,6 +33,6 @@ def __init__(self, value=None): def getvalue(self): try: - return u''.join(self) + return ''.join(self) except UnicodeDecodeError: - return u''.join([_unicode_replace(value) for value in self]) + return ''.join([_unicode_replace(value) for value in self]) diff --git a/Products/CMFPlone/patches/z3c_form.py b/Products/CMFPlone/patches/z3c_form.py index 5440afa5b0..c65b18dc66 100644 --- a/Products/CMFPlone/patches/z3c_form.py +++ b/Products/CMFPlone/patches/z3c_form.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # This is from Products.PloneHotfix20160830. from urllib.parse import urlparse from z3c.form import widget diff --git a/Products/CMFPlone/patterns/__init__.py b/Products/CMFPlone/patterns/__init__.py index aa264f65ac..da2630c137 100644 --- a/Products/CMFPlone/patterns/__init__.py +++ b/Products/CMFPlone/patterns/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.deferredimport import deprecated deprecated( diff --git a/Products/CMFPlone/patterns/settings.py b/Products/CMFPlone/patterns/settings.py index 5f3ae140f7..a4683384cd 100644 --- a/Products/CMFPlone/patterns/settings.py +++ b/Products/CMFPlone/patterns/settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_inner from Acquisition import aq_parent from borg.localrole.interfaces import IFactoryTempFolder @@ -22,7 +21,7 @@ @implementer(IPatternsSettings) -class PatternSettingsAdapter(object): +class PatternSettingsAdapter: """ Provides default plone settings relevant for patterns. """ @@ -143,11 +142,11 @@ def tinymce(self): 'imageScales': self.image_scales, 'linkAttribute': 'UID', # This is for loading the languages on tinymce - 'loadingBaseUrl': '{0}/++plone++static/components/tinymce-builded/' + 'loadingBaseUrl': '{}/++plone++static/components/tinymce-builded/' 'js/tinymce'.format(portal_url), 'relatedItems': related_items_config, 'prependToScalePart': '/@@images/image/', - 'prependToUrl': '{0}/resolveuid/'.format(site_path.rstrip('/')), + 'prependToUrl': '{}/resolveuid/'.format(site_path.rstrip('/')), 'tiny': generator.get_tiny_config(), 'upload': { 'baseUrl': portal_url, diff --git a/Products/CMFPlone/patterns/tinymce.py b/Products/CMFPlone/patterns/tinymce.py index a858e7fe3d..9cb77d0329 100644 --- a/Products/CMFPlone/patterns/tinymce.py +++ b/Products/CMFPlone/patterns/tinymce.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from lxml import html from plone.app.layout.navigation.root import getNavigationRootObject from plone.app.theming.utils import theming_policy @@ -13,7 +12,7 @@ import json -class TinyMCESettingsGenerator(object): +class TinyMCESettingsGenerator: def __init__(self, context, request): self.context = context @@ -39,7 +38,7 @@ def get_theme(self): def get_content_css(self, style_css=''): files = [ - '{0}/++plone++static/plone-compiled.css'.format(self.nav_root_url) + f'{self.nav_root_url}/++plone++static/plone-compiled.css' ] if style_css: files.extend(style_css.split(',')) @@ -116,7 +115,7 @@ def get_tiny_config(self): theme = self.get_theme() if theme and getattr(theme, 'tinymce_styles_css', None): - importcss_file_filter += ',%s/%s' % ( + importcss_file_filter += ',{}/{}'.format( self.nav_root_url, theme.tinymce_styles_css.lstrip('/')) @@ -158,7 +157,7 @@ def get_tiny_config(self): if 'compat3x' not in tiny_config['plugins']: tiny_config['plugins'].append('compat3x') tiny_config['external_plugins']['AtD'] = ( - '{0}/++plone++static/tinymce-AtD-plugin/' + '{}/++plone++static/tinymce-AtD-plugin/' 'editor_plugin.js'.format(self.nav_root_url) ) # None when Anonymous User @@ -175,7 +174,7 @@ def get_tiny_config(self): tiny_config['browser_spellcheck'] = True if toolbar_additions: - tiny_config['toolbar'] += ' | {0}'.format( + tiny_config['toolbar'] += ' | {}'.format( ' '.join(toolbar_additions) ) @@ -217,12 +216,12 @@ def get_tiny_config(self): # valid_elements : 'a[href|target=_blank],strong/b,div[align],br' tiny_valid_elements = [] for tag in valid_tags: - tag_str = "%s[%s]" % (tag, "|".join(valid_attributes)) + tag_str = "{}[{}]".format(tag, "|".join(valid_attributes)) tiny_valid_elements.append(tag_str) # We want to remove the nasty tag including the content in the # backend, so TinyMCE should allow them here. for tag in nasty_tags: - tag_str = "%s[%s]" % (tag, "|".join(valid_attributes)) + tag_str = "{}[{}]".format(tag, "|".join(valid_attributes)) tiny_valid_elements.append(tag_str) tiny_config['valid_elements'] = ",".join(tiny_valid_elements) diff --git a/Products/CMFPlone/patterns/utils.py b/Products/CMFPlone/patterns/utils.py index e86fef7109..675eb7c2d4 100644 --- a/Products/CMFPlone/patterns/utils.py +++ b/Products/CMFPlone/patterns/utils.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone import utils import json diff --git a/Products/CMFPlone/patterns/view.py b/Products/CMFPlone/patterns/view.py index 3603df8426..6a1c63660f 100644 --- a/Products/CMFPlone/patterns/view.py +++ b/Products/CMFPlone/patterns/view.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # This module delivers the global patterns settings from plone.registry.interfaces import IRegistry from Products.CMFPlone.interfaces import IPatternsSettings @@ -16,7 +15,7 @@ class PatternsSettingsView(BrowserView): def __call__(self): portal_state = getMultiAdapter( (self.context, self.request), - name=u'plone_portal_state' + name='plone_portal_state' ) context_state = getMultiAdapter( (self.context, self.request), diff --git a/Products/CMFPlone/permissions.py b/Products/CMFPlone/permissions.py index 04ffbcd60b..07370e2931 100644 --- a/Products/CMFPlone/permissions.py +++ b/Products/CMFPlone/permissions.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ CMFPlone product permissions """ from AccessControl import ModuleSecurityInfo diff --git a/Products/CMFPlone/resources/__init__.py b/Products/CMFPlone/resources/__init__.py index 20d71b68ff..7d97e51ad5 100644 --- a/Products/CMFPlone/resources/__init__.py +++ b/Products/CMFPlone/resources/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import os diff --git a/Products/CMFPlone/resources/browser/__init__.py b/Products/CMFPlone/resources/browser/__init__.py index 40a96afc6f..e69de29bb2 100644 --- a/Products/CMFPlone/resources/browser/__init__.py +++ b/Products/CMFPlone/resources/browser/__init__.py @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- diff --git a/Products/CMFPlone/resources/browser/combine.py b/Products/CMFPlone/resources/browser/combine.py index d08a9234bc..1e842a10b9 100644 --- a/Products/CMFPlone/resources/browser/combine.py +++ b/Products/CMFPlone/resources/browser/combine.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_base from datetime import datetime from io import BytesIO @@ -33,7 +32,7 @@ def get_production_resource_directory(): timestamp = production_folder.readFile('timestamp.txt') if isinstance(timestamp, bytes): timestamp = timestamp.decode() - return '%s/++unique++%s' % ( + return '{}/++unique++{}'.format( PRODUCTION_RESOURCE_DIRECTORY, timestamp) @@ -49,7 +48,7 @@ def get_resource(context, path): try: resource = context.unrestrictedTraverse(path) except (NotFound, AttributeError): - logger.warning(u'Could not find resource {0}. You may have to create it first.'.format(path)) # noqa + logger.warning(f'Could not find resource {path}. You may have to create it first.') # noqa return if isinstance(resource, FilesystemFile): @@ -115,7 +114,7 @@ def write_js(context, folder, meta_bundle): for script in resources: if not isinstance(script, bytes): script = script.encode() - fi.write((script + b'\n')) + fi.write(script + b'\n') folder.writeFile(meta_bundle + '.js', fi) logger.info('Wrote combined JS bundle "%s".' % meta_bundle) @@ -150,7 +149,7 @@ def write_css(context, folder, meta_bundle): for script in resources: if not isinstance(script, bytes): script = script.encode() - fi.write((script + b'\n')) + fi.write(script + b'\n') folder.writeFile(meta_bundle + '.css', fi) logger.info('Wrote combined CSS bundle "%s".' % meta_bundle) diff --git a/Products/CMFPlone/resources/browser/configjs.py b/Products/CMFPlone/resources/browser/configjs.py index a88268a4b2..25c5fb134a 100644 --- a/Products/CMFPlone/resources/browser/configjs.py +++ b/Products/CMFPlone/resources/browser/configjs.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.registry.interfaces import IRegistry from Products.CMFPlone.interfaces import IResourceRegistry from Products.Five.browser import BrowserView @@ -29,9 +28,9 @@ def _format_shims(shims): # function, no escaping here options.append('init: %s' % val['init']) result.append(""" - "%s": { - %s - }""" % (name, ',\n '.join(options))) + "{}": {{ + {} + }}""".format(name, ',\n '.join(options))) return '{' + ','.join(result) + '\n }' diff --git a/Products/CMFPlone/resources/browser/cook.py b/Products/CMFPlone/resources/browser/cook.py index 537fcb05e5..2d6ed3b471 100644 --- a/Products/CMFPlone/resources/browser/cook.py +++ b/Products/CMFPlone/resources/browser/cook.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals from calmjs.parse import es5 from datetime import datetime from io import BytesIO @@ -98,13 +96,13 @@ def cookWhenChangingSettings(context, bundle=None): css = css_compiler.compile_string(css) if not isinstance(css, str): css = css.decode('utf8') - cooked_css += '\n/* Resource: {0} */\n{1}\n'.format( + cooked_css += '\n/* Resource: {} */\n{}\n'.format( css_resource, css ) else: cooked_css +=\ - '\n/* Could not find resource: {0} */\n\n'.format( + '\n/* Could not find resource: {} */\n\n'.format( css_resource ) logger.warning('Could not find resource: %s', css_resource) @@ -118,21 +116,21 @@ def cookWhenChangingSettings(context, bundle=None): if not isinstance(js, str): js = js.decode('utf8') try: - cooked_js += '\n/* resource: {0} */\n{1}'.format( + cooked_js += '\n/* resource: {} */\n{}'.format( resource.js, js if resource.js.endswith('.min.js') else es5.minify_print(js) ) except SyntaxError: cooked_js +=\ - '\n/* Resource (error cooking): {0} */\n{1}'.format( + '\n/* Resource (error cooking): {} */\n{}'.format( resource.js, js ) logger.warning('Error cooking resource: %s', resource.js) else: logger.warning('Could not find resource: %s', resource.js) - cooked_js += '\n/* Could not find resource: {0} */\n\n'.format( + cooked_js += '\n/* Could not find resource: {} */\n\n'.format( js_url ) diff --git a/Products/CMFPlone/resources/browser/interfaces.py b/Products/CMFPlone/resources/browser/interfaces.py index 97717f90a1..b10009c3b8 100644 --- a/Products/CMFPlone/resources/browser/interfaces.py +++ b/Products/CMFPlone/resources/browser/interfaces.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.interface import Interface diff --git a/Products/CMFPlone/resources/browser/mixins.py b/Products/CMFPlone/resources/browser/mixins.py index b616f0a95e..fe235f922a 100644 --- a/Products/CMFPlone/resources/browser/mixins.py +++ b/Products/CMFPlone/resources/browser/mixins.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl.safe_formatter import SafeFormatter from plone.registry.interfaces import IRegistry from urllib.parse import urlparse @@ -51,7 +50,7 @@ def resource_registry(self): def __call__(self): registry = self.registry() portal_state = getMultiAdapter((self.context, self.request), - name=u'plone_portal_state') + name='plone_portal_state') site_url = portal_state.portal_url() result = "" result += "sitePath: '\"%s\"',\n" % site_url @@ -70,7 +69,7 @@ def __call__(self): for name, value in registry.items(): t = SafeFormatter(value).safe_format(**less_vars_params) - result += "'%s': \"%s\",\n" % (name, t) + result += f"'{name}': \"{t}\",\n" # Adding all plone.resource entries css values as less vars for name, value in self.resource_registry().items(): @@ -79,11 +78,11 @@ def __call__(self): url = urlparse(css) if url.netloc == '': # Local - src = "%s/%s" % (site_url, css) + src = f"{site_url}/{css}" else: src = "%s" % (css) # less vars can't have dots on it - result += "'%s': '\"%s\"',\n" % (name.replace('.', '_'), src) + result += "'{}': '\"{}\"',\n".format(name.replace('.', '_'), src) self.request.response.setHeader("Content-Type", "application/javascript") @@ -100,7 +99,7 @@ class LessModifyConfiguration(LessConfiguration): def __call__(self): registry = self.registry() portal_state = getMultiAdapter((self.context, self.request), - name=u'plone_portal_state') + name='plone_portal_state') site_url = portal_state.portal_url() result2 = "" result2 += "'@sitePath': '\"%s\"',\n" % site_url @@ -119,7 +118,7 @@ def __call__(self): for name, value in registry.items(): t = SafeFormatter(value).safe_format(**less_vars_params) - result2 += "'@%s': \"%s\",\n" % (name, t) + result2 += f"'@{name}': \"{t}\",\n" self.request.response.setHeader("Content-Type", "application/javascript") @@ -139,7 +138,7 @@ def registry(self): def __call__(self): portal_state = getMultiAdapter((self.context, self.request), - name=u'plone_portal_state') + name='plone_portal_state') site_url = portal_state.portal_url() registry = self.registry() @@ -151,7 +150,7 @@ def __call__(self): url = urlparse(css) if url.netloc == '': # Local - src = "%s/%s" % (site_url, css) + src = f"{site_url}/{css}" else: src = "%s" % (css) diff --git a/Products/CMFPlone/resources/browser/resource.py b/Products/CMFPlone/resources/browser/resource.py index 7d3bb2a4ed..bb64409814 100644 --- a/Products/CMFPlone/resources/browser/resource.py +++ b/Products/CMFPlone/resources/browser/resource.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_base from Acquisition import aq_inner from Acquisition import aq_parent @@ -23,7 +22,7 @@ from zope.ramcache.interfaces import ram -class ResourceBase(object): +class ResourceBase: """Information for script rendering. This is a mixin base class for a browser view, a viewlet or a tile @@ -102,7 +101,7 @@ def evaluateExpression(self, expression, context): def update(self): self.portal_state = getMultiAdapter( (self.context, self.request), - name=u'plone_portal_state' + name='plone_portal_state' ) self.site_url = self.portal_state.portal_url() self.registry = getUtility(IRegistry) diff --git a/Products/CMFPlone/resources/browser/scripts.py b/Products/CMFPlone/resources/browser/scripts.py index 71c8c8dff3..b7051ff22f 100644 --- a/Products/CMFPlone/resources/browser/scripts.py +++ b/Products/CMFPlone/resources/browser/scripts.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.resources.browser.cook import cookWhenChangingSettings from Products.CMFPlone.resources.browser.resource import ResourceView from Products.CMFPlone.utils import get_top_request @@ -26,7 +25,7 @@ def _add_resources( url = parse.urlparse(data.js) if url.netloc == '': # Local - src = '{0}/{1}'.format(self.site_url, data.js) + src = f'{self.site_url}/{data.js}' else: src = data.js data = { @@ -70,14 +69,14 @@ def get_data(self, bundle, result): resource_path = js_path.split('++plone++')[-1] resource_name, resource_filepath = resource_path.split( '/', 1) - js_location = '{0}/++plone++{1}/++unique++{2}/{3}'.format( + js_location = '{}/++plone++{}/++unique++{}/{}'.format( self.site_url, resource_name, parse.quote(str(bundle.last_compilation)), resource_filepath ) else: - js_location = '{0}/{1}?version={2}'.format( + js_location = '{}/{}?version={}'.format( self.site_url, bundle.jscompilation, parse.quote(str(bundle.last_compilation)) @@ -100,7 +99,7 @@ def default_resources(self): result = [] # We always add jquery resource result.append({ - 'src': '{0}/{1}'.format( + 'src': '{}/{}'.format( self.site_url, self.registry.records['plone.resources/jquery.js'].value), 'conditionalcomment': None, @@ -109,28 +108,28 @@ def default_resources(self): if self.development: # We need to add require.js and config.js result.append({ - 'src': '{0}/{1}'.format( + 'src': '{}/{}'.format( self.site_url, self.registry.records['plone.resources.less-variables'].value), # noqa 'conditionalcomment': None, 'bundle': 'basic' }) result.append({ - 'src': '{0}/{1}'.format( + 'src': '{}/{}'.format( self.site_url, self.registry.records['plone.resources.lessc'].value), 'conditionalcomment': None, 'bundle': 'basic' }) result.append({ - 'src': '{0}/{1}'.format( + 'src': '{}/{}'.format( self.site_url, self.registry.records['plone.resources.requirejs'].value), 'conditionalcomment': None, 'bundle': 'basic' }) result.append({ - 'src': '{0}/{1}'.format( + 'src': '{}/{}'.format( self.site_url, self.registry.records['plone.resources.configjs'].value), 'conditionalcomment': None, @@ -141,7 +140,7 @@ def default_resources(self): def base_url(self): portal_state = getMultiAdapter( (self.context, self.request), - name=u'plone_portal_state' + name='plone_portal_state' ) site_url = portal_state.portal_url() return site_url @@ -155,7 +154,7 @@ def scripts(self): result.extend(self.ordered_bundles_result()) else: result = [{ - 'src': '{0}/++plone++{1}'.format( + 'src': '{}/++plone++{}'.format( self.site_url, self.production_path + '/default.js' ), @@ -166,7 +165,7 @@ def scripts(self): }] if not self.anonymous: result.append({ - 'src': '{0}/++plone++{1}'.format( + 'src': '{}/++plone++{}'.format( self.site_url, self.production_path + '/logged-in.js' ), @@ -193,7 +192,7 @@ def scripts(self): result.append({ 'bundle': 'diazo', 'conditionalcomment': '', - 'src': '{0}/{1}'.format(self.site_url, origin), + 'src': f'{self.site_url}/{origin}', }) return result diff --git a/Products/CMFPlone/resources/browser/styles.py b/Products/CMFPlone/resources/browser/styles.py index ef163bf057..6b7458d838 100644 --- a/Products/CMFPlone/resources/browser/styles.py +++ b/Products/CMFPlone/resources/browser/styles.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.layout.viewlets.common import ViewletBase from plone.app.theming.interfaces import IThemeSettings from plone.registry.interfaces import IRegistry @@ -21,7 +20,7 @@ def get_urls(self, style, bundle): url = parse.urlparse(css) if url.netloc == '': # Local - src = "%s/%s" % (self.site_url, css) + src = f"{self.site_url}/{css}" else: src = "%s" % (css) @@ -65,14 +64,14 @@ def get_data(self, bundle, result): resource_path = css_path.split('++plone++')[-1] resource_name, resource_filepath = resource_path.split( '/', 1) - css_location = '%s/++plone++%s/++unique++%s/%s' % ( + css_location = '{}/++plone++{}/++unique++{}/{}'.format( self.site_url, resource_name, parse.quote(str(bundle.last_compilation)), resource_filepath ) else: - css_location = '%s/%s?version=%s' % ( + css_location = '{}/{}?version={}'.format( self.site_url, bundle.csscompilation, parse.quote(str(bundle.last_compilation)) @@ -105,7 +104,7 @@ def styles(self): result = self.ordered_bundles_result() else: result = [{ - 'src': '%s/++plone++%s' % ( + 'src': '{}/++plone++{}'.format( self.site_url, self.production_path + '/default.css' ), @@ -115,7 +114,7 @@ def styles(self): }, ] if not self.anonymous: result.append({ - 'src': '%s/++plone++%s' % ( + 'src': '{}/++plone++{}'.format( self.site_url, self.production_path + '/logged-in.css' ), @@ -144,7 +143,7 @@ def styles(self): url = parse.urlparse(origin) if url.netloc == '': # Local - src = "%s/%s" % (self.site_url, origin) + src = f"{self.site_url}/{origin}" else: src = "%s" % (origin) @@ -165,7 +164,7 @@ def styles(self): custom_css = { 'rel': 'stylesheet', 'conditionalcomment': '', - 'src': "{0}/custom.css?timestamp={1}".format( + 'src': "{}/custom.css?timestamp={}".format( self.site_url, self.custom_css_timestamp, ), diff --git a/Products/CMFPlone/resources/bundle.py b/Products/CMFPlone/resources/bundle.py index 9515b20f1c..16a2007bc1 100644 --- a/Products/CMFPlone/resources/bundle.py +++ b/Products/CMFPlone/resources/bundle.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from datetime import datetime from plone.resource.directory import FilesystemResourceDirectory from plone.resource.file import FilesystemFile @@ -11,7 +10,7 @@ import os -class Bundle(object): +class Bundle: """Wraps pure bundles RecordsProxy and enrich with logic . Proxy attributes and provide some utility functions @@ -97,7 +96,7 @@ def __getattr__(self, name): return getattr(self.data, name) def __repr__(self): - return '<{0}.{1} object "{2}" at {3}>'.format( + return '<{}.{} object "{}" at {}>'.format( self.__class__.__module__, self.__class__.__name__, self.name, diff --git a/Products/CMFPlone/resources/exportimport/__init__.py b/Products/CMFPlone/resources/exportimport/__init__.py index 40a96afc6f..e69de29bb2 100644 --- a/Products/CMFPlone/resources/exportimport/__init__.py +++ b/Products/CMFPlone/resources/exportimport/__init__.py @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- diff --git a/Products/CMFPlone/resources/exportimport/bundles.py b/Products/CMFPlone/resources/exportimport/bundles.py index 1f3ca986b0..c4d7379307 100644 --- a/Products/CMFPlone/resources/exportimport/bundles.py +++ b/Products/CMFPlone/resources/exportimport/bundles.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from ..browser.combine import combine_bundles from plone.registry.interfaces import IRegistry from zope.component import queryUtility diff --git a/Products/CMFPlone/resources/exportimport/resourceregistry.py b/Products/CMFPlone/resources/exportimport/resourceregistry.py index b31942247e..9e97729bc7 100644 --- a/Products/CMFPlone/resources/exportimport/resourceregistry.py +++ b/Products/CMFPlone/resources/exportimport/resourceregistry.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from datetime import datetime from plone.i18n.normalizer.interfaces import IIDNormalizer from Products.CMFCore.utils import getToolByName diff --git a/Products/CMFPlone/setuphandlers.py b/Products/CMFPlone/setuphandlers.py index a72158af05..d0ff9c21f6 100644 --- a/Products/CMFPlone/setuphandlers.py +++ b/Products/CMFPlone/setuphandlers.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_base from Products.CMFCore.utils import getToolByName from Products.CMFPlone.factory import _DEFAULT_PROFILE @@ -205,7 +204,7 @@ def first_weekday_setup(context): parts = (language.split('-') + [None, None])[:3] locale = locales.getLocale(*parts) # look up first day of week - gregorian_calendar = locale.dates.calendars.get(u'gregorian', None) + gregorian_calendar = locale.dates.calendars.get('gregorian', None) if gregorian_calendar is not None: day = gregorian_calendar.week.get('firstDay', 7) first = 6 if day == 0 else day - 1 diff --git a/Products/CMFPlone/skins/plone_form_scripts/plone_change_password.py b/Products/CMFPlone/skins/plone_form_scripts/plone_change_password.py index 8bb1672c37..77a5ee90b0 100644 --- a/Products/CMFPlone/skins/plone_form_scripts/plone_change_password.py +++ b/Products/CMFPlone/skins/plone_form_scripts/plone_change_password.py @@ -11,7 +11,7 @@ REQUEST = context.REQUEST if 'cancel' in REQUEST.form: - context.plone_utils.addPortalMessage(_(u'Password change was canceled.'), + context.plone_utils.addPortalMessage(_('Password change was canceled.'), 'warning') return context.REQUEST.RESPONSE.redirect( '%s/@@personal-preferences' % context.absolute_url()) @@ -19,7 +19,7 @@ mt = context.portal_membership if not mt.testCurrentPassword(current): - failMessage = _(u'Does not match current password.') + failMessage = _('Does not match current password.') context.plone_utils.addPortalMessage(failMessage, 'error') return context.password_form(context, REQUEST, @@ -37,9 +37,9 @@ try: mt.setPassword(password, domains, REQUEST=context.REQUEST) except AttributeError: - failMessage = _(u'While changing your password an AttributeError ' - u'occurred. This is usually caused by your user being ' - u'defined outside the portal.') + failMessage = _('While changing your password an AttributeError ' + 'occurred. This is usually caused by your user being ' + 'defined outside the portal.') context.plone_utils.addPortalMessage(failMessage, 'error') return context.password_form(context, REQUEST, @@ -48,7 +48,7 @@ from Products.CMFPlone.utils import transaction_note transaction_note('Changed password for %s' % (member.getUserName())) -context.plone_utils.addPortalMessage(_(u'Password changed.')) +context.plone_utils.addPortalMessage(_('Password changed.')) return context.REQUEST.RESPONSE.redirect( '%s/@@personal-preferences' % context.absolute_url()) diff --git a/Products/CMFPlone/skins/plone_prefs/prefs_error_log_setProperties.py b/Products/CMFPlone/skins/plone_prefs/prefs_error_log_setProperties.py index b321accd8e..254eba829e 100644 --- a/Products/CMFPlone/skins/plone_prefs/prefs_error_log_setProperties.py +++ b/Products/CMFPlone/skins/plone_prefs/prefs_error_log_setProperties.py @@ -14,7 +14,7 @@ ignored_exceptions = map(safe_nativestring, ignored_exceptions) context.error_log.setProperties(keep_entries, copy_to_zlog, ignored_exceptions) -context.plone_utils.addPortalMessage(_(u'Changes made.')) +context.plone_utils.addPortalMessage(_('Changes made.')) return request.RESPONSE.redirect( context.absolute_url() + '/prefs_error_log_form') diff --git a/Products/CMFPlone/skins/plone_prefs/prefs_error_log_update.py b/Products/CMFPlone/skins/plone_prefs/prefs_error_log_update.py index 83be5609b8..b636dda8f1 100644 --- a/Products/CMFPlone/skins/plone_prefs/prefs_error_log_update.py +++ b/Products/CMFPlone/skins/plone_prefs/prefs_error_log_update.py @@ -11,16 +11,16 @@ search = request.form.get('search_entry') if search == '': member.setProperties(error_log_update=0.0) - context.plone_utils.addPortalMessage(_(u'Showing all entries')) + context.plone_utils.addPortalMessage(_('Showing all entries')) return request.RESPONSE.redirect(context.absolute_url() + '/prefs_error_log_form') return request.RESPONSE.redirect(context.absolute_url() + '/prefs_error_log_showEntry?id=%s' % search) elif getattr(request, 'form.button.showall', None) is not None: member.setProperties(error_log_update=0.0) - context.plone_utils.addPortalMessage(_(u'Showing all entries')) + context.plone_utils.addPortalMessage(_('Showing all entries')) return request.RESPONSE.redirect(context.absolute_url() + '/prefs_error_log_form') elif getattr(request, 'form.button.clear', None) is not None: member.setProperties(error_log_update=DateTime().timeTime()) - context.plone_utils.addPortalMessage(_(u'Entries cleared')) + context.plone_utils.addPortalMessage(_('Entries cleared')) return request.RESPONSE.redirect(context.absolute_url() + '/prefs_error_log_form') else: return request.RESPONSE.redirect(context.absolute_url() + '/prefs_error_log_form') diff --git a/Products/CMFPlone/skins/plone_scripts/external_edit.py b/Products/CMFPlone/skins/plone_scripts/external_edit.py index 8423c8c37e..c962afdd14 100644 --- a/Products/CMFPlone/skins/plone_scripts/external_edit.py +++ b/Products/CMFPlone/skins/plone_scripts/external_edit.py @@ -13,9 +13,9 @@ if 'Mac OS X' in request.get('HTTP_USER_AGENT', ''): return context.REQUEST['RESPONSE'].redirect( - '%s/externalEdit_/%s.zem?macosx=1' % (context.aq_parent.absolute_url(), + '{}/externalEdit_/{}.zem?macosx=1'.format(context.aq_parent.absolute_url(), url_quote(context.getId()))) else: return context.REQUEST['RESPONSE'].redirect( - '%s/externalEdit_/%s' % (context.aq_parent.absolute_url(), + '{}/externalEdit_/{}'.format(context.aq_parent.absolute_url(), url_quote(context.getId()))) diff --git a/Products/CMFPlone/skins/plone_scripts/queryCatalog.py b/Products/CMFPlone/skins/plone_scripts/queryCatalog.py index d3f3166ae8..12d3b5678e 100644 --- a/Products/CMFPlone/skins/plone_scripts/queryCatalog.py +++ b/Products/CMFPlone/skins/plone_scripts/queryCatalog.py @@ -22,7 +22,7 @@ if REQUEST is None: REQUEST = context.REQUEST -multispace = u'\u3000' +multispace = '\u3000' def quotestring(s): return '"%s"' % s diff --git a/Products/CMFPlone/testing.py b/Products/CMFPlone/testing.py index b7f96ed80e..3bf8591240 100644 --- a/Products/CMFPlone/testing.py +++ b/Products/CMFPlone/testing.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_base from plone.app.contenttypes.testing import PLONE_APP_CONTENTTYPES_FIXTURE from plone.app.robotframework import AutoLogin @@ -46,7 +45,7 @@ def setUpPloneSite(self, portal): portal.invokeFactory( "Folder", id="test-folder", - title=u"Test Folder" + title="Test Folder" ) # XXX: this is needed for tests that rely on the Members folder to be # present. This folder is otherwise created by a setup handler in @@ -55,7 +54,7 @@ def setUpPloneSite(self, portal): portal.invokeFactory( "Folder", id="Members", - title=u"Members" + title="Members" ) portal._original_MailHost = portal.MailHost diff --git a/Products/CMFPlone/tests/PloneTestCase.py b/Products/CMFPlone/tests/PloneTestCase.py index 0c83868c31..3e78448490 100644 --- a/Products/CMFPlone/tests/PloneTestCase.py +++ b/Products/CMFPlone/tests/PloneTestCase.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.testing.zope import Browser from plone.app.testing.bbb import PloneTestCase from plone.app.testing import PLONE_SITE_ID as portal_name @@ -38,7 +37,7 @@ def getBrowser(self, loggedIn=True): if loggedIn: user = TEST_USER_NAME pwd = default_password - browser.addHeader('Authorization', 'Basic %s:%s' % (user, pwd)) + browser.addHeader('Authorization', f'Basic {user}:{pwd}') return browser diff --git a/Products/CMFPlone/tests/dummy.py b/Products/CMFPlone/tests/dummy.py index 88fd8cfc6c..c89a7b3852 100644 --- a/Products/CMFPlone/tests/dummy.py +++ b/Products/CMFPlone/tests/dummy.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # # Helper objects for the Plone test suite # @@ -17,7 +16,7 @@ TEXT = b'file data' -UTEXT = u'file data' +UTEXT = 'file data' GIF_FILE = os.path.join( os.path.dirname(__file__), os.pardir, 'tool.gif') with open(GIF_FILE, 'rb') as f: @@ -59,7 +58,7 @@ def get_size(self): return self.size -class FieldStorage(object): +class FieldStorage: def __init__(self, file, filename='testfile', headers=None): self.file = file @@ -191,7 +190,7 @@ def getPortalTypeName(self): return getattr(self, 'portal_type') -class DummyWorkflowTool(object): +class DummyWorkflowTool: """A dummy workflow tool for testing adaptation based workflow""" def __init__(self, id='portal_workflow'): diff --git a/Products/CMFPlone/tests/robot/robot_setup.py b/Products/CMFPlone/tests/robot/robot_setup.py index f0a59ef83c..b32e25ec06 100644 --- a/Products/CMFPlone/tests/robot/robot_setup.py +++ b/Products/CMFPlone/tests/robot/robot_setup.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.robotframework.remote import RemoteLibrary from plone.app.robotframework.utils import disableCSRFProtection @@ -20,7 +19,7 @@ def the_mail_setup_configured(self): mail_settings = registry.forInterface(IMailSchema, prefix='plone') if mail_settings is None: return - mail_settings.smtp_host = u'localhost' + mail_settings.smtp_host = 'localhost' mail_settings.email_from_address = 'john@doe.com' def the_self_registration_enabled(self): diff --git a/Products/CMFPlone/tests/robot/variables.py b/Products/CMFPlone/tests/robot/variables.py index 040b845ae3..a32e833f5f 100644 --- a/Products/CMFPlone/tests/robot/variables.py +++ b/Products/CMFPlone/tests/robot/variables.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import os PATH_TO_TEST_FILES = os.path.join(os.path.dirname(__file__)) # noqa diff --git a/Products/CMFPlone/tests/testActionsTool.py b/Products/CMFPlone/tests/testActionsTool.py index 6a44881d97..1b304e438b 100644 --- a/Products/CMFPlone/tests/testActionsTool.py +++ b/Products/CMFPlone/tests/testActionsTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import Explicit from OFS.SimpleItem import Item from plone.app.testing import login @@ -33,7 +32,7 @@ def fail_tb(self, msg): import sys e, v, tb = sys.exc_info() tb = ''.join(format_exception(e, v, tb)) - self.fail("%s\n%s\n" % (msg, tb)) + self.fail(f"{msg}\n{tb}\n") def testAddAction(self): # addAction should work even though PloneTestCase patches _cloneActions diff --git a/Products/CMFPlone/tests/testBatch.py b/Products/CMFPlone/tests/testBatch.py index 6c755dd7b8..5964e2ecfd 100644 --- a/Products/CMFPlone/tests/testBatch.py +++ b/Products/CMFPlone/tests/testBatch.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.PloneBatch import Batch from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING from ZTUtils.Lazy import LazyMap @@ -61,5 +60,5 @@ def test_batch_brains(self): self.assertEqual( batch[0].id, obj_ids[start], - 'Failing test for start value: {}'.format(start) + f'Failing test for start value: {start}' ) diff --git a/Products/CMFPlone/tests/testBrowserAdmin.py b/Products/CMFPlone/tests/testBrowserAdmin.py index 5c806f7dec..bee18f86cb 100644 --- a/Products/CMFPlone/tests/testBrowserAdmin.py +++ b/Products/CMFPlone/tests/testBrowserAdmin.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.testing import SITE_OWNER_NAME from plone.app.testing import SITE_OWNER_PASSWORD from plone.testing.zope import Browser @@ -19,7 +18,7 @@ def setUp(self): self.browser.handleErrors = False self.browser.addHeader( 'Authorization', - 'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD) + f'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}' ) def test_normal_redirect(self): diff --git a/Products/CMFPlone/tests/testBrowserDefault.py b/Products/CMFPlone/tests/testBrowserDefault.py index 335eb88731..3d8bc83e4d 100644 --- a/Products/CMFPlone/tests/testBrowserDefault.py +++ b/Products/CMFPlone/tests/testBrowserDefault.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_base from plone.app.testing import TEST_USER_ID from plone.app.testing import TEST_USER_NAME @@ -47,13 +46,13 @@ def setUp(self): _createObjectByType('Folder', self.portal, 'folder') _createObjectByType('Document', self.portal, 'document') _createObjectByType('File', self.portal, 'file') - self.portal.file.file = NamedBlobFile('foo', 'text/plain', u'foo.txt') + self.portal.file.file = NamedBlobFile('foo', 'text/plain', 'foo.txt') transaction.commit() self.putils = getToolByName(self.portal, "plone_utils") self.browser = Browser(self.layer['app']) self.browser.addHeader( - 'Authorization', 'Basic %s:%s' % ( + 'Authorization', 'Basic {}:{}'.format( TEST_USER_NAME, TEST_USER_PASSWORD, ) @@ -143,7 +142,7 @@ def testBrowserDefaultMixinFolderIndexHtml(self): def testBrowserDefaultMixinFolderGlobalDefaultPage(self): registry = getUtility(IRegistry) - registry['plone.default_page'] = [u'foo'] + registry['plone.default_page'] = ['foo'] self.portal.folder.invokeFactory('Document', 'foo') self.assertEqual(self.putils.browserDefault(self.portal.folder), (self.portal.folder, ['foo'])) @@ -242,7 +241,7 @@ def testDefaultPageSetting(self): default = registry.get('plone.default_page', []) self.assertEqual( default, - [u'index_html', u'index.html', u'index.htm', u'FrontPage'] + ['index_html', 'index.html', 'index.htm', 'FrontPage'] ) diff --git a/Products/CMFPlone/tests/testBrowserLayerPrecedence.py b/Products/CMFPlone/tests/testBrowserLayerPrecedence.py index 25b3c6b08c..f8d90b229f 100644 --- a/Products/CMFPlone/tests/testBrowserLayerPrecedence.py +++ b/Products/CMFPlone/tests/testBrowserLayerPrecedence.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # This test confirms that views assigned to theme-specific layers (a la # plone.theme) take precedence over views assigned to layers from other # add-on products (a la plone.browserlayer). diff --git a/Products/CMFPlone/tests/testCSRFProtection.py b/Products/CMFPlone/tests/testCSRFProtection.py index 8c7a5cd412..fd0d7afb6b 100644 --- a/Products/CMFPlone/tests/testCSRFProtection.py +++ b/Products/CMFPlone/tests/testCSRFProtection.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.testing import TEST_USER_ID from plone.app.testing import TEST_USER_NAME from plone.app.testing import TEST_USER_PASSWORD @@ -18,7 +17,7 @@ def test_KeyManager(self): self.assertTrue(queryUtility(IKeyManager), 'key manager not found') def checkAuthenticator(self, path, query='', status=200): - credentials = '%s:%s' % (TEST_USER_NAME, TEST_USER_PASSWORD) + credentials = f'{TEST_USER_NAME}:{TEST_USER_PASSWORD}' path = '/' + self.portal.absolute_url(relative=True) + path data = BytesIO(query.encode('utf8')) # without authenticator... diff --git a/Products/CMFPlone/tests/testCSSandJSRegistry.py b/Products/CMFPlone/tests/testCSSandJSRegistry.py index d8c249fbc0..cf8ee57a78 100644 --- a/Products/CMFPlone/tests/testCSSandJSRegistry.py +++ b/Products/CMFPlone/tests/testCSSandJSRegistry.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.registry.interfaces import IRegistry from Products.CMFPlone.interfaces import IBundleRegistry from Products.CMFPlone.interfaces import IResourceRegistry diff --git a/Products/CMFPlone/tests/testCatalogTool.py b/Products/CMFPlone/tests/testCatalogTool.py index f3fa4adc1b..87cb05456b 100644 --- a/Products/CMFPlone/tests/testCatalogTool.py +++ b/Products/CMFPlone/tests/testCatalogTool.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# -*- encoding: utf-8 -*- from Acquisition import aq_base from DateTime import DateTime from functools import partial @@ -396,7 +394,7 @@ def testListAllowedRolesAndUsers(self): # Should include the group in list of allowed users groupname = self.addUser2ToGroup() uf = self.portal.acl_users - user = 'user:{0:s}'.format(groupname) + user = f'user:{groupname:s}' self.assertTrue( user in self.catalog._listAllowedRolesAndUsers(uf.getUser(user2))) @@ -1367,7 +1365,7 @@ def _index(self, object): return object_provides(object)() def testNoInterfaces(self): - class Dummy(object): + class Dummy: pass self.assertEqual(self._index(Dummy()), ()) @@ -1376,7 +1374,7 @@ class IDummy(zope.interface.Interface): pass @zope.interface.implementer(IDummy) - class Dummy(object): + class Dummy: pass self.assertEqual( self._index(Dummy()), diff --git a/Products/CMFPlone/tests/testCheckId.py b/Products/CMFPlone/tests/testCheckId.py index 87c0fc9d9c..9ca7796556 100644 --- a/Products/CMFPlone/tests/testCheckId.py +++ b/Products/CMFPlone/tests/testCheckId.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl import Unauthorized from plone.app.testing.bbb import PloneTestCase from Products.CMFCore.utils import getToolByName @@ -58,7 +57,7 @@ def testEmptyId(self): def testRequiredId(self): r = check_id(self.folder, '', required=1) - self.assertEqual(r, u'Please enter a name.') + self.assertEqual(r, 'Please enter a name.') def testAlternativeId(self): r = check_id(self.folder, '', alternative_id='foo') @@ -83,7 +82,7 @@ def testCatalogIndex(self): 'Expected permission "Search ZCatalog"') r = check_id(self.folder, 'created') - self.assertEqual(r, u'created is reserved.') + self.assertEqual(r, 'created is reserved.') def testCatalogMetadata(self): portal_catalog = getToolByName(self.portal, 'portal_catalog') @@ -91,25 +90,25 @@ def testCatalogMetadata(self): self.assertTrue('new_metadata' in portal_catalog.schema()) self.assertFalse('new_metadata' in portal_catalog.indexes()) r = check_id(self.folder, 'new_metadata') - self.assertEqual(r, u'new_metadata is reserved.') + self.assertEqual(r, 'new_metadata is reserved.') def testCollision(self): self.folder.invokeFactory('Document', id='foo') self.folder.invokeFactory('Document', id='bar') r = check_id(self.folder.foo, 'bar') - self.assertEqual(r, u'There is already an item named bar in this ' - u'folder.') + self.assertEqual(r, 'There is already an item named bar in this ' + 'folder.') def testReservedId(self): self.folder._setObject('foo', dummy.Item('foo')) r = check_id(self.folder.foo, 'portal_catalog') - self.assertEqual(r, u'portal_catalog is reserved.') + self.assertEqual(r, 'portal_catalog is reserved.') def testHiddenObjectId(self): # If a parallel object is not in content-space, should get 'reserved' # instead of 'taken' r = check_id(self.folder, 'portal_skins') - self.assertEqual(r, u'portal_skins is reserved.') + self.assertEqual(r, 'portal_skins is reserved.') def testCanOverrideParentNames(self): self.folder.invokeFactory('Document', id='item1') @@ -121,21 +120,21 @@ def testCanOverrideParentNames(self): def testInvalidId(self): self.folder._setObject('foo', dummy.Item('foo')) r = check_id(self.folder.foo, '_foo') - self.assertEqual(r, u'_foo is reserved.') + self.assertEqual(r, '_foo is reserved.') def testContainerHook(self): # Container may have a checkValidId method; make sure it is called self.folder._setObject('checkValidId', dummy.Raiser(dummy.Error)) self.folder._setObject('foo', dummy.Item('foo')) r = check_id(self.folder.foo, 'whatever') - self.assertEqual(r, u'whatever is reserved.') + self.assertEqual(r, 'whatever is reserved.') def testContainerHookRaisesUnauthorized(self): # check_id does not raise Unauthorized errors raised by hook self.folder._setObject('checkValidId', dummy.Raiser(Unauthorized)) self.folder._setObject('foo', dummy.Item('foo')) r = check_id(self.folder.foo, 'whatever') - self.assertEqual(r, u'whatever is reserved.') + self.assertEqual(r, 'whatever is reserved.') def testContainerHookRaisesConflictError(self): # check_id should not swallow ConflictErrors raised by hook @@ -171,7 +170,7 @@ def testCatalogIndexSkipped(self): r = check_id(self.folder, 'created') # But now the final hasattr check picks this up - self.assertEqual(r, u'created is reserved.') + self.assertEqual(r, 'created is reserved.') def testCollisionNotSkipped(self): # Note that the existing object check is done, even when we don't have @@ -187,7 +186,7 @@ def testCollisionNotSkipped(self): self.folder._setObject('foo', dummy.Item('foo')) self.folder._setObject('bar', dummy.Item('bar')) r = check_id(self.folder.foo, 'bar') - self.assertEqual(r, u'bar is reserved.') + self.assertEqual(r, 'bar is reserved.') def testReservedIdSkipped(self): # This check is picked up by the checkIdAvailable, unless we don't have @@ -197,7 +196,7 @@ def testReservedIdSkipped(self): self.folder._setObject('foo', dummy.Item('foo')) r = check_id(self.folder.foo, 'portal_catalog') - self.assertEqual(r, u'portal_catalog is reserved.') + self.assertEqual(r, 'portal_catalog is reserved.') def testInvalidIdSkipped(self): # Note that the check is skipped when we don't have @@ -217,7 +216,7 @@ def testParentMethodAliasDisallowed(self): self.folder._setObject('foo', dummy.Item('foo')) for alias in self.folder.getTypeInfo().getMethodAliases().keys(): r = check_id(self.folder.foo, alias) - self.assertEqual(r, u'%s is reserved.' % alias) + self.assertEqual(r, '%s is reserved.' % alias) def testCheckingMethodAliasesOnPortalRoot(self): # Test for bug http://dev.plone.org/plone/ticket/4351 diff --git a/Products/CMFPlone/tests/testContentPublishing.py b/Products/CMFPlone/tests/testContentPublishing.py index 79dbcaf429..ab11407398 100644 --- a/Products/CMFPlone/tests/testContentPublishing.py +++ b/Products/CMFPlone/tests/testContentPublishing.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Tests security of content publishing operations # code inspired by Ween diff --git a/Products/CMFPlone/tests/testContentSecurity.py b/Products/CMFPlone/tests/testContentSecurity.py index 7a64fd2db0..a5c8b86eab 100644 --- a/Products/CMFPlone/tests/testContentSecurity.py +++ b/Products/CMFPlone/tests/testContentSecurity.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl import Unauthorized from Acquisition import aq_base from Products.CMFPlone.tests.PloneTestCase import PloneTestCase diff --git a/Products/CMFPlone/tests/testContentTypeScripts.py b/Products/CMFPlone/tests/testContentTypeScripts.py index 44195920a9..325238d92a 100644 --- a/Products/CMFPlone/tests/testContentTypeScripts.py +++ b/Products/CMFPlone/tests/testContentTypeScripts.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from datetime import datetime from plone.app.textfield import RichTextValue from plone.namedfile.file import NamedFile @@ -22,7 +21,7 @@ def getPermissionsOfRole(self, role): def testDocumentCreate(self): self.folder.invokeFactory( - 'Document', id='doc', text=RichTextValue(u'data')) + 'Document', id='doc', text=RichTextValue('data')) self.assertEqual(self.folder.doc.text.raw, 'data') self.assertEqual(self.folder.doc.Format(), 'text/html') @@ -61,7 +60,7 @@ def testLinkCreate(self): def testNewsItemCreate(self): self.folder.invokeFactory('News Item', id='newsitem', - text=RichTextValue(u'data'), title='Foo') + text=RichTextValue('data'), title='Foo') self.assertEqual(self.folder.newsitem.text.raw, 'data') self.assertEqual(self.folder.newsitem.Title(), 'Foo') diff --git a/Products/CMFPlone/tests/testControlPanel.py b/Products/CMFPlone/tests/testControlPanel.py index bea2c7b313..159e1ee627 100644 --- a/Products/CMFPlone/tests/testControlPanel.py +++ b/Products/CMFPlone/tests/testControlPanel.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING import unittest diff --git a/Products/CMFPlone/tests/testControlPanelScripts.py b/Products/CMFPlone/tests/testControlPanelScripts.py index ca047c6b9b..e0428af4cb 100644 --- a/Products/CMFPlone/tests/testControlPanelScripts.py +++ b/Products/CMFPlone/tests/testControlPanelScripts.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from DateTime import DateTime from plone.app.testing import SITE_OWNER_NAME from plone.app.testing import SITE_OWNER_PASSWORD @@ -38,7 +37,7 @@ class TestAccessControlPanelScripts(PloneTestCase): def afterSetUp(self): self.portal_path = self.portal.absolute_url(1) - self.basic_auth = '%s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD) + self.basic_auth = f'{SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}' def testUserInformation(self): '''Test access to user details.''' diff --git a/Products/CMFPlone/tests/testCookieAuth.py b/Products/CMFPlone/tests/testCookieAuth.py index 9ae8ae1810..4b6e8a8c0b 100644 --- a/Products/CMFPlone/tests/testCookieAuth.py +++ b/Products/CMFPlone/tests/testCookieAuth.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.testing import logout from plone.app.testing import TEST_USER_NAME from plone.app.testing import TEST_USER_PASSWORD @@ -21,7 +20,7 @@ def setUp(self): self.portal = self.layer['portal'] self.folder = self.portal['test-folder'] self.browser = Browser(self.layer['app']) - self.auth_info = '%s:%s' % (TEST_USER_NAME, TEST_USER_PASSWORD) + self.auth_info = f'{TEST_USER_NAME}:{TEST_USER_PASSWORD}' self.cookie = encodebytes(self.auth_info.encode('utf8'))[:-1] self.folder.manage_permission('View', ['Manager'], acquire=0) logout() diff --git a/Products/CMFPlone/tests/testCutPasteSecurity.py b/Products/CMFPlone/tests/testCutPasteSecurity.py index 92c549098e..d2eb66e2a5 100644 --- a/Products/CMFPlone/tests/testCutPasteSecurity.py +++ b/Products/CMFPlone/tests/testCutPasteSecurity.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl import Unauthorized from Acquisition import aq_base from OFS.CopySupport import CopyError diff --git a/Products/CMFPlone/tests/testDateIndexRanges.py b/Products/CMFPlone/tests/testDateIndexRanges.py index 2b4cd98bd2..a1954f49c6 100644 --- a/Products/CMFPlone/tests/testDateIndexRanges.py +++ b/Products/CMFPlone/tests/testDateIndexRanges.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.tests import PloneTestCase from DateTime import DateTime diff --git a/Products/CMFPlone/tests/testDateTimeIntegration.py b/Products/CMFPlone/tests/testDateTimeIntegration.py index 616fccabdd..15d39b5f68 100644 --- a/Products/CMFPlone/tests/testDateTimeIntegration.py +++ b/Products/CMFPlone/tests/testDateTimeIntegration.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # tests for issues related to changes in `DateTime` 2.12 # please see tickets: # diff --git a/Products/CMFPlone/tests/testEmailLogin.py b/Products/CMFPlone/tests/testEmailLogin.py index e914beea25..b603237a4a 100644 --- a/Products/CMFPlone/tests/testEmailLogin.py +++ b/Products/CMFPlone/tests/testEmailLogin.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl import Unauthorized from plone.app.testing import SITE_OWNER_NAME from plone.registry.interfaces import IRegistry diff --git a/Products/CMFPlone/tests/testExternalEditorEnabled.py b/Products/CMFPlone/tests/testExternalEditorEnabled.py index bcbeaeab0c..860c6a2612 100644 --- a/Products/CMFPlone/tests/testExternalEditorEnabled.py +++ b/Products/CMFPlone/tests/testExternalEditorEnabled.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import unittest from Products.CMFPlone.tests import PloneTestCase diff --git a/Products/CMFPlone/tests/testIImagingSchema.py b/Products/CMFPlone/tests/testIImagingSchema.py index 3a9e707da7..3f42d990d8 100644 --- a/Products/CMFPlone/tests/testIImagingSchema.py +++ b/Products/CMFPlone/tests/testIImagingSchema.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.testing import PLONE_INTEGRATION_TESTING from plone.registry.interfaces import IRegistry from Products.CMFPlone.interfaces.controlpanel import IImagingSchema @@ -20,7 +19,7 @@ def test_AllowedSizes(self): # Add a new image scale sizes = imaging_settings.allowed_sizes - imaging_settings.allowed_sizes = sizes + [u"larger 800:800"] + imaging_settings.allowed_sizes = sizes + ["larger 800:800"] # Set back to original imaging_settings.allowed_sizes = sizes diff --git a/Products/CMFPlone/tests/testInterfaces.py b/Products/CMFPlone/tests/testInterfaces.py index 53e6009e37..f6a040d315 100644 --- a/Products/CMFPlone/tests/testInterfaces.py +++ b/Products/CMFPlone/tests/testInterfaces.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from ExtensionClass import ExtensionClass from Products.CMFPlone.ActionsTool import ActionsTool from Products.CMFPlone.CatalogTool import CatalogTool @@ -40,7 +39,7 @@ def className(klass): def dottedName(klass): - return "%s.%s" % (klass.__module__, klass.__name__) + return f"{klass.__module__}.{klass.__name__}" # list of tests tests = [] @@ -76,7 +75,7 @@ def interfaceImplementedByInstanceOf(self, klass, interface): # is the class really implemented by the given interface? self.assertTrue(interface.implementedBy(klass), - 'The class %s does not implement %s' % (dottedName(klass), + 'The class {} does not implement {}'.format(dottedName(klass), dottedName(interface))) # verify if the implementation is correct try: @@ -123,7 +122,7 @@ def doesImplementByInstanceOf(self, klass, interfaces): for interface in interfaces: self.assertTrue( interface in impl, - 'The class %s does not implement %s' % (dottedName(klass), + 'The class {} does not implement {}'.format(dottedName(klass), dottedName(interface))) def doesImplementBy(self, instance, interfaces): @@ -182,7 +181,7 @@ def interfaceImplementedBy(self, klass, interface): # is the class really implemented by the given interface? self.assertTrue(interface.implementedBy(klass), - 'The class %s does not implement %s' % (dottedName(klass), + 'The class {} does not implement {}'.format(dottedName(klass), dottedName(interface))) # verify if the implementation is correct try: @@ -201,7 +200,7 @@ def interfaceProvidedBy(self, instance, interface): # is the class really implemented by the given interface? self.assertTrue(interface.providedBy(instance), - 'The instance of %s does not provide %s' % (dottedName(instance), + 'The instance of {} does not provide {}'.format(dottedName(instance), dottedName(interface))) # verify if the implementation is correct try: @@ -227,7 +226,7 @@ def doesImplementedBy(self, klass, interfaces): for interface in interfaces: self.assertTrue( interface in impl, - 'The class %s does not implement %s' % (dottedName(klass), + 'The class {} does not implement {}'.format(dottedName(klass), dottedName(interface))) def doesProvidedBy(self, instance, interfaces): diff --git a/Products/CMFPlone/tests/testMigrationTool.py b/Products/CMFPlone/tests/testMigrationTool.py index d2a31abe2b..3bef1d2ef4 100644 --- a/Products/CMFPlone/tests/testMigrationTool.py +++ b/Products/CMFPlone/tests/testMigrationTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.tests import PloneTestCase from Products.CMFPlone.factory import _DEFAULT_PROFILE @@ -161,17 +160,17 @@ def test_addon_safe(self): def test_addon_repr(self): from Products.CMFPlone.MigrationTool import Addon addon = Addon(profile_id='foo') - self.assertEqual(repr(addon), u'') + self.assertEqual(repr(addon), '') self.assertEqual(str(addon), '') def test_upgrade_all(self): from Products.CMFPlone.MigrationTool import Addon from Products.CMFPlone.MigrationTool import AddonList # real ones: - cmfeditions = Addon(profile_id=u'Products.CMFEditions:CMFEditions') - discussion = Addon(profile_id=u'plone.app.discussion:default') + cmfeditions = Addon(profile_id='Products.CMFEditions:CMFEditions') + discussion = Addon(profile_id='plone.app.discussion:default') # real one with failing check_module: - dexterity = Addon(profile_id=u'plone.app.dexterity:default', + dexterity = Addon(profile_id='plone.app.dexterity:default', check_module='no.such.module') # non-existing one: foo = Addon(profile_id='foo') diff --git a/Products/CMFPlone/tests/testNavTree.py b/Products/CMFPlone/tests/testNavTree.py index fd7a47a504..4003b842bc 100644 --- a/Products/CMFPlone/tests/testNavTree.py +++ b/Products/CMFPlone/tests/testNavTree.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.tests import PloneTestCase from Products.CMFCore.utils import getToolByName @@ -537,7 +536,7 @@ def testCurrentParent(self): class TestNavigationRoot(PloneTestCase.PloneTestCase): def testGetNavigationRootPropertyNotSet(self): - self.portal.portal_registry['plone.root'] = u'/' + self.portal.portal_registry['plone.root'] = '/' root = getNavigationRoot(self.portal) self.assertEqual(root, '/'.join(self.portal.getPhysicalPath())) diff --git a/Products/CMFPlone/tests/testNavigationView.py b/Products/CMFPlone/tests/testNavigationView.py index 62f3e4436b..cb6acb4844 100644 --- a/Products/CMFPlone/tests/testNavigationView.py +++ b/Products/CMFPlone/tests/testNavigationView.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.registry.interfaces import IRegistry from Products.CMFPlone.browser.navigation import CatalogNavigationBreadcrumbs from Products.CMFPlone.browser.navigation import CatalogNavigationTabs @@ -220,7 +219,7 @@ def testBottomLevelStopsAtFolder(self): self.assertEqual(len(tree['children'][-1]['children']), 0) def testNoRootSet(self): - self.navigation_settings.root = u'' + self.navigation_settings.root = '' view = self.view_class(self.portal.folder2.file21, self.request) tree = view.navigationTree() self.assertTrue(tree) @@ -228,7 +227,7 @@ def testNoRootSet(self): '/plone/folder2') def testRootIsPortal(self): - self.navigation_settings.root = u'/' + self.navigation_settings.root = '/' view = self.view_class(self.portal.folder2.file21, self.request) tree = view.navigationTree() self.assertTrue(tree) @@ -236,7 +235,7 @@ def testRootIsPortal(self): '/plone/folder2') def testRootIsNotPortal(self): - self.navigation_settings.root = u'/folder2' + self.navigation_settings.root = '/folder2' view = self.view_class(self.portal.folder2.file21, self.request) tree = view.navigationTree() self.assertTrue(tree) @@ -244,7 +243,7 @@ def testRootIsNotPortal(self): '/plone/folder2/doc21') def testRootDoesNotExist(self): - self.navigation_settings.root = u'/dodo' + self.navigation_settings.root = '/dodo' view = self.view_class(self.portal.folder2.file21, self.request) tree = view.navigationTree() self.assertTrue(tree) @@ -252,7 +251,7 @@ def testRootDoesNotExist(self): self.assertEqual(len(tree['children']), 0) def testAboveRoot(self): - self.navigation_settings.root = u'/folder2' + self.navigation_settings.root = '/folder2' view = self.view_class(self.portal, self.request) tree = view.navigationTree() self.assertTrue(tree) @@ -262,7 +261,7 @@ def testAboveRoot(self): ) def testOutsideRoot(self): - self.navigation_settings.root = u'/folder2' + self.navigation_settings.root = '/folder2' view = self.view_class(self.portal.folder1, self.request) tree = view.navigationTree() self.assertTrue(tree) @@ -460,7 +459,7 @@ def testSitemapUnchangedWithBottomLevel(self): self.assertTrue(len(sitemap['children'][-1]['children']) > 0) def testSitemapWithNavigationRoot(self): - self.navigation_settings.root = u'/folder2' + self.navigation_settings.root = '/folder2' view = self.view_class(self.portal, self.request) sitemap = view.siteMap() self.assertEqual(sitemap['children'][-1]['item'].getPath(), @@ -634,7 +633,7 @@ def testTabsRespectsTypesWithViewAction(self): check=False ) type_settings.types_use_view_action_in_listings = [ - u'Image', u'File', u'Folder' + 'Image', 'File', 'Folder' ] # Verify that we have '/view' view = self.view_class(self.portal, self.request) @@ -745,7 +744,7 @@ def testBreadcrumbsRespectTypesWithViewAction(self): def testBreadcrumbsStopAtNavigationRoot(self): self.navigation_settings.top_level = 1 - self.navigation_settings.root = u'/folder1' + self.navigation_settings.root = '/folder1' view = self.view_class(self.portal.folder1.doc11, self.request) crumbs = view.breadcrumbs() self.assertTrue(crumbs) diff --git a/Products/CMFPlone/tests/testNextPrevious.py b/Products/CMFPlone/tests/testNextPrevious.py index e74ed9b761..6f98616085 100644 --- a/Products/CMFPlone/tests/testNextPrevious.py +++ b/Products/CMFPlone/tests/testNextPrevious.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.tests import PloneTestCase from plone.app.layout.nextprevious.interfaces import INextPreviousProvider diff --git a/Products/CMFPlone/tests/testOrderSupport.py b/Products/CMFPlone/tests/testOrderSupport.py index 54ff5c4588..7d5bb891a7 100644 --- a/Products/CMFPlone/tests/testOrderSupport.py +++ b/Products/CMFPlone/tests/testOrderSupport.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.tests import PloneTestCase import transaction diff --git a/Products/CMFPlone/tests/testPloneFolder.py b/Products/CMFPlone/tests/testPloneFolder.py index a10c05d248..3ccbc81431 100644 --- a/Products/CMFPlone/tests/testPloneFolder.py +++ b/Products/CMFPlone/tests/testPloneFolder.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.tests import PloneTestCase from Products.CMFPlone.tests import dummy diff --git a/Products/CMFPlone/tests/testPloneTestCase.py b/Products/CMFPlone/tests/testPloneTestCase.py index 280d827c62..fcb722afd5 100644 --- a/Products/CMFPlone/tests/testPloneTestCase.py +++ b/Products/CMFPlone/tests/testPloneTestCase.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_base from Products.CMFPlone.tests import PloneTestCase diff --git a/Products/CMFPlone/tests/testPloneTool.py b/Products/CMFPlone/tests/testPloneTool.py index 683df9e898..7546d7a0d1 100644 --- a/Products/CMFPlone/tests/testPloneTool.py +++ b/Products/CMFPlone/tests/testPloneTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import Implicit from plone.app.testing import SITE_OWNER_NAME from plone.registry.interfaces import IRegistry @@ -136,7 +135,7 @@ def testGetUserFriendlyTypes(self): # 'ChangeSet' is blacklisted, but not in the types by default, # so we filter that out. - blacklistedTypes = set([t for t in blacklistedTypes if t in types]) + blacklistedTypes = {t for t in blacklistedTypes if t in types} # No black listed types should be returned. self.assertEqual([t for t in self.utils.getUserFriendlyTypes() if t in blacklistedTypes], []) @@ -603,10 +602,10 @@ def test_pretty_title_or_id_works_with_method_that_needs_context(self): def test_pretty_title_or_id_on_catalog_brain(self): cat = self.portal.portal_catalog self.setRoles(['Manager', 'Member']) - self.folder.title = u'My pretty title' - self.folder.subject = (u'foobar',) + self.folder.title = 'My pretty title' + self.folder.subject = ('foobar',) self.folder.reindexObject() - results = cat(Subject=u'foobar') + results = cat(Subject='foobar') self.assertEqual(len(results), 1) self.assertEqual(self.utils.pretty_title_or_id(results[0]), 'My pretty title') @@ -614,10 +613,10 @@ def test_pretty_title_or_id_on_catalog_brain(self): def test_pretty_title_or_id_on_catalog_brain_returns_id(self): cat = self.portal.portal_catalog self.setRoles(['Manager', 'Member']) - self.folder.title = u'' - self.folder.subject = (u'foobar',) + self.folder.title = '' + self.folder.subject = ('foobar',) self.folder.reindexObject() - results = cat(Subject=u'foobar') + results = cat(Subject='foobar') self.assertEqual(len(results), 1) self.assertEqual(self.utils.pretty_title_or_id(results[0]), self.folder.getId()) @@ -627,10 +626,10 @@ def test_pretty_title_or_id_on_catalog_brain_autogenerated(self): self.setRoles(['Manager', 'Member']) self.folder.__parent__.manage_renameObject( self.folder.id, 'folder.2004-11-09.0123456789') - self.folder.title = u'' - self.folder.subject = (u'foobar',) + self.folder.title = '' + self.folder.subject = ('foobar',) self.folder.reindexObject() - results = cat(Subject=u'foobar') + results = cat(Subject='foobar') self.assertEqual(len(results), 1) self.assertEqual(self.utils.pretty_title_or_id(results[0], 'Marker'), 'Marker') @@ -641,7 +640,7 @@ def test_pretty_title_or_id_on_catalog_brain_no_title(self): # Remove Title from catalog metadata to simulate a catalog with no # Title metadata and similar pathological cases. cat.delColumn('Title') - self.folder.title = u'' + self.folder.title = '' self.folder.subject = ('foobar',) self.folder.reindexObject() results = cat(Subject='foobar') diff --git a/Products/CMFPlone/tests/testPloneView.py b/Products/CMFPlone/tests/testPloneView.py index 896bcbd64d..4f68681a98 100644 --- a/Products/CMFPlone/tests/testPloneView.py +++ b/Products/CMFPlone/tests/testPloneView.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.browser.ploneview import Plone from Products.CMFPlone.tests import dummy from Products.CMFPlone.tests import PloneTestCase @@ -137,16 +136,16 @@ def testGetCurrentFolder(self): def testCropText(self): view = Plone(self.portal, self.app.REQUEST) self.assertEqual(view.cropText(b'Hello world', 7), b'Hello ...') - self.assertEqual(view.cropText(u'Hello world', 7), u'Hello ...') + self.assertEqual(view.cropText('Hello world', 7), 'Hello ...') self.assertEqual(view.cropText(b'Hello world', 10), b'Hello worl...') - self.assertEqual(view.cropText(u'Hello world', 10), u'Hello worl...') + self.assertEqual(view.cropText('Hello world', 10), 'Hello worl...') self.assertEqual(view.cropText(b'Hello world', 99), b'Hello world') - self.assertEqual(view.cropText(u'Hello world', 99), u'Hello world') + self.assertEqual(view.cropText('Hello world', 99), 'Hello world') self.assertEqual( - view.cropText(u'Koko\u0159\xedn', 5), u'Koko\u0159...') + view.cropText('Koko\u0159\xedn', 5), 'Koko\u0159...') # Test utf encoded string Kokorin with 'r' and 'i' accented # Must return 6 characters, because 5th character is two byte - text = u'Koko\u0159\xedn'.encode('utf8') + text = 'Koko\u0159\xedn'.encode() self.assertEqual(view.cropText(text, 5), b'Koko\xc5\x99...') def testSiteEncoding(self): diff --git a/Products/CMFPlone/tests/testPortalCreation.py b/Products/CMFPlone/tests/testPortalCreation.py index ae33a046e9..fca5d5358a 100644 --- a/Products/CMFPlone/tests/testPortalCreation.py +++ b/Products/CMFPlone/tests/testPortalCreation.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_base from plone.portlets.constants import CONTEXT_CATEGORY as CONTEXT_PORTLETS from plone.portlets.interfaces import ILocalPortletAssignmentManager @@ -215,8 +214,8 @@ def testNonDefaultPageTypes(self): # We should have a default_page_types setting registry = self.portal.portal_registry self.assertIn('plone.default_page_types', registry) - self.assertNotIn(u'Folder', registry['plone.default_page_types']) - self.assertIn(u'Document', registry['plone.default_page_types']) + self.assertNotIn('Folder', registry['plone.default_page_types']) + self.assertIn('Document', registry['plone.default_page_types']) def testNoMembersAction(self): # There should not be a Members action @@ -398,7 +397,7 @@ def testSiteSetupActionIsPresent(self): actions = self.actions.listActions() self.assertEqual( [x.title for x in actions if x.title == 'Site Setup'], - [u'Site Setup'], + ['Site Setup'], ) def testEnableLivesearchProperty(self): @@ -780,8 +779,8 @@ def testPortletManagersInstalled(self): ) def testPortletAssignmentsAtRoot(self): - leftColumn = getUtility(IPortletManager, name=u'plone.leftcolumn') - rightColumn = getUtility(IPortletManager, name=u'plone.rightcolumn') + leftColumn = getUtility(IPortletManager, name='plone.leftcolumn') + rightColumn = getUtility(IPortletManager, name='plone.rightcolumn') left = getMultiAdapter( (self.portal, leftColumn), IPortletAssignmentMapping @@ -795,7 +794,7 @@ def testPortletAssignmentsAtRoot(self): def testPortletBlockingForMembersFolder(self): members = self.portal.Members - rightColumn = getUtility(IPortletManager, name=u'plone.rightcolumn') + rightColumn = getUtility(IPortletManager, name='plone.rightcolumn') portletAssignments = getMultiAdapter( (members, rightColumn), ILocalPortletAssignmentManager ) @@ -804,7 +803,7 @@ def testPortletBlockingForMembersFolder(self): ) def testAddablePortletsInColumns(self): - for name in (u'plone.leftcolumn', u'plone.rightcolumn'): + for name in ('plone.leftcolumn', 'plone.rightcolumn'): column = getUtility(IPortletManager, name=name) addable_types = [ p.addview for p in column.getAddablePortletTypes() diff --git a/Products/CMFPlone/tests/testQueryCatalog.py b/Products/CMFPlone/tests/testQueryCatalog.py index f1ebac9992..6bafb5856b 100644 --- a/Products/CMFPlone/tests/testQueryCatalog.py +++ b/Products/CMFPlone/tests/testQueryCatalog.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Test queryCatalog and plone search forms from plone.app.textfield.value import RichTextValue from plone.registry.interfaces import IRegistry @@ -120,12 +119,12 @@ def testNavigationRoot(self): INavigationSchema, prefix='plone' ) - navigation_settings.root = u'/' + navigation_settings.root = '/' qry = self.folder.queryCatalog(request, use_navigation_root=True) self.assertEqual('/'.join(self.portal.getPhysicalPath()), qry['path']) self.setRoles(('Manager',)) self.portal.invokeFactory('Folder', 'foo') - navigation_settings.root = u'/foo' + navigation_settings.root = '/foo' qry = self.folder.queryCatalog(request, use_navigation_root=True) self.assertEqual( '/'.join(self.portal.foo.getPhysicalPath()), @@ -242,7 +241,7 @@ class TestQueryCatalogParseError(PloneTestCase.PloneTestCase): def afterSetUp(self): self.folder.invokeFactory( - 'Document', id='doc', text=RichTextValue(u'foo bar baz')) + 'Document', id='doc', text=RichTextValue('foo bar baz')) def testSearchableText(self): request = {'SearchableText': 'foo'} diff --git a/Products/CMFPlone/tests/testRegistrationTool.py b/Products/CMFPlone/tests/testRegistrationTool.py index 0a922935f1..a10869da25 100644 --- a/Products/CMFPlone/tests/testRegistrationTool.py +++ b/Products/CMFPlone/tests/testRegistrationTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import unittest from AccessControl import Unauthorized @@ -148,9 +147,9 @@ def testRegisteredNotify(self): registry = getUtility(IRegistry) site_settings = registry.forInterface(ISiteSchema, prefix='plone') - site_settings.site_title = u'Tëst Portal' + site_settings.site_title = 'Tëst Portal' mail_settings = registry.forInterface(IMailSchema, prefix="plone") - mail_settings.email_from_name = u'Tëst Admin' + mail_settings.email_from_name = 'Tëst Admin' mail_settings.email_from_address = 'bar@baz.com' # Notify the registered user @@ -177,9 +176,9 @@ def testRegisteredNotifyEncoding(self): 'email': 'foo@bar.com'}) registry = getUtility(IRegistry) site_settings = registry.forInterface(ISiteSchema, prefix='plone') - site_settings.site_title = u'Test Portal' + site_settings.site_title = 'Test Portal' mail_settings = registry.forInterface(IMailSchema, prefix="plone") - mail_settings.email_from_name = u'Test Admin' + mail_settings.email_from_name = 'Test Admin' mail_settings.email_from_address = 'bar@baz.com' # Set the portal email encoding @@ -207,9 +206,9 @@ def testMailPassword(self): registry = getUtility(IRegistry) site_settings = registry.forInterface(ISiteSchema, prefix='plone') - site_settings.site_title = u'Tëst Portal' + site_settings.site_title = 'Tëst Portal' mail_settings = registry.forInterface(IMailSchema, prefix="plone") - mail_settings.email_from_name = u'Tëst Admin' + mail_settings.email_from_name = 'Tëst Admin' mail_settings.email_from_address = 'bar@baz.com' from zope.publisher.browser import TestRequest @@ -237,9 +236,9 @@ def testMailPasswordEncoding(self): 'email': 'foo@bar.com'}) registry = getUtility(IRegistry) site_settings = registry.forInterface(ISiteSchema, prefix='plone') - site_settings.site_title = u'Tëst Portal' + site_settings.site_title = 'Tëst Portal' mail_settings = registry.forInterface(IMailSchema, prefix="plone") - mail_settings.email_from_name = u'Test Admin' + mail_settings.email_from_name = 'Test Admin' mail_settings.email_from_address = 'bar@baz.com' # Set the portal email encoding @@ -307,11 +306,11 @@ def test_normal_cc_tld(self): self.assertTrue(*result) def test_idn_cc_tld(self): - result = self.check(u"webmaster@example.xn--wgbh1c") + result = self.check("webmaster@example.xn--wgbh1c") self.assertTrue(*result) def test_long_tld(self): - result = self.check(u"webmaster@example.onion") + result = self.check("webmaster@example.onion") self.assertTrue(*result) diff --git a/Products/CMFPlone/tests/testResourceRegistries.py b/Products/CMFPlone/tests/testResourceRegistries.py index 21e7c707f5..d17106da82 100644 --- a/Products/CMFPlone/tests/testResourceRegistries.py +++ b/Products/CMFPlone/tests/testResourceRegistries.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.testing import logout from plone.registry.interfaces import IRegistry from plone.resource.interfaces import IResourceDirectory @@ -21,7 +20,7 @@ from zope.component import getUtility import json -import mock +from unittest import mock import os @@ -57,14 +56,14 @@ def test_cooking_resources(self): cookWhenChangingSettings(self.portal, bundle) resp_js = subrequest( - '{0}/++plone++static/foobar-compiled.js'.format( + '{}/++plone++static/foobar-compiled.js'.format( self.portal.absolute_url() ) ) self.assertIn(b'alert("Hi!");alert("Ho!");', resp_js.getBody()) resp_css = subrequest( - '{0}/++plone++static/foobar-compiled.css'.format( + '{}/++plone++static/foobar-compiled.css'.format( self.portal.absolute_url() ) ) @@ -100,14 +99,14 @@ def test_dont_minify_already_minified(self): cookWhenChangingSettings(self.portal, bundle) resp_js = subrequest( - '{0}/++plone++static/foobar-compiled.js'.format( + '{}/++plone++static/foobar-compiled.js'.format( self.portal.absolute_url() ) ) self.assertIn(b'alert("Hi!");\n\nalert("Ho!");', resp_js.getBody()) resp_css = subrequest( - '{0}/++plone++static/foobar-compiled.css'.format( + '{}/++plone++static/foobar-compiled.css'.format( self.portal.absolute_url() ) ) @@ -141,7 +140,7 @@ def test_cook_only_css(self): cookWhenChangingSettings(self.portal, bundle) resp_css = subrequest( - '{0}/++plone++static/foobar-compiled.css'.format( + '{}/++plone++static/foobar-compiled.css'.format( self.portal.absolute_url() ) ) @@ -166,7 +165,7 @@ def test_cooking_missing(self): cookWhenChangingSettings(self.portal, bundle) resp = subrequest( - '{0}/++plone++static/foobar-compiled.js'.format( + '{}/++plone++static/foobar-compiled.js'.format( self.portal.absolute_url() ) ) @@ -223,7 +222,7 @@ def test_error(self): cookWhenChangingSettings(self.portal, bundle) resp = subrequest( - '{0}/++plone++static/foobar-compiled.js'.format( + '{}/++plone++static/foobar-compiled.js'.format( self.portal.absolute_url() ) ) @@ -344,15 +343,15 @@ def test_override_rewrite_links(self): req.environ['PATH_INFO'] = '++plone++foo/bar.css' mng = OverrideFolderManager(self.portal) css = """ -.foo { - background-image: url("%(site_url)s/foobar.css"); -} -.bar { - background-image: url("%(site_url)s/++plone++foo/bar/foobar.css"); -} -.foobar { - background-image: url("%(site_url)s/foo/bar/foobar.css"); -}""" % {'site_url': self.portal.absolute_url()} +.foo {{ + background-image: url("{site_url}/foobar.css"); +}} +.bar {{ + background-image: url("{site_url}/++plone++foo/bar/foobar.css"); +}} +.foobar {{ + background-image: url("{site_url}/foo/bar/foobar.css"); +}}""".format(site_url=self.portal.absolute_url()) mng.save_file('foo/bar.css', css) value = self.portal.restrictedTraverse('++plone++foo/bar.css') match = b""" @@ -375,13 +374,13 @@ def test_get_require_js_config_uses_stub_modules(self): self.assertEqual(config['paths']['jquery'], 'empty:') -class DummyResource(object): +class DummyResource: def __init__(self, name): self.js = name self.css = [name, ] -class DummyBundle(object): +class DummyBundle: def __init__(self, name, enabled=True): self.__prefix__ = 'test/' + name self.compile = True diff --git a/Products/CMFPlone/tests/testRestrictedAcquisition.py b/Products/CMFPlone/tests/testRestrictedAcquisition.py index d243d31564..dda5d66426 100644 --- a/Products/CMFPlone/tests/testRestrictedAcquisition.py +++ b/Products/CMFPlone/tests/testRestrictedAcquisition.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # # This test module demonstrates a problem caused by the removal of # a few lines of code from cAccessControl.c and ImplPython.c diff --git a/Products/CMFPlone/tests/testSearch.py b/Products/CMFPlone/tests/testSearch.py index c048f954cd..e331876b9e 100644 --- a/Products/CMFPlone/tests/testSearch.py +++ b/Products/CMFPlone/tests/testSearch.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import sys import time import unittest @@ -71,7 +70,7 @@ def setUpPloneSite(self, portal): 'Document', 'my-page' + str(i), text=RichTextValue( - u'spam spam ham eggs', 'text/html', 'text/x-html-safe'), + 'spam spam ham eggs', 'text/html', 'text/x-html-safe'), ) # Sleep before creating the next one, otherwise ordering by date is # not deterministic. @@ -224,14 +223,14 @@ def test_filter_empty(self): # Search.filter_query() will get SearchableText from form if not # passed in explicit query argument: req.form['SearchableText'] = 'spam' - view = getMultiAdapter((portal, req), name=u'search') + view = getMultiAdapter((portal, req), name='search') res = view.results(batch=False) self.assertTrue('my-page1' in [r.getId() for r in res], 'Test document is not found in the results.') # filter_query() will return None on invalid query (no real indexes): req = test_request() req.form['garbanzo'] = 'chickpea' # just noise, no index for this - view = getMultiAdapter((portal, req), name=u'search') + view = getMultiAdapter((portal, req), name='search') self.assertIsNone(view.filter_query({'b_start': 0, 'b_size': 10})) # resulting empty query, ergo no search performed, empty result: self.assertFalse(view.results(batch=False)) @@ -254,7 +253,7 @@ def test_filter_with_plone3_query(self): req.form['created'] = [DateTime('1970/02/01 00:00:00 GMT+0')] req.form['created_usage'] = 'range:min' req.form['submit'] = 'Search' - view = getMultiAdapter((portal, req), name=u'search') + view = getMultiAdapter((portal, req), name='search') res = view.results(batch=False) self.assertEqual([], [r for r in res]) diff --git a/Products/CMFPlone/tests/testSecurity.py b/Products/CMFPlone/tests/testSecurity.py index 76e5d53ce2..c5551791ce 100644 --- a/Products/CMFPlone/tests/testSecurity.py +++ b/Products/CMFPlone/tests/testSecurity.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.tests.PloneTestCase import PloneTestCase from Testing.makerequest import makerequest from plone.app.testing import SITE_OWNER_NAME diff --git a/Products/CMFPlone/tests/testSecurityDeclarations.py b/Products/CMFPlone/tests/testSecurityDeclarations.py index c2678d6689..fd6a447558 100644 --- a/Products/CMFPlone/tests/testSecurityDeclarations.py +++ b/Products/CMFPlone/tests/testSecurityDeclarations.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Tests the security declarations Plone makes on resources # for access by restricted code (aka PythonScripts) diff --git a/Products/CMFPlone/tests/testSiteAdminRole.py b/Products/CMFPlone/tests/testSiteAdminRole.py index e514a99433..788673a770 100644 --- a/Products/CMFPlone/tests/testSiteAdminRole.py +++ b/Products/CMFPlone/tests/testSiteAdminRole.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl.PermissionRole import rolesForPermissionOn from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING diff --git a/Products/CMFPlone/tests/testSyndication.py b/Products/CMFPlone/tests/testSyndication.py index 3ec8577763..88da13ded3 100644 --- a/Products/CMFPlone/tests/testSyndication.py +++ b/Products/CMFPlone/tests/testSyndication.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import re from Products.CMFCore.utils import getToolByName from AccessControl import Unauthorized @@ -156,11 +155,11 @@ def test_search_feed_view_raises_404_not_site_root(self): class TestSyndicationFeedAdapter(BaseSyndicationTest): def afterSetUp(self): - super(TestSyndicationFeedAdapter, self).afterSetUp() + super().afterSetUp() self.feed = IFeed(self.folder) self.feeddatadoc = DexterityItem(self.doc1, self.feed) from plone.namedfile.file import NamedBlobFile - self.file.file = NamedBlobFile(data='lorem', filename=u'string.txt') + self.file.file = NamedBlobFile(data='lorem', filename='string.txt') self.feeddatafile = DexterityItem(self.file, self.feed) def test_link_on_folder(self): @@ -213,7 +212,7 @@ def test_has_enclosure(self): class TestRenderBody(BaseSyndicationTest): def afterSetUp(self): - super(TestRenderBody, self).afterSetUp() + super().afterSetUp() self.folder.invokeFactory('News Item', 'news1') self.folder.invokeFactory('News Item', 'news2') self.news1 = self.folder.news1 @@ -235,18 +234,18 @@ def test_atom(self): xml = self.folder.restrictedTraverse("@@atom.xml")() self.assertTrue(len(re.findall('', xml)) == 5) news1_feed = r'\s*News 1\s*' \ - r'\s*' \ - r'urn:syndication:{1}\s*' \ + r'\s*' \ + r'urn:syndication:{}\s*' \ r'

The news item #1\s*' \ - r''.format(self.news1.absolute_url(), + r''.format(self.news1.absolute_url(), self.news1.UID(), self.folder.absolute_url()) self.assertTrue(re.search(news1_feed, xml) is not None) self.assertTrue(re.search(BODY_TEXT, xml) is not None) news2_feed = r'\s*News 2\s*' \ - r'\s*' \ - r'urn:syndication:{1}\s*' \ - r''.format(self.news2.absolute_url(), + r'\s*' \ + r'urn:syndication:{}\s*' \ + r''.format(self.news2.absolute_url(), self.news2.UID(), self.folder.absolute_url()) self.assertTrue(re.search(news2_feed, xml) is not None) diff --git a/Products/CMFPlone/tests/testTranslationServiceTool.py b/Products/CMFPlone/tests/testTranslationServiceTool.py index bd13492922..801a6098a0 100644 --- a/Products/CMFPlone/tests/testTranslationServiceTool.py +++ b/Products/CMFPlone/tests/testTranslationServiceTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Test toLocalizedTime script and TranslationServiceTool. from Products.CMFPlone.tests import PloneTestCase @@ -12,24 +11,24 @@ def afterSetUp(self): def testUTranslate(self): # Test Unicode value - value = self.tool.translate(u'foo', 'domain') - self.assertEqual(value, u'foo') + value = self.tool.translate('foo', 'domain') + self.assertEqual(value, 'foo') # Test ascii value value = self.tool.translate('foo', 'domain') - self.assertEqual(value, u'foo') + self.assertEqual(value, 'foo') # Test empty string value = self.tool.translate('', 'domain') - self.assertEqual(value, u'') + self.assertEqual(value, '') # Test empty domain value = self.tool.translate('foo', 'domain') - self.assertEqual(value, u'foo') + self.assertEqual(value, 'foo') # Test default is None value = self.tool.translate('foo', 'domain', default=None) - self.assertEqual(value, u'foo') + self.assertEqual(value, 'foo') class TestTranslationServiceTool(PloneTestCase.PloneTestCase): diff --git a/Products/CMFPlone/tests/testURLTool.py b/Products/CMFPlone/tests/testURLTool.py index 45ac973422..78d38eb845 100644 --- a/Products/CMFPlone/tests/testURLTool.py +++ b/Products/CMFPlone/tests/testURLTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import unittest from Products.CMFCore.tests.base.dummy import DummySite diff --git a/Products/CMFPlone/tests/testUnicodeSplitter.py b/Products/CMFPlone/tests/testUnicodeSplitter.py index fdfaf9ea59..6e1fa69b53 100644 --- a/Products/CMFPlone/tests/testUnicodeSplitter.py +++ b/Products/CMFPlone/tests/testUnicodeSplitter.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from OFS.metaconfigure import setDeprecatedManageAddDelete from plone.app.testing import setRoles from plone.app.testing import TEST_USER_ID @@ -49,8 +48,8 @@ def setUp(self): def testProcessGerman(self): # German letters - input = [u"\xc4ffin foo"] - output = [u"\xc4ffin", u"foo"] + input = ["\xc4ffin foo"] + output = ["\xc4ffin", "foo"] output = [t.encode('utf-8') for t in output] self.assertEqual(self.process(input), output) @@ -63,9 +62,9 @@ def testProcessGerman(self): def testProcessGreek(self): # Greek letters input = [ - u'\u039d\u03af\u03ba\u03bf\u03c2 \u03a4\u03b6\u03ac\u03bd\u03bf\u03c2 foo'] - output = [u'\u039d\u03af\u03ba\u03bf\u03c2', - u'\u03a4\u03b6\u03ac\u03bd\u03bf\u03c2', u'foo'] + '\u039d\u03af\u03ba\u03bf\u03c2 \u03a4\u03b6\u03ac\u03bd\u03bf\u03c2 foo'] + output = ['\u039d\u03af\u03ba\u03bf\u03c2', + '\u03a4\u03b6\u03ac\u03bd\u03bf\u03c2', 'foo'] output = [t.encode('utf-8') for t in output] self.assertEqual(self.process(input), output) @@ -77,8 +76,8 @@ def testProcessGreek(self): def testProcessTurkish(self): # Turkish letters - input = [u"\xdc\u011f\xfcr foo"] - output = [u"\xdc\u011f\xfcr", u"foo"] + input = ["\xdc\u011f\xfcr foo"] + output = ["\xdc\u011f\xfcr", "foo"] output = [t.encode('utf-8') for t in output] self.assertEqual(self.process(input), output) @@ -97,9 +96,9 @@ def testProcessLatin1(self): # Test passes because plone_lexicon pipeline elements # are coded defensively. # - u_input = [u"\xc4ffin foo"] + u_input = ["\xc4ffin foo"] b_input = [t.encode('utf-8') for t in u_input] - u_output = [u"\xc4ffin", u"foo"] + u_output = ["\xc4ffin", "foo"] b_output = [t.encode('utf-8') for t in u_output] # May still fail if none of the locales is available @@ -123,9 +122,9 @@ def setUp(self): self.process = self.normalizer.process def testNormalizeGerman(self): - u_input = [u"\xc4ffin"] + u_input = ["\xc4ffin"] b_input = [t.encode('utf-8') for t in u_input] - u_output = [u"\xe4ffin"] + u_output = ["\xe4ffin"] b_output = [t.encode('utf-8') for t in u_output] self.assertEqual(self.process(u_input), b_output) @@ -136,9 +135,9 @@ def testNormalizeLatin1(self): # Test passes because plone_lexicon pipeline elements # are coded defensively. # - u_input = [u"\xc4ffin"] + u_input = ["\xc4ffin"] b_input = [t.encode('utf-8') for t in u_input] - u_output = [u"\xe4ffin"] + u_output = ["\xe4ffin"] b_output = [t.encode('utf-8') for t in u_output] # May still fail if none of the locales is available @@ -243,23 +242,23 @@ def testMixedModeQuery(self): def testQueryByUnicode(self): self.doc1.SearchableText = 'Äffin' self.catalog.indexObject(self.doc1) - brains = self.catalog(SearchableText=u'Äffin') + brains = self.catalog(SearchableText='Äffin') self.assertEqual(len(brains), 1) def testQueryByUnicodeLower(self): self.doc1.SearchableText = 'Äffin' self.catalog.indexObject(self.doc1) - brains = self.catalog(SearchableText=u'äffin') + brains = self.catalog(SearchableText='äffin') self.assertEqual(len(brains), 1) def testIndexUnicode(self): - self.doc1.SearchableText = u'\xc4ffin' + self.doc1.SearchableText = '\xc4ffin' self.catalog.indexObject(self.doc1) brains = self.catalog(SearchableText='Äffin') self.assertEqual(len(brains), 1) def testIndexUnicodeLower(self): - self.doc1.SearchableText = u'\xc4ffin' + self.doc1.SearchableText = '\xc4ffin' self.catalog.indexObject(self.doc1) brains = self.catalog(SearchableText='äffin') self.assertEqual(len(brains), 1) @@ -269,11 +268,11 @@ class TestBigramFunctions(unittest.TestCase): def test_process_str(self): lsts = [ - ("日本", [u"日本", u"本"]), - ("日", [u"日"]), - ("日本語", [u"日本", u"本語", u"語"]), - ("日本語python", [u"日本", u"本語", u"語", u"python"]), - ("日本語12345", [u"日本", u"本語", u"語", u"12345"]), + ("日本", ["日本", "本"]), + ("日", ["日"]), + ("日本語", ["日本", "本語", "語"]), + ("日本語python", ["日本", "本語", "語", "python"]), + ("日本語12345", ["日本", "本語", "語", "12345"]), ] for lst, rst in lsts: rst = [x.encode('utf8') for x in rst] @@ -281,11 +280,11 @@ def test_process_str(self): def test_process_unicode(self): lsts = [ - (u"日本", [u"日本", u"本"]), - (u"日", [u"日"]), - (u"日本語", [u"日本", u"本語", u"語"]), - (u"日本語python", [u"日本", u"本語", u"語", u"python"]), - (u"日本語12345", [u"日本", u"本語", u"語", u"12345"]), + ("日本", ["日本", "本"]), + ("日", ["日"]), + ("日本語", ["日本", "本語", "語"]), + ("日本語python", ["日本", "本語", "語", "python"]), + ("日本語12345", ["日本", "本語", "語", "12345"]), ] for lst, rst in lsts: self.assertEqual(rst, list(process_unicode(lst))) @@ -293,10 +292,10 @@ def test_process_unicode(self): def test_process_str_glob(self): enc = "utf8" lsts = [ - ("日本", [u"日本"]), - ("日", [u"日*"]), - ("日本語", [u"日本", u"本語"]), - ("日本語python", [u"日本", u"本語", u"語", u"python"]), + ("日本", ["日本"]), + ("日", ["日*"]), + ("日本語", ["日本", "本語"]), + ("日本語python", ["日本", "本語", "語", "python"]), ] for lst, rst in lsts: rst = [x.encode('utf8') for x in rst] @@ -307,10 +306,10 @@ def test_process_str_glob(self): def test_process_unicode_glob(self): lsts = [ - (u"日本", [u"日本"]), - (u"日", [u"日*"]), - (u"日本語", [u"日本", u"本語"]), - (u"日本語python", [u"日本", u"本語", u"語", u"python"]), + ("日本", ["日本"]), + ("日", ["日*"]), + ("日本語", ["日本", "本語"]), + ("日本語python", ["日本", "本語", "語", "python"]), ] for lst, rst in lsts: self.assertEqual(rst, list(process_unicode_glob(lst))) @@ -321,8 +320,8 @@ def test_process_unicode_glob(self): def test_process_str_post(self): enc = "utf8" lsts = [ - ("日本", u"日本"), - ("日本*", u"日本"), + ("日本", "日本"), + ("日本*", "日本"), ] for lst, rst in lsts: rst = rst.encode('utf8') @@ -340,27 +339,27 @@ def setUp(self): setRoles(self.portal, TEST_USER_ID, ['Manager']) self.portal.invokeFactory('Document', 'doc1') self.doc1 = getattr(self.portal, 'doc1') - self.doc1.setTitle(u"Ploneは素晴らしい。") - text = u"このページは予想している通り、テストです。 Pages Testing." + self.doc1.setTitle("Ploneは素晴らしい。") + text = "このページは予想している通り、テストです。 Pages Testing." self.doc1.text = RichTextValue(text, 'text/html', 'text/x-html-safe') self.doc1.reindexObject() def testSearch(self): catalog = getToolByName(self.portal, 'portal_catalog') - items1 = catalog(SearchableText=u"予想") + items1 = catalog(SearchableText="予想") self.assertEqual(len(items1), 1) - items12 = catalog(SearchableText=u"素晴らしい") + items12 = catalog(SearchableText="素晴らしい") self.assertEqual(len(items12), 1) - items13 = catalog(SearchableText=u"Pages") + items13 = catalog(SearchableText="Pages") self.assertEqual(len(items13), 1) - items14 = catalog(SearchableText=u"ページ") + items14 = catalog(SearchableText="ページ") self.assertEqual(len(items14), 1) - items15 = catalog(SearchableText=u"予想*") + items15 = catalog(SearchableText="予想*") self.assertEqual(len(items15), 1) - items16 = catalog(SearchableText=u"予想") + items16 = catalog(SearchableText="予想") self.assertEqual(len(items16), 1) self.portal.manage_delObjects(['doc1']) - items2 = catalog(SearchableText=u"予想") + items2 = catalog(SearchableText="予想") self.assertEqual(len(items2), 0) @@ -374,25 +373,25 @@ def setUp(self): setRoles(self.portal, TEST_USER_ID, ['Manager']) self.portal.invokeFactory('Document', 'doc1') self.doc1 = getattr(self.portal, 'doc1') - self.doc1.setTitle(u"Ploneは素晴らしい。") - text = u"このページは予想している通り、テストです。 Pages Testing." + self.doc1.setTitle("Ploneは素晴らしい。") + text = "このページは予想している通り、テストです。 Pages Testing." self.doc1.text = RichTextValue(text, 'text/html', 'text/x-html-safe') self.doc1.reindexObject() def testSearch(self): catalog = getToolByName(self.portal, 'portal_catalog') - items1 = catalog(SearchableText=u"予想") + items1 = catalog(SearchableText="予想") self.assertEqual(len(items1), 1) - items12 = catalog(SearchableText=u"素晴らしい") + items12 = catalog(SearchableText="素晴らしい") self.assertEqual(len(items12), 1) - items13 = catalog(SearchableText=u"Pages") + items13 = catalog(SearchableText="Pages") self.assertEqual(len(items13), 1) - items14 = catalog(SearchableText=u"ページ") + items14 = catalog(SearchableText="ページ") self.assertEqual(len(items14), 1) - items15 = catalog(SearchableText=u"予想*") + items15 = catalog(SearchableText="予想*") self.assertEqual(len(items15), 1) items16 = catalog(SearchableText="予想") self.assertEqual(len(items16), 1) self.portal.manage_delObjects(['doc1']) - items2 = catalog(SearchableText=u"予想") + items2 = catalog(SearchableText="予想") self.assertEqual(len(items2), 0) diff --git a/Products/CMFPlone/tests/testUserFolderBasics.py b/Products/CMFPlone/tests/testUserFolderBasics.py index 119945e0fd..d8d5919b22 100644 --- a/Products/CMFPlone/tests/testUserFolderBasics.py +++ b/Products/CMFPlone/tests/testUserFolderBasics.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generic user folder tests. Every user folder implementation # must pass these. diff --git a/Products/CMFPlone/tests/testWebDAV.py b/Products/CMFPlone/tests/testWebDAV.py index b2d7dae797..63ca592faa 100644 --- a/Products/CMFPlone/tests/testWebDAV.py +++ b/Products/CMFPlone/tests/testWebDAV.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.testing import SITE_OWNER_NAME from plone.app.testing import SITE_OWNER_PASSWORD from plone.app.testing import TEST_USER_NAME @@ -36,7 +35,7 @@ class TestPUTObjects(PloneTestCase.PloneTestCase): # Confirms fix for http://dev.plone.org/plone/ticket/1375 def afterSetUp(self): - self.basic_auth = '%s:%s' % (TEST_USER_NAME, TEST_USER_PASSWORD) + self.basic_auth = f'{TEST_USER_NAME}:{TEST_USER_PASSWORD}' self.portal_path = self.portal.absolute_url(1) self.folder_path = self.folder.absolute_url(1) @@ -279,7 +278,7 @@ class TestPUTIndexHtml(PloneTestCase.PloneTestCase): """ def afterSetUp(self): - self.basic_auth = '%s:%s' % (TEST_USER_NAME, TEST_USER_PASSWORD) + self.basic_auth = f'{TEST_USER_NAME}:{TEST_USER_PASSWORD}' self.portal_path = self.portal.absolute_url(1) self.folder_path = self.folder.absolute_url(1) self.body = 'I am the walrus' @@ -325,7 +324,7 @@ class TestDAVOperations(PloneTestCase.FunctionalTestCase): def afterSetUp(self): self.loginAsPortalOwner() - self.basic_auth = '%s:%s' % (SITE_OWNER_NAME, + self.basic_auth = '{}:{}'.format(SITE_OWNER_NAME, SITE_OWNER_PASSWORD) self.portal_path = self.portal.absolute_url(1) self.folder_path = self.folder.absolute_url(1) diff --git a/Products/CMFPlone/tests/testWorkflowTool.py b/Products/CMFPlone/tests/testWorkflowTool.py index 0fefdd1b5d..d9a64e7d5c 100644 --- a/Products/CMFPlone/tests/testWorkflowTool.py +++ b/Products/CMFPlone/tests/testWorkflowTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.interface import directlyProvides, Interface from zope.component import provideAdapter, getGlobalSiteManager from Products.CMFPlone.tests import PloneTestCase diff --git a/Products/CMFPlone/tests/test_PloneTool.py b/Products/CMFPlone/tests/test_PloneTool.py index 88541894ec..c28a337cbf 100644 --- a/Products/CMFPlone/tests/test_PloneTool.py +++ b/Products/CMFPlone/tests/test_PloneTool.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.testing import login from plone.app.testing import TEST_USER_ID from plone.app.testing import TEST_USER_NAME @@ -74,7 +73,7 @@ def test_addPortalMessage(self): [] ) - self.tool.addPortalMessage(u'A random warning message', 'warning') + self.tool.addPortalMessage('A random warning message', 'warning') status = IStatusMessage(self.request).show() self.assertEqual( len(status), @@ -91,7 +90,7 @@ def test_addPortalMessage(self): [] ) - self.tool.addPortalMessage(u'A random info message') + self.tool.addPortalMessage('A random info message') status = IStatusMessage(self.request).show() self.assertEqual( len(status), @@ -186,5 +185,5 @@ def test_normalizeString_file_like(self): def test_getEmptyTitle(self): self.assertEqual( self.tool.getEmptyTitle(translated=False), - u'[\xb7\xb7\xb7]' + '[\xb7\xb7\xb7]' ) diff --git a/Products/CMFPlone/tests/test_defaultpage.py b/Products/CMFPlone/tests/test_defaultpage.py index 4dfd670d07..1bab2cbc4b 100644 --- a/Products/CMFPlone/tests/test_defaultpage.py +++ b/Products/CMFPlone/tests/test_defaultpage.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.component import getUtility from plone.registry.interfaces import IRegistry from plone.app.testing import setRoles @@ -14,14 +13,14 @@ class DefaultPageTestCase(unittest.TestCase): def setUp(self): self.portal = self.layer['portal'] setRoles(self.portal, TEST_USER_ID, ['Manager']) - self.portal.invokeFactory('Folder', 'folder', title=u"Test Folder") + self.portal.invokeFactory('Folder', 'folder', title="Test Folder") self.folder = self.portal.folder def test_get_default_page_step_1(self): # A content object called 'index_html' wins - self.folder.invokeFactory('Document', 'd1', title=u"Doc 1") + self.folder.invokeFactory('Document', 'd1', title="Doc 1") self.folder.setDefaultPage('d1') - self.folder.invokeFactory('Document', 'index_html', title=u"Doc 2") + self.folder.invokeFactory('Document', 'index_html', title="Doc 2") from Products.CMFPlone.defaultpage import get_default_page self.assertEqual('index_html', get_default_page(self.folder)) @@ -46,7 +45,7 @@ def test_get_default_page_step_2(self): self.assertTrue(IDynamicViewTypeInformation.providedBy(fti)) # so if we set a document as defaultpage - self.folder.invokeFactory('Document', 'd1', title=u"Doc 1") + self.folder.invokeFactory('Document', 'd1', title="Doc 1") self.folder.setDefaultPage('d1') # 3) fti should return it @@ -67,7 +66,7 @@ def test_get_default_page_step_3_1(self): # 3. Else, look up the attribute default_page on the object, without # acquisition in place # 3.1 look for a content in the container with the id, no acquisition! - self.folder.invokeFactory('Document', 'd1', title=u"Doc 1") + self.folder.invokeFactory('Document', 'd1', title="Doc 1") from Products.CMFPlone.defaultpage import get_default_page # set doc d1 must work @@ -87,8 +86,8 @@ def test_get_default_page_step_3_1(self): self.assertIsNone(get_default_page(self.folder)) # acquisition check, must not work - self.folder.invokeFactory('Folder', 'f1', title=u"Sub Folder 1") - self.folder.f1.invokeFactory('Document', 'd2', title=u"Document 2") + self.folder.invokeFactory('Folder', 'f1', title="Sub Folder 1") + self.folder.f1.invokeFactory('Document', 'd2', title="Document 2") self.folder.default_page = 'd2' self.assertIsNone(get_default_page(self.folder.f1)) @@ -96,7 +95,7 @@ def test_get_default_page_step_3_2(self): # 3. Else, look up the attribute default_page on the object, without # acquisition in place # 3.2 look for a content at portal, with acquisition - self.portal.invokeFactory('Document', 'd1', title=u"Doc 1") + self.portal.invokeFactory('Document', 'd1', title="Doc 1") self.folder.default_page = 'd1' from Products.CMFPlone.defaultpage import get_default_page @@ -113,8 +112,8 @@ def test_get_default_page_step_4(self): # 4. Else, look up the property default_page in site_properties for # magic ids and test these registry = getUtility(IRegistry) - registry['plone.default_page'] = [u'd1'] - self.folder.invokeFactory('Document', 'd1', title=u"Doc 1") + registry['plone.default_page'] = ['d1'] + self.folder.invokeFactory('Document', 'd1', title="Doc 1") from Products.CMFPlone.defaultpage import get_default_page self.assertEqual('d1', get_default_page(self.folder)) diff --git a/Products/CMFPlone/tests/test_doctests.py b/Products/CMFPlone/tests/test_doctests.py index 0ec096194b..14c5b17659 100644 --- a/Products/CMFPlone/tests/test_doctests.py +++ b/Products/CMFPlone/tests/test_doctests.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from unittest import TestSuite import doctest diff --git a/Products/CMFPlone/tests/test_error_message.py b/Products/CMFPlone/tests/test_error_message.py index 1a5874ff9d..1e234c4066 100644 --- a/Products/CMFPlone/tests/test_error_message.py +++ b/Products/CMFPlone/tests/test_error_message.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.redirector.interfaces import IRedirectionStorage from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING from zExceptions import HTTPNotImplemented diff --git a/Products/CMFPlone/tests/test_factory.py b/Products/CMFPlone/tests/test_factory.py index e3c776f881..e542972258 100644 --- a/Products/CMFPlone/tests/test_factory.py +++ b/Products/CMFPlone/tests/test_factory.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.dexterity.interfaces import IDexterityFTI from Products.CMFPlone.factory import addPloneSite from Products.CMFPlone.utils import get_installer diff --git a/Products/CMFPlone/tests/test_functional.py b/Products/CMFPlone/tests/test_functional.py index 15c1add384..8a5d695d3e 100644 --- a/Products/CMFPlone/tests/test_functional.py +++ b/Products/CMFPlone/tests/test_functional.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.contenttypes.testing import PLONE_APP_CONTENTTYPES_FUNCTIONAL_TESTING # noqa from plone.app.testing import PLONE_FUNCTIONAL_TESTING from plone.testing import layered diff --git a/Products/CMFPlone/tests/test_l18nl10n.py b/Products/CMFPlone/tests/test_l18nl10n.py index 89086a11a9..3a56a06736 100644 --- a/Products/CMFPlone/tests/test_l18nl10n.py +++ b/Products/CMFPlone/tests/test_l18nl10n.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Unit tests for Products.CMFPlone.i18nl10n module. """ import unittest diff --git a/Products/CMFPlone/tests/test_login_form.py b/Products/CMFPlone/tests/test_login_form.py index 49e20620cc..78fc2cbc44 100644 --- a/Products/CMFPlone/tests/test_login_form.py +++ b/Products/CMFPlone/tests/test_login_form.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from DateTime import DateTime from plone.app.z3cform.interfaces import IPloneFormLayer from Products.CMFCore.permissions import SetOwnProperties @@ -35,7 +34,7 @@ def _setup_authenticator_request(self): self.request.set('REQUEST_METHOD', 'POST') authenticator = getMultiAdapter( (self.portal, self.request), - name=u'authenticator' + name='authenticator' ) html = authenticator.authenticator() token = re.search('value="(.*)"', html).groups()[0] @@ -43,9 +42,9 @@ def _setup_authenticator_request(self): def test_form_update(self): self._setup_authenticator_request() - self.request['__ac_name'] = u'test' - self.request['__ac_password'] = u'secret' - self.request['form.widgets.came_from'] = [u''] + self.request['__ac_name'] = 'test' + self.request['__ac_password'] = 'secret' + self.request['form.widgets.came_from'] = [''] form = self.portal.restrictedTraverse(FORM_ID) form.update() data, errors = form.extractData() @@ -61,9 +60,9 @@ def test_failsafe_login_form(self): def test_failsafe_login_form_update(self): self._setup_authenticator_request() - self.request['__ac_name'] = u'test' - self.request['__ac_password'] = u'secret' - self.request['form.widgets.came_from'] = [u''] + self.request['__ac_name'] = 'test' + self.request['__ac_password'] = 'secret' + self.request['form.widgets.came_from'] = [''] form = self.portal.restrictedTraverse('failsafe_login') form.update() data, errors = form.extractData() diff --git a/Products/CMFPlone/tests/test_login_help.py b/Products/CMFPlone/tests/test_login_help.py index a004f603c6..681538c9cc 100644 --- a/Products/CMFPlone/tests/test_login_help.py +++ b/Products/CMFPlone/tests/test_login_help.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone import api from plone.testing.zope import Browser from Products.CMFPlone.browser.login.login_help import RequestResetPassword @@ -51,21 +50,21 @@ def test_request_reset_password(self): reset_password = form.subforms[0] reset_password.handleResetPassword(reset_password, None) # the field reset_password is required - self.assertEqual(reset_password.status, u'There were some errors.') + self.assertEqual(reset_password.status, 'There were some errors.') # reset error message reset_password.status = '' - self.request['form.widgets.reset_password'] = u'test' + self.request['form.widgets.reset_password'] = 'test' reset_password.handleResetPassword(reset_password, None) self.assertEqual(reset_password.status, '') self.assertEqual(len(self.portal.MailHost.messages), 0) # no mail was sent since the user does not exist - self.request['form.widgets.reset_password'] = u'test' + self.request['form.widgets.reset_password'] = 'test' member = api.user.get('test_user_1_') email = 'foo@plone.org' member.setMemberProperties({'email': email}) - self.request['form.widgets.reset_password'] = u'test_user_1_' + self.request['form.widgets.reset_password'] = 'test_user_1_' reset_password.handleResetPassword(reset_password, None) self.assertEqual(reset_password.status, '') self.assertEqual(len(self.portal.MailHost.messages), 1) diff --git a/Products/CMFPlone/tests/test_login_logout.py b/Products/CMFPlone/tests/test_login_logout.py index 865fc046fd..8998d07549 100644 --- a/Products/CMFPlone/tests/test_login_logout.py +++ b/Products/CMFPlone/tests/test_login_logout.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.testing import setRoles from plone.app.testing import TEST_USER_ID from plone.app.testing import TEST_USER_NAME diff --git a/Products/CMFPlone/tests/test_login_views.py b/Products/CMFPlone/tests/test_login_views.py index d620f47b77..716012c44f 100644 --- a/Products/CMFPlone/tests/test_login_views.py +++ b/Products/CMFPlone/tests/test_login_views.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING from zope.component import getMultiAdapter diff --git a/Products/CMFPlone/tests/test_mails.py b/Products/CMFPlone/tests/test_mails.py index 15489c56ed..431a616899 100644 --- a/Products/CMFPlone/tests/test_mails.py +++ b/Products/CMFPlone/tests/test_mails.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.testing import FunctionalTesting from plone.app.testing import MOCK_MAILHOST_FIXTURE from plone.app.testing import PLONE_FIXTURE diff --git a/Products/CMFPlone/tests/test_metabundles.py b/Products/CMFPlone/tests/test_metabundles.py index bd12a3546a..57874b4b3f 100644 --- a/Products/CMFPlone/tests/test_metabundles.py +++ b/Products/CMFPlone/tests/test_metabundles.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.resource.interfaces import IResourceDirectory from Products.CMFPlone.interfaces.resources import ( OVERRIDE_RESOURCE_DIRECTORY_NAME, diff --git a/Products/CMFPlone/tests/test_nogopip.py b/Products/CMFPlone/tests/test_nogopip.py index 9dd653bfbc..f7eeeaa009 100644 --- a/Products/CMFPlone/tests/test_nogopip.py +++ b/Products/CMFPlone/tests/test_nogopip.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING import unittest diff --git a/Products/CMFPlone/tests/test_okay.py b/Products/CMFPlone/tests/test_okay.py index b3e5a7a2ad..f50beb8116 100644 --- a/Products/CMFPlone/tests/test_okay.py +++ b/Products/CMFPlone/tests/test_okay.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.testing.zope import Browser from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING @@ -27,7 +26,7 @@ def test_okay_browser(self): ) for url in urls: browser.open(url) - self.assertEqual(browser.contents, u'OK') + self.assertEqual(browser.contents, 'OK') get_header = browser.headers.get self.assertEqual( get_header('Expires'), 'Sat, 1 Jan 2000 00:00:00 GMT') @@ -44,7 +43,7 @@ def test_okay_browser(self): def test_okay_view(self): for page in (self.app, self.portal): view = page.restrictedTraverse('@@ok') - self.assertEqual(view(), u'OK') + self.assertEqual(view(), 'OK') get_header = view.request.response.getHeader self.assertEqual( get_header('Expires'), 'Sat, 1 Jan 2000 00:00:00 GMT') diff --git a/Products/CMFPlone/tests/test_patternsettings.py b/Products/CMFPlone/tests/test_patternsettings.py index 817e7a0bd6..6872091250 100644 --- a/Products/CMFPlone/tests/test_patternsettings.py +++ b/Products/CMFPlone/tests/test_patternsettings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.testing import login from plone.app.testing import TEST_USER_NAME from plone.registry.interfaces import IRegistry @@ -41,7 +40,7 @@ def test_style_formats(self): def test_other_settings(self): registry = getUtility(IRegistry) settings = registry.forInterface(ITinyMCESchema, prefix="plone") - settings.other_settings = u'{"foo": "bar"}' + settings.other_settings = '{"foo": "bar"}' conf = self.get_conf() self.assertEqual(conf['tiny']['foo'], 'bar') @@ -98,9 +97,9 @@ def testFileUrls(self): def testPatternOptions(self): registry = getUtility(IRegistry) registry['plone.patternoptions'] = { - 'foo': u'{"foo": "bar"}' + 'foo': '{"foo": "bar"}' } settings = PatternsSettingsView(self.folder, self.layer['request']) result = settings() - self.assertEqual(result['data-pat-foo'], u'{"foo": "bar"}') + self.assertEqual(result['data-pat-foo'], '{"foo": "bar"}') diff --git a/Products/CMFPlone/tests/test_redirect_after_login.py b/Products/CMFPlone/tests/test_redirect_after_login.py index 6dd1a54221..4c0aec9a81 100644 --- a/Products/CMFPlone/tests/test_redirect_after_login.py +++ b/Products/CMFPlone/tests/test_redirect_after_login.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.testing import TEST_USER_NAME from plone.app.testing import TEST_USER_PASSWORD from plone.testing.zope import Browser @@ -15,7 +14,7 @@ @implementer(IRedirectAfterLogin) -class AfterLoginAdapter(object): +class AfterLoginAdapter: def __init__(self, context, request): self.context = context @@ -26,7 +25,7 @@ def __call__(self, came_from=None, is_first_login=False): @implementer(IInitialLogin) -class InitialLoginAdapter(object): +class InitialLoginAdapter: def __init__(self, context, request): self.context = context diff --git a/Products/CMFPlone/tests/test_robot.py b/Products/CMFPlone/tests/test_robot.py index 9dd63a234c..d282eab3d2 100644 --- a/Products/CMFPlone/tests/test_robot.py +++ b/Products/CMFPlone/tests/test_robot.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_ROBOT_TESTING from plone.app.testing import ROBOT_TEST_LEVEL from plone.testing import layered diff --git a/Products/CMFPlone/tests/test_robots_txt.py b/Products/CMFPlone/tests/test_robots_txt.py index 52fc746447..23a54ba1fb 100644 --- a/Products/CMFPlone/tests/test_robots_txt.py +++ b/Products/CMFPlone/tests/test_robots_txt.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import ISiteSchema from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING from plone.registry.interfaces import IRegistry @@ -20,5 +19,5 @@ def test_robots_view(self): self.assertIn('{portal_url}/sitemap.xml.gz', settings.robots_txt) view = self.portal.restrictedTraverse('robots.txt') self.assertIn('http://nohost/plone/sitemap.xml.gz', view()) - settings.robots_txt = u"Dummy" - self.assertEqual(u"Dummy", view()) + settings.robots_txt = "Dummy" + self.assertEqual("Dummy", view()) diff --git a/Products/CMFPlone/tests/test_safe_formatter.py b/Products/CMFPlone/tests/test_safe_formatter.py index 8142482322..bb90285cdd 100644 --- a/Products/CMFPlone/tests/test_safe_formatter.py +++ b/Products/CMFPlone/tests/test_safe_formatter.py @@ -136,7 +136,7 @@ def test_access_to_private_content_not_allowed_via_rich_text(self): from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate foobar = create_private_document(self.portal, 'foobar') login(self.portal, TEST_USER_NAME) - foobar.text = RichTextValue(u'Secret.', 'text/plain', 'text/html') + foobar.text = RichTextValue('Secret.', 'text/plain', 'text/html') self.assertEqual( self.portal.portal_workflow.getInfoFor(foobar, 'review_state'), 'private') @@ -210,8 +210,8 @@ def test_access_to_private_content_not_allowed_in_any_way(self): method_name = 'DexterityContent.Title' self.assertEqual( pt.pt_render(), - u'

access >

' % method_name) + '

access >

' % method_name) logout() self.assertRaises(Unauthorized, pt.pt_render) @@ -223,7 +223,7 @@ def test_access_to_private_content_not_allowed_in_any_way(self): login(self.portal, TEST_USER_NAME) self.assertEqual( pt.pt_render(), - u'

') + '

') logout() self.assertRaises(Unauthorized, pt.pt_render) @@ -236,7 +236,7 @@ def test_access_to_private_content_not_allowed_in_any_way(self): # If you have such a list, you *can* see an id. self.assertEqual( pt.pt_render(), - u'

[]

') + '

[]

') # But you cannot access an item. pt = ZopePageTemplate( 'mytemplate', TEMPLATE % @@ -247,7 +247,7 @@ def test_access_to_private_content_not_allowed_in_any_way(self): login(self.portal, TEST_USER_NAME) self.assertEqual( pt.pt_render(), - u'

') + '

') # Zope 3 templates are always file system templates. So we actually have # no problems allowing str.format there. @@ -261,8 +261,8 @@ def test_cook_zope3_page_templates_normal(self): namespace = {'context': self.portal} self.assertEqual( pt.pt_render(namespace).strip(), - u'

<plonesite at plone>

\n' - u'

<PLONESITE AT PLONE>

') + '

<plonesite at plone>

\n' + '

<PLONESITE AT PLONE>

') def test_cook_zope3_page_templates_using_format(self): from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile @@ -273,14 +273,14 @@ def test_cook_zope3_page_templates_using_format(self): namespace = {'context': self.portal} self.assertEqual( pt.pt_render(namespace).strip(), - u"

class of <plonesite at plone> is " - u"<class 'products.cmfplone.portal.plonesite'>

\n" - u"

CLASS OF <PLONESITE AT PLONE> IS " - u"<CLASS 'PRODUCTS.CMFPLONE.PORTAL.PLONESITE'>

\n" - u"

{'foo': 42} has foo=42

\n" - u"

{'foo': 42} has foo=42

\n" - u"

['ni'] has first item ni

\n" - u"

['ni'] has first item ni

" + "

class of <plonesite at plone> is " + "<class 'products.cmfplone.portal.plonesite'>

\n" + "

CLASS OF <PLONESITE AT PLONE> IS " + "<CLASS 'PRODUCTS.CMFPLONE.PORTAL.PLONESITE'>

\n" + "

{'foo': 42} has foo=42

\n" + "

{'foo': 42} has foo=42

\n" + "

['ni'] has first item ni

\n" + "

['ni'] has first item ni

" ) diff --git a/Products/CMFPlone/tests/test_sitelogo.py b/Products/CMFPlone/tests/test_sitelogo.py index 9f216ca1e9..1f1f8340f9 100644 --- a/Products/CMFPlone/tests/test_sitelogo.py +++ b/Products/CMFPlone/tests/test_sitelogo.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import ISiteSchema from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_INTEGRATION_TESTING from plone.registry.interfaces import IRegistry diff --git a/Products/CMFPlone/tests/test_sitemap.py b/Products/CMFPlone/tests/test_sitemap.py index 44b37f7f0c..a1c9f2fca8 100644 --- a/Products/CMFPlone/tests/test_sitemap.py +++ b/Products/CMFPlone/tests/test_sitemap.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import unittest import transaction import lxml @@ -28,7 +27,7 @@ def setUp(self): self.browser.handleErrors = False self.browser.addHeader( 'Authorization', - 'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD,) + f'Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}' ) setRoles(self.portal, TEST_USER_ID, ['Manager']) diff --git a/Products/CMFPlone/tests/test_utils.py b/Products/CMFPlone/tests/test_utils.py index a9222934e5..64ef7ea302 100644 --- a/Products/CMFPlone/tests/test_utils.py +++ b/Products/CMFPlone/tests/test_utils.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Unit tests for utils module. """ from plone.registry.interfaces import IRegistry @@ -41,9 +40,9 @@ def test_safe_encode(self): """safe_encode should always encode unicode to the specified encoding. """ from Products.CMFPlone.utils import safe_encode - self.assertEqual(safe_encode(u'späm'), b'sp\xc3\xa4m') - self.assertEqual(safe_encode(u'späm', 'utf-8'), b'sp\xc3\xa4m') - self.assertEqual(safe_encode(u'späm', encoding='latin-1'), b'sp\xe4m') + self.assertEqual(safe_encode('späm'), b'sp\xc3\xa4m') + self.assertEqual(safe_encode('späm', 'utf-8'), b'sp\xc3\xa4m') + self.assertEqual(safe_encode('späm', encoding='latin-1'), b'sp\xe4m') def test_get_top_request(self): """If in a subrequest, ``get_top_request`` should always return the top @@ -51,7 +50,7 @@ def test_get_top_request(self): """ from Products.CMFPlone.utils import get_top_request - class MockRequest(object): + class MockRequest: def __init__(self, parent_request=None): self._dict = {} @@ -82,7 +81,7 @@ def test_get_top_site_from_url(self): from urllib.parse import urlparse from zope.component.interfaces import ISite - class MockContext(object): + class MockContext: vh_url = 'http://nohost' vh_root = '' @@ -101,7 +100,7 @@ def absolute_url(self): def restrictedTraverse(self, path): return MockContext(self.vh_root + path) - class MockRequest(object): + class MockRequest: vh_url = 'http://nohost' vh_root = '' @@ -128,7 +127,7 @@ def physicalPathFromURL(self, url): self.assertEqual(get_top_site_from_url(ctx, req).id, 'PloneSite') # Case 4, using unicode paths accidentially: - ctx = MockContext(u'/approot/PloneSite/folder/SubSite/folder') + ctx = MockContext('/approot/PloneSite/folder/SubSite/folder') self.assertEqual(get_top_site_from_url(ctx, req).id, 'PloneSite') # VIRTUAL HOSTING ON SUBSITE diff --git a/Products/CMFPlone/tests/test_z3c_form_widgets.py b/Products/CMFPlone/tests/test_z3c_form_widgets.py index 0535d3f951..0e98131c04 100644 --- a/Products/CMFPlone/tests/test_z3c_form_widgets.py +++ b/Products/CMFPlone/tests/test_z3c_form_widgets.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.testing import PRODUCTS_CMFPLONE_FUNCTIONAL_TESTING from z3c.form import widget from z3c.form.browser.text import TextWidget @@ -16,7 +15,7 @@ _marker = object() -class FakeForm(object): +class FakeForm: method = 'post' ignoreRequest = False diff --git a/Products/CMFPlone/tests/test_zmi.py b/Products/CMFPlone/tests/test_zmi.py index 622559b7ca..19ecdc4d6d 100644 --- a/Products/CMFPlone/tests/test_zmi.py +++ b/Products/CMFPlone/tests/test_zmi.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.contenttypes.testing import PLONE_APP_CONTENTTYPES_INTEGRATION_TESTING # noqa: E501 from plone.app.testing import setRoles from plone.app.testing import TEST_USER_ID @@ -19,192 +18,192 @@ def setUp(self): def test_manage(self): url = 'manage' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_manage_main(self): url = 'manage_main' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_manage_components(self): url = 'manage_components' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_manage_propertiesForm(self): url = 'manage_propertiesForm' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_manage_owner(self): url = 'manage_owner' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_manage_findForm(self): url = 'manage_findForm' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_acl_users(self): url = 'acl_users/manage_main' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_caching_policy_manager(self): url = 'caching_policy_manager/manage_cachingPolicies' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_content_type_registry(self): url = 'content_type_registry/manage_predicates' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_error_log(self): url = 'error_log/manage_main' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_HTTPCache(self): url = 'HTTPCache/manage_main' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_MailHost(self): url = 'MailHost/manage_main' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_mimetypes_registry(self): url = 'mimetypes_registry/manage_main' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_actions(self): url = 'portal_actions/manage_main' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_catalog(self): url = 'portal_catalog/manage_main' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_diff(self): url = 'portal_diff/manage_difftypes' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_form_controller(self): url = 'portal_form_controller/manage_overview' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_historiesstorage(self): url = 'portal_historiesstorage/storageStatistics' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_historyidhandler(self): url = 'portal_historyidhandler/manage_queryObject' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_memberdata(self): url = 'portal_memberdata/manage_overview' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_membership(self): url = 'portal_membership/manage_mapRoles' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_modifier(self): url = 'portal_modifier/manage_main' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_properties(self): url = 'portal_properties/manage_main' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_purgepolicy(self): url = 'portal_purgepolicy/manage_propertiesForm' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_referencefactories(self): url = 'portal_referencefactories/manage_main' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_registration(self): url = 'portal_registration/manage_overview' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_repository(self): url = 'portal_repository/manage_owner' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_resources(self): url = 'portal_resources/manage_main' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_setup(self): url = 'portal_setup/manage_main' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_skins(self): url = 'portal_skins/manage_main' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_transforms(self): url = 'portal_transforms/manage_main' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_types(self): url = 'portal_types/manage_main' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_uidannotation(self): url = 'portal_uidannotation/manage_propertiesForm' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_uidhandler(self): url = 'portal_uidhandler/manage_queryObject' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_view_customizations(self): url = 'portal_view_customizations/registrations.html' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_portal_workflow(self): url = 'portal_workflow/manage_main' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_RAMCache(self): url = 'RAMCache/manage_main' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_ResourceRegistryCache(self): url = 'ResourceRegistryCache/manage_main' view = self.portal.restrictedTraverse(url) - self.assertTrue(view(), msg='{0} is broken'.format(url)) + self.assertTrue(view(), msg=f'{url} is broken') def test_manage_access(self): """manage_access cannot be travesed to directly diff --git a/Products/CMFPlone/tests/utils.py b/Products/CMFPlone/tests/utils.py index 3dbefe12b9..61b740cb3a 100644 --- a/Products/CMFPlone/tests/utils.py +++ b/Products/CMFPlone/tests/utils.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from persistent.list import PersistentList import re diff --git a/Products/CMFPlone/traversal.py b/Products/CMFPlone/traversal.py index 6afe23ce4f..ebeb4a9120 100644 --- a/Products/CMFPlone/traversal.py +++ b/Products/CMFPlone/traversal.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.resource.traversal import ResourceTraverser from zope.component import queryUtility from plone.resource.interfaces import IResourceDirectory @@ -31,7 +30,7 @@ def traverse(self, name, remaining): # in case its not a request get the default one req = getRequest() if not req or 'PATH_INFO' not in req.environ: - return super(PloneBundlesTraverser, self).traverse(name, remaining) + return super().traverse(name, remaining) resource_path = req.environ['PATH_INFO'].split('++plone++')[-1] resource_name, resource_filepath = resource_path.split('/', 1) @@ -52,7 +51,7 @@ def traverse(self, name, remaining): directory = container[resource_name] if resource_filepath in directory: return directory - return super(PloneBundlesTraverser, self).traverse(name, remaining) + return super().traverse(name, remaining) @implementer(IZopeAwareEngine) diff --git a/Products/CMFPlone/unicodeconflictresolver.py b/Products/CMFPlone/unicodeconflictresolver.py index 0f31966a72..cdea9bc71c 100644 --- a/Products/CMFPlone/unicodeconflictresolver.py +++ b/Products/CMFPlone/unicodeconflictresolver.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.interface import implementer from Products.PageTemplates.interfaces import IUnicodeEncodingConflictResolver @@ -6,7 +5,7 @@ @implementer(IUnicodeEncodingConflictResolver) -class UTF8EncodingConflictResolver(object): +class UTF8EncodingConflictResolver: """This resolver tries to decode a string from utf-8 and replaces it otherwise but logs a warning. """ diff --git a/Products/CMFPlone/utils.py b/Products/CMFPlone/utils.py index 210d8fbe77..0e011246f8 100644 --- a/Products/CMFPlone/utils.py +++ b/Products/CMFPlone/utils.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import print_function from AccessControl import ClassSecurityInfo from AccessControl import getSecurityManager from AccessControl import ModuleSecurityInfo @@ -245,7 +243,7 @@ def normalizeString(text, context=None, encoding=None): return queryUtility(IIDNormalizer).normalize(text) -class RealIndexIterator(object): +class RealIndexIterator: """The 'real' version of the IndexIterator class, that's actually used to generate unique indexes. """ @@ -281,18 +279,18 @@ def getIcon(self, context, path): icon_path = path try: icon = ImageFile(path, pack.__dict__) - except (IOError, OSError): + except OSError: # Fallback: # Assume path is relative to CMFPlone directory path = abspath(join(PACKAGE_HOME, path)) try: icon = ImageFile(path, pack.__dict__) - except (IOError, OSError): + except OSError: # if there is some problem loading the fancy image # from the tool then tell someone about it - log(('The icon for the product: %s which was set to: %s, ' + log('The icon for the product: %s which was set to: %s, ' 'was not found. Using the default.' % - (self.product_name, icon_path))) + (self.product_name, icon_path)) return icon def initialize(self, context): @@ -311,7 +309,7 @@ def initialize(self, context): # Icon was not found return icon.__roles__ = None - tool.icon = 'misc_/%s/%s' % (self.product_name, name) + tool.icon = f'misc_/{self.product_name}/{name}' misc = OFS.misc_.misc_ Misc = OFS.misc_.Misc_ if not hasattr(misc, pid): @@ -654,7 +652,7 @@ def set_own_login_name(member, loginname): def ajax_load_url(url): if url and 'ajax_load' not in url: sep = '?' in url and '&' or '?' # url parameter seperator - url = '%s%sajax_load=1' % (url, sep) + url = f'{url}{sep}ajax_load=1' return url @@ -668,8 +666,8 @@ def validate_json(value): json.loads(value) except ValueError as exc: class JSONError(schema.ValidationError): - __doc__ = _(u"Must be empty or a valid JSON-formatted " - u"configuration – ${message}.", mapping={ + __doc__ = _("Must be empty or a valid JSON-formatted " + "configuration – ${message}.", mapping={ 'message': str(exc)}) raise JSONError(value) @@ -838,7 +836,7 @@ def human_readable_size(size): for c in SIZE_ORDER: if size // SIZE_CONST[c] > 0: break - return '%.1f %s' % (float(size / float(SIZE_CONST[c])), c) + return '{:.1f} {}'.format(float(size / float(SIZE_CONST[c])), c) return size @@ -883,7 +881,7 @@ def xlate(message): # make sure we have an id if one is required if not id: if required: - return xlate(_(u'Please enter a name.')) + return xlate(_('Please enter a name.')) # Id is not required and no alternative was specified, so assume the # object's id will be context.getId(). We still should check to make @@ -901,7 +899,7 @@ def xlate(message): # check for reserved names if id in ('login', 'layout', 'plone', 'zip', 'properties', ): return xlate( - _(u'${name} is reserved.', + _('${name} is reserved.', mapping={'name': id})) # check for bad characters @@ -912,17 +910,17 @@ def xlate(message): bad_chars = ''.join(bad_chars).decode('utf-8') decoded_id = id.decode('utf-8') return xlate( - _(u'${name} is not a legal name. The following characters are ' - u'invalid: ${characters}', - mapping={u'name': decoded_id, u'characters': bad_chars})) + _('${name} is not a legal name. The following characters are ' + 'invalid: ${characters}', + mapping={'name': decoded_id, 'characters': bad_chars})) # check for a catalog index portal_catalog = getToolByName(context, 'portal_catalog', None) if portal_catalog is not None: if id in list(portal_catalog.indexes()) + list(portal_catalog.schema()): return xlate( - _(u'${name} is reserved.', - mapping={u'name': id})) + _('${name} is reserved.', + mapping={'name': id})) # id is good; decide if we should check for id collisions portal_factory = getToolByName(context, 'portal_factory', None) @@ -958,8 +956,8 @@ def xlate(message): except Unauthorized: # There is a permission problem. Safe to assume we can't use this id. return xlate( - _(u'${name} is reserved.', - mapping={u'name': id})) + _('${name} is reserved.', + mapping={'name': id})) if result is not None: result = xlate(result, ) return result @@ -993,8 +991,8 @@ def _check_for_collision(contained_by, id, **kwargs): existing_obj = getattr(contained_by, id, None) if base_hasattr(existing_obj, 'portal_type'): return _( - u'There is already an item named ${name} in this folder.', - mapping={u'name': id}) + 'There is already an item named ${name} in this folder.', + mapping={'name': id}) if base_hasattr(contained_by, 'checkIdAvailable'): # This used to be called from the check_id skin script, @@ -1002,7 +1000,7 @@ def _check_for_collision(contained_by, id, **kwargs): # and the code would catch the Unauthorized exception. if secman.checkPermission(AddPortalContent, contained_by): if not contained_by.checkIdAvailable(id): - return _(u'${name} is reserved.', mapping={u'name': id}) + return _('${name} is reserved.', mapping={'name': id}) # containers may implement this hook to further restrict ids if base_hasattr(contained_by, 'checkValidId'): @@ -1011,7 +1009,7 @@ def _check_for_collision(contained_by, id, **kwargs): except ConflictError: raise except: # noqa: E722 - return _(u'${name} is reserved.', mapping={u'name': id}) + return _('${name} is reserved.', mapping={'name': id}) # make sure we don't collide with any parent method aliases plone_utils = getToolByName(contained_by, 'plone_utils', None) @@ -1022,7 +1020,7 @@ def _check_for_collision(contained_by, id, **kwargs): aliases = plone_utils.getMethodAliases(parentFti) if aliases is not None: if id in aliases.keys(): - return _(u'${name} is reserved.', mapping={u'name': id}) + return _('${name} is reserved.', mapping={'name': id}) # Lastly, we want to disallow the id of any of the tools in the portal # root, as well as any object that can be acquired via portal_skins. @@ -1052,4 +1050,4 @@ def _check_for_collision(contained_by, id, **kwargs): return # but not other things if getattr(portal, id, None) is not None: - return _(u'${name} is reserved.', mapping={u'name': id}) + return _('${name} is reserved.', mapping={'name': id}) diff --git a/Products/CMFPlone/workflow.py b/Products/CMFPlone/workflow.py index 912fc10391..ac939662d3 100644 --- a/Products/CMFPlone/workflow.py +++ b/Products/CMFPlone/workflow.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.interface import Interface, implementer from zope.component import adapter from Acquisition import aq_base diff --git a/Products/__init__.py b/Products/__init__.py index 85880ef0d0..f48ad10528 100644 --- a/Products/__init__.py +++ b/Products/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages try: __import__('pkg_resources').declare_namespace(__name__) diff --git a/news/3185.misc b/news/3185.misc new file mode 100644 index 0000000000..c5811901a6 --- /dev/null +++ b/news/3185.misc @@ -0,0 +1,3 @@ +Applied: `find . -name "*.py" |grep -v skins|xargs pyupgrade --py36-plus --py3-only`. +This auto-rewrites Python 2.7 specific syntax and code to Python 3.6+. +[jensens] diff --git a/setup.py b/setup.py index bcc2499d51..88eb125aaa 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from setuptools import setup from setuptools import find_packages From 6d73df3f53c38b83e1335653e829d8b6349367a2 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Wed, 30 Sep 2020 15:41:11 +0200 Subject: [PATCH 104/127] Fixed news snippet extension. [ci skip] --- news/{3185.misc => 3185.bugfix} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename news/{3185.misc => 3185.bugfix} (100%) diff --git a/news/3185.misc b/news/3185.bugfix similarity index 100% rename from news/3185.misc rename to news/3185.bugfix From a5c6417186f6dc623a65d76ae0720480f27ec740 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Wed, 14 Feb 2018 00:54:25 +0100 Subject: [PATCH 105/127] Removed our CMFQuickInstallerTool code completely. --- Products/CMFPlone/MigrationTool.py | 3 +- Products/CMFPlone/__init__.py | 2 - .../controlpanel/browser/configure.zcml | 5 +- .../controlpanel/browser/quickinstaller.py | 153 +----------------- Products/CMFPlone/factory.py | 1 - Products/CMFPlone/interfaces/installable.py | 2 - .../CMFPlone/profiles/default/toolset.xml | 2 - Products/CMFPlone/setuphandlers.py | 1 - Products/CMFPlone/tests/testSiteAdminRole.py | 2 - news/1775.breaking | 3 + setup.py | 1 - 11 files changed, 8 insertions(+), 167 deletions(-) create mode 100644 news/1775.breaking diff --git a/Products/CMFPlone/MigrationTool.py b/Products/CMFPlone/MigrationTool.py index e3f6fac9d3..a7bf17b886 100644 --- a/Products/CMFPlone/MigrationTool.py +++ b/Products/CMFPlone/MigrationTool.py @@ -27,8 +27,7 @@ class Addon: """A profile or product. This is meant for core Plone packages, especially packages that - are marked as not installable (INonInstallable from - CMFQuickInstallerTool). These are packages that an admin should + are marked as not installable. These are packages that an admin should not activate, deactivate or upgrade manually, but that should be handled by Plone. diff --git a/Products/CMFPlone/__init__.py b/Products/CMFPlone/__init__.py index b78c455324..1a53d1856c 100644 --- a/Products/CMFPlone/__init__.py +++ b/Products/CMFPlone/__init__.py @@ -142,7 +142,6 @@ def initialize(context): from Products.CMFPlone import TypesTool from Products.CMFPlone import CatalogTool from Products.CMFPlone import SkinsTool - from Products.CMFPlone import QuickInstallerTool from Products.CMFPlone import TranslationServiceTool tools = ( @@ -158,7 +157,6 @@ def initialize(context): TypesTool.TypesTool, CatalogTool.CatalogTool, SkinsTool.SkinsTool, - QuickInstallerTool.QuickInstallerTool, TranslationServiceTool.TranslationServiceTool, ) diff --git a/Products/CMFPlone/controlpanel/browser/configure.zcml b/Products/CMFPlone/controlpanel/browser/configure.zcml index a6f3382c06..f47f2877c3 100644 --- a/Products/CMFPlone/controlpanel/browser/configure.zcml +++ b/Products/CMFPlone/controlpanel/browser/configure.zcml @@ -210,11 +210,10 @@ template="usergroups_groupdetails.pt" /> - + + It is the replacement for any use of the portal_quickinstaller. -->