diff options
author | Jason Madden <jamadden@gmail.com> | 2020-03-23 08:15:47 -0500 |
---|---|---|
committer | Jason Madden <jamadden@gmail.com> | 2020-03-23 08:15:47 -0500 |
commit | 027ce52cc45d066ba25809473ba21beb2f8f1bf3 (patch) | |
tree | 47d82b9df69f716cfb911c7f119b69082f533d16 | |
parent | 4382cde773a27d7699c74ad0cda3a9268da9e302 (diff) | |
download | zope-security-027ce52cc45d066ba25809473ba21beb2f8f1bf3.tar.gz |
Ensure all objects have consistent interface resolution orders.
Fixes #71
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | .travis.yml | 1 | ||||
-rw-r--r-- | CHANGES.rst | 6 | ||||
-rw-r--r-- | setup.py | 2 | ||||
-rw-r--r-- | src/zope/security/_compat.py | 23 | ||||
-rw-r--r-- | src/zope/security/checker.py | 3 | ||||
-rw-r--r-- | src/zope/security/zcml.py | 9 | ||||
-rw-r--r-- | tox.ini | 24 |
8 files changed, 39 insertions, 30 deletions
@@ -1,4 +1,5 @@ *.pyc +*.pyo *.so __pycache__ *.egg diff --git a/.travis.yml b/.travis.yml index 75eb8b1..7cb9c7f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ env: TWINE_USERNAME: zope.wheelbuilder TWINE_PASSWORD: secure: "U6CeZtNEPDN3qKXfrLcvHFLrowqNWxmapXLWygZRxKgfR+ypowe1Y0a4kCBEBZKtysbY26MmIkrMV07tEMxny1yUWVCvRvUaQw0Ic3t5CM0R019zjVh9fQUTdWGCwri86Qj/OaeuPeMR0LCr6d9nMSun0GWSWhjOUhkTCdchfQw=" + ZOPE_INTERFACE_STRICT_IRO: 1 python: - 2.7 diff --git a/CHANGES.rst b/CHANGES.rst index cdee135..9f227d7 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,10 +2,12 @@ Changes ========= -5.2.0 (unreleased) +5.1.1 (unreleased) ================== -- Nothing changed yet. +- Ensure all objects have consistent interface resolution orders (if + all dependencies are up-to-date). See `issue 71 + <https://github.com/zopefoundation/zope.security/issues/71>`_. 5.1.0 (2020-02-14) @@ -127,7 +127,7 @@ TESTS_REQUIRE = [ setup(name='zope.security', - version='5.2.0.dev0', + version='5.1.1.dev0', author='Zope Foundation and Contributors', author_email='zope-dev@zope.org', description='Zope Security Framework', diff --git a/src/zope/security/_compat.py b/src/zope/security/_compat.py index 84ac98d..07b3a02 100644 --- a/src/zope/security/_compat.py +++ b/src/zope/security/_compat.py @@ -39,4 +39,25 @@ else: # pragma: no cover PYTHON2 = False -_BLANK = u'' +class implementer_if_needed(object): + # Helper to make sure we don't redundantly implement interfaces + # already inherited. Doing so tends to produce problems with the + # C3 order. Even though here we could easily statically determine + # if we need the interface or not, this is used for clarity, to + # reduce the testing load, and to insulate against changes in + # super classes. + def __init__(self, *ifaces): + self._ifaces = ifaces + + def __call__(self, cls): + from zope.interface import implementedBy + from zope.interface import implementer + + ifaces_needed = [] + implemented = implementedBy(cls) + ifaces_needed = [ + iface + for iface in self._ifaces + if not implemented.isOrExtends(iface) + ] + return implementer(*ifaces_needed)(cls) diff --git a/src/zope/security/checker.py b/src/zope/security/checker.py index 8fbf3ec..2dbc4e1 100644 --- a/src/zope/security/checker.py +++ b/src/zope/security/checker.py @@ -82,6 +82,7 @@ from zope.security._definitions import thread_local from zope.security._compat import CLASS_TYPES from zope.security._compat import PYTHON2 from zope.security._compat import PURE_PYTHON +from zope.security._compat import implementer_if_needed from zope.security.proxy import Proxy from zope.security.proxy import getChecker @@ -503,7 +504,7 @@ if _c_available: _getChecker = _checkers.get -@implementer(IChecker) +@implementer_if_needed(IChecker) class CombinedChecker(Checker): """A checker that combines two other checkers in a logical-or fashion. diff --git a/src/zope/security/zcml.py b/src/zope/security/zcml.py index 52bcf91..473c06e 100644 --- a/src/zope/security/zcml.py +++ b/src/zope/security/zcml.py @@ -18,21 +18,22 @@ __docformat__ = 'restructuredtext' from zope.configuration.fields import GlobalObject from zope.configuration.fields import MessageID from zope.interface import Interface -from zope.interface import implementer from zope.schema import Id from zope.schema.interfaces import IFromUnicode +from zope.security._compat import implementer_if_needed from zope.security.permission import checkPermission from zope.security.management import setSecurityPolicy from zope.security.interfaces import PUBLIC_PERMISSION_NAME as zope_Public -@implementer(IFromUnicode) + +@implementer_if_needed(IFromUnicode) class Permission(Id): r"""This field describes a permission. """ - def fromUnicode(self, u): - u = super(Permission, self).fromUnicode(u) + def fromUnicode(self, value): + u = super(Permission, self).fromUnicode(value) map = getattr(self.context, 'permission_mapping', {}) return map.get(u, u) @@ -13,28 +13,10 @@ extras = test docs deps = - -[testenv:py27-watch] -basepython = - python2.7 -setenv = - PURE_PYTHON = 1 - ZOPE_WATCH_CHECKERS = 1 - PIP_CACHE_DIR = {envdir}/.cache - -[testenv:py37-watch] -basepython = - python3.7 -setenv = - ZOPE_WATCH_CHECKERS = 1 - PIP_CACHE_DIR = {envdir}/.cache - -[testenv:py37-pure] -basepython = - python3.7 setenv = - PURE_PYTHON = 1 - PIP_CACHE_DIR = {envdir}/.cache + ZOPE_INTERFACE_STRICT_IRO = 1 + watch: ZOPE_WATCH_CHECKERS = 1 + pure: PURE_PYTHON = 1 [testenv:coverage] usedevelop = true |