diff options
-rw-r--r-- | astroid/bases.py | 3 | ||||
-rw-r--r-- | astroid/inference.py | 28 | ||||
-rw-r--r-- | astroid/node_classes.py | 3 | ||||
-rw-r--r-- | astroid/objects.py | 2 | ||||
-rw-r--r-- | astroid/rebuilder.py | 36 | ||||
-rw-r--r-- | astroid/scoped_nodes.py | 41 | ||||
-rw-r--r-- | astroid/tests/unittest_builder.py | 1 | ||||
-rw-r--r-- | astroid/tests/unittest_inference.py | 3 | ||||
-rw-r--r-- | astroid/tests/unittest_objects.py | 2 | ||||
-rw-r--r-- | astroid/tests/unittest_regrtest.py | 2 | ||||
-rw-r--r-- | astroid/tests/unittest_scoped_nodes.py | 2 | ||||
-rw-r--r-- | astroid/tests/unittest_transforms.py | 43 | ||||
-rw-r--r-- | tox.ini | 2 |
13 files changed, 90 insertions, 78 deletions
diff --git a/astroid/bases.py b/astroid/bases.py index 3c0e2f6..146d8e7 100644 --- a/astroid/bases.py +++ b/astroid/bases.py @@ -20,6 +20,7 @@ inference utils. """ from __future__ import print_function +import inspect import sys import warnings @@ -348,7 +349,6 @@ def path_wrapper(func): context = contextmod.InferenceContext() context.push(node) yielded = set() - print(node, context, _func, kwargs, file=sys.stderr) for res in _func(node, context, **kwargs): # unproxy only true instance, not const, tuple, dict... if res.__class__ is Instance: @@ -377,6 +377,7 @@ def raise_if_nothing_inferred(func): inferred = True yield node if not inferred: + # print('Not inferred:', func, args, kwargs, inspect.getframeinfo(inspect.currentframe().f_back), sep='\n') raise exceptions.InferenceError() return wrapper diff --git a/astroid/inference.py b/astroid/inference.py index 62894a2..afba7fb 100644 --- a/astroid/inference.py +++ b/astroid/inference.py @@ -18,6 +18,8 @@ """this module contains a set of functions to handle inference on astroid trees """ +from __future__ import print_function + import functools import itertools import operator @@ -92,8 +94,8 @@ nodes.AssignName.infer_lhs = infer_name # won't work with a path wrapper @bases.raise_if_nothing_inferred @bases.path_wrapper -def infer_callfunc(self, context=None): - """infer a CallFunc node by trying to guess what the function returns""" +def infer_call(self, context=None): + """infer a Call node by trying to guess what the function returns""" callcontext = context.clone() callcontext.callcontext = contextmod.CallContext(args=self.args, keywords=self.keywords, @@ -111,7 +113,7 @@ def infer_callfunc(self, context=None): except exceptions.InferenceError: ## XXX log error ? continue -nodes.Call._infer = infer_callfunc +nodes.Call._infer = infer_call @bases.path_wrapper @@ -135,8 +137,8 @@ nodes.Import.infer_name_module = infer_name_module @bases.path_wrapper -def infer_from(self, context=None, asname=True): - """infer a From nodes: return the imported module/object""" +def infer_import_from(self, context=None, asname=True): + """infer a ImportFrom node: return the imported module/object""" name = context.lookupname if name is None: raise exceptions.InferenceError() @@ -150,12 +152,12 @@ def infer_from(self, context=None, asname=True): return bases._infer_stmts(stmts, context) except exceptions.NotFoundError: raise exceptions.InferenceError(name) -nodes.ImportFrom._infer = infer_from +nodes.ImportFrom._infer = infer_import_from @bases.raise_if_nothing_inferred -def infer_getattr(self, context=None): - """infer a Getattr node by using getattr on the associated object""" +def infer_attribute(self, context=None): + """infer an Attribute node by using getattr on the associated object""" for owner in self.expr.infer(context): if owner is util.YES: yield owner @@ -170,8 +172,8 @@ def infer_getattr(self, context=None): except AttributeError: # XXX method / function context.boundnode = None -nodes.Attribute._infer = bases.path_wrapper(infer_getattr) -nodes.AssignAttr.infer_lhs = infer_getattr # # won't work with a path wrapper +nodes.Attribute._infer = bases.path_wrapper(infer_attribute) +nodes.AssignAttr.infer_lhs = infer_attribute # # won't work with a path wrapper @bases.path_wrapper @@ -600,7 +602,7 @@ nodes.Arguments._infer = infer_arguments @bases.path_wrapper -def infer_ass(self, context=None): +def infer_assign(self, context=None): """infer a AssName/AssAttr: need to inspect the RHS part of the assign node """ @@ -609,8 +611,8 @@ def infer_ass(self, context=None): return stmt.infer(context) stmts = list(self.assigned_stmts(context=context)) return bases._infer_stmts(stmts, context) -nodes.AssignName._infer = infer_ass -nodes.AssignAttr._infer = infer_ass +nodes.AssignName._infer = infer_assign +nodes.AssignAttr._infer = infer_assign # no infer method on DelName and DelAttr (expected InferenceError) diff --git a/astroid/node_classes.py b/astroid/node_classes.py index 42f5b7d..9e424f7 100644 --- a/astroid/node_classes.py +++ b/astroid/node_classes.py @@ -566,7 +566,8 @@ class Call(bases.NodeNG): starargs = None kwargs = None - def postinit(self, func=None, args=None, starargs=None, kwargs=None): + def postinit(self, func=None, args=None, keywords=None, + starargs=None, kwargs=None): self.func = func self.args = args self.keywords = keywords diff --git a/astroid/objects.py b/astroid/objects.py index 9ae21f3..a38c2ee 100644 --- a/astroid/objects.py +++ b/astroid/objects.py @@ -22,7 +22,7 @@ which are used only as inference results, so they can't be found in the original AST tree. For instance, inferring the following frozenset use, leads to an inferred FrozenSet: - CallFunc(func=Name('frozenset'), args=Tuple(...)) + Call(func=Name('frozenset'), args=Tuple(...)) """ diff --git a/astroid/rebuilder.py b/astroid/rebuilder.py index 95bbce8..d55eb76 100644 --- a/astroid/rebuilder.py +++ b/astroid/rebuilder.py @@ -90,17 +90,17 @@ def _get_doc(node): pass # ast built from scratch return node, None -def _visit_or_none(node, attr, visitor, parent, assign_ctx): +def _visit_or_none(node, attr, visitor, parent, assign_ctx, visit='visit'): """If the given node has an attribute, visits the attribute, and otherwise returns None. """ value = getattr(node, attr, None) - if value is None: - return None + if value: + return getattr(visitor, visit)(value, parent, assign_ctx) else: - return visitor.visit(value, parent, assign_ctx) + return None class TreeRebuilder(object): @@ -283,20 +283,19 @@ class TreeRebuilder(object): def visit_call(self, node, parent, assign_ctx=None): """visit a CallFunc node by returning a fresh instance of it""" newnode = nodes.Call(node.lineno, node.col_offset, parent) - if node.starargs: - starargs = self.visit(node.starargs, newnode, assign_ctx) - else: - starargs = None - if node.kwargs: - kwargs = self.visit(node.kwargs, newnode, assign_ctx) + if node.keywords: + keywords = [self.visit(child, newnode, assign_ctx) + for child in node.keywords] else: - kwargs = None + keywords = None newnode.postinit(self.visit(node.func, newnode, assign_ctx), [self.visit(child, newnode, assign_ctx) for child in node.args], - [self.visit(child, newnode, assign_ctx) - for child in node.keywords], - starargs, kwargs) + keywords, + _visit_or_none(node, 'starargs', self, newnode, + assign_ctx), + _visit_or_none(node, 'kwargs', self, newnode, + assign_ctx)) return newnode def visit_classdef(self, node, parent, assign_ctx=None, newstyle=None): @@ -406,7 +405,7 @@ class TreeRebuilder(object): newnode = nodes.ExceptHandler(node.lineno, node.col_offset, parent) # /!\ node.name can be a tuple newnode.postinit(_visit_or_none(node, 'type', self, newnode, assign_ctx), - _visit_or_none(node, 'name', self, newnode, "Assign"), + _visit_or_none(node, 'name', self, newnode, 'Assign'), [self.visit(child, newnode, None) for child in node.body]) return newnode @@ -743,7 +742,7 @@ class TreeRebuilder3(TreeRebuilder): """visit an ExceptHandler node by returning a fresh instance of it""" newnode = nodes.ExceptHandler(node.lineno, node.col_offset, parent) newnode.postinit(_visit_or_none(node, 'type', self, newnode, assign_ctx), - _visit_or_none(node, 'name', self, newnode, assign_ctx), + _visit_or_none(node, 'name', self, newnode, 'Assign', visit='visit_assignname'), [self.visit(child, newnode, assign_ctx) for child in node.body]) return newnode @@ -793,10 +792,7 @@ class TreeRebuilder3(TreeRebuilder): newnode = nodes.With(node.lineno, node.col_offset, parent) def visit_child(child): expr = self.visit(child.context_expr, newnode, assign_ctx) - if child.optional_vars: - var = self.visit(child.optional_vars, newnode, 'Assign') - else: - var = None + var = _visit_or_none(child, 'optional_vars', self, newnode, 'Assign') return expr, var newnode.postinit([visit_child(child) for child in node.items], [self.visit(child, newnode, None) diff --git a/astroid/scoped_nodes.py b/astroid/scoped_nodes.py index fbb8be0..7a312bb 100644 --- a/astroid/scoped_nodes.py +++ b/astroid/scoped_nodes.py @@ -21,6 +21,10 @@ This module contains the classes for "scoped" node, i.e. which are opening a new local scope in the language definition : Module, ClassDef, FunctionDef (and Lambda, GeneratorExp, DictComp and SetComp to some extent). """ + +from __future__ import print_function +import inspect + import functools import io import itertools @@ -193,6 +197,7 @@ class LocalsDictNodeNG(node_classes.LookupMixIn, bases.NodeNG): if the name is already defined, ignore it """ #assert not stmt in self.locals.get(name, ()), (self, stmt) + # print('Set local:', self, name, stmt, inspect.getframeinfo(inspect.currentframe().f_back), sep='\n') self.locals.setdefault(name, []).append(stmt) __setitem__ = set_local @@ -712,6 +717,9 @@ class FunctionDef(bases.Statement, Lambda): self.doc = doc self.instance_attrs = {} super(FunctionDef, self).__init__(lineno, col_offset, parent) + if parent: + frame = parent.frame() + frame.set_local(name, self) def postinit(self, args, body, decorators=None, returns=None): self.args = args @@ -721,23 +729,22 @@ class FunctionDef(bases.Statement, Lambda): @decorators_mod.cachedproperty def extra_decorators(self): - """Get the extra decorators that this function can have - + """Get the extra decorators that this function can haves Additional decorators are considered when they are used as assignments, as in `method = staticmethod(method)`. The property will return all the callables that are used for decoration. """ frame = self.parent.frame() - if not isinstance(frame, Class): + if not isinstance(frame, ClassDef): return [] decorators = [] for assign in frame.nodes_of_class(node_classes.Assign): - if (isinstance(assign.value, node_classes.CallFunc) + if (isinstance(assign.value, node_classes.Call) and isinstance(assign.value.func, node_classes.Name)): for assign_node in assign.targets: - if not isinstance(assign_node, node_classes.AssName): + if not isinstance(assign_node, node_classes.AssignName): # Support only `name = callable(name)` continue @@ -750,7 +757,7 @@ class FunctionDef(bases.Statement, Lambda): except KeyError: continue else: - if isinstance(meth, Function): + if isinstance(meth, FunctionDef): decorators.append(assign.value) return decorators @@ -768,9 +775,9 @@ class FunctionDef(bases.Statement, Lambda): frame = self.parent.frame() type_name = 'function' - if isinstance(frame, Class): + if isinstance(frame, ClassDef): if self.name == '__new__': - return'classmethod' + return 'classmethod' else: type_name = 'method' @@ -780,7 +787,7 @@ class FunctionDef(bases.Statement, Lambda): if node.name in builtin_descriptors: return node.name - if isinstance(node, node_classes.CallFunc): + if isinstance(node, node_classes.Call): # Handle the following case: # @some_decorator(arg1, arg2) # def func(...) @@ -794,16 +801,16 @@ class FunctionDef(bases.Statement, Lambda): return _type try: - for infered in node.infer(): + for inferred in node.infer(): # Check to see if this returns a static or a class method. - _type = _infer_decorator_callchain(infered) + _type = _infer_decorator_callchain(inferred) if _type is not None: return _type - if not isinstance(infered, Class): + if not isinstance(inferred, ClassDef): continue - for ancestor in infered.ancestors(): - if not isinstance(ancestor, Class): + for ancestor in inferred.ancestors(): + if not isinstance(ancestor, ClassDef): continue if ancestor.is_subtype_of('%s.classmethod' % BUILTINS): return 'classmethod' @@ -1039,7 +1046,7 @@ def get_wrapping_class(node): """ klass = node.frame() - while klass is not None and not isinstance(klass, Class): + while klass is not None and not isinstance(klass, ClassDef): if klass.parent is None: klass = None else: @@ -1394,8 +1401,8 @@ class ClassDef(bases.Statement, LocalsDictNodeNG, mixins.FilterStmtsMixin): if bases._is_property(attr): # TODO(cpopa): don't use a private API. - for infered in attr.infer_call_result(self, context): - yield infered + for inferred in attr.infer_call_result(self, context): + yield inferred continue if attr.type == 'classmethod': # If the method is a classmethod, then it will diff --git a/astroid/tests/unittest_builder.py b/astroid/tests/unittest_builder.py index 84bf50c..dd2e875 100644 --- a/astroid/tests/unittest_builder.py +++ b/astroid/tests/unittest_builder.py @@ -687,6 +687,7 @@ class FileBuildTest(unittest.TestCase): # class method method = klass2['class_method'] self.assertEqual([n.name for n in method.args.args], ['cls']) + # import pdb; pdb.set_trace() self.assertEqual(method.type, 'classmethod') # static method method = klass2['static_method'] diff --git a/astroid/tests/unittest_inference.py b/astroid/tests/unittest_inference.py index dd3cd91..6ce6c45 100644 --- a/astroid/tests/unittest_inference.py +++ b/astroid/tests/unittest_inference.py @@ -2138,6 +2138,7 @@ class InferenceTest(resources.SysPathSetup, unittest.TestCase): ('frozenset()', False), ('frozenset((1, 2))', True), ] + # import pdb; pdb.set_trace() for code, expected in pairs: node = test_utils.extract_node(code) inferred = next(node.infer()) @@ -2568,6 +2569,8 @@ class InferenceTest(resources.SysPathSetup, unittest.TestCase): f = A() f += B() #@ ''') + print('TEST HERE', ast_node) + import pdb; pdb.set_trace() inferred = next(ast_node.infer()) self.assertIsInstance(inferred, Instance) self.assertEqual(inferred.name, 'A') diff --git a/astroid/tests/unittest_objects.py b/astroid/tests/unittest_objects.py index b62f5d9..d44446b 100644 --- a/astroid/tests/unittest_objects.py +++ b/astroid/tests/unittest_objects.py @@ -17,7 +17,6 @@ # with astroid. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
-import sys
import unittest
@@ -280,7 +279,6 @@ class SuperTests(unittest.TestCase): super(Super_Type_Object, self).class_method #@
''')
# Super(type, type) is the same for both functions and classmethods.
- print('TEST HERE', file=sys.stderr)
first = next(ast_nodes[0].infer())
self.assertIsInstance(first, nodes.FunctionDef)
self.assertEqual(first.name, 'method')
diff --git a/astroid/tests/unittest_regrtest.py b/astroid/tests/unittest_regrtest.py index ba7e2bf..72f0928 100644 --- a/astroid/tests/unittest_regrtest.py +++ b/astroid/tests/unittest_regrtest.py @@ -160,7 +160,7 @@ multiply(1, 2, 3) self.assertEqual(next(default.infer()).value, True) @require_version('2.7') - def test_with_infer_assnames(self): + def test_with_infer_assignnames(self): builder = AstroidBuilder() data = """ with open('a.txt') as stream, open('b.txt'): diff --git a/astroid/tests/unittest_scoped_nodes.py b/astroid/tests/unittest_scoped_nodes.py index f7088d8..1a9c20b 100644 --- a/astroid/tests/unittest_scoped_nodes.py +++ b/astroid/tests/unittest_scoped_nodes.py @@ -90,7 +90,7 @@ class ModuleNodeTest(ModuleLoader, unittest.TestCase): self.assertIsInstance(red, nodes.FunctionDef) self.assertEqual(red.name, 'four_args') namenode = next(self.module.igetattr('NameNode')) - self.assertIsInstance(namenode, nodes.Class) + self.assertIsInstance(namenode, nodes.ClassDef) self.assertEqual(namenode.name, 'Name') # resolve packageredirection mod = resources.build_file('data/appl/myConnection.py', diff --git a/astroid/tests/unittest_transforms.py b/astroid/tests/unittest_transforms.py index 3bb0cc2..fe206a1 100644 --- a/astroid/tests/unittest_transforms.py +++ b/astroid/tests/unittest_transforms.py @@ -16,6 +16,9 @@ # You should have received a copy of the GNU Lesser General Public License along # with astroid. If not, see <http://www.gnu.org/licenses/>.
+from __future__ import print_function +import sys + import contextlib
import time
import unittest
@@ -45,20 +48,20 @@ class TestTransforms(unittest.TestCase): return self.transformer.visit(module)
def test_function_inlining_transform(self):
- def transform_callfunc(node):
+ def transform_call(node):
# Let's do some function inlining
inferred = next(node.infer())
return inferred
- self.transformer.register_transform(nodes.CallFunc,
- transform_callfunc)
+ self.transformer.register_transform(nodes.Call,
+ transform_call)
module = self.parse_transform('''
def test(): return 42
test() #@
''')
- self.assertIsInstance(module.body[1], nodes.Discard)
+ self.assertIsInstance(module.body[1], nodes.Expr)
self.assertIsInstance(module.body[1].value, nodes.Const)
self.assertEqual(module.body[1].value.value, 42)
@@ -85,20 +88,20 @@ class TestTransforms(unittest.TestCase): a < b
''')
- self.assertIsInstance(module.body[2], nodes.Discard)
+ self.assertIsInstance(module.body[2], nodes.Expr)
self.assertIsInstance(module.body[2].value, nodes.Const)
self.assertFalse(module.body[2].value.value)
def test_transform_patches_locals(self):
def transform_function(node):
assign = nodes.Assign()
- name = nodes.AssName()
+ name = nodes.AssignName()
name.name = 'value'
assign.targets = [name]
assign.value = nodes.const_factory(42)
node.body.append(assign)
- self.transformer.register_transform(nodes.Function,
+ self.transformer.register_transform(nodes.FunctionDef,
transform_function)
module = self.parse_transform('''
@@ -112,15 +115,15 @@ class TestTransforms(unittest.TestCase): self.assertEqual(func.body[1].as_string(), 'value = 42')
def test_predicates(self):
- def transform_callfunc(node):
+ def transform_call(node):
inferred = next(node.infer())
return inferred
def should_inline(node):
return node.func.name.startswith('inlineme')
- self.transformer.register_transform(nodes.CallFunc,
- transform_callfunc,
+ self.transformer.register_transform(nodes.Call,
+ transform_call,
should_inline)
module = self.parse_transform('''
@@ -135,12 +138,12 @@ class TestTransforms(unittest.TestCase): inlineme_2()
''')
values = module.body[-3:]
- self.assertIsInstance(values[0], nodes.Discard)
+ self.assertIsInstance(values[0], nodes.Expr)
self.assertIsInstance(values[0].value, nodes.Const)
self.assertEqual(values[0].value.value, 24)
- self.assertIsInstance(values[1], nodes.Discard)
- self.assertIsInstance(values[1].value, nodes.CallFunc)
- self.assertIsInstance(values[2], nodes.Discard)
+ self.assertIsInstance(values[1], nodes.Expr)
+ self.assertIsInstance(values[1].value, nodes.Call)
+ self.assertIsInstance(values[2], nodes.Expr)
self.assertIsInstance(values[2].value, nodes.Const)
self.assertEqual(values[2].value.value, 2)
@@ -158,7 +161,7 @@ class TestTransforms(unittest.TestCase): return next(node.infer_call_result(node))
manager = builder.MANAGER
- with add_transform(manager, nodes.Function, transform_function):
+ with add_transform(manager, nodes.FunctionDef, transform_function):
module = builder.parse('''
import abc
from abc import abstractmethod
@@ -184,21 +187,21 @@ class TestTransforms(unittest.TestCase): def test_transforms_are_called_for_builtin_modules(self):
# Test that transforms are called for builtin modules.
def transform_function(node):
- name = nodes.AssName()
+ name = nodes.AssignName()
name.name = 'value'
node.args.args = [name]
return node
manager = builder.MANAGER
predicate = lambda node: node.root().name == 'time'
- with add_transform(manager, nodes.Function,
+ with add_transform(manager, nodes.FunctionDef,
transform_function, predicate):
builder_instance = builder.AstroidBuilder()
module = builder_instance.module_build(time)
asctime = module['asctime']
self.assertEqual(len(asctime.args.args), 1)
- self.assertIsInstance(asctime.args.args[0], nodes.AssName)
+ self.assertIsInstance(asctime.args.args[0], nodes.AssignName)
self.assertEqual(asctime.args.args[0].name, 'value')
def test_builder_apply_transforms(self):
@@ -206,12 +209,12 @@ class TestTransforms(unittest.TestCase): return nodes.const_factory(42)
manager = builder.MANAGER
- with add_transform(manager, nodes.Function, transform_function):
+ with add_transform(manager, nodes.FunctionDef, transform_function):
astroid_builder = builder.AstroidBuilder(apply_transforms=False)
module = astroid_builder.string_build('''def test(): pass''')
# The transform wasn't applied.
- self.assertIsInstance(module.body[0], nodes.Function)
+ self.assertIsInstance(module.body[0], nodes.FunctionDef)
if __name__ == '__main__':
@@ -1,7 +1,7 @@ [tox] # official list is # envlist = py27, py33, py34, pypy, jython -envlist = py27, py34, pylint +envlist = py27, py34 # envlist = py27, py33 [testenv:pylint] |