summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudiu Popa <pcmanticore@gmail.com>2015-12-07 15:40:25 +0200
committerClaudiu Popa <pcmanticore@gmail.com>2015-12-07 15:40:25 +0200
commit403df92d1710267ae5b7fe215acd9357a8cbf251 (patch)
treecc7337fb8a9f088550531dc3bb1204e643982ffc
parent1fc333e90d0328f878c8a58084eb2cba536d0b4b (diff)
parent9e0620833d014a0c8d34b6bf8c908e01b3ac7e70 (diff)
downloadpylint-403df92d1710267ae5b7fe215acd9357a8cbf251.tar.gz
Merged in jakirkham/pylint/issue_538_pt2 (pull request #315)
Add another check of the current working directory for `.pylintrc`.
-rw-r--r--ChangeLog22
-rw-r--r--pylint/checkers/imports.py61
-rw-r--r--pylint/checkers/newstyle.py14
-rw-r--r--pylint/checkers/stdlib.py12
-rw-r--r--pylint/checkers/typecheck.py20
-rw-r--r--pylint/checkers/variables.py4
-rw-r--r--pylint/lint.py12
-rw-r--r--pylint/test/functional/super_checks.py2
-rw-r--r--pylint/test/functional/super_checks.txt27
-rw-r--r--pylint/test/functional/syntax_error.txt2
-rw-r--r--pylint/test/functional/unknown_encoding_py29.txt2
-rw-r--r--pylint/test/functional/wrong_import_position.py16
-rw-r--r--pylint/test/functional/wrong_import_position.txt6
-rw-r--r--pylint/test/regrtest_data/beyond_top/__init__.py6
-rw-r--r--pylint/test/regrtest_data/beyond_top/data.py1
-rw-r--r--pylint/test/unittest_checker_imports.py22
-rw-r--r--pylint/test/unittest_checker_stdlib.py65
17 files changed, 224 insertions, 70 deletions
diff --git a/ChangeLog b/ChangeLog
index 5e7b4b3..f8129cc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,24 @@ ChangeLog for Pylint
--------------------
--
+
+ * Added a new error, 'relative-beyond-top-level', which is emitted
+ when a relative import was attempted beyond the top level package.
+
+ Closes issue #588.
+
+ * Accept only functions and methods for the deprecated-method checker.
+
+ This prevents a crash which can occur when an object doesn't have
+ .qname() method after the inference.
+
+ * Don't emit super-on-old-class on classes with unknown bases.
+ Closes issue #721.
+
+ * Allow statements in `if` or `try` blocks containing imports.
+
+ Closes issue #714.
+
* Added a new warning, 'unsupported-assignment-operation', which is
emitted when item assignment is tried on an object which doesn't
have this ability. Closes issue #591.
@@ -10,6 +28,10 @@ ChangeLog for Pylint
emitted when item deletion is tried on an object which doesn't
have this ability. Closes issue #592.
+
+2015-12-02 -- 1.5.1
+
+
* Fix a crash which occurred when old visit methods are encountered
in plugin modules. Closes issue #711.
diff --git a/pylint/checkers/imports.py b/pylint/checkers/imports.py
index 0e16d18..2d37461 100644
--- a/pylint/checkers/imports.py
+++ b/pylint/checkers/imports.py
@@ -88,6 +88,14 @@ def _get_first_import(node, context, name, base, level):
if found and not are_exclusive(first, node):
return first
+
+def _ignore_import_failure(node, modname, ignored_modules):
+ for submodule in _qualified_names(modname):
+ if submodule in ignored_modules:
+ return True
+
+ return node_ignores_exception(node, ImportError)
+
# utilities to represents import dependencies as tree and dot graph ###########
def _make_tree_defs(mod_files_list):
@@ -161,6 +169,10 @@ MSGS = {
'import-error',
'Used when pylint has been unable to import a module.',
{'old_names': [('F0401', 'import-error')]}),
+ 'E0402': ('Attempted relative import beyond top-level package',
+ 'relative-beyond-top-level',
+ 'Used when a relative import tries to access too many levels '
+ 'in the current package.'),
'R0401': ('Cyclic import (%s)',
'cyclic-import',
'Used when a cyclic import between two or more modules is \
@@ -298,7 +310,7 @@ given file (report RP0402 must not be disabled)'}
for name in names:
self._check_deprecated_module(node, name)
- importedmodnode = self.get_imported_module(node, name)
+ importedmodnode = self._get_imported_module(node, name)
if isinstance(node.scope(), astroid.Module):
self._check_position(node)
self._record_import(node, importedmodnode)
@@ -320,7 +332,7 @@ given file (report RP0402 must not be disabled)'}
self._check_reimport(node, basename=basename, level=node.level)
modnode = node.root()
- importedmodnode = self.get_imported_module(node, basename)
+ importedmodnode = self._get_imported_module(node, basename)
if isinstance(node.scope(), astroid.Module):
self._check_position(node)
self._record_import(node, importedmodnode)
@@ -369,9 +381,24 @@ given file (report RP0402 must not be disabled)'}
= visit_ifexp = visit_comprehension = visit_if
def visit_functiondef(self, node):
- # if it is the first non import instruction of the module, record it
- if not self._first_non_import_node:
- self._first_non_import_node = node
+ # If it is the first non import instruction of the module, record it.
+ if self._first_non_import_node:
+ return
+
+ # Check if the node belongs to an `If` or a `Try` block. If they
+ # contain imports, skip recording this node.
+ if not isinstance(node.parent.scope(), astroid.Module):
+ return
+
+ root = node
+ while not isinstance(root.parent, astroid.Module):
+ root = root.parent
+
+ if isinstance(root, (astroid.If, astroid.TryFinally, astroid.TryExcept)):
+ if any(root.nodes_of_class((astroid.Import, astroid.ImportFrom))):
+ return
+
+ self._first_non_import_node = node
visit_classdef = visit_for = visit_while = visit_functiondef
@@ -458,22 +485,22 @@ given file (report RP0402 must not be disabled)'}
'"%s"' % local_imports[0][0].as_string()))
return std_imports, extern_imports, local_imports
- def get_imported_module(self, importnode, modname):
+ def _get_imported_module(self, importnode, modname):
try:
return importnode.do_import_module(modname)
- except astroid.InferenceError as ex:
- dotted_modname = _get_import_name(importnode, modname)
- if str(ex) != modname:
- args = '%r (%s)' % (dotted_modname, ex)
- else:
- args = repr(dotted_modname)
+ except astroid.TooManyLevelsError:
+ if _ignore_import_failure(importnode, modname, self._ignored_modules):
+ return None
+
+ self.add_message('relative-beyond-top-level', node=importnode)
- for submodule in _qualified_names(modname):
- if submodule in self._ignored_modules:
- return None
+ except astroid.AstroidBuildingException as exc:
+ if _ignore_import_failure(importnode, modname, self._ignored_modules):
+ return None
- if not node_ignores_exception(importnode, ImportError):
- self.add_message("import-error", args=args, node=importnode)
+ dotted_modname = _get_import_name(importnode, modname)
+ self.add_message('import-error', args=repr(dotted_modname),
+ node=importnode)
def _check_relative_import(self, modnode, importnode, importedmodnode,
importedasname):
diff --git a/pylint/checkers/newstyle.py b/pylint/checkers/newstyle.py
index 489c22f..5cc8f13 100644
--- a/pylint/checkers/newstyle.py
+++ b/pylint/checkers/newstyle.py
@@ -128,12 +128,10 @@ class NewStyleConflictChecker(BaseChecker):
isinstance(call.func, astroid.Name) and
call.func.name == 'super'):
continue
- confidence = (INFERENCE if has_known_bases(klass)
- else INFERENCE_FAILURE)
- if not klass.newstyle:
+
+ if not klass.newstyle and has_known_bases(klass):
# super should not be used on an old style class
- self.add_message('super-on-old-class', node=node,
- confidence=confidence)
+ self.add_message('super-on-old-class', node=node)
else:
# super first arg should be the class
if not call.args and sys.version_info[0] == 3:
@@ -147,8 +145,7 @@ class NewStyleConflictChecker(BaseChecker):
continue
if supcls is None:
- self.add_message('missing-super-argument', node=call,
- confidence=confidence)
+ self.add_message('missing-super-argument', node=call)
continue
if klass is not supcls:
@@ -162,8 +159,7 @@ class NewStyleConflictChecker(BaseChecker):
if hasattr(call.args[0], 'name'):
name = call.args[0].name
if name is not None:
- self.add_message('bad-super-call', node=call, args=(name, ),
- confidence=confidence)
+ self.add_message('bad-super-call', node=call, args=(name, ))
def register(linter):
diff --git a/pylint/checkers/stdlib.py b/pylint/checkers/stdlib.py
index afb4541..0ec3d6c 100644
--- a/pylint/checkers/stdlib.py
+++ b/pylint/checkers/stdlib.py
@@ -211,7 +211,7 @@ class StdlibChecker(BaseChecker):
for value in node.values:
self._check_datetime(value)
- def _check_deprecated_method(self, node, infer):
+ def _check_deprecated_method(self, node, inferred):
py_vers = sys.version_info[0]
if isinstance(node.func, astroid.Attribute):
@@ -222,7 +222,14 @@ class StdlibChecker(BaseChecker):
# Not interested in other nodes.
return
- qname = infer.qname()
+ # Reject nodes which aren't of interest to us.
+ acceptable_nodes = (astroid.BoundMethod,
+ astroid.UnboundMethod,
+ astroid.FunctionDef)
+ if not isinstance(inferred, acceptable_nodes):
+ return
+
+ qname = inferred.qname()
if qname in self.deprecated[0]:
self.add_message('deprecated-method', node=node,
args=(func_name, ))
@@ -233,7 +240,6 @@ class StdlibChecker(BaseChecker):
args=(func_name, ))
break
-
def _check_redundant_assert(self, node, infer):
if (isinstance(infer, astroid.BoundMethod) and
node.args and isinstance(node.args[0], astroid.Const) and
diff --git a/pylint/checkers/typecheck.py b/pylint/checkers/typecheck.py
index 46535d2..076f21a 100644
--- a/pylint/checkers/typecheck.py
+++ b/pylint/checkers/typecheck.py
@@ -317,7 +317,15 @@ accessed. Python regular expressions are accepted.'}
def open(self):
# do this in open since config not fully initialized in __init__
- self.generated_members = list(self.config.generated_members)
+ # generated_members may contain regular expressions
+ # (surrounded by quote `"` and followed by a comma `,`)
+ # REQUEST,aq_parent,"[a-zA-Z]+_set{1,2}"' =>
+ # ('REQUEST', 'aq_parent', '[a-zA-Z]+_set{1,2}')
+ if isinstance(self.config.generated_members, str):
+ gen = shlex.shlex(self.config.generated_members)
+ gen.whitespace += ','
+ gen.wordchars += '[]-+'
+ self.config.generated_members = tuple(tok.strip('"') for tok in gen)
def visit_assignattr(self, node):
if isinstance(node.assign_type(), astroid.AugAssign):
@@ -335,19 +343,11 @@ accessed. Python regular expressions are accepted.'}
function/method, super call and metaclasses are ignored
"""
- # generated_members may contain regular expressions
- # (surrounded by quote `"` and followed by a comma `,`)
- # REQUEST,aq_parent,"[a-zA-Z]+_set{1,2}"' =>
- # ('REQUEST', 'aq_parent', '[a-zA-Z]+_set{1,2}')
- if isinstance(self.config.generated_members, str):
- gen = shlex.shlex(self.config.generated_members)
- gen.whitespace += ','
- gen.wordchars += '[]-+'
- self.config.generated_members = tuple(tok.strip('"') for tok in gen)
for pattern in self.config.generated_members:
# attribute is marked as generated, stop here
if re.match(pattern, node.attrname):
return
+
try:
infered = list(node.expr.infer())
except exceptions.InferenceError:
diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py
index 7629a7b..b7a114d 100644
--- a/pylint/checkers/variables.py
+++ b/pylint/checkers/variables.py
@@ -44,7 +44,7 @@ def _is_from_future_import(stmt, name):
"""Check if the name is a future import from another module."""
try:
module = stmt.do_import_module(stmt.modname)
- except astroid.InferenceError:
+ except astroid.AstroidBuildingException:
return
for local_node in module.locals.get(name, []):
@@ -1014,7 +1014,7 @@ builtins. Remember that you should avoid to define new builtins when possible.'
name_parts = node.modname.split('.')
try:
module = node.do_import_module(name_parts[0])
- except Exception:
+ except astroid.AstroidBuildingException:
return
module = self._check_module_attrs(node, module, name_parts[1:])
if not module:
diff --git a/pylint/lint.py b/pylint/lint.py
index 7d08a76..03fcbb1 100644
--- a/pylint/lint.py
+++ b/pylint/lint.py
@@ -903,14 +903,12 @@ class PyLinter(config.OptionsManagerMixIn,
"""return a ast(roid) representation for a module"""
try:
return MANAGER.ast_from_file(filepath, modname, source=True)
+ except astroid.AstroidSyntaxError as ex:
+ self.add_message('syntax-error',
+ line=getattr(ex.error, 'lineno', 0),
+ args=str(ex.error))
except astroid.AstroidBuildingException as ex:
- if isinstance(ex.args[0], SyntaxError):
- ex = ex.args[0]
- self.add_message('syntax-error',
- line=ex.lineno or 0,
- args=ex.msg)
- else:
- self.add_message('parse-error', args=ex)
+ self.add_message('parse-error', args=ex)
except Exception as ex: # pylint: disable=broad-except
import traceback
traceback.print_exc()
diff --git a/pylint/test/functional/super_checks.py b/pylint/test/functional/super_checks.py
index 14fd5a2..f4aec0a 100644
--- a/pylint/test/functional/super_checks.py
+++ b/pylint/test/functional/super_checks.py
@@ -65,9 +65,9 @@ class SuperDifferentScope(object):
class UnknownBases(Missing):
"""Don't emit if we don't know all the bases."""
def __init__(self):
- # pylint: disable=super-on-old-class
super(UnknownBases, self).__init__()
super(UnknownBases, self).test()
+ super(Missing, self).test() # [bad-super-call]
# Test that we are detecting proper super errors.
diff --git a/pylint/test/functional/super_checks.txt b/pylint/test/functional/super_checks.txt
index a98a25b..ea1d67b 100644
--- a/pylint/test/functional/super_checks.txt
+++ b/pylint/test/functional/super_checks.txt
@@ -1,18 +1,19 @@
old-style-class:6:Aaaa:Old-style class defined.
-super-on-old-class:8:Aaaa.hop:Use of super on an old style class:INFERENCE
+super-on-old-class:8:Aaaa.hop:Use of super on an old style class
no-member:10:Aaaa.hop:Super of 'Aaaa' has no 'hop' member:INFERENCE
-super-on-old-class:12:Aaaa.__init__:Use of super on an old style class:INFERENCE
+super-on-old-class:12:Aaaa.__init__:Use of super on an old style class
no-member:19:NewAaaa.hop:Super of 'NewAaaa' has no 'hop' member:INFERENCE
-bad-super-call:22:NewAaaa.__init__:Bad first argument 'Aaaa' given to super():INFERENCE
-missing-super-argument:27:Py3kAaaa.__init__:Missing argument to super():INFERENCE
-bad-super-call:32:Py3kWrongSuper.__init__:Bad first argument 'NewAaaa' given to super():INFERENCE
-bad-super-call:37:WrongNameRegression.__init__:Bad first argument 'Missing' given to super():INFERENCE
-bad-super-call:46:CrashSuper.__init__:Bad first argument 'NewAaaa' given to super():INFERENCE
-bad-super-call:62:SuperDifferentScope.test:Bad first argument 'object' given to super():INFERENCE
-not-callable:89:InvalidSuperChecks.__init__:super(InvalidSuperChecks, self).not_a_method is not callable:HIGH
+bad-super-call:22:NewAaaa.__init__:Bad first argument 'Aaaa' given to super()
+missing-super-argument:27:Py3kAaaa.__init__:Missing argument to super()
+bad-super-call:32:Py3kWrongSuper.__init__:Bad first argument 'NewAaaa' given to super()
+bad-super-call:37:WrongNameRegression.__init__:Bad first argument 'Missing' given to super()
+bad-super-call:46:CrashSuper.__init__:Bad first argument 'NewAaaa' given to super()
+bad-super-call:62:SuperDifferentScope.test:Bad first argument 'object' given to super()
+bad-super-call:70:UnknownBases.__init__:Bad first argument 'Missing' given to super()
+not-callable:89:InvalidSuperChecks.__init__:super(InvalidSuperChecks, self).not_a_method is not callable
no-member:90:InvalidSuperChecks.__init__:Super of 'InvalidSuperChecks' has no 'attribute_error' member:INFERENCE
-no-value-for-parameter:92:InvalidSuperChecks.__init__:No value for argument 'param' in method call:HIGH
-too-many-function-args:93:InvalidSuperChecks.__init__:Too many positional arguments for method call:HIGH
-no-value-for-parameter:95:InvalidSuperChecks.__init__:No value for argument 'param' in method call:HIGH
-unexpected-keyword-arg:95:InvalidSuperChecks.__init__:Unexpected keyword argument 'lala' in method call:HIGH
+no-value-for-parameter:92:InvalidSuperChecks.__init__:No value for argument 'param' in method call
+too-many-function-args:93:InvalidSuperChecks.__init__:Too many positional arguments for method call
+no-value-for-parameter:95:InvalidSuperChecks.__init__:No value for argument 'param' in method call
+unexpected-keyword-arg:95:InvalidSuperChecks.__init__:Unexpected keyword argument 'lala' in method call
no-member:98:InvalidSuperChecks.__init__:Super of 'InvalidSuperChecks' has no 'attribute_error' member:INFERENCE \ No newline at end of file
diff --git a/pylint/test/functional/syntax_error.txt b/pylint/test/functional/syntax_error.txt
index b57bc72..76abba8 100644
--- a/pylint/test/functional/syntax_error.txt
+++ b/pylint/test/functional/syntax_error.txt
@@ -1 +1 @@
-syntax-error:1::invalid syntax \ No newline at end of file
+syntax-error:1::invalid syntax (<string>, line 1) \ No newline at end of file
diff --git a/pylint/test/functional/unknown_encoding_py29.txt b/pylint/test/functional/unknown_encoding_py29.txt
index 588b3bf..20e7757 100644
--- a/pylint/test/functional/unknown_encoding_py29.txt
+++ b/pylint/test/functional/unknown_encoding_py29.txt
@@ -1 +1 @@
-syntax-error:1::"unknown encoding: IBO-8859-1"
+syntax-error:1::"unknown encoding: IBO-8859-1 (<string>, line 0)"
diff --git a/pylint/test/functional/wrong_import_position.py b/pylint/test/functional/wrong_import_position.py
index 1547ff2..269d757 100644
--- a/pylint/test/functional/wrong_import_position.py
+++ b/pylint/test/functional/wrong_import_position.py
@@ -1,13 +1,25 @@
"""Checks import order rule"""
# pylint: disable=unused-import,relative-import,ungrouped-imports,wrong-import-order,using-constant-test
-# pylint: disable=import-error
+# pylint: disable=import-error, too-few-public-methods, missing-docstring
import os.path
+
if True:
from astroid import are_exclusive
try:
import sys
except ImportError:
- import datetime
+ class Myclass(object):
+ """docstring"""
+
+if sys.version_info[0] == 3:
+ from collections import OrderedDict
+else:
+ class OrderedDict(object):
+ """Nothing to see here."""
+ def some_func(self):
+ pass
+
+import six
CONSTANT = True
diff --git a/pylint/test/functional/wrong_import_position.txt b/pylint/test/functional/wrong_import_position.txt
index 2f417e4..5cde17d 100644
--- a/pylint/test/functional/wrong_import_position.txt
+++ b/pylint/test/functional/wrong_import_position.txt
@@ -1,3 +1,3 @@
-wrong-import-position:14::Import "import datetime" should be placed at the top of the module
-wrong-import-position:20::Import "import scipy" should be placed at the top of the module
-wrong-import-position:21::Import "import astroid" should be placed at the top of the module
+wrong-import-position:26::Import "import datetime" should be placed at the top of the module
+wrong-import-position:32::Import "import scipy" should be placed at the top of the module
+wrong-import-position:33::Import "import astroid" should be placed at the top of the module
diff --git a/pylint/test/regrtest_data/beyond_top/__init__.py b/pylint/test/regrtest_data/beyond_top/__init__.py
new file mode 100644
index 0000000..401fe06
--- /dev/null
+++ b/pylint/test/regrtest_data/beyond_top/__init__.py
@@ -0,0 +1,6 @@
+from ... import Something
+from . import data
+try:
+ from ... import Lala
+except ImportError:
+ pass \ No newline at end of file
diff --git a/pylint/test/regrtest_data/beyond_top/data.py b/pylint/test/regrtest_data/beyond_top/data.py
new file mode 100644
index 0000000..9ec64d2
--- /dev/null
+++ b/pylint/test/regrtest_data/beyond_top/data.py
@@ -0,0 +1 @@
+Anything = 42 \ No newline at end of file
diff --git a/pylint/test/unittest_checker_imports.py b/pylint/test/unittest_checker_imports.py
index f5e6bbb..0069be2 100644
--- a/pylint/test/unittest_checker_imports.py
+++ b/pylint/test/unittest_checker_imports.py
@@ -1,6 +1,8 @@
"""Unit tests for the imports checker."""
+import os
import unittest
+import astroid
from astroid import test_utils
from pylint.checkers import imports
from pylint.testutils import CheckerTestCase, Message, set_config
@@ -62,7 +64,7 @@ class ImportsCheckerTC(CheckerTestCase):
with self.assertNoMessages():
self.checker.visit_import(node)
- def test_visit_importfrom(self):
+ def test_reimported_same_line(self):
"""
Test that duplicate imports on single line raise 'reimported'.
"""
@@ -71,5 +73,23 @@ class ImportsCheckerTC(CheckerTestCase):
with self.assertAddsMessages(msg):
self.checker.visit_importfrom(node)
+ def test_relative_beyond_top_level(self):
+ here = os.path.abspath(os.path.dirname(__file__))
+ path = os.path.join(here, 'regrtest_data', 'beyond_top', '__init__.py')
+ with open(path) as stream:
+ data = stream.read()
+ module = astroid.parse(data, module_name='beyond_top', path=path)
+ import_from = module.body[0]
+
+ msg = Message(msg_id='relative-beyond-top-level',
+ node=import_from)
+ with self.assertAddsMessages(msg):
+ self.checker.visit_importfrom(import_from)
+ with self.assertNoMessages():
+ self.checker.visit_importfrom(module.body[1])
+ with self.assertNoMessages():
+ self.checker.visit_importfrom(module.body[2].body[0])
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/pylint/test/unittest_checker_stdlib.py b/pylint/test/unittest_checker_stdlib.py
new file mode 100644
index 0000000..82c1f17
--- /dev/null
+++ b/pylint/test/unittest_checker_stdlib.py
@@ -0,0 +1,65 @@
+# Copyright (c) 2003-2015 LOGILAB S.A. (Paris, FRANCE).
+# http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+import contextlib
+import unittest
+
+import astroid
+from astroid import test_utils
+
+from pylint.checkers import stdlib
+from pylint.testutils import CheckerTestCase
+
+
+@contextlib.contextmanager
+def _add_transform(manager, node, transform, predicate=None):
+ manager.register_transform(node, transform, predicate)
+ try:
+ yield
+ finally:
+ manager.unregister_transform(node, transform, predicate)
+
+
+class StdlibCheckerTest(CheckerTestCase):
+ CHECKER_CLASS = stdlib.StdlibChecker
+
+ def test_deprecated_no_qname_on_unexpected_nodes(self):
+ # Test that we don't crash on nodes which don't have
+ # a qname method. While this test might seem weird since
+ # it uses a transform, it's actually testing a crash that
+ # happened in production, but there was no way to retrieve
+ # the code for which this occurred (how an AssignAttr
+ # got to be the result of a function inference
+ # beats me..)
+
+ def infer_func(node, context=None):
+ new_node = astroid.AssignAttr()
+ new_node.parent = node
+ yield new_node
+
+ manager = astroid.MANAGER
+ transform = astroid.inference_tip(infer_func)
+ with _add_transform(manager, astroid.Name, transform):
+ node = test_utils.extract_node('''
+ call_something()
+ ''')
+ with self.assertNoMessages():
+ self.checker.visit_call(node)
+
+
+
+if __name__ == '__main__':
+ unittest.main()