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_scoped_nodes.py 64KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789
  1. # Copyright (c) 2006-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
  2. # Copyright (c) 2011, 2013-2015 Google, Inc.
  3. # Copyright (c) 2013-2016 Claudiu Popa <pcmanticore@gmail.com>
  4. # Copyright (c) 2015-2016 Cara Vinson <ceridwenv@gmail.com>
  5. # Copyright (c) 2015 Philip Lorenz <philip@bithub.de>
  6. # Copyright (c) 2015 Rene Zhang <rz99@cornell.edu>
  7. # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
  8. # For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER
  9. """tests for specific behaviour of astroid scoped nodes (i.e. module, class and
  10. function)
  11. """
  12. import os
  13. import sys
  14. from functools import partial
  15. import unittest
  16. from astroid import builder
  17. from astroid import nodes
  18. from astroid import scoped_nodes
  19. from astroid import util
  20. from astroid.exceptions import (
  21. InferenceError, AttributeInferenceError,
  22. NoDefault, ResolveError, MroError,
  23. InconsistentMroError, DuplicateBasesError,
  24. TooManyLevelsError,
  25. NameInferenceError
  26. )
  27. from astroid.bases import (
  28. BUILTINS, Instance,
  29. BoundMethod, UnboundMethod, Generator
  30. )
  31. from astroid import __pkginfo__
  32. from astroid import test_utils
  33. from astroid.tests import resources
  34. def _test_dict_interface(self, node, test_attr):
  35. self.assertIs(node[test_attr], node[test_attr])
  36. self.assertIn(test_attr, node)
  37. node.keys()
  38. node.values()
  39. node.items()
  40. iter(node)
  41. class ModuleLoader(resources.SysPathSetup):
  42. def setUp(self):
  43. super(ModuleLoader, self).setUp()
  44. self.module = resources.build_file('data/module.py', 'data.module')
  45. self.module2 = resources.build_file('data/module2.py', 'data.module2')
  46. self.nonregr = resources.build_file('data/nonregr.py', 'data.nonregr')
  47. self.pack = resources.build_file('data/__init__.py', 'data')
  48. class ModuleNodeTest(ModuleLoader, unittest.TestCase):
  49. def test_special_attributes(self):
  50. self.assertEqual(len(self.module.getattr('__name__')), 1)
  51. self.assertIsInstance(self.module.getattr('__name__')[0], nodes.Const)
  52. self.assertEqual(self.module.getattr('__name__')[0].value, 'data.module')
  53. self.assertEqual(len(self.module.getattr('__doc__')), 1)
  54. self.assertIsInstance(self.module.getattr('__doc__')[0], nodes.Const)
  55. self.assertEqual(self.module.getattr('__doc__')[0].value, 'test module for astroid\n')
  56. self.assertEqual(len(self.module.getattr('__file__')), 1)
  57. self.assertIsInstance(self.module.getattr('__file__')[0], nodes.Const)
  58. self.assertEqual(self.module.getattr('__file__')[0].value,
  59. os.path.abspath(resources.find('data/module.py')))
  60. self.assertEqual(len(self.module.getattr('__dict__')), 1)
  61. self.assertIsInstance(self.module.getattr('__dict__')[0], nodes.Dict)
  62. self.assertRaises(AttributeInferenceError, self.module.getattr, '__path__')
  63. self.assertEqual(len(self.pack.getattr('__path__')), 1)
  64. self.assertIsInstance(self.pack.getattr('__path__')[0], nodes.List)
  65. def test_dict_interface(self):
  66. _test_dict_interface(self, self.module, 'YO')
  67. def test_getattr(self):
  68. yo = self.module.getattr('YO')[0]
  69. self.assertIsInstance(yo, nodes.ClassDef)
  70. self.assertEqual(yo.name, 'YO')
  71. red = next(self.module.igetattr('redirect'))
  72. self.assertIsInstance(red, nodes.FunctionDef)
  73. self.assertEqual(red.name, 'four_args')
  74. namenode = next(self.module.igetattr('NameNode'))
  75. self.assertIsInstance(namenode, nodes.ClassDef)
  76. self.assertEqual(namenode.name, 'Name')
  77. # resolve packageredirection
  78. mod = resources.build_file('data/appl/myConnection.py',
  79. 'data.appl.myConnection')
  80. ssl = next(mod.igetattr('SSL1'))
  81. cnx = next(ssl.igetattr('Connection'))
  82. self.assertEqual(cnx.__class__, nodes.ClassDef)
  83. self.assertEqual(cnx.name, 'Connection')
  84. self.assertEqual(cnx.root().name, 'data.SSL1.Connection1')
  85. self.assertEqual(len(self.nonregr.getattr('enumerate')), 2)
  86. self.assertRaises(InferenceError, self.nonregr.igetattr, 'YOAA')
  87. def test_wildcard_import_names(self):
  88. m = resources.build_file('data/all.py', 'all')
  89. self.assertEqual(m.wildcard_import_names(), ['Aaa', '_bla', 'name'])
  90. m = resources.build_file('data/notall.py', 'notall')
  91. res = sorted(m.wildcard_import_names())
  92. self.assertEqual(res, ['Aaa', 'func', 'name', 'other'])
  93. def test_public_names(self):
  94. m = builder.parse('''
  95. name = 'a'
  96. _bla = 2
  97. other = 'o'
  98. class Aaa: pass
  99. def func(): print('yo')
  100. __all__ = 'Aaa', '_bla', 'name'
  101. ''')
  102. values = sorted(['Aaa', 'name', 'other', 'func'])
  103. self.assertEqual(sorted(m.public_names()), values)
  104. m = builder.parse('''
  105. name = 'a'
  106. _bla = 2
  107. other = 'o'
  108. class Aaa: pass
  109. def func(): return 'yo'
  110. ''')
  111. res = sorted(m.public_names())
  112. self.assertEqual(res, values)
  113. m = builder.parse('''
  114. from missing import tzop
  115. trop = "test"
  116. __all__ = (trop, "test1", tzop, 42)
  117. ''')
  118. res = sorted(m.public_names())
  119. self.assertEqual(res, ["trop", "tzop"])
  120. m = builder.parse('''
  121. test = tzop = 42
  122. __all__ = ('test', ) + ('tzop', )
  123. ''')
  124. res = sorted(m.public_names())
  125. self.assertEqual(res, ['test', 'tzop'])
  126. def test_module_getattr(self):
  127. data = '''
  128. appli = application
  129. appli += 2
  130. del appli
  131. '''
  132. astroid = builder.parse(data, __name__)
  133. # test del statement not returned by getattr
  134. self.assertEqual(len(astroid.getattr('appli')), 2,
  135. astroid.getattr('appli'))
  136. def test_relative_to_absolute_name(self):
  137. # package
  138. mod = nodes.Module('very.multi.package', 'doc')
  139. mod.package = True
  140. modname = mod.relative_to_absolute_name('utils', 1)
  141. self.assertEqual(modname, 'very.multi.package.utils')
  142. modname = mod.relative_to_absolute_name('utils', 2)
  143. self.assertEqual(modname, 'very.multi.utils')
  144. modname = mod.relative_to_absolute_name('utils', 0)
  145. self.assertEqual(modname, 'very.multi.package.utils')
  146. modname = mod.relative_to_absolute_name('', 1)
  147. self.assertEqual(modname, 'very.multi.package')
  148. # non package
  149. mod = nodes.Module('very.multi.module', 'doc')
  150. mod.package = False
  151. modname = mod.relative_to_absolute_name('utils', 0)
  152. self.assertEqual(modname, 'very.multi.utils')
  153. modname = mod.relative_to_absolute_name('utils', 1)
  154. self.assertEqual(modname, 'very.multi.utils')
  155. modname = mod.relative_to_absolute_name('utils', 2)
  156. self.assertEqual(modname, 'very.utils')
  157. modname = mod.relative_to_absolute_name('', 1)
  158. self.assertEqual(modname, 'very.multi')
  159. def test_relative_to_absolute_name_beyond_top_level(self):
  160. mod = nodes.Module('a.b.c', '')
  161. mod.package = True
  162. for level in (5, 4):
  163. with self.assertRaises(TooManyLevelsError) as cm:
  164. mod.relative_to_absolute_name('test', level)
  165. expected = ("Relative import with too many levels "
  166. "({level}) for module {name!r}".format(
  167. level=level - 1, name=mod.name))
  168. self.assertEqual(expected, str(cm.exception))
  169. def test_import_1(self):
  170. data = '''from . import subpackage'''
  171. sys.path.insert(0, resources.find('data'))
  172. astroid = builder.parse(data, 'package', 'data/package/__init__.py')
  173. try:
  174. m = astroid.import_module('', level=1)
  175. self.assertEqual(m.name, 'package')
  176. inferred = list(astroid.igetattr('subpackage'))
  177. self.assertEqual(len(inferred), 1)
  178. self.assertEqual(inferred[0].name, 'package.subpackage')
  179. finally:
  180. del sys.path[0]
  181. def test_import_2(self):
  182. data = '''from . import subpackage as pouet'''
  183. astroid = builder.parse(data, 'package', 'data/package/__init__.py')
  184. sys.path.insert(0, resources.find('data'))
  185. try:
  186. m = astroid.import_module('', level=1)
  187. self.assertEqual(m.name, 'package')
  188. inferred = list(astroid.igetattr('pouet'))
  189. self.assertEqual(len(inferred), 1)
  190. self.assertEqual(inferred[0].name, 'package.subpackage')
  191. finally:
  192. del sys.path[0]
  193. def test_file_stream_in_memory(self):
  194. data = '''irrelevant_variable is irrelevant'''
  195. astroid = builder.parse(data, 'in_memory')
  196. with astroid.stream() as stream:
  197. self.assertEqual(stream.read().decode(), data)
  198. def test_file_stream_physical(self):
  199. path = resources.find('data/all.py')
  200. astroid = builder.AstroidBuilder().file_build(path, 'all')
  201. with open(path, 'rb') as file_io:
  202. with astroid.stream() as stream:
  203. self.assertEqual(stream.read(), file_io.read())
  204. def test_file_stream_api(self):
  205. path = resources.find('data/all.py')
  206. astroid = builder.AstroidBuilder().file_build(path, 'all')
  207. with self.assertRaises(AttributeError):
  208. # pylint: disable=pointless-statement
  209. astroid.file_stream
  210. def test_stream_api(self):
  211. path = resources.find('data/all.py')
  212. astroid = builder.AstroidBuilder().file_build(path, 'all')
  213. stream = astroid.stream()
  214. self.assertTrue(hasattr(stream, 'close'))
  215. with stream:
  216. with open(path, 'rb') as file_io:
  217. self.assertEqual(stream.read(), file_io.read())
  218. class FunctionNodeTest(ModuleLoader, unittest.TestCase):
  219. def test_special_attributes(self):
  220. func = self.module2['make_class']
  221. self.assertEqual(len(func.getattr('__name__')), 1)
  222. self.assertIsInstance(func.getattr('__name__')[0], nodes.Const)
  223. self.assertEqual(func.getattr('__name__')[0].value, 'make_class')
  224. self.assertEqual(len(func.getattr('__doc__')), 1)
  225. self.assertIsInstance(func.getattr('__doc__')[0], nodes.Const)
  226. self.assertEqual(func.getattr('__doc__')[0].value,
  227. 'check base is correctly resolved to Concrete0')
  228. self.assertEqual(len(self.module.getattr('__dict__')), 1)
  229. self.assertIsInstance(self.module.getattr('__dict__')[0], nodes.Dict)
  230. def test_dict_interface(self):
  231. _test_dict_interface(self, self.module['global_access'], 'local')
  232. def test_default_value(self):
  233. func = self.module2['make_class']
  234. self.assertIsInstance(func.args.default_value('base'), nodes.Attribute)
  235. self.assertRaises(NoDefault, func.args.default_value, 'args')
  236. self.assertRaises(NoDefault, func.args.default_value, 'kwargs')
  237. self.assertRaises(NoDefault, func.args.default_value, 'any')
  238. #self.assertIsInstance(func.mularg_class('args'), nodes.Tuple)
  239. #self.assertIsInstance(func.mularg_class('kwargs'), nodes.Dict)
  240. #self.assertIsNone(func.mularg_class('base'))
  241. def test_navigation(self):
  242. function = self.module['global_access']
  243. self.assertEqual(function.statement(), function)
  244. l_sibling = function.previous_sibling()
  245. # check taking parent if child is not a stmt
  246. self.assertIsInstance(l_sibling, nodes.Assign)
  247. child = function.args.args[0]
  248. self.assertIs(l_sibling, child.previous_sibling())
  249. r_sibling = function.next_sibling()
  250. self.assertIsInstance(r_sibling, nodes.ClassDef)
  251. self.assertEqual(r_sibling.name, 'YO')
  252. self.assertIs(r_sibling, child.next_sibling())
  253. last = r_sibling.next_sibling().next_sibling().next_sibling()
  254. self.assertIsInstance(last, nodes.Assign)
  255. self.assertIsNone(last.next_sibling())
  256. first = l_sibling.root().body[0]
  257. self.assertIsNone(first.previous_sibling())
  258. def test_nested_args(self):
  259. if sys.version_info >= (3, 0):
  260. self.skipTest("nested args has been removed in py3.x")
  261. code = '''
  262. def nested_args(a, (b, c, d)):
  263. "nested arguments test"
  264. '''
  265. tree = builder.parse(code)
  266. func = tree['nested_args']
  267. self.assertEqual(sorted(func.locals), ['a', 'b', 'c', 'd'])
  268. self.assertEqual(func.args.format_args(), 'a, (b, c, d)')
  269. def test_four_args(self):
  270. func = self.module['four_args']
  271. local = sorted(func.keys())
  272. self.assertEqual(local, ['a', 'b', 'c', 'd'])
  273. self.assertEqual(func.type, 'function')
  274. def test_format_args(self):
  275. func = self.module2['make_class']
  276. self.assertEqual(func.args.format_args(),
  277. 'any, base=data.module.YO, *args, **kwargs')
  278. func = self.module['four_args']
  279. self.assertEqual(func.args.format_args(), 'a, b, c, d')
  280. @test_utils.require_version('3.0')
  281. def test_format_args_keyword_only_args(self):
  282. node = builder.parse('''
  283. def test(a: int, *, b: dict):
  284. pass
  285. ''').body[-1].args
  286. formatted = node.format_args()
  287. self.assertEqual(formatted, 'a:int, *, b:dict')
  288. def test_is_generator(self):
  289. self.assertTrue(self.module2['generator'].is_generator())
  290. self.assertFalse(self.module2['not_a_generator'].is_generator())
  291. self.assertFalse(self.module2['make_class'].is_generator())
  292. def test_is_abstract(self):
  293. method = self.module2['AbstractClass']['to_override']
  294. self.assertTrue(method.is_abstract(pass_is_abstract=False))
  295. self.assertEqual(method.qname(), 'data.module2.AbstractClass.to_override')
  296. self.assertEqual(method.pytype(), '%s.instancemethod' % BUILTINS)
  297. method = self.module2['AbstractClass']['return_something']
  298. self.assertFalse(method.is_abstract(pass_is_abstract=False))
  299. # non regression : test raise "string" doesn't cause an exception in is_abstract
  300. func = self.module2['raise_string']
  301. self.assertFalse(func.is_abstract(pass_is_abstract=False))
  302. def test_is_abstract_decorated(self):
  303. methods = builder.extract_node("""
  304. import abc
  305. class Klass(object):
  306. @abc.abstractproperty
  307. def prop(self): #@
  308. pass
  309. @abc.abstractmethod
  310. def method1(self): #@
  311. pass
  312. some_other_decorator = lambda x: x
  313. @some_other_decorator
  314. def method2(self): #@
  315. pass
  316. """)
  317. self.assertTrue(methods[0].is_abstract(pass_is_abstract=False))
  318. self.assertTrue(methods[1].is_abstract(pass_is_abstract=False))
  319. self.assertFalse(methods[2].is_abstract(pass_is_abstract=False))
  320. ## def test_raises(self):
  321. ## method = self.module2['AbstractClass']['to_override']
  322. ## self.assertEqual([str(term) for term in method.raises()],
  323. ## ["Call(Name('NotImplementedError'), [], None, None)"] )
  324. ## def test_returns(self):
  325. ## method = self.module2['AbstractClass']['return_something']
  326. ## # use string comp since Node doesn't handle __cmp__
  327. ## self.assertEqual([str(term) for term in method.returns()],
  328. ## ["Const('toto')", "Const(None)"])
  329. def test_lambda_pytype(self):
  330. data = '''
  331. def f():
  332. g = lambda: None
  333. '''
  334. astroid = builder.parse(data)
  335. g = list(astroid['f'].ilookup('g'))[0]
  336. self.assertEqual(g.pytype(), '%s.function' % BUILTINS)
  337. def test_lambda_qname(self):
  338. astroid = builder.parse('lmbd = lambda: None', __name__)
  339. self.assertEqual('%s.<lambda>' % __name__, astroid['lmbd'].parent.value.qname())
  340. def test_is_method(self):
  341. data = '''
  342. class A:
  343. def meth1(self):
  344. return 1
  345. @classmethod
  346. def meth2(cls):
  347. return 2
  348. @staticmethod
  349. def meth3():
  350. return 3
  351. def function():
  352. return 0
  353. @staticmethod
  354. def sfunction():
  355. return -1
  356. '''
  357. astroid = builder.parse(data)
  358. self.assertTrue(astroid['A']['meth1'].is_method())
  359. self.assertTrue(astroid['A']['meth2'].is_method())
  360. self.assertTrue(astroid['A']['meth3'].is_method())
  361. self.assertFalse(astroid['function'].is_method())
  362. self.assertFalse(astroid['sfunction'].is_method())
  363. def test_argnames(self):
  364. if sys.version_info < (3, 0):
  365. code = 'def f(a, (b, c), *args, **kwargs): pass'
  366. else:
  367. code = 'def f(a, b, c, *args, **kwargs): pass'
  368. astroid = builder.parse(code, __name__)
  369. self.assertEqual(astroid['f'].argnames(), ['a', 'b', 'c', 'args', 'kwargs'])
  370. def test_return_nothing(self):
  371. """test inferred value on a function with empty return"""
  372. data = '''
  373. def func():
  374. return
  375. a = func()
  376. '''
  377. astroid = builder.parse(data)
  378. call = astroid.body[1].value
  379. func_vals = call.inferred()
  380. self.assertEqual(len(func_vals), 1)
  381. self.assertIsInstance(func_vals[0], nodes.Const)
  382. self.assertIsNone(func_vals[0].value)
  383. def test_func_instance_attr(self):
  384. """test instance attributes for functions"""
  385. data = """
  386. def test():
  387. print(test.bar)
  388. test.bar = 1
  389. test()
  390. """
  391. astroid = builder.parse(data, 'mod')
  392. func = astroid.body[2].value.func.inferred()[0]
  393. self.assertIsInstance(func, nodes.FunctionDef)
  394. self.assertEqual(func.name, 'test')
  395. one = func.getattr('bar')[0].inferred()[0]
  396. self.assertIsInstance(one, nodes.Const)
  397. self.assertEqual(one.value, 1)
  398. def test_type_builtin_descriptor_subclasses(self):
  399. astroid = builder.parse("""
  400. class classonlymethod(classmethod):
  401. pass
  402. class staticonlymethod(staticmethod):
  403. pass
  404. class Node:
  405. @classonlymethod
  406. def clsmethod_subclass(cls):
  407. pass
  408. @classmethod
  409. def clsmethod(cls):
  410. pass
  411. @staticonlymethod
  412. def staticmethod_subclass(cls):
  413. pass
  414. @staticmethod
  415. def stcmethod(cls):
  416. pass
  417. """)
  418. node = astroid.locals['Node'][0]
  419. self.assertEqual(node.locals['clsmethod_subclass'][0].type,
  420. 'classmethod')
  421. self.assertEqual(node.locals['clsmethod'][0].type,
  422. 'classmethod')
  423. self.assertEqual(node.locals['staticmethod_subclass'][0].type,
  424. 'staticmethod')
  425. self.assertEqual(node.locals['stcmethod'][0].type,
  426. 'staticmethod')
  427. def test_decorator_builtin_descriptors(self):
  428. astroid = builder.parse("""
  429. def static_decorator(platform=None, order=50):
  430. def wrapper(f):
  431. f.cgm_module = True
  432. f.cgm_module_order = order
  433. f.cgm_module_platform = platform
  434. return staticmethod(f)
  435. return wrapper
  436. def long_classmethod_decorator(platform=None, order=50):
  437. def wrapper(f):
  438. def wrapper2(f):
  439. def wrapper3(f):
  440. f.cgm_module = True
  441. f.cgm_module_order = order
  442. f.cgm_module_platform = platform
  443. return classmethod(f)
  444. return wrapper3(f)
  445. return wrapper2(f)
  446. return wrapper
  447. def classmethod_decorator(platform=None):
  448. def wrapper(f):
  449. f.platform = platform
  450. return classmethod(f)
  451. return wrapper
  452. def classmethod_wrapper(fn):
  453. def wrapper(cls, *args, **kwargs):
  454. result = fn(cls, *args, **kwargs)
  455. return result
  456. return classmethod(wrapper)
  457. def staticmethod_wrapper(fn):
  458. def wrapper(*args, **kwargs):
  459. return fn(*args, **kwargs)
  460. return staticmethod(wrapper)
  461. class SomeClass(object):
  462. @static_decorator()
  463. def static(node, cfg):
  464. pass
  465. @classmethod_decorator()
  466. def classmethod(cls):
  467. pass
  468. @static_decorator
  469. def not_so_static(node):
  470. pass
  471. @classmethod_decorator
  472. def not_so_classmethod(node):
  473. pass
  474. @classmethod_wrapper
  475. def classmethod_wrapped(cls):
  476. pass
  477. @staticmethod_wrapper
  478. def staticmethod_wrapped():
  479. pass
  480. @long_classmethod_decorator()
  481. def long_classmethod(cls):
  482. pass
  483. """)
  484. node = astroid.locals['SomeClass'][0]
  485. self.assertEqual(node.locals['static'][0].type,
  486. 'staticmethod')
  487. self.assertEqual(node.locals['classmethod'][0].type,
  488. 'classmethod')
  489. self.assertEqual(node.locals['not_so_static'][0].type,
  490. 'method')
  491. self.assertEqual(node.locals['not_so_classmethod'][0].type,
  492. 'method')
  493. self.assertEqual(node.locals['classmethod_wrapped'][0].type,
  494. 'classmethod')
  495. self.assertEqual(node.locals['staticmethod_wrapped'][0].type,
  496. 'staticmethod')
  497. self.assertEqual(node.locals['long_classmethod'][0].type,
  498. 'classmethod')
  499. def test_igetattr(self):
  500. func = builder.extract_node('''
  501. def test():
  502. pass
  503. ''')
  504. func.instance_attrs['value'] = [nodes.Const(42)]
  505. value = func.getattr('value')
  506. self.assertEqual(len(value), 1)
  507. self.assertIsInstance(value[0], nodes.Const)
  508. self.assertEqual(value[0].value, 42)
  509. inferred = next(func.igetattr('value'))
  510. self.assertIsInstance(inferred, nodes.Const)
  511. self.assertEqual(inferred.value, 42)
  512. @test_utils.require_version(minver='3.0')
  513. def test_return_annotation_is_not_the_last(self):
  514. func = builder.extract_node('''
  515. def test() -> bytes:
  516. pass
  517. pass
  518. return
  519. ''')
  520. last_child = func.last_child()
  521. self.assertIsInstance(last_child, nodes.Return)
  522. self.assertEqual(func.tolineno, 5)
  523. @test_utils.require_version(minver='3.6')
  524. def test_method_init_subclass(self):
  525. klass = builder.extract_node('''
  526. class MyClass:
  527. def __init_subclass__(cls):
  528. pass
  529. ''')
  530. method = klass['__init_subclass__']
  531. self.assertEqual([n.name for n in method.args.args], ['cls'])
  532. self.assertEqual(method.type, 'classmethod')
  533. @test_utils.require_version(minver='3.0')
  534. def test_dunder_class_local_to_method(self):
  535. node = builder.extract_node('''
  536. class MyClass:
  537. def test(self):
  538. __class__ #@
  539. ''')
  540. inferred = next(node.infer())
  541. self.assertIsInstance(inferred, nodes.ClassDef)
  542. self.assertEqual(inferred.name, 'MyClass')
  543. @test_utils.require_version(minver='3.0')
  544. def test_dunder_class_local_to_function(self):
  545. node = builder.extract_node('''
  546. def test(self):
  547. __class__ #@
  548. ''')
  549. with self.assertRaises(NameInferenceError):
  550. next(node.infer())
  551. @test_utils.require_version(minver='3.0')
  552. def test_dunder_class_local_to_classmethod(self):
  553. node = builder.extract_node('''
  554. class MyClass:
  555. @classmethod
  556. def test(cls):
  557. __class__ #@
  558. ''')
  559. inferred = next(node.infer())
  560. self.assertIsInstance(inferred, nodes.ClassDef)
  561. self.assertEqual(inferred.name, 'MyClass')
  562. class ClassNodeTest(ModuleLoader, unittest.TestCase):
  563. def test_dict_interface(self):
  564. _test_dict_interface(self, self.module['YOUPI'], 'method')
  565. def test_cls_special_attributes_1(self):
  566. cls = self.module['YO']
  567. self.assertEqual(len(cls.getattr('__bases__')), 1)
  568. self.assertEqual(len(cls.getattr('__name__')), 1)
  569. self.assertIsInstance(cls.getattr('__name__')[0], nodes.Const)
  570. self.assertEqual(cls.getattr('__name__')[0].value, 'YO')
  571. self.assertEqual(len(cls.getattr('__doc__')), 1)
  572. self.assertIsInstance(cls.getattr('__doc__')[0], nodes.Const)
  573. self.assertEqual(cls.getattr('__doc__')[0].value, 'hehe')
  574. self.assertEqual(len(cls.getattr('__module__')), 1)
  575. self.assertIsInstance(cls.getattr('__module__')[0], nodes.Const)
  576. self.assertEqual(cls.getattr('__module__')[0].value, 'data.module')
  577. self.assertEqual(len(cls.getattr('__dict__')), 1)
  578. if not cls.newstyle:
  579. self.assertRaises(AttributeInferenceError, cls.getattr, '__mro__')
  580. for cls in (nodes.List._proxied, nodes.Const(1)._proxied):
  581. self.assertEqual(len(cls.getattr('__bases__')), 1)
  582. self.assertEqual(len(cls.getattr('__name__')), 1)
  583. self.assertEqual(len(cls.getattr('__doc__')), 1, (cls, cls.getattr('__doc__')))
  584. self.assertEqual(cls.getattr('__doc__')[0].value, cls.doc)
  585. self.assertEqual(len(cls.getattr('__module__')), 1)
  586. self.assertEqual(len(cls.getattr('__dict__')), 1)
  587. self.assertEqual(len(cls.getattr('__mro__')), 1)
  588. def test__mro__attribute(self):
  589. node = builder.extract_node('''
  590. class A(object): pass
  591. class B(object): pass
  592. class C(A, B): pass
  593. ''')
  594. mro = node.getattr('__mro__')[0]
  595. self.assertIsInstance(mro, nodes.Tuple)
  596. self.assertEqual(mro.elts, node.mro())
  597. def test__bases__attribute(self):
  598. node = builder.extract_node('''
  599. class A(object): pass
  600. class B(object): pass
  601. class C(A, B): pass
  602. class D(C): pass
  603. ''')
  604. bases = node.getattr('__bases__')[0]
  605. self.assertIsInstance(bases, nodes.Tuple)
  606. self.assertEqual(len(bases.elts), 1)
  607. self.assertIsInstance(bases.elts[0], nodes.ClassDef)
  608. self.assertEqual(bases.elts[0].name, 'C')
  609. def test_cls_special_attributes_2(self):
  610. astroid = builder.parse('''
  611. class A(object): pass
  612. class B(object): pass
  613. A.__bases__ += (B,)
  614. ''', __name__)
  615. self.assertEqual(len(astroid['A'].getattr('__bases__')), 2)
  616. self.assertIsInstance(astroid['A'].getattr('__bases__')[1], nodes.Tuple)
  617. self.assertIsInstance(astroid['A'].getattr('__bases__')[0], nodes.AssignAttr)
  618. def test_instance_special_attributes(self):
  619. for inst in (Instance(self.module['YO']), nodes.List(), nodes.Const(1)):
  620. self.assertRaises(AttributeInferenceError, inst.getattr, '__mro__')
  621. self.assertRaises(AttributeInferenceError, inst.getattr, '__bases__')
  622. self.assertRaises(AttributeInferenceError, inst.getattr, '__name__')
  623. self.assertEqual(len(inst.getattr('__dict__')), 1)
  624. self.assertEqual(len(inst.getattr('__doc__')), 1)
  625. def test_navigation(self):
  626. klass = self.module['YO']
  627. self.assertEqual(klass.statement(), klass)
  628. l_sibling = klass.previous_sibling()
  629. self.assertTrue(isinstance(l_sibling, nodes.FunctionDef), l_sibling)
  630. self.assertEqual(l_sibling.name, 'global_access')
  631. r_sibling = klass.next_sibling()
  632. self.assertIsInstance(r_sibling, nodes.ClassDef)
  633. self.assertEqual(r_sibling.name, 'YOUPI')
  634. def test_local_attr_ancestors(self):
  635. module = builder.parse('''
  636. class A():
  637. def __init__(self): pass
  638. class B(A): pass
  639. class C(B): pass
  640. class D(object): pass
  641. class F(): pass
  642. class E(F, D): pass
  643. ''')
  644. # Test old-style (Python 2) / new-style (Python 3+) ancestors lookups
  645. klass2 = module['C']
  646. it = klass2.local_attr_ancestors('__init__')
  647. anc_klass = next(it)
  648. self.assertIsInstance(anc_klass, nodes.ClassDef)
  649. self.assertEqual(anc_klass.name, 'A')
  650. if sys.version_info[0] == 2:
  651. self.assertRaises(StopIteration, partial(next, it))
  652. else:
  653. anc_klass = next(it)
  654. self.assertIsInstance(anc_klass, nodes.ClassDef)
  655. self.assertEqual(anc_klass.name, 'object')
  656. self.assertRaises(StopIteration, partial(next, it))
  657. it = klass2.local_attr_ancestors('method')
  658. self.assertRaises(StopIteration, partial(next, it))
  659. # Test mixed-style ancestor lookups
  660. klass2 = module['E']
  661. it = klass2.local_attr_ancestors('__init__')
  662. anc_klass = next(it)
  663. self.assertIsInstance(anc_klass, nodes.ClassDef)
  664. self.assertEqual(anc_klass.name, 'object')
  665. self.assertRaises(StopIteration, partial(next, it))
  666. def test_local_attr_mro(self):
  667. module = builder.parse('''
  668. class A(object):
  669. def __init__(self): pass
  670. class B(A):
  671. def __init__(self, arg, arg2): pass
  672. class C(A): pass
  673. class D(C, B): pass
  674. ''')
  675. dclass = module['D']
  676. init = dclass.local_attr('__init__')[0]
  677. self.assertIsInstance(init, nodes.FunctionDef)
  678. self.assertEqual(init.parent.name, 'B')
  679. cclass = module['C']
  680. init = cclass.local_attr('__init__')[0]
  681. self.assertIsInstance(init, nodes.FunctionDef)
  682. self.assertEqual(init.parent.name, 'A')
  683. ancestors = list(dclass.local_attr_ancestors('__init__'))
  684. self.assertEqual([node.name for node in ancestors], ['B', 'A', 'object'])
  685. def test_instance_attr_ancestors(self):
  686. klass2 = self.module['YOUPI']
  687. it = klass2.instance_attr_ancestors('yo')
  688. anc_klass = next(it)
  689. self.assertIsInstance(anc_klass, nodes.ClassDef)
  690. self.assertEqual(anc_klass.name, 'YO')
  691. self.assertRaises(StopIteration, partial(next, it))
  692. klass2 = self.module['YOUPI']
  693. it = klass2.instance_attr_ancestors('member')
  694. self.assertRaises(StopIteration, partial(next, it))
  695. def test_methods(self):
  696. expected_methods = {'__init__', 'class_method', 'method', 'static_method'}
  697. klass2 = self.module['YOUPI']
  698. methods = {m.name for m in klass2.methods()}
  699. self.assertTrue(
  700. methods.issuperset(expected_methods))
  701. methods = {m.name for m in klass2.mymethods()}
  702. self.assertSetEqual(expected_methods, methods)
  703. klass2 = self.module2['Specialization']
  704. methods = {m.name for m in klass2.mymethods()}
  705. self.assertSetEqual(set([]), methods)
  706. method_locals = klass2.local_attr('method')
  707. self.assertEqual(len(method_locals), 1)
  708. self.assertEqual(method_locals[0].name, 'method')
  709. self.assertRaises(AttributeInferenceError, klass2.local_attr, 'nonexistent')
  710. methods = {m.name for m in klass2.methods()}
  711. self.assertTrue(methods.issuperset(expected_methods))
  712. #def test_rhs(self):
  713. # my_dict = self.module['MY_DICT']
  714. # self.assertIsInstance(my_dict.rhs(), nodes.Dict)
  715. # a = self.module['YO']['a']
  716. # value = a.rhs()
  717. # self.assertIsInstance(value, nodes.Const)
  718. # self.assertEqual(value.value, 1)
  719. @unittest.skipIf(sys.version_info[0] >= 3, "Python 2 class semantics required.")
  720. def test_ancestors(self):
  721. klass = self.module['YOUPI']
  722. self.assertEqual(['YO'], [a.name for a in klass.ancestors()])
  723. klass = self.module2['Specialization']
  724. self.assertEqual(['YOUPI', 'YO'], [a.name for a in klass.ancestors()])
  725. @unittest.skipIf(sys.version_info[0] < 3, "Python 3 class semantics required.")
  726. def test_ancestors_py3(self):
  727. klass = self.module['YOUPI']
  728. self.assertEqual(['YO', 'object'], [a.name for a in klass.ancestors()])
  729. klass = self.module2['Specialization']
  730. self.assertEqual(['YOUPI', 'YO', 'object'], [a.name for a in klass.ancestors()])
  731. def test_type(self):
  732. klass = self.module['YOUPI']
  733. self.assertEqual(klass.type, 'class')
  734. klass = self.module2['Metaclass']
  735. self.assertEqual(klass.type, 'metaclass')
  736. klass = self.module2['MyException']
  737. self.assertEqual(klass.type, 'exception')
  738. klass = self.module2['MyError']
  739. self.assertEqual(klass.type, 'exception')
  740. # the following class used to be detected as a metaclass
  741. # after the fix which used instance._proxied in .ancestors(),
  742. # when in fact it is a normal class
  743. klass = self.module2['NotMetaclass']
  744. self.assertEqual(klass.type, 'class')
  745. def test_inner_classes(self):
  746. eee = self.nonregr['Ccc']['Eee']
  747. self.assertEqual([n.name for n in eee.ancestors()], ['Ddd', 'Aaa', 'object'])
  748. def test_classmethod_attributes(self):
  749. data = '''
  750. class WebAppObject(object):
  751. def registered(cls, application):
  752. cls.appli = application
  753. cls.schema = application.schema
  754. cls.config = application.config
  755. return cls
  756. registered = classmethod(registered)
  757. '''
  758. astroid = builder.parse(data, __name__)
  759. cls = astroid['WebAppObject']
  760. self.assertEqual(sorted(cls.locals.keys()),
  761. ['appli', 'config', 'registered', 'schema'])
  762. def test_class_getattr(self):
  763. data = '''
  764. class WebAppObject(object):
  765. appli = application
  766. appli += 2
  767. del self.appli
  768. '''
  769. astroid = builder.parse(data, __name__)
  770. cls = astroid['WebAppObject']
  771. # test del statement not returned by getattr
  772. self.assertEqual(len(cls.getattr('appli')), 2)
  773. def test_instance_getattr(self):
  774. data = '''
  775. class WebAppObject(object):
  776. def __init__(self, application):
  777. self.appli = application
  778. self.appli += 2
  779. del self.appli
  780. '''
  781. astroid = builder.parse(data)
  782. inst = Instance(astroid['WebAppObject'])
  783. # test del statement not returned by getattr
  784. self.assertEqual(len(inst.getattr('appli')), 2)
  785. def test_instance_getattr_with_class_attr(self):
  786. data = '''
  787. class Parent:
  788. aa = 1
  789. cc = 1
  790. class Klass(Parent):
  791. aa = 0
  792. bb = 0
  793. def incr(self, val):
  794. self.cc = self.aa
  795. if val > self.aa:
  796. val = self.aa
  797. if val < self.bb:
  798. val = self.bb
  799. self.aa += val
  800. '''
  801. astroid = builder.parse(data)
  802. inst = Instance(astroid['Klass'])
  803. self.assertEqual(len(inst.getattr('aa')), 3, inst.getattr('aa'))
  804. self.assertEqual(len(inst.getattr('bb')), 1, inst.getattr('bb'))
  805. self.assertEqual(len(inst.getattr('cc')), 2, inst.getattr('cc'))
  806. def test_getattr_method_transform(self):
  807. data = '''
  808. class Clazz(object):
  809. def m1(self, value):
  810. self.value = value
  811. m2 = m1
  812. def func(arg1, arg2):
  813. "function that will be used as a method"
  814. return arg1.value + arg2
  815. Clazz.m3 = func
  816. inst = Clazz()
  817. inst.m4 = func
  818. '''
  819. astroid = builder.parse(data)
  820. cls = astroid['Clazz']
  821. # test del statement not returned by getattr
  822. for method in ('m1', 'm2', 'm3'):
  823. inferred = list(cls.igetattr(method))
  824. self.assertEqual(len(inferred), 1)
  825. self.assertIsInstance(inferred[0], UnboundMethod)
  826. inferred = list(Instance(cls).igetattr(method))
  827. self.assertEqual(len(inferred), 1)
  828. self.assertIsInstance(inferred[0], BoundMethod)
  829. inferred = list(Instance(cls).igetattr('m4'))
  830. self.assertEqual(len(inferred), 1)
  831. self.assertIsInstance(inferred[0], nodes.FunctionDef)
  832. def test_getattr_from_grandpa(self):
  833. data = '''
  834. class Future:
  835. attr = 1
  836. class Present(Future):
  837. pass
  838. class Past(Present):
  839. pass
  840. '''
  841. astroid = builder.parse(data)
  842. past = astroid['Past']
  843. attr = past.getattr('attr')
  844. self.assertEqual(len(attr), 1)
  845. attr1 = attr[0]
  846. self.assertIsInstance(attr1, nodes.AssignName)
  847. self.assertEqual(attr1.name, 'attr')
  848. def test_function_with_decorator_lineno(self):
  849. data = '''
  850. @f(a=2,
  851. b=3)
  852. def g1(x):
  853. print(x)
  854. @f(a=2,
  855. b=3)
  856. def g2():
  857. pass
  858. '''
  859. astroid = builder.parse(data)
  860. self.assertEqual(astroid['g1'].fromlineno, 4)
  861. self.assertEqual(astroid['g1'].tolineno, 5)
  862. self.assertEqual(astroid['g2'].fromlineno, 9)
  863. self.assertEqual(astroid['g2'].tolineno, 10)
  864. @test_utils.require_version(maxver='3.0')
  865. def test_simple_metaclass(self):
  866. astroid = builder.parse("""
  867. class Test(object):
  868. __metaclass__ = type
  869. """)
  870. klass = astroid['Test']
  871. metaclass = klass.metaclass()
  872. self.assertIsInstance(metaclass, scoped_nodes.ClassDef)
  873. self.assertEqual(metaclass.name, 'type')
  874. def test_metaclass_error(self):
  875. astroid = builder.parse("""
  876. class Test(object):
  877. __metaclass__ = typ
  878. """)
  879. klass = astroid['Test']
  880. self.assertFalse(klass.metaclass())
  881. @test_utils.require_version(maxver='3.0')
  882. def test_metaclass_imported(self):
  883. astroid = builder.parse("""
  884. from abc import ABCMeta
  885. class Test(object):
  886. __metaclass__ = ABCMeta
  887. """)
  888. klass = astroid['Test']
  889. metaclass = klass.metaclass()
  890. self.assertIsInstance(metaclass, scoped_nodes.ClassDef)
  891. self.assertEqual(metaclass.name, 'ABCMeta')
  892. def test_metaclass_yes_leak(self):
  893. astroid = builder.parse("""
  894. # notice `ab` instead of `abc`
  895. from ab import ABCMeta
  896. class Meta(object):
  897. __metaclass__ = ABCMeta
  898. """)
  899. klass = astroid['Meta']
  900. self.assertIsNone(klass.metaclass())
  901. @test_utils.require_version(maxver='3.0')
  902. def test_newstyle_and_metaclass_good(self):
  903. astroid = builder.parse("""
  904. from abc import ABCMeta
  905. class Test:
  906. __metaclass__ = ABCMeta
  907. """)
  908. klass = astroid['Test']
  909. self.assertTrue(klass.newstyle)
  910. self.assertEqual(klass.metaclass().name, 'ABCMeta')
  911. astroid = builder.parse("""
  912. from abc import ABCMeta
  913. __metaclass__ = ABCMeta
  914. class Test:
  915. pass
  916. """)
  917. klass = astroid['Test']
  918. self.assertTrue(klass.newstyle)
  919. self.assertEqual(klass.metaclass().name, 'ABCMeta')
  920. @test_utils.require_version(maxver='3.0')
  921. def test_nested_metaclass(self):
  922. astroid = builder.parse("""
  923. from abc import ABCMeta
  924. class A(object):
  925. __metaclass__ = ABCMeta
  926. class B: pass
  927. __metaclass__ = ABCMeta
  928. class C:
  929. __metaclass__ = type
  930. class D: pass
  931. """)
  932. a = astroid['A']
  933. b = a.locals['B'][0]
  934. c = astroid['C']
  935. d = c.locals['D'][0]
  936. self.assertEqual(a.metaclass().name, 'ABCMeta')
  937. self.assertFalse(b.newstyle)
  938. self.assertIsNone(b.metaclass())
  939. self.assertEqual(c.metaclass().name, 'type')
  940. self.assertEqual(d.metaclass().name, 'ABCMeta')
  941. @test_utils.require_version(maxver='3.0')
  942. def test_parent_metaclass(self):
  943. astroid = builder.parse("""
  944. from abc import ABCMeta
  945. class Test:
  946. __metaclass__ = ABCMeta
  947. class SubTest(Test): pass
  948. """)
  949. klass = astroid['SubTest']
  950. self.assertTrue(klass.newstyle)
  951. metaclass = klass.metaclass()
  952. self.assertIsInstance(metaclass, scoped_nodes.ClassDef)
  953. self.assertEqual(metaclass.name, 'ABCMeta')
  954. @test_utils.require_version(maxver='3.0')
  955. def test_metaclass_ancestors(self):
  956. astroid = builder.parse("""
  957. from abc import ABCMeta
  958. class FirstMeta(object):
  959. __metaclass__ = ABCMeta
  960. class SecondMeta(object):
  961. __metaclass__ = type
  962. class Simple(object):
  963. pass
  964. class FirstImpl(FirstMeta): pass
  965. class SecondImpl(FirstImpl): pass
  966. class ThirdImpl(Simple, SecondMeta):
  967. pass
  968. """)
  969. classes = {
  970. 'ABCMeta': ('FirstImpl', 'SecondImpl'),
  971. 'type': ('ThirdImpl', )
  972. }
  973. for metaclass, names in classes.items():
  974. for name in names:
  975. impl = astroid[name]
  976. meta = impl.metaclass()
  977. self.assertIsInstance(meta, nodes.ClassDef)
  978. self.assertEqual(meta.name, metaclass)
  979. def test_metaclass_type(self):
  980. klass = builder.extract_node("""
  981. def with_metaclass(meta, base=object):
  982. return meta("NewBase", (base, ), {})
  983. class ClassWithMeta(with_metaclass(type)): #@
  984. pass
  985. """)
  986. self.assertEqual(
  987. ['NewBase', 'object'],
  988. [base.name for base in klass.ancestors()])
  989. def test_no_infinite_metaclass_loop(self):
  990. klass = builder.extract_node("""
  991. class SSS(object):
  992. class JJJ(object):
  993. pass
  994. @classmethod
  995. def Init(cls):
  996. cls.JJJ = type('JJJ', (cls.JJJ,), {})
  997. class AAA(SSS):
  998. pass
  999. class BBB(AAA.JJJ):
  1000. pass
  1001. """)
  1002. self.assertFalse(scoped_nodes._is_metaclass(klass))
  1003. ancestors = [base.name for base in klass.ancestors()]
  1004. self.assertIn('object', ancestors)
  1005. self.assertIn('JJJ', ancestors)
  1006. def test_no_infinite_metaclass_loop_with_redefine(self):
  1007. ast_nodes = builder.extract_node("""
  1008. import datetime
  1009. class A(datetime.date): #@
  1010. @classmethod
  1011. def now(cls):
  1012. return cls()
  1013. class B(datetime.date): #@
  1014. pass
  1015. datetime.date = A
  1016. datetime.date = B
  1017. """)
  1018. for klass in ast_nodes:
  1019. self.assertEqual(None, klass.metaclass())
  1020. def test_metaclass_generator_hack(self):
  1021. klass = builder.extract_node("""
  1022. import six
  1023. class WithMeta(six.with_metaclass(type, object)): #@
  1024. pass
  1025. """)
  1026. self.assertEqual(
  1027. ['object'],
  1028. [base.name for base in klass.ancestors()])
  1029. self.assertEqual(
  1030. 'type', klass.metaclass().name)
  1031. def test_using_six_add_metaclass(self):
  1032. klass = builder.extract_node('''
  1033. import six
  1034. import abc
  1035. @six.add_metaclass(abc.ABCMeta)
  1036. class WithMeta(object):
  1037. pass
  1038. ''')
  1039. inferred = next(klass.infer())
  1040. metaclass = inferred.metaclass()
  1041. self.assertIsInstance(metaclass, scoped_nodes.ClassDef)
  1042. self.assertEqual(metaclass.qname(), 'abc.ABCMeta')
  1043. def test_using_invalid_six_add_metaclass_call(self):
  1044. klass = builder.extract_node('''
  1045. import six
  1046. @six.add_metaclass()
  1047. class Invalid(object):
  1048. pass
  1049. ''')
  1050. inferred = next(klass.infer())
  1051. self.assertIsNone(inferred.metaclass())
  1052. def test_nonregr_infer_callresult(self):
  1053. astroid = builder.parse("""
  1054. class Delegate(object):
  1055. def __get__(self, obj, cls):
  1056. return getattr(obj._subject, self.attribute)
  1057. class CompositeBuilder(object):
  1058. __call__ = Delegate()
  1059. builder = CompositeBuilder(result, composite)
  1060. tgts = builder()
  1061. """)
  1062. instance = astroid['tgts']
  1063. # used to raise "'_Yes' object is not iterable", see
  1064. # https://bitbucket.org/logilab/astroid/issue/17
  1065. self.assertEqual(list(instance.infer()), [util.Uninferable])
  1066. def test_slots(self):
  1067. astroid = builder.parse("""
  1068. from collections import deque
  1069. from textwrap import dedent
  1070. class First(object): #@
  1071. __slots__ = ("a", "b", 1)
  1072. class Second(object): #@
  1073. __slots__ = "a"
  1074. class Third(object): #@
  1075. __slots__ = deque(["a", "b", "c"])
  1076. class Fourth(object): #@
  1077. __slots__ = {"a": "a", "b": "b"}
  1078. class Fifth(object): #@
  1079. __slots__ = list
  1080. class Sixth(object): #@
  1081. __slots__ = ""
  1082. class Seventh(object): #@
  1083. __slots__ = dedent.__name__
  1084. class Eight(object): #@
  1085. __slots__ = ("parens")
  1086. class Ninth(object): #@
  1087. pass
  1088. class Ten(object): #@
  1089. __slots__ = dict({"a": "b", "c": "d"})
  1090. """)
  1091. expected = [
  1092. ('First', ('a', 'b')),
  1093. ('Second', ('a', )),
  1094. ('Third', None),
  1095. ('Fourth', ('a', 'b')),
  1096. ('Fifth', None),
  1097. ('Sixth', None),
  1098. ('Seventh', ('dedent', )),
  1099. ('Eight', ('parens', )),
  1100. ('Ninth', None),
  1101. ('Ten', ('a', 'c')),
  1102. ]
  1103. for cls, expected_value in expected:
  1104. slots = astroid[cls].slots()
  1105. if expected_value is None:
  1106. self.assertIsNone(slots)
  1107. else:
  1108. self.assertEqual(list(expected_value),
  1109. [node.value for node in slots])
  1110. @test_utils.require_version(maxver='3.0')
  1111. def test_slots_py2(self):
  1112. module = builder.parse("""
  1113. class UnicodeSlots(object):
  1114. __slots__ = (u"a", u"b", "c")
  1115. """)
  1116. slots = module['UnicodeSlots'].slots()
  1117. self.assertEqual(len(slots), 3)
  1118. self.assertEqual(slots[0].value, "a")
  1119. self.assertEqual(slots[1].value, "b")
  1120. self.assertEqual(slots[2].value, "c")
  1121. @test_utils.require_version(maxver='3.0')
  1122. def test_slots_py2_not_implemented(self):
  1123. module = builder.parse("""
  1124. class OldStyle:
  1125. __slots__ = ("a", "b")
  1126. """)
  1127. msg = "The concept of slots is undefined for old-style classes."
  1128. with self.assertRaises(NotImplementedError) as cm:
  1129. module['OldStyle'].slots()
  1130. self.assertEqual(str(cm.exception), msg)
  1131. def test_slots_for_dict_keys(self):
  1132. module = builder.parse('''
  1133. class Issue(object):
  1134. SlotDefaults = {'id': 0, 'id1':1}
  1135. __slots__ = SlotDefaults.keys()
  1136. ''')
  1137. cls = module['Issue']
  1138. slots = cls.slots()
  1139. self.assertEqual(len(slots), 2)
  1140. self.assertEqual(slots[0].value, 'id')
  1141. self.assertEqual(slots[1].value, 'id1')
  1142. def test_slots_empty_list_of_slots(self):
  1143. module = builder.parse("""
  1144. class Klass(object):
  1145. __slots__ = ()
  1146. """)
  1147. cls = module['Klass']
  1148. self.assertEqual(cls.slots(), [])
  1149. def test_slots_taken_from_parents(self):
  1150. module = builder.parse('''
  1151. class FirstParent(object):
  1152. __slots__ = ('a', 'b', 'c')
  1153. class SecondParent(FirstParent):
  1154. __slots__ = ('d', 'e')
  1155. class Third(SecondParent):
  1156. __slots__ = ('d', )
  1157. ''')
  1158. cls = module['Third']
  1159. slots = cls.slots()
  1160. self.assertEqual(sorted(set(slot.value for slot in slots)),
  1161. ['a', 'b', 'c', 'd', 'e'])
  1162. def test_all_ancestors_need_slots(self):
  1163. module = builder.parse('''
  1164. class A(object):
  1165. __slots__ = ('a', )
  1166. class B(A): pass
  1167. class C(B):
  1168. __slots__ = ('a', )
  1169. ''')
  1170. cls = module['C']
  1171. self.assertIsNone(cls.slots())
  1172. cls = module['B']
  1173. self.assertIsNone(cls.slots())
  1174. def assertEqualMro(self, klass, expected_mro):
  1175. self.assertEqual(
  1176. [member.name for member in klass.mro()],
  1177. expected_mro)
  1178. @test_utils.require_version(maxver='3.0')
  1179. def test_no_mro_for_old_style(self):
  1180. node = builder.extract_node("""
  1181. class Old: pass""")
  1182. with self.assertRaises(NotImplementedError) as cm:
  1183. node.mro()
  1184. self.assertEqual(str(cm.exception), "Could not obtain mro for "
  1185. "old-style classes.")
  1186. @test_utils.require_version(maxver='3.0')
  1187. def test_mro_for_classes_with_old_style_in_mro(self):
  1188. node = builder.extract_node('''
  1189. class Factory:
  1190. pass
  1191. class ClientFactory(Factory):
  1192. pass
  1193. class ReconnectingClientFactory(ClientFactory):
  1194. pass
  1195. class WebSocketAdapterFactory(object):
  1196. pass
  1197. class WebSocketClientFactory(WebSocketAdapterFactory, ClientFactory):
  1198. pass
  1199. class WampWebSocketClientFactory(WebSocketClientFactory):
  1200. pass
  1201. class RetryFactory(WampWebSocketClientFactory, ReconnectingClientFactory):
  1202. pas
  1203. ''')
  1204. self.assertEqualMro(
  1205. node,
  1206. ['RetryFactory', 'WampWebSocketClientFactory',
  1207. 'WebSocketClientFactory', 'WebSocketAdapterFactory', 'object',
  1208. 'ReconnectingClientFactory', 'ClientFactory',
  1209. 'Factory']
  1210. )
  1211. @test_utils.require_version(maxver='3.0')
  1212. def test_combined_newstyle_oldstyle_in_mro(self):
  1213. node = builder.extract_node('''
  1214. class Old:
  1215. pass
  1216. class New(object):
  1217. pass
  1218. class New1(object):
  1219. pass
  1220. class New2(New, New1):
  1221. pass
  1222. class NewOld(New2, Old): #@
  1223. pass
  1224. ''')
  1225. self.assertEqualMro(node, ['NewOld', 'New2', 'New', 'New1', 'object', 'Old'])
  1226. self.assertTrue(node.newstyle)
  1227. def test_with_metaclass_mro(self):
  1228. astroid = builder.parse("""
  1229. import six
  1230. class C(object):
  1231. pass
  1232. class B(C):
  1233. pass
  1234. class A(six.with_metaclass(type, B)):
  1235. pass
  1236. """)
  1237. self.assertEqualMro(astroid['A'], ['A', 'B', 'C', 'object'])
  1238. def test_mro(self):
  1239. astroid = builder.parse("""
  1240. class C(object): pass
  1241. class D(dict, C): pass
  1242. class A1(object): pass
  1243. class B1(A1): pass
  1244. class C1(A1): pass
  1245. class D1(B1, C1): pass
  1246. class E1(C1, B1): pass
  1247. class F1(D1, E1): pass
  1248. class G1(E1, D1): pass
  1249. class Boat(object): pass
  1250. class DayBoat(Boat): pass
  1251. class WheelBoat(Boat): pass
  1252. class EngineLess(DayBoat): pass
  1253. class SmallMultihull(DayBoat): pass
  1254. class PedalWheelBoat(EngineLess, WheelBoat): pass
  1255. class SmallCatamaran(SmallMultihull): pass
  1256. class Pedalo(PedalWheelBoat, SmallCatamaran): pass
  1257. class OuterA(object):
  1258. class Inner(object):
  1259. pass
  1260. class OuterB(OuterA):
  1261. class Inner(OuterA.Inner):
  1262. pass
  1263. class OuterC(OuterA):
  1264. class Inner(OuterA.Inner):
  1265. pass
  1266. class OuterD(OuterC):
  1267. class Inner(OuterC.Inner, OuterB.Inner):
  1268. pass
  1269. class Duplicates(str, str): pass
  1270. """)
  1271. self.assertEqualMro(astroid['D'], ['D', 'dict', 'C', 'object'])
  1272. self.assertEqualMro(astroid['D1'], ['D1', 'B1', 'C1', 'A1', 'object'])
  1273. self.assertEqualMro(astroid['E1'], ['E1', 'C1', 'B1', 'A1', 'object'])
  1274. with self.assertRaises(InconsistentMroError) as cm:
  1275. astroid['F1'].mro()
  1276. A1 = astroid.getattr('A1')[0]
  1277. B1 = astroid.getattr('B1')[0]
  1278. C1 = astroid.getattr('C1')[0]
  1279. object_ = builder.MANAGER.astroid_cache[BUILTINS].getattr('object')[0]
  1280. self.assertEqual(cm.exception.mros, [[B1, C1, A1, object_],
  1281. [C1, B1, A1, object_]])
  1282. with self.assertRaises(InconsistentMroError) as cm:
  1283. astroid['G1'].mro()
  1284. self.assertEqual(cm.exception.mros, [[C1, B1, A1, object_],
  1285. [B1, C1, A1, object_]])
  1286. self.assertEqualMro(
  1287. astroid['PedalWheelBoat'],
  1288. ["PedalWheelBoat", "EngineLess",
  1289. "DayBoat", "WheelBoat", "Boat", "object"])
  1290. self.assertEqualMro(
  1291. astroid["SmallCatamaran"],
  1292. ["SmallCatamaran", "SmallMultihull", "DayBoat", "Boat", "object"])
  1293. self.assertEqualMro(
  1294. astroid["Pedalo"],
  1295. ["Pedalo", "PedalWheelBoat", "EngineLess", "SmallCatamaran",
  1296. "SmallMultihull", "DayBoat", "WheelBoat", "Boat", "object"])
  1297. self.assertEqualMro(
  1298. astroid['OuterD']['Inner'],
  1299. ['Inner', 'Inner', 'Inner', 'Inner', 'object'])
  1300. with self.assertRaises(DuplicateBasesError) as cm:
  1301. astroid['Duplicates'].mro()
  1302. Duplicates = astroid.getattr('Duplicates')[0]
  1303. self.assertEqual(cm.exception.cls, Duplicates)
  1304. self.assertIsInstance(cm.exception, MroError)
  1305. self.assertIsInstance(cm.exception, ResolveError)
  1306. def test_mro_with_factories(self):
  1307. cls = builder.extract_node('''
  1308. def MixinFactory(cls):
  1309. mixin_name = '{}Mixin'.format(cls.__name__)
  1310. mixin_bases = (object,)
  1311. mixin_attrs = {}
  1312. mixin = type(mixin_name, mixin_bases, mixin_attrs)
  1313. return mixin
  1314. class MixinA(MixinFactory(int)):
  1315. pass
  1316. class MixinB(MixinFactory(str)):
  1317. pass
  1318. class Base(object):
  1319. pass
  1320. class ClassA(MixinA, Base):
  1321. pass
  1322. class ClassB(MixinB, ClassA):
  1323. pass
  1324. class FinalClass(ClassB):
  1325. def __init__(self):
  1326. self.name = 'x'
  1327. ''')
  1328. self.assertEqualMro(
  1329. cls,
  1330. [
  1331. "FinalClass", "ClassB", "MixinB", "", "ClassA", "MixinA", "", "Base", "object"
  1332. ]
  1333. )
  1334. def test_generator_from_infer_call_result_parent(self):
  1335. func = builder.extract_node("""
  1336. import contextlib
  1337. @contextlib.contextmanager
  1338. def test(): #@
  1339. yield
  1340. """)
  1341. result = next(func.infer_call_result(func))
  1342. self.assertIsInstance(result, Generator)
  1343. self.assertEqual(result.parent, func)
  1344. def test_type_three_arguments(self):
  1345. classes = builder.extract_node("""
  1346. type('A', (object, ), {"a": 1, "b": 2, missing: 3}) #@
  1347. """)
  1348. first = next(classes.infer())
  1349. self.assertIsInstance(first, nodes.ClassDef)
  1350. self.assertEqual(first.name, "A")
  1351. self.assertEqual(first.basenames, ["object"])
  1352. self.assertIsInstance(first["a"], nodes.Const)
  1353. self.assertEqual(first["a"].value, 1)
  1354. self.assertIsInstance(first["b"], nodes.Const)
  1355. self.assertEqual(first["b"].value, 2)
  1356. with self.assertRaises(AttributeInferenceError):
  1357. first.getattr("missing")
  1358. def test_implicit_metaclass(self):
  1359. cls = builder.extract_node("""
  1360. class A(object):
  1361. pass
  1362. """)
  1363. type_cls = scoped_nodes.builtin_lookup("type")[1][0]
  1364. self.assertEqual(cls.implicit_metaclass(), type_cls)
  1365. def test_implicit_metaclass_lookup(self):
  1366. cls = builder.extract_node('''
  1367. class A(object):
  1368. pass
  1369. ''')
  1370. instance = cls.instantiate_class()
  1371. func = cls.getattr('mro')
  1372. self.assertEqual(len(func), 1)
  1373. self.assertRaises(AttributeInferenceError, instance.getattr, 'mro')
  1374. def test_metaclass_lookup_using_same_class(self):
  1375. # Check that we don't have recursive attribute access for metaclass
  1376. cls = builder.extract_node('''
  1377. class A(object): pass
  1378. ''')
  1379. self.assertEqual(len(cls.getattr('mro')), 1)
  1380. def test_metaclass_lookup_inferrence_errors(self):
  1381. module = builder.parse('''
  1382. import six
  1383. class Metaclass(type):
  1384. foo = lala
  1385. @six.add_metaclass(Metaclass)
  1386. class B(object): pass
  1387. ''')
  1388. cls = module['B']
  1389. self.assertEqual(util.Uninferable, next(cls.igetattr('foo')))
  1390. def test_metaclass_lookup(self):
  1391. module = builder.parse('''
  1392. import six
  1393. class Metaclass(type):
  1394. foo = 42
  1395. @classmethod
  1396. def class_method(cls):
  1397. pass
  1398. def normal_method(cls):
  1399. pass
  1400. @property
  1401. def meta_property(cls):
  1402. return 42
  1403. @staticmethod
  1404. def static():
  1405. pass
  1406. @six.add_metaclass(Metaclass)
  1407. class A(object):
  1408. pass
  1409. ''')
  1410. acls = module['A']
  1411. normal_attr = next(acls.igetattr('foo'))
  1412. self.assertIsInstance(normal_attr, nodes.Const)
  1413. self.assertEqual(normal_attr.value, 42)
  1414. class_method = next(acls.igetattr('class_method'))
  1415. self.assertIsInstance(class_method, BoundMethod)
  1416. self.assertEqual(class_method.bound, module['Metaclass'])
  1417. normal_method = next(acls.igetattr('normal_method'))
  1418. self.assertIsInstance(normal_method, BoundMethod)
  1419. self.assertEqual(normal_method.bound, module['A'])
  1420. # Attribute access for properties:
  1421. # from the metaclass is a property object
  1422. # from the class that uses the metaclass, the value
  1423. # of the property
  1424. property_meta = next(module['Metaclass'].igetattr('meta_property'))
  1425. self.assertIsInstance(property_meta, UnboundMethod)
  1426. wrapping = scoped_nodes.get_wrapping_class(property_meta)
  1427. self.assertEqual(wrapping, module['Metaclass'])
  1428. property_class = next(acls.igetattr('meta_property'))
  1429. self.assertIsInstance(property_class, nodes.Const)
  1430. self.assertEqual(property_class.value, 42)
  1431. static = next(acls.igetattr('static'))
  1432. self.assertIsInstance(static, scoped_nodes.FunctionDef)
  1433. @test_utils.require_version(maxver='3.0')
  1434. def test_implicit_metaclass_is_none(self):
  1435. cls = builder.extract_node("""
  1436. class A: pass
  1437. """)
  1438. self.assertIsNone(cls.implicit_metaclass())
  1439. def test_local_attr_invalid_mro(self):
  1440. cls = builder.extract_node("""
  1441. # A has an invalid MRO, local_attr should fallback
  1442. # to using .ancestors.
  1443. class A(object, object):
  1444. test = 42
  1445. class B(A): #@
  1446. pass
  1447. """)
  1448. local = cls.local_attr('test')[0]
  1449. inferred = next(local.infer())
  1450. self.assertIsInstance(inferred, nodes.Const)
  1451. self.assertEqual(inferred.value, 42)
  1452. def test_has_dynamic_getattr(self):
  1453. module = builder.parse("""
  1454. class Getattr(object):
  1455. def __getattr__(self, attrname):
  1456. pass
  1457. class Getattribute(object):
  1458. def __getattribute__(self, attrname):
  1459. pass
  1460. class ParentGetattr(Getattr):
  1461. pass
  1462. """)
  1463. self.assertTrue(module['Getattr'].has_dynamic_getattr())
  1464. self.assertTrue(module['Getattribute'].has_dynamic_getattr())
  1465. self.assertTrue(module['ParentGetattr'].has_dynamic_getattr())
  1466. # Test that objects analyzed through the live introspection
  1467. # aren't considered to have dynamic getattr implemented.
  1468. import datetime
  1469. astroid_builder = builder.AstroidBuilder()
  1470. module = astroid_builder.module_build(datetime)
  1471. self.assertFalse(module['timedelta'].has_dynamic_getattr())
  1472. def test_duplicate_bases_namedtuple(self):
  1473. module = builder.parse("""
  1474. import collections
  1475. _A = collections.namedtuple('A', 'a')
  1476. class A(_A): pass
  1477. class B(A): pass
  1478. """)
  1479. names = ['B', 'A', 'A', 'tuple', 'object']
  1480. mro = module['B'].mro()
  1481. class_names = [i.name for i in mro]
  1482. self.assertEqual(names, class_names)
  1483. def test_instance_bound_method_lambdas(self):
  1484. ast_nodes = builder.extract_node('''
  1485. class Test(object): #@
  1486. lam = lambda self: self
  1487. not_method = lambda xargs: xargs
  1488. Test() #@
  1489. ''')
  1490. cls = next(ast_nodes[0].infer())
  1491. self.assertIsInstance(next(cls.igetattr('lam')), scoped_nodes.Lambda)
  1492. self.assertIsInstance(next(cls.igetattr('not_method')), scoped_nodes.Lambda)
  1493. instance = next(ast_nodes[1].infer())
  1494. lam = next(instance.igetattr('lam'))
  1495. self.assertIsInstance(lam, BoundMethod)
  1496. not_method = next(instance.igetattr('not_method'))
  1497. self.assertIsInstance(not_method, scoped_nodes.Lambda)
  1498. def test_class_extra_decorators_frame_is_not_class(self):
  1499. ast_node = builder.extract_node('''
  1500. def ala():
  1501. def bala(): #@
  1502. func = 42
  1503. ''')
  1504. self.assertEqual(ast_node.extra_decorators, [])
  1505. def test_class_extra_decorators_only_callfunc_are_considered(self):
  1506. ast_node = builder.extract_node('''
  1507. class Ala(object):
  1508. def func(self): #@
  1509. pass
  1510. func = 42
  1511. ''')
  1512. self.assertEqual(ast_node.extra_decorators, [])
  1513. def test_class_extra_decorators_only_assignment_names_are_considered(self):
  1514. ast_node = builder.extract_node('''
  1515. class Ala(object):
  1516. def func(self): #@
  1517. pass
  1518. def __init__(self):
  1519. self.func = staticmethod(func)
  1520. ''')
  1521. self.assertEqual(ast_node.extra_decorators, [])
  1522. def test_class_extra_decorators_only_same_name_considered(self):
  1523. ast_node = builder.extract_node('''
  1524. class Ala(object):
  1525. def func(self): #@
  1526. pass
  1527. bala = staticmethod(func)
  1528. ''')
  1529. self.assertEqual(ast_node.extra_decorators, [])
  1530. self.assertEqual(ast_node.type, 'method')
  1531. def test_class_extra_decorators(self):
  1532. static_method, clsmethod = builder.extract_node('''
  1533. class Ala(object):
  1534. def static(self): #@
  1535. pass
  1536. def class_method(self): #@
  1537. pass
  1538. class_method = classmethod(class_method)
  1539. static = staticmethod(static)
  1540. ''')
  1541. self.assertEqual(len(clsmethod.extra_decorators), 1)
  1542. self.assertEqual(clsmethod.type, 'classmethod')
  1543. self.assertEqual(len(static_method.extra_decorators), 1)
  1544. self.assertEqual(static_method.type, 'staticmethod')
  1545. def test_extra_decorators_only_class_level_assignments(self):
  1546. node = builder.extract_node('''
  1547. def _bind(arg):
  1548. return arg.bind
  1549. class A(object):
  1550. @property
  1551. def bind(self):
  1552. return 42
  1553. def irelevant(self):
  1554. # This is important, because it used to trigger
  1555. # a maximum recursion error.
  1556. bind = _bind(self)
  1557. return bind
  1558. A() #@
  1559. ''')
  1560. inferred = next(node.infer())
  1561. bind = next(inferred.igetattr('bind'))
  1562. self.assertIsInstance(bind, nodes.Const)
  1563. self.assertEqual(bind.value, 42)
  1564. parent = bind.scope()
  1565. self.assertEqual(len(parent.extra_decorators), 0)
  1566. @test_utils.require_version(minver='3.0')
  1567. def test_class_keywords(self):
  1568. data = '''
  1569. class TestKlass(object, metaclass=TestMetaKlass,
  1570. foo=42, bar='baz'):
  1571. pass
  1572. '''
  1573. astroid = builder.parse(data, __name__)
  1574. cls = astroid['TestKlass']
  1575. self.assertEqual(len(cls.keywords), 2)
  1576. self.assertEqual([x.arg for x in cls.keywords], ['foo', 'bar'])
  1577. if __name__ == '__main__':
  1578. unittest.main()