|
39 | 39 |
|
40 | 40 | counter = 0
|
41 | 41 |
|
| 42 | + |
42 | 43 | class Foo:
|
43 |
| - def __setattr__(self, key, value): |
44 |
| - global counter |
45 |
| - counter = counter + 1 |
46 |
| - object.__setattr__(self, key, value) |
47 |
| - def __delattr__(self, key): |
48 |
| - global counter |
49 |
| - counter = counter + 10 |
50 |
| - object.__delattr__(self, key) |
| 44 | + def __setattr__(self, key, value): |
| 45 | + global counter |
| 46 | + counter = counter + 1 |
| 47 | + object.__setattr__(self, key, value) |
| 48 | + |
| 49 | + def __delattr__(self, key): |
| 50 | + global counter |
| 51 | + counter = counter + 10 |
| 52 | + object.__delattr__(self, key) |
| 53 | + |
51 | 54 |
|
52 | 55 | def test_call():
|
53 |
| - global counter |
54 |
| - counter = 0 |
55 |
| - f = Foo() |
56 |
| - f.a = 1 |
57 |
| - Foo.b = 123 |
58 |
| - assert counter == 1, "setting attrib on class should not call its own __setattr__" |
59 |
| - del f.a |
60 |
| - del Foo.b |
61 |
| - assert counter == 11, "deleting attrib on class should not call its own __delattr__" |
| 56 | + global counter |
| 57 | + counter = 0 |
| 58 | + f = Foo() |
| 59 | + f.a = 1 |
| 60 | + Foo.b = 123 |
| 61 | + assert counter == 1, "setting attrib on class should not call its own __setattr__" |
| 62 | + del f.a |
| 63 | + del Foo.b |
| 64 | + assert counter == 11, "deleting attrib on class should not call its own __delattr__" |
| 65 | + |
62 | 66 |
|
63 | 67 | class AClass:
|
64 |
| - pass |
| 68 | + pass |
| 69 | + |
65 | 70 |
|
66 | 71 | class BClass(AClass):
|
67 |
| - pass |
| 72 | + pass |
| 73 | + |
68 | 74 |
|
69 | 75 | class CClass(BClass):
|
70 |
| - pass |
| 76 | + pass |
| 77 | + |
71 | 78 |
|
72 | 79 | class DClass(BClass):
|
73 |
| - pass |
| 80 | + pass |
| 81 | + |
74 | 82 |
|
75 | 83 | def custom_set(self, key, value):
|
76 |
| - object.__setattr__(self, key, value + 10 if isinstance(value, int) else value) |
| 84 | + object.__setattr__(self, key, value + 10 if isinstance(value, int) else value) |
| 85 | + |
77 | 86 |
|
78 | 87 | def custom_get(self, key):
|
79 |
| - value = object.__getattribute__(self, key) |
80 |
| - return value + 100 if isinstance(value, int) else value |
| 88 | + value = object.__getattribute__(self, key) |
| 89 | + return value + 100 if isinstance(value, int) else value |
| 90 | + |
81 | 91 |
|
82 | 92 | def test_assignments():
|
83 |
| - object = CClass() |
84 |
| - # writing to BClass changes the result, writing to DClass doesn't |
85 |
| - targets = (AClass, BClass, DClass, CClass, object) |
86 |
| - results = (0, 1, 1, 3, 4) |
87 |
| - for i in range(0, len(targets)): |
88 |
| - targets[i].foo = i |
89 |
| - assert object.foo == results[i], "normal %d" %i |
90 |
| - # make sure that a custom __getattribute__ is used |
91 |
| - BClass.__getattribute__ = custom_get |
92 |
| - for i in range(0, len(targets)): |
93 |
| - targets[i].bar = i |
94 |
| - assert object.bar == results[i] + 100, "custom get %d" % i |
95 |
| - # check correct lookups when deleting attributes |
96 |
| - for i in reversed(range(0, len(targets))): |
97 |
| - assert object.bar == results[i] + 100, "delete %d" % i |
98 |
| - del targets[i].bar |
99 |
| - # make sure a custom __setattr__ is used |
100 |
| - BClass.__setattr__ = custom_set |
101 |
| - object.baz = 9 |
102 |
| - assert object.baz == 119, "custom set" |
| 93 | + object = CClass() |
| 94 | + # writing to BClass changes the result, writing to DClass doesn't |
| 95 | + targets = (AClass, BClass, DClass, CClass, object) |
| 96 | + results = (0, 1, 1, 3, 4) |
| 97 | + for i in range(0, len(targets)): |
| 98 | + targets[i].foo = i |
| 99 | + assert object.foo == results[i], "normal %d" % i |
| 100 | + # make sure that a custom __getattribute__ is used |
| 101 | + BClass.__getattribute__ = custom_get |
| 102 | + for i in range(0, len(targets)): |
| 103 | + targets[i].bar = i |
| 104 | + assert object.bar == results[i] + 100, "custom get %d" % i |
| 105 | + # check correct lookups when deleting attributes |
| 106 | + for i in reversed(range(0, len(targets))): |
| 107 | + assert object.bar == results[i] + 100, "delete %d" % i |
| 108 | + del targets[i].bar |
| 109 | + # make sure a custom __setattr__ is used |
| 110 | + BClass.__setattr__ = custom_set |
| 111 | + object.baz = 9 |
| 112 | + assert object.baz == 119, "custom set" |
103 | 113 |
|
104 | 114 |
|
105 | 115 | def test_setattr_via_decorator():
|
106 |
| - def setdec(func): |
107 |
| - setattr(func, 'SPECIAL_ATTR', {'a': 1, 'b': 2}) |
108 |
| - return func |
| 116 | + def setdec(func): |
| 117 | + setattr(func, 'SPECIAL_ATTR', {'a': 1, 'b': 2}) |
| 118 | + return func |
109 | 119 |
|
110 |
| - @setdec |
111 |
| - def f(): |
112 |
| - return 1 |
| 120 | + @setdec |
| 121 | + def f(): |
| 122 | + return 1 |
113 | 123 |
|
114 |
| - assert hasattr(f, 'SPECIAL_ATTR') |
115 |
| - assert getattr(f, 'SPECIAL_ATTR') == {'a': 1, 'b': 2} |
| 124 | + assert hasattr(f, 'SPECIAL_ATTR') |
| 125 | + assert getattr(f, 'SPECIAL_ATTR') == {'a': 1, 'b': 2} |
116 | 126 |
|
| 127 | + class MyClass(object): |
| 128 | + @setdec |
| 129 | + def f(self): |
| 130 | + return 1 |
117 | 131 |
|
118 |
| - class MyClass(object): |
119 |
| - @setdec |
120 |
| - def f(self): |
121 |
| - return 1 |
| 132 | + m = MyClass() |
| 133 | + assert hasattr(m.f, 'SPECIAL_ATTR') |
| 134 | + assert getattr(m.f, 'SPECIAL_ATTR') == {'a': 1, 'b': 2} |
| 135 | + |
| 136 | + |
| 137 | +def test_deepcopy_attribute_removal(): |
| 138 | + from copy import deepcopy |
| 139 | + |
| 140 | + class A: |
| 141 | + a = "a" |
| 142 | + |
| 143 | + def add_rem_attr(self): |
| 144 | + self.b = "b" |
| 145 | + del self.b |
| 146 | + |
| 147 | + i1 = A() |
| 148 | + assert i1.__dict__ == deepcopy(i1).__dict__ |
122 | 149 |
|
123 |
| - m = MyClass() |
124 |
| - assert hasattr(m.f, 'SPECIAL_ATTR') |
125 |
| - assert getattr(m.f, 'SPECIAL_ATTR') == {'a': 1, 'b': 2} |
| 150 | + i1.add_rem_attr() |
| 151 | + assert i1.__dict__ == deepcopy(i1).__dict__ |
0 commit comments