Skip to content

Commit

Permalink
Merge pull request #36 from zopefoundation/issue34redux
Browse files Browse the repository at this point in the history
Ensure all objects have consistent resolution errors
  • Loading branch information
jamadden committed Apr 1, 2020
2 parents 1cd4079 + 1523b1c commit e4b3799
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 5 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ language: python

env:
global:
ZOPE_INTERFACE_STRICT_IRO: 1
TWINE_USERNAME: zope.wheelbuilder
TWINE_PASSWORD:
secure: "G1ORcUIV439Iws2toGhxPvYvQKQt6L1wyXfIMspz2xtjJvQ2D1XrqK8dRYyQ0YaGLY/OAI8BrEdTp/l7jrhiG0gXMeAs0k1KFbp7ATahcVT8rWOzvcLGMAiYRVloQ3rz5x5HjMm0CWpDjo1MAeJMmesyq8RlmYzaMu4aw1mBd/Y="
Expand Down
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@

- Drop support for the deprecated ``python setup.py test`` command.

- Ensure all objects have consistent interface resolution orders. This
may slightly change the order of interfaces for ``ContainedProxy``
objects. See `issue 34 <https://github.com/zopefoundation/zope.container/issues/34>`_.

4.3.0 (2019-11-11)
==================
Expand Down
12 changes: 10 additions & 2 deletions src/zope/container/_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,16 @@ def find_impl():
if static:
v = staticmethod(v)
setattr(py_impl, k, v)
# copy the interface declarations.
# copy the interface declarations, being careful not
# to redeclare interfaces already implemented (through
# inheritance usually)
implements = list(implementedBy(py_impl))
if implements:
implemented_by_c = implementedBy(c_impl)
implements = [
iface
for iface in implements
if not implemented_by_c.isOrExtends(iface)
]
if implements: # pragma: no cover
classImplements(c_impl, *implements)
return c_impl
12 changes: 9 additions & 3 deletions src/zope/container/contained.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@

import zope.component

import zope.interface.declarations
from zope.interface import providedBy, Interface
from zope.interface import providedBy
from zope.interface import Interface
from zope.interface import implementedBy
from zope.interface.declarations import getObjectSpecification
from zope.interface.declarations import Provides

Expand Down Expand Up @@ -902,12 +903,13 @@ class DecoratorSpecificationDescriptor(
When we decorate objects, what order should the interfaces come in? One
could argue that decorators are less specific, so they should come last.
This is subject to respecting the C3 resolution order, of course.
>>> [interface.getName() for interface in list(providedBy(D1(x)))]
['I4', 'I3', 'I1', 'IContained', 'IPersistent']
>>> [interface.getName() for interface in list(providedBy(D2(D1(x))))]
['I4', 'I3', 'I1', 'IContained', 'IPersistent', 'I2']
['I4', 'I3', 'I1', 'I2', 'IContained', 'IPersistent']
"""
def __get__(self, inst, cls=None):
if inst is None: # pragma: no cover (Not sure how we can get here)
Expand All @@ -918,6 +920,10 @@ def __get__(self, inst, cls=None):
# Use type rather than __class__ because inst is a proxy and
# will return the proxied object's class.
cls = type(inst)
implemented_by_cls = implementedBy(cls)
for iface in list(provided):
if implemented_by_cls.isOrExtends(iface):
provided = provided - iface
return Provides(cls, provided)


Expand Down
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ deps =
coverage
setenv =
PURE_PYTHON=0
ZOPE_INTERFACE_STRICT_IRO=1
pure: PURE_PYTHON=1
pypy: PURE_PYTHON=1
pypy3: PURE_PYTHON=1
Expand Down

0 comments on commit e4b3799

Please sign in to comment.