~ubuntu-branches/ubuntu/precise/zope.proxy/precise

« back to all changes in this revision

Viewing changes to src/zope/proxy/tests/test_proxy.py

  • Committer: Bazaar Package Importer
  • Author(s): Fabio Tranchitella
  • Date: 2009-06-18 17:20:52 UTC
  • Revision ID: james.westby@ubuntu.com-20090618172052-2vpxps4mfz0pw2e1
Tags: upstream-3.5.0
ImportĀ upstreamĀ versionĀ 3.5.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
##############################################################################
 
2
#
 
3
# Copyright (c) 2003 Zope Corporation and Contributors.
 
4
# All Rights Reserved.
 
5
#
 
6
# This software is subject to the provisions of the Zope Public License,
 
7
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
 
8
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
 
9
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 
10
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
 
11
# FOR A PARTICULAR PURPOSE.
 
12
#
 
13
##############################################################################
 
14
"""Test base proxy class.
 
15
 
 
16
$Id: test_proxy.py 87706 2008-06-24 12:23:50Z srichter $
 
17
"""
 
18
import pickle
 
19
import sys
 
20
import unittest
 
21
 
 
22
from zope.testing.doctestunit import DocTestSuite
 
23
from zope.proxy import ProxyBase
 
24
import zope.proxy
 
25
 
 
26
class Thing:
 
27
    """This class is expected to be a classic class."""
 
28
 
 
29
class Comparable(object):
 
30
    def __init__(self, value):
 
31
        self.value = value
 
32
 
 
33
    def __eq__(self, other):
 
34
        if hasattr(other, "value"):
 
35
            other = other.value
 
36
        return self.value == other
 
37
 
 
38
    def __ne__(self, other):
 
39
        return not self.__eq__(other)
 
40
 
 
41
    def __lt__(self, other):
 
42
        if hasattr(other, "value"):
 
43
            other = other.value
 
44
        return self.value < other
 
45
 
 
46
    def __ge__(self, other):
 
47
        return not self.__lt__(other)
 
48
 
 
49
    def __le__(self, other):
 
50
        if hasattr(other, "value"):
 
51
            other = other.value
 
52
        return self.value <= other
 
53
 
 
54
    def __gt__(self, other):
 
55
        return not self.__le__(other)
 
56
 
 
57
    def __repr__(self):
 
58
        return "<Comparable: %r>" % self.value
 
59
 
 
60
 
 
61
class ProxyTestCase(unittest.TestCase):
 
62
 
 
63
    proxy_class = ProxyBase
 
64
 
 
65
    def setUp(self):
 
66
        self.x = Thing()
 
67
        self.p = self.new_proxy(self.x)
 
68
 
 
69
    def new_proxy(self, o):
 
70
        return self.proxy_class(o)
 
71
 
 
72
    def test_constructor(self):
 
73
        o = object()
 
74
        self.assertRaises(TypeError, self.proxy_class, o, o)
 
75
        self.assertRaises(TypeError, self.proxy_class, o, key='value')
 
76
        self.assertRaises(TypeError, self.proxy_class, key='value')
 
77
 
 
78
    def test_subclass_constructor(self):
 
79
        class MyProxy(self.proxy_class):
 
80
            def __new__(cls, *args, **kwds):
 
81
                return super(MyProxy, cls).__new__(cls, *args, **kwds)
 
82
            def __init__(self, *args, **kwds):
 
83
                super(MyProxy, self).__init__(*args, **kwds)
 
84
        o1 = object()
 
85
        o2 = object()
 
86
        o = MyProxy((o1, o2))
 
87
 
 
88
        self.assertEquals(o1, o[0])
 
89
        self.assertEquals(o2, o[1])
 
90
 
 
91
        self.assertRaises(TypeError, MyProxy, o1, o2)
 
92
        self.assertRaises(TypeError, MyProxy, o1, key='value')
 
93
        self.assertRaises(TypeError, MyProxy, key='value')
 
94
 
 
95
        # Check that are passed to __init__() overrides what's passed
 
96
        # to __new__().
 
97
        class MyProxy2(self.proxy_class):
 
98
            def __new__(cls, *args, **kwds):
 
99
                return super(MyProxy2, cls).__new__(cls, 'value')
 
100
 
 
101
        p = MyProxy2('splat!')
 
102
        self.assertEquals(list(p), list('splat!'))
 
103
 
 
104
        class MyProxy3(MyProxy2):
 
105
            def __init__(self, arg):
 
106
                if list(self) != list('value'):
 
107
                    raise AssertionError("list(self) != list('value')")
 
108
                super(MyProxy3, self).__init__('another')
 
109
 
 
110
        p = MyProxy3('notused')
 
111
        self.assertEquals(list(p), list('another'))
 
112
 
 
113
    def test_proxy_attributes(self):
 
114
        o = Thing()
 
115
        o.foo = 1
 
116
        w = self.new_proxy(o)
 
117
        self.assert_(w.foo == 1)
 
118
 
 
119
    def test___class__(self):
 
120
        o = object()
 
121
        w = self.new_proxy(o)
 
122
        self.assert_(w.__class__ is o.__class__)
 
123
 
 
124
    def test_pickle_prevention(self):
 
125
        w = self.new_proxy(Thing())
 
126
        self.assertRaises(pickle.PicklingError,
 
127
                          pickle.dumps, w)
 
128
 
 
129
    def test_proxy_equality(self):
 
130
        w = self.new_proxy('foo')
 
131
        self.assertEquals(w, 'foo')
 
132
 
 
133
        o1 = Comparable(1)
 
134
        o2 = Comparable(1.0)
 
135
        o3 = Comparable("splat!")
 
136
 
 
137
        w1 = self.new_proxy(o1)
 
138
        w2 = self.new_proxy(o2)
 
139
        w3 = self.new_proxy(o3)
 
140
 
 
141
        self.assertEquals(o1, w1)
 
142
        self.assertEquals(o1, w2)
 
143
        self.assertEquals(o2, w1)
 
144
        self.assertEquals(w1, o2)
 
145
        self.assertEquals(w2, o1)
 
146
 
 
147
        self.assertNotEquals(o3, w1)
 
148
        self.assertNotEquals(w1, o3)
 
149
        self.assertNotEquals(w3, o1)
 
150
        self.assertNotEquals(o1, w3)
 
151
 
 
152
    def test_proxy_ordering_lt(self):
 
153
        o1 = Comparable(1)
 
154
        o2 = Comparable(2.0)
 
155
 
 
156
        w1 = self.new_proxy(o1)
 
157
        w2 = self.new_proxy(o2)
 
158
 
 
159
        self.assert_(w1 < w2)
 
160
        self.assert_(w1 <= w2)
 
161
        self.assert_(o1 < w2)
 
162
        self.assert_(o1 <= w2)
 
163
        self.assert_(w1 < o2)
 
164
        self.assert_(w2 <= o2)
 
165
 
 
166
    def test_proxy_callable(self):
 
167
        w = self.new_proxy({}.get)
 
168
        self.assert_(callable(w))
 
169
 
 
170
    def test_proxy_item_protocol(self):
 
171
        w = self.new_proxy({})
 
172
        self.assertRaises(KeyError, lambda: w[1])
 
173
        w[1] = 'a'
 
174
        self.assertEquals(w[1], 'a')
 
175
        del w[1]
 
176
        self.assertRaises(KeyError, lambda: w[1])
 
177
        def del_w_1():
 
178
            del w[1]
 
179
        self.assertRaises(KeyError, del_w_1)
 
180
 
 
181
    def test_wrapped_iterable(self):
 
182
        a = [1, 2, 3]
 
183
        b = []
 
184
        for x in self.new_proxy(a):
 
185
            b.append(x)
 
186
        self.assertEquals(a, b)
 
187
 
 
188
    def test_iteration_over_proxy(self):
 
189
        # Wrap an iterator before starting iteration.
 
190
        # PyObject_GetIter() will still be called on the proxy.
 
191
        a = [1, 2, 3]
 
192
        b = []
 
193
        for x in self.new_proxy(iter(a)):
 
194
            b.append(x)
 
195
        self.assertEquals(a, b)
 
196
        t = tuple(self.new_proxy(iter(a)))
 
197
        self.assertEquals(t, (1, 2, 3))
 
