1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
5 Test cases for twisted.reflect module.
9 from ihooks import ModuleImporter
12 from collections import deque
16 from twisted.trial import unittest
17 from twisted.python import reflect, util
18 from twisted.python.versions import Version
22 class SettableTest(unittest.TestCase):
24 self.setter = reflect.Settable()
31 self.assertEqual(self.setter.a, 1)
32 self.assertEqual(self.setter.b, 2)
36 class AccessorTester(reflect.Accessor):
40 self.reallySet('x', x)
53 class PropertyAccessorTester(reflect.PropertyAccessor):
55 Test class to check L{reflect.PropertyAccessor} functionalities.
65 self.reallySet('x', x)
78 class AccessorTest(unittest.TestCase):
80 self.tester = AccessorTester()
84 self.assertEqual(self.tester.x, 1)
85 self.assertEqual(self.tester.y, 1)
88 self.assertEqual(self.tester.z, 1)
89 self.assertEqual(self.tester.q, 1)
93 self.assertEqual(self.tester.q, 1)
95 self.assertEqual(hasattr(self.tester, "q"), 0)
98 self.assertEqual(hasattr(self.tester, "x"), 0)
102 class PropertyAccessorTest(AccessorTest):
104 Tests for L{reflect.PropertyAccessor}, using L{PropertyAccessorTester}.
108 self.tester = PropertyAccessorTester()
111 def test_setWithDefaultValue(self):
113 If an attribute is present in the class, it can be retrieved by
116 self.assertEqual(self.tester.r, 0)
118 self.assertEqual(self.tester.r, 0)
119 self.assertEqual(self.tester.s, 1)
122 def test_getValueInDict(self):
124 The attribute value can be overriden by directly modifying the value in
127 self.tester.__dict__["r"] = 10
128 self.assertEqual(self.tester.r, 10)
131 def test_notYetInDict(self):
133 If a getter is defined on an attribute but without any default value,
134 it raises C{AttributeError} when trying to access it.
136 self.assertRaises(AttributeError, getattr, self.tester, "x")
140 class LookupsTestCase(unittest.TestCase):
142 Tests for L{namedClass}, L{namedModule}, and L{namedAny}.
145 def test_namedClassLookup(self):
147 L{namedClass} should return the class object for the name it is passed.
149 self.assertIdentical(
150 reflect.namedClass("twisted.python.reflect.Summer"),
154 def test_namedModuleLookup(self):
156 L{namedModule} should return the module object for the name it is
159 self.assertIdentical(
160 reflect.namedModule("twisted.python.reflect"), reflect)
163 def test_namedAnyPackageLookup(self):
165 L{namedAny} should return the package object for the name it is passed.
167 import twisted.python
168 self.assertIdentical(
169 reflect.namedAny("twisted.python"), twisted.python)
171 def test_namedAnyModuleLookup(self):
173 L{namedAny} should return the module object for the name it is passed.
175 self.assertIdentical(
176 reflect.namedAny("twisted.python.reflect"), reflect)
179 def test_namedAnyClassLookup(self):
181 L{namedAny} should return the class object for the name it is passed.
183 self.assertIdentical(
184 reflect.namedAny("twisted.python.reflect.Summer"), reflect.Summer)
187 def test_namedAnyAttributeLookup(self):
189 L{namedAny} should return the object an attribute of a non-module,
190 non-package object is bound to for the name it is passed.
192 # Note - not assertEqual because unbound method lookup creates a new
193 # object every time. This is a foolishness of Python's object
194 # implementation, not a bug in Twisted.
196 reflect.namedAny("twisted.python.reflect.Summer.reallySet"),
197 reflect.Summer.reallySet)
200 def test_namedAnySecondAttributeLookup(self):
202 L{namedAny} should return the object an attribute of an object which
203 itself was an attribute of a non-module, non-package object is bound to
204 for the name it is passed.
206 self.assertIdentical(
208 "twisted.python.reflect.Summer.reallySet.__doc__"),
209 reflect.Summer.reallySet.__doc__)
212 def test_importExceptions(self):
214 Exceptions raised by modules which L{namedAny} causes to be imported
215 should pass through L{namedAny} to the caller.
219 reflect.namedAny, "twisted.test.reflect_helper_ZDE")
220 # Make sure that this behavior is *consistent* for 2.3, where there is
221 # no post-failed-import cleanup
224 reflect.namedAny, "twisted.test.reflect_helper_ZDE")
227 reflect.namedAny, "twisted.test.reflect_helper_VE")
228 # Modules which themselves raise ImportError when imported should result in an ImportError
231 reflect.namedAny, "twisted.test.reflect_helper_IE")
234 def test_attributeExceptions(self):
236 If segments on the end of a fully-qualified Python name represents
237 attributes which aren't actually present on the object represented by
238 the earlier segments, L{namedAny} should raise an L{AttributeError}.
242 reflect.namedAny, "twisted.nosuchmoduleintheworld")
243 # ImportError behaves somewhat differently between "import
244 # extant.nonextant" and "import extant.nonextant.nonextant", so test
245 # the latter as well.
248 reflect.namedAny, "twisted.nosuch.modulein.theworld")
251 reflect.namedAny, "twisted.python.reflect.Summer.nosuchattributeintheworld")
254 def test_invalidNames(self):
256 Passing a name which isn't a fully-qualified Python name to L{namedAny}
257 should result in one of the following exceptions:
258 - L{InvalidName}: the name is not a dot-separated list of Python objects
259 - L{ObjectNotFound}: the object doesn't exist
260 - L{ModuleNotFound}: the object doesn't exist and there is only one
261 component in the name
263 err = self.assertRaises(reflect.ModuleNotFound, reflect.namedAny,
264 'nosuchmoduleintheworld')
265 self.assertEqual(str(err), "No module named 'nosuchmoduleintheworld'")
267 # This is a dot-separated list, but it isn't valid!
268 err = self.assertRaises(reflect.ObjectNotFound, reflect.namedAny,
270 self.assertEqual(str(err), "'@#$@(#.!@(#!@#' does not name an object")
272 err = self.assertRaises(reflect.ObjectNotFound, reflect.namedAny,
273 "tcelfer.nohtyp.detsiwt")
276 "'tcelfer.nohtyp.detsiwt' does not name an object")
278 err = self.assertRaises(reflect.InvalidName, reflect.namedAny, '')
279 self.assertEqual(str(err), 'Empty module name')
281 for invalidName in ['.twisted', 'twisted.', 'twisted..python']:
282 err = self.assertRaises(
283 reflect.InvalidName, reflect.namedAny, invalidName)
286 "name must be a string giving a '.'-separated list of Python "
287 "identifiers, not %r" % (invalidName,))
291 class ImportHooksLookupTests(LookupsTestCase):
293 Tests for lookup methods in the presence of L{ihooks}-style import hooks.
294 Runs all of the tests from L{LookupsTestCase} after installing a custom
299 Perturb the normal import behavior subtly by installing an import
300 hook. No custom behavior is provided, but this adds some extra
301 frames to the call stack, which L{namedAny} must be able to account
304 self.importer = ModuleImporter()
305 self.importer.install()
310 Uninstall the custom import hook.
312 self.importer.uninstall()
316 class ObjectGrep(unittest.TestCase):
317 def test_dictionary(self):
319 Test references search through a dictionnary, as a key or as a value.
325 self.assertIn("[None]", reflect.objgrep(d1, o, reflect.isSame))
326 self.assertIn("{None}", reflect.objgrep(d2, o, reflect.isSame))
330 Test references search through a list.
335 self.assertIn("[1]", reflect.objgrep(L, o, reflect.isSame))
337 def test_tuple(self):
339 Test references search through a tuple.
344 self.assertIn("[0]", reflect.objgrep(T, o, reflect.isSame))
346 def test_instance(self):
348 Test references search through an object attribute.
356 self.assertIn(".o", reflect.objgrep(d, o, reflect.isSame))
358 def test_weakref(self):
360 Test references search through a weakref object.
367 self.assertIn("()", reflect.objgrep(w1, o, reflect.isSame))
369 def test_boundMethod(self):
371 Test references search through method special attributes.
379 self.assertIn(".im_self", reflect.objgrep(m, m.im_self, reflect.isSame))
380 self.assertIn(".im_class", reflect.objgrep(m, m.im_class, reflect.isSame))
381 self.assertIn(".im_func", reflect.objgrep(m, m.im_func, reflect.isSame))
383 def test_everything(self):
385 Test references search using complex set of objects.
392 D1 = {(): "baz", None: "Quux", o: "Foosh"}
393 L = [None, (), D1, 3]
395 D2 = {0: "foo", 1: "bar", 2: T}
401 self.assertIn("().im_self.attr[2][0][2]{'Foosh'}", reflect.objgrep(w, o, reflect.isSame))
403 def test_depthLimit(self):
405 Test the depth of references search.
412 self.assertEqual(['[0]'], reflect.objgrep(d, a, reflect.isSame, maxDepth=1))
413 self.assertEqual(['[0]', '[1][0]'], reflect.objgrep(d, a, reflect.isSame, maxDepth=2))
414 self.assertEqual(['[0]', '[1][0]', '[1][1][0]'], reflect.objgrep(d, a, reflect.isSame, maxDepth=3))
416 def test_deque(self):
418 Test references search through a deque object. Only for Python > 2.3.
425 self.assertIn("[1]", reflect.objgrep(D, o, reflect.isSame))
428 test_deque.skip = "Deque not available"
431 class GetClass(unittest.TestCase):
436 self.assertIn(reflect.getClass(OldClass).__name__, ('class', 'classobj'))
437 self.assertEqual(reflect.getClass(old).__name__, 'OldClass')
440 class NewClass(object):
443 self.assertEqual(reflect.getClass(NewClass).__name__, 'type')
444 self.assertEqual(reflect.getClass(new).__name__, 'NewClass')
448 class Breakable(object):
455 raise RuntimeError("str!")
461 raise RuntimeError("repr!")
467 class BrokenType(Breakable, type):
470 def get___name__(self):
472 raise RuntimeError("no name")
474 __name__ = property(get___name__)
478 class BTBase(Breakable):
479 __metaclass__ = BrokenType
485 class NoClassAttr(Breakable):
486 __class__ = property(lambda x: x.not_class)
490 class SafeRepr(unittest.TestCase):
492 Tests for L{reflect.safe_repr} function.
495 def test_workingRepr(self):
497 L{reflect.safe_repr} produces the same output as C{repr} on a working
501 self.assertEqual(reflect.safe_repr(x), repr(x))
504 def test_brokenRepr(self):
506 L{reflect.safe_repr} returns a string with class name, address, and
507 traceback when the repr call failed.
511 bRepr = reflect.safe_repr(b)
512 self.assertIn("Breakable instance at 0x", bRepr)
513 # Check that the file is in the repr, but without the extension as it
515 self.assertIn(os.path.splitext(__file__)[0], bRepr)
516 self.assertIn("RuntimeError: repr!", bRepr)
519 def test_brokenStr(self):
521 L{reflect.safe_repr} isn't affected by a broken C{__str__} method.
525 self.assertEqual(reflect.safe_repr(b), repr(b))
528 def test_brokenClassRepr(self):
532 reflect.safe_repr(X())
535 def test_unsignedID(self):
537 L{unsignedID} is used to print ID of the object in case of error, not
538 standard ID value which can be negative.
547 except (TypeError, KeyError):
549 self.addCleanup(util.setIDFunction, util.setIDFunction(fakeID))
551 xRepr = reflect.safe_repr(X)
552 self.assertIn("0x64", xRepr)
555 def test_brokenClassStr(self):
559 reflect.safe_repr(X())
562 def test_brokenClassAttribute(self):
564 If an object raises an exception when accessing its C{__class__}
565 attribute, L{reflect.safe_repr} uses C{type} to retrieve the class
570 bRepr = reflect.safe_repr(b)
571 self.assertIn("NoClassAttr instance at 0x", bRepr)
572 self.assertIn(os.path.splitext(__file__)[0], bRepr)
573 self.assertIn("RuntimeError: repr!", bRepr)
576 def test_brokenClassNameAttribute(self):
578 If a class raises an exception when accessing its C{__name__} attribute
579 B{and} when calling its C{__str__} implementation, L{reflect.safe_repr}
580 returns 'BROKEN CLASS' instead of the class name.
584 xRepr = reflect.safe_repr(X())
585 self.assertIn("<BROKEN CLASS AT 0x", xRepr)
586 self.assertIn(os.path.splitext(__file__)[0], xRepr)
587 self.assertIn("RuntimeError: repr!", xRepr)
591 class SafeStr(unittest.TestCase):
593 Tests for L{reflect.safe_str} function.
596 def test_workingStr(self):
598 self.assertEqual(reflect.safe_str(x), str(x))
601 def test_brokenStr(self):
607 def test_brokenRepr(self):
613 def test_brokenClassStr(self):
617 reflect.safe_str(X())
620 def test_brokenClassRepr(self):
624 reflect.safe_str(X())
627 def test_brokenClassAttribute(self):
629 If an object raises an exception when accessing its C{__class__}
630 attribute, L{reflect.safe_str} uses C{type} to retrieve the class
635 bStr = reflect.safe_str(b)
636 self.assertIn("NoClassAttr instance at 0x", bStr)
637 self.assertIn(os.path.splitext(__file__)[0], bStr)
638 self.assertIn("RuntimeError: str!", bStr)
641 def test_brokenClassNameAttribute(self):
643 If a class raises an exception when accessing its C{__name__} attribute
644 B{and} when calling its C{__str__} implementation, L{reflect.safe_str}
645 returns 'BROKEN CLASS' instead of the class name.
649 xStr = reflect.safe_str(X())
650 self.assertIn("<BROKEN CLASS AT 0x", xStr)
651 self.assertIn(os.path.splitext(__file__)[0], xStr)
652 self.assertIn("RuntimeError: str!", xStr)
656 class FilenameToModule(unittest.TestCase):
658 Test L{reflect.filenameToModuleName} detection.
660 def test_directory(self):
662 Tests it finds good name for directories/packages.
664 module = reflect.filenameToModuleName(os.path.join('twisted', 'test'))
665 self.assertEqual(module, 'test')
666 module = reflect.filenameToModuleName(os.path.join('twisted', 'test')
668 self.assertEqual(module, 'test')
672 Test it finds good name for files.
674 module = reflect.filenameToModuleName(
675 os.path.join('twisted', 'test', 'test_reflect.py'))
676 self.assertEqual(module, 'test_reflect')
680 class FullyQualifiedNameTests(unittest.TestCase):
682 Test for L{reflect.fullyQualifiedName}.
685 def _checkFullyQualifiedName(self, obj, expected):
687 Helper to check that fully qualified name of C{obj} results to
691 reflect.fullyQualifiedName(obj), expected)
694 def test_package(self):
696 L{reflect.fullyQualifiedName} returns the full name of a package and
700 self._checkFullyQualifiedName(twisted, 'twisted')
701 import twisted.python
702 self._checkFullyQualifiedName(twisted.python, 'twisted.python')
705 def test_module(self):
707 L{reflect.fullyQualifiedName} returns the name of a module inside a a
710 self._checkFullyQualifiedName(reflect, 'twisted.python.reflect')
711 import twisted.trial.unittest
712 self._checkFullyQualifiedName(twisted.trial.unittest,
713 'twisted.trial.unittest')
716 def test_class(self):
718 L{reflect.fullyQualifiedName} returns the name of a class and its
721 self._checkFullyQualifiedName(reflect.Settable,
722 'twisted.python.reflect.Settable')
725 def test_function(self):
727 L{reflect.fullyQualifiedName} returns the name of a function inside its
730 self._checkFullyQualifiedName(reflect.fullyQualifiedName,
731 "twisted.python.reflect.fullyQualifiedName")
734 def test_boundMethod(self):
736 L{reflect.fullyQualifiedName} returns the name of a bound method inside
737 its class and its module.
739 self._checkFullyQualifiedName(
740 reflect.PropertyAccessor().reallyDel,
741 "twisted.python.reflect.PropertyAccessor.reallyDel")
744 def test_unboundMethod(self):
746 L{reflect.fullyQualifiedName} returns the name of an unbound method
747 inside its class and its module.
749 self._checkFullyQualifiedName(
750 reflect.PropertyAccessor.reallyDel,
751 "twisted.python.reflect.PropertyAccessor.reallyDel")
755 class DeprecationTestCase(unittest.TestCase):
757 Test deprecations in twisted.python.reflect
760 def test_allYourBase(self):
762 Test deprecation of L{reflect.allYourBase}. See #5481 for removal.
765 (Version("Twisted", 11, 0, 0), "inspect.getmro"),
766 reflect.allYourBase, DeprecationTestCase)
769 def test_accumulateBases(self):
771 Test deprecation of L{reflect.accumulateBases}. See #5481 for removal.
775 (Version("Twisted", 11, 0, 0), "inspect.getmro"),
776 reflect.accumulateBases, DeprecationTestCase, l, None)
779 def lookForDeprecationWarning(self, testMethod, attributeName, warningMsg):
781 Test deprecation of attribute 'reflect.attributeName' by calling
782 'reflect.testMethod' and verifying the warning message
785 @param testMethod: Name of the offending function to be used with
787 @type testmethod: C{str}
789 @param attributeName: Name of attribute to be checked for deprecation
790 @type attributeName: C{str}
792 @param warningMsg: Deprecation warning message
793 @type warningMsg: C{str}
795 warningsShown = self.flushWarnings([testMethod])
796 self.assertEqual(len(warningsShown), 1)
797 self.assertIdentical(warningsShown[0]['category'], DeprecationWarning)
799 warningsShown[0]['message'],
800 "twisted.python.reflect." + attributeName + " "
801 "was deprecated in Twisted 12.1.0: " + warningMsg + ".")
804 def test_settable(self):
806 Test deprecation of L{reflect.Settable}.
809 self.lookForDeprecationWarning(
810 self.test_settable, "Settable",
811 "Settable is old and untested. Please write your own version of this "
812 "functionality if you need it")
815 def test_accessorType(self):
817 Test deprecation of L{reflect.AccessorType}.
819 reflect.AccessorType(' ', ( ), { })
820 self.lookForDeprecationWarning(
821 self.test_accessorType, "AccessorType",
822 "AccessorType is old and untested. Please write your own version of "
823 "this functionality if you need it")
826 def test_propertyAccessor(self):
828 Test deprecation of L{reflect.PropertyAccessor}.
830 reflect.PropertyAccessor()
831 self.lookForDeprecationWarning(
832 self.test_propertyAccessor, "PropertyAccessor",
833 "PropertyAccessor is old and untested. Please write your own "
834 "version of this functionality if you need it")
837 def test_accessor(self):
839 Test deprecation of L{reflect.Accessor}.
842 self.lookForDeprecationWarning(
843 self.test_accessor, "Accessor",
844 "Accessor is an implementation for Python 2.1 which is no longer "
845 "supported by Twisted")
848 def test_originalAccessor(self):
850 Test deprecation of L{reflect.OriginalAccessor}.
852 reflect.OriginalAccessor()
853 self.lookForDeprecationWarning(
854 self.test_originalAccessor, "OriginalAccessor",
855 "OriginalAccessor is a reference to class "
856 "twisted.python.reflect.Accessor which is deprecated")
859 def test_summer(self):
861 Test deprecation of L{reflect.Summer}.
864 self.lookForDeprecationWarning(
865 self.test_summer, "Summer",
866 "Summer is a child class of twisted.python.reflect.Accessor which "