-
Notifications
You must be signed in to change notification settings - Fork 227
/
Copy pathtest_attribute_customize.py
265 lines (193 loc) · 7.82 KB
/
test_attribute_customize.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# Licensed to the .NET Foundation under one or more agreements.
# The .NET Foundation licenses this file to you under the Apache 2.0 License.
# See the LICENSE file in the project root for more information.
import unittest
from iptest import IronPythonTestCase, run_test
global flag
def new_classes():
class C1: pass
class C2(object): pass
return C1, C2
# used as handler for __getattr__ and __getattribute__
def return_100(self, name): return 100
def throw_attribute_error(self, name): raise AttributeError
def throw_assertion_error(self, name): raise AssertionError
class AttributeCustomizeTest(IronPythonTestCase):
def test_getattr_alone(self):
C1, C2 = new_classes()
def __init__(self): self.x = 10
def plus_100(self, name):
if self.__class__ == C2:
pass
for C in [C1, C2]:
C.__init__ = __init__
C.y = 20
c = C()
C.__getattr__ = return_100
self.assertEqual([c.x, c.y, c.z], [10, 20, 100])
def access_z(): return c.z
C.__getattr__ = throw_attribute_error
self.assertEqual([c.x, c.y], [10, 20])
self.assertRaises(AttributeError, access_z)
C.__getattr__ = throw_assertion_error
self.assertRaises(AssertionError, access_z)
C.__getattr__ = lambda self, name: self.x + 200 # access attribute inside
self.assertEqual([c.x, c.y, c.z], [10, 20, 210])
del C.__getattr__
self.assertRaises(AttributeError, access_z)
def test_setattr_alone(self):
global flag
C1, C2 = new_classes()
def f(self): self.x = 10
def simply_record(self, name, value): global flag; flag = "%s %s" % (name, value)
def simply_throw(self, name, value): raise AssertionError
def add_10_via_dict(self, name, value):
self.__dict__[name] = value + 10
def add_20_via_object(self, name, value):
if self.__class__ == C2:
object.__setattr__(self, name, value + 20)
if self.__class__ == C1:
self.__dict__[name] = value + 20
for C in [C1, C2]:
C.set_something = f
c = C()
c.x = 0
C.__setattr__ = simply_record
flag = 0
c.set_something()
self.assertEqual(flag, "x 10")
self.assertEqual(c.x, 0) # unchanged
c.y = 20
self.assertEqual(flag, "y 20")
self.assertRaises(AttributeError, lambda: c.y)
C.__setattr__ = simply_throw
self.assertRaises(AssertionError, c.set_something) # even if c.x already exists
C.z = 30 # ok: class variable
self.assertEqual(c.z, 30)
C.__setattr__ = add_10_via_dict
c.set_something()
self.assertEqual(c.x, 20)
C.__setattr__ = add_20_via_object
c.u = 50
self.assertEqual(c.u, 70)
del C.__setattr__
c.z = 40
self.assertEqual([c.z, C.z], [40, 30])
def test_delattr_only(self):
C1, C2 = new_classes()
# low pri
@unittest.skip("bug 365168")
def test_negative1(self):
class C:
def __setattr__(self, name, value):
object.__setattr__(self, name, value)
try: C().x = 1
except TypeError: pass
else: self.fail("should have thrown: can't apply this __setattr__ to instance object")
class C:
def __getattr__(self, name):
object.__getattribute__(self, name)
self.assertRaisesMessage(AttributeError, "'instance' object has no attribute 'x'", lambda: C().x)
def test_bad_signatures(self):
C1, C2 = new_classes()
def bad1(self): pass
def bad2(self, x): pass
def bad3(self, x, y): pass
def bad4(self, x, y, z): pass
for C in [C1, C2]:
c = C()
def f(): c.x = 1
for bad_for_get in [bad1, bad3]:
C.__getattr__ = bad_for_get
self.assertRaises(TypeError, lambda: c.x)
for bad_for_set in [bad2, bad4]:
C.__setattr__ = bad_for_set
self.assertRaises(TypeError, f)
for bad_for_getattribute in [bad1, bad3]:
C2.__getattribute__ = bad_for_getattribute
self.assertRaises(TypeError, lambda: c.x)
def test_getattribute_only(self):
class C:
def __getattribute__(self, name):
return 10
c = C()
self.assertRaises(AttributeError, lambda: c.x) # __getattribute__ only works for new-style
class C(object):
def set_y(self): self.y = 30
c = C()
f = c.set_y
c.x = 10
C.__getattribute__ = return_100
self.assertEqual(100, c.x)
c.x = 20
def plus_100(self, name):
try:
return object.__getattribute__(self, name) + 100
except AttributeError:
return 200
C.__getattribute__ = plus_100
self.assertEqual(120, c.x)
f()
self.assertEqual(130, c.y)
self.assertEqual(200, c.z)
C.__getattribute__ = throw_attribute_error
self.assertRaises(AttributeError, lambda: c.x)
C.__getattribute__ = throw_assertion_error
self.assertRaises(AssertionError, lambda: c.x)
del C.__getattribute__
self.assertEqual(c.x, 20)
self.assertEqual(c.y, 30)
self.assertRaises(AttributeError, lambda: c.z)
def test_getattr_and_getattribute_together(self):
class C(object): pass
c = C()
C.__getattr__ = lambda *args: 20
C.__getattribute__ = lambda *args: 30
self.assertEqual(c.x, 30)
C.__getattribute__ = throw_attribute_error
self.assertEqual(c.x, 20)
C.__getattribute__ = throw_assertion_error
self.assertRaises(AssertionError, lambda: c.x)
C.__getattribute__ = lambda *args: C.__getattr__(*args)
self.assertEqual(c.x, 20)
def test_subclassing(self):
C1, C2 = new_classes()
## new style
class D(C2): pass
d = D()
d.x = 10
C2.__getattr__ = return_100
self.assertEqual(d.y, 100)
del C2.__getattr__
def f(self, name, value): self.__dict__[name] = value + 10
C2.__setattr__ = f
d.x = 20
self.assertEqual(d.x, 30)
del C2.__setattr__
C2.__getattribute__ = return_100
#self.assertEqual(d.x, 100) # bug 365242
## old style
class D(C1): pass
d = D()
C1.__getattr__ = return_100
#self.assertRaises(AttributeError, lambda: d.y) # (no?) dynamism for old style, bug 365266
class D(C1): pass
d = D()
d.x = 10
self.assertEqual([d.x, d.y], [10, 100])
C1.__setattr__ = f
class D(C1): pass
d = D()
d.x = 20
self.assertEqual([d.x, d.y], [30, 100])
C1.__getattribute__ = lambda *args: 200 # __getattribute__ not honored
class D(C1): pass
d = D()
self.assertEqual([d.x, d.y], [100, 100])
def test_delete_getattribute(self):
class B(object):
def __getattribute__(self, name): pass
class D(B): pass
def f(): del D.__getattribute__
self.assertRaises(AttributeError, f)
run_test(__name__)