198
 
 
199
    def test_iteration_using_proxy(self):
 
200
        # Wrap an iterator within the iteration protocol, expecting it
 
201
        # still to work.  PyObject_GetIter() will not be called on the
 
202
        # proxy, so the tp_iter slot won't unwrap it.
 
203
 
 
204
        class Iterable(object):
 
205
            def __init__(self, test, data):
 
206
                self.test = test
 
207
                self.data = data
 
208
            def __iter__(self):
 
209
                return self.test.new_proxy(iter(self.data))
 
210
 
 
211
        a = [1, 2, 3]
 
212
        b = []
 
213
        for x in Iterable(self, a):
 
214
            b.append(x)
 
215
        self.assertEquals(a, b)
 
216
 
 
217
    def test_bool_wrapped_None(self):
 
218
        w = self.new_proxy(None)
 
219
        self.assertEquals(not w, 1)
 
220
 
 
221
    # Numeric ops.
 
222
 
 
223
    unops = [
 
224
        "-x", "+x", "abs(x)", "~x",
 
225
        "int(x)", "long(x)", "float(x)",
 
226
        ]
 
227
 
 
228
    def test_unops(self):
 
229
        P = self.new_proxy
 
230
        for expr in self.unops:
 
231
            x = 1
 
232
            y = eval(expr)
 
233
            x = P(1)
 
234
            z = eval(expr)
 
235
            self.assertEqual(z, y,
 
236
                             "x=%r; expr=%r" % (x, expr))
 
237
 
 
238
    def test_odd_unops(self):
 
239
        # unops that don't return a proxy
 
240
        P = self.new_proxy
 
241
        for func in hex, oct, lambda x: not x:
 
242
            self.assertEqual(func(P(100)), func(100))
 
243
 
 
244
    binops = [
 
245
        "x+y", "x-y", "x*y", "x/y", "divmod(x, y)", "x**y", "x//y",
 
246
        "x<<y", "x>>y", "x&y", "x|y", "x^y",
 
247
        ]
 
248
 
 
249
    def test_binops(self):
 
250
        P = self.new_proxy
 
251
        for expr in self.binops:
 
252
            first = 1
 
253
            for x in [1, P(1)]:
 
254
                for y in [2, P(2)]:
 
255
                    if first:
 
256
                        z = eval(expr)
 
257
                        first = 0
 
258
                    else:
 
259
                        self.assertEqual(eval(expr), z,
 
260
                                         "x=%r; y=%r; expr=%r" % (x, y, expr))
 
261
 
 
262
    def test_inplace(self):
 
263
        # TODO: should test all inplace operators...
 
264
        P = self.new_proxy
 
265
 
 
266
        pa = P(1)
 
267
        pa += 2
 
268
        self.assertEqual(pa, 3)
 
269
 
 
270
        a = [1, 2, 3]
 
271
        pa = qa = P(a)
 
272
        pa += [4, 5, 6]
 
273
        self.failUnless(pa is qa)
 
274
        self.assertEqual(a, [1, 2, 3, 4, 5, 6])
 
275
 
 
276
        pa = P(2)
 
277
        pa **= 2
 
278
        self.assertEqual(pa, 4)
 
279
 
 
280
    def test_coerce(self):
 
281
        P = self.new_proxy
 
282
 
 
283
        # Before 2.3, coerce() of two proxies returns them unchanged
 
284
        fixed_coerce = sys.version_info >= (2, 3, 0)
 
285
 
 
286
        x = P(1)
 
287
        y = P(2)
 
288
        a, b = coerce(x, y)
 
289
        self.failUnless(a is x and b is y)
 
290
 
 
291
        x = P(1)
 
292
        y = P(2.1)
 
293
        a, b = coerce(x, y)
 
294
        self.failUnless(a == 1.0)
 
295
        self.failUnless(b is y)
 
296
        if fixed_coerce:
 
297
            self.failUnless(a.__class__ is float, a.__class__)
 
298
 
 
299
        x = P(1.1)
 
300
        y = P(2)
 
301
        a, b = coerce(x, y)
 
302
        self.failUnless(a is x)
 
303
        self.failUnless(b == 2.0)
 
304
        if fixed_coerce:
 
