summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Madden <jamadden@gmail.com>2020-03-23 10:31:23 -0500
committerGitHub <noreply@github.com>2020-03-23 10:31:23 -0500
commit6c99bcbc4472a8e1407f96f78c4764678a45d875 (patch)
tree47d82b9df69f716cfb911c7f119b69082f533d16
parent4382cde773a27d7699c74ad0cda3a9268da9e302 (diff)
parent027ce52cc45d066ba25809473ba21beb2f8f1bf3 (diff)
downloadzope-security-6c99bcbc4472a8e1407f96f78c4764678a45d875.tar.gz
Merge pull request #73 from zopefoundation/consistent-interfaces
Ensure all objects have consistent interface resolution orders.
-rw-r--r--.gitignore1
-rw-r--r--.travis.yml1
-rw-r--r--CHANGES.rst6
-rw-r--r--setup.py2
-rw-r--r--src/zope/security/_compat.py23
-rw-r--r--src/zope/security/checker.py3
-rw-r--r--src/zope/security/zcml.py9
-rw-r--r--tox.ini24
8 files changed, 39 insertions, 30 deletions
diff --git a/.gitignore b/.gitignore
index 095537c..c7adc9b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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)
diff --git a/setup.py b/setup.py
index 0830708..8f80e3b 100644
--- a/setup.py
+++ b/setup.py
@@ -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)
diff --git a/tox.ini b/tox.ini
index 2e59a39..1a7a0ee 100644
--- a/tox.ini
+++ b/tox.ini
@@ -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