1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789 |
- # Copyright (c) 2006-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
- # Copyright (c) 2011, 2013-2015 Google, Inc.
- # Copyright (c) 2013-2016 Claudiu Popa <pcmanticore@gmail.com>
- # Copyright (c) 2015-2016 Cara Vinson <ceridwenv@gmail.com>
- # Copyright (c) 2015 Philip Lorenz <philip@bithub.de>
- # Copyright (c) 2015 Rene Zhang <rz99@cornell.edu>
-
- # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
- # For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER
-
- """tests for specific behaviour of astroid scoped nodes (i.e. module, class and
- function)
- """
- import os
- import sys
- from functools import partial
- import unittest
-
- from astroid import builder
- from astroid import nodes
- from astroid import scoped_nodes
- from astroid import util
- from astroid.exceptions import (
- InferenceError, AttributeInferenceError,
- NoDefault, ResolveError, MroError,
- InconsistentMroError, DuplicateBasesError,
- TooManyLevelsError,
- NameInferenceError
- )
- from astroid.bases import (
- BUILTINS, Instance,
- BoundMethod, UnboundMethod, Generator
- )
- from astroid import __pkginfo__
- from astroid import test_utils
- from astroid.tests import resources
-
-
- def _test_dict_interface(self, node, test_attr):
- self.assertIs(node[test_attr], node[test_attr])
- self.assertIn(test_attr, node)
- node.keys()
- node.values()
- node.items()
- iter(node)
-
-
- class ModuleLoader(resources.SysPathSetup):
- def setUp(self):
- super(ModuleLoader, self).setUp()
- self.module = resources.build_file('data/module.py', 'data.module')
- self.module2 = resources.build_file('data/module2.py', 'data.module2')
- self.nonregr = resources.build_file('data/nonregr.py', 'data.nonregr')
- self.pack = resources.build_file('data/__init__.py', 'data')
-
-
- class ModuleNodeTest(ModuleLoader, unittest.TestCase):
-
- def test_special_attributes(self):
- self.assertEqual(len(self.module.getattr('__name__')), 1)
- self.assertIsInstance(self.module.getattr('__name__')[0], nodes.Const)
- self.assertEqual(self.module.getattr('__name__')[0].value, 'data.module')
- self.assertEqual(len(self.module.getattr('__doc__')), 1)
- self.assertIsInstance(self.module.getattr('__doc__')[0], nodes.Const)
- self.assertEqual(self.module.getattr('__doc__')[0].value, 'test module for astroid\n')
- self.assertEqual(len(self.module.getattr('__file__')), 1)
- self.assertIsInstance(self.module.getattr('__file__')[0], nodes.Const)
- self.assertEqual(self.module.getattr('__file__')[0].value,
- os.path.abspath(resources.find('data/module.py')))
- self.assertEqual(len(self.module.getattr('__dict__')), 1)
- self.assertIsInstance(self.module.getattr('__dict__')[0], nodes.Dict)
- self.assertRaises(AttributeInferenceError, self.module.getattr, '__path__')
- self.assertEqual(len(self.pack.getattr('__path__')), 1)
- self.assertIsInstance(self.pack.getattr('__path__')[0], nodes.List)
-
- def test_dict_interface(self):
- _test_dict_interface(self, self.module, 'YO')
-
- def test_getattr(self):
- yo = self.module.getattr('YO')[0]
- self.assertIsInstance(yo, nodes.ClassDef)
- self.assertEqual(yo.name, 'YO')
- red = next(self.module.igetattr('redirect'))
- self.assertIsInstance(red, nodes.FunctionDef)
- self.assertEqual(red.name, 'four_args')
- namenode = next(self.module.igetattr('NameNode'))
- self.assertIsInstance(namenode, nodes.ClassDef)
- self.assertEqual(namenode.name, 'Name')
- # resolve packageredirection
- mod = resources.build_file('data/appl/myConnection.py',
- 'data.appl.myConnection')
- ssl = next(mod.igetattr('SSL1'))
- cnx = next(ssl.igetattr('Connection'))
- self.assertEqual(cnx.__class__, nodes.ClassDef)
- self.assertEqual(cnx.name, 'Connection')
- self.assertEqual(cnx.root().name, 'data.SSL1.Connection1')
- self.assertEqual(len(self.nonregr.getattr('enumerate')), 2)
- self.assertRaises(InferenceError, self.nonregr.igetattr, 'YOAA')
-
- def test_wildcard_import_names(self):
- m = resources.build_file('data/all.py', 'all')
- self.assertEqual(m.wildcard_import_names(), ['Aaa', '_bla', 'name'])
- m = resources.build_file('data/notall.py', 'notall')
- res = sorted(m.wildcard_import_names())
- self.assertEqual(res, ['Aaa', 'func', 'name', 'other'])
-
- def test_public_names(self):
- m = builder.parse('''
- name = 'a'
- _bla = 2
- other = 'o'
- class Aaa: pass
- def func(): print('yo')
- __all__ = 'Aaa', '_bla', 'name'
- ''')
- values = sorted(['Aaa', 'name', 'other', 'func'])
- self.assertEqual(sorted(m.public_names()), values)
- m = builder.parse('''
- name = 'a'
- _bla = 2
- other = 'o'
- class Aaa: pass
-
- def func(): return 'yo'
- ''')
- res = sorted(m.public_names())
- self.assertEqual(res, values)
-
- m = builder.parse('''
- from missing import tzop
- trop = "test"
- __all__ = (trop, "test1", tzop, 42)
- ''')
- res = sorted(m.public_names())
- self.assertEqual(res, ["trop", "tzop"])
-
- m = builder.parse('''
- test = tzop = 42
- __all__ = ('test', ) + ('tzop', )
- ''')
- res = sorted(m.public_names())
- self.assertEqual(res, ['test', 'tzop'])
-
- def test_module_getattr(self):
- data = '''
- appli = application
- appli += 2
- del appli
- '''
- astroid = builder.parse(data, __name__)
- # test del statement not returned by getattr
- self.assertEqual(len(astroid.getattr('appli')), 2,
- astroid.getattr('appli'))
-
- def test_relative_to_absolute_name(self):
- # package
- mod = nodes.Module('very.multi.package', 'doc')
- mod.package = True
- modname = mod.relative_to_absolute_name('utils', 1)
- self.assertEqual(modname, 'very.multi.package.utils')
- modname = mod.relative_to_absolute_name('utils', 2)
- self.assertEqual(modname, 'very.multi.utils')
- modname = mod.relative_to_absolute_name('utils', 0)
- self.assertEqual(modname, 'very.multi.package.utils')
- modname = mod.relative_to_absolute_name('', 1)
- self.assertEqual(modname, 'very.multi.package')
- # non package
- mod = nodes.Module('very.multi.module', 'doc')
- mod.package = False
- modname = mod.relative_to_absolute_name('utils', 0)
- self.assertEqual(modname, 'very.multi.utils')
- modname = mod.relative_to_absolute_name('utils', 1)
- self.assertEqual(modname, 'very.multi.utils')
- modname = mod.relative_to_absolute_name('utils', 2)
- self.assertEqual(modname, 'very.utils')
- modname = mod.relative_to_absolute_name('', 1)
- self.assertEqual(modname, 'very.multi')
-
- def test_relative_to_absolute_name_beyond_top_level(self):
- mod = nodes.Module('a.b.c', '')
- mod.package = True
- for level in (5, 4):
- with self.assertRaises(TooManyLevelsError) as cm:
- mod.relative_to_absolute_name('test', level)
-
- expected = ("Relative import with too many levels "
- "({level}) for module {name!r}".format(
- level=level - 1, name=mod.name))
- self.assertEqual(expected, str(cm.exception))
-
- def test_import_1(self):
- data = '''from . import subpackage'''
- sys.path.insert(0, resources.find('data'))
- astroid = builder.parse(data, 'package', 'data/package/__init__.py')
- try:
- m = astroid.import_module('', level=1)
- self.assertEqual(m.name, 'package')
- inferred = list(astroid.igetattr('subpackage'))
- self.assertEqual(len(inferred), 1)
- self.assertEqual(inferred[0].name, 'package.subpackage')
- finally:
- del sys.path[0]
-
-
- def test_import_2(self):
- data = '''from . import subpackage as pouet'''
- astroid = builder.parse(data, 'package', 'data/package/__init__.py')
- sys.path.insert(0, resources.find('data'))
- try:
- m = astroid.import_module('', level=1)
- self.assertEqual(m.name, 'package')
- inferred = list(astroid.igetattr('pouet'))
- self.assertEqual(len(inferred), 1)
- self.assertEqual(inferred[0].name, 'package.subpackage')
- finally:
- del sys.path[0]
-
-
- def test_file_stream_in_memory(self):
- data = '''irrelevant_variable is irrelevant'''
- astroid = builder.parse(data, 'in_memory')
- with astroid.stream() as stream:
- self.assertEqual(stream.read().decode(), data)
-
- def test_file_stream_physical(self):
- path = resources.find('data/all.py')
- astroid = builder.AstroidBuilder().file_build(path, 'all')
- with open(path, 'rb') as file_io:
- with astroid.stream() as stream:
- self.assertEqual(stream.read(), file_io.read())
-
- def test_file_stream_api(self):
- path = resources.find('data/all.py')
- astroid = builder.AstroidBuilder().file_build(path, 'all')
- with self.assertRaises(AttributeError):
- # pylint: disable=pointless-statement
- astroid.file_stream
-
- def test_stream_api(self):
- path = resources.find('data/all.py')
- astroid = builder.AstroidBuilder().file_build(path, 'all')
- stream = astroid.stream()
- self.assertTrue(hasattr(stream, 'close'))
- with stream:
- with open(path, 'rb') as file_io:
- self.assertEqual(stream.read(), file_io.read())
-
-
- class FunctionNodeTest(ModuleLoader, unittest.TestCase):
-
- def test_special_attributes(self):
- func = self.module2['make_class']
- self.assertEqual(len(func.getattr('__name__')), 1)
- self.assertIsInstance(func.getattr('__name__')[0], nodes.Const)
- self.assertEqual(func.getattr('__name__')[0].value, 'make_class')
- self.assertEqual(len(func.getattr('__doc__')), 1)
- self.assertIsInstance(func.getattr('__doc__')[0], nodes.Const)
- self.assertEqual(func.getattr('__doc__')[0].value,
- 'check base is correctly resolved to Concrete0')
- self.assertEqual(len(self.module.getattr('__dict__')), 1)
- self.assertIsInstance(self.module.getattr('__dict__')[0], nodes.Dict)
-
- def test_dict_interface(self):
- _test_dict_interface(self, self.module['global_access'], 'local')
-
- def test_default_value(self):
- func = self.module2['make_class']
- self.assertIsInstance(func.args.default_value('base'), nodes.Attribute)
- self.assertRaises(NoDefault, func.args.default_value, 'args')
- self.assertRaises(NoDefault, func.args.default_value, 'kwargs')
- self.assertRaises(NoDefault, func.args.default_value, 'any')
- #self.assertIsInstance(func.mularg_class('args'), nodes.Tuple)
- #self.assertIsInstance(func.mularg_class('kwargs'), nodes.Dict)
- #self.assertIsNone(func.mularg_class('base'))
-
- def test_navigation(self):
- function = self.module['global_access']
- self.assertEqual(function.statement(), function)
- l_sibling = function.previous_sibling()
- # check taking parent if child is not a stmt
- self.assertIsInstance(l_sibling, nodes.Assign)
- child = function.args.args[0]
- self.assertIs(l_sibling, child.previous_sibling())
- r_sibling = function.next_sibling()
- self.assertIsInstance(r_sibling, nodes.ClassDef)
- self.assertEqual(r_sibling.name, 'YO')
- self.assertIs(r_sibling, child.next_sibling())
- last = r_sibling.next_sibling().next_sibling().next_sibling()
- self.assertIsInstance(last, nodes.Assign)
- self.assertIsNone(last.next_sibling())
- first = l_sibling.root().body[0]
- self.assertIsNone(first.previous_sibling())
-
- def test_nested_args(self):
- if sys.version_info >= (3, 0):
- self.skipTest("nested args has been removed in py3.x")
- code = '''
- def nested_args(a, (b, c, d)):
- "nested arguments test"
- '''
- tree = builder.parse(code)
- func = tree['nested_args']
- self.assertEqual(sorted(func.locals), ['a', 'b', 'c', 'd'])
- self.assertEqual(func.args.format_args(), 'a, (b, c, d)')
-
- def test_four_args(self):
- func = self.module['four_args']
- local = sorted(func.keys())
- self.assertEqual(local, ['a', 'b', 'c', 'd'])
- self.assertEqual(func.type, 'function')
-
- def test_format_args(self):
- func = self.module2['make_class']
- self.assertEqual(func.args.format_args(),
- 'any, base=data.module.YO, *args, **kwargs')
- func = self.module['four_args']
- self.assertEqual(func.args.format_args(), 'a, b, c, d')
-
- @test_utils.require_version('3.0')
- def test_format_args_keyword_only_args(self):
- node = builder.parse('''
- def test(a: int, *, b: dict):
- pass
- ''').body[-1].args
- formatted = node.format_args()
- self.assertEqual(formatted, 'a:int, *, b:dict')
-
- def test_is_generator(self):
- self.assertTrue(self.module2['generator'].is_generator())
- self.assertFalse(self.module2['not_a_generator'].is_generator())
- self.assertFalse(self.module2['make_class'].is_generator())
-
- def test_is_abstract(self):
- method = self.module2['AbstractClass']['to_override']
- self.assertTrue(method.is_abstract(pass_is_abstract=False))
- self.assertEqual(method.qname(), 'data.module2.AbstractClass.to_override')
- self.assertEqual(method.pytype(), '%s.instancemethod' % BUILTINS)
- method = self.module2['AbstractClass']['return_something']
- self.assertFalse(method.is_abstract(pass_is_abstract=False))
- # non regression : test raise "string" doesn't cause an exception in is_abstract
- func = self.module2['raise_string']
- self.assertFalse(func.is_abstract(pass_is_abstract=False))
-
- def test_is_abstract_decorated(self):
- methods = builder.extract_node("""
- import abc
-
- class Klass(object):
- @abc.abstractproperty
- def prop(self): #@
- pass
-
- @abc.abstractmethod
- def method1(self): #@
- pass
-
- some_other_decorator = lambda x: x
- @some_other_decorator
- def method2(self): #@
- pass
- """)
- self.assertTrue(methods[0].is_abstract(pass_is_abstract=False))
- self.assertTrue(methods[1].is_abstract(pass_is_abstract=False))
- self.assertFalse(methods[2].is_abstract(pass_is_abstract=False))
-
- ## def test_raises(self):
- ## method = self.module2['AbstractClass']['to_override']
- ## self.assertEqual([str(term) for term in method.raises()],
- ## ["Call(Name('NotImplementedError'), [], None, None)"] )
-
- ## def test_returns(self):
- ## method = self.module2['AbstractClass']['return_something']
- ## # use string comp since Node doesn't handle __cmp__
- ## self.assertEqual([str(term) for term in method.returns()],
- ## ["Const('toto')", "Const(None)"])
-
- def test_lambda_pytype(self):
- data = '''
- def f():
- g = lambda: None
- '''
- astroid = builder.parse(data)
- g = list(astroid['f'].ilookup('g'))[0]
- self.assertEqual(g.pytype(), '%s.function' % BUILTINS)
-
- def test_lambda_qname(self):
- astroid = builder.parse('lmbd = lambda: None', __name__)
- self.assertEqual('%s.<lambda>' % __name__, astroid['lmbd'].parent.value.qname())
-
- def test_is_method(self):
- data = '''
- class A:
- def meth1(self):
- return 1
- @classmethod
- def meth2(cls):
- return 2
- @staticmethod
- def meth3():
- return 3
-
- def function():
- return 0
-
- @staticmethod
- def sfunction():
- return -1
- '''
- astroid = builder.parse(data)
- self.assertTrue(astroid['A']['meth1'].is_method())
- self.assertTrue(astroid['A']['meth2'].is_method())
- self.assertTrue(astroid['A']['meth3'].is_method())
- self.assertFalse(astroid['function'].is_method())
- self.assertFalse(astroid['sfunction'].is_method())
-
- def test_argnames(self):
- if sys.version_info < (3, 0):
- code = 'def f(a, (b, c), *args, **kwargs): pass'
- else:
- code = 'def f(a, b, c, *args, **kwargs): pass'
- astroid = builder.parse(code, __name__)
- self.assertEqual(astroid['f'].argnames(), ['a', 'b', 'c', 'args', 'kwargs'])
-
- def test_return_nothing(self):
- """test inferred value on a function with empty return"""
- data = '''
- def func():
- return
-
- a = func()
- '''
- astroid = builder.parse(data)
- call = astroid.body[1].value
- func_vals = call.inferred()
- self.assertEqual(len(func_vals), 1)
- self.assertIsInstance(func_vals[0], nodes.Const)
- self.assertIsNone(func_vals[0].value)
-
- def test_func_instance_attr(self):
- """test instance attributes for functions"""
- data = """
- def test():
- print(test.bar)
-
- test.bar = 1
- test()
- """
- astroid = builder.parse(data, 'mod')
- func = astroid.body[2].value.func.inferred()[0]
- self.assertIsInstance(func, nodes.FunctionDef)
- self.assertEqual(func.name, 'test')
- one = func.getattr('bar')[0].inferred()[0]
- self.assertIsInstance(one, nodes.Const)
- self.assertEqual(one.value, 1)
-
- def test_type_builtin_descriptor_subclasses(self):
- astroid = builder.parse("""
- class classonlymethod(classmethod):
- pass
- class staticonlymethod(staticmethod):
- pass
-
- class Node:
- @classonlymethod
- def clsmethod_subclass(cls):
- pass
- @classmethod
- def clsmethod(cls):
- pass
- @staticonlymethod
- def staticmethod_subclass(cls):
- pass
- @staticmethod
- def stcmethod(cls):
- pass
- """)
- node = astroid.locals['Node'][0]
- self.assertEqual(node.locals['clsmethod_subclass'][0].type,
- 'classmethod')
- self.assertEqual(node.locals['clsmethod'][0].type,
- 'classmethod')
- self.assertEqual(node.locals['staticmethod_subclass'][0].type,
- 'staticmethod')
- self.assertEqual(node.locals['stcmethod'][0].type,
- 'staticmethod')
-
- def test_decorator_builtin_descriptors(self):
- astroid = builder.parse("""
- def static_decorator(platform=None, order=50):
- def wrapper(f):
- f.cgm_module = True
- f.cgm_module_order = order
- f.cgm_module_platform = platform
- return staticmethod(f)
- return wrapper
-
- def long_classmethod_decorator(platform=None, order=50):
- def wrapper(f):
- def wrapper2(f):
- def wrapper3(f):
- f.cgm_module = True
- f.cgm_module_order = order
- f.cgm_module_platform = platform
- return classmethod(f)
- return wrapper3(f)
- return wrapper2(f)
- return wrapper
-
- def classmethod_decorator(platform=None):
- def wrapper(f):
- f.platform = platform
- return classmethod(f)
- return wrapper
-
- def classmethod_wrapper(fn):
- def wrapper(cls, *args, **kwargs):
- result = fn(cls, *args, **kwargs)
- return result
-
- return classmethod(wrapper)
-
- def staticmethod_wrapper(fn):
- def wrapper(*args, **kwargs):
- return fn(*args, **kwargs)
- return staticmethod(wrapper)
-
- class SomeClass(object):
- @static_decorator()
- def static(node, cfg):
- pass
- @classmethod_decorator()
- def classmethod(cls):
- pass
- @static_decorator
- def not_so_static(node):
- pass
- @classmethod_decorator
- def not_so_classmethod(node):
- pass
- @classmethod_wrapper
- def classmethod_wrapped(cls):
- pass
- @staticmethod_wrapper
- def staticmethod_wrapped():
- pass
- @long_classmethod_decorator()
- def long_classmethod(cls):
- pass
- """)
- node = astroid.locals['SomeClass'][0]
- self.assertEqual(node.locals['static'][0].type,
- 'staticmethod')
- self.assertEqual(node.locals['classmethod'][0].type,
- 'classmethod')
- self.assertEqual(node.locals['not_so_static'][0].type,
- 'method')
- self.assertEqual(node.locals['not_so_classmethod'][0].type,
- 'method')
- self.assertEqual(node.locals['classmethod_wrapped'][0].type,
- 'classmethod')
- self.assertEqual(node.locals['staticmethod_wrapped'][0].type,
- 'staticmethod')
- self.assertEqual(node.locals['long_classmethod'][0].type,
- 'classmethod')
-
- def test_igetattr(self):
- func = builder.extract_node('''
- def test():
- pass
- ''')
- func.instance_attrs['value'] = [nodes.Const(42)]
- value = func.getattr('value')
- self.assertEqual(len(value), 1)
- self.assertIsInstance(value[0], nodes.Const)
- self.assertEqual(value[0].value, 42)
- inferred = next(func.igetattr('value'))
- self.assertIsInstance(inferred, nodes.Const)
- self.assertEqual(inferred.value, 42)
-
- @test_utils.require_version(minver='3.0')
- def test_return_annotation_is_not_the_last(self):
- func = builder.extract_node('''
- def test() -> bytes:
- pass
- pass
- return
- ''')
- last_child = func.last_child()
- self.assertIsInstance(last_child, nodes.Return)
- self.assertEqual(func.tolineno, 5)
-
- @test_utils.require_version(minver='3.6')
- def test_method_init_subclass(self):
- klass = builder.extract_node('''
- class MyClass:
- def __init_subclass__(cls):
- pass
- ''')
- method = klass['__init_subclass__']
- self.assertEqual([n.name for n in method.args.args], ['cls'])
- self.assertEqual(method.type, 'classmethod')
-
- @test_utils.require_version(minver='3.0')
- def test_dunder_class_local_to_method(self):
- node = builder.extract_node('''
- class MyClass:
- def test(self):
- __class__ #@
- ''')
- inferred = next(node.infer())
- self.assertIsInstance(inferred, nodes.ClassDef)
- self.assertEqual(inferred.name, 'MyClass')
-
- @test_utils.require_version(minver='3.0')
- def test_dunder_class_local_to_function(self):
- node = builder.extract_node('''
- def test(self):
- __class__ #@
- ''')
- with self.assertRaises(NameInferenceError):
- next(node.infer())
-
- @test_utils.require_version(minver='3.0')
- def test_dunder_class_local_to_classmethod(self):
- node = builder.extract_node('''
- class MyClass:
- @classmethod
- def test(cls):
- __class__ #@
- ''')
- inferred = next(node.infer())
- self.assertIsInstance(inferred, nodes.ClassDef)
- self.assertEqual(inferred.name, 'MyClass')
-
-
- class ClassNodeTest(ModuleLoader, unittest.TestCase):
-
- def test_dict_interface(self):
- _test_dict_interface(self, self.module['YOUPI'], 'method')
-
- def test_cls_special_attributes_1(self):
- cls = self.module['YO']
- self.assertEqual(len(cls.getattr('__bases__')), 1)
- self.assertEqual(len(cls.getattr('__name__')), 1)
- self.assertIsInstance(cls.getattr('__name__')[0], nodes.Const)
- self.assertEqual(cls.getattr('__name__')[0].value, 'YO')
- self.assertEqual(len(cls.getattr('__doc__')), 1)
- self.assertIsInstance(cls.getattr('__doc__')[0], nodes.Const)
- self.assertEqual(cls.getattr('__doc__')[0].value, 'hehe')
- self.assertEqual(len(cls.getattr('__module__')), 1)
- self.assertIsInstance(cls.getattr('__module__')[0], nodes.Const)
- self.assertEqual(cls.getattr('__module__')[0].value, 'data.module')
- self.assertEqual(len(cls.getattr('__dict__')), 1)
- if not cls.newstyle:
- self.assertRaises(AttributeInferenceError, cls.getattr, '__mro__')
- for cls in (nodes.List._proxied, nodes.Const(1)._proxied):
- self.assertEqual(len(cls.getattr('__bases__')), 1)
- self.assertEqual(len(cls.getattr('__name__')), 1)
- self.assertEqual(len(cls.getattr('__doc__')), 1, (cls, cls.getattr('__doc__')))
- self.assertEqual(cls.getattr('__doc__')[0].value, cls.doc)
- self.assertEqual(len(cls.getattr('__module__')), 1)
- self.assertEqual(len(cls.getattr('__dict__')), 1)
- self.assertEqual(len(cls.getattr('__mro__')), 1)
-
- def test__mro__attribute(self):
- node = builder.extract_node('''
- class A(object): pass
- class B(object): pass
- class C(A, B): pass
- ''')
- mro = node.getattr('__mro__')[0]
- self.assertIsInstance(mro, nodes.Tuple)
- self.assertEqual(mro.elts, node.mro())
-
- def test__bases__attribute(self):
- node = builder.extract_node('''
- class A(object): pass
- class B(object): pass
- class C(A, B): pass
- class D(C): pass
- ''')
- bases = node.getattr('__bases__')[0]
- self.assertIsInstance(bases, nodes.Tuple)
- self.assertEqual(len(bases.elts), 1)
- self.assertIsInstance(bases.elts[0], nodes.ClassDef)
- self.assertEqual(bases.elts[0].name, 'C')
-
- def test_cls_special_attributes_2(self):
- astroid = builder.parse('''
- class A(object): pass
- class B(object): pass
-
- A.__bases__ += (B,)
- ''', __name__)
- self.assertEqual(len(astroid['A'].getattr('__bases__')), 2)
- self.assertIsInstance(astroid['A'].getattr('__bases__')[1], nodes.Tuple)
- self.assertIsInstance(astroid['A'].getattr('__bases__')[0], nodes.AssignAttr)
-
- def test_instance_special_attributes(self):
- for inst in (Instance(self.module['YO']), nodes.List(), nodes.Const(1)):
- self.assertRaises(AttributeInferenceError, inst.getattr, '__mro__')
- self.assertRaises(AttributeInferenceError, inst.getattr, '__bases__')
- self.assertRaises(AttributeInferenceError, inst.getattr, '__name__')
- self.assertEqual(len(inst.getattr('__dict__')), 1)
- self.assertEqual(len(inst.getattr('__doc__')), 1)
-
- def test_navigation(self):
- klass = self.module['YO']
- self.assertEqual(klass.statement(), klass)
- l_sibling = klass.previous_sibling()
- self.assertTrue(isinstance(l_sibling, nodes.FunctionDef), l_sibling)
- self.assertEqual(l_sibling.name, 'global_access')
- r_sibling = klass.next_sibling()
- self.assertIsInstance(r_sibling, nodes.ClassDef)
- self.assertEqual(r_sibling.name, 'YOUPI')
-
- def test_local_attr_ancestors(self):
- module = builder.parse('''
- class A():
- def __init__(self): pass
- class B(A): pass
- class C(B): pass
- class D(object): pass
- class F(): pass
- class E(F, D): pass
- ''')
- # Test old-style (Python 2) / new-style (Python 3+) ancestors lookups
- klass2 = module['C']
- it = klass2.local_attr_ancestors('__init__')
- anc_klass = next(it)
- self.assertIsInstance(anc_klass, nodes.ClassDef)
- self.assertEqual(anc_klass.name, 'A')
- if sys.version_info[0] == 2:
- self.assertRaises(StopIteration, partial(next, it))
- else:
- anc_klass = next(it)
- self.assertIsInstance(anc_klass, nodes.ClassDef)
- self.assertEqual(anc_klass.name, 'object')
- self.assertRaises(StopIteration, partial(next, it))
-
- it = klass2.local_attr_ancestors('method')
- self.assertRaises(StopIteration, partial(next, it))
-
- # Test mixed-style ancestor lookups
- klass2 = module['E']
- it = klass2.local_attr_ancestors('__init__')
- anc_klass = next(it)
- self.assertIsInstance(anc_klass, nodes.ClassDef)
- self.assertEqual(anc_klass.name, 'object')
- self.assertRaises(StopIteration, partial(next, it))
-
- def test_local_attr_mro(self):
- module = builder.parse('''
- class A(object):
- def __init__(self): pass
- class B(A):
- def __init__(self, arg, arg2): pass
- class C(A): pass
- class D(C, B): pass
- ''')
- dclass = module['D']
- init = dclass.local_attr('__init__')[0]
- self.assertIsInstance(init, nodes.FunctionDef)
- self.assertEqual(init.parent.name, 'B')
-
- cclass = module['C']
- init = cclass.local_attr('__init__')[0]
- self.assertIsInstance(init, nodes.FunctionDef)
- self.assertEqual(init.parent.name, 'A')
-
- ancestors = list(dclass.local_attr_ancestors('__init__'))
- self.assertEqual([node.name for node in ancestors], ['B', 'A', 'object'])
-
- def test_instance_attr_ancestors(self):
- klass2 = self.module['YOUPI']
- it = klass2.instance_attr_ancestors('yo')
- anc_klass = next(it)
- self.assertIsInstance(anc_klass, nodes.ClassDef)
- self.assertEqual(anc_klass.name, 'YO')
- self.assertRaises(StopIteration, partial(next, it))
- klass2 = self.module['YOUPI']
- it = klass2.instance_attr_ancestors('member')
- self.assertRaises(StopIteration, partial(next, it))
-
- def test_methods(self):
- expected_methods = {'__init__', 'class_method', 'method', 'static_method'}
- klass2 = self.module['YOUPI']
- methods = {m.name for m in klass2.methods()}
- self.assertTrue(
- methods.issuperset(expected_methods))
- methods = {m.name for m in klass2.mymethods()}
- self.assertSetEqual(expected_methods, methods)
- klass2 = self.module2['Specialization']
- methods = {m.name for m in klass2.mymethods()}
- self.assertSetEqual(set([]), methods)
- method_locals = klass2.local_attr('method')
- self.assertEqual(len(method_locals), 1)
- self.assertEqual(method_locals[0].name, 'method')
- self.assertRaises(AttributeInferenceError, klass2.local_attr, 'nonexistent')
- methods = {m.name for m in klass2.methods()}
- self.assertTrue(methods.issuperset(expected_methods))
-
- #def test_rhs(self):
- # my_dict = self.module['MY_DICT']
- # self.assertIsInstance(my_dict.rhs(), nodes.Dict)
- # a = self.module['YO']['a']
- # value = a.rhs()
- # self.assertIsInstance(value, nodes.Const)
- # self.assertEqual(value.value, 1)
-
- @unittest.skipIf(sys.version_info[0] >= 3, "Python 2 class semantics required.")
- def test_ancestors(self):
- klass = self.module['YOUPI']
- self.assertEqual(['YO'], [a.name for a in klass.ancestors()])
- klass = self.module2['Specialization']
- self.assertEqual(['YOUPI', 'YO'], [a.name for a in klass.ancestors()])
-
- @unittest.skipIf(sys.version_info[0] < 3, "Python 3 class semantics required.")
- def test_ancestors_py3(self):
- klass = self.module['YOUPI']
- self.assertEqual(['YO', 'object'], [a.name for a in klass.ancestors()])
- klass = self.module2['Specialization']
- self.assertEqual(['YOUPI', 'YO', 'object'], [a.name for a in klass.ancestors()])
-
- def test_type(self):
- klass = self.module['YOUPI']
- self.assertEqual(klass.type, 'class')
- klass = self.module2['Metaclass']
- self.assertEqual(klass.type, 'metaclass')
- klass = self.module2['MyException']
- self.assertEqual(klass.type, 'exception')
- klass = self.module2['MyError']
- self.assertEqual(klass.type, 'exception')
- # the following class used to be detected as a metaclass
- # after the fix which used instance._proxied in .ancestors(),
- # when in fact it is a normal class
- klass = self.module2['NotMetaclass']
- self.assertEqual(klass.type, 'class')
-
- def test_inner_classes(self):
- eee = self.nonregr['Ccc']['Eee']
- self.assertEqual([n.name for n in eee.ancestors()], ['Ddd', 'Aaa', 'object'])
-
-
- def test_classmethod_attributes(self):
- data = '''
- class WebAppObject(object):
- def registered(cls, application):
- cls.appli = application
- cls.schema = application.schema
- cls.config = application.config
- return cls
- registered = classmethod(registered)
- '''
- astroid = builder.parse(data, __name__)
- cls = astroid['WebAppObject']
- self.assertEqual(sorted(cls.locals.keys()),
- ['appli', 'config', 'registered', 'schema'])
-
- def test_class_getattr(self):
- data = '''
- class WebAppObject(object):
- appli = application
- appli += 2
- del self.appli
- '''
- astroid = builder.parse(data, __name__)
- cls = astroid['WebAppObject']
- # test del statement not returned by getattr
- self.assertEqual(len(cls.getattr('appli')), 2)
-
-
- def test_instance_getattr(self):
- data = '''
- class WebAppObject(object):
- def __init__(self, application):
- self.appli = application
- self.appli += 2
- del self.appli
- '''
- astroid = builder.parse(data)
- inst = Instance(astroid['WebAppObject'])
- # test del statement not returned by getattr
- self.assertEqual(len(inst.getattr('appli')), 2)
-
-
- def test_instance_getattr_with_class_attr(self):
- data = '''
- class Parent:
- aa = 1
- cc = 1
-
- class Klass(Parent):
- aa = 0
- bb = 0
-
- def incr(self, val):
- self.cc = self.aa
- if val > self.aa:
- val = self.aa
- if val < self.bb:
- val = self.bb
- self.aa += val
- '''
- astroid = builder.parse(data)
- inst = Instance(astroid['Klass'])
- self.assertEqual(len(inst.getattr('aa')), 3, inst.getattr('aa'))
- self.assertEqual(len(inst.getattr('bb')), 1, inst.getattr('bb'))
- self.assertEqual(len(inst.getattr('cc')), 2, inst.getattr('cc'))
-
-
- def test_getattr_method_transform(self):
- data = '''
- class Clazz(object):
-
- def m1(self, value):
- self.value = value
- m2 = m1
-
- def func(arg1, arg2):
- "function that will be used as a method"
- return arg1.value + arg2
-
- Clazz.m3 = func
- inst = Clazz()
- inst.m4 = func
- '''
- astroid = builder.parse(data)
- cls = astroid['Clazz']
- # test del statement not returned by getattr
- for method in ('m1', 'm2', 'm3'):
- inferred = list(cls.igetattr(method))
- self.assertEqual(len(inferred), 1)
- self.assertIsInstance(inferred[0], UnboundMethod)
- inferred = list(Instance(cls).igetattr(method))
- self.assertEqual(len(inferred), 1)
- self.assertIsInstance(inferred[0], BoundMethod)
- inferred = list(Instance(cls).igetattr('m4'))
- self.assertEqual(len(inferred), 1)
- self.assertIsInstance(inferred[0], nodes.FunctionDef)
-
- def test_getattr_from_grandpa(self):
- data = '''
- class Future:
- attr = 1
-
- class Present(Future):
- pass
-
- class Past(Present):
- pass
- '''
- astroid = builder.parse(data)
- past = astroid['Past']
- attr = past.getattr('attr')
- self.assertEqual(len(attr), 1)
- attr1 = attr[0]
- self.assertIsInstance(attr1, nodes.AssignName)
- self.assertEqual(attr1.name, 'attr')
-
- def test_function_with_decorator_lineno(self):
- data = '''
- @f(a=2,
- b=3)
- def g1(x):
- print(x)
-
- @f(a=2,
- b=3)
- def g2():
- pass
- '''
- astroid = builder.parse(data)
- self.assertEqual(astroid['g1'].fromlineno, 4)
- self.assertEqual(astroid['g1'].tolineno, 5)
- self.assertEqual(astroid['g2'].fromlineno, 9)
- self.assertEqual(astroid['g2'].tolineno, 10)
-
- @test_utils.require_version(maxver='3.0')
- def test_simple_metaclass(self):
- astroid = builder.parse("""
- class Test(object):
- __metaclass__ = type
- """)
- klass = astroid['Test']
- metaclass = klass.metaclass()
- self.assertIsInstance(metaclass, scoped_nodes.ClassDef)
- self.assertEqual(metaclass.name, 'type')
-
- def test_metaclass_error(self):
- astroid = builder.parse("""
- class Test(object):
- __metaclass__ = typ
- """)
- klass = astroid['Test']
- self.assertFalse(klass.metaclass())
-
- @test_utils.require_version(maxver='3.0')
- def test_metaclass_imported(self):
- astroid = builder.parse("""
- from abc import ABCMeta
- class Test(object):
- __metaclass__ = ABCMeta
- """)
- klass = astroid['Test']
-
- metaclass = klass.metaclass()
- self.assertIsInstance(metaclass, scoped_nodes.ClassDef)
- self.assertEqual(metaclass.name, 'ABCMeta')
-
- def test_metaclass_yes_leak(self):
- astroid = builder.parse("""
- # notice `ab` instead of `abc`
- from ab import ABCMeta
-
- class Meta(object):
- __metaclass__ = ABCMeta
- """)
- klass = astroid['Meta']
- self.assertIsNone(klass.metaclass())
-
- @test_utils.require_version(maxver='3.0')
- def test_newstyle_and_metaclass_good(self):
- astroid = builder.parse("""
- from abc import ABCMeta
- class Test:
- __metaclass__ = ABCMeta
- """)
- klass = astroid['Test']
- self.assertTrue(klass.newstyle)
- self.assertEqual(klass.metaclass().name, 'ABCMeta')
- astroid = builder.parse("""
- from abc import ABCMeta
- __metaclass__ = ABCMeta
- class Test:
- pass
- """)
- klass = astroid['Test']
- self.assertTrue(klass.newstyle)
- self.assertEqual(klass.metaclass().name, 'ABCMeta')
-
- @test_utils.require_version(maxver='3.0')
- def test_nested_metaclass(self):
- astroid = builder.parse("""
- from abc import ABCMeta
- class A(object):
- __metaclass__ = ABCMeta
- class B: pass
-
- __metaclass__ = ABCMeta
- class C:
- __metaclass__ = type
- class D: pass
- """)
- a = astroid['A']
- b = a.locals['B'][0]
- c = astroid['C']
- d = c.locals['D'][0]
- self.assertEqual(a.metaclass().name, 'ABCMeta')
- self.assertFalse(b.newstyle)
- self.assertIsNone(b.metaclass())
- self.assertEqual(c.metaclass().name, 'type')
- self.assertEqual(d.metaclass().name, 'ABCMeta')
-
- @test_utils.require_version(maxver='3.0')
- def test_parent_metaclass(self):
- astroid = builder.parse("""
- from abc import ABCMeta
- class Test:
- __metaclass__ = ABCMeta
- class SubTest(Test): pass
- """)
- klass = astroid['SubTest']
- self.assertTrue(klass.newstyle)
- metaclass = klass.metaclass()
- self.assertIsInstance(metaclass, scoped_nodes.ClassDef)
- self.assertEqual(metaclass.name, 'ABCMeta')
-
- @test_utils.require_version(maxver='3.0')
- def test_metaclass_ancestors(self):
- astroid = builder.parse("""
- from abc import ABCMeta
-
- class FirstMeta(object):
- __metaclass__ = ABCMeta
-
- class SecondMeta(object):
- __metaclass__ = type
-
- class Simple(object):
- pass
-
- class FirstImpl(FirstMeta): pass
- class SecondImpl(FirstImpl): pass
- class ThirdImpl(Simple, SecondMeta):
- pass
- """)
- classes = {
- 'ABCMeta': ('FirstImpl', 'SecondImpl'),
- 'type': ('ThirdImpl', )
- }
- for metaclass, names in classes.items():
- for name in names:
- impl = astroid[name]
- meta = impl.metaclass()
- self.assertIsInstance(meta, nodes.ClassDef)
- self.assertEqual(meta.name, metaclass)
-
- def test_metaclass_type(self):
- klass = builder.extract_node("""
- def with_metaclass(meta, base=object):
- return meta("NewBase", (base, ), {})
-
- class ClassWithMeta(with_metaclass(type)): #@
- pass
- """)
- self.assertEqual(
- ['NewBase', 'object'],
- [base.name for base in klass.ancestors()])
-
- def test_no_infinite_metaclass_loop(self):
- klass = builder.extract_node("""
- class SSS(object):
-
- class JJJ(object):
- pass
-
- @classmethod
- def Init(cls):
- cls.JJJ = type('JJJ', (cls.JJJ,), {})
-
- class AAA(SSS):
- pass
-
- class BBB(AAA.JJJ):
- pass
- """)
- self.assertFalse(scoped_nodes._is_metaclass(klass))
- ancestors = [base.name for base in klass.ancestors()]
- self.assertIn('object', ancestors)
- self.assertIn('JJJ', ancestors)
-
- def test_no_infinite_metaclass_loop_with_redefine(self):
- ast_nodes = builder.extract_node("""
- import datetime
-
- class A(datetime.date): #@
- @classmethod
- def now(cls):
- return cls()
-
- class B(datetime.date): #@
- pass
-
- datetime.date = A
- datetime.date = B
- """)
- for klass in ast_nodes:
- self.assertEqual(None, klass.metaclass())
-
- def test_metaclass_generator_hack(self):
- klass = builder.extract_node("""
- import six
-
- class WithMeta(six.with_metaclass(type, object)): #@
- pass
- """)
- self.assertEqual(
- ['object'],
- [base.name for base in klass.ancestors()])
- self.assertEqual(
- 'type', klass.metaclass().name)
-
- def test_using_six_add_metaclass(self):
- klass = builder.extract_node('''
- import six
- import abc
-
- @six.add_metaclass(abc.ABCMeta)
- class WithMeta(object):
- pass
- ''')
- inferred = next(klass.infer())
- metaclass = inferred.metaclass()
- self.assertIsInstance(metaclass, scoped_nodes.ClassDef)
- self.assertEqual(metaclass.qname(), 'abc.ABCMeta')
-
- def test_using_invalid_six_add_metaclass_call(self):
- klass = builder.extract_node('''
- import six
- @six.add_metaclass()
- class Invalid(object):
- pass
- ''')
- inferred = next(klass.infer())
- self.assertIsNone(inferred.metaclass())
-
- def test_nonregr_infer_callresult(self):
- astroid = builder.parse("""
- class Delegate(object):
- def __get__(self, obj, cls):
- return getattr(obj._subject, self.attribute)
-
- class CompositeBuilder(object):
- __call__ = Delegate()
-
- builder = CompositeBuilder(result, composite)
- tgts = builder()
- """)
- instance = astroid['tgts']
- # used to raise "'_Yes' object is not iterable", see
- # https://bitbucket.org/logilab/astroid/issue/17
- self.assertEqual(list(instance.infer()), [util.Uninferable])
-
- def test_slots(self):
- astroid = builder.parse("""
- from collections import deque
- from textwrap import dedent
-
- class First(object): #@
- __slots__ = ("a", "b", 1)
- class Second(object): #@
- __slots__ = "a"
- class Third(object): #@
- __slots__ = deque(["a", "b", "c"])
- class Fourth(object): #@
- __slots__ = {"a": "a", "b": "b"}
- class Fifth(object): #@
- __slots__ = list
- class Sixth(object): #@
- __slots__ = ""
- class Seventh(object): #@
- __slots__ = dedent.__name__
- class Eight(object): #@
- __slots__ = ("parens")
- class Ninth(object): #@
- pass
- class Ten(object): #@
- __slots__ = dict({"a": "b", "c": "d"})
- """)
- expected = [
- ('First', ('a', 'b')),
- ('Second', ('a', )),
- ('Third', None),
- ('Fourth', ('a', 'b')),
- ('Fifth', None),
- ('Sixth', None),
- ('Seventh', ('dedent', )),
- ('Eight', ('parens', )),
- ('Ninth', None),
- ('Ten', ('a', 'c')),
- ]
- for cls, expected_value in expected:
- slots = astroid[cls].slots()
- if expected_value is None:
- self.assertIsNone(slots)
- else:
- self.assertEqual(list(expected_value),
- [node.value for node in slots])
-
- @test_utils.require_version(maxver='3.0')
- def test_slots_py2(self):
- module = builder.parse("""
- class UnicodeSlots(object):
- __slots__ = (u"a", u"b", "c")
- """)
- slots = module['UnicodeSlots'].slots()
- self.assertEqual(len(slots), 3)
- self.assertEqual(slots[0].value, "a")
- self.assertEqual(slots[1].value, "b")
- self.assertEqual(slots[2].value, "c")
-
- @test_utils.require_version(maxver='3.0')
- def test_slots_py2_not_implemented(self):
- module = builder.parse("""
- class OldStyle:
- __slots__ = ("a", "b")
- """)
- msg = "The concept of slots is undefined for old-style classes."
- with self.assertRaises(NotImplementedError) as cm:
- module['OldStyle'].slots()
- self.assertEqual(str(cm.exception), msg)
-
- def test_slots_for_dict_keys(self):
- module = builder.parse('''
- class Issue(object):
- SlotDefaults = {'id': 0, 'id1':1}
- __slots__ = SlotDefaults.keys()
- ''')
- cls = module['Issue']
- slots = cls.slots()
- self.assertEqual(len(slots), 2)
- self.assertEqual(slots[0].value, 'id')
- self.assertEqual(slots[1].value, 'id1')
-
- def test_slots_empty_list_of_slots(self):
- module = builder.parse("""
- class Klass(object):
- __slots__ = ()
- """)
- cls = module['Klass']
- self.assertEqual(cls.slots(), [])
-
- def test_slots_taken_from_parents(self):
- module = builder.parse('''
- class FirstParent(object):
- __slots__ = ('a', 'b', 'c')
- class SecondParent(FirstParent):
- __slots__ = ('d', 'e')
- class Third(SecondParent):
- __slots__ = ('d', )
- ''')
- cls = module['Third']
- slots = cls.slots()
- self.assertEqual(sorted(set(slot.value for slot in slots)),
- ['a', 'b', 'c', 'd', 'e'])
-
- def test_all_ancestors_need_slots(self):
- module = builder.parse('''
- class A(object):
- __slots__ = ('a', )
- class B(A): pass
- class C(B):
- __slots__ = ('a', )
- ''')
- cls = module['C']
- self.assertIsNone(cls.slots())
- cls = module['B']
- self.assertIsNone(cls.slots())
-
- def assertEqualMro(self, klass, expected_mro):
- self.assertEqual(
- [member.name for member in klass.mro()],
- expected_mro)
-
- @test_utils.require_version(maxver='3.0')
- def test_no_mro_for_old_style(self):
- node = builder.extract_node("""
- class Old: pass""")
- with self.assertRaises(NotImplementedError) as cm:
- node.mro()
- self.assertEqual(str(cm.exception), "Could not obtain mro for "
- "old-style classes.")
-
- @test_utils.require_version(maxver='3.0')
- def test_mro_for_classes_with_old_style_in_mro(self):
- node = builder.extract_node('''
- class Factory:
- pass
- class ClientFactory(Factory):
- pass
- class ReconnectingClientFactory(ClientFactory):
- pass
- class WebSocketAdapterFactory(object):
- pass
- class WebSocketClientFactory(WebSocketAdapterFactory, ClientFactory):
- pass
- class WampWebSocketClientFactory(WebSocketClientFactory):
- pass
- class RetryFactory(WampWebSocketClientFactory, ReconnectingClientFactory):
- pas
- ''')
- self.assertEqualMro(
- node,
- ['RetryFactory', 'WampWebSocketClientFactory',
- 'WebSocketClientFactory', 'WebSocketAdapterFactory', 'object',
- 'ReconnectingClientFactory', 'ClientFactory',
- 'Factory']
- )
-
- @test_utils.require_version(maxver='3.0')
- def test_combined_newstyle_oldstyle_in_mro(self):
- node = builder.extract_node('''
- class Old:
- pass
- class New(object):
- pass
- class New1(object):
- pass
- class New2(New, New1):
- pass
- class NewOld(New2, Old): #@
- pass
- ''')
- self.assertEqualMro(node, ['NewOld', 'New2', 'New', 'New1', 'object', 'Old'])
- self.assertTrue(node.newstyle)
-
- def test_with_metaclass_mro(self):
- astroid = builder.parse("""
- import six
-
- class C(object):
- pass
- class B(C):
- pass
- class A(six.with_metaclass(type, B)):
- pass
- """)
- self.assertEqualMro(astroid['A'], ['A', 'B', 'C', 'object'])
-
- def test_mro(self):
- astroid = builder.parse("""
- class C(object): pass
- class D(dict, C): pass
-
- class A1(object): pass
- class B1(A1): pass
- class C1(A1): pass
- class D1(B1, C1): pass
- class E1(C1, B1): pass
- class F1(D1, E1): pass
- class G1(E1, D1): pass
-
- class Boat(object): pass
- class DayBoat(Boat): pass
- class WheelBoat(Boat): pass
- class EngineLess(DayBoat): pass
- class SmallMultihull(DayBoat): pass
- class PedalWheelBoat(EngineLess, WheelBoat): pass
- class SmallCatamaran(SmallMultihull): pass
- class Pedalo(PedalWheelBoat, SmallCatamaran): pass
-
- class OuterA(object):
- class Inner(object):
- pass
- class OuterB(OuterA):
- class Inner(OuterA.Inner):
- pass
- class OuterC(OuterA):
- class Inner(OuterA.Inner):
- pass
- class OuterD(OuterC):
- class Inner(OuterC.Inner, OuterB.Inner):
- pass
- class Duplicates(str, str): pass
-
- """)
- self.assertEqualMro(astroid['D'], ['D', 'dict', 'C', 'object'])
- self.assertEqualMro(astroid['D1'], ['D1', 'B1', 'C1', 'A1', 'object'])
- self.assertEqualMro(astroid['E1'], ['E1', 'C1', 'B1', 'A1', 'object'])
- with self.assertRaises(InconsistentMroError) as cm:
- astroid['F1'].mro()
- A1 = astroid.getattr('A1')[0]
- B1 = astroid.getattr('B1')[0]
- C1 = astroid.getattr('C1')[0]
- object_ = builder.MANAGER.astroid_cache[BUILTINS].getattr('object')[0]
- self.assertEqual(cm.exception.mros, [[B1, C1, A1, object_],
- [C1, B1, A1, object_]])
- with self.assertRaises(InconsistentMroError) as cm:
- astroid['G1'].mro()
- self.assertEqual(cm.exception.mros, [[C1, B1, A1, object_],
- [B1, C1, A1, object_]])
- self.assertEqualMro(
- astroid['PedalWheelBoat'],
- ["PedalWheelBoat", "EngineLess",
- "DayBoat", "WheelBoat", "Boat", "object"])
-
- self.assertEqualMro(
- astroid["SmallCatamaran"],
- ["SmallCatamaran", "SmallMultihull", "DayBoat", "Boat", "object"])
-
- self.assertEqualMro(
- astroid["Pedalo"],
- ["Pedalo", "PedalWheelBoat", "EngineLess", "SmallCatamaran",
- "SmallMultihull", "DayBoat", "WheelBoat", "Boat", "object"])
-
- self.assertEqualMro(
- astroid['OuterD']['Inner'],
- ['Inner', 'Inner', 'Inner', 'Inner', 'object'])
-
- with self.assertRaises(DuplicateBasesError) as cm:
- astroid['Duplicates'].mro()
- Duplicates = astroid.getattr('Duplicates')[0]
- self.assertEqual(cm.exception.cls, Duplicates)
- self.assertIsInstance(cm.exception, MroError)
- self.assertIsInstance(cm.exception, ResolveError)
-
- def test_mro_with_factories(self):
- cls = builder.extract_node('''
- def MixinFactory(cls):
- mixin_name = '{}Mixin'.format(cls.__name__)
- mixin_bases = (object,)
- mixin_attrs = {}
- mixin = type(mixin_name, mixin_bases, mixin_attrs)
- return mixin
- class MixinA(MixinFactory(int)):
- pass
- class MixinB(MixinFactory(str)):
- pass
- class Base(object):
- pass
- class ClassA(MixinA, Base):
- pass
- class ClassB(MixinB, ClassA):
- pass
- class FinalClass(ClassB):
- def __init__(self):
- self.name = 'x'
- ''')
- self.assertEqualMro(
- cls,
- [
- "FinalClass", "ClassB", "MixinB", "", "ClassA", "MixinA", "", "Base", "object"
- ]
- )
-
- def test_generator_from_infer_call_result_parent(self):
- func = builder.extract_node("""
- import contextlib
-
- @contextlib.contextmanager
- def test(): #@
- yield
- """)
- result = next(func.infer_call_result(func))
- self.assertIsInstance(result, Generator)
- self.assertEqual(result.parent, func)
-
- def test_type_three_arguments(self):
- classes = builder.extract_node("""
- type('A', (object, ), {"a": 1, "b": 2, missing: 3}) #@
- """)
- first = next(classes.infer())
- self.assertIsInstance(first, nodes.ClassDef)
- self.assertEqual(first.name, "A")
- self.assertEqual(first.basenames, ["object"])
- self.assertIsInstance(first["a"], nodes.Const)
- self.assertEqual(first["a"].value, 1)
- self.assertIsInstance(first["b"], nodes.Const)
- self.assertEqual(first["b"].value, 2)
- with self.assertRaises(AttributeInferenceError):
- first.getattr("missing")
-
- def test_implicit_metaclass(self):
- cls = builder.extract_node("""
- class A(object):
- pass
- """)
- type_cls = scoped_nodes.builtin_lookup("type")[1][0]
- self.assertEqual(cls.implicit_metaclass(), type_cls)
-
- def test_implicit_metaclass_lookup(self):
- cls = builder.extract_node('''
- class A(object):
- pass
- ''')
- instance = cls.instantiate_class()
- func = cls.getattr('mro')
- self.assertEqual(len(func), 1)
- self.assertRaises(AttributeInferenceError, instance.getattr, 'mro')
-
- def test_metaclass_lookup_using_same_class(self):
- # Check that we don't have recursive attribute access for metaclass
- cls = builder.extract_node('''
- class A(object): pass
- ''')
- self.assertEqual(len(cls.getattr('mro')), 1)
-
- def test_metaclass_lookup_inferrence_errors(self):
- module = builder.parse('''
- import six
-
- class Metaclass(type):
- foo = lala
-
- @six.add_metaclass(Metaclass)
- class B(object): pass
- ''')
- cls = module['B']
- self.assertEqual(util.Uninferable, next(cls.igetattr('foo')))
-
- def test_metaclass_lookup(self):
- module = builder.parse('''
- import six
-
- class Metaclass(type):
- foo = 42
- @classmethod
- def class_method(cls):
- pass
- def normal_method(cls):
- pass
- @property
- def meta_property(cls):
- return 42
- @staticmethod
- def static():
- pass
-
- @six.add_metaclass(Metaclass)
- class A(object):
- pass
- ''')
- acls = module['A']
- normal_attr = next(acls.igetattr('foo'))
- self.assertIsInstance(normal_attr, nodes.Const)
- self.assertEqual(normal_attr.value, 42)
-
- class_method = next(acls.igetattr('class_method'))
- self.assertIsInstance(class_method, BoundMethod)
- self.assertEqual(class_method.bound, module['Metaclass'])
-
- normal_method = next(acls.igetattr('normal_method'))
- self.assertIsInstance(normal_method, BoundMethod)
- self.assertEqual(normal_method.bound, module['A'])
-
- # Attribute access for properties:
- # from the metaclass is a property object
- # from the class that uses the metaclass, the value
- # of the property
- property_meta = next(module['Metaclass'].igetattr('meta_property'))
- self.assertIsInstance(property_meta, UnboundMethod)
- wrapping = scoped_nodes.get_wrapping_class(property_meta)
- self.assertEqual(wrapping, module['Metaclass'])
-
- property_class = next(acls.igetattr('meta_property'))
- self.assertIsInstance(property_class, nodes.Const)
- self.assertEqual(property_class.value, 42)
-
- static = next(acls.igetattr('static'))
- self.assertIsInstance(static, scoped_nodes.FunctionDef)
-
- @test_utils.require_version(maxver='3.0')
- def test_implicit_metaclass_is_none(self):
- cls = builder.extract_node("""
- class A: pass
- """)
- self.assertIsNone(cls.implicit_metaclass())
-
- def test_local_attr_invalid_mro(self):
- cls = builder.extract_node("""
- # A has an invalid MRO, local_attr should fallback
- # to using .ancestors.
- class A(object, object):
- test = 42
- class B(A): #@
- pass
- """)
- local = cls.local_attr('test')[0]
- inferred = next(local.infer())
- self.assertIsInstance(inferred, nodes.Const)
- self.assertEqual(inferred.value, 42)
-
- def test_has_dynamic_getattr(self):
- module = builder.parse("""
- class Getattr(object):
- def __getattr__(self, attrname):
- pass
-
- class Getattribute(object):
- def __getattribute__(self, attrname):
- pass
-
- class ParentGetattr(Getattr):
- pass
- """)
- self.assertTrue(module['Getattr'].has_dynamic_getattr())
- self.assertTrue(module['Getattribute'].has_dynamic_getattr())
- self.assertTrue(module['ParentGetattr'].has_dynamic_getattr())
-
- # Test that objects analyzed through the live introspection
- # aren't considered to have dynamic getattr implemented.
- import datetime
- astroid_builder = builder.AstroidBuilder()
- module = astroid_builder.module_build(datetime)
- self.assertFalse(module['timedelta'].has_dynamic_getattr())
-
- def test_duplicate_bases_namedtuple(self):
- module = builder.parse("""
- import collections
- _A = collections.namedtuple('A', 'a')
-
- class A(_A): pass
-
- class B(A): pass
- """)
- names = ['B', 'A', 'A', 'tuple', 'object']
- mro = module['B'].mro()
- class_names = [i.name for i in mro]
- self.assertEqual(names, class_names)
-
- def test_instance_bound_method_lambdas(self):
- ast_nodes = builder.extract_node('''
- class Test(object): #@
- lam = lambda self: self
- not_method = lambda xargs: xargs
- Test() #@
- ''')
- cls = next(ast_nodes[0].infer())
- self.assertIsInstance(next(cls.igetattr('lam')), scoped_nodes.Lambda)
- self.assertIsInstance(next(cls.igetattr('not_method')), scoped_nodes.Lambda)
-
- instance = next(ast_nodes[1].infer())
- lam = next(instance.igetattr('lam'))
- self.assertIsInstance(lam, BoundMethod)
- not_method = next(instance.igetattr('not_method'))
- self.assertIsInstance(not_method, scoped_nodes.Lambda)
-
- def test_class_extra_decorators_frame_is_not_class(self):
- ast_node = builder.extract_node('''
- def ala():
- def bala(): #@
- func = 42
- ''')
- self.assertEqual(ast_node.extra_decorators, [])
-
- def test_class_extra_decorators_only_callfunc_are_considered(self):
- ast_node = builder.extract_node('''
- class Ala(object):
- def func(self): #@
- pass
- func = 42
- ''')
- self.assertEqual(ast_node.extra_decorators, [])
-
- def test_class_extra_decorators_only_assignment_names_are_considered(self):
- ast_node = builder.extract_node('''
- class Ala(object):
- def func(self): #@
- pass
- def __init__(self):
- self.func = staticmethod(func)
-
- ''')
- self.assertEqual(ast_node.extra_decorators, [])
-
- def test_class_extra_decorators_only_same_name_considered(self):
- ast_node = builder.extract_node('''
- class Ala(object):
- def func(self): #@
- pass
- bala = staticmethod(func)
- ''')
- self.assertEqual(ast_node.extra_decorators, [])
- self.assertEqual(ast_node.type, 'method')
-
- def test_class_extra_decorators(self):
- static_method, clsmethod = builder.extract_node('''
- class Ala(object):
- def static(self): #@
- pass
- def class_method(self): #@
- pass
- class_method = classmethod(class_method)
- static = staticmethod(static)
- ''')
- self.assertEqual(len(clsmethod.extra_decorators), 1)
- self.assertEqual(clsmethod.type, 'classmethod')
- self.assertEqual(len(static_method.extra_decorators), 1)
- self.assertEqual(static_method.type, 'staticmethod')
-
- def test_extra_decorators_only_class_level_assignments(self):
- node = builder.extract_node('''
- def _bind(arg):
- return arg.bind
-
- class A(object):
- @property
- def bind(self):
- return 42
- def irelevant(self):
- # This is important, because it used to trigger
- # a maximum recursion error.
- bind = _bind(self)
- return bind
- A() #@
- ''')
- inferred = next(node.infer())
- bind = next(inferred.igetattr('bind'))
- self.assertIsInstance(bind, nodes.Const)
- self.assertEqual(bind.value, 42)
- parent = bind.scope()
- self.assertEqual(len(parent.extra_decorators), 0)
-
- @test_utils.require_version(minver='3.0')
- def test_class_keywords(self):
- data = '''
- class TestKlass(object, metaclass=TestMetaKlass,
- foo=42, bar='baz'):
- pass
- '''
- astroid = builder.parse(data, __name__)
- cls = astroid['TestKlass']
- self.assertEqual(len(cls.keywords), 2)
- self.assertEqual([x.arg for x in cls.keywords], ['foo', 'bar'])
-
-
- if __name__ == '__main__':
- unittest.main()
|