-
-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Branch: refs/heads/master Date: 2019-02-12T20:45:42+01:00 Author: Maurits van Rees (mauritsvanrees) <maurits@vanrees.org> Commit: plone/plone.app.upgrade@94e8413 Fixed permission error while removing old resource registries. Fixes plone/plone.app.upgrade#197 Files changed: A news/197.bugfix M plone/app/upgrade/v52/betas.py Repository: plone.app.upgrade Branch: refs/heads/master Date: 2019-02-19T11:57:28+01:00 Author: Jens W. Klein (jensens) <jk@kleinundpartner.at> Commit: plone/plone.app.upgrade@2659b44 Merge pull request #198 from plone/maurits-fix-remove_legacy_resource_registries Fixed permission error while removing old resource registries. Files changed: A news/197.bugfix M plone/app/upgrade/v52/betas.py
- Loading branch information
Showing
1 changed file
with
28 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,36 @@ | ||
Repository: plone.api | ||
Repository: plone.app.upgrade | ||
|
||
|
||
Branch: refs/heads/master | ||
Date: 2019-02-14T10:12:07+01:00 | ||
Author: Harald Friessnegger (frisi) <friessnegger@lovelysystems.com> | ||
Commit: https://github.com/plone/plone.api/commit/548aafea844325a63399da08a2229795dd2e8c44 | ||
Date: 2019-02-12T20:45:42+01:00 | ||
Author: Maurits van Rees (mauritsvanrees) <maurits@vanrees.org> | ||
Commit: https://github.com/plone/plone.app.upgrade/commit/94e8413d8e5be5a909addd73d94f0bd0d302081b | ||
|
||
fix content.find(object_provides) for 'and' query (#427) | ||
Fixed permission error while removing old resource registries. | ||
|
||
this fixes https://github.com/plone/plone.api/issues/426 | ||
|
||
* Fixed flake8 warning W605 invalid escape sequence. | ||
|
||
* Flake8: fixed W504 line break after binary operator. | ||
|
||
And ignore its reverse: W503 line break before binary operator. | ||
See https://github.com/plone/plone.api/pull/427#issuecomment-462925931 | ||
Fixes https://github.com/plone/plone.app.upgrade/issues/197 | ||
|
||
Files changed: | ||
A news/426.bugfix | ||
M src/plone/api/content.py | ||
M src/plone/api/portal.py | ||
M src/plone/api/tests/test_content.py | ||
M src/plone/api/tests/test_doctests.py | ||
M src/plone/api/tests/test_env.py | ||
M tox.ini | ||
|
||
b'diff --git a/news/426.bugfix b/news/426.bugfix\nnew file mode 100644\nindex 0000000..9c806a9\n--- /dev/null\n+++ b/news/426.bugfix\n@@ -0,0 +1,2 @@\n+Fix querying ``object_provides`` for multiple interfaces using \'and\' operator.\n+[fRiSi]\ndiff --git a/src/plone/api/content.py b/src/plone/api/content.py\nindex f11a299..9931599 100644\n--- a/src/plone/api/content.py\n+++ b/src/plone/api/content.py\n@@ -586,6 +586,28 @@ def get_uuid(obj=None):\n return IUUID(obj)\n \n \n+def _parse_object_provides_query(query):\n+ """Create a query for the object_provides index.\n+\n+ :param query: [required]\n+ :type query: Single (or list of) Interface or Identifier or a KeywordIndex\n+ query for multiple values\n+ (eg. `{\'query\': [Iface1, Iface2], \'operator\': \'or\'}`)\n+ """\n+ operator = \'or\'\n+ ifaces = query\n+ if isinstance(query, dict):\n+ operator = query.get(\'operator\', operator)\n+ ifaces = query.get(\'query\', [])\n+ elif not isinstance(query, (list, tuple)):\n+ ifaces = [query]\n+\n+ return {\n+ \'query\': [getattr(x, \'__identifier__\', x) for x in ifaces],\n+ \'operator\': operator,\n+ }\n+\n+\n def find(context=None, depth=None, **kwargs):\n """Find content in the portal.\n \n@@ -631,10 +653,17 @@ def find(context=None, depth=None, **kwargs):\n >>> find(path={\'query\': \'/plone/about/team\', \'depth\': 1})\n \n The `object_provides` index/argument allows Interface objects as well as\n- identifiers.\n+ identifiers. It also supports querying multiple interfaces combined with\n+ `and` or `or`.\n >>> find(object_provides=IATDocument)\n - or -\n >>> find(object_provides=IATDocument.__identifier__)\n+ - or -\n+ >>> find(object_provides={\n+ ... \'query\': [IATFolder, INavigationRoot],\n+ ... \'operator\': \'and\',\n+ ... })\n+\n \n An empty resultset is returned if no valid indexes are queried.\n >>> len(find())\n@@ -668,14 +697,11 @@ def find(context=None, depth=None, **kwargs):\n if context is not None:\n query[\'path\'][\'query\'] = \'/\'.join(context.getPhysicalPath())\n \n- # Convert interfaces to their identifiers\n- object_provides = query.get(\'object_provides\', [])\n- if object_provides:\n- if not isinstance(object_provides, (list, tuple)):\n- object_provides = [object_provides]\n- query[\'object_provides\'] = [\n- getattr(x, \'__identifier__\', x) for x in object_provides\n- ]\n+ # Convert interfaces to their identifiers and also allow to query\n+ # multiple values using {\'query:[], \'operator\':\'and|or\'}\n+ obj_provides = query.get(\'object_provides\', [])\n+ if obj_provides:\n+ query[\'object_provides\'] = _parse_object_provides_query(obj_provides)\n \n # Make sure we don\'t dump the whole catalog.\n catalog = portal.get_tool(\'portal_catalog\')\ndiff --git a/src/plone/api/portal.py b/src/plone/api/portal.py\nindex 8d1791b..0a3e477 100644\n--- a/src/plone/api/portal.py\n+++ b/src/plone/api/portal.py\n@@ -42,13 +42,13 @@\n if not PrintingMailHost:\n PRINTINGMAILHOST_ENABLED = False\n elif (\n- PrintingMailHost.ENABLED is not None and\n- PrintingMailHost.ENABLED.lower() in PrintingMailHost.TRUISMS\n+ PrintingMailHost.ENABLED is not None\n+ and PrintingMailHost.ENABLED.lower() in PrintingMailHost.TRUISMS\n ):\n PRINTINGMAILHOST_ENABLED = True\n elif (\n- PrintingMailHost.ENABLED is None and\n- PrintingMailHost.DevelopmentMode is True\n+ PrintingMailHost.ENABLED is None\n+ and PrintingMailHost.DevelopmentMode is True\n ):\n PRINTINGMAILHOST_ENABLED = True\n else:\ndiff --git a/src/plone/api/tests/test_content.py b/src/plone/api/tests/test_content.py\nindex d575457..795a8c2 100644\n--- a/src/plone/api/tests/test_content.py\n+++ b/src/plone/api/tests/test_content.py\n@@ -8,6 +8,7 @@\n from plone import api\n from plone.api.content import NEW_LINKINTEGRITY\n from plone.api.tests.base import INTEGRATION_TESTING\n+from plone.app.layout.navigation.interfaces import INavigationRoot\n from plone.app.linkintegrity.exceptions import LinkIntegrityNotificationException # NOQA: E501\n from plone.app.textfield import RichTextValue\n from plone.dexterity.interfaces import IDexterityContent\n@@ -21,6 +22,7 @@\n from zope.component import getGlobalSiteManager\n from zope.component import getUtility\n from zope.container.contained import ContainerModifiedEvent\n+from zope.interface import alsoProvides\n from zope.lifecycleevent import IObjectModifiedEvent\n from zope.lifecycleevent import IObjectMovedEvent\n from zope.lifecycleevent import modified\n@@ -503,8 +505,8 @@ def test_move(self):\n \n # Move contact to the same folder (basically a rename)\n nucontact = api.content.move(source=self.contact, id=\'nu-contact\')\n- assert (container[\'about\'][\'nu-contact\'] and\n- container[\'about\'][\'nu-contact\'] == nucontact)\n+ assert (container[\'about\'][\'nu-contact\']\n+ and container[\'about\'][\'nu-contact\'] == nucontact)\n assert \'contact\' not in container[\'about\'].keys()\n \n # Move team page to portal root\n@@ -519,8 +521,8 @@ def test_move(self):\n target=self.about,\n id=\'our-team\',\n )\n- assert (container[\'about\'][\'our-team\'] and\n- container[\'about\'][\'our-team\'] == ourteam)\n+ assert (container[\'about\'][\'our-team\']\n+ and container[\'about\'][\'our-team\'] == ourteam)\n assert \'team\' not in container.keys()\n \n # Test with safe_id option when moving content\n@@ -533,8 +535,8 @@ def test_move(self):\n id=\'link-to-blog\',\n safe_id=True,\n )\n- assert (container[\'about\'][\'link-to-blog-1\'] and\n- container[\'about\'][\'link-to-blog-1\'] == linktoblog1)\n+ assert (container[\'about\'][\'link-to-blog-1\']\n+ and container[\'about\'][\'link-to-blog-1\'] == linktoblog1)\n assert \'link-to-blog\' not in container.keys()\n \n api.content.move(source=self.conference, id=\'conference-renamed\')\n@@ -546,8 +548,8 @@ def test_move(self):\n target=container.events,\n )\n assert (\n- container[\'events\'][\'about\'] and\n- container[\'events\'][\'about\'] == about\n+ container[\'events\'][\'about\']\n+ and container[\'events\'][\'about\'] == about\n )\n \n def test_move_no_move_if_target_is_source_parent(self):\n@@ -591,8 +593,8 @@ def recordEvent(event):\n \n # Rename contact\n nucontact = api.content.rename(obj=self.contact, new_id=\'nu-contact\')\n- assert (container[\'about\'][\'nu-contact\'] and\n- container[\'about\'][\'nu-contact\'] == nucontact)\n+ assert (container[\'about\'][\'nu-contact\']\n+ and container[\'about\'][\'nu-contact\'] == nucontact)\n assert \'contact\' not in container[\'about\'].keys()\n \n if six.PY2:\n@@ -620,8 +622,8 @@ def recordEvent(event):\n new_id=\'link-to-blog\',\n safe_id=True,\n )\n- assert (container[\'about\'][\'link-to-blog-1\'] and\n- container[\'about\'][\'link-to-blog-1\'] == linktoblog1)\n+ assert (container[\'about\'][\'link-to-blog-1\']\n+ and container[\'about\'][\'link-to-blog-1\'] == linktoblog1)\n assert \'link-to-blog\' not in container.keys()\n \n # Rename to existing id\n@@ -639,8 +641,8 @@ def recordEvent(event):\n new_id=\'link-to-blog-1\',\n safe_id=True,\n )\n- assert (container[\'about\'][\'link-to-blog-1-1\'] and\n- container[\'about\'][\'link-to-blog-1-1\'] == linktoblog11)\n+ assert (container[\'about\'][\'link-to-blog-1-1\']\n+ and container[\'about\'][\'link-to-blog-1-1\'] == linktoblog11)\n assert \'link-to-blog\' not in container.keys()\n \n def test_rename_same_id(self):\n@@ -686,8 +688,8 @@ def test_copy(self):\n team = api.content.copy(source=self.team, target=container)\n assert container[\'team\'] and container[\'team\'] == team\n assert (\n- container[\'about\'][\'team\'] and\n- container[\'about\'][\'team\'] != team\n+ container[\'about\'][\'team\']\n+ and container[\'about\'][\'team\'] != team\n ) # old content still available\n \n # When copying objects we can change the id\n@@ -697,8 +699,8 @@ def test_copy(self):\n id=\'our-team\',\n )\n assert(\n- container[\'about\'][\'our-team\'] and\n- container[\'about\'][\'our-team\'] == ourteam\n+ container[\'about\'][\'our-team\']\n+ and container[\'about\'][\'our-team\'] == ourteam\n )\n \n # When copying whithout target parameter should take source parent\n@@ -717,8 +719,8 @@ def test_copy(self):\n safe_id=True,\n )\n assert(\n- container[\'about\'][\'link-to-blog-1\'] and\n- container[\'about\'][\'link-to-blog-1\'] == linktoblog1\n+ container[\'about\'][\'link-to-blog-1\']\n+ and container[\'about\'][\'link-to-blog-1\'] == linktoblog1\n )\n \n # Copy folderish content under target\n@@ -727,8 +729,8 @@ def test_copy(self):\n target=container.events,\n )\n assert(\n- container[\'events\'][\'about\'] and\n- container[\'events\'][\'about\'] == about\n+ container[\'events\'][\'about\']\n+ and container[\'events\'][\'about\'] == about\n )\n \n # When copying with safe_id=True, the prior created item should not be\n@@ -1020,6 +1022,33 @@ def test_find_interface(self):\n \n self.assertEqual(by_identifier, by_interface)\n \n+ def test_find_interface_dict(self):\n+ # Find documents by interface combined with \'and\'\n+\n+ alsoProvides(self.portal.events, INavigationRoot)\n+ self.portal.events.reindexObject(idxs=[\'object_provides\'])\n+\n+ # standard catalog query using identifiers\n+ brains = api.content.find(\n+ object_provides={\n+ \'query\': [\n+ IContentish.__identifier__,\n+ INavigationRoot.__identifier__,\n+ ],\n+ \'operator\': \'and\',\n+ },\n+ )\n+ self.assertEqual(len(brains), 1)\n+\n+ # plone.api query using interfaces\n+ brains = api.content.find(\n+ object_provides={\n+ \'query\': [IContentish, INavigationRoot],\n+ \'operator\': \'and\',\n+ },\n+ )\n+ self.assertEqual(len(brains), 1)\n+\n def test_find_dict(self):\n # Pass arguments using dict\n path = \'/\'.join(self.portal.about.getPhysicalPath())\n@@ -1056,6 +1085,63 @@ def test_find_dict(self):\n documents = api.content.find(**query)\n self.assertEqual(len(documents), 0)\n \n+ def test_find_parse_object_provides_query(self):\n+\n+ parse = api.content._parse_object_provides_query\n+\n+ # single interface\n+ self.assertDictEqual(\n+ parse(IContentish),\n+ {\n+ \'query\': [IContentish.__identifier__],\n+ \'operator\': \'or\',\n+ },\n+ )\n+ # single identifier\n+ self.assertDictEqual(\n+ parse(IContentish.__identifier__),\n+ {\n+ \'query\': [IContentish.__identifier__],\n+ \'operator\': \'or\',\n+ },\n+ )\n+ # multiple interfaces/identifiers (mixed as list)\n+ self.assertDictEqual(\n+ parse([INavigationRoot, IContentish.__identifier__]),\n+ {\n+ \'query\': [\n+ INavigationRoot.__identifier__,\n+ IContentish.__identifier__,\n+ ],\n+ \'operator\': \'or\',\n+ },\n+ )\n+ # multiple interfaces/identifiers (mixed as tuple)\n+ self.assertDictEqual(\n+ parse((INavigationRoot, IContentish.__identifier__)),\n+ {\n+ \'query\': [\n+ INavigationRoot.__identifier__,\n+ IContentish.__identifier__,\n+ ],\n+ \'operator\': \'or\',\n+ },\n+ )\n+ # full blown query - interfaces/identifiers mixed\n+ self.assertDictEqual(\n+ parse({\n+ \'query\': [INavigationRoot, IContentish.__identifier__],\n+ \'operator\': \'and\',\n+ }),\n+ {\n+ \'query\': [\n+ INavigationRoot.__identifier__,\n+ IContentish.__identifier__,\n+ ],\n+ \'operator\': \'and\',\n+ },\n+ )\n+\n def test_get_state(self):\n """Test retrieving the workflow state of a content item."""\n \ndiff --git a/src/plone/api/tests/test_doctests.py b/src/plone/api/tests/test_doctests.py\nindex c946d40..c95b3f7 100644\n--- a/src/plone/api/tests/test_doctests.py\n+++ b/src/plone/api/tests/test_doctests.py\n@@ -32,10 +32,10 @@\n HAS_PA_CONTENTTYPES = True\n \n FLAGS = (\n- doctest.NORMALIZE_WHITESPACE |\n- doctest.ELLIPSIS |\n- doctest.REPORT_NDIFF |\n- doctest.REPORT_ONLY_FIRST_FAILURE\n+ doctest.NORMALIZE_WHITESPACE\n+ | doctest.ELLIPSIS\n+ | doctest.REPORT_NDIFF\n+ | doctest.REPORT_ONLY_FIRST_FAILURE\n )\n \n CHECKER = renormalizing.RENormalizing([\ndiff --git a/src/plone/api/tests/test_env.py b/src/plone/api/tests/test_env.py\nindex bef8168..49d5cc9 100644\n--- a/src/plone/api/tests/test_env.py\n+++ b/src/plone/api/tests/test_env.py\n@@ -25,7 +25,7 @@ class ExampleException(Exception):\n # \'X.Y\' or \'X.Y.Z\' or \'X.Y.Z.A\'\n # It could also include a package status id (Alpha, Beta or RC).\n # When run against coredev, we may have a .devN suffix as well.\n-version_regexp = \'^(\\d+(\\.\\d+){1,3})(a\\d+|b\\d+|rc\\d+)?(\\.dev\\d)?$\'\n+version_regexp = r\'^(\\d+(\\.\\d+){1,3})(a\\d+|b\\d+|rc\\d+)?(\\.dev\\d)?$\'\n \n \n class HasProtectedMethods(SimpleItem):\ndiff --git a/tox.ini b/tox.ini\nindex 631d453..71dbccb 100644\n--- a/tox.ini\n+++ b/tox.ini\n@@ -79,8 +79,8 @@ deps =\n \n commands =\n mkdir -p {toxinidir}/reports/flake8\n- - flake8 --format=html --htmldir={toxinidir}/reports/flake8 src setup.py\n- flake8 src setup.py\n+ - flake8 --ignore=W503 --format=html --htmldir={toxinidir}/reports/flake8 src setup.py\n+ flake8 --ignore=W503 src setup.py\n \n whitelist_externals =\n mkdir\n' | ||
A news/197.bugfix | ||
M plone/app/upgrade/v52/betas.py | ||
|
||
b'diff --git a/news/197.bugfix b/news/197.bugfix\nnew file mode 100644\nindex 00000000..4603befd\n--- /dev/null\n+++ b/news/197.bugfix\n@@ -0,0 +1,2 @@\n+Fixed permission error while removing old resource registries.\n+[maurits]\ndiff --git a/plone/app/upgrade/v52/betas.py b/plone/app/upgrade/v52/betas.py\nindex 925ef0e9..8ba2c9fc 100644\n--- a/plone/app/upgrade/v52/betas.py\n+++ b/plone/app/upgrade/v52/betas.py\n@@ -43,9 +43,10 @@ def remove_legacy_resource_registries(context):\n ]\n \n # remove obsolete tools\n- tools = [t for t in tools_to_remove if t in portal]\n- if tools:\n- portal.manage_delObjects(tools)\n+ for tool in tools_to_remove:\n+ if tool not in portal:\n+ continue\n+ portal._delObject(tool)\n \n cleanUpToolRegistry(context)\n \n' | ||
|
||
Repository: plone.app.upgrade | ||
|
||
|
||
Branch: refs/heads/master | ||
Date: 2019-02-19T11:57:28+01:00 | ||
Author: Jens W. Klein (jensens) <jk@kleinundpartner.at> | ||
Commit: https://github.com/plone/plone.app.upgrade/commit/2659b4470ca43530c02d2d765cd37050c6510926 | ||
|
||
Merge pull request #198 from plone/maurits-fix-remove_legacy_resource_registries | ||
|
||
Fixed permission error while removing old resource registries. | ||
|
||
Files changed: | ||
A news/197.bugfix | ||
M plone/app/upgrade/v52/betas.py | ||
|
||
b'diff --git a/news/197.bugfix b/news/197.bugfix\nnew file mode 100644\nindex 00000000..4603befd\n--- /dev/null\n+++ b/news/197.bugfix\n@@ -0,0 +1,2 @@\n+Fixed permission error while removing old resource registries.\n+[maurits]\ndiff --git a/plone/app/upgrade/v52/betas.py b/plone/app/upgrade/v52/betas.py\nindex 925ef0e9..8ba2c9fc 100644\n--- a/plone/app/upgrade/v52/betas.py\n+++ b/plone/app/upgrade/v52/betas.py\n@@ -43,9 +43,10 @@ def remove_legacy_resource_registries(context):\n ]\n \n # remove obsolete tools\n- tools = [t for t in tools_to_remove if t in portal]\n- if tools:\n- portal.manage_delObjects(tools)\n+ for tool in tools_to_remove:\n+ if tool not in portal:\n+ continue\n+ portal._delObject(tool)\n \n cleanUpToolRegistry(context)\n \n' | ||
|