305
            self.failUnless(b.__class__ is float, b.__class__)
 
306
 
 
307
        x = P(1)
 
308
        y = 2
 
309
        a, b = coerce(x, y)
 
310
        self.failUnless(a is x)
 
311
        self.failUnless(b is y)
 
312
 
 
313
        x = P(1)
 
314
        y = 2.1
 
315
        a, b = coerce(x, y)
 
316
        self.failUnless(a.__class__ is float, a.__class__)
 
317
        self.failUnless(b is y)
 
318
 
 
319
        x = P(1.1)
 
320
        y = 2
 
321
        a, b = coerce(x, y)
 
322
        self.failUnless(a is x)
 
323
        self.failUnless(b.__class__ is float, b.__class__)
 
324
 
 
325
        x = 1
 
326
        y = P(2)
 
327
        a, b = coerce(x, y)
 
328
        self.failUnless(a is x)
 
329
        self.failUnless(b is y)
 
330
 
 
331
        x = 1.1
 
332
        y = P(2)
 
333
        a, b = coerce(x, y)
 
334
        self.failUnless(a is x)
 
335
        self.failUnless(b.__class__ is float, b.__class__)
 
336
 
 
337
        x = 1
 
338
        y = P(2.1)
 
339
        a, b = coerce(x, y)
 
340
        self.failUnless(a.__class__ is float, a.__class__)
 
341
        self.failUnless(b is y)
 
342
 
 
343
    def test_getslice(self):
 
344
        # Lists have special slicing bahvior.
 
345
        pList = self.new_proxy([1, 2])
 
346
        self.assertEqual(pList[-1:], [2])
 
347
        self.assertEqual(pList[-2:], [1, 2])
 
348
        self.assertEqual(pList[-3:], [1, 2])
 
349
 
 
350
        # Tuples also have special slicing behavior.
 
351
        pTuple = self.new_proxy((1, 2))
 
352
        self.assertEqual(pTuple[-1:], (2,))
 
353
        self.assertEqual(pTuple[-2:], (1, 2))
 
354
        self.assertEqual(pTuple[-3:], (1, 2))
 
355
 
 
356
        # This behavior should be true for all list- and tuple-derived classes.
 
357
        class DerivedList(list):
 
358
 
 
359
            def __getslice__(self, start, end, step=None):
 
360
                return (start, end, step)
 
361
 
 
362
        pList = self.new_proxy(DerivedList([1, 2]))
 
363
        self.assertEqual(pList[-1:], [2])
 
364
        self.assertEqual(pList[-2:], [1, 2])
 
365
        self.assertEqual(pList[-3:], [1, 2])
 
366
 
 
367
        # Another sort of sequence has a different slicing interpretation.
 
368
        class Slicer(object):
 
369
 
 
370
            def __len__(self):
 
371
                return 2
 
372
 
 
373
            def __getslice__(self, start, end, step=None):
 
374
                return (start, end, step)
 
375
 
 
376
        pSlicer = self.new_proxy(Slicer())
 
377
        self.assertEqual(pSlicer[-1:][0], 1)
 
378
        self.assertEqual(pSlicer[-2:][0], 0)
 
379
        # Note that for non-lists and non-tuples the slice is computed
 
380
        # differently
 
381
        self.assertEqual(pSlicer[-3:][0], 1)
 
382
 
 
383
    def test_setslice(self):
 
384
        # Lists have special slicing bahvior for assignment as well.
 
385
        pList = self.new_proxy([1, 2])
 
386
        pList[-1:] = [3, 4]
 
387
        self.assertEqual(pList, [1, 3, 4])
 
388
        pList = self.new_proxy([1, 2])
 
389
        pList[-2:] = [3, 4]
 
390
        self.assertEqual(pList, [3, 4])
 
391
        pList = self.new_proxy([1, 2])
 
392
        pList[-3:] = [3, 4]
 
393
        self.assertEqual(pList, [3, 4])
 
394
 
 
395
        # This behavior should be true for all list-derived classes.
 
396
        class DerivedList(list):
 
397
            pass
 
398
 
 
399
        pList = self.new_proxy(DerivedList([1, 2]))
 
400
        pList[-1:] = [3, 4]
 
