Commit 82101534 authored by Jason Madden's avatar Jason Madden

Add a test and a fix for the __of__ issue @davisagli reported. Only tested...

Add a test and a fix for the __of__ issue @davisagli reported. Only tested under Python2 because I couldn't figure out how to reproduce it under Python 3
parent a27312ab
......@@ -41,7 +41,7 @@ else:
setup(
name='Acquisition',
version='4.2.dev.0',
version='4.2.dev0',
url='https://github.com/zopefoundation/Acquisition',
license='ZPL 2.1',
description="Acquisition is a mechanism that allows objects to obtain "
......
......@@ -28,9 +28,10 @@ _NOT_FOUND = object() # marker
def _has__of__(obj):
"""Check whether an object has an __of__ method for returning itself
in the context of a container."""
# Note specifically this is a type check, not duck typing, or
# we get into cycles
return isinstance(obj, ExtensionClass.Base)
# It is necessary to check both the type (or we get into cycles)
# as well as the presence of the method (or mixins of Base
# post-class-creation as done somewhere in Zope) can fail.
return isinstance(obj, ExtensionClass.Base) and hasattr(type(obj), '__of__')
def _apply_filter(predicate, inst, name, result, extra, orig):
......
......@@ -1766,6 +1766,47 @@ def test_interfaces():
True
"""
if PY2:
# Assigning to __bases__ is difficult under Python 3.
# In this example, you get:
# "TypeError: __bases__ assignment: 'Base' deallocator differs from 'object'"
# I don't know what the workaround is; the old one of using a dummy
# superclass no longer works. See http://bugs.python.org/issue672115
def test_mixin_post_class_definition():
"""
Code in Zope mixes in ExtensionClass.Base to existing
classes after they've been defined.
>>> from ExtensionClass import Base
>>> class Plain(object):
... pass
>>> Plain.__bases__ == (object,)
True
>>> Plain.__bases__ = (Base,)
>>> isinstance(Plain(), Base)
True
Even after they do this, when we request such an object
from an implicit acquiring base, it doesn't come out wrapped:
>>> from Acquisition import Implicit
>>> class I(Implicit):
... pass
>>> root = I()
>>> root.a = I()
>>> root.a.b = Plain()
>>> type(root.a.b) is Plain
True
This is because after the mixin, even though Plain is-a Base,
it doesn't provide the `__of__` method used for wrapping
(that only gets added at class definition time, or in C code):
>>> hasattr(Plain, '__of__')
False
"""
def show(x):
print(showaq(x).strip())
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment