[Checkins] SVN: zope.proxy/trunk/ Add pure-Python fallback implementation of zope.proxy.ProxyBase.
Tres Seaver
cvs-admin at zope.org
Wed Jun 6 20:12:55 UTC 2012
Log message for revision 126617:
Add pure-Python fallback implementation of zope.proxy.ProxyBase.
This version passes all tests except the one which asserts that the proxy
can lie about its '__class__', which can't be done in Python.
Changed:
_U zope.proxy/trunk/
U zope.proxy/trunk/CHANGES.txt
U zope.proxy/trunk/src/zope/proxy/__init__.py
U zope.proxy/trunk/src/zope/proxy/_zope_proxy_proxy.c
U zope.proxy/trunk/src/zope/proxy/tests/test_proxy.py
-=-
Modified: zope.proxy/trunk/CHANGES.txt
===================================================================
--- zope.proxy/trunk/CHANGES.txt 2012-06-06 20:12:48 UTC (rev 126616)
+++ zope.proxy/trunk/CHANGES.txt 2012-06-06 20:12:51 UTC (rev 126617)
@@ -5,6 +5,8 @@
4.0.0 (unreleased)
------------------
+- Added a pure-Python fallback implementation of ``zope.proxy.ProxyBase``.
+
- Added support for continuous integration using ``tox`` and ``jenkins``.
- 100% unit test coverage.
Modified: zope.proxy/trunk/src/zope/proxy/__init__.py
===================================================================
--- zope.proxy/trunk/src/zope/proxy/__init__.py 2012-06-06 20:12:48 UTC (rev 126616)
+++ zope.proxy/trunk/src/zope/proxy/__init__.py 2012-06-06 20:12:51 UTC (rev 126617)
@@ -13,18 +13,15 @@
##############################################################################
"""More convenience functions for dealing with proxies.
"""
+import operator
+import pickle
+import sys
+import types
+
from zope.interface import moduleProvides
from zope.proxy.interfaces import IProxyIntrospection
-from zope.proxy._zope_proxy_proxy import ProxyBase
-from zope.proxy._zope_proxy_proxy import getProxiedObject
-from zope.proxy._zope_proxy_proxy import setProxiedObject
-from zope.proxy._zope_proxy_proxy import isProxy
-from zope.proxy._zope_proxy_proxy import sameProxiedObjects
-from zope.proxy._zope_proxy_proxy import queryProxy
-from zope.proxy._zope_proxy_proxy import queryInnerProxy
-from zope.proxy._zope_proxy_proxy import removeAllProxies
-from zope.proxy._zope_proxy_proxy import _CAPI
+
moduleProvides(IProxyIntrospection)
__all__ = tuple(IProxyIntrospection)
@@ -36,3 +33,321 @@
def non_overridable(func):
return property(lambda self: func.__get__(self))
+
+
+class PyProxyBase(object):
+ """Reference implementation.
+ """
+ __slots__ = ('_wrapped', )
+
+ def __new__(cls, value):
+ inst = super(PyProxyBase, cls).__new__(cls)
+ inst._wrapped = value
+ return inst
+
+ def __init__(self, obj):
+ self._wrapped = obj
+
+ def __call__(self, *args, **kw):
+ return self._wrapped(*args, **kw)
+
+ def __repr__(self):
+ return repr(self._wrapped)
+
+ def __str__(self):
+ return str(self._wrapped)
+
+ def __unicode__(self):
+ return unicode(self._wrapped)
+
+ def __reduce__(self):
+ raise pickle.PicklingError
+
+ # Rich comparison protocol
+ def __lt__(self, other):
+ return self._wrapped < other
+
+ def __le__(self, other):
+ return self._wrapped <= other
+
+ def __eq__(self, other):
+ return self._wrapped == other
+
+ def __ne__(self, other):
+ return self._wrapped != other
+
+ def __gt__(self, other):
+ return self._wrapped > other
+
+ def __ge__(self, other):
+ return self._wrapped >= other
+
+ def __nonzero__(self):
+ return bool(self._wrapped)
+
+ def __hash__(self):
+ return hash(self._wrapped)
+
+ # Attribute protocol
+ def __getattr__(self, name):
+ return getattr(self._wrapped, name)
+
+ def __setattr__(self, name, value):
+ if name == '_wrapped':
+ return super(PyProxyBase, self).__setattr__(name, value)
+ setattr(self._wrapped, name, value)
+
+ def __delattr__(self, name):
+ if name == '_wrapped':
+ raise AttributeError()
+ delattr(self._wrapped, name)
+
+ # Container protocols
+
+ def __len__(self):
+ return len(self._wrapped)
+
+ def __getitem__(self, key):
+ if isinstance(key, types.SliceType):
+ if isinstance(self._wrapped, (list, tuple)):
+ return self._wrapped[key]
+ start, stop = key.start, key.stop
+ if start is None:
+ start = 0
+ if start < 0:
+ start += len(self._wrapped)
+ if stop is None:
+ stop = sys.maxint
+ if stop < 0:
+ stop += len(self._wrapped)
+ return operator.getslice(self._wrapped, start, stop)
+ return self._wrapped[key]
+
+ def __setitem__(self, key, value):
+ self._wrapped[key] = value
+
+ def __delitem__(self, key):
+ del self._wrapped[key]
+
+ def __iter__(self):
+ for item in self._wrapped:
+ yield item
+
+ def next(self):
+ # Called when we wrap an iterator itself.
+ return self._wrapped.next()
+
+ def __reversed__(self):
+ return reversed(self._wrapped)
+
+ def __contains__(self, item):
+ return item in self._wrapped
+
+ # Numeric protocol: unary operators
+ def __neg__(self):
+ return -self._wrapped
+
+ def __pos__(self):
+ return +self._wrapped
+
+ def __abs__(self):
+ return abs(self._wrapped)
+
+ def __invert__(self):
+ return ~self._wrapped
+
+ # Numeric protocol: unary conversions
+ def __complex__(self):
+ return complex(self._wrapped)
+
+ def __int__(self):
+ return int(self._wrapped)
+
+ def __long__(self):
+ return long(self._wrapped)
+
+ def __float__(self):
+ return float(self._wrapped)
+
+ def __oct__(self):
+ return oct(self._wrapped)
+
+ def __hex__(self):
+ return hex(self._wrapped)
+
+ def __index__(self):
+ return operator.index(self._wrapped)
+
+ # Numeric protocol: binary coercion
+ def __coerce__(self, other):
+ left, right = coerce(self._wrapped, other)
+ if left == self._wrapped and type(left) is type(self._wrapped):
+ left = self
+ return left, right
+
+ # Numeric protocol: binary arithmetic operators
+ def __add__(self, other):
+ return self._wrapped + other
+
+ def __sub__(self, other):
+ return self._wrapped - other
+
+ def __mul__(self, other):
+ return self._wrapped * other
+
+ def __floordiv__(self, other):
+ return self._wrapped // other
+
+ def __truediv__(self, other): #pragma NO COVER
+ # Only one of __truediv__ and __div__ is meaningful at any one time.
+ return self._wrapped / other
+
+ def __div__(self, other): #pragma NO COVER
+ # Only one of __truediv__ and __div__ is meaningful at any one time.
+ return self._wrapped / other
+
+ def __mod__(self, other):
+ return self._wrapped % other
+
+ def __divmod__(self, other):
+ return divmod(self._wrapped, other)
+
+ def __pow__(self, other, modulus=None):
+ if modulus is None:
+ return pow(self._wrapped, other)
+ return pow(self._wrapped, other, modulus)
+
+ def __radd__(self, other):
+ return other + self._wrapped
+
+ def __rsub__(self, other):
+ return other - self._wrapped
+
+ def __rmul__(self, other):
+ return other * self._wrapped
+
+ def __rfloordiv__(self, other):
+ return other // self._wrapped
+
+ def __rtruediv__(self, other): #pragma NO COVER
+ # Only one of __rtruediv__ and __rdiv__ is meaningful at any one time.
+ return other / self._wrapped
+
+ def __rdiv__(self, other): #pragma NO COVER
+ # Only one of __rtruediv__ and __rdiv__ is meaningful at any one time.
+ return other / self._wrapped
+
+ def __rmod__(self, other):
+ return other % self._wrapped
+
+ def __rdivmod__(self, other):
+ return divmod(other, self._wrapped)
+
+ def __rpow__(self, other, modulus=None):
+ if modulus is None:
+ return pow(other, self._wrapped)
+ # We can't actually get here, because we can't lie about our type()
+ return pow(other, self._wrapped, modulus) #pragma NO COVER
+
+ # Numeric protocol: binary bitwise operators
+ def __lshift__(self, other):
+ return self._wrapped << other
+
+ def __rshift__(self, other):
+ return self._wrapped >> other
+
+ def __and__(self, other):
+ return self._wrapped & other
+
+ def __xor__(self, other):
+ return self._wrapped ^ other
+
+ def __or__(self, other):
+ return self._wrapped | other
+
+ def __rlshift__(self, other):
+ return other << self._wrapped
+
+ def __rrshift__(self, other):
+ return other >> self._wrapped
+
+ def __rand__(self, other):
+ return other & self._wrapped
+
+ def __rxor__(self, other):
+ return other ^ self._wrapped
+
+ def __ror__(self, other):
+ return other | self._wrapped
+
+ # Numeric protocol: binary in-place operators
+ def __iadd__(self, other):
+ self._wrapped += other
+ return self
+
+ def __isub__(self, other):
+ self._wrapped -= other
+ return self
+
+ def __imul__(self, other):
+ self._wrapped *= other
+ return self
+
+ def __idiv__(self, other): #pragma NO COVER
+ # Only one of __itruediv__ and __idiv__ is meaningful at any one time.
+ self._wrapped /= other
+ return self
+
+ def __itruediv__(self, other): #pragma NO COVER
+ # Only one of __itruediv__ and __idiv__ is meaningful at any one time.
+ self._wrapped /= other
+ return self
+
+ def __ifloordiv__(self, other):
+ self._wrapped //= other
+ return self
+
+ def __imod__(self, other):
+ self._wrapped %= other
+ return self
+
+ def __ilshift__(self, other):
+ self._wrapped <<= other
+ return self
+
+ def __irshift__(self, other):
+ self._wrapped >>= other
+ return self
+
+ def __iand__(self, other):
+ self._wrapped &= other
+ return self
+
+ def __ixor__(self, other):
+ self._wrapped ^= other
+ return self
+
+ def __ior__(self, other):
+ self._wrapped |= other
+ return self
+
+ def __ipow__(self, other, modulus=None):
+ if modulus is None:
+ self._wrapped **= other
+ else: #pragma NO COVER
+ # There is no syntax which triggers in-place pow w/ modulus
+ self._wrapped = pow(self._wrapped, other, modulus)
+ return self
+
+# Python API: not used in this module
+from zope.proxy._zope_proxy_proxy import ProxyBase
+from zope.proxy._zope_proxy_proxy import getProxiedObject
+from zope.proxy._zope_proxy_proxy import setProxiedObject
+from zope.proxy._zope_proxy_proxy import isProxy
+from zope.proxy._zope_proxy_proxy import sameProxiedObjects
+from zope.proxy._zope_proxy_proxy import queryProxy
+from zope.proxy._zope_proxy_proxy import queryInnerProxy
+from zope.proxy._zope_proxy_proxy import removeAllProxies
+
+# API for proxy-using C extensions.
+from zope.proxy._zope_proxy_proxy import _CAPI
Modified: zope.proxy/trunk/src/zope/proxy/_zope_proxy_proxy.c
===================================================================
--- zope.proxy/trunk/src/zope/proxy/_zope_proxy_proxy.c 2012-06-06 20:12:48 UTC (rev 126616)
+++ zope.proxy/trunk/src/zope/proxy/_zope_proxy_proxy.c 2012-06-06 20:12:51 UTC (rev 126617)
@@ -467,6 +467,18 @@
#endif
static PyObject *
+call_index(PyObject *self)
+{
+ PyNumberMethods *nb = self->ob_type->tp_as_number;
+ if (nb == NULL || nb->nb_index == NULL) {
+ PyErr_SetString(PyExc_TypeError,
+ "object can't be converted to index");
+ return NULL;
+ }
+ return nb->nb_index(self);
+}
+
+static PyObject *
call_float(PyObject *self)
{
PyNumberMethods *nb = self->ob_type->tp_as_number;
@@ -675,6 +687,7 @@
BINOP(truediv, PyNumber_TrueDivide)
INPLACE(floordiv, PyNumber_InPlaceFloorDivide)
INPLACE(truediv, PyNumber_InPlaceTrueDivide)
+UNOP(index, call_index)
static int
wrap_nonzero(PyObject *self)
@@ -834,6 +847,7 @@
wrap_truediv, /* nb_true_divide */
wrap_ifloordiv, /* nb_inplace_floor_divide */
wrap_itruediv, /* nb_inplace_true_divide */
+ wrap_index, /* nb_index */
};
static PySequenceMethods
Modified: zope.proxy/trunk/src/zope/proxy/tests/test_proxy.py
===================================================================
--- zope.proxy/trunk/src/zope/proxy/tests/test_proxy.py 2012-06-06 20:12:48 UTC (rev 126616)
+++ zope.proxy/trunk/src/zope/proxy/tests/test_proxy.py 2012-06-06 20:12:51 UTC (rev 126617)
@@ -25,24 +25,23 @@
verifyObject(IProxyIntrospection, zope.proxy)
-class ProxyBaseTestCase(unittest.TestCase):
+class PyProxyBaseTestCase(unittest.TestCase):
- @property
- def proxy_class(self):
- from zope.proxy import ProxyBase
- return ProxyBase
+ def _getTargetClass(self):
+ from zope.proxy import PyProxyBase
+ return PyProxyBase
- def new_proxy(self, o):
- return self.proxy_class(o)
+ def _makeOne(self, o):
+ return self._getTargetClass()(o)
def test_constructor(self):
o = object()
- self.assertRaises(TypeError, self.proxy_class, o, o)
- self.assertRaises(TypeError, self.proxy_class, o, key='value')
- self.assertRaises(TypeError, self.proxy_class, key='value')
+ self.assertRaises(TypeError, self._makeOne, o, o)
+ self.assertRaises(TypeError, self._makeOne, o, key='value')
+ self.assertRaises(TypeError, self._makeOne, key='value')
def test_subclass_constructor(self):
- class MyProxy(self.proxy_class):
+ class MyProxy(self._getTargetClass()):
def __new__(cls, *args, **kwds):
return super(MyProxy, cls).__new__(cls, *args, **kwds)
def __init__(self, *args, **kwds):
@@ -60,7 +59,7 @@
# Check that are passed to __init__() overrides what's passed
# to __new__().
- class MyProxy2(self.proxy_class):
+ class MyProxy2(self._getTargetClass()):
def __new__(cls, *args, **kwds):
return super(MyProxy2, cls).__new__(cls, 'value')
@@ -76,59 +75,79 @@
p = MyProxy3('notused')
self.assertEqual(list(p), list('another'))
- def test_proxy_attributes(self):
- class Thing:
- """This class is expected to be a classic class."""
- o = Thing()
- o.foo = 1
- w = self.new_proxy(o)
- self.assertTrue(w.foo == 1)
+ def test___call__(self):
+ def _foo():
+ return 'FOO'
+ p = self._makeOne(_foo)
+ self.assertEqual(p(), 'FOO')
- def test___class__(self):
- o = object()
- w = self.new_proxy(o)
- self.assertTrue(w.__class__ is o.__class__)
+ def test_callable(self):
+ from zope.proxy._compat import PY3
+ if not PY3: # Gone in Python 3:
+ w = self._makeOne({}.get)
+ self.assertTrue(callable(w))
- def test_pickle_prevention(self):
+ def test___repr__(self):
+ def _foo():
+ return 'FOO'
+ p = self._makeOne(_foo)
+ self.assertTrue(repr(p).startswith('<function _foo'))
+
+ def test___str__(self):
+ def _foo():
+ return 'FOO'
+ p = self._makeOne(_foo)
+ self.assertTrue(str(p).startswith('<function _foo'))
+
+ def test___unicode__(self):
+ from zope.proxy._compat import PY3
+ if PY3: # Gone in Python 3:
+ return
+ def _foo():
+ return 'FOO'
+ p = self._makeOne(_foo)
+ self.assertTrue(unicode(p).startswith('<function _foo'))
+
+ def test___reduce___via_pickling(self):
import pickle
from zope.proxy._compat import PY3
# Proxies of old-style classes can't be pickled.
if not PY3: # No old-style classes in Python 3.
class Thing:
"""This class is expected to be a classic class."""
- w = self.new_proxy(Thing())
+ w = self._makeOne(Thing())
self.assertRaises(pickle.PicklingError,
pickle.dumps, w)
- def test_proxy_equality(self):
- w = self.new_proxy('foo')
+ def test___eq___and___ne__(self):
+ w = self._makeOne('foo')
self.assertEqual(w, 'foo')
o1 = Comparable(1)
o2 = Comparable(1.0)
o3 = Comparable("splat!")
- w1 = self.new_proxy(o1)
- w2 = self.new_proxy(o2)
- w3 = self.new_proxy(o3)
+ w1 = self._makeOne(o1)
+ w2 = self._makeOne(o2)
+ w3 = self._makeOne(o3)
- self.assertEqual(o1, w1)
- self.assertEqual(o1, w2)
- self.assertEqual(o2, w1)
- self.assertEqual(w1, o2)
- self.assertEqual(w2, o1)
+ self.assertTrue(o1 == w1)
+ self.assertTrue(o1 == w2)
+ self.assertTrue(o2 == w1)
+ self.assertTrue(w1 == o2)
+ self.assertTrue(w2 == o1)
- self.assertNotEqual(o3, w1)
- self.assertNotEqual(w1, o3)
- self.assertNotEqual(w3, o1)
- self.assertNotEqual(o1, w3)
+ self.assertTrue(o3 != w1)
+ self.assertTrue(w1 != o3)
+ self.assertTrue(w3 != o1)
+ self.assertTrue(o1 != w3)
- def test_proxy_ordering_lt(self):
+ def test___lt___and___le__(self):
o1 = Comparable(1)
o2 = Comparable(2.0)
- w1 = self.new_proxy(o1)
- w2 = self.new_proxy(o2)
+ w1 = self._makeOne(o1)
+ w2 = self._makeOne(o2)
self.assertTrue(w1 < w2)
self.assertTrue(w1 <= w2)
@@ -137,14 +156,73 @@
self.assertTrue(w1 < o2)
self.assertTrue(w2 <= o2)
- def test_proxy_callable(self):
- from zope.proxy._compat import PY3
- if not PY3: # Gone in Python 3:
- w = self.new_proxy({}.get)
- self.assertTrue(callable(w))
+ def test___gt___and___ge__(self):
+ o1 = Comparable(1)
+ o2 = Comparable(2.0)
- def test_proxy_item_protocol(self):
- w = self.new_proxy({})
+ w1 = self._makeOne(o1)
+ w2 = self._makeOne(o2)
+
+ self.assertTrue(w2 > w1)
+ self.assertTrue(w2 >= w1)
+ self.assertTrue(w2 > o1)
+ self.assertTrue(w2 >= o1)
+ self.assertTrue(o2 > w1)
+ self.assertTrue(o2 >= w2)
+
+ def test___nonzero__(self):
+ w = self._makeOne(None)
+ self.assertFalse(w)
+ self.assertTrue(not w)
+
+ def test___hash__(self):
+ w1 = self._makeOne(1)
+ self.assertEqual(hash(w1), hash(1))
+
+ def test___getattr__delegates_to_wrapped(self):
+ class Foo(object):
+ pass
+ o = Foo()
+ o.foo = 1
+ w = self._makeOne(o)
+ self.assertEqual(w.foo, 1)
+
+ def test___setattr__delegates_to_wrapped(self):
+ class Foo(object):
+ pass
+ o = Foo()
+ w = self._makeOne(o)
+ w.foo = 1
+ self.assertEqual(o.foo, 1)
+
+ def test___delattr___wrapped(self):
+ class Foo(object):
+ pass
+ o = Foo()
+ o.foo = 1
+ w = self._makeOne(o)
+ def _try():
+ del w._wrapped
+ self.assertRaises(AttributeError, _try)
+
+ def test___delattr__delegates_to_wrapped(self):
+ class Foo(object):
+ pass
+ o = Foo()
+ o.foo = 1
+ w = self._makeOne(o)
+ del w.foo
+ self.assertFalse('foo' in o.__dict__)
+
+ def test___len__(self):
+ l = []
+ w = self._makeOne(l)
+ self.assertEqual(len(w), 0)
+ l.append(0)
+ self.assertEqual(len(w), 1)
+
+ def test___getitem_____setitem_____delitem__(self):
+ w = self._makeOne({})
self.assertRaises(KeyError, lambda: w[1])
w[1] = 'a'
self.assertEqual(w[1], 'a')
@@ -154,25 +232,98 @@
del w[1]
self.assertRaises(KeyError, del_w_1)
- def test_wrapped_iterable(self):
+ def test___getitem__w_slice_against_list(self):
+ # Lists have special slicing behavior.
+ pList = self._makeOne([1, 2])
+ self.assertEqual(pList[-1:], [2])
+ self.assertEqual(pList[-2:], [1, 2])
+ self.assertEqual(pList[-3:], [1, 2])
+
+ def test___getitem__w_slice_against_tuple(self):
+ # Tuples also have special slicing behavior.
+ pTuple = self._makeOne((1, 2))
+ self.assertEqual(pTuple[-1:], (2,))
+ self.assertEqual(pTuple[-2:], (1, 2))
+ self.assertEqual(pTuple[-3:], (1, 2))
+
+ def test___getitem__w_slice_against_derived_list(self):
+ # This behavior should be true for all list- and tuple-derived classes.
+ class DerivedList(list):
+ def __getslice__(self, start, end, step=None):
+ return (start, end, step)
+
+ pList = self._makeOne(DerivedList([1, 2]))
+ self.assertEqual(pList[-1:], [2])
+ self.assertEqual(pList[-2:], [1, 2])
+ self.assertEqual(pList[-3:], [1, 2])
+
+ def test___getitem__w_slice_against_class_w_custom___getslice__(self):
+ # moot under Python 3, where __getslice__ isn't supported.
+ from zope.proxy._compat import PY3
+ if not PY3:
+ class Slicer(object):
+ def __len__(self):
+ return 2
+ def __getslice__(self, start, end, step=None):
+ return (start, end, step)
+
+ pSlicer = self._makeOne(Slicer())
+ self.assertEqual(pSlicer[:1][0], 0)
+ self.assertEqual(pSlicer[:1][1], 1)
+ self.assertEqual(pSlicer[:-1][0], 0)
+ self.assertEqual(pSlicer[:-1][1], 1)
+ self.assertEqual(pSlicer[-1:][0], 1)
+ self.assertEqual(pSlicer[-2:][0], 0)
+ # Note that for non-lists and non-tuples the slice is computed
+ # differently
+ self.assertEqual(pSlicer[-3:][0], 1)
+
+ def test___setslice___against_list(self):
+ # Lists have special slicing bahvior for assignment as well.
+ pList = self._makeOne([1, 2])
+ pList[-1:] = [3, 4]
+ self.assertEqual(pList, [1, 3, 4])
+ pList = self._makeOne([1, 2])
+ pList[-2:] = [3, 4]
+ self.assertEqual(pList, [3, 4])
+ pList = self._makeOne([1, 2])
+ pList[-3:] = [3, 4]
+ self.assertEqual(pList, [3, 4])
+
+ def test___setslice___against_derived_list(self):
+ # This behavior should be true for all list-derived classes.
+ class DerivedList(list):
+ pass
+
+ pList = self._makeOne(DerivedList([1, 2]))
+ pList[-1:] = [3, 4]
+ self.assertEqual(pList, [1, 3, 4])
+ pList = self._makeOne(DerivedList([1, 2]))
+ pList[-2:] = [3, 4]
+ self.assertEqual(pList, [3, 4])
+ pList = self._makeOne(DerivedList([1, 2]))
+ pList[-3:] = [3, 4]
+ self.assertEqual(pList, [3, 4])
+
+ def test___iter___w_wrapped_iterable(self):
a = [1, 2, 3]
b = []
- for x in self.new_proxy(a):
+ for x in self._makeOne(a):
b.append(x)
self.assertEqual(a, b)
- def test_iteration_over_proxy(self):
+ def test___iter___w_wrapped_iterator(self):
# Wrap an iterator before starting iteration.
# PyObject_GetIter() will still be called on the proxy.
a = [1, 2, 3]
b = []
- for x in self.new_proxy(iter(a)):
+ for x in self._makeOne(iter(a)):
b.append(x)
self.assertEqual(a, b)
- t = tuple(self.new_proxy(iter(a)))
+ t = tuple(self._makeOne(iter(a)))
self.assertEqual(t, (1, 2, 3))
- def test_iteration_using_proxy(self):
+ def test___iter___next_when_returned_by_iterable(self):
# Wrap an iterator within the iteration protocol, expecting it
# still to work. PyObject_GetIter() will not be called on the
# proxy, so the tp_iter slot won't unwrap it.
@@ -182,7 +333,7 @@
self.test = test
self.data = data
def __iter__(self):
- return self.test.new_proxy(iter(self.data))
+ return self.test._makeOne(iter(self.data))
a = [1, 2, 3]
b = []
@@ -190,10 +341,20 @@
b.append(x)
self.assertEqual(a, b)
- def test_bool_wrapped_None(self):
- w = self.new_proxy(None)
- self.assertEqual(not w, 1)
+ def test___reversed__(self):
+ w = self._makeOne([0, 1, 2, 3])
+ self.assertEqual(list(reversed(w)), [3, 2, 1, 0])
+ def test___contains__(self):
+ w = self._makeOne([0, 1, 2, 3])
+ self.assertTrue(1 in w)
+ self.assertFalse(4 in w)
+
+ def test___index__(self):
+ import operator
+ w = self._makeOne(42)
+ self.assertEqual(operator.index(w), 42)
+
# Numeric ops.
@property
@@ -206,17 +367,17 @@
"~x",
"int(x)",
"float(x)",
+ "complex(x)",
]
if not PY3: # long is gone in Python 3
ops.append("long(x)")
return ops
def test_unops(self):
- P = self.new_proxy
for expr in self.unops:
x = 1
y = eval(expr)
- x = P(1)
+ x = self._makeOne(1)
z = eval(expr)
self.assertEqual(z, y,
"x=%r; expr=%r" % (x, expr))
@@ -224,24 +385,23 @@
def test_odd_unops(self):
from zope.proxy._compat import PY3
# unops that don't return a proxy
- P = self.new_proxy
funcs = (lambda x: not x,)
if not PY3:
funcs += (oct, hex)
for func in funcs:
- self.assertEqual(func(P(100)), func(100))
+ self.assertEqual(func(self._makeOne(100)), func(100))
binops = [
- "x+y", "x-y", "x*y", "x/y", "divmod(x, y)", "x**y", "x//y",
+ "x+y", "x-y", "x*y", "x/y", "x//y", "x%y", "divmod(x, y)",
+ "x**y", #"pow(x,y,3)" (RHS coercion not supported w/ modulus)
"x<<y", "x>>y", "x&y", "x|y", "x^y",
]
def test_binops(self):
- P = self.new_proxy
for expr in self.binops:
first = 1
- for x in [1, P(1)]:
- for y in [2, P(2)]:
+ for x in [1, self._makeOne(1)]:
+ for y in [2, self._makeOne(2)]:
if first:
z = eval(expr)
first = 0
@@ -249,159 +409,168 @@
self.assertEqual(eval(expr), z,
"x=%r; y=%r; expr=%r" % (x, y, expr))
+ def test_pow_w_modulus(self):
+ x = self._makeOne(2)
+ # Can't coerce 2nd / 3rd args in pure Python, because we can't
+ # lie about our type
+ self.assertEqual(pow(x, 3, 3), 2)
+
def test_inplace(self):
# TODO: should test all inplace operators...
- P = self.new_proxy
-
- pa = P(1)
+ pa = self._makeOne(1)
pa += 2
self.assertEqual(pa, 3)
a = [1, 2, 3]
- pa = qa = P(a)
+ pa = qa = self._makeOne(a)
pa += [4, 5, 6]
self.assertTrue(pa is qa)
self.assertEqual(a, [1, 2, 3, 4, 5, 6])
- pa = P(2)
+ pa = self._makeOne(2)
+ pa -= 1
+ self.assertEqual(pa, 1)
+ pa *= 4
+ self.assertEqual(pa, 4)
+ pa /= 2
+ self.assertEqual(pa, 2)
+ pa //= 2
+ self.assertEqual(pa, 1)
+ pa += 2
+ self.assertEqual(pa, 3)
+ pa %= 2
+ self.assertEqual(pa, 1)
+
+ pa = self._makeOne(2)
pa **= 2
self.assertEqual(pa, 4)
+ pa <<= 1
+ self.assertEqual(pa, 8)
+ pa >>= 2
+ self.assertEqual(pa, 2)
+ pa = self._makeOne(7)
+ pa &= 6
+ self.assertEqual(pa, 6)
+ pa |= 16
+ self.assertEqual(pa, 22)
+ pa ^= 2
+ self.assertEqual(pa, 20)
+
def test_coerce(self):
from zope.proxy._compat import PY3
if PY3: # No coercion in Python 3
return
- P = self.new_proxy
-
# Before 2.3, coerce() of two proxies returns them unchanged
- x = P(1)
- y = P(2)
+ x = self._makeOne(1)
+ y = self._makeOne(2)
a, b = coerce(x, y)
self.assertTrue(a is x and b is y)
- x = P(1)
- y = P(2.1)
+ x = self._makeOne(1)
+ y = self._makeOne(2.1)
a, b = coerce(x, y)
- self.assertTrue(a == 1.0)
+ self.assertFalse(a is x) # a was coerced
+ self.assertEqual(a, float(x))
self.assertTrue(b is y)
- self.assertTrue(a.__class__ is float, a.__class__)
- x = P(1.1)
- y = P(2)
+ x = self._makeOne(1.1)
+ y = self._makeOne(2)
a, b = coerce(x, y)
self.assertTrue(a is x)
- self.assertTrue(b == 2.0)
- self.assertTrue(b.__class__ is float, b.__class__)
+ self.assertFalse(b is y) # b was coerced
+ self.assertEqual(b, float(y))
- x = P(1)
+ x = self._makeOne(1)
y = 2
a, b = coerce(x, y)
- self.assertTrue(a is x)
+ self.assertTrue(a is x) # neither was coerced
self.assertTrue(b is y)
- x = P(1)
+ x = self._makeOne(1)
y = 2.1
a, b = coerce(x, y)
- self.assertTrue(a.__class__ is float, a.__class__)
+ self.assertFalse(a is x) # a was coerced
+ self.assertEqual(a, float(x))
self.assertTrue(b is y)
- x = P(1.1)
+ x = self._makeOne(1.1)
y = 2
a, b = coerce(x, y)
self.assertTrue(a is x)
- self.assertTrue(b.__class__ is float, b.__class__)
+ self.assertFalse(b is y) # b was coerced
+ self.assertEqual(b, float(y))
x = 1
- y = P(2)
+ y = self._makeOne(2)
a, b = coerce(x, y)
- self.assertTrue(a is x)
+ self.assertTrue(a is x) # neither was coerced
self.assertTrue(b is y)
x = 1.1
- y = P(2)
+ y = self._makeOne(2)
a, b = coerce(x, y)
self.assertTrue(a is x)
- self.assertTrue(b.__class__ is float, b.__class__)
+ self.assertFalse(b is y) # b was coerced
+ self.assertEqual(b, float(y))
x = 1
- y = P(2.1)
+ y = self._makeOne(2.1)
a, b = coerce(x, y)
- self.assertTrue(a.__class__ is float, a.__class__)
+ self.assertFalse(a is x) # a was coerced
+ self.assertEqual(a, float(x))
self.assertTrue(b is y)
- def test_getslice(self):
- # These tests are moot under Python 3 as __slice__ isn't supported.
- from zope.proxy._compat import PY3
- if PY3:
- return
-
- # Lists have special slicing behavior.
- pList = self.new_proxy([1, 2])
- self.assertEqual(pList[-1:], [2])
- self.assertEqual(pList[-2:], [1, 2])
- self.assertEqual(pList[-3:], [1, 2])
- # Tuples also have special slicing behavior.
- pTuple = self.new_proxy((1, 2))
- self.assertEqual(pTuple[-1:], (2,))
- self.assertEqual(pTuple[-2:], (1, 2))
- self.assertEqual(pTuple[-3:], (1, 2))
+class ProxyBaseTestCase(PyProxyBaseTestCase):
- # This behavior should be true for all list- and tuple-derived classes.
- class DerivedList(list):
+ def _getTargetClass(self):
+ from zope.proxy import ProxyBase
+ return ProxyBase
- def __getslice__(self, start, end, step=None):
- return (start, end, step)
+ def test___class__(self):
+ try:
+ from zope.proxy import _CAPI
+ except ImportError:
+ # Pure Python proxies can't lie about their '__class__'
+ pass
+ else:
+ o = object()
+ w = self._makeOne(o)
+ self.assertTrue(w.__class__ is o.__class__)
- pList = self.new_proxy(DerivedList([1, 2]))
- self.assertEqual(pList[-1:], [2])
- self.assertEqual(pList[-2:], [1, 2])
- self.assertEqual(pList[-3:], [1, 2])
- # Another sort of sequence has a different slicing interpretation.
- class Slicer(object):
+class Test_getProxiedObject(unittest.TestCase):
- def __len__(self):
- return 2
+ def _callFUT(self, *args):
+ from zope.proxy import getProxiedObject
+ return getProxiedObject(*args)
- def __getslice__(self, start, end, step=None):
- return (start, end, step)
+ def test_no_proxy(self):
+ class C(object):
+ pass
+ c = C()
+ self.assertTrue(self._callFUT(c) is c)
- pSlicer = self.new_proxy(Slicer())
- self.assertEqual(pSlicer[-1:][0], 1)
- self.assertEqual(pSlicer[-2:][0], 0)
- # Note that for non-lists and non-tuples the slice is computed
- # differently
- self.assertEqual(pSlicer[-3:][0], 1)
+ def test_simple_proxy(self):
+ from zope.proxy import ProxyBase
+ class C(object):
+ pass
+ c = C()
+ p = ProxyBase(c)
+ self.assertTrue(self._callFUT(p) is c)
- def test_setslice(self):
- # Lists have special slicing bahvior for assignment as well.
- pList = self.new_proxy([1, 2])
- pList[-1:] = [3, 4]
- self.assertEqual(pList, [1, 3, 4])
- pList = self.new_proxy([1, 2])
- pList[-2:] = [3, 4]
- self.assertEqual(pList, [3, 4])
- pList = self.new_proxy([1, 2])
- pList[-3:] = [3, 4]
- self.assertEqual(pList, [3, 4])
-
- # This behavior should be true for all list-derived classes.
- class DerivedList(list):
+ def test_nested_proxy(self):
+ from zope.proxy import ProxyBase
+ class C(object):
pass
+ c = C()
+ p = ProxyBase(c)
+ p2 = ProxyBase(p)
+ self.assertTrue(self._callFUT(p2) is p)
- pList = self.new_proxy(DerivedList([1, 2]))
- pList[-1:] = [3, 4]
- self.assertEqual(pList, [1, 3, 4])
- pList = self.new_proxy(DerivedList([1, 2]))
- pList[-2:] = [3, 4]
- self.assertEqual(pList, [3, 4])
- pList = self.new_proxy(DerivedList([1, 2]))
- pList[-3:] = [3, 4]
- self.assertEqual(pList, [3, 4])
-
class Test_isProxy(unittest.TestCase):
def _callFUT(self, *args):
@@ -447,96 +616,75 @@
self.assertFalse(self._callFUT(p1, P2))
-class Test_getProxiedObject(unittest.TestCase):
+class Test_sameProxiedObjects(unittest.TestCase):
def _callFUT(self, *args):
- from zope.proxy import getProxiedObject
- return getProxiedObject(*args)
+ from zope.proxy import sameProxiedObjects
+ return sameProxiedObjects(*args)
- def test_no_proxy(self):
+ def test_bare_instance_identical(self):
class C(object):
pass
- c = C()
- self.assertTrue(self._callFUT(c) is c)
+ c1 = C()
+ self.assertTrue(self._callFUT(c1, c1))
- def test_simple_proxy(self):
- from zope.proxy import ProxyBase
+ def test_bare_instances_different(self):
class C(object):
pass
- c = C()
- p = ProxyBase(c)
- self.assertTrue(self._callFUT(p) is c)
+ c1 = C()
+ c2 = C()
+ self.assertFalse(self._callFUT(c1, c2))
+ self.assertFalse(self._callFUT(c2, c1))
- def test_nested_proxy(self):
+ def test_proxy_and_same_bare(self):
from zope.proxy import ProxyBase
class C(object):
pass
- c = C()
- p = ProxyBase(c)
- p2 = ProxyBase(p)
- self.assertTrue(self._callFUT(p2) is p)
+ c1 = C()
+ self.assertTrue(self._callFUT(ProxyBase(c1), c1))
+ self.assertTrue(self._callFUT(c1, ProxyBase(c1)))
-
-class Test_ProxyIterator(unittest.TestCase):
-
- def _callFUT(self, *args):
- from zope.proxy import ProxyIterator
- return ProxyIterator(*args)
-
- def test_no_proxy(self):
+ def test_proxy_and_other_bare(self):
+ from zope.proxy import ProxyBase
class C(object):
pass
- c = C()
- self.assertEqual(list(self._callFUT(c)), [c])
+ c1 = C()
+ c2 = C()
+ self.assertFalse(self._callFUT(ProxyBase(c1), c2))
+ self.assertFalse(self._callFUT(c2, ProxyBase(c1)))
- def test_w_simple_proxy(self):
+ def test_proxies_w_same_bare(self):
from zope.proxy import ProxyBase
class C(object):
pass
- c = C()
- p = ProxyBase(c)
- self.assertEqual(list(self._callFUT(p)), [p, c])
+ c1 = C()
+ self.assertTrue(self._callFUT(ProxyBase(c1), ProxyBase(c1)))
- def test_w_nested_proxies(self):
+ def test_proxies_w_other_bare(self):
from zope.proxy import ProxyBase
class C(object):
pass
- c = C()
- p = ProxyBase(c)
- p2 = ProxyBase(p)
- p3 = ProxyBase(p2)
- p4 = ProxyBase(p3)
- self.assertEqual(list(self._callFUT(p4)), [p4, p3, p2, p, c])
+ c1 = C()
+ c2 = C()
+ self.assertFalse(self._callFUT(ProxyBase(c1), ProxyBase(c2)))
+ self.assertFalse(self._callFUT(ProxyBase(c2), ProxyBase(c1)))
-
-class Test_removeAllProxies(unittest.TestCase):
-
- def _callFUT(self, *args):
- from zope.proxy import removeAllProxies
- return removeAllProxies(*args)
-
- def test_no_proxy(self):
- class C(object):
- pass
- c = C()
- self.assertTrue(self._callFUT(c) is c)
-
- def test_simple_proxy(self):
+ def test_nested_proxy_and_same_bare(self):
from zope.proxy import ProxyBase
class C(object):
pass
- c = C()
- p = ProxyBase(c)
- self.assertTrue(self._callFUT(p) is c)
+ c1 = C()
+ self.assertTrue(self._callFUT(ProxyBase(ProxyBase(c1)), c1))
+ self.assertTrue(self._callFUT(c1, ProxyBase(ProxyBase(c1))))
- def test_nested_proxy(self):
+ def test_nested_proxy_and_other_bare(self):
from zope.proxy import ProxyBase
class C(object):
pass
- c = C()
- p = ProxyBase(c)
- p2 = ProxyBase(p)
- self.assertTrue(self._callFUT(p2) is c)
+ c1 = C()
+ c2 = C()
+ self.assertFalse(self._callFUT(ProxyBase(ProxyBase(c1)), c2))
+ self.assertFalse(self._callFUT(c2, ProxyBase(ProxyBase(c1))))
class Test_queryProxy(unittest.TestCase):
@@ -666,75 +814,66 @@
self.assertTrue(self._callFUT(p3, P2, 42) is p2)
-class Test_sameProxiedObjects(unittest.TestCase):
+class Test_removeAllProxies(unittest.TestCase):
def _callFUT(self, *args):
- from zope.proxy import sameProxiedObjects
- return sameProxiedObjects(*args)
+ from zope.proxy import removeAllProxies
+ return removeAllProxies(*args)
- def test_bare_instance_identical(self):
+ def test_no_proxy(self):
class C(object):
pass
- c1 = C()
- self.assertTrue(self._callFUT(c1, c1))
+ c = C()
+ self.assertTrue(self._callFUT(c) is c)
- def test_bare_instances_different(self):
- class C(object):
- pass
- c1 = C()
- c2 = C()
- self.assertFalse(self._callFUT(c1, c2))
- self.assertFalse(self._callFUT(c2, c1))
-
- def test_proxy_and_same_bare(self):
+ def test_simple_proxy(self):
from zope.proxy import ProxyBase
class C(object):
pass
- c1 = C()
- self.assertTrue(self._callFUT(ProxyBase(c1), c1))
- self.assertTrue(self._callFUT(c1, ProxyBase(c1)))
+ c = C()
+ p = ProxyBase(c)
+ self.assertTrue(self._callFUT(p) is c)
- def test_proxy_and_other_bare(self):
+ def test_nested_proxy(self):
from zope.proxy import ProxyBase
class C(object):
pass
- c1 = C()
- c2 = C()
- self.assertFalse(self._callFUT(ProxyBase(c1), c2))
- self.assertFalse(self._callFUT(c2, ProxyBase(c1)))
+ c = C()
+ p = ProxyBase(c)
+ p2 = ProxyBase(p)
+ self.assertTrue(self._callFUT(p2) is c)
- def test_proxies_w_same_bare(self):
- from zope.proxy import ProxyBase
- class C(object):
- pass
- c1 = C()
- self.assertTrue(self._callFUT(ProxyBase(c1), ProxyBase(c1)))
- def test_proxies_w_other_bare(self):
- from zope.proxy import ProxyBase
+class Test_ProxyIterator(unittest.TestCase):
+
+ def _callFUT(self, *args):
+ from zope.proxy import ProxyIterator
+ return ProxyIterator(*args)
+
+ def test_no_proxy(self):
class C(object):
pass
- c1 = C()
- c2 = C()
- self.assertFalse(self._callFUT(ProxyBase(c1), ProxyBase(c2)))
- self.assertFalse(self._callFUT(ProxyBase(c2), ProxyBase(c1)))
+ c = C()
+ self.assertEqual(list(self._callFUT(c)), [c])
- def test_nested_proxy_and_same_bare(self):
+ def test_w_simple_proxy(self):
from zope.proxy import ProxyBase
class C(object):
pass
- c1 = C()
- self.assertTrue(self._callFUT(ProxyBase(ProxyBase(c1)), c1))
- self.assertTrue(self._callFUT(c1, ProxyBase(ProxyBase(c1))))
+ c = C()
+ p = ProxyBase(c)
+ self.assertEqual(list(self._callFUT(p)), [p, c])
- def test_nested_proxy_and_other_bare(self):
+ def test_w_nested_proxies(self):
from zope.proxy import ProxyBase
class C(object):
pass
- c1 = C()
- c2 = C()
- self.assertFalse(self._callFUT(ProxyBase(ProxyBase(c1)), c2))
- self.assertFalse(self._callFUT(c2, ProxyBase(ProxyBase(c1))))
+ c = C()
+ p = ProxyBase(c)
+ p2 = ProxyBase(p)
+ p3 = ProxyBase(p2)
+ p4 = ProxyBase(p3)
+ self.assertEqual(list(self._callFUT(p4)), [p4, p3, p2, p, c])
class Test_nonOverridable(unittest.TestCase):
@@ -787,13 +926,14 @@
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(ModuleConformanceCase),
+ unittest.makeSuite(PyProxyBaseTestCase),
unittest.makeSuite(ProxyBaseTestCase),
+ unittest.makeSuite(Test_getProxiedObject),
unittest.makeSuite(Test_isProxy),
- unittest.makeSuite(Test_getProxiedObject),
- unittest.makeSuite(Test_ProxyIterator),
- unittest.makeSuite(Test_removeAllProxies),
+ unittest.makeSuite(Test_sameProxiedObjects),
unittest.makeSuite(Test_queryProxy),
unittest.makeSuite(Test_queryInnerProxy),
- unittest.makeSuite(Test_sameProxiedObjects),
+ unittest.makeSuite(Test_removeAllProxies),
+ unittest.makeSuite(Test_ProxyIterator),
unittest.makeSuite(Test_nonOverridable),
))
More information about the checkins
mailing list