401
        self.assertEqual(pList, [1, 3, 4])
 
402
        pList = self.new_proxy(DerivedList([1, 2]))
 
403
        pList[-2:] = [3, 4]
 
404
        self.assertEqual(pList, [3, 4])
 
405
        pList = self.new_proxy(DerivedList([1, 2]))
 
406
        pList[-3:] = [3, 4]
 
407
        self.assertEqual(pList, [3, 4])
 
408
 
 
409
 
 
410
def test_isProxy():
 
411
    """
 
412
    >>> from zope.proxy import ProxyBase, isProxy
 
413
    >>> class P1(ProxyBase):
 
414
    ...     pass
 
415
    >>> class P2(ProxyBase):
 
416
    ...     pass
 
417
    >>> class C(object):
 
418
    ...     pass
 
419
    >>> c = C()
 
420
    >>> int(isProxy(c))
 
421
    0
 
422
    >>> p = P1(c)
 
423
    >>> int(isProxy(p))
 
424
    1
 
425
    >>> int(isProxy(p, P1))
 
426
    1
 
427
    >>> int(isProxy(p, P2))
 
428
    0
 
429
    >>> p = P2(p)
 
430
    >>> int(isProxy(p, P1))
 
431
    1
 
432
    >>> int(isProxy(p, P2))
 
433
    1
 
434
 
 
435
    """
 
436
 
 
437
def test_getProxiedObject():
 
438
    """
 
439
    >>> from zope.proxy import ProxyBase, getProxiedObject
 
440
    >>> class C(object):
 
441
    ...     pass
 
442
    >>> c = C()
 
443
    >>> int(getProxiedObject(c) is c)
 
444
    1
 
445
    >>> p = ProxyBase(c)
 
446
    >>> int(getProxiedObject(p) is c)
 
447
    1
 
448
    >>> p2 = ProxyBase(p)
 
449
    >>> int(getProxiedObject(p2) is p)
 
450
    1
 
451
 
 
452
    """
 
453
 
 
454
def test_ProxyIterator():
 
455
    """
 
456
    >>> from zope.proxy import ProxyBase, ProxyIterator
 
457
    >>> class C(object):
 
458
    ...     pass
 
459
    >>> c = C()
 
460
    >>> p1 = ProxyBase(c)
 
461
    >>> class P(ProxyBase):
 
462
    ...     pass
 
463
    >>> p2 = P(p1)
 
464
    >>> p3 = ProxyBase(p2)
 
465
    >>> list(ProxyIterator(p3)) == [p3, p2, p1, c]
 
466
    1
 
467
    """
 
468
 
 
469
def test_removeAllProxies():
 
470
    """
 
471
    >>> from zope.proxy import ProxyBase, removeAllProxies
 
472
    >>> class C(object):
 
473
    ...     pass
 
474
    >>> c = C()
 
475
    >>> int(removeAllProxies(c) is c)
 
476
    1
 
477
    >>> p = ProxyBase(c)
 
478
    >>> int(removeAllProxies(p) is c)
 
479
    1
 
480
    >>> p2 = ProxyBase(p)
 
481
    >>> int(removeAllProxies(p2) is c)
 
482
    1
 
483
 
 
484
    """
 
485
 
 
486
def test_queryProxy():
 
487
    """
 
488
    >>> from zope.proxy import ProxyBase, queryProxy
 
489
    >>> class P1(ProxyBase):
 
490
    ...    pass
 
491
    >>> class P2(ProxyBase):
 
492
    ...    pass
 
493
    >>> class C(object):
 
494
    ...     pass
 
495
    >>> c = C()
 
496
    >>> queryProxy(c, P1)
 
497
    >>> queryProxy(c, P1, 42)
 
498
    42
 
499
    >>> p1 = P1(c)
 
500
    >>> int(queryProxy(p1, P1) is p1)
 
501
    1
 
502
    >>> queryProxy(c, P2)
 
503
    >>> queryProxy(c, P2, 42)
 
504
    42
 
505
    >>> p2 = P2(p1)
 
506
    >>> int(queryProxy(p2, P1) is p1)
 
507
    1
 
508
    >>> int(queryProxy(p2, P2) is p2)
 
509
    1
 
510
    >>> int(queryProxy(p2, ProxyBase) is p2)
 
511
    1
 
512
    
 
513
    """
 
