| # Copyright (c) 2006-2007, 2009-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr> |
| # Copyright (c) 2013-2016 Claudiu Popa <pcmanticore@gmail.com> |
| # Copyright (c) 2014 Google, Inc. |
| # Copyright (c) 2015 Florian Bruhin <me@the-compiler.org> |
| # Copyright (c) 2015-2016 Cara Vinson <ceridwenv@gmail.com> |
| |
| # 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 nodes |
| """ |
| import os |
| import sys |
| import textwrap |
| import unittest |
| import warnings |
| |
| import six |
| |
| import astroid |
| from astroid import builder |
| from astroid import context as contextmod |
| from astroid import exceptions |
| from astroid.tree import node_classes |
| from astroid import nodes |
| from astroid import parse |
| from astroid import raw_building |
| from astroid.interpreter import runtimeabc |
| from astroid.interpreter import objects |
| from astroid.interpreter import util as inferenceutil |
| from astroid import util |
| from astroid import test_utils |
| from astroid import transforms |
| from astroid.tests import resources |
| from astroid.tree import treeabc |
| |
| |
| abuilder = builder.AstroidBuilder() |
| BUILTINS = six.moves.builtins.__name__ |
| |
| |
| class AsStringTest(resources.SysPathSetup, unittest.TestCase): |
| |
| def test_tuple_as_string(self): |
| def build(string): |
| return abuilder.string_build(string).body[0].value |
| |
| self.assertEqual(build('1,').as_string(), '(1, )') |
| self.assertEqual(build('1, 2, 3').as_string(), '(1, 2, 3)') |
| self.assertEqual(build('(1, )').as_string(), '(1, )') |
| self.assertEqual(build('1, 2, 3').as_string(), '(1, 2, 3)') |
| |
| @test_utils.require_version(minver='3.0') |
| def test_func_signature_issue_185(self): |
| code = textwrap.dedent(''' |
| def test(a, b, c=42, *, x=42, **kwargs): |
| print(a, b, c, args) |
| ''') |
| node = parse(code) |
| self.assertEqual(node.as_string().strip(), code.strip()) |
| |
| def test_as_string_for_list_containing_uninferable(self): |
| node = astroid.extract_node(''' |
| def foo(): |
| bar = [arg] * 1 |
| ''') |
| binop = node.body[0].value |
| inferred = next(binop.infer()) |
| self.assertEqual(inferred.as_string(), '[Uninferable]') |
| self.assertEqual(binop.as_string(), '([arg]) * (1)') |
| |
| def test_frozenset_as_string(self): |
| nodes = astroid.extract_node(''' |
| frozenset((1, 2, 3)) #@ |
| frozenset({1, 2, 3}) #@ |
| frozenset([1, 2, 3,]) #@ |
| |
| frozenset(None) #@ |
| frozenset(1) #@ |
| ''') |
| nodes = [next(node.infer()) for node in nodes] |
| |
| self.assertEqual(nodes[0].as_string(), 'frozenset((1, 2, 3))') |
| self.assertEqual(nodes[1].as_string(), 'frozenset({1, 2, 3})') |
| self.assertEqual(nodes[2].as_string(), 'frozenset([1, 2, 3])') |
| |
| self.assertNotEqual(nodes[3].as_string(), 'frozenset(None)') |
| self.assertNotEqual(nodes[4].as_string(), 'frozenset(1)') |
| |
| def test_varargs_kwargs_as_string(self): |
| ast = abuilder.string_build('raise_string(*args, **kwargs)').body[0] |
| self.assertEqual(ast.as_string(), 'raise_string(*args, **kwargs)') |
| |
| def test_module_as_string(self): |
| """check as_string on a whole module prepared to be returned identically |
| """ |
| module = resources.build_file('data/module.py', 'data.module') |
| with open(resources.find('data/module.py'), 'r') as fobj: |
| self.assertMultiLineEqual(module.as_string(), fobj.read()) |
| |
| maxDiff = None |
| def test_module2_as_string(self): |
| """check as_string on a whole module prepared to be returned identically |
| """ |
| module2 = resources.build_file('data/module2.py', 'data.module2') |
| with open(resources.find('data/module2.py'), 'r') as fobj: |
| self.assertMultiLineEqual(module2.as_string(), fobj.read()) |
| |
| def test_as_string(self): |
| """check as_string for python syntax >= 2.7""" |
| code = '''one_two = {1, 2} |
| b = {v: k for (k, v) in enumerate('string')} |
| cdd = {k for k in b}\n\n''' |
| ast = abuilder.string_build(code) |
| self.assertMultiLineEqual(ast.as_string(), code) |
| |
| @test_utils.require_version('3.0') |
| def test_3k_as_string(self): |
| """check as_string for python 3k syntax""" |
| code = '''print() |
| |
| def function(var): |
| nonlocal counter |
| try: |
| hello |
| except NameError as nexc: |
| (*hell, o) = b'hello' |
| raise AttributeError from nexc |
| \n''' |
| ast = abuilder.string_build(code) |
| self.assertEqual(ast.as_string(), code) |
| |
| @test_utils.require_version('3.0') |
| @unittest.expectedFailure |
| def test_3k_annotations_and_metaclass(self): |
| code_annotations = textwrap.dedent(''' |
| def function(var:int): |
| nonlocal counter |
| |
| class Language(metaclass=Natural): |
| """natural language""" |
| ''') |
| |
| ast = abuilder.string_build(code_annotations) |
| self.assertEqual(ast.as_string(), code_annotations) |
| |
| def test_ellipsis(self): |
| ast = abuilder.string_build('a[...]').body[0] |
| self.assertEqual(ast.as_string(), 'a[...]') |
| |
| def test_slices(self): |
| for code in ('a[0]', 'a[1:3]', 'a[:-1:step]', 'a[:,newaxis]', |
| 'a[newaxis,:]', 'del L[::2]', 'del A[1]', 'del Br[:]'): |
| ast = abuilder.string_build(code).body[0] |
| self.assertEqual(ast.as_string(), code) |
| |
| def test_slice_and_subscripts(self): |
| code = """a[:1] = bord[2:] |
| a[:1] = bord[2:] |
| del bree[3:d] |
| bord[2:] |
| del av[d::f], a[df:] |
| a[:1] = bord[2:] |
| del SRC[::1,newaxis,1:] |
| tous[vals] = 1010 |
| del thousand[key] |
| del a[::2], a[:-1:step] |
| del Fee.form[left:] |
| aout.vals = miles.of_stuff |
| del (ccok, (name.thing, foo.attrib.value)), Fee.form[left:] |
| if all[1] == bord[0:]: |
| pass\n\n""" |
| ast = abuilder.string_build(code) |
| self.assertEqual(ast.as_string(), code) |
| |
| |
| class _NodeTest(unittest.TestCase): |
| """test transformation of If Node""" |
| CODE = None |
| |
| @property |
| def astroid(self): |
| try: |
| return self.__class__.__dict__['CODE_Astroid'] |
| except KeyError: |
| astroid = builder.parse(self.CODE) |
| self.__class__.CODE_Astroid = astroid |
| return astroid |
| |
| |
| class IfNodeTest(_NodeTest): |
| """test transformation of If Node""" |
| CODE = """ |
| if 0: |
| print() |
| |
| if True: |
| print() |
| else: |
| pass |
| |
| if "": |
| print() |
| elif []: |
| raise |
| |
| if 1: |
| print() |
| elif True: |
| print() |
| elif func(): |
| pass |
| else: |
| raise |
| """ |
| |
| def test_if_elif_else_node(self): |
| """test transformation for If node""" |
| self.assertEqual(len(self.astroid.body), 4) |
| for stmt in self.astroid.body: |
| self.assertIsInstance(stmt, nodes.If) |
| self.assertFalse(self.astroid.body[0].orelse) # simple If |
| self.assertIsInstance(self.astroid.body[1].orelse[0], nodes.Pass) # If / else |
| self.assertIsInstance(self.astroid.body[2].orelse[0], nodes.If) # If / elif |
| self.assertIsInstance(self.astroid.body[3].orelse[0].orelse[0], nodes.If) |
| |
| def test_block_range(self): |
| # XXX ensure expected values |
| self.assertEqual(self.astroid.block_range(1), (0, 22)) |
| self.assertEqual(self.astroid.block_range(10), (0, 22)) # XXX (10, 22) ? |
| self.assertEqual(self.astroid.body[1].block_range(5), (5, 6)) |
| self.assertEqual(self.astroid.body[1].block_range(6), (6, 6)) |
| self.assertEqual(self.astroid.body[1].orelse[0].block_range(7), (7, 8)) |
| self.assertEqual(self.astroid.body[1].orelse[0].block_range(8), (8, 8)) |
| |
| |
| class TryExceptNodeTest(_NodeTest): |
| CODE = """ |
| try: |
| print ('pouet') |
| except IOError: |
| pass |
| except UnicodeError: |
| print() |
| else: |
| print() |
| """ |
| |
| def test_block_range(self): |
| # XXX ensure expected values |
| self.assertEqual(self.astroid.body[0].block_range(1), (1, 8)) |
| self.assertEqual(self.astroid.body[0].block_range(2), (2, 2)) |
| self.assertEqual(self.astroid.body[0].block_range(3), (3, 8)) |
| self.assertEqual(self.astroid.body[0].block_range(4), (4, 4)) |
| self.assertEqual(self.astroid.body[0].block_range(5), (5, 5)) |
| self.assertEqual(self.astroid.body[0].block_range(6), (6, 6)) |
| self.assertEqual(self.astroid.body[0].block_range(7), (7, 7)) |
| self.assertEqual(self.astroid.body[0].block_range(8), (8, 8)) |
| |
| |
| class TryFinallyNodeTest(_NodeTest): |
| CODE = """ |
| try: |
| print ('pouet') |
| finally: |
| print ('pouet') |
| """ |
| |
| def test_block_range(self): |
| # XXX ensure expected values |
| self.assertEqual(self.astroid.body[0].block_range(1), (1, 4)) |
| self.assertEqual(self.astroid.body[0].block_range(2), (2, 2)) |
| self.assertEqual(self.astroid.body[0].block_range(3), (3, 4)) |
| self.assertEqual(self.astroid.body[0].block_range(4), (4, 4)) |
| |
| |
| class TryExceptFinallyNodeTest(_NodeTest): |
| CODE = """ |
| try: |
| print('pouet') |
| except Exception: |
| print ('oops') |
| finally: |
| print ('pouet') |
| """ |
| |
| def test_block_range(self): |
| # XXX ensure expected values |
| self.assertEqual(self.astroid.body[0].block_range(1), (1, 6)) |
| self.assertEqual(self.astroid.body[0].block_range(2), (2, 2)) |
| self.assertEqual(self.astroid.body[0].block_range(3), (3, 4)) |
| self.assertEqual(self.astroid.body[0].block_range(4), (4, 4)) |
| self.assertEqual(self.astroid.body[0].block_range(5), (5, 5)) |
| self.assertEqual(self.astroid.body[0].block_range(6), (6, 6)) |
| |
| |
| @unittest.skipIf(six.PY3, "Python 2 specific test.") |
| class TryExcept2xNodeTest(_NodeTest): |
| CODE = """ |
| try: |
| hello |
| except AttributeError, (retval, desc): |
| pass |
| """ |
| |
| |
| def test_tuple_attribute(self): |
| handler = self.astroid.body[0].handlers[0] |
| self.assertIsInstance(handler.name, nodes.Tuple) |
| |
| |
| class ImportNodeTest(resources.SysPathSetup, unittest.TestCase): |
| def setUp(self): |
| super(ImportNodeTest, self).setUp() |
| self.module = resources.build_file('data/module.py', 'data.module') |
| self.module2 = resources.build_file('data/module2.py', 'data.module2') |
| |
| def test_do_import_module_works_for_all(self): |
| import_from, import_ = astroid.extract_node(''' |
| from collections import deque #@ |
| import collections #@ |
| ''') |
| inferred = inferenceutil.do_import_module(import_from, 'collections') |
| self.assertIsInstance(inferred, nodes.Module) |
| self.assertEqual(inferred.name, 'collections') |
| inferred = inferenceutil.do_import_module(import_, 'collections') |
| self.assertIsInstance(inferred, nodes.Module) |
| self.assertEqual(inferred.name, 'collections') |
| |
| def test_import_self_resolve(self): |
| myos = next(self.module2.igetattr('myos')) |
| self.assertTrue(isinstance(myos, nodes.Module), myos) |
| self.assertEqual(myos.name, 'os') |
| self.assertEqual(myos.qname(), 'os') |
| self.assertEqual(myos.pytype(), '%s.module' % BUILTINS) |
| |
| def test_from_self_resolve(self): |
| namenode = next(self.module.igetattr('NameNode')) |
| self.assertTrue(isinstance(namenode, nodes.ClassDef), namenode) |
| self.assertEqual(namenode.root().name, 'astroid.tree.node_classes') |
| self.assertEqual(namenode.qname(), 'astroid.tree.node_classes.Name') |
| self.assertEqual(namenode.pytype(), '%s.type' % BUILTINS) |
| abspath = next(self.module2.igetattr('abspath')) |
| self.assertTrue(isinstance(abspath, nodes.FunctionDef), abspath) |
| self.assertEqual(abspath.root().name, 'os.path') |
| self.assertEqual(abspath.qname(), 'os.path.abspath') |
| self.assertEqual(abspath.pytype(), '%s.function' % BUILTINS) |
| |
| def test_real_name(self): |
| from_ = self.module['NameNode'] |
| self.assertEqual(inferenceutil.real_name(from_, 'NameNode'), 'Name') |
| imp_ = self.module['os'] |
| self.assertEqual(inferenceutil.real_name(imp_, 'os'), 'os') |
| self.assertRaises(exceptions.AttributeInferenceError, |
| inferenceutil.real_name, imp_, 'os.path') |
| imp_ = self.module['NameNode'] |
| self.assertEqual(inferenceutil.real_name(imp_, 'NameNode'), 'Name') |
| self.assertRaises(exceptions.AttributeInferenceError, |
| inferenceutil.real_name, imp_, 'Name') |
| imp_ = self.module2['YO'] |
| self.assertEqual(inferenceutil.real_name(imp_, 'YO'), 'YO') |
| self.assertRaises(exceptions.AttributeInferenceError, |
| inferenceutil.real_name, imp_, 'data') |
| |
| def test_as_string(self): |
| ast = self.module['modutils'] |
| self.assertEqual(ast.as_string(), "from astroid import modutils") |
| ast = self.module['NameNode'] |
| self.assertEqual(ast.as_string(), "from astroid.tree.node_classes import Name as NameNode") |
| ast = self.module['os'] |
| self.assertEqual(ast.as_string(), "import os.path") |
| code = """from . import here |
| from .. import door |
| from .store import bread |
| from ..cave import wine\n\n""" |
| ast = abuilder.string_build(code) |
| self.assertMultiLineEqual(ast.as_string(), code) |
| |
| def test_bad_import_inference(self): |
| # Explication of bug |
| '''When we import PickleError from nonexistent, a call to the infer |
| method of this From node will be made by unpack_infer. |
| inference.infer_from will try to import this module, which will fail and |
| raise a InferenceException (by mixins.do_import_module). The infer_name |
| will catch this exception and yield and Uninferable instead. |
| ''' |
| |
| code = ''' |
| try: |
| from pickle import PickleError |
| except ImportError: |
| from nonexistent import PickleError |
| |
| try: |
| pass |
| except PickleError: |
| pass |
| ''' |
| astroid = builder.parse(code) |
| handler_type = astroid.body[1].handlers[0].type |
| |
| excs = list(inferenceutil.unpack_infer(handler_type)) |
| # The number of returned object can differ on Python 2 |
| # and Python 3. In one version, an additional item will |
| # be returned, from the _pickle module, which is not |
| # present in the other version. |
| self.assertIsInstance(excs[0], nodes.ClassDef) |
| self.assertEqual(excs[0].name, 'PickleError') |
| self.assertIs(excs[-1], util.Uninferable) |
| |
| def test_absolute_import(self): |
| astroid = resources.build_file('data/absimport.py') |
| ctx = contextmod.InferenceContext() |
| # will fail if absolute import failed |
| ctx.lookupname = 'message' |
| next(astroid['message'].infer(ctx)) |
| ctx.lookupname = 'email' |
| m = next(astroid['email'].infer(ctx)) |
| self.assertFalse(m.source_file.startswith(os.path.join('data', 'email.py'))) |
| |
| def test_more_absolute_import(self): |
| astroid = resources.build_file('data/module1abs/__init__.py', 'data.module1abs') |
| self.assertIn('sys', astroid.locals) |
| |
| |
| class CmpNodeTest(unittest.TestCase): |
| def test_as_string(self): |
| ast = abuilder.string_build("a == 2").body[0] |
| self.assertEqual(ast.as_string(), "a == 2") |
| |
| |
| class ConstNodeTest(unittest.TestCase): |
| |
| def _test(self, value): |
| node = raw_building.ast_from_object(value) |
| self.assertIsInstance(node._proxied, (nodes.ClassDef, nodes.AssignName)) |
| self.assertEqual(node._proxied.name, value.__class__.__name__) |
| self.assertIs(node.value, value) |
| self.assertTrue(node._proxied.parent) |
| self.assertEqual(node._proxied.root().name, value.__class__.__module__) |
| |
| def test_none(self): |
| self._test(None) |
| |
| def test_bool(self): |
| self._test(True) |
| |
| def test_int(self): |
| self._test(1) |
| |
| def test_float(self): |
| self._test(1.0) |
| |
| def test_complex(self): |
| self._test(1.0j) |
| |
| def test_str(self): |
| self._test('a') |
| |
| def test_unicode(self): |
| self._test(u'a') |
| |
| |
| class NameNodeTest(unittest.TestCase): |
| def test_assign_to_True(self): |
| """test that True and False assignements don't crash""" |
| code = """ |
| True = False |
| def hello(False): |
| pass |
| del True |
| """ |
| if sys.version_info >= (3, 0): |
| with self.assertRaises(exceptions.AstroidBuildingError): |
| builder.parse(code) |
| else: |
| ast = builder.parse(code) |
| assign_true = ast['True'] |
| self.assertIsInstance(assign_true, nodes.AssignName) |
| self.assertEqual(assign_true.name, "True") |
| del_true = ast.body[2].targets[0] |
| self.assertIsInstance(del_true, nodes.DelName) |
| self.assertEqual(del_true.name, "True") |
| |
| |
| class ArgumentsNodeTC(unittest.TestCase): |
| |
| @unittest.skipIf(sys.version_info[:2] == (3, 3), |
| "Line numbering is broken on Python 3.3.") |
| def test_linenumbering(self): |
| ast = builder.parse(''' |
| def func(a, |
| b): pass |
| x = lambda x: None |
| ''') |
| self.assertEqual(ast['func'].args.fromlineno, 2) |
| self.assertFalse(ast['func'].args.is_statement) |
| xlambda = next(ast['x'].infer()) |
| self.assertEqual(xlambda.args.fromlineno, 4) |
| self.assertEqual(xlambda.args.tolineno, 4) |
| self.assertFalse(xlambda.args.is_statement) |
| if sys.version_info < (3, 0): |
| self.assertEqual(ast['func'].args.tolineno, 3) |
| else: |
| self.skipTest('FIXME http://bugs.python.org/issue10445 ' |
| '(no line number on function args)') |
| |
| @test_utils.require_version(minver='3.0') |
| def test_kwoargs(self): |
| ast = builder.parse(''' |
| def func(*, x): |
| pass |
| ''') |
| args = ast['func'].args |
| self.assertTrue(args.is_argument('x')) |
| |
| |
| class UnboundMethodNodeTest(unittest.TestCase): |
| |
| def test_no_super_getattr(self): |
| # This is a test for issue |
| # https://bitbucket.org/logilab/astroid/issue/91, which tests |
| # that UnboundMethod doesn't call super when doing .getattr. |
| |
| ast = builder.parse(''' |
| class A(object): |
| def test(self): |
| pass |
| meth = A.test |
| ''') |
| node = next(ast['meth'].infer()) |
| with self.assertRaises(exceptions.AttributeInferenceError): |
| node.getattr('__missssing__') |
| name = node.getattr('__name__')[0] |
| self.assertIsInstance(name, nodes.Const) |
| self.assertEqual(name.value, 'test') |
| |
| |
| class BoundMethodNodeTest(unittest.TestCase): |
| |
| def test_is_property(self): |
| ast = builder.parse(''' |
| import abc |
| |
| def cached_property(): |
| # Not a real decorator, but we don't care |
| pass |
| def reify(): |
| # Same as cached_property |
| pass |
| def lazy_property(): |
| pass |
| def lazyproperty(): |
| pass |
| def lazy(): pass |
| class A(object): |
| @property |
| def builtin_property(self): |
| return 42 |
| @abc.abstractproperty |
| def abc_property(self): |
| return 42 |
| @cached_property |
| def cached_property(self): return 42 |
| @reify |
| def reified(self): return 42 |
| @lazy_property |
| def lazy_prop(self): return 42 |
| @lazyproperty |
| def lazyprop(self): return 42 |
| def not_prop(self): pass |
| @lazy |
| def decorated_with_lazy(self): return 42 |
| |
| cls = A() |
| builtin_property = cls.builtin_property |
| abc_property = cls.abc_property |
| cached_p = cls.cached_property |
| reified = cls.reified |
| not_prop = cls.not_prop |
| lazy_prop = cls.lazy_prop |
| lazyprop = cls.lazyprop |
| decorated_with_lazy = cls.decorated_with_lazy |
| ''') |
| for prop in ('builtin_property', 'abc_property', 'cached_p', 'reified', |
| 'lazy_prop', 'lazyprop', 'decorated_with_lazy'): |
| inferred = next(ast[prop].infer()) |
| self.assertIsInstance(inferred, nodes.Const, prop) |
| self.assertEqual(inferred.value, 42, prop) |
| |
| inferred = next(ast['not_prop'].infer()) |
| self.assertIsInstance(inferred, objects.BoundMethod) |
| |
| |
| @test_utils.require_version('3.5') |
| class Python35AsyncTest(unittest.TestCase): |
| |
| def test_async_await_keywords(self): |
| async_def, async_for, async_with, await_node = astroid.extract_node(''' |
| async def func(): #@ |
| async for i in range(10): #@ |
| f = __(await i) |
| async with test(): #@ |
| pass |
| ''') |
| self.assertIsInstance(async_def, nodes.AsyncFunctionDef) |
| self.assertIsInstance(async_for, nodes.AsyncFor) |
| self.assertIsInstance(async_with, nodes.AsyncWith) |
| self.assertIsInstance(await_node, nodes.Await) |
| self.assertIsInstance(await_node.value, nodes.Name) |
| |
| def _test_await_async_as_string(self, code): |
| ast_node = parse(code) |
| self.assertEqual(ast_node.as_string().strip(), code.strip()) |
| |
| def test_await_as_string(self): |
| code = textwrap.dedent(''' |
| async def function(): |
| await 42 |
| ''') |
| self._test_await_async_as_string(code) |
| |
| def test_asyncwith_as_string(self): |
| code = textwrap.dedent(''' |
| async def function(): |
| async with (42): |
| pass |
| ''') |
| self._test_await_async_as_string(code) |
| |
| def test_asyncfor_as_string(self): |
| code = textwrap.dedent(''' |
| async def function(): |
| async for i in range(10): |
| await 42 |
| ''') |
| self._test_await_async_as_string(code) |
| |
| |
| class BaseTypesTest(unittest.TestCase): |
| |
| def test_concrete_issubclass(self): |
| for node in nodes.ALL_NODE_CLASSES: |
| name = node.__name__ |
| base_type = getattr(treeabc, name) |
| self.assertTrue(issubclass(node, base_type), (node, base_type)) |
| |
| self.assertTrue(issubclass(objects.Instance, runtimeabc.Instance)) |
| self.assertTrue(issubclass(objects.Generator, runtimeabc.Generator)) |
| self.assertTrue(issubclass(objects.BoundMethod, runtimeabc.BoundMethod)) |
| self.assertTrue(issubclass(objects.UnboundMethod, runtimeabc.UnboundMethod)) |
| |
| |
| class ScopeTest(unittest.TestCase): |
| |
| def test_decorators(self): |
| ast_node = astroid.extract_node(''' |
| @test |
| def foo(): pass |
| ''') |
| decorators = ast_node.decorators |
| self.assertIsInstance(decorators.scope(), nodes.Module) |
| self.assertEqual(decorators.scope(), decorators.root()) |
| |
| def test_scoped_nodes(self): |
| module = parse(''' |
| def function(): |
| pass |
| genexp = (i for i in range(10)) |
| dictcomp = {i:i for i in range(10)} |
| setcomp = {i for i in range(10)} |
| listcomp = [i for i in range(10)] |
| lambd = lambda x: x |
| class classdef: pass |
| ''') |
| self.assertIsInstance(module.scope(), nodes.Module) |
| self.assertIsInstance(module['genexp'].parent.value.scope(), nodes.GeneratorExp) |
| self.assertIsInstance(module['dictcomp'].parent.value.scope(), nodes.DictComp) |
| self.assertIsInstance(module['setcomp'].parent.value.scope(), nodes.SetComp) |
| self.assertIsInstance(module['lambd'].parent.value.scope(), nodes.Lambda) |
| self.assertIsInstance(next(module['function'].infer()).scope(), nodes.FunctionDef) |
| self.assertIsInstance(next(module['classdef'].infer()).scope(), nodes.ClassDef) |
| |
| if six.PY3: |
| self.assertIsInstance(module['listcomp'].parent.value.scope(), nodes.ListComp) |
| else: |
| self.assertIsInstance(module['listcomp'].parent.value.scope(), nodes.Module) |
| |
| def test_scope_of_default_argument_value(self): |
| node = astroid.extract_node(''' |
| def test(a=__(b)): |
| pass |
| ''') |
| scope = node.scope() |
| self.assertIsInstance(scope, nodes.Module) |
| |
| @test_utils.require_version(minver='3.0') |
| def test_scope_of_default_keyword_argument_value(self): |
| node = astroid.extract_node(''' |
| def test(*, b=__(c)): |
| pass |
| ''') |
| scope = node.scope() |
| self.assertIsInstance(scope, nodes.Module) |
| |
| @test_utils.require_version(minver='3.0') |
| def test_scope_of_annotations(self): |
| ast_nodes = astroid.extract_node(''' |
| def test(a: __(b), *args:__(f), c:__(d)=4, **kwargs: _(l))->__(x): |
| pass |
| ''') |
| for node in ast_nodes: |
| scope = node.scope() |
| self.assertIsInstance(scope, nodes.Module) |
| |
| def test_scope_of_list_comprehension_target_composite_nodes(self): |
| ast_node = astroid.extract_node(''' |
| [i for data in __([DATA1, DATA2]) for i in data] |
| ''') |
| node = ast_node.elts[0] |
| scope = node.scope() |
| self.assertIsInstance(scope, nodes.Module) |
| |
| def test_scope_of_nested_list_comprehensions(self): |
| ast_node = astroid.extract_node(''' |
| [1 for data in DATA for x in __(data)] |
| ''') |
| scope = ast_node.scope() |
| if six.PY2: |
| self.assertIsInstance(scope, nodes.Module) |
| else: |
| self.assertIsInstance(scope, nodes.ListComp) |
| |
| def test_scope_of_list_comprehension_targets(self): |
| ast_node = astroid.extract_node(''' |
| [1 for data in DATA] |
| ''') |
| # target is `data` from the list comprehension |
| target = ast_node.generators[0].target |
| scope = target.scope() |
| if six.PY2: |
| self.assertIsInstance(scope, nodes.Module) |
| else: |
| self.assertIsInstance(scope, nodes.ListComp) |
| |
| def test_scope_of_list_comprehension_value(self): |
| ast_node = astroid.extract_node(''' |
| [__(i) for i in DATA] |
| ''') |
| scope = ast_node.scope() |
| if six.PY3: |
| self.assertIsInstance(scope, nodes.ListComp) |
| else: |
| self.assertIsInstance(scope, nodes.Module) |
| |
| def test_scope_of_dict_comprehension(self): |
| ast_nodes = astroid.extract_node(''' |
| {i: __(j) for (i, j) in DATA} |
| {i:j for (i, j) in __(DATA)} |
| ''') |
| elt_scope = ast_nodes[0].scope() |
| self.assertIsInstance(elt_scope, nodes.DictComp) |
| iter_scope = ast_nodes[1].scope() |
| self.assertIsInstance(iter_scope, nodes.Module) |
| |
| ast_node = astroid.extract_node(''' |
| {i:1 for i in DATA}''') |
| target = ast_node.generators[0].target |
| target_scope = target.scope() |
| self.assertIsInstance(target_scope, nodes.DictComp) |
| |
| def test_scope_elt_of_generator_exp(self): |
| ast_node = astroid.extract_node(''' |
| list(__(i) for i in range(10)) |
| ''') |
| scope = ast_node.scope() |
| self.assertIsInstance(scope, nodes.GeneratorExp) |
| |
| |
| class ContextTest(unittest.TestCase): |
| |
| def test_subscript_load(self): |
| node = astroid.extract_node('f[1]') |
| self.assertIs(node.ctx, astroid.Load) |
| |
| def test_subscript_del(self): |
| node = astroid.extract_node('del f[1]') |
| self.assertIs(node.targets[0].ctx, astroid.Del) |
| |
| def test_subscript_store(self): |
| node = astroid.extract_node('f[1] = 2') |
| subscript = node.targets[0] |
| self.assertIs(subscript.ctx, astroid.Store) |
| |
| def test_list_load(self): |
| node = astroid.extract_node('[]') |
| self.assertIs(node.ctx, astroid.Load) |
| |
| def test_list_del(self): |
| node = astroid.extract_node('del []') |
| self.assertIs(node.targets[0].ctx, astroid.Del) |
| |
| def test_list_store(self): |
| with self.assertRaises(exceptions.AstroidSyntaxError): |
| astroid.extract_node('[0] = 2') |
| |
| def test_tuple_load(self): |
| node = astroid.extract_node('(1, )') |
| self.assertIs(node.ctx, astroid.Load) |
| |
| def test_tuple_store(self): |
| with self.assertRaises(exceptions.AstroidSyntaxError): |
| astroid.extract_node('(1, ) = 3') |
| |
| @test_utils.require_version(minver='3.5') |
| def test_starred_load(self): |
| node = astroid.extract_node('a = *b') |
| starred = node.value |
| self.assertIs(starred.ctx, astroid.Load) |
| |
| @test_utils.require_version(minver='3.0') |
| def test_starred_store(self): |
| node = astroid.extract_node('a, *b = 1, 2') |
| starred = node.targets[0].elts[1] |
| self.assertIs(starred.ctx, astroid.Store) |
| |
| |
| class FunctionTest(unittest.TestCase): |
| |
| def test_function_not_on_top_of_lambda(self): |
| lambda_, function_ = astroid.extract_node(''' |
| lambda x: x #@ |
| def func(): pass #@ |
| ''') |
| self.assertNotIsInstance(lambda_, astroid.FunctionDef) |
| self.assertNotIsInstance(function_, astroid.Lambda) |
| |
| |
| class DictTest(unittest.TestCase): |
| |
| def test_keys_values_items(self): |
| node = astroid.extract_node(''' |
| {1: 2, 2:3} |
| ''') |
| self.assertEqual([key.value for key in node.keys], [1, 2]) |
| self.assertEqual([value.value for value in node.values], [2, 3]) |
| self.assertEqual([(key.value, value.value) for (key, value) in node.items], |
| [(1, 2), (2, 3)]) |
| |
| |
| class ParameterTest(unittest.TestCase): |
| |
| def _variadics_test_helper(self, vararg_lineno, vararg_col_offset, |
| kwarg_lineno, kwarg_col_offset): |
| node = astroid.extract_node(''' |
| def test(*args, **kwargs): pass |
| ''') |
| args = node.args |
| self.assertIsInstance(args.vararg, astroid.Parameter) |
| self.assertEqual(args.vararg.lineno, vararg_lineno) |
| self.assertEqual(args.vararg.col_offset, vararg_col_offset) |
| self.assertIsInstance(args.kwarg, astroid.Parameter) |
| self.assertEqual(args.kwarg.lineno, kwarg_lineno) |
| self.assertEqual(args.kwarg.col_offset, kwarg_col_offset) |
| |
| @unittest.skipUnless(sys.version_info[:2] < (3, 5), |
| "variadics support lineno & col_offset in 3.5+") |
| def test_no_lineno_for_variadics(self): |
| self._variadics_test_helper(vararg_lineno=None, vararg_col_offset=None, |
| kwarg_lineno=None, kwarg_col_offset=None) |
| |
| @unittest.skipUnless(sys.version_info[:2] >= (3, 5), |
| "variadics support lineno & col_offset in 3.5+") |
| def test_no_lineno_for_variadics(self): |
| self._variadics_test_helper(vararg_lineno=2, vararg_col_offset=10, |
| kwarg_lineno=2, kwarg_col_offset=18) |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |