OLD | NEW |
| (Empty) |
1 # Copyright (c) 2001-2007 Twisted Matrix Laboratories. | |
2 # See LICENSE for details. | |
3 | |
4 | |
5 """ | |
6 Test cases for twisted.reflect module. | |
7 """ | |
8 | |
9 import weakref, os | |
10 from ihooks import ModuleImporter | |
11 | |
12 try: | |
13 from collections import deque | |
14 except ImportError: | |
15 deque = None | |
16 | |
17 # Twisted Imports | |
18 from twisted.trial import unittest | |
19 from twisted.python import reflect | |
20 | |
21 | |
22 | |
23 class SettableTest(unittest.TestCase): | |
24 def setUp(self): | |
25 self.setter = reflect.Settable() | |
26 | |
27 def tearDown(self): | |
28 del self.setter | |
29 | |
30 def testSet(self): | |
31 self.setter(a=1, b=2) | |
32 self.failUnlessEqual(self.setter.a, 1) | |
33 self.failUnlessEqual(self.setter.b, 2) | |
34 | |
35 | |
36 class AccessorTester(reflect.Accessor): | |
37 def set_x(self, x): | |
38 self.y = x | |
39 self.reallySet('x',x) | |
40 | |
41 def get_z(self): | |
42 self.q = 1 | |
43 return 1 | |
44 | |
45 def del_z(self): | |
46 self.reallyDel("q") | |
47 | |
48 | |
49 class AccessorTest(unittest.TestCase): | |
50 def setUp(self): | |
51 self.tester = AccessorTester() | |
52 | |
53 def testSet(self): | |
54 self.tester.x = 1 | |
55 self.failUnlessEqual(self.tester.x, 1) | |
56 self.failUnlessEqual(self.tester.y, 1) | |
57 | |
58 def testGet(self): | |
59 self.failUnlessEqual(self.tester.z, 1) | |
60 self.failUnlessEqual(self.tester.q, 1) | |
61 | |
62 def testDel(self): | |
63 self.tester.z | |
64 self.failUnlessEqual(self.tester.q, 1) | |
65 del self.tester.z | |
66 self.failUnlessEqual(hasattr(self.tester, "q"), 0) | |
67 self.tester.x = 1 | |
68 del self.tester.x | |
69 self.failUnlessEqual(hasattr(self.tester, "x"), 0) | |
70 | |
71 | |
72 class LookupsTestCase(unittest.TestCase): | |
73 """ | |
74 Tests for L{namedClass}, L{namedModule}, and L{namedAny}. | |
75 """ | |
76 | |
77 def test_namedClassLookup(self): | |
78 """ | |
79 L{namedClass} should return the class object for the name it is passed. | |
80 """ | |
81 self.assertIdentical( | |
82 reflect.namedClass("twisted.python.reflect.Summer"), | |
83 reflect.Summer) | |
84 | |
85 | |
86 def test_namedModuleLookup(self): | |
87 """ | |
88 L{namedModule} should return the module object for the name it is | |
89 passed. | |
90 """ | |
91 self.assertIdentical( | |
92 reflect.namedModule("twisted.python.reflect"), reflect) | |
93 | |
94 | |
95 def test_namedAnyPackageLookup(self): | |
96 """ | |
97 L{namedAny} should return the package object for the name it is passed. | |
98 """ | |
99 import twisted.python | |
100 self.assertIdentical( | |
101 reflect.namedAny("twisted.python"), twisted.python) | |
102 | |
103 def test_namedAnyModuleLookup(self): | |
104 """ | |
105 L{namedAny} should return the module object for the name it is passed. | |
106 """ | |
107 self.assertIdentical( | |
108 reflect.namedAny("twisted.python.reflect"), reflect) | |
109 | |
110 | |
111 def test_namedAnyClassLookup(self): | |
112 """ | |
113 L{namedAny} should return the class object for the name it is passed. | |
114 """ | |
115 self.assertIdentical( | |
116 reflect.namedAny("twisted.python.reflect.Summer"), reflect.Summer) | |
117 | |
118 | |
119 def test_namedAnyAttributeLookup(self): | |
120 """ | |
121 L{namedAny} should return the object an attribute of a non-module, | |
122 non-package object is bound to for the name it is passed. | |
123 """ | |
124 # Note - not assertEqual because unbound method lookup creates a new | |
125 # object every time. This is a foolishness of Python's object | |
126 # implementation, not a bug in Twisted. | |
127 self.assertEqual( | |
128 reflect.namedAny("twisted.python.reflect.Summer.reallySet"), | |
129 reflect.Summer.reallySet) | |
130 | |
131 | |
132 def test_namedAnySecondAttributeLookup(self): | |
133 """ | |
134 L{namedAny} should return the object an attribute of an object which | |
135 itself was an attribute of a non-module, non-package object is bound to | |
136 for the name it is passed. | |
137 """ | |
138 self.assertIdentical( | |
139 reflect.namedAny( | |
140 "twisted.python.reflect.Summer.reallySet.__doc__"), | |
141 reflect.Summer.reallySet.__doc__) | |
142 | |
143 | |
144 def test_importExceptions(self): | |
145 """ | |
146 Exceptions raised by modules which L{namedAny} causes to be imported | |
147 should pass through L{namedAny} to the caller. | |
148 """ | |
149 self.assertRaises( | |
150 ZeroDivisionError, | |
151 reflect.namedAny, "twisted.test.reflect_helper_ZDE") | |
152 # Make sure that this behavior is *consistent* for 2.3, where there is | |
153 # no post-failed-import cleanup | |
154 self.assertRaises( | |
155 ZeroDivisionError, | |
156 reflect.namedAny, "twisted.test.reflect_helper_ZDE") | |
157 self.assertRaises( | |
158 ValueError, | |
159 reflect.namedAny, "twisted.test.reflect_helper_VE") | |
160 # Modules which themselves raise ImportError when imported should result
in an ImportError | |
161 self.assertRaises( | |
162 ImportError, | |
163 reflect.namedAny, "twisted.test.reflect_helper_IE") | |
164 | |
165 | |
166 def test_attributeExceptions(self): | |
167 """ | |
168 If segments on the end of a fully-qualified Python name represents | |
169 attributes which aren't actually present on the object represented by | |
170 the earlier segments, L{namedAny} should raise an L{AttributeError}. | |
171 """ | |
172 self.assertRaises( | |
173 AttributeError, | |
174 reflect.namedAny, "twisted.nosuchmoduleintheworld") | |
175 # ImportError behaves somewhat differently between "import | |
176 # extant.nonextant" and "import extant.nonextant.nonextant", so test | |
177 # the latter as well. | |
178 self.assertRaises( | |
179 AttributeError, | |
180 reflect.namedAny, "twisted.nosuch.modulein.theworld") | |
181 self.assertRaises( | |
182 AttributeError, | |
183 reflect.namedAny, "twisted.python.reflect.Summer.nosuchattributeinth
eworld") | |
184 | |
185 | |
186 def test_invalidNames(self): | |
187 """ | |
188 Passing a name which isn't a fully-qualified Python name to L{namedAny} | |
189 should result in a L{ValueError}. | |
190 """ | |
191 # Finally, invalid module names should raise a ValueError | |
192 self.assertRaises( | |
193 ValueError, | |
194 reflect.namedAny, "") | |
195 self.assertRaises( | |
196 ValueError, | |
197 reflect.namedAny, "12345") | |
198 self.assertRaises( | |
199 ValueError, | |
200 reflect.namedAny, "@#$@(#.!@(#!@#") | |
201 # This case is kind of stupid and is mostly a historical accident. | |
202 self.assertRaises( | |
203 ValueError, | |
204 reflect.namedAny, "tcelfer.nohtyp.detsiwt") | |
205 | |
206 | |
207 | |
208 class ImportHooksLookupTests(LookupsTestCase): | |
209 """ | |
210 Tests for lookup methods in the presence of L{ihooks}-style import hooks. | |
211 Runs all of the tests from L{LookupsTestCase} after installing a custom | |
212 import hook. | |
213 """ | |
214 def setUp(self): | |
215 """ | |
216 Perturb the normal import behavior subtly by installing an import | |
217 hook. No custom behavior is provided, but this adds some extra | |
218 frames to the call stack, which L{namedAny} must be able to account | |
219 for. | |
220 """ | |
221 self.importer = ModuleImporter() | |
222 self.importer.install() | |
223 | |
224 | |
225 def tearDown(self): | |
226 """ | |
227 Uninstall the custom import hook. | |
228 """ | |
229 self.importer.uninstall() | |
230 | |
231 | |
232 | |
233 class ObjectGrep(unittest.TestCase): | |
234 def test_dictionary(self): | |
235 """ | |
236 Test references search through a dictionnary, as a key or as a value. | |
237 """ | |
238 o = object() | |
239 d1 = {None: o} | |
240 d2 = {o: None} | |
241 | |
242 self.assertIn("[None]", reflect.objgrep(d1, o, reflect.isSame)) | |
243 self.assertIn("{None}", reflect.objgrep(d2, o, reflect.isSame)) | |
244 | |
245 def test_list(self): | |
246 """ | |
247 Test references search through a list. | |
248 """ | |
249 o = object() | |
250 L = [None, o] | |
251 | |
252 self.assertIn("[1]", reflect.objgrep(L, o, reflect.isSame)) | |
253 | |
254 def test_tuple(self): | |
255 """ | |
256 Test references search through a tuple. | |
257 """ | |
258 o = object() | |
259 T = (o, None) | |
260 | |
261 self.assertIn("[0]", reflect.objgrep(T, o, reflect.isSame)) | |
262 | |
263 def test_instance(self): | |
264 """ | |
265 Test references search through an object attribute. | |
266 """ | |
267 class Dummy: | |
268 pass | |
269 o = object() | |
270 d = Dummy() | |
271 d.o = o | |
272 | |
273 self.assertIn(".o", reflect.objgrep(d, o, reflect.isSame)) | |
274 | |
275 def test_weakref(self): | |
276 """ | |
277 Test references search through a weakref object. | |
278 """ | |
279 class Dummy: | |
280 pass | |
281 o = Dummy() | |
282 w1 = weakref.ref(o) | |
283 | |
284 self.assertIn("()", reflect.objgrep(w1, o, reflect.isSame)) | |
285 | |
286 def test_boundMethod(self): | |
287 """ | |
288 Test references search through method special attributes. | |
289 """ | |
290 class Dummy: | |
291 def dummy(self): | |
292 pass | |
293 o = Dummy() | |
294 m = o.dummy | |
295 | |
296 self.assertIn(".im_self", reflect.objgrep(m, m.im_self, reflect.isSame)) | |
297 self.assertIn(".im_class", reflect.objgrep(m, m.im_class, reflect.isSame
)) | |
298 self.assertIn(".im_func", reflect.objgrep(m, m.im_func, reflect.isSame)) | |
299 | |
300 def test_everything(self): | |
301 """ | |
302 Test references search using complex set of objects. | |
303 """ | |
304 class Dummy: | |
305 def method(self): | |
306 pass | |
307 | |
308 o = Dummy() | |
309 D1 = {(): "baz", None: "Quux", o: "Foosh"} | |
310 L = [None, (), D1, 3] | |
311 T = (L, {}, Dummy()) | |
312 D2 = {0: "foo", 1: "bar", 2: T} | |
313 i = Dummy() | |
314 i.attr = D2 | |
315 m = i.method | |
316 w = weakref.ref(m) | |
317 | |
318 self.assertIn("().im_self.attr[2][0][2]{'Foosh'}", reflect.objgrep(w, o,
reflect.isSame)) | |
319 | |
320 def test_depthLimit(self): | |
321 """ | |
322 Test the depth of references search. | |
323 """ | |
324 a = [] | |
325 b = [a] | |
326 c = [a, b] | |
327 d = [a, c] | |
328 | |
329 self.assertEquals(['[0]'], reflect.objgrep(d, a, reflect.isSame, maxDept
h=1)) | |
330 self.assertEquals(['[0]', '[1][0]'], reflect.objgrep(d, a, reflect.isSam
e, maxDepth=2)) | |
331 self.assertEquals(['[0]', '[1][0]', '[1][1][0]'], reflect.objgrep(d, a,
reflect.isSame, maxDepth=3)) | |
332 | |
333 def test_deque(self): | |
334 """ | |
335 Test references search through a deque object. Only for Python > 2.3. | |
336 """ | |
337 o = object() | |
338 D = deque() | |
339 D.append(None) | |
340 D.append(o) | |
341 | |
342 self.assertIn("[1]", reflect.objgrep(D, o, reflect.isSame)) | |
343 | |
344 if deque is None: | |
345 test_deque.skip = "Deque not available" | |
346 | |
347 | |
348 class GetClass(unittest.TestCase): | |
349 def testOld(self): | |
350 class OldClass: | |
351 pass | |
352 old = OldClass() | |
353 self.assertIn(reflect.getClass(OldClass).__name__, ('class', 'classobj')
) | |
354 self.assertEquals(reflect.getClass(old).__name__, 'OldClass') | |
355 | |
356 def testNew(self): | |
357 class NewClass(object): | |
358 pass | |
359 new = NewClass() | |
360 self.assertEquals(reflect.getClass(NewClass).__name__, 'type') | |
361 self.assertEquals(reflect.getClass(new).__name__, 'NewClass') | |
362 | |
363 class Breakable(object): | |
364 | |
365 breakRepr = False | |
366 breakStr = False | |
367 | |
368 def __str__(self): | |
369 if self.breakStr: | |
370 raise self | |
371 else: | |
372 return '<Breakable>' | |
373 | |
374 def __repr__(self): | |
375 if self.breakRepr: | |
376 raise self | |
377 else: | |
378 return 'Breakable()' | |
379 | |
380 class BrokenType(Breakable, type): | |
381 breakName = False | |
382 def get___name__(self): | |
383 if self.breakName: | |
384 raise RuntimeError("no name") | |
385 return 'BrokenType' | |
386 __name__ = property(get___name__) | |
387 | |
388 class BTBase(Breakable): | |
389 __metaclass__ = BrokenType | |
390 breakRepr = True | |
391 breakStr = True | |
392 | |
393 | |
394 class NoClassAttr(object): | |
395 __class__ = property(lambda x: x.not_class) | |
396 | |
397 class SafeRepr(unittest.TestCase): | |
398 | |
399 def testWorkingRepr(self): | |
400 x = [1,2,3] | |
401 self.assertEquals(reflect.safe_repr(x), repr(x)) | |
402 | |
403 def testBrokenRepr(self): | |
404 b = Breakable() | |
405 b.breakRepr = True | |
406 reflect.safe_repr(b) | |
407 | |
408 def testBrokenStr(self): | |
409 b = Breakable() | |
410 b.breakStr = True | |
411 reflect.safe_repr(b) | |
412 | |
413 def testBrokenClassRepr(self): | |
414 class X(BTBase): | |
415 breakRepr = True | |
416 reflect.safe_repr(X) | |
417 reflect.safe_repr(X()) | |
418 | |
419 def testBrokenClassStr(self): | |
420 class X(BTBase): | |
421 breakStr = True | |
422 reflect.safe_repr(X) | |
423 reflect.safe_repr(X()) | |
424 | |
425 def testBroken__Class__Attr(self): | |
426 reflect.safe_repr(NoClassAttr()) | |
427 | |
428 def testBroken__Class__Name__Attr(self): | |
429 class X(BTBase): | |
430 breakName = True | |
431 reflect.safe_repr(X()) | |
432 | |
433 | |
434 class SafeStr(unittest.TestCase): | |
435 def testWorkingStr(self): | |
436 x = [1,2,3] | |
437 self.assertEquals(reflect.safe_str(x), str(x)) | |
438 | |
439 def testBrokenStr(self): | |
440 b = Breakable() | |
441 b.breakStr = True | |
442 reflect.safe_str(b) | |
443 | |
444 def testBrokenRepr(self): | |
445 b = Breakable() | |
446 b.breakRepr = True | |
447 reflect.safe_str(b) | |
448 | |
449 def testBrokenClassStr(self): | |
450 class X(BTBase): | |
451 breakStr = True | |
452 reflect.safe_str(X) | |
453 reflect.safe_str(X()) | |
454 | |
455 def testBrokenClassRepr(self): | |
456 class X(BTBase): | |
457 breakRepr = True | |
458 reflect.safe_str(X) | |
459 reflect.safe_str(X()) | |
460 | |
461 def testBroken__Class__Attr(self): | |
462 reflect.safe_str(NoClassAttr()) | |
463 | |
464 def testBroken__Class__Name__Attr(self): | |
465 class X(BTBase): | |
466 breakName = True | |
467 reflect.safe_str(X()) | |
468 | |
469 | |
470 class FilenameToModule(unittest.TestCase): | |
471 """ | |
472 Test L{reflect.filenameToModuleName} detection. | |
473 """ | |
474 def test_directory(self): | |
475 """ | |
476 Tests it finds good name for directories/packages. | |
477 """ | |
478 module = reflect.filenameToModuleName(os.path.join('twisted', 'test')) | |
479 self.assertEquals(module, 'test') | |
480 module = reflect.filenameToModuleName(os.path.join('twisted', 'test') | |
481 + os.path.sep) | |
482 self.assertEquals(module, 'test') | |
483 | |
484 def test_file(self): | |
485 """ | |
486 Test it finds good name for files. | |
487 """ | |
488 module = reflect.filenameToModuleName( | |
489 os.path.join('twisted', 'test', 'test_reflect.py')) | |
490 self.assertEquals(module, 'test_reflect') | |
491 | |
OLD | NEW |