1import copy
2import sys
3
4from sqlalchemy import util, sql, exc, testing
5from sqlalchemy.testing import assert_raises, assert_raises_message, fixtures
6from sqlalchemy.testing import eq_, is_, ne_, fails_if, mock, expect_warnings
7from sqlalchemy.testing.util import picklers, gc_collect
8from sqlalchemy.util import classproperty, WeakSequence, get_callable_argspec
9from sqlalchemy.sql import column
10from sqlalchemy.util import langhelpers, compat
11import inspect
12
13
14class _KeyedTupleTest(object):
15
16    def _fixture(self, values, labels):
17        raise NotImplementedError()
18
19    def test_empty(self):
20        keyed_tuple = self._fixture([], [])
21        eq_(str(keyed_tuple), '()')
22        eq_(len(keyed_tuple), 0)
23
24        eq_(list(keyed_tuple.keys()), [])
25        eq_(keyed_tuple._fields, ())
26        eq_(keyed_tuple._asdict(), {})
27
28    def test_values_but_no_labels(self):
29        keyed_tuple = self._fixture([1, 2], [])
30        eq_(str(keyed_tuple), '(1, 2)')
31        eq_(len(keyed_tuple), 2)
32
33        eq_(list(keyed_tuple.keys()), [])
34        eq_(keyed_tuple._fields, ())
35        eq_(keyed_tuple._asdict(), {})
36
37        eq_(keyed_tuple[0], 1)
38        eq_(keyed_tuple[1], 2)
39
40    def test_basic_creation(self):
41        keyed_tuple = self._fixture([1, 2], ['a', 'b'])
42        eq_(str(keyed_tuple), '(1, 2)')
43        eq_(list(keyed_tuple.keys()), ['a', 'b'])
44        eq_(keyed_tuple._fields, ('a', 'b'))
45        eq_(keyed_tuple._asdict(), {'a': 1, 'b': 2})
46
47    def test_basic_index_access(self):
48        keyed_tuple = self._fixture([1, 2], ['a', 'b'])
49        eq_(keyed_tuple[0], 1)
50        eq_(keyed_tuple[1], 2)
51
52        def should_raise():
53            keyed_tuple[2]
54        assert_raises(IndexError, should_raise)
55
56    def test_basic_attribute_access(self):
57        keyed_tuple = self._fixture([1, 2], ['a', 'b'])
58        eq_(keyed_tuple.a, 1)
59        eq_(keyed_tuple.b, 2)
60
61        def should_raise():
62            keyed_tuple.c
63        assert_raises(AttributeError, should_raise)
64
65    def test_none_label(self):
66        keyed_tuple = self._fixture([1, 2, 3], ['a', None, 'b'])
67        eq_(str(keyed_tuple), '(1, 2, 3)')
68
69        eq_(list(keyed_tuple.keys()), ['a', 'b'])
70        eq_(keyed_tuple._fields, ('a', 'b'))
71        eq_(keyed_tuple._asdict(), {'a': 1, 'b': 3})
72
73        # attribute access: can't get at value 2
74        eq_(keyed_tuple.a, 1)
75        eq_(keyed_tuple.b, 3)
76
77        # index access: can get at value 2
78        eq_(keyed_tuple[0], 1)
79        eq_(keyed_tuple[1], 2)
80        eq_(keyed_tuple[2], 3)
81
82    def test_duplicate_labels(self):
83        keyed_tuple = self._fixture([1, 2, 3], ['a', 'b', 'b'])
84        eq_(str(keyed_tuple), '(1, 2, 3)')
85
86        eq_(list(keyed_tuple.keys()), ['a', 'b', 'b'])
87        eq_(keyed_tuple._fields, ('a', 'b', 'b'))
88        eq_(keyed_tuple._asdict(), {'a': 1, 'b': 3})
89
90        # attribute access: can't get at value 2
91        eq_(keyed_tuple.a, 1)
92        eq_(keyed_tuple.b, 3)
93
94        # index access: can get at value 2
95        eq_(keyed_tuple[0], 1)
96        eq_(keyed_tuple[1], 2)
97        eq_(keyed_tuple[2], 3)
98
99    def test_immutable(self):
100        keyed_tuple = self._fixture([1, 2], ['a', 'b'])
101        eq_(str(keyed_tuple), '(1, 2)')
102
103        eq_(keyed_tuple.a, 1)
104
105        assert_raises(AttributeError, setattr, keyed_tuple, "a", 5)
106
107        def should_raise():
108            keyed_tuple[0] = 100
109        assert_raises(TypeError, should_raise)
110
111    def test_serialize(self):
112
113        keyed_tuple = self._fixture([1, 2, 3], ['a', None, 'b'])
114
115        for loads, dumps in picklers():
116            kt = loads(dumps(keyed_tuple))
117
118            eq_(str(kt), '(1, 2, 3)')
119
120            eq_(list(kt.keys()), ['a', 'b'])
121            eq_(kt._fields, ('a', 'b'))
122            eq_(kt._asdict(), {'a': 1, 'b': 3})
123
124
125class KeyedTupleTest(_KeyedTupleTest, fixtures.TestBase):
126    def _fixture(self, values, labels):
127        return util.KeyedTuple(values, labels)
128
129
130class LWKeyedTupleTest(_KeyedTupleTest, fixtures.TestBase):
131    def _fixture(self, values, labels):
132        return util.lightweight_named_tuple('n', labels)(values)
133
134
135class WeakSequenceTest(fixtures.TestBase):
136    @testing.requires.predictable_gc
137    def test_cleanout_elements(self):
138        class Foo(object):
139            pass
140        f1, f2, f3 = Foo(), Foo(), Foo()
141        w = WeakSequence([f1, f2, f3])
142        eq_(len(w), 3)
143        eq_(len(w._storage), 3)
144        del f2
145        gc_collect()
146        eq_(len(w), 2)
147        eq_(len(w._storage), 2)
148
149    @testing.requires.predictable_gc
150    def test_cleanout_appended(self):
151        class Foo(object):
152            pass
153        f1, f2, f3 = Foo(), Foo(), Foo()
154        w = WeakSequence()
155        w.append(f1)
156        w.append(f2)
157        w.append(f3)
158        eq_(len(w), 3)
159        eq_(len(w._storage), 3)
160        del f2
161        gc_collect()
162        eq_(len(w), 2)
163        eq_(len(w._storage), 2)
164
165
166class OrderedDictTest(fixtures.TestBase):
167
168    def test_odict(self):
169        o = util.OrderedDict()
170        o['a'] = 1
171        o['b'] = 2
172        o['snack'] = 'attack'
173        o['c'] = 3
174
175        eq_(list(o.keys()), ['a', 'b', 'snack', 'c'])
176        eq_(list(o.values()), [1, 2, 'attack', 3])
177
178        o.pop('snack')
179        eq_(list(o.keys()), ['a', 'b', 'c'])
180        eq_(list(o.values()), [1, 2, 3])
181
182        try:
183            o.pop('eep')
184            assert False
185        except KeyError:
186            pass
187
188        eq_(o.pop('eep', 'woot'), 'woot')
189
190        try:
191            o.pop('whiff', 'bang', 'pow')
192            assert False
193        except TypeError:
194            pass
195
196        eq_(list(o.keys()), ['a', 'b', 'c'])
197        eq_(list(o.values()), [1, 2, 3])
198
199        o2 = util.OrderedDict(d=4)
200        o2['e'] = 5
201
202        eq_(list(o2.keys()), ['d', 'e'])
203        eq_(list(o2.values()), [4, 5])
204
205        o.update(o2)
206        eq_(list(o.keys()), ['a', 'b', 'c', 'd', 'e'])
207        eq_(list(o.values()), [1, 2, 3, 4, 5])
208
209        o.setdefault('c', 'zzz')
210        o.setdefault('f', 6)
211        eq_(list(o.keys()), ['a', 'b', 'c', 'd', 'e', 'f'])
212        eq_(list(o.values()), [1, 2, 3, 4, 5, 6])
213
214    def test_odict_constructor(self):
215        o = util.OrderedDict([('name', 'jbe'),
216                              ('fullname', 'jonathan'), ('password', '')])
217        eq_(list(o.keys()), ['name', 'fullname', 'password'])
218
219    def test_odict_copy(self):
220        o = util.OrderedDict()
221        o["zzz"] = 1
222        o["aaa"] = 2
223        eq_(list(o.keys()), ['zzz', 'aaa'])
224
225        o2 = o.copy()
226        eq_(list(o2.keys()), list(o.keys()))
227
228        o3 = copy.copy(o)
229        eq_(list(o3.keys()), list(o.keys()))
230
231
232class OrderedSetTest(fixtures.TestBase):
233
234    def test_mutators_against_iter(self):
235        # testing a set modified against an iterator
236        o = util.OrderedSet([3, 2, 4, 5])
237
238        eq_(o.difference(iter([3, 4])), util.OrderedSet([2, 5]))
239        eq_(o.intersection(iter([3, 4, 6])), util.OrderedSet([3, 4]))
240        eq_(o.union(iter([3, 4, 6])), util.OrderedSet([2, 3, 4, 5, 6]))
241
242
243class FrozenDictTest(fixtures.TestBase):
244
245    def test_serialize(self):
246        d = util.immutabledict({1: 2, 3: 4})
247        for loads, dumps in picklers():
248            print(loads(dumps(d)))
249
250
251class MemoizedAttrTest(fixtures.TestBase):
252
253    def test_memoized_property(self):
254        val = [20]
255
256        class Foo(object):
257            @util.memoized_property
258            def bar(self):
259                v = val[0]
260                val[0] += 1
261                return v
262
263        ne_(Foo.bar, None)
264        f1 = Foo()
265        assert 'bar' not in f1.__dict__
266        eq_(f1.bar, 20)
267        eq_(f1.bar, 20)
268        eq_(val[0], 21)
269        eq_(f1.__dict__['bar'], 20)
270
271    def test_memoized_instancemethod(self):
272        val = [20]
273
274        class Foo(object):
275            @util.memoized_instancemethod
276            def bar(self):
277                v = val[0]
278                val[0] += 1
279                return v
280
281        assert inspect.ismethod(Foo().bar)
282        ne_(Foo.bar, None)
283        f1 = Foo()
284        assert 'bar' not in f1.__dict__
285        eq_(f1.bar(), 20)
286        eq_(f1.bar(), 20)
287        eq_(val[0], 21)
288
289    def test_memoized_slots(self):
290        canary = mock.Mock()
291
292        class Foob(util.MemoizedSlots):
293            __slots__ = ('foo_bar', 'gogo')
294
295            def _memoized_method_gogo(self):
296                canary.method()
297                return "gogo"
298
299            def _memoized_attr_foo_bar(self):
300                canary.attr()
301                return "foobar"
302
303        f1 = Foob()
304        assert_raises(AttributeError, setattr, f1, "bar", "bat")
305
306        eq_(f1.foo_bar, "foobar")
307
308        eq_(f1.foo_bar, "foobar")
309
310        eq_(f1.gogo(), "gogo")
311
312        eq_(f1.gogo(), "gogo")
313
314        eq_(canary.mock_calls, [mock.call.attr(), mock.call.method()])
315
316
317class WrapCallableTest(fixtures.TestBase):
318    def test_wrapping_update_wrapper_fn(self):
319        def my_fancy_default():
320            """run the fancy default"""
321            return 10
322
323        c = util.wrap_callable(lambda: my_fancy_default, my_fancy_default)
324
325        eq_(c.__name__, "my_fancy_default")
326        eq_(c.__doc__, "run the fancy default")
327
328    def test_wrapping_update_wrapper_fn_nodocstring(self):
329        def my_fancy_default():
330            return 10
331
332        c = util.wrap_callable(lambda: my_fancy_default, my_fancy_default)
333        eq_(c.__name__, "my_fancy_default")
334        eq_(c.__doc__, None)
335
336    def test_wrapping_update_wrapper_cls(self):
337        class MyFancyDefault(object):
338            """a fancy default"""
339
340            def __call__(self):
341                """run the fancy default"""
342                return 10
343
344        def_ = MyFancyDefault()
345        c = util.wrap_callable(lambda: def_(), def_)
346
347        eq_(c.__name__, "MyFancyDefault")
348        eq_(c.__doc__, "run the fancy default")
349
350    def test_wrapping_update_wrapper_cls_noclsdocstring(self):
351        class MyFancyDefault(object):
352
353            def __call__(self):
354                """run the fancy default"""
355                return 10
356
357        def_ = MyFancyDefault()
358        c = util.wrap_callable(lambda: def_(), def_)
359        eq_(c.__name__, "MyFancyDefault")
360        eq_(c.__doc__, "run the fancy default")
361
362    def test_wrapping_update_wrapper_cls_nomethdocstring(self):
363        class MyFancyDefault(object):
364            """a fancy default"""
365
366            def __call__(self):
367                return 10
368
369        def_ = MyFancyDefault()
370        c = util.wrap_callable(lambda: def_(), def_)
371        eq_(c.__name__, "MyFancyDefault")
372        eq_(c.__doc__, "a fancy default")
373
374    def test_wrapping_update_wrapper_cls_noclsdocstring_nomethdocstring(self):
375        class MyFancyDefault(object):
376
377            def __call__(self):
378                return 10
379
380        def_ = MyFancyDefault()
381        c = util.wrap_callable(lambda: def_(), def_)
382        eq_(c.__name__, "MyFancyDefault")
383        eq_(c.__doc__, None)
384
385    def test_wrapping_update_wrapper_functools_parial(self):
386        def my_default(x):
387            return x
388
389        import functools
390        my_functools_default = functools.partial(my_default, 5)
391
392        c = util.wrap_callable(
393            lambda: my_functools_default(), my_functools_default)
394        eq_(c.__name__, "partial")
395        eq_(c.__doc__, my_functools_default.__call__.__doc__)
396        eq_(c(), 5)
397
398
399class ToListTest(fixtures.TestBase):
400    def test_from_string(self):
401        eq_(
402            util.to_list("xyz"),
403            ["xyz"]
404        )
405
406    def test_from_set(self):
407        spec = util.to_list(set([1, 2, 3]))
408        assert isinstance(spec, list)
409        eq_(
410            sorted(spec),
411            [1, 2, 3]
412        )
413
414    def test_from_dict(self):
415        spec = util.to_list({1: "a", 2: "b", 3: "c"})
416        assert isinstance(spec, list)
417        eq_(
418            sorted(spec),
419            [1, 2, 3]
420        )
421
422    def test_from_tuple(self):
423        eq_(
424            util.to_list((1, 2, 3)),
425            [1, 2, 3]
426        )
427
428    def test_from_bytes(self):
429
430        eq_(
431            util.to_list(compat.b('abc')),
432            [compat.b('abc')]
433        )
434
435        eq_(
436            util.to_list([
437                compat.b('abc'), compat.b('def')]),
438            [compat.b('abc'), compat.b('def')]
439        )
440
441
442class ColumnCollectionTest(fixtures.TestBase):
443
444    def test_in(self):
445        cc = sql.ColumnCollection()
446        cc.add(sql.column('col1'))
447        cc.add(sql.column('col2'))
448        cc.add(sql.column('col3'))
449        assert 'col1' in cc
450        assert 'col2' in cc
451
452        try:
453            cc['col1'] in cc
454            assert False
455        except exc.ArgumentError as e:
456            eq_(str(e), "__contains__ requires a string argument")
457
458    def test_compare(self):
459        cc1 = sql.ColumnCollection()
460        cc2 = sql.ColumnCollection()
461        cc3 = sql.ColumnCollection()
462        c1 = sql.column('col1')
463        c2 = c1.label('col2')
464        c3 = sql.column('col3')
465        cc1.add(c1)
466        cc2.add(c2)
467        cc3.add(c3)
468        assert (cc1 == cc2).compare(c1 == c2)
469        assert not (cc1 == cc3).compare(c2 == c3)
470
471    @testing.emits_warning("Column ")
472    def test_dupes_add(self):
473        cc = sql.ColumnCollection()
474
475        c1, c2a, c3, c2b = (column('c1'),
476                            column('c2'),
477                            column('c3'),
478                            column('c2'))
479
480        cc.add(c1)
481        cc.add(c2a)
482        cc.add(c3)
483        cc.add(c2b)
484
485        eq_(cc._all_columns, [c1, c2a, c3, c2b])
486
487        # for iter, c2a is replaced by c2b, ordering
488        # is maintained in that way.  ideally, iter would be
489        # the same as the "_all_columns" collection.
490        eq_(list(cc), [c1, c2b, c3])
491
492        assert cc.contains_column(c2a)
493        assert cc.contains_column(c2b)
494
495        ci = cc.as_immutable()
496        eq_(ci._all_columns, [c1, c2a, c3, c2b])
497        eq_(list(ci), [c1, c2b, c3])
498
499    def test_replace(self):
500        cc = sql.ColumnCollection()
501
502        c1, c2a, c3, c2b = (column('c1'),
503                            column('c2'),
504                            column('c3'),
505                            column('c2'))
506
507        cc.add(c1)
508        cc.add(c2a)
509        cc.add(c3)
510
511        cc.replace(c2b)
512
513        eq_(cc._all_columns, [c1, c2b, c3])
514        eq_(list(cc), [c1, c2b, c3])
515
516        assert not cc.contains_column(c2a)
517        assert cc.contains_column(c2b)
518
519        ci = cc.as_immutable()
520        eq_(ci._all_columns, [c1, c2b, c3])
521        eq_(list(ci), [c1, c2b, c3])
522
523    def test_replace_key_matches(self):
524        cc = sql.ColumnCollection()
525
526        c1, c2a, c3, c2b = (column('c1'),
527                            column('c2'),
528                            column('c3'),
529                            column('X'))
530        c2b.key = 'c2'
531
532        cc.add(c1)
533        cc.add(c2a)
534        cc.add(c3)
535
536        cc.replace(c2b)
537
538        assert not cc.contains_column(c2a)
539        assert cc.contains_column(c2b)
540
541        eq_(cc._all_columns, [c1, c2b, c3])
542        eq_(list(cc), [c1, c2b, c3])
543
544        ci = cc.as_immutable()
545        eq_(ci._all_columns, [c1, c2b, c3])
546        eq_(list(ci), [c1, c2b, c3])
547
548    def test_replace_name_matches(self):
549        cc = sql.ColumnCollection()
550
551        c1, c2a, c3, c2b = (column('c1'),
552                            column('c2'),
553                            column('c3'),
554                            column('c2'))
555        c2b.key = 'X'
556
557        cc.add(c1)
558        cc.add(c2a)
559        cc.add(c3)
560
561        cc.replace(c2b)
562
563        assert not cc.contains_column(c2a)
564        assert cc.contains_column(c2b)
565
566        eq_(cc._all_columns, [c1, c2b, c3])
567        eq_(list(cc), [c1, c3, c2b])
568
569        ci = cc.as_immutable()
570        eq_(ci._all_columns, [c1, c2b, c3])
571        eq_(list(ci), [c1, c3, c2b])
572
573    def test_replace_no_match(self):
574        cc = sql.ColumnCollection()
575
576        c1, c2, c3, c4 = column('c1'), column('c2'), column('c3'), column('c4')
577        c4.key = 'X'
578
579        cc.add(c1)
580        cc.add(c2)
581        cc.add(c3)
582
583        cc.replace(c4)
584
585        assert cc.contains_column(c2)
586        assert cc.contains_column(c4)
587
588        eq_(cc._all_columns, [c1, c2, c3, c4])
589        eq_(list(cc), [c1, c2, c3, c4])
590
591        ci = cc.as_immutable()
592        eq_(ci._all_columns, [c1, c2, c3, c4])
593        eq_(list(ci), [c1, c2, c3, c4])
594
595    def test_dupes_extend(self):
596        cc = sql.ColumnCollection()
597
598        c1, c2a, c3, c2b = (column('c1'),
599                            column('c2'),
600                            column('c3'),
601                            column('c2'))
602
603        cc.add(c1)
604        cc.add(c2a)
605
606        cc.extend([c3, c2b])
607
608        eq_(cc._all_columns, [c1, c2a, c3, c2b])
609
610        # for iter, c2a is replaced by c2b, ordering
611        # is maintained in that way.  ideally, iter would be
612        # the same as the "_all_columns" collection.
613        eq_(list(cc), [c1, c2b, c3])
614
615        assert cc.contains_column(c2a)
616        assert cc.contains_column(c2b)
617
618        ci = cc.as_immutable()
619        eq_(ci._all_columns, [c1, c2a, c3, c2b])
620        eq_(list(ci), [c1, c2b, c3])
621
622    def test_dupes_update(self):
623        cc = sql.ColumnCollection()
624
625        c1, c2a, c3, c2b = (column('c1'),
626                            column('c2'),
627                            column('c3'),
628                            column('c2'))
629
630        cc.add(c1)
631        cc.add(c2a)
632
633        cc.update([(c3.key, c3), (c2b.key, c2b)])
634
635        eq_(cc._all_columns, [c1, c2a, c3, c2b])
636
637        assert cc.contains_column(c2a)
638        assert cc.contains_column(c2b)
639
640        # for iter, c2a is replaced by c2b, ordering
641        # is maintained in that way.  ideally, iter would be
642        # the same as the "_all_columns" collection.
643        eq_(list(cc), [c1, c2b, c3])
644
645    def test_extend_existing(self):
646        cc = sql.ColumnCollection()
647
648        c1, c2, c3, c4, c5 = (column('c1'),
649                              column('c2'),
650                              column('c3'),
651                              column('c4'),
652                              column('c5'))
653
654        cc.extend([c1, c2])
655        eq_(cc._all_columns, [c1, c2])
656
657        cc.extend([c3])
658        eq_(cc._all_columns, [c1, c2, c3])
659        cc.extend([c4, c2, c5])
660
661        eq_(cc._all_columns, [c1, c2, c3, c4, c5])
662
663    def test_update_existing(self):
664        cc = sql.ColumnCollection()
665
666        c1, c2, c3, c4, c5 = (column('c1'),
667                              column('c2'),
668                              column('c3'),
669                              column('c4'),
670                              column('c5'))
671
672        cc.update([('c1', c1), ('c2', c2)])
673        eq_(cc._all_columns, [c1, c2])
674
675        cc.update([('c3', c3)])
676        eq_(cc._all_columns, [c1, c2, c3])
677        cc.update([('c4', c4), ('c2', c2), ('c5', c5)])
678
679        eq_(cc._all_columns, [c1, c2, c3, c4, c5])
680
681
682class LRUTest(fixtures.TestBase):
683
684    def test_lru(self):
685        class item(object):
686            def __init__(self, id):
687                self.id = id
688
689            def __str__(self):
690                return "item id %d" % self.id
691
692        lru = util.LRUCache(10, threshold=.2)
693
694        for id in range(1, 20):
695            lru[id] = item(id)
696
697        # first couple of items should be gone
698        assert 1 not in lru
699        assert 2 not in lru
700
701        # next batch over the threshold of 10 should be present
702        for id_ in range(11, 20):
703            assert id_ in lru
704
705        lru[12]
706        lru[15]
707        lru[23] = item(23)
708        lru[24] = item(24)
709        lru[25] = item(25)
710        lru[26] = item(26)
711        lru[27] = item(27)
712
713        assert 11 not in lru
714        assert 13 not in lru
715
716        for id_ in (25, 24, 23, 14, 12, 19, 18, 17, 16, 15):
717            assert id_ in lru
718
719        i1 = lru[25]
720        i2 = item(25)
721        lru[25] = i2
722        assert 25 in lru
723        assert lru[25] is i2
724
725
726class ImmutableSubclass(str):
727    pass
728
729
730class FlattenIteratorTest(fixtures.TestBase):
731
732    def test_flatten(self):
733        assert list(util.flatten_iterator([[1, 2, 3], [4, 5, 6], 7,
734                    8])) == [1, 2, 3, 4, 5, 6, 7, 8]
735
736    def test_str_with_iter(self):
737        """ensure that a str object with an __iter__ method (like in
738        PyPy) is not interpreted as an iterable.
739
740        """
741
742        class IterString(str):
743            def __iter__(self):
744                return iter(self + '')
745
746        iter_list = [IterString('asdf'), [IterString('x'), IterString('y')]]
747
748        assert list(util.flatten_iterator(iter_list)) == ['asdf', 'x', 'y']
749
750
751class HashOverride(object):
752
753    def __init__(self, value=None):
754        self.value = value
755
756    def __hash__(self):
757        return hash(self.value)
758
759
760class EqOverride(object):
761
762    def __init__(self, value=None):
763        self.value = value
764    __hash__ = object.__hash__
765
766    def __eq__(self, other):
767        if isinstance(other, EqOverride):
768            return self.value == other.value
769        else:
770            return False
771
772    def __ne__(self, other):
773        if isinstance(other, EqOverride):
774            return self.value != other.value
775        else:
776            return True
777
778
779class HashEqOverride(object):
780
781    def __init__(self, value=None):
782        self.value = value
783
784    def __hash__(self):
785        return hash(self.value)
786
787    def __eq__(self, other):
788        if isinstance(other, EqOverride):
789            return self.value == other.value
790        else:
791            return False
792
793    def __ne__(self, other):
794        if isinstance(other, EqOverride):
795            return self.value != other.value
796        else:
797            return True
798
799
800class IdentitySetTest(fixtures.TestBase):
801
802    def assert_eq(self, identityset, expected_iterable):
803        expected = sorted([id(o) for o in expected_iterable])
804        found = sorted([id(o) for o in identityset])
805        eq_(found, expected)
806
807    def test_init(self):
808        ids = util.IdentitySet([1, 2, 3, 2, 1])
809        self.assert_eq(ids, [1, 2, 3])
810
811        ids = util.IdentitySet(ids)
812        self.assert_eq(ids, [1, 2, 3])
813
814        ids = util.IdentitySet()
815        self.assert_eq(ids, [])
816
817        ids = util.IdentitySet([])
818        self.assert_eq(ids, [])
819
820        ids = util.IdentitySet(ids)
821        self.assert_eq(ids, [])
822
823    def test_add(self):
824        for type_ in (object, ImmutableSubclass):
825            data = [type_(), type_()]
826            ids = util.IdentitySet()
827            for i in list(range(2)) + list(range(2)):
828                ids.add(data[i])
829            self.assert_eq(ids, data)
830
831        for type_ in (EqOverride, HashOverride, HashEqOverride):
832            data = [type_(1), type_(1), type_(2)]
833            ids = util.IdentitySet()
834            for i in list(range(3)) + list(range(3)):
835                ids.add(data[i])
836            self.assert_eq(ids, data)
837
838    def test_dunder_sub2(self):
839        IdentitySet = util.IdentitySet
840        o1, o2, o3 = object(), object(), object()
841        ids1 = IdentitySet([o1])
842        ids2 = IdentitySet([o1, o2, o3])
843        eq_(
844            ids2 - ids1,
845            IdentitySet([o2, o3])
846        )
847
848        ids2 -= ids1
849        eq_(ids2, IdentitySet([o2, o3]))
850
851    def test_dunder_eq(self):
852        _, _, twin1, twin2, unique1, unique2 = self._create_sets()
853
854        # basic set math
855        eq_(twin1 == twin2, True)
856        eq_(unique1 == unique2, False)
857
858        # not an IdentitySet
859        not_an_identity_set = object()
860        eq_(unique1 == not_an_identity_set, False)
861
862    def test_dunder_ne(self):
863        _, _, twin1, twin2, unique1, unique2 = self._create_sets()
864
865        # basic set math
866        eq_(twin1 != twin2, False)
867        eq_(unique1 != unique2, True)
868
869        # not an IdentitySet
870        not_an_identity_set = object()
871        eq_(unique1 != not_an_identity_set, True)
872
873    def test_dunder_le(self):
874        super_, sub_, twin1, twin2, unique1, unique2 = self._create_sets()
875
876        # basic set math
877        eq_(sub_ <= super_, True)
878        eq_(super_ <= sub_, False)
879
880        # the same sets
881        eq_(twin1 <= twin2, True)
882        eq_(twin2 <= twin1, True)
883
884        # totally different sets
885        eq_(unique1 <= unique2, False)
886        eq_(unique2 <= unique1, False)
887
888        # not an IdentitySet
889        def should_raise():
890            not_an_identity_set = object()
891            return unique1 <= not_an_identity_set
892        self._assert_unorderable_types(should_raise)
893
894    def test_dunder_lt(self):
895        super_, sub_, twin1, twin2, unique1, unique2 = self._create_sets()
896
897        # basic set math
898        eq_(sub_ < super_, True)
899        eq_(super_ < sub_, False)
900
901        # the same sets
902        eq_(twin1 < twin2, False)
903        eq_(twin2 < twin1, False)
904
905        # totally different sets
906        eq_(unique1 < unique2, False)
907        eq_(unique2 < unique1, False)
908
909        # not an IdentitySet
910        def should_raise():
911            not_an_identity_set = object()
912            return unique1 < not_an_identity_set
913        self._assert_unorderable_types(should_raise)
914
915    def test_dunder_ge(self):
916        super_, sub_, twin1, twin2, unique1, unique2 = self._create_sets()
917
918        # basic set math
919        eq_(sub_ >= super_, False)
920        eq_(super_ >= sub_, True)
921
922        # the same sets
923        eq_(twin1 >= twin2, True)
924        eq_(twin2 >= twin1, True)
925
926        # totally different sets
927        eq_(unique1 >= unique2, False)
928        eq_(unique2 >= unique1, False)
929
930        # not an IdentitySet
931        def should_raise():
932            not_an_identity_set = object()
933            return unique1 >= not_an_identity_set
934        self._assert_unorderable_types(should_raise)
935
936    def test_dunder_gt(self):
937        super_, sub_, twin1, twin2, unique1, unique2 = self._create_sets()
938
939        # basic set math
940        eq_(sub_ > super_, False)
941        eq_(super_ > sub_, True)
942
943        # the same sets
944        eq_(twin1 > twin2, False)
945        eq_(twin2 > twin1, False)
946
947        # totally different sets
948        eq_(unique1 > unique2, False)
949        eq_(unique2 > unique1, False)
950
951        # not an IdentitySet
952        def should_raise():
953            not_an_identity_set = object()
954            return unique1 > not_an_identity_set
955        self._assert_unorderable_types(should_raise)
956
957    def test_issubset(self):
958        super_, sub_, twin1, twin2, unique1, unique2 = self._create_sets()
959
960        # basic set math
961        eq_(sub_.issubset(super_), True)
962        eq_(super_.issubset(sub_), False)
963
964        # the same sets
965        eq_(twin1.issubset(twin2), True)
966        eq_(twin2.issubset(twin1), True)
967
968        # totally different sets
969        eq_(unique1.issubset(unique2), False)
970        eq_(unique2.issubset(unique1), False)
971
972        # not an IdentitySet
973        not_an_identity_set = object()
974        assert_raises(TypeError, unique1.issubset, not_an_identity_set)
975
976    def test_issuperset(self):
977        super_, sub_, twin1, twin2, unique1, unique2 = self._create_sets()
978
979        # basic set math
980        eq_(sub_.issuperset(super_), False)
981        eq_(super_.issuperset(sub_), True)
982
983        # the same sets
984        eq_(twin1.issuperset(twin2), True)
985        eq_(twin2.issuperset(twin1), True)
986
987        # totally different sets
988        eq_(unique1.issuperset(unique2), False)
989        eq_(unique2.issuperset(unique1), False)
990
991        # not an IdentitySet
992        not_an_identity_set = object()
993        assert_raises(TypeError, unique1.issuperset, not_an_identity_set)
994
995    def test_union(self):
996        super_, sub_, twin1, twin2, _, _ = self._create_sets()
997
998        # basic set math
999        eq_(sub_.union(super_), super_)
1000        eq_(super_.union(sub_), super_)
1001
1002        # the same sets
1003        eq_(twin1.union(twin2), twin1)
1004        eq_(twin2.union(twin1), twin1)
1005
1006        # empty sets
1007        empty = util.IdentitySet([])
1008        eq_(empty.union(empty), empty)
1009
1010        # totally different sets
1011        unique1 = util.IdentitySet([1])
1012        unique2 = util.IdentitySet([2])
1013        eq_(unique1.union(unique2), util.IdentitySet([1, 2]))
1014
1015        # not an IdentitySet
1016        not_an_identity_set = object()
1017        assert_raises(TypeError, unique1.union, not_an_identity_set)
1018
1019    def test_dunder_or(self):
1020        super_, sub_, twin1, twin2, _, _ = self._create_sets()
1021
1022        # basic set math
1023        eq_(sub_ | super_, super_)
1024        eq_(super_ | sub_, super_)
1025
1026        # the same sets
1027        eq_(twin1 | twin2, twin1)
1028        eq_(twin2 | twin1, twin1)
1029
1030        # empty sets
1031        empty = util.IdentitySet([])
1032        eq_(empty | empty, empty)
1033
1034        # totally different sets
1035        unique1 = util.IdentitySet([1])
1036        unique2 = util.IdentitySet([2])
1037        eq_(unique1 | unique2, util.IdentitySet([1, 2]))
1038
1039        # not an IdentitySet
1040        def should_raise():
1041            not_an_identity_set = object()
1042            return unique1 | not_an_identity_set
1043        assert_raises(TypeError, should_raise)
1044
1045    def test_update(self):
1046        pass  # TODO
1047
1048    def test_dunder_ior(self):
1049        super_, sub_, _, _, _, _ = self._create_sets()
1050
1051        # basic set math
1052        sub_ |= super_
1053        eq_(sub_, super_)
1054        super_ |= sub_
1055        eq_(super_, super_)
1056
1057        # totally different sets
1058        unique1 = util.IdentitySet([1])
1059        unique2 = util.IdentitySet([2])
1060        unique1 |= unique2
1061        eq_(unique1, util.IdentitySet([1, 2]))
1062        eq_(unique2, util.IdentitySet([2]))
1063
1064        # not an IdentitySet
1065        def should_raise():
1066            unique = util.IdentitySet([1])
1067            not_an_identity_set = object()
1068            unique |= not_an_identity_set
1069        assert_raises(TypeError, should_raise)
1070
1071    def test_difference(self):
1072        _, _, twin1, twin2, _, _ = self._create_sets()
1073
1074        # basic set math
1075        set1 = util.IdentitySet([1, 2, 3])
1076        set2 = util.IdentitySet([2, 3, 4])
1077        eq_(set1.difference(set2), util.IdentitySet([1]))
1078        eq_(set2.difference(set1), util.IdentitySet([4]))
1079
1080        # empty sets
1081        empty = util.IdentitySet([])
1082        eq_(empty.difference(empty), empty)
1083
1084        # the same sets
1085        eq_(twin1.difference(twin2), empty)
1086        eq_(twin2.difference(twin1), empty)
1087
1088        # totally different sets
1089        unique1 = util.IdentitySet([1])
1090        unique2 = util.IdentitySet([2])
1091        eq_(unique1.difference(unique2), util.IdentitySet([1]))
1092        eq_(unique2.difference(unique1), util.IdentitySet([2]))
1093
1094        # not an IdentitySet
1095        not_an_identity_set = object()
1096        assert_raises(TypeError, unique1.difference, not_an_identity_set)
1097
1098    def test_dunder_sub(self):
1099        _, _, twin1, twin2, _, _ = self._create_sets()
1100
1101        # basic set math
1102        set1 = util.IdentitySet([1, 2, 3])
1103        set2 = util.IdentitySet([2, 3, 4])
1104        eq_(set1 - set2, util.IdentitySet([1]))
1105        eq_(set2 - set1, util.IdentitySet([4]))
1106
1107        # empty sets
1108        empty = util.IdentitySet([])
1109        eq_(empty - empty, empty)
1110
1111        # the same sets
1112        eq_(twin1 - twin2, empty)
1113        eq_(twin2 - twin1, empty)
1114
1115        # totally different sets
1116        unique1 = util.IdentitySet([1])
1117        unique2 = util.IdentitySet([2])
1118        eq_(unique1 - unique2, util.IdentitySet([1]))
1119        eq_(unique2 - unique1, util.IdentitySet([2]))
1120
1121        # not an IdentitySet
1122        def should_raise():
1123            not_an_identity_set = object()
1124            unique1 - not_an_identity_set
1125        assert_raises(TypeError, should_raise)
1126
1127    def test_difference_update(self):
1128        pass  # TODO
1129
1130    def test_dunder_isub(self):
1131        pass  # TODO
1132
1133    def test_intersection(self):
1134        super_, sub_, twin1, twin2, unique1, unique2 = self._create_sets()
1135
1136        # basic set math
1137        eq_(sub_.intersection(super_), sub_)
1138        eq_(super_.intersection(sub_), sub_)
1139
1140        # the same sets
1141        eq_(twin1.intersection(twin2), twin1)
1142        eq_(twin2.intersection(twin1), twin1)
1143
1144        # empty sets
1145        empty = util.IdentitySet([])
1146        eq_(empty.intersection(empty), empty)
1147
1148        # totally different sets
1149        eq_(unique1.intersection(unique2), empty)
1150
1151        # not an IdentitySet
1152        not_an_identity_set = object()
1153        assert_raises(TypeError, unique1.intersection, not_an_identity_set)
1154
1155    def test_dunder_and(self):
1156        super_, sub_, twin1, twin2, unique1, unique2 = self._create_sets()
1157
1158        # basic set math
1159        eq_(sub_ & super_, sub_)
1160        eq_(super_ & sub_, sub_)
1161
1162        # the same sets
1163        eq_(twin1 & twin2, twin1)
1164        eq_(twin2 & twin1, twin1)
1165
1166        # empty sets
1167        empty = util.IdentitySet([])
1168        eq_(empty & empty, empty)
1169
1170        # totally different sets
1171        eq_(unique1 & unique2, empty)
1172
1173        # not an IdentitySet
1174        def should_raise():
1175            not_an_identity_set = object()
1176            return unique1 & not_an_identity_set
1177        assert_raises(TypeError, should_raise)
1178
1179    def test_intersection_update(self):
1180        pass  # TODO
1181
1182    def test_dunder_iand(self):
1183        pass  # TODO
1184
1185    def test_symmetric_difference(self):
1186        _, _, twin1, twin2, _, _ = self._create_sets()
1187
1188        # basic set math
1189        set1 = util.IdentitySet([1, 2, 3])
1190        set2 = util.IdentitySet([2, 3, 4])
1191        eq_(set1.symmetric_difference(set2), util.IdentitySet([1, 4]))
1192        eq_(set2.symmetric_difference(set1), util.IdentitySet([1, 4]))
1193
1194        # empty sets
1195        empty = util.IdentitySet([])
1196        eq_(empty.symmetric_difference(empty), empty)
1197
1198        # the same sets
1199        eq_(twin1.symmetric_difference(twin2), empty)
1200        eq_(twin2.symmetric_difference(twin1), empty)
1201
1202        # totally different sets
1203        unique1 = util.IdentitySet([1])
1204        unique2 = util.IdentitySet([2])
1205        eq_(unique1.symmetric_difference(unique2), util.IdentitySet([1, 2]))
1206        eq_(unique2.symmetric_difference(unique1), util.IdentitySet([1, 2]))
1207
1208        # not an IdentitySet
1209        not_an_identity_set = object()
1210        assert_raises(
1211            TypeError, unique1.symmetric_difference, not_an_identity_set)
1212
1213    def test_dunder_xor(self):
1214        _, _, twin1, twin2, _, _ = self._create_sets()
1215
1216        # basic set math
1217        set1 = util.IdentitySet([1, 2, 3])
1218        set2 = util.IdentitySet([2, 3, 4])
1219        eq_(set1 ^ set2, util.IdentitySet([1, 4]))
1220        eq_(set2 ^ set1, util.IdentitySet([1, 4]))
1221
1222        # empty sets
1223        empty = util.IdentitySet([])
1224        eq_(empty ^ empty, empty)
1225
1226        # the same sets
1227        eq_(twin1 ^ twin2, empty)
1228        eq_(twin2 ^ twin1, empty)
1229
1230        # totally different sets
1231        unique1 = util.IdentitySet([1])
1232        unique2 = util.IdentitySet([2])
1233        eq_(unique1 ^ unique2, util.IdentitySet([1, 2]))
1234        eq_(unique2 ^ unique1, util.IdentitySet([1, 2]))
1235
1236        # not an IdentitySet
1237        def should_raise():
1238            not_an_identity_set = object()
1239            return unique1 ^ not_an_identity_set
1240        assert_raises(TypeError, should_raise)
1241
1242    def test_symmetric_difference_update(self):
1243        pass  # TODO
1244
1245    def _create_sets(self):
1246        o1, o2, o3, o4, o5 = object(), object(), object(), object(), object()
1247        super_ = util.IdentitySet([o1, o2, o3])
1248        sub_ = util.IdentitySet([o2])
1249        twin1 = util.IdentitySet([o3])
1250        twin2 = util.IdentitySet([o3])
1251        unique1 = util.IdentitySet([o4])
1252        unique2 = util.IdentitySet([o5])
1253        return super_, sub_, twin1, twin2, unique1, unique2
1254
1255    def _assert_unorderable_types(self, callable_):
1256        if util.py36:
1257            assert_raises_message(
1258                TypeError, 'not supported between instances of', callable_)
1259        elif util.py3k:
1260            assert_raises_message(
1261                TypeError, 'unorderable types', callable_)
1262        else:
1263            assert_raises_message(
1264                TypeError, 'cannot compare sets using cmp()', callable_)
1265
1266    def test_basic_sanity(self):
1267        IdentitySet = util.IdentitySet
1268
1269        o1, o2, o3 = object(), object(), object()
1270        ids = IdentitySet([o1])
1271        ids.discard(o1)
1272        ids.discard(o1)
1273        ids.add(o1)
1274        ids.remove(o1)
1275        assert_raises(KeyError, ids.remove, o1)
1276
1277        eq_(ids.copy(), ids)
1278
1279        # explicit __eq__ and __ne__ tests
1280        assert ids != None  # noqa
1281        assert not(ids == None)  # noqa
1282
1283        ne_(ids, IdentitySet([o1, o2, o3]))
1284        ids.clear()
1285        assert o1 not in ids
1286        ids.add(o2)
1287        assert o2 in ids
1288        eq_(ids.pop(), o2)
1289        ids.add(o1)
1290        eq_(len(ids), 1)
1291
1292        isuper = IdentitySet([o1, o2])
1293        assert ids < isuper
1294        assert ids.issubset(isuper)
1295        assert isuper.issuperset(ids)
1296        assert isuper > ids
1297
1298        eq_(ids.union(isuper), isuper)
1299        eq_(ids | isuper, isuper)
1300        eq_(isuper - ids, IdentitySet([o2]))
1301        eq_(isuper.difference(ids), IdentitySet([o2]))
1302        eq_(ids.intersection(isuper), IdentitySet([o1]))
1303        eq_(ids & isuper, IdentitySet([o1]))
1304        eq_(ids.symmetric_difference(isuper), IdentitySet([o2]))
1305        eq_(ids ^ isuper, IdentitySet([o2]))
1306
1307        ids.update(isuper)
1308        ids |= isuper
1309        ids.difference_update(isuper)
1310        ids -= isuper
1311        ids.intersection_update(isuper)
1312        ids &= isuper
1313        ids.symmetric_difference_update(isuper)
1314        ids ^= isuper
1315
1316        ids.update('foobar')
1317        try:
1318            ids |= 'foobar'
1319            assert False
1320        except TypeError:
1321            assert True
1322
1323        try:
1324            s = set([o1, o2])
1325            s |= ids
1326            assert False
1327        except TypeError:
1328            assert True
1329
1330        assert_raises(TypeError, util.cmp, ids)
1331        assert_raises(TypeError, hash, ids)
1332
1333
1334class OrderedIdentitySetTest(fixtures.TestBase):
1335
1336    def assert_eq(self, identityset, expected_iterable):
1337        expected = [id(o) for o in expected_iterable]
1338        found = [id(o) for o in identityset]
1339        eq_(found, expected)
1340
1341    def test_add(self):
1342        elem = object
1343        s = util.OrderedIdentitySet()
1344        s.add(elem())
1345        s.add(elem())
1346
1347    def test_intersection(self):
1348        elem = object
1349        eq_ = self.assert_eq
1350
1351        a, b, c, d, e, f, g = \
1352            elem(), elem(), elem(), elem(), elem(), elem(), elem()
1353
1354        s1 = util.OrderedIdentitySet([a, b, c])
1355        s2 = util.OrderedIdentitySet([d, e, f])
1356        s3 = util.OrderedIdentitySet([a, d, f, g])
1357        eq_(s1.intersection(s2), [])
1358        eq_(s1.intersection(s3), [a])
1359        eq_(s1.union(s2).intersection(s3), [a, d, f])
1360
1361
1362class DictlikeIteritemsTest(fixtures.TestBase):
1363    baseline = set([('a', 1), ('b', 2), ('c', 3)])
1364
1365    def _ok(self, instance):
1366        iterator = util.dictlike_iteritems(instance)
1367        eq_(set(iterator), self.baseline)
1368
1369    def _notok(self, instance):
1370        assert_raises(TypeError,
1371                      util.dictlike_iteritems,
1372                      instance)
1373
1374    def test_dict(self):
1375        d = dict(a=1, b=2, c=3)
1376        self._ok(d)
1377
1378    def test_subdict(self):
1379        class subdict(dict):
1380            pass
1381        d = subdict(a=1, b=2, c=3)
1382        self._ok(d)
1383
1384    if util.py2k:
1385        def test_UserDict(self):
1386            import UserDict
1387            d = UserDict.UserDict(a=1, b=2, c=3)
1388            self._ok(d)
1389
1390    def test_object(self):
1391        self._notok(object())
1392
1393    if util.py2k:
1394        def test_duck_1(self):
1395            class duck1(object):
1396                def iteritems(duck):
1397                    return iter(self.baseline)
1398            self._ok(duck1())
1399
1400    def test_duck_2(self):
1401        class duck2(object):
1402            def items(duck):
1403                return list(self.baseline)
1404        self._ok(duck2())
1405
1406    if util.py2k:
1407        def test_duck_3(self):
1408            class duck3(object):
1409                def iterkeys(duck):
1410                    return iter(['a', 'b', 'c'])
1411
1412                def __getitem__(duck, key):
1413                    return dict(a=1, b=2, c=3).get(key)
1414            self._ok(duck3())
1415
1416    def test_duck_4(self):
1417        class duck4(object):
1418            def iterkeys(duck):
1419                return iter(['a', 'b', 'c'])
1420        self._notok(duck4())
1421
1422    def test_duck_5(self):
1423        class duck5(object):
1424            def keys(duck):
1425                return ['a', 'b', 'c']
1426
1427            def get(duck, key):
1428                return dict(a=1, b=2, c=3).get(key)
1429        self._ok(duck5())
1430
1431    def test_duck_6(self):
1432        class duck6(object):
1433            def keys(duck):
1434                return ['a', 'b', 'c']
1435        self._notok(duck6())
1436
1437
1438class DuckTypeCollectionTest(fixtures.TestBase):
1439
1440    def test_sets(self):
1441        class SetLike(object):
1442            def add(self):
1443                pass
1444
1445        class ForcedSet(list):
1446            __emulates__ = set
1447
1448        for type_ in (set,
1449                      SetLike,
1450                      ForcedSet):
1451            eq_(util.duck_type_collection(type_), set)
1452            instance = type_()
1453            eq_(util.duck_type_collection(instance), set)
1454
1455        for type_ in (frozenset, ):
1456            is_(util.duck_type_collection(type_), None)
1457            instance = type_()
1458            is_(util.duck_type_collection(instance), None)
1459
1460
1461class PublicFactoryTest(fixtures.TestBase):
1462
1463    def _fixture(self):
1464        class Thingy(object):
1465            def __init__(self, value):
1466                "make a thingy"
1467                self.value = value
1468
1469            @classmethod
1470            def foobar(cls, x, y):
1471                "do the foobar"
1472                return Thingy(x + y)
1473
1474        return Thingy
1475
1476    def test_classmethod(self):
1477        Thingy = self._fixture()
1478        foob = langhelpers.public_factory(
1479            Thingy.foobar, ".sql.elements.foob")
1480        eq_(foob(3, 4).value, 7)
1481        eq_(foob(x=3, y=4).value, 7)
1482        eq_(foob.__doc__, "do the foobar")
1483        eq_(foob.__module__, "sqlalchemy.sql.elements")
1484        assert Thingy.foobar.__doc__.startswith("This function is mirrored;")
1485
1486    def test_constructor(self):
1487        Thingy = self._fixture()
1488        foob = langhelpers.public_factory(
1489            Thingy, ".sql.elements.foob")
1490        eq_(foob(7).value, 7)
1491        eq_(foob(value=7).value, 7)
1492        eq_(foob.__doc__, "make a thingy")
1493        eq_(foob.__module__, "sqlalchemy.sql.elements")
1494        assert Thingy.__init__.__doc__.startswith(
1495            "Construct a new :class:`.Thingy` object.")
1496
1497
1498class ArgInspectionTest(fixtures.TestBase):
1499
1500    def test_get_cls_kwargs(self):
1501
1502        class A(object):
1503            def __init__(self, a):
1504                pass
1505
1506        class A1(A):
1507            def __init__(self, a1):
1508                pass
1509
1510        class A11(A1):
1511            def __init__(self, a11, **kw):
1512                pass
1513
1514        class B(object):
1515            def __init__(self, b, **kw):
1516                pass
1517
1518        class B1(B):
1519            def __init__(self, b1, **kw):
1520                pass
1521
1522        class B2(B):
1523            def __init__(self, b2):
1524                pass
1525
1526        class AB(A, B):
1527            def __init__(self, ab):
1528                pass
1529
1530        class BA(B, A):
1531            def __init__(self, ba, **kwargs):
1532                pass
1533
1534        class BA1(BA):
1535            pass
1536
1537        class CAB(A, B):
1538            pass
1539
1540        class CBA(B, A):
1541            pass
1542
1543        class CB1A1(B1, A1):
1544            pass
1545
1546        class CAB1(A, B1):
1547            pass
1548
1549        class CB1A(B1, A):
1550            pass
1551
1552        class CB2A(B2, A):
1553            pass
1554
1555        class D(object):
1556            pass
1557
1558        class BA2(B, A):
1559            pass
1560
1561        class A11B1(A11, B1):
1562            pass
1563
1564        def test(cls, *expected):
1565            eq_(set(util.get_cls_kwargs(cls)), set(expected))
1566
1567        test(A, 'a')
1568        test(A1, 'a1')
1569        test(A11, 'a11', 'a1')
1570        test(B, 'b')
1571        test(B1, 'b1', 'b')
1572        test(AB, 'ab')
1573        test(BA, 'ba', 'b', 'a')
1574        test(BA1, 'ba', 'b', 'a')
1575        test(CAB, 'a')
1576        test(CBA, 'b', 'a')
1577        test(CAB1, 'a')
1578        test(CB1A, 'b1', 'b', 'a')
1579        test(CB2A, 'b2')
1580        test(CB1A1, "a1", "b1", "b")
1581        test(D)
1582        test(BA2, "a", "b")
1583        test(A11B1, "a1", "a11", "b", "b1")
1584
1585    def test_get_func_kwargs(self):
1586
1587        def f1():
1588            pass
1589
1590        def f2(foo):
1591            pass
1592
1593        def f3(*foo):
1594            pass
1595
1596        def f4(**foo):
1597            pass
1598
1599        def test(fn, *expected):
1600            eq_(set(util.get_func_kwargs(fn)), set(expected))
1601
1602        test(f1)
1603        test(f2, 'foo')
1604        test(f3)
1605        test(f4)
1606
1607    def test_callable_argspec_fn(self):
1608        def foo(x, y, **kw):
1609            pass
1610        eq_(
1611            get_callable_argspec(foo),
1612            (['x', 'y'], None, 'kw', None)
1613        )
1614
1615    def test_callable_argspec_fn_no_self(self):
1616        def foo(x, y, **kw):
1617            pass
1618        eq_(
1619            get_callable_argspec(foo, no_self=True),
1620            (['x', 'y'], None, 'kw', None)
1621        )
1622
1623    def test_callable_argspec_fn_no_self_but_self(self):
1624        def foo(self, x, y, **kw):
1625            pass
1626        eq_(
1627            get_callable_argspec(foo, no_self=True),
1628            (['self', 'x', 'y'], None, 'kw', None)
1629        )
1630
1631    @fails_if(lambda: util.pypy,  "pypy returns plain *arg, **kw")
1632    def test_callable_argspec_py_builtin(self):
1633        import datetime
1634        assert_raises(
1635            TypeError,
1636            get_callable_argspec, datetime.datetime.now
1637        )
1638
1639    @fails_if(lambda: util.pypy,  "pypy returns plain *arg, **kw")
1640    def test_callable_argspec_obj_init(self):
1641        assert_raises(
1642            TypeError,
1643            get_callable_argspec, object
1644        )
1645
1646    def test_callable_argspec_method(self):
1647        class Foo(object):
1648            def foo(self, x, y, **kw):
1649                pass
1650        eq_(
1651            get_callable_argspec(Foo.foo),
1652            (['self', 'x', 'y'], None, 'kw', None)
1653        )
1654
1655    def test_callable_argspec_instance_method_no_self(self):
1656        class Foo(object):
1657            def foo(self, x, y, **kw):
1658                pass
1659        eq_(
1660            get_callable_argspec(Foo().foo, no_self=True),
1661            (['x', 'y'], None, 'kw', None)
1662        )
1663
1664    def test_callable_argspec_unbound_method_no_self(self):
1665        class Foo(object):
1666            def foo(self, x, y, **kw):
1667                pass
1668        eq_(
1669            get_callable_argspec(Foo.foo, no_self=True),
1670            (['self', 'x', 'y'], None, 'kw', None)
1671        )
1672
1673    def test_callable_argspec_init(self):
1674        class Foo(object):
1675            def __init__(self, x, y):
1676                pass
1677
1678        eq_(
1679            get_callable_argspec(Foo),
1680            (['self', 'x', 'y'], None, None, None)
1681        )
1682
1683    def test_callable_argspec_init_no_self(self):
1684        class Foo(object):
1685            def __init__(self, x, y):
1686                pass
1687
1688        eq_(
1689            get_callable_argspec(Foo, no_self=True),
1690            (['x', 'y'], None, None, None)
1691        )
1692
1693    def test_callable_argspec_call(self):
1694        class Foo(object):
1695            def __call__(self, x, y):
1696                pass
1697        eq_(
1698            get_callable_argspec(Foo()),
1699            (['self', 'x', 'y'], None, None, None)
1700        )
1701
1702    def test_callable_argspec_call_no_self(self):
1703        class Foo(object):
1704            def __call__(self, x, y):
1705                pass
1706        eq_(
1707            get_callable_argspec(Foo(), no_self=True),
1708            (['x', 'y'], None, None, None)
1709        )
1710
1711    @fails_if(lambda: util.pypy,  "pypy returns plain *arg, **kw")
1712    def test_callable_argspec_partial(self):
1713        from functools import partial
1714
1715        def foo(x, y, z, **kw):
1716            pass
1717        bar = partial(foo, 5)
1718
1719        assert_raises(
1720            TypeError,
1721            get_callable_argspec, bar
1722        )
1723
1724
1725class SymbolTest(fixtures.TestBase):
1726
1727    def test_basic(self):
1728        sym1 = util.symbol('foo')
1729        assert sym1.name == 'foo'
1730        sym2 = util.symbol('foo')
1731
1732        assert sym1 is sym2
1733        assert sym1 == sym2
1734
1735        sym3 = util.symbol('bar')
1736        assert sym1 is not sym3
1737        assert sym1 != sym3
1738
1739    def test_pickle(self):
1740        sym1 = util.symbol('foo')
1741        sym2 = util.symbol('foo')
1742
1743        assert sym1 is sym2
1744
1745        # default
1746        s = util.pickle.dumps(sym1)
1747        sym3 = util.pickle.loads(s)
1748
1749        for protocol in 0, 1, 2:
1750            print(protocol)
1751            serial = util.pickle.dumps(sym1)
1752            rt = util.pickle.loads(serial)
1753            assert rt is sym1
1754            assert rt is sym2
1755
1756    def test_bitflags(self):
1757        sym1 = util.symbol('sym1', canonical=1)
1758        sym2 = util.symbol('sym2', canonical=2)
1759
1760        assert sym1 & sym1
1761        assert not sym1 & sym2
1762        assert not sym1 & sym1 & sym2
1763
1764    def test_composites(self):
1765        sym1 = util.symbol('sym1', canonical=1)
1766        sym2 = util.symbol('sym2', canonical=2)
1767        sym3 = util.symbol('sym3', canonical=4)
1768        sym4 = util.symbol('sym4', canonical=8)
1769
1770        assert sym1 & (sym2 | sym1 | sym4)
1771        assert not sym1 & (sym2 | sym3)
1772
1773        assert not (sym1 | sym2) & (sym3 | sym4)
1774        assert (sym1 | sym2) & (sym2 | sym4)
1775
1776
1777class TestFormatArgspec(fixtures.TestBase):
1778
1779    def test_specs(self):
1780        def test(fn, wanted, grouped=None):
1781            if grouped is None:
1782                parsed = util.format_argspec_plus(fn)
1783            else:
1784                parsed = util.format_argspec_plus(fn, grouped=grouped)
1785            eq_(parsed, wanted)
1786
1787        test(lambda: None,
1788             {'args': '()', 'self_arg': None,
1789              'apply_kw': '()', 'apply_pos': '()'})
1790
1791        test(lambda: None,
1792             {'args': '', 'self_arg': None,
1793              'apply_kw': '', 'apply_pos': ''},
1794             grouped=False)
1795
1796        test(lambda self: None,
1797             {'args': '(self)', 'self_arg': 'self',
1798              'apply_kw': '(self)', 'apply_pos': '(self)'})
1799
1800        test(lambda self: None,
1801             {'args': 'self', 'self_arg': 'self',
1802              'apply_kw': 'self', 'apply_pos': 'self'},
1803             grouped=False)
1804
1805        test(lambda *a: None,
1806             {'args': '(*a)', 'self_arg': 'a[0]',
1807              'apply_kw': '(*a)', 'apply_pos': '(*a)'})
1808
1809        test(lambda **kw: None,
1810             {'args': '(**kw)', 'self_arg': None,
1811              'apply_kw': '(**kw)', 'apply_pos': '(**kw)'})
1812
1813        test(lambda *a, **kw: None,
1814             {'args': '(*a, **kw)', 'self_arg': 'a[0]',
1815              'apply_kw': '(*a, **kw)', 'apply_pos': '(*a, **kw)'})
1816
1817        test(lambda a, *b: None,
1818             {'args': '(a, *b)', 'self_arg': 'a',
1819              'apply_kw': '(a, *b)', 'apply_pos': '(a, *b)'})
1820
1821        test(lambda a, **b: None,
1822             {'args': '(a, **b)', 'self_arg': 'a',
1823              'apply_kw': '(a, **b)', 'apply_pos': '(a, **b)'})
1824
1825        test(lambda a, *b, **c: None,
1826             {'args': '(a, *b, **c)', 'self_arg': 'a',
1827              'apply_kw': '(a, *b, **c)', 'apply_pos': '(a, *b, **c)'})
1828
1829        test(lambda a, b=1, **c: None,
1830             {'args': '(a, b=1, **c)', 'self_arg': 'a',
1831              'apply_kw': '(a, b=b, **c)', 'apply_pos': '(a, b, **c)'})
1832
1833        test(lambda a=1, b=2: None,
1834             {'args': '(a=1, b=2)', 'self_arg': 'a',
1835              'apply_kw': '(a=a, b=b)', 'apply_pos': '(a, b)'})
1836
1837        test(lambda a=1, b=2: None,
1838             {'args': 'a=1, b=2', 'self_arg': 'a',
1839              'apply_kw': 'a=a, b=b', 'apply_pos': 'a, b'},
1840             grouped=False)
1841
1842    @testing.fails_if(lambda: util.pypy,
1843                      "pypy doesn't report Obj.__init__ as object.__init__")
1844    def test_init_grouped(self):
1845        object_spec = {
1846            'args': '(self)', 'self_arg': 'self',
1847            'apply_pos': '(self)', 'apply_kw': '(self)'}
1848        wrapper_spec = {
1849            'args': '(self, *args, **kwargs)', 'self_arg': 'self',
1850            'apply_pos': '(self, *args, **kwargs)',
1851            'apply_kw': '(self, *args, **kwargs)'}
1852        custom_spec = {
1853            'args': '(slef, a=123)', 'self_arg': 'slef',  # yes, slef
1854            'apply_pos': '(slef, a)', 'apply_kw': '(slef, a=a)'}
1855
1856        self._test_init(None, object_spec, wrapper_spec, custom_spec)
1857        self._test_init(True, object_spec, wrapper_spec, custom_spec)
1858
1859    @testing.fails_if(lambda: util.pypy,
1860                      "pypy doesn't report Obj.__init__ as object.__init__")
1861    def test_init_bare(self):
1862        object_spec = {
1863            'args': 'self', 'self_arg': 'self',
1864            'apply_pos': 'self', 'apply_kw': 'self'}
1865        wrapper_spec = {
1866            'args': 'self, *args, **kwargs', 'self_arg': 'self',
1867            'apply_pos': 'self, *args, **kwargs',
1868            'apply_kw': 'self, *args, **kwargs'}
1869        custom_spec = {
1870            'args': 'slef, a=123', 'self_arg': 'slef',  # yes, slef
1871            'apply_pos': 'slef, a', 'apply_kw': 'slef, a=a'}
1872
1873        self._test_init(False, object_spec, wrapper_spec, custom_spec)
1874
1875    def _test_init(self, grouped, object_spec, wrapper_spec, custom_spec):
1876        def test(fn, wanted):
1877            if grouped is None:
1878                parsed = util.format_argspec_init(fn)
1879            else:
1880                parsed = util.format_argspec_init(fn, grouped=grouped)
1881            eq_(parsed, wanted)
1882
1883        class Obj(object):
1884            pass
1885
1886        test(Obj.__init__, object_spec)
1887
1888        class Obj(object):
1889            def __init__(self):
1890                pass
1891
1892        test(Obj.__init__, object_spec)
1893
1894        class Obj(object):
1895            def __init__(slef, a=123):
1896                pass
1897
1898        test(Obj.__init__, custom_spec)
1899
1900        class Obj(list):
1901            pass
1902
1903        test(Obj.__init__, wrapper_spec)
1904
1905        class Obj(list):
1906            def __init__(self, *args, **kwargs):
1907                pass
1908
1909        test(Obj.__init__, wrapper_spec)
1910
1911        class Obj(list):
1912            def __init__(self):
1913                pass
1914
1915        test(Obj.__init__, object_spec)
1916
1917        class Obj(list):
1918            def __init__(slef, a=123):
1919                pass
1920
1921        test(Obj.__init__, custom_spec)
1922
1923
1924class GenericReprTest(fixtures.TestBase):
1925
1926    def test_all_positional(self):
1927        class Foo(object):
1928            def __init__(self, a, b, c):
1929                self.a = a
1930                self.b = b
1931                self.c = c
1932        eq_(
1933            util.generic_repr(Foo(1, 2, 3)),
1934            "Foo(1, 2, 3)"
1935        )
1936
1937    def test_positional_plus_kw(self):
1938        class Foo(object):
1939            def __init__(self, a, b, c=5, d=4):
1940                self.a = a
1941                self.b = b
1942                self.c = c
1943                self.d = d
1944        eq_(
1945            util.generic_repr(Foo(1, 2, 3, 6)),
1946            "Foo(1, 2, c=3, d=6)"
1947        )
1948
1949    def test_kw_defaults(self):
1950        class Foo(object):
1951            def __init__(self, a=1, b=2, c=3, d=4):
1952                self.a = a
1953                self.b = b
1954                self.c = c
1955                self.d = d
1956        eq_(
1957            util.generic_repr(Foo(1, 5, 3, 7)),
1958            "Foo(b=5, d=7)"
1959        )
1960
1961    def test_multi_kw(self):
1962        class Foo(object):
1963            def __init__(self, a, b, c=3, d=4):
1964                self.a = a
1965                self.b = b
1966                self.c = c
1967                self.d = d
1968
1969        class Bar(Foo):
1970            def __init__(self, e, f, g=5, **kw):
1971                self.e = e
1972                self.f = f
1973                self.g = g
1974                super(Bar, self).__init__(**kw)
1975
1976        eq_(
1977            util.generic_repr(
1978                Bar('e', 'f', g=7, a=6, b=5, d=9),
1979                to_inspect=[Bar, Foo]
1980            ),
1981            "Bar('e', 'f', g=7, a=6, b=5, d=9)"
1982        )
1983
1984        eq_(
1985            util.generic_repr(
1986                Bar('e', 'f', a=6, b=5),
1987                to_inspect=[Bar, Foo]
1988            ),
1989            "Bar('e', 'f', a=6, b=5)"
1990        )
1991
1992    def test_multi_kw_repeated(self):
1993        class Foo(object):
1994            def __init__(self, a=1, b=2):
1995                self.a = a
1996                self.b = b
1997
1998        class Bar(Foo):
1999            def __init__(self, b=3, c=4, **kw):
2000                self.c = c
2001                super(Bar, self).__init__(b=b, **kw)
2002
2003        eq_(
2004            util.generic_repr(
2005                Bar(a='a', b='b', c='c'),
2006                to_inspect=[Bar, Foo]
2007            ),
2008            "Bar(b='b', c='c', a='a')"
2009        )
2010
2011    def test_discard_vargs(self):
2012        class Foo(object):
2013            def __init__(self, a, b, *args):
2014                self.a = a
2015                self.b = b
2016                self.c, self.d = args[0:2]
2017        eq_(
2018            util.generic_repr(Foo(1, 2, 3, 4)),
2019            "Foo(1, 2)"
2020        )
2021
2022    def test_discard_vargs_kwargs(self):
2023        class Foo(object):
2024            def __init__(self, a, b, *args, **kw):
2025                self.a = a
2026                self.b = b
2027                self.c, self.d = args[0:2]
2028        eq_(
2029            util.generic_repr(Foo(1, 2, 3, 4, x=7, y=4)),
2030            "Foo(1, 2)"
2031        )
2032
2033    def test_significant_vargs(self):
2034        class Foo(object):
2035            def __init__(self, a, b, *args):
2036                self.a = a
2037                self.b = b
2038                self.args = args
2039        eq_(
2040            util.generic_repr(Foo(1, 2, 3, 4)),
2041            "Foo(1, 2, 3, 4)"
2042        )
2043
2044    def test_no_args(self):
2045        class Foo(object):
2046            def __init__(self):
2047                pass
2048        eq_(
2049            util.generic_repr(Foo()),
2050            "Foo()"
2051        )
2052
2053    def test_no_init(self):
2054        class Foo(object):
2055            pass
2056        eq_(
2057            util.generic_repr(Foo()),
2058            "Foo()"
2059        )
2060
2061
2062class AsInterfaceTest(fixtures.TestBase):
2063
2064    class Something(object):
2065
2066        def _ignoreme(self):
2067            pass
2068
2069        def foo(self):
2070            pass
2071
2072        def bar(self):
2073            pass
2074
2075    class Partial(object):
2076
2077        def bar(self):
2078            pass
2079
2080    class Object(object):
2081        pass
2082
2083    def test_instance(self):
2084        obj = object()
2085        assert_raises(TypeError, util.as_interface, obj,
2086                      cls=self.Something)
2087
2088        assert_raises(TypeError, util.as_interface, obj,
2089                      methods=('foo'))
2090
2091        assert_raises(TypeError, util.as_interface, obj,
2092                      cls=self.Something, required=('foo'))
2093
2094        obj = self.Something()
2095        eq_(obj, util.as_interface(obj, cls=self.Something))
2096        eq_(obj, util.as_interface(obj, methods=('foo',)))
2097        eq_(
2098            obj, util.as_interface(obj, cls=self.Something,
2099                                   required=('outofband',)))
2100        partial = self.Partial()
2101
2102        slotted = self.Object()
2103        slotted.bar = lambda self: 123
2104
2105        for obj in partial, slotted:
2106            eq_(obj, util.as_interface(obj, cls=self.Something))
2107            assert_raises(TypeError, util.as_interface, obj,
2108                          methods=('foo'))
2109            eq_(obj, util.as_interface(obj, methods=('bar',)))
2110            eq_(obj, util.as_interface(obj, cls=self.Something,
2111                                       required=('bar',)))
2112            assert_raises(TypeError, util.as_interface, obj,
2113                          cls=self.Something, required=('foo',))
2114
2115            assert_raises(TypeError, util.as_interface, obj,
2116                          cls=self.Something, required=self.Something)
2117
2118    def test_dict(self):
2119        obj = {}
2120        assert_raises(TypeError, util.as_interface, obj,
2121                      cls=self.Something)
2122        assert_raises(TypeError, util.as_interface, obj, methods='foo')
2123        assert_raises(TypeError, util.as_interface, obj,
2124                      cls=self.Something, required='foo')
2125
2126        def assertAdapted(obj, *methods):
2127            assert isinstance(obj, type)
2128            found = set([m for m in dir(obj) if not m.startswith('_')])
2129            for method in methods:
2130                assert method in found
2131                found.remove(method)
2132            assert not found
2133
2134        def fn(self): return 123
2135        obj = {'foo': fn, 'bar': fn}
2136        res = util.as_interface(obj, cls=self.Something)
2137        assertAdapted(res, 'foo', 'bar')
2138        res = util.as_interface(obj, cls=self.Something,
2139                                required=self.Something)
2140        assertAdapted(res, 'foo', 'bar')
2141        res = util.as_interface(obj, cls=self.Something, required=('foo',))
2142        assertAdapted(res, 'foo', 'bar')
2143        res = util.as_interface(obj, methods=('foo', 'bar'))
2144        assertAdapted(res, 'foo', 'bar')
2145        res = util.as_interface(obj, methods=('foo', 'bar', 'baz'))
2146        assertAdapted(res, 'foo', 'bar')
2147        res = util.as_interface(obj, methods=('foo', 'bar'), required=('foo',))
2148        assertAdapted(res, 'foo', 'bar')
2149        assert_raises(TypeError, util.as_interface, obj, methods=('foo',))
2150        assert_raises(TypeError, util.as_interface, obj,
2151                      methods=('foo', 'bar', 'baz'), required=('baz', ))
2152        obj = {'foo': 123}
2153        assert_raises(TypeError, util.as_interface, obj, cls=self.Something)
2154
2155
2156class TestClassHierarchy(fixtures.TestBase):
2157
2158    def test_object(self):
2159        eq_(set(util.class_hierarchy(object)), set((object,)))
2160
2161    def test_single(self):
2162        class A(object):
2163            pass
2164
2165        class B(object):
2166            pass
2167
2168        eq_(set(util.class_hierarchy(A)), set((A, object)))
2169        eq_(set(util.class_hierarchy(B)), set((B, object)))
2170
2171        class C(A, B):
2172            pass
2173
2174        eq_(set(util.class_hierarchy(A)), set((A, B, C, object)))
2175        eq_(set(util.class_hierarchy(B)), set((A, B, C, object)))
2176
2177    if util.py2k:
2178        def test_oldstyle_mixin(self):
2179            class A(object):
2180                pass
2181
2182            class Mixin:
2183                pass
2184
2185            class B(A, Mixin):
2186                pass
2187
2188            eq_(set(util.class_hierarchy(B)), set((A, B, object)))
2189            eq_(set(util.class_hierarchy(Mixin)), set())
2190            eq_(set(util.class_hierarchy(A)), set((A, B, object)))
2191
2192
2193class ReraiseTest(fixtures.TestBase):
2194    @testing.requires.python3
2195    def test_raise_from_cause_same_cause(self):
2196        class MyException(Exception):
2197            pass
2198
2199        def go():
2200            try:
2201                raise MyException("exc one")
2202            except Exception as err:
2203                util.raise_from_cause(err)
2204
2205        try:
2206            go()
2207            assert False
2208        except MyException as err:
2209            is_(err.__cause__, None)
2210
2211    def test_reraise_disallow_same_cause(self):
2212        class MyException(Exception):
2213            pass
2214
2215        def go():
2216            try:
2217                raise MyException("exc one")
2218            except Exception as err:
2219                type_, value, tb = sys.exc_info()
2220                util.reraise(type_, err, tb, value)
2221
2222        assert_raises_message(
2223            AssertionError,
2224            "Same cause emitted",
2225            go
2226        )
2227
2228    def test_raise_from_cause(self):
2229        class MyException(Exception):
2230            pass
2231
2232        class MyOtherException(Exception):
2233            pass
2234
2235        me = MyException("exc on")
2236
2237        def go():
2238            try:
2239                raise me
2240            except Exception:
2241                util.raise_from_cause(MyOtherException("exc two"))
2242
2243        try:
2244            go()
2245            assert False
2246        except MyOtherException as moe:
2247            if testing.requires.python3.enabled:
2248                is_(moe.__cause__, me)
2249
2250    @testing.requires.python2
2251    def test_safe_reraise_py2k_warning(self):
2252        class MyException(Exception):
2253            pass
2254
2255        class MyOtherException(Exception):
2256            pass
2257
2258        m1 = MyException("exc one")
2259        m2 = MyOtherException("exc two")
2260
2261        def go2():
2262            raise m2
2263
2264        def go():
2265            try:
2266                raise m1
2267            except Exception:
2268                with util.safe_reraise():
2269                    go2()
2270
2271        with expect_warnings(
2272            "An exception has occurred during handling of a previous "
2273            "exception.  The previous exception "
2274            "is:.*MyException.*exc one"
2275        ):
2276            try:
2277                go()
2278                assert False
2279            except MyOtherException:
2280                pass
2281
2282
2283class TestClassProperty(fixtures.TestBase):
2284
2285    def test_simple(self):
2286        class A(object):
2287            something = {'foo': 1}
2288
2289        class B(A):
2290
2291            @classproperty
2292            def something(cls):
2293                d = dict(super(B, cls).something)
2294                d.update({'bazz': 2})
2295                return d
2296
2297        eq_(B.something, {'foo': 1, 'bazz': 2})
2298
2299
2300class TestProperties(fixtures.TestBase):
2301
2302    def test_pickle(self):
2303        data = {'hello': 'bla'}
2304        props = util.Properties(data)
2305
2306        for loader, dumper in picklers():
2307            s = dumper(props)
2308            p = loader(s)
2309
2310            eq_(props._data, p._data)
2311            eq_(props.keys(), p.keys())
2312
2313    def test_pickle_immuatbleprops(self):
2314        data = {'hello': 'bla'}
2315        props = util.Properties(data).as_immutable()
2316
2317        for loader, dumper in picklers():
2318            s = dumper(props)
2319            p = loader(s)
2320
2321            eq_(props._data, p._data)
2322            eq_(props.keys(), p.keys())
2323
2324    def test_pickle_orderedprops(self):
2325        data = {'hello': 'bla'}
2326        props = util.OrderedProperties()
2327        props.update(data)
2328
2329        for loader, dumper in picklers():
2330            s = dumper(props)
2331            p = loader(s)
2332
2333            eq_(props._data, p._data)
2334            eq_(props.keys(), p.keys())
2335