Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_reflect.py 24KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826
  1. # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. """
  4. Test cases for the L{twisted.python.reflect} module.
  5. """
  6. import os
  7. import weakref
  8. from collections import deque
  9. from twisted.python import reflect
  10. from twisted.python.reflect import (
  11. accumulateMethods,
  12. addMethodNamesToDict,
  13. fullyQualifiedName,
  14. prefixedMethodNames,
  15. prefixedMethods,
  16. )
  17. from twisted.trial.unittest import SynchronousTestCase as TestCase
  18. class Base:
  19. """
  20. A no-op class which can be used to verify the behavior of
  21. method-discovering APIs.
  22. """
  23. def method(self):
  24. """
  25. A no-op method which can be discovered.
  26. """
  27. class Sub(Base):
  28. """
  29. A subclass of a class with a method which can be discovered.
  30. """
  31. class Separate:
  32. """
  33. A no-op class with methods with differing prefixes.
  34. """
  35. def good_method(self):
  36. """
  37. A no-op method which a matching prefix to be discovered.
  38. """
  39. def bad_method(self):
  40. """
  41. A no-op method with a mismatched prefix to not be discovered.
  42. """
  43. class AccumulateMethodsTests(TestCase):
  44. """
  45. Tests for L{accumulateMethods} which finds methods on a class hierarchy and
  46. adds them to a dictionary.
  47. """
  48. def test_ownClass(self):
  49. """
  50. If x is and instance of Base and Base defines a method named method,
  51. L{accumulateMethods} adds an item to the given dictionary with
  52. C{"method"} as the key and a bound method object for Base.method value.
  53. """
  54. x = Base()
  55. output = {}
  56. accumulateMethods(x, output)
  57. self.assertEqual({"method": x.method}, output)
  58. def test_baseClass(self):
  59. """
  60. If x is an instance of Sub and Sub is a subclass of Base and Base
  61. defines a method named method, L{accumulateMethods} adds an item to the
  62. given dictionary with C{"method"} as the key and a bound method object
  63. for Base.method as the value.
  64. """
  65. x = Sub()
  66. output = {}
  67. accumulateMethods(x, output)
  68. self.assertEqual({"method": x.method}, output)
  69. def test_prefix(self):
  70. """
  71. If a prefix is given, L{accumulateMethods} limits its results to
  72. methods beginning with that prefix. Keys in the resulting dictionary
  73. also have the prefix removed from them.
  74. """
  75. x = Separate()
  76. output = {}
  77. accumulateMethods(x, output, "good_")
  78. self.assertEqual({"method": x.good_method}, output)
  79. class PrefixedMethodsTests(TestCase):
  80. """
  81. Tests for L{prefixedMethods} which finds methods on a class hierarchy and
  82. adds them to a dictionary.
  83. """
  84. def test_onlyObject(self):
  85. """
  86. L{prefixedMethods} returns a list of the methods discovered on an
  87. object.
  88. """
  89. x = Base()
  90. output = prefixedMethods(x)
  91. self.assertEqual([x.method], output)
  92. def test_prefix(self):
  93. """
  94. If a prefix is given, L{prefixedMethods} returns only methods named
  95. with that prefix.
  96. """
  97. x = Separate()
  98. output = prefixedMethods(x, "good_")
  99. self.assertEqual([x.good_method], output)
  100. class PrefixedMethodNamesTests(TestCase):
  101. """
  102. Tests for L{prefixedMethodNames}.
  103. """
  104. def test_method(self):
  105. """
  106. L{prefixedMethodNames} returns a list including methods with the given
  107. prefix defined on the class passed to it.
  108. """
  109. self.assertEqual(["method"], prefixedMethodNames(Separate, "good_"))
  110. def test_inheritedMethod(self):
  111. """
  112. L{prefixedMethodNames} returns a list included methods with the given
  113. prefix defined on base classes of the class passed to it.
  114. """
  115. class Child(Separate):
  116. pass
  117. self.assertEqual(["method"], prefixedMethodNames(Child, "good_"))
  118. class AddMethodNamesToDictTests(TestCase):
  119. """
  120. Tests for L{addMethodNamesToDict}.
  121. """
  122. def test_baseClass(self):
  123. """
  124. If C{baseClass} is passed to L{addMethodNamesToDict}, only methods which
  125. are a subclass of C{baseClass} are added to the result dictionary.
  126. """
  127. class Alternate:
  128. pass
  129. class Child(Separate, Alternate):
  130. def good_alternate(self):
  131. pass
  132. result = {}
  133. addMethodNamesToDict(Child, result, "good_", Alternate)
  134. self.assertEqual({"alternate": 1}, result)
  135. class Summer:
  136. """
  137. A class we look up as part of the LookupsTests.
  138. """
  139. def reallySet(self):
  140. """
  141. Do something.
  142. """
  143. class LookupsTests(TestCase):
  144. """
  145. Tests for L{namedClass}, L{namedModule}, and L{namedAny}.
  146. """
  147. def test_namedClassLookup(self):
  148. """
  149. L{namedClass} should return the class object for the name it is passed.
  150. """
  151. self.assertIs(reflect.namedClass("twisted.test.test_reflect.Summer"), Summer)
  152. def test_namedModuleLookup(self):
  153. """
  154. L{namedModule} should return the module object for the name it is
  155. passed.
  156. """
  157. from twisted.python import monkey
  158. self.assertIs(reflect.namedModule("twisted.python.monkey"), monkey)
  159. def test_namedAnyPackageLookup(self):
  160. """
  161. L{namedAny} should return the package object for the name it is passed.
  162. """
  163. import twisted.python
  164. self.assertIs(reflect.namedAny("twisted.python"), twisted.python)
  165. def test_namedAnyModuleLookup(self):
  166. """
  167. L{namedAny} should return the module object for the name it is passed.
  168. """
  169. from twisted.python import monkey
  170. self.assertIs(reflect.namedAny("twisted.python.monkey"), monkey)
  171. def test_namedAnyClassLookup(self):
  172. """
  173. L{namedAny} should return the class object for the name it is passed.
  174. """
  175. self.assertIs(reflect.namedAny("twisted.test.test_reflect.Summer"), Summer)
  176. def test_namedAnyAttributeLookup(self):
  177. """
  178. L{namedAny} should return the object an attribute of a non-module,
  179. non-package object is bound to for the name it is passed.
  180. """
  181. # Note - not assertIs because unbound method lookup creates a new
  182. # object every time. This is a foolishness of Python's object
  183. # implementation, not a bug in Twisted.
  184. self.assertEqual(
  185. reflect.namedAny("twisted.test.test_reflect.Summer.reallySet"),
  186. Summer.reallySet,
  187. )
  188. def test_namedAnySecondAttributeLookup(self):
  189. """
  190. L{namedAny} should return the object an attribute of an object which
  191. itself was an attribute of a non-module, non-package object is bound to
  192. for the name it is passed.
  193. """
  194. self.assertIs(
  195. reflect.namedAny("twisted.test.test_reflect." "Summer.reallySet.__doc__"),
  196. Summer.reallySet.__doc__,
  197. )
  198. def test_importExceptions(self):
  199. """
  200. Exceptions raised by modules which L{namedAny} causes to be imported
  201. should pass through L{namedAny} to the caller.
  202. """
  203. self.assertRaises(
  204. ZeroDivisionError, reflect.namedAny, "twisted.test.reflect_helper_ZDE"
  205. )
  206. # Make sure that there is post-failed-import cleanup
  207. self.assertRaises(
  208. ZeroDivisionError, reflect.namedAny, "twisted.test.reflect_helper_ZDE"
  209. )
  210. self.assertRaises(
  211. ValueError, reflect.namedAny, "twisted.test.reflect_helper_VE"
  212. )
  213. # Modules which themselves raise ImportError when imported should
  214. # result in an ImportError
  215. self.assertRaises(
  216. ImportError, reflect.namedAny, "twisted.test.reflect_helper_IE"
  217. )
  218. def test_attributeExceptions(self):
  219. """
  220. If segments on the end of a fully-qualified Python name represents
  221. attributes which aren't actually present on the object represented by
  222. the earlier segments, L{namedAny} should raise an L{AttributeError}.
  223. """
  224. self.assertRaises(
  225. AttributeError, reflect.namedAny, "twisted.nosuchmoduleintheworld"
  226. )
  227. # ImportError behaves somewhat differently between "import
  228. # extant.nonextant" and "import extant.nonextant.nonextant", so test
  229. # the latter as well.
  230. self.assertRaises(
  231. AttributeError, reflect.namedAny, "twisted.nosuch.modulein.theworld"
  232. )
  233. self.assertRaises(
  234. AttributeError,
  235. reflect.namedAny,
  236. "twisted.test.test_reflect.Summer.nosuchattribute",
  237. )
  238. def test_invalidNames(self):
  239. """
  240. Passing a name which isn't a fully-qualified Python name to L{namedAny}
  241. should result in one of the following exceptions:
  242. - L{InvalidName}: the name is not a dot-separated list of Python
  243. objects
  244. - L{ObjectNotFound}: the object doesn't exist
  245. - L{ModuleNotFound}: the object doesn't exist and there is only one
  246. component in the name
  247. """
  248. err = self.assertRaises(
  249. reflect.ModuleNotFound, reflect.namedAny, "nosuchmoduleintheworld"
  250. )
  251. self.assertEqual(str(err), "No module named 'nosuchmoduleintheworld'")
  252. # This is a dot-separated list, but it isn't valid!
  253. err = self.assertRaises(
  254. reflect.ObjectNotFound, reflect.namedAny, "@#$@(#.!@(#!@#"
  255. )
  256. self.assertEqual(str(err), "'@#$@(#.!@(#!@#' does not name an object")
  257. err = self.assertRaises(
  258. reflect.ObjectNotFound, reflect.namedAny, "tcelfer.nohtyp.detsiwt"
  259. )
  260. self.assertEqual(str(err), "'tcelfer.nohtyp.detsiwt' does not name an object")
  261. err = self.assertRaises(reflect.InvalidName, reflect.namedAny, "")
  262. self.assertEqual(str(err), "Empty module name")
  263. for invalidName in [".twisted", "twisted.", "twisted..python"]:
  264. err = self.assertRaises(reflect.InvalidName, reflect.namedAny, invalidName)
  265. self.assertEqual(
  266. str(err),
  267. "name must be a string giving a '.'-separated list of Python "
  268. "identifiers, not %r" % (invalidName,),
  269. )
  270. def test_requireModuleImportError(self):
  271. """
  272. When module import fails with ImportError it returns the specified
  273. default value.
  274. """
  275. for name in ["nosuchmtopodule", "no.such.module"]:
  276. default = object()
  277. result = reflect.requireModule(name, default=default)
  278. self.assertIs(result, default)
  279. def test_requireModuleDefaultNone(self):
  280. """
  281. When module import fails it returns L{None} by default.
  282. """
  283. result = reflect.requireModule("no.such.module")
  284. self.assertIsNone(result)
  285. def test_requireModuleRequestedImport(self):
  286. """
  287. When module import succeed it returns the module and not the default
  288. value.
  289. """
  290. from twisted.python import monkey
  291. default = object()
  292. self.assertIs(
  293. reflect.requireModule("twisted.python.monkey", default=default),
  294. monkey,
  295. )
  296. class Breakable:
  297. breakRepr = False
  298. breakStr = False
  299. def __str__(self) -> str:
  300. if self.breakStr:
  301. raise RuntimeError("str!")
  302. else:
  303. return "<Breakable>"
  304. def __repr__(self) -> str:
  305. if self.breakRepr:
  306. raise RuntimeError("repr!")
  307. else:
  308. return "Breakable()"
  309. class BrokenType(Breakable, type):
  310. breakName = False
  311. @property
  312. def __name__(self):
  313. if self.breakName:
  314. raise RuntimeError("no name")
  315. return "BrokenType"
  316. BTBase = BrokenType("BTBase", (Breakable,), {"breakRepr": True, "breakStr": True})
  317. class NoClassAttr(Breakable):
  318. __class__ = property(lambda x: x.not_class) # type: ignore[assignment]
  319. class SafeReprTests(TestCase):
  320. """
  321. Tests for L{reflect.safe_repr} function.
  322. """
  323. def test_workingRepr(self):
  324. """
  325. L{reflect.safe_repr} produces the same output as C{repr} on a working
  326. object.
  327. """
  328. xs = ([1, 2, 3], b"a")
  329. self.assertEqual(list(map(reflect.safe_repr, xs)), list(map(repr, xs)))
  330. def test_brokenRepr(self):
  331. """
  332. L{reflect.safe_repr} returns a string with class name, address, and
  333. traceback when the repr call failed.
  334. """
  335. b = Breakable()
  336. b.breakRepr = True
  337. bRepr = reflect.safe_repr(b)
  338. self.assertIn("Breakable instance at 0x", bRepr)
  339. # Check that the file is in the repr, but without the extension as it
  340. # can be .py/.pyc
  341. self.assertIn(os.path.splitext(__file__)[0], bRepr)
  342. self.assertIn("RuntimeError: repr!", bRepr)
  343. def test_brokenStr(self):
  344. """
  345. L{reflect.safe_repr} isn't affected by a broken C{__str__} method.
  346. """
  347. b = Breakable()
  348. b.breakStr = True
  349. self.assertEqual(reflect.safe_repr(b), repr(b))
  350. def test_brokenClassRepr(self):
  351. class X(BTBase):
  352. breakRepr = True
  353. reflect.safe_repr(X)
  354. reflect.safe_repr(X())
  355. def test_brokenReprIncludesID(self):
  356. """
  357. C{id} is used to print the ID of the object in case of an error.
  358. L{safe_repr} includes a traceback after a newline, so we only check
  359. against the first line of the repr.
  360. """
  361. class X(BTBase):
  362. breakRepr = True
  363. xRepr = reflect.safe_repr(X)
  364. xReprExpected = f"<BrokenType instance at 0x{id(X):x} with repr error:"
  365. self.assertEqual(xReprExpected, xRepr.split("\n")[0])
  366. def test_brokenClassStr(self):
  367. class X(BTBase):
  368. breakStr = True
  369. reflect.safe_repr(X)
  370. reflect.safe_repr(X())
  371. def test_brokenClassAttribute(self):
  372. """
  373. If an object raises an exception when accessing its C{__class__}
  374. attribute, L{reflect.safe_repr} uses C{type} to retrieve the class
  375. object.
  376. """
  377. b = NoClassAttr()
  378. b.breakRepr = True
  379. bRepr = reflect.safe_repr(b)
  380. self.assertIn("NoClassAttr instance at 0x", bRepr)
  381. self.assertIn(os.path.splitext(__file__)[0], bRepr)
  382. self.assertIn("RuntimeError: repr!", bRepr)
  383. def test_brokenClassNameAttribute(self):
  384. """
  385. If a class raises an exception when accessing its C{__name__} attribute
  386. B{and} when calling its C{__str__} implementation, L{reflect.safe_repr}
  387. returns 'BROKEN CLASS' instead of the class name.
  388. """
  389. class X(BTBase):
  390. breakName = True
  391. xRepr = reflect.safe_repr(X())
  392. self.assertIn("<BROKEN CLASS AT 0x", xRepr)
  393. self.assertIn(os.path.splitext(__file__)[0], xRepr)
  394. self.assertIn("RuntimeError: repr!", xRepr)
  395. class SafeStrTests(TestCase):
  396. """
  397. Tests for L{reflect.safe_str} function.
  398. """
  399. def test_workingStr(self):
  400. x = [1, 2, 3]
  401. self.assertEqual(reflect.safe_str(x), str(x))
  402. def test_brokenStr(self):
  403. b = Breakable()
  404. b.breakStr = True
  405. reflect.safe_str(b)
  406. def test_workingAscii(self):
  407. """
  408. L{safe_str} for C{str} with ascii-only data should return the
  409. value unchanged.
  410. """
  411. x = "a"
  412. self.assertEqual(reflect.safe_str(x), "a")
  413. def test_workingUtf8_3(self):
  414. """
  415. L{safe_str} for C{bytes} with utf-8 encoded data should return
  416. the value decoded into C{str}.
  417. """
  418. x = b"t\xc3\xbcst"
  419. self.assertEqual(reflect.safe_str(x), x.decode("utf-8"))
  420. def test_brokenUtf8(self):
  421. """
  422. Use str() for non-utf8 bytes: "b'non-utf8'"
  423. """
  424. x = b"\xff"
  425. xStr = reflect.safe_str(x)
  426. self.assertEqual(xStr, str(x))
  427. def test_brokenRepr(self):
  428. b = Breakable()
  429. b.breakRepr = True
  430. reflect.safe_str(b)
  431. def test_brokenClassStr(self):
  432. class X(BTBase):
  433. breakStr = True
  434. reflect.safe_str(X)
  435. reflect.safe_str(X())
  436. def test_brokenClassRepr(self):
  437. class X(BTBase):
  438. breakRepr = True
  439. reflect.safe_str(X)
  440. reflect.safe_str(X())
  441. def test_brokenClassAttribute(self):
  442. """
  443. If an object raises an exception when accessing its C{__class__}
  444. attribute, L{reflect.safe_str} uses C{type} to retrieve the class
  445. object.
  446. """
  447. b = NoClassAttr()
  448. b.breakStr = True
  449. bStr = reflect.safe_str(b)
  450. self.assertIn("NoClassAttr instance at 0x", bStr)
  451. self.assertIn(os.path.splitext(__file__)[0], bStr)
  452. self.assertIn("RuntimeError: str!", bStr)
  453. def test_brokenClassNameAttribute(self):
  454. """
  455. If a class raises an exception when accessing its C{__name__} attribute
  456. B{and} when calling its C{__str__} implementation, L{reflect.safe_str}
  457. returns 'BROKEN CLASS' instead of the class name.
  458. """
  459. class X(BTBase):
  460. breakName = True
  461. xStr = reflect.safe_str(X())
  462. self.assertIn("<BROKEN CLASS AT 0x", xStr)
  463. self.assertIn(os.path.splitext(__file__)[0], xStr)
  464. self.assertIn("RuntimeError: str!", xStr)
  465. class FilenameToModuleTests(TestCase):
  466. """
  467. Test L{filenameToModuleName} detection.
  468. """
  469. def setUp(self):
  470. self.path = os.path.join(self.mktemp(), "fakepackage", "test")
  471. os.makedirs(self.path)
  472. with open(os.path.join(self.path, "__init__.py"), "w") as f:
  473. f.write("")
  474. with open(os.path.join(os.path.dirname(self.path), "__init__.py"), "w") as f:
  475. f.write("")
  476. def test_directory(self):
  477. """
  478. L{filenameToModuleName} returns the correct module (a package) given a
  479. directory.
  480. """
  481. module = reflect.filenameToModuleName(self.path)
  482. self.assertEqual(module, "fakepackage.test")
  483. module = reflect.filenameToModuleName(self.path + os.path.sep)
  484. self.assertEqual(module, "fakepackage.test")
  485. def test_file(self):
  486. """
  487. L{filenameToModuleName} returns the correct module given the path to
  488. its file.
  489. """
  490. module = reflect.filenameToModuleName(
  491. os.path.join(self.path, "test_reflect.py")
  492. )
  493. self.assertEqual(module, "fakepackage.test.test_reflect")
  494. def test_bytes(self):
  495. """
  496. L{filenameToModuleName} returns the correct module given a C{bytes}
  497. path to its file.
  498. """
  499. module = reflect.filenameToModuleName(
  500. os.path.join(self.path.encode("utf-8"), b"test_reflect.py")
  501. )
  502. # Module names are always native string:
  503. self.assertEqual(module, "fakepackage.test.test_reflect")
  504. class FullyQualifiedNameTests(TestCase):
  505. """
  506. Test for L{fullyQualifiedName}.
  507. """
  508. def _checkFullyQualifiedName(self, obj, expected):
  509. """
  510. Helper to check that fully qualified name of C{obj} results to
  511. C{expected}.
  512. """
  513. self.assertEqual(fullyQualifiedName(obj), expected)
  514. def test_package(self):
  515. """
  516. L{fullyQualifiedName} returns the full name of a package and a
  517. subpackage.
  518. """
  519. import twisted
  520. self._checkFullyQualifiedName(twisted, "twisted")
  521. import twisted.python
  522. self._checkFullyQualifiedName(twisted.python, "twisted.python")
  523. def test_module(self):
  524. """
  525. L{fullyQualifiedName} returns the name of a module inside a package.
  526. """
  527. import twisted.python.compat
  528. self._checkFullyQualifiedName(twisted.python.compat, "twisted.python.compat")
  529. def test_class(self):
  530. """
  531. L{fullyQualifiedName} returns the name of a class and its module.
  532. """
  533. self._checkFullyQualifiedName(
  534. FullyQualifiedNameTests, f"{__name__}.FullyQualifiedNameTests"
  535. )
  536. def test_function(self):
  537. """
  538. L{fullyQualifiedName} returns the name of a function inside its module.
  539. """
  540. self._checkFullyQualifiedName(
  541. fullyQualifiedName, "twisted.python.reflect.fullyQualifiedName"
  542. )
  543. def test_boundMethod(self):
  544. """
  545. L{fullyQualifiedName} returns the name of a bound method inside its
  546. class and its module.
  547. """
  548. self._checkFullyQualifiedName(
  549. self.test_boundMethod,
  550. f"{__name__}.{self.__class__.__name__}.test_boundMethod",
  551. )
  552. def test_unboundMethod(self):
  553. """
  554. L{fullyQualifiedName} returns the name of an unbound method inside its
  555. class and its module.
  556. """
  557. self._checkFullyQualifiedName(
  558. self.__class__.test_unboundMethod,
  559. f"{__name__}.{self.__class__.__name__}.test_unboundMethod",
  560. )
  561. class ObjectGrepTests(TestCase):
  562. def test_dictionary(self):
  563. """
  564. Test references search through a dictionary, as a key or as a value.
  565. """
  566. o = object()
  567. d1 = {None: o}
  568. d2 = {o: None}
  569. self.assertIn("[None]", reflect.objgrep(d1, o, reflect.isSame))
  570. self.assertIn("{None}", reflect.objgrep(d2, o, reflect.isSame))
  571. def test_list(self):
  572. """
  573. Test references search through a list.
  574. """
  575. o = object()
  576. L = [None, o]
  577. self.assertIn("[1]", reflect.objgrep(L, o, reflect.isSame))
  578. def test_tuple(self):
  579. """
  580. Test references search through a tuple.
  581. """
  582. o = object()
  583. T = (o, None)
  584. self.assertIn("[0]", reflect.objgrep(T, o, reflect.isSame))
  585. def test_instance(self):
  586. """
  587. Test references search through an object attribute.
  588. """
  589. class Dummy:
  590. pass
  591. o = object()
  592. d = Dummy()
  593. d.o = o
  594. self.assertIn(".o", reflect.objgrep(d, o, reflect.isSame))
  595. def test_weakref(self):
  596. """
  597. Test references search through a weakref object.
  598. """
  599. class Dummy:
  600. pass
  601. o = Dummy()
  602. w1 = weakref.ref(o)
  603. self.assertIn("()", reflect.objgrep(w1, o, reflect.isSame))
  604. def test_boundMethod(self):
  605. """
  606. Test references search through method special attributes.
  607. """
  608. class Dummy:
  609. def dummy(self):
  610. pass
  611. o = Dummy()
  612. m = o.dummy
  613. self.assertIn(".__self__", reflect.objgrep(m, m.__self__, reflect.isSame))
  614. self.assertIn(
  615. ".__self__.__class__",
  616. reflect.objgrep(m, m.__self__.__class__, reflect.isSame),
  617. )
  618. self.assertIn(".__func__", reflect.objgrep(m, m.__func__, reflect.isSame))
  619. def test_everything(self):
  620. """
  621. Test references search using complex set of objects.
  622. """
  623. class Dummy:
  624. def method(self):
  625. pass
  626. o = Dummy()
  627. D1 = {(): "baz", None: "Quux", o: "Foosh"}
  628. L = [None, (), D1, 3]
  629. T = (L, {}, Dummy())
  630. D2 = {0: "foo", 1: "bar", 2: T}
  631. i = Dummy()
  632. i.attr = D2
  633. m = i.method
  634. w = weakref.ref(m)
  635. self.assertIn(
  636. "().__self__.attr[2][0][2]{'Foosh'}", reflect.objgrep(w, o, reflect.isSame)
  637. )
  638. def test_depthLimit(self):
  639. """
  640. Test the depth of references search.
  641. """
  642. a = []
  643. b = [a]
  644. c = [a, b]
  645. d = [a, c]
  646. self.assertEqual(["[0]"], reflect.objgrep(d, a, reflect.isSame, maxDepth=1))
  647. self.assertEqual(
  648. ["[0]", "[1][0]"], reflect.objgrep(d, a, reflect.isSame, maxDepth=2)
  649. )
  650. self.assertEqual(
  651. ["[0]", "[1][0]", "[1][1][0]"],
  652. reflect.objgrep(d, a, reflect.isSame, maxDepth=3),
  653. )
  654. def test_deque(self):
  655. """
  656. Test references search through a deque object.
  657. """
  658. o = object()
  659. D = deque()
  660. D.append(None)
  661. D.append(o)
  662. self.assertIn("[1]", reflect.objgrep(D, o, reflect.isSame))
  663. class GetClassTests(TestCase):
  664. def test_new(self):
  665. class NewClass:
  666. pass
  667. new = NewClass()
  668. self.assertEqual(reflect.getClass(NewClass).__name__, "type")
  669. self.assertEqual(reflect.getClass(new).__name__, "NewClass")