514
 
 
515
def test_queryInnerProxy():
 
516
    """
 
517
    >>> from zope.proxy import ProxyBase, queryProxy, queryInnerProxy
 
518
    >>> class P1(ProxyBase):
 
519
    ...    pass
 
520
    >>> class P2(ProxyBase):
 
521
    ...    pass
 
522
    >>> class C(object):
 
523
    ...     pass
 
524
    >>> c = C()
 
525
    >>> queryInnerProxy(c, P1)
 
526
    >>> queryInnerProxy(c, P1, 42)
 
527
    42
 
528
    >>> p1 = P1(c)
 
529
    >>> int(queryProxy(p1, P1) is p1)
 
530
    1
 
531
    >>> queryInnerProxy(c, P2)
 
532
    >>> queryInnerProxy(c, P2, 42)
 
533
    42
 
534
    >>> p2 = P2(p1)
 
535
    >>> int(queryInnerProxy(p2, P1) is p1)
 
536
    1
 
537
    >>> int(queryInnerProxy(p2, P2) is p2)
 
538
    1
 
539
    >>> int(queryInnerProxy(p2, ProxyBase) is p1)
 
540
    1
 
541
 
 
542
    >>> p3 = P1(p2)
 
543
    >>> int(queryProxy(p3, P1) is p3)
 
544
    1
 
545
    >>> int(queryInnerProxy(p3, P1) is p1)
 
546
    1
 
547
    >>> int(queryInnerProxy(p3, P2) is p2)
 
548
    1
 
549
    
 
550
    """
 
551
 
 
552
def test_sameProxiedObjects():
 
553
    """
 
554
    >>> from zope.proxy import ProxyBase, sameProxiedObjects
 
555
    >>> class C(object):
 
556
    ...     pass
 
557
    >>> c1 = C()
 
558
    >>> c2 = C()
 
559
    >>> int(sameProxiedObjects(c1, c1))
 
560
    1
 
561
    >>> int(sameProxiedObjects(ProxyBase(c1), c1))
 
562
    1
 
563
    >>> int(sameProxiedObjects(ProxyBase(c1), ProxyBase(c1)))
 
564
    1
 
565
    >>> int(sameProxiedObjects(ProxyBase(ProxyBase(c1)), c1))
 
566
    1
 
567
    >>> int(sameProxiedObjects(c1, ProxyBase(c1)))
 
568
    1
 
569
    >>> int(sameProxiedObjects(c1, ProxyBase(ProxyBase(c1))))
 
570
    1
 
571
    >>> int(sameProxiedObjects(c1, c2))
 
572
    0
 
573
    >>> int(sameProxiedObjects(ProxyBase(c1), c2))
 
574
    0
 
575
    >>> int(sameProxiedObjects(ProxyBase(c1), ProxyBase(c2)))
 
576
    0
 
577
    >>> int(sameProxiedObjects(ProxyBase(ProxyBase(c1)), c2))
 
578
    0
 
579
    >>> int(sameProxiedObjects(c1, ProxyBase(c2)))
 
580
    0
 
581
    >>> int(sameProxiedObjects(c1, ProxyBase(ProxyBase(c2))))
 
582
    0
 
583
    """
 
584
 
 
585
def test_subclassing_proxies():
 
586
    """You can subclass ProxyBase
 
587
 
 
588
    If you subclass a proxy, instances of the subclass have access to
 
589
    data defined in the class, including descriptors.
 
590
 
 
591
    Your subclass instances don't get instance dictionaries, but they
 
592
    can have slots.
 
593
 
 
594
    >>> class MyProxy(ProxyBase):
 
595
    ...    __slots__ = 'x', 'y'
 
596
    ...
 
597
    ...    def f(self):
 
598
    ...        return self.x
 
599
 
 
600
    >>> l = [1, 2, 3]
 
601
    >>> p = MyProxy(l)
 
602
 
 
603
    I can use attributes defined by the class, including slots:
 
604
    
 
605
    >>> p.x = 'x'
 
606
    >>> p.x
 
607
    'x'
 
608
    >>> p.f()
 
609
    'x'
 
610
 
 
611
    I can also use attributes of the proxied object:
 
612
    
 
613
    >>> p
 
614
    [1, 2, 3]
 
615
    >>> p.pop()
 
616
    3
 
617
    >>> p
 
618
    [1, 2]
 
619
    
 
620
    """
 
