Development of an internal social media platform with personalised dashboards for students
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.

unittest_object_model.py 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  1. # Copyright (c) 2016 Claudiu Popa <pcmanticore@gmail.com>
  2. # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
  3. # For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER
  4. import unittest
  5. import xml
  6. import six
  7. import astroid
  8. from astroid import builder
  9. from astroid import exceptions
  10. from astroid import MANAGER
  11. from astroid import test_utils
  12. from astroid import objects
  13. BUILTINS = MANAGER.astroid_cache[six.moves.builtins.__name__]
  14. class InstanceModelTest(unittest.TestCase):
  15. def test_instance_special_model(self):
  16. ast_nodes = builder.extract_node('''
  17. class A:
  18. "test"
  19. def __init__(self):
  20. self.a = 42
  21. a = A()
  22. a.__class__ #@
  23. a.__module__ #@
  24. a.__doc__ #@
  25. a.__dict__ #@
  26. ''', module_name='fake_module')
  27. cls = next(ast_nodes[0].infer())
  28. self.assertIsInstance(cls, astroid.ClassDef)
  29. self.assertEqual(cls.name, 'A')
  30. module = next(ast_nodes[1].infer())
  31. self.assertIsInstance(module, astroid.Const)
  32. self.assertEqual(module.value, 'fake_module')
  33. doc = next(ast_nodes[2].infer())
  34. self.assertIsInstance(doc, astroid.Const)
  35. self.assertEqual(doc.value, 'test')
  36. dunder_dict = next(ast_nodes[3].infer())
  37. self.assertIsInstance(dunder_dict, astroid.Dict)
  38. attr = next(dunder_dict.getitem(astroid.Const('a')).infer())
  39. self.assertIsInstance(attr, astroid.Const)
  40. self.assertEqual(attr.value, 42)
  41. @unittest.expectedFailure
  42. def test_instance_local_attributes_overrides_object_model(self):
  43. # The instance lookup needs to be changed in order for this to work.
  44. ast_node = builder.extract_node('''
  45. class A:
  46. @property
  47. def __dict__(self):
  48. return []
  49. A().__dict__
  50. ''')
  51. inferred = next(ast_node.infer())
  52. self.assertIsInstance(inferred, astroid.List)
  53. self.assertEqual(inferred.elts, [])
  54. class BoundMethodModelTest(unittest.TestCase):
  55. def test_bound_method_model(self):
  56. ast_nodes = builder.extract_node('''
  57. class A:
  58. def test(self): pass
  59. a = A()
  60. a.test.__func__ #@
  61. a.test.__self__ #@
  62. ''')
  63. func = next(ast_nodes[0].infer())
  64. self.assertIsInstance(func, astroid.FunctionDef)
  65. self.assertEqual(func.name, 'test')
  66. self_ = next(ast_nodes[1].infer())
  67. self.assertIsInstance(self_, astroid.Instance)
  68. self.assertEqual(self_.name, 'A')
  69. class UnboundMethodModelTest(unittest.TestCase):
  70. def test_unbound_method_model(self):
  71. ast_nodes = builder.extract_node('''
  72. class A:
  73. def test(self): pass
  74. t = A.test
  75. t.__class__ #@
  76. t.__func__ #@
  77. t.__self__ #@
  78. t.im_class #@
  79. t.im_func #@
  80. t.im_self #@
  81. ''')
  82. cls = next(ast_nodes[0].infer())
  83. self.assertIsInstance(cls, astroid.ClassDef)
  84. if six.PY2:
  85. unbound_name = 'instancemethod'
  86. else:
  87. unbound_name = 'function'
  88. self.assertEqual(cls.name, unbound_name)
  89. func = next(ast_nodes[1].infer())
  90. self.assertIsInstance(func, astroid.FunctionDef)
  91. self.assertEqual(func.name, 'test')
  92. self_ = next(ast_nodes[2].infer())
  93. self.assertIsInstance(self_, astroid.Const)
  94. self.assertIsNone(self_.value)
  95. self.assertEqual(cls.name, next(ast_nodes[3].infer()).name)
  96. self.assertEqual(func, next(ast_nodes[4].infer()))
  97. self.assertIsNone(next(ast_nodes[5].infer()).value)
  98. class ClassModelTest(unittest.TestCase):
  99. def test_priority_to_local_defined_values(self):
  100. ast_node = builder.extract_node('''
  101. class A:
  102. __doc__ = "first"
  103. A.__doc__ #@
  104. ''')
  105. inferred = next(ast_node.infer())
  106. self.assertIsInstance(inferred, astroid.Const)
  107. self.assertEqual(inferred.value, "first")
  108. @test_utils.require_version(maxver='3.0')
  109. def test__mro__old_style(self):
  110. ast_node = builder.extract_node('''
  111. class A:
  112. pass
  113. A.__mro__
  114. ''')
  115. with self.assertRaises(exceptions.InferenceError):
  116. next(ast_node.infer())
  117. @test_utils.require_version(maxver='3.0')
  118. def test__subclasses__old_style(self):
  119. ast_node = builder.extract_node('''
  120. class A:
  121. pass
  122. A.__subclasses__
  123. ''')
  124. with self.assertRaises(exceptions.InferenceError):
  125. next(ast_node.infer())
  126. def test_class_model_correct_mro_subclasses_proxied(self):
  127. ast_nodes = builder.extract_node('''
  128. class A(object):
  129. pass
  130. A.mro #@
  131. A.__subclasses__ #@
  132. ''')
  133. for node in ast_nodes:
  134. inferred = next(node.infer())
  135. self.assertIsInstance(inferred, astroid.BoundMethod)
  136. self.assertIsInstance(inferred._proxied, astroid.FunctionDef)
  137. self.assertIsInstance(inferred.bound, astroid.ClassDef)
  138. self.assertEqual(inferred.bound.name, 'type')
  139. @unittest.skipUnless(six.PY2, "Needs old style classes")
  140. def test_old_style_classes_no_mro(self):
  141. ast_node = builder.extract_node('''
  142. class A:
  143. pass
  144. A.mro #@
  145. ''')
  146. with self.assertRaises(exceptions.InferenceError):
  147. next(ast_node.infer())
  148. def test_class_model(self):
  149. ast_nodes = builder.extract_node('''
  150. class A(object):
  151. "test"
  152. class B(A): pass
  153. class C(A): pass
  154. A.__module__ #@
  155. A.__name__ #@
  156. A.__qualname__ #@
  157. A.__doc__ #@
  158. A.__mro__ #@
  159. A.mro() #@
  160. A.__bases__ #@
  161. A.__class__ #@
  162. A.__dict__ #@
  163. A.__subclasses__() #@
  164. ''', module_name='fake_module')
  165. module = next(ast_nodes[0].infer())
  166. self.assertIsInstance(module, astroid.Const)
  167. self.assertEqual(module.value, 'fake_module')
  168. name = next(ast_nodes[1].infer())
  169. self.assertIsInstance(name, astroid.Const)
  170. self.assertEqual(name.value, 'A')
  171. qualname = next(ast_nodes[2].infer())
  172. self.assertIsInstance(qualname, astroid.Const)
  173. self.assertEqual(qualname.value, 'fake_module.A')
  174. doc = next(ast_nodes[3].infer())
  175. self.assertIsInstance(doc, astroid.Const)
  176. self.assertEqual(doc.value, 'test')
  177. mro = next(ast_nodes[4].infer())
  178. self.assertIsInstance(mro, astroid.Tuple)
  179. self.assertEqual([cls.name for cls in mro.elts],
  180. ['A', 'object'])
  181. called_mro = next(ast_nodes[5].infer())
  182. self.assertEqual(called_mro.elts, mro.elts)
  183. bases = next(ast_nodes[6].infer())
  184. self.assertIsInstance(bases, astroid.Tuple)
  185. self.assertEqual([cls.name for cls in bases.elts],
  186. ['object'])
  187. cls = next(ast_nodes[7].infer())
  188. self.assertIsInstance(cls, astroid.ClassDef)
  189. self.assertEqual(cls.name, 'type')
  190. cls_dict = next(ast_nodes[8].infer())
  191. self.assertIsInstance(cls_dict, astroid.Dict)
  192. subclasses = next(ast_nodes[9].infer())
  193. self.assertIsInstance(subclasses, astroid.List)
  194. self.assertEqual([cls.name for cls in subclasses.elts], ['B', 'C'])
  195. class ModuleModelTest(unittest.TestCase):
  196. def test_priority_to_local_defined_values(self):
  197. ast_node = astroid.parse('''
  198. __file__ = "mine"
  199. ''')
  200. file_value = next(ast_node.igetattr('__file__'))
  201. self.assertIsInstance(file_value, astroid.Const)
  202. self.assertEqual(file_value.value, "mine")
  203. def test__path__not_a_package(self):
  204. ast_node = builder.extract_node('''
  205. import sys
  206. sys.__path__ #@
  207. ''')
  208. with self.assertRaises(exceptions.InferenceError):
  209. next(ast_node.infer())
  210. def test_module_model(self):
  211. ast_nodes = builder.extract_node('''
  212. import xml
  213. xml.__path__ #@
  214. xml.__name__ #@
  215. xml.__doc__ #@
  216. xml.__file__ #@
  217. xml.__spec__ #@
  218. xml.__loader__ #@
  219. xml.__cached__ #@
  220. xml.__package__ #@
  221. xml.__dict__ #@
  222. ''')
  223. path = next(ast_nodes[0].infer())
  224. self.assertIsInstance(path, astroid.List)
  225. self.assertIsInstance(path.elts[0], astroid.Const)
  226. self.assertEqual(path.elts[0].value, xml.__path__[0])
  227. name = next(ast_nodes[1].infer())
  228. self.assertIsInstance(name, astroid.Const)
  229. self.assertEqual(name.value, 'xml')
  230. doc = next(ast_nodes[2].infer())
  231. self.assertIsInstance(doc, astroid.Const)
  232. self.assertEqual(doc.value, xml.__doc__)
  233. file_ = next(ast_nodes[3].infer())
  234. self.assertIsInstance(file_, astroid.Const)
  235. self.assertEqual(file_.value, xml.__file__.replace(".pyc", ".py"))
  236. for ast_node in ast_nodes[4:7]:
  237. inferred = next(ast_node.infer())
  238. self.assertIs(inferred, astroid.Uninferable)
  239. package = next(ast_nodes[7].infer())
  240. self.assertIsInstance(package, astroid.Const)
  241. self.assertEqual(package.value, 'xml')
  242. dict_ = next(ast_nodes[8].infer())
  243. self.assertIsInstance(dict_, astroid.Dict)
  244. class FunctionModelTest(unittest.TestCase):
  245. def test_partial_descriptor_support(self):
  246. bound, result = builder.extract_node('''
  247. class A(object): pass
  248. def test(self): return 42
  249. f = test.__get__(A(), A)
  250. f #@
  251. f() #@
  252. ''')
  253. bound = next(bound.infer())
  254. self.assertIsInstance(bound, astroid.BoundMethod)
  255. self.assertEqual(bound._proxied._proxied.name, 'test')
  256. result = next(result.infer())
  257. self.assertIsInstance(result, astroid.Const)
  258. self.assertEqual(result.value, 42)
  259. @unittest.expectedFailure
  260. def test_descriptor_not_inferrring_self(self):
  261. # We can't infer __get__(X, Y)() when the bounded function
  262. # uses self, because of the tree's parent not being propagating good enough.
  263. result = builder.extract_node('''
  264. class A(object):
  265. x = 42
  266. def test(self): return self.x
  267. f = test.__get__(A(), A)
  268. f() #@
  269. ''')
  270. result = next(result.infer())
  271. self.assertIsInstance(result, astroid.Const)
  272. self.assertEqual(result.value, 42)
  273. def test_descriptors_binding_invalid(self):
  274. ast_nodes = builder.extract_node('''
  275. class A: pass
  276. def test(self): return 42
  277. test.__get__()() #@
  278. test.__get__(1)() #@
  279. test.__get__(2, 3, 4) #@
  280. ''')
  281. for node in ast_nodes:
  282. with self.assertRaises(exceptions.InferenceError):
  283. next(node.infer())
  284. def test_function_model(self):
  285. ast_nodes = builder.extract_node('''
  286. def func(a=1, b=2):
  287. """test"""
  288. func.__name__ #@
  289. func.__doc__ #@
  290. func.__qualname__ #@
  291. func.__module__ #@
  292. func.__defaults__ #@
  293. func.__dict__ #@
  294. func.__globals__ #@
  295. func.__code__ #@
  296. func.__closure__ #@
  297. ''', module_name='fake_module')
  298. name = next(ast_nodes[0].infer())
  299. self.assertIsInstance(name, astroid.Const)
  300. self.assertEqual(name.value, 'func')
  301. doc = next(ast_nodes[1].infer())
  302. self.assertIsInstance(doc, astroid.Const)
  303. self.assertEqual(doc.value, 'test')
  304. qualname = next(ast_nodes[2].infer())
  305. self.assertIsInstance(qualname, astroid.Const)
  306. self.assertEqual(qualname.value, 'fake_module.func')
  307. module = next(ast_nodes[3].infer())
  308. self.assertIsInstance(module, astroid.Const)
  309. self.assertEqual(module.value, 'fake_module')
  310. defaults = next(ast_nodes[4].infer())
  311. self.assertIsInstance(defaults, astroid.Tuple)
  312. self.assertEqual([default.value for default in defaults.elts], [1, 2])
  313. dict_ = next(ast_nodes[5].infer())
  314. self.assertIsInstance(dict_, astroid.Dict)
  315. globals_ = next(ast_nodes[6].infer())
  316. self.assertIsInstance(globals_, astroid.Dict)
  317. for ast_node in ast_nodes[7:9]:
  318. self.assertIs(next(ast_node.infer()), astroid.Uninferable)
  319. @test_utils.require_version(minver='3.0')
  320. def test_empty_return_annotation(self):
  321. ast_node = builder.extract_node('''
  322. def test(): pass
  323. test.__annotations__
  324. ''')
  325. annotations = next(ast_node.infer())
  326. self.assertIsInstance(annotations, astroid.Dict)
  327. self.assertEqual(len(annotations.items), 0)
  328. @test_utils.require_version(minver='3.0')
  329. def test_builtin_dunder_init_does_not_crash_when_accessing_annotations(self):
  330. ast_node = builder.extract_node('''
  331. class Class:
  332. @classmethod
  333. def class_method(cls):
  334. cls.__init__.__annotations__ #@
  335. ''')
  336. inferred = next(ast_node.infer())
  337. self.assertIsInstance(inferred, astroid.Dict)
  338. self.assertEqual(len(inferred.items), 0)
  339. @test_utils.require_version(minver='3.0')
  340. def test_annotations_kwdefaults(self):
  341. ast_node = builder.extract_node('''
  342. def test(a: 1, *args: 2, f:4='lala', **kwarg:3)->2: pass
  343. test.__annotations__ #@
  344. test.__kwdefaults__ #@
  345. ''')
  346. annotations = next(ast_node[0].infer())
  347. self.assertIsInstance(annotations, astroid.Dict)
  348. self.assertIsInstance(annotations.getitem(astroid.Const('return')), astroid.Const)
  349. self.assertEqual(annotations.getitem(astroid.Const('return')).value, 2)
  350. self.assertIsInstance(annotations.getitem(astroid.Const('a')), astroid.Const)
  351. self.assertEqual(annotations.getitem(astroid.Const('a')).value, 1)
  352. self.assertEqual(annotations.getitem(astroid.Const('args')).value, 2)
  353. self.assertEqual(annotations.getitem(astroid.Const('kwarg')).value, 3)
  354. self.assertEqual(annotations.getitem(astroid.Const('f')).value, 4)
  355. kwdefaults = next(ast_node[1].infer())
  356. self.assertIsInstance(kwdefaults, astroid.Dict)
  357. # self.assertEqual(kwdefaults.getitem('f').value, 'lala')
  358. @test_utils.require_version(maxver='3.0')
  359. def test_function_model_for_python2(self):
  360. ast_nodes = builder.extract_node('''
  361. def test(a=1):
  362. "a"
  363. test.func_name #@
  364. test.func_doc #@
  365. test.func_dict #@
  366. test.func_globals #@
  367. test.func_defaults #@
  368. test.func_code #@
  369. test.func_closure #@
  370. ''')
  371. name = next(ast_nodes[0].infer())
  372. self.assertIsInstance(name, astroid.Const)
  373. self.assertEqual(name.value, 'test')
  374. doc = next(ast_nodes[1].infer())
  375. self.assertIsInstance(doc, astroid.Const)
  376. self.assertEqual(doc.value, 'a')
  377. pydict = next(ast_nodes[2].infer())
  378. self.assertIsInstance(pydict, astroid.Dict)
  379. pyglobals = next(ast_nodes[3].infer())
  380. self.assertIsInstance(pyglobals, astroid.Dict)
  381. defaults = next(ast_nodes[4].infer())
  382. self.assertIsInstance(defaults, astroid.Tuple)
  383. for node in ast_nodes[5:]:
  384. self.assertIs(next(node.infer()), astroid.Uninferable)
  385. class GeneratorModelTest(unittest.TestCase):
  386. def test_model(self):
  387. ast_nodes = builder.extract_node('''
  388. def test():
  389. "a"
  390. yield
  391. gen = test()
  392. gen.__name__ #@
  393. gen.__doc__ #@
  394. gen.gi_code #@
  395. gen.gi_frame #@
  396. gen.send #@
  397. ''')
  398. name = next(ast_nodes[0].infer())
  399. self.assertEqual(name.value, 'test')
  400. doc = next(ast_nodes[1].infer())
  401. self.assertEqual(doc.value, 'a')
  402. gi_code = next(ast_nodes[2].infer())
  403. self.assertIsInstance(gi_code, astroid.ClassDef)
  404. self.assertEqual(gi_code.name, 'gi_code')
  405. gi_frame = next(ast_nodes[3].infer())
  406. self.assertIsInstance(gi_frame, astroid.ClassDef)
  407. self.assertEqual(gi_frame.name, 'gi_frame')
  408. send = next(ast_nodes[4].infer())
  409. self.assertIsInstance(send, astroid.BoundMethod)
  410. class ExceptionModelTest(unittest.TestCase):
  411. @unittest.skipIf(six.PY2, "needs Python 3")
  412. def test_model_py3(self):
  413. ast_nodes = builder.extract_node('''
  414. try:
  415. x[42]
  416. except ValueError as err:
  417. err.args #@
  418. err.__traceback__ #@
  419. err.message #@
  420. ''')
  421. args = next(ast_nodes[0].infer())
  422. self.assertIsInstance(args, astroid.Tuple)
  423. tb = next(ast_nodes[1].infer())
  424. self.assertIsInstance(tb, astroid.Instance)
  425. self.assertEqual(tb.name, 'traceback')
  426. with self.assertRaises(exceptions.InferenceError):
  427. next(ast_nodes[2].infer())
  428. @unittest.skipUnless(six.PY2, "needs Python 2")
  429. def test_model_py2(self):
  430. ast_nodes = builder.extract_node('''
  431. try:
  432. x[42]
  433. except ValueError as err:
  434. err.args #@
  435. err.message #@
  436. err.__traceback__ #@
  437. ''')
  438. args = next(ast_nodes[0].infer())
  439. self.assertIsInstance(args, astroid.Tuple)
  440. message = next(ast_nodes[1].infer())
  441. self.assertIsInstance(message, astroid.Const)
  442. with self.assertRaises(exceptions.InferenceError):
  443. next(ast_nodes[2].infer())
  444. class DictObjectModelTest(unittest.TestCase):
  445. def test__class__(self):
  446. ast_node = builder.extract_node('{}.__class__')
  447. inferred = next(ast_node.infer())
  448. self.assertIsInstance(inferred, astroid.ClassDef)
  449. self.assertEqual(inferred.name, 'dict')
  450. def test_attributes_inferred_as_methods(self):
  451. ast_nodes = builder.extract_node('''
  452. {}.values #@
  453. {}.items #@
  454. {}.keys #@
  455. ''')
  456. for node in ast_nodes:
  457. inferred = next(node.infer())
  458. self.assertIsInstance(inferred, astroid.BoundMethod)
  459. @unittest.skipUnless(six.PY2, "needs Python 2")
  460. def test_concrete_objects_for_dict_methods(self):
  461. ast_nodes = builder.extract_node('''
  462. {1:1, 2:3}.values() #@
  463. {1:1, 2:3}.keys() #@
  464. {1:1, 2:3}.items() #@
  465. ''')
  466. values = next(ast_nodes[0].infer())
  467. self.assertIsInstance(values, astroid.List)
  468. self.assertEqual([value.value for value in values.elts], [1, 3])
  469. keys = next(ast_nodes[1].infer())
  470. self.assertIsInstance(keys, astroid.List)
  471. self.assertEqual([key.value for key in keys.elts], [1, 2])
  472. items = next(ast_nodes[2].infer())
  473. self.assertIsInstance(items, astroid.List)
  474. for expected, elem in zip([(1, 1), (2, 3)], items.elts):
  475. self.assertIsInstance(elem, astroid.Tuple)
  476. self.assertEqual(list(expected), [elt.value for elt in elem.elts])
  477. @unittest.skipIf(six.PY2, "needs Python 3")
  478. def test_wrapper_objects_for_dict_methods_python3(self):
  479. ast_nodes = builder.extract_node('''
  480. {1:1, 2:3}.values() #@
  481. {1:1, 2:3}.keys() #@
  482. {1:1, 2:3}.items() #@
  483. ''')
  484. values = next(ast_nodes[0].infer())
  485. self.assertIsInstance(values, objects.DictValues)
  486. self.assertEqual([elt.value for elt in values.elts], [1, 3])
  487. keys = next(ast_nodes[1].infer())
  488. self.assertIsInstance(keys, objects.DictKeys)
  489. self.assertEqual([elt.value for elt in keys.elts], [1, 2])
  490. items = next(ast_nodes[2].infer())
  491. self.assertIsInstance(items, objects.DictItems)
  492. class LruCacheModelTest(unittest.TestCase):
  493. @unittest.skipIf(six.PY2, "needs Python 3")
  494. def test_lru_cache(self):
  495. ast_nodes = builder.extract_node('''
  496. import functools
  497. class Foo(object):
  498. @functools.lru_cache()
  499. def foo():
  500. pass
  501. f = Foo()
  502. f.foo.cache_clear #@
  503. f.foo.__wrapped__ #@
  504. f.foo.cache_info() #@
  505. ''')
  506. cache_clear = next(ast_nodes[0].infer())
  507. self.assertIsInstance(cache_clear, astroid.BoundMethod)
  508. wrapped = next(ast_nodes[1].infer())
  509. self.assertIsInstance(wrapped, astroid.FunctionDef)
  510. self.assertEqual(wrapped.name, 'foo')
  511. cache_info = next(ast_nodes[2].infer())
  512. self.assertIsInstance(cache_info, astroid.Instance)
  513. if __name__ == '__main__':
  514. unittest.main()