Commit 0018bc9c authored by Jason Madden's avatar Jason Madden

Fix looking up interfaces implemented/providedBy proxies around builtin types (in pure-Python.).

parent 4f3a07f7
......@@ -5,7 +5,11 @@ Changes
------------------
- Made subclasses of ProxyBase properly delegate ``__module__`` to the
wrapped object.
wrapped object. This fixes some ``zope.interface`` lookups under
PyPy.
- Made the pure-Python implementation of ProxyBase properly report the
``zope.interface`` interfaces implemented by builtin types like
``list``. This fixes some ``zope.interface`` lookups under PyPy.
4.1.5 (2015-05-19)
------------------
......
......@@ -21,7 +21,6 @@ import sys
from zope.interface import moduleProvides
from zope.proxy.interfaces import IProxyIntrospection
moduleProvides(IProxyIntrospection)
__all__ = tuple(IProxyIntrospection)
......@@ -56,6 +55,35 @@ def _get_wrapped(self):
"""
return super(AbstractPyProxyBase, self).__getattribute__('_wrapped')
class _EmptyInterfaceDescriptor(object):
"""A descriptor for the attributes used on the class by the
Python implementation of `zope.interface`.
When wrapping builtin types, these descriptors prevent the objects
we find in the AbstractPyProxyBase from being used.
"""
def __get__(self, inst, klass):
raise AttributeError()
def __set__(self, inst, value):
raise TypeError()
def __delete__(self, inst):
pass
def __iter__(self):
return self
def __next__(self):
raise StopIteration()
next = __next__
class _ProxyMetaclass(type):
# The metaclass is applied after the class definition
# for Py2/Py3 compatibility.
__implemented__ = _EmptyInterfaceDescriptor()
class AbstractPyProxyBase(object):
"""
A reference implementation that cannot be instantiated. Most users
......@@ -424,6 +452,9 @@ class AbstractPyProxyBase(object):
self._wrapped = pow(self._wrapped, other, modulus)
return self
AbstractPyProxyBase = _ProxyMetaclass(str('AbstractPyProxyBase'), (),
dict(AbstractPyProxyBase.__dict__))
class PyProxyBase(AbstractPyProxyBase):
"""Reference implementation.
"""
......
......@@ -706,6 +706,53 @@ class PyProxyBaseTestCase(unittest.TestCase):
self.assertRaises(AttributeError, setattr, proxy, 'attr', 42)
self.assertEqual(proxy.attr, "constant value")
def _check_wrapping_builtin_returns_correct_provided_by(self, proxy_class, builtin_type):
# We get the __implemented__ (fallback) of the type, not our own
from zope.interface import Interface
from zope.interface import classImplements
from zope.interface import classImplementsOnly
from zope.interface import implementedBy
from zope.interface import providedBy
from zope.interface import implementedBy
# Set up the builtin interface
class IFoo(Interface):
pass
impl_before = list(implementedBy(builtin_type))
classImplements(builtin_type, IFoo)
builtin = builtin_type()
self.assertTrue(IFoo in list(providedBy(builtin)))
try:
proxy_instance = proxy_class(builtin)
provided_instance = providedBy(proxy_instance)
proxy_type = proxy_class(builtin_type)
provided_type = implementedBy(proxy_type)
# The asserts must be before we remove the interface
# because there's a single object that gets mutated
self.assertTrue(IFoo in list(provided_instance))
self.assertTrue(IFoo in list(provided_type))
finally:
classImplementsOnly(builtin_type, *impl_before)
def test_wrapping_builtin_type_returns_correct_provided_by(self):
self._check_wrapping_builtin_returns_correct_provided_by(self._getTargetClass(), list)
def _check_wrapping_builtin_with_subclass_returns_correct_provided_by(self, builtin_type):
class Proxy(self._getTargetClass()):
pass
self._check_wrapping_builtin_returns_correct_provided_by(Proxy, builtin_type)
# Our new class did not gain an __implemented__ attribute, unless we're
# the pure-python version
if hasattr(Proxy, '__implemented__'):
from zope.proxy import PyProxyBase
self.assertTrue(self._getTargetClass() is PyProxyBase)
def test_wrapping_builtin_with_subclass_returns_correct_provided_by(self):
self._check_wrapping_builtin_with_subclass_returns_correct_provided_by(list)
def test_method_in_proxy_subclass(self):
class Proxy(self._getTargetClass()):
def __getitem__(self, k):
......@@ -727,7 +774,7 @@ class PyProxyBaseTestCase(unittest.TestCase):
self.assertEqual(14, int(proxy))
except TypeError:
from zope.proxy import PyProxyBase
self.assertNotEqual(self._getTargetClass, PyProxyBase)
self.assertNotEqual(self._getTargetClass(), PyProxyBase)
class ProxyBaseTestCase(PyProxyBaseTestCase):
......
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