621
 
 
622
def test_get_descriptors_in_proxy_class():
 
623
    """
 
624
    A non-data descriptor in a proxy class doesn't hide an attribute on
 
625
    a proxied object or prevent writing the attribute.
 
626
 
 
627
    >>> class ReadDescr(object):
 
628
    ...     def __get__(self, i, c):
 
629
    ...         return 'read'
 
630
 
 
631
    >>> class MyProxy(ProxyBase):
 
632
    ...    __slots__ = ()
 
633
    ...
 
634
    ...    z = ReadDescr()
 
635
    ...    q = ReadDescr()
 
636
 
 
637
    >>> class MyOb:
 
638
    ...    q = 1
 
639
 
 
640
    >>> o = MyOb()
 
641
    >>> p = MyProxy(o)
 
642
    >>> p.q
 
643
    1
 
644
 
 
645
    >>> p.z
 
646
    'read'
 
647
 
 
648
    >>> p.z = 1
 
649
    >>> o.z, p.z
 
650
    (1, 1)
 
651
    
 
652
    """
 
653
 
 
654
def test_non_overridable():
 
655
    """
 
656
    Normally, methods defined in proxies are overridden by
 
657
    methods of proxied objects.  This applies to all non-data
 
658
    descriptors.  The non_overridable function can be used to
 
659
    convert a non-data descriptor to a data descriptor that disallows
 
660
    writes.  This function can be used as a decorator to make functions
 
661
    defined in proxy classes take precedence over functions defined
 
662
    in proxied objects.
 
663
 
 
664
    
 
665
    >>> class MyProxy(ProxyBase):
 
666
    ...    __slots__ = ()
 
667
    ...
 
668
    ...    @zope.proxy.non_overridable
 
669
    ...    def foo(self):
 
670
    ...        return 'MyProxy foo'
 
671
 
 
672
    >>> class MyOb:
 
673
    ...    def foo(self):
 
674
    ...        return 'MyOb foo'
 
675
 
 
676
    >>> o = MyOb()
 
677
    >>> p = MyProxy(o)
 
678
    >>> p.foo()
 
679
    'MyProxy foo'
 
680
    
 
681
    """
 
682
 
 
683
def test_setProxiedObject():
 
684
    """
 
685
    >>> from zope.proxy import ProxyBase
 
686
    >>> from zope.proxy import setProxiedObject, getProxiedObject
 
687
 
 
688
    >>> class C(object):
 
689
    ...     pass
 
690
 
 
691
    >>> c1 = C()
 
692
    >>> c2 = C()
 
693
 
 
694
    >>> p = ProxyBase(c1)
 
695
 
 
696
    `setProxiedObject()` allows us to change the object a proxy refers to,
 
697
    returning the previous referent:
 
698
 
 
699
    >>> old = setProxiedObject(p, c2)
 
700
    >>> old is c1
 
701
    True
 
702
 
 
703
    >>> getProxiedObject(p) is c2
 
704
    True
 
705
 
 
706
    The first argument  to `setProxiedObject()` must be a proxy; other objects
 
707
    cause it to raise an exception:
 
708
 
 
709
    >>> setProxiedObject(c1, None)
 
710
    Traceback (most recent call last):
 
711
    TypeError: setProxiedObject() argument 1 must be zope.proxy.ProxyBase, not C
 
712
 
 
713
    """
 
714
 
 
715
def test_suite():
 
716
    suite = unittest.makeSuite(ProxyTestCase)
 
717
    suite.addTest(DocTestSuite())
 
718
    return suite
 
719
 
 
720
if __name__ == "__main__":
 
721
    runner = unittest.TextTestRunner(sys.stdout)
 
722
    result = runner.run(test_suite())
 
723
    newerrs = len(result.errors) + len(result.failures)
 
724
    sys.exit(newerrs and 1 or 0)