summaryrefslogtreecommitdiff
path: root/astroid/objects.py
diff options
context:
space:
mode:
authorhippo91 <guillaume.peillex@gmail.com>2018-12-02 16:20:06 +0100
committerClaudiu Popa <pcmanticore@gmail.com>2019-01-23 09:09:22 +0100
commit87b55a6ea6a421b4702dbc178a45165f20d1e775 (patch)
tree18c75077ec735554381ecd88be576c3f18cec91a /astroid/objects.py
parentc54ca8e30d8cce8660ddac842c58b66de2733322 (diff)
downloadastroid-git-87b55a6ea6a421b4702dbc178a45165f20d1e775.tar.gz
Avoid statement deletion in the _filter_stmts method of the LookupMixin class for PartialFunction
In the case where the node is a PartialFunction and its name is the same as the current statement's name, avoid the statement deletion. The problem was that a call to a function that has been previously called vit a functools.partial was wrongly inferred. The bug comes from the _filter_stmts method of the LookupMixin class. The deletion of the current statement should not be made in the case where the node is an instance of the PartialFunction class and if the node's name is the same as the statement's name. This change also extracts PartialFunction from brain_functools into astroid.objects so that we remove a circular import problem. Close PyCQA/pylint#2588
Diffstat (limited to 'astroid/objects.py')
-rw-r--r--astroid/objects.py29
1 files changed, 29 insertions, 0 deletions
diff --git a/astroid/objects.py b/astroid/objects.py
index b68d3596..b511cda0 100644
--- a/astroid/objects.py
+++ b/astroid/objects.py
@@ -248,6 +248,35 @@ class DictValues(bases.Proxy):
__repr__ = node_classes.NodeNG.__repr__
+class PartialFunction(scoped_nodes.FunctionDef):
+ """A class representing partial function obtained via functools.partial"""
+
+ def __init__(
+ self, call, name=None, doc=None, lineno=None, col_offset=None, parent=None
+ ):
+ super().__init__(name, doc, lineno, col_offset, parent)
+ self.filled_positionals = len(call.positional_arguments[1:])
+ self.filled_args = call.positional_arguments[1:]
+ self.filled_keywords = call.keyword_arguments
+
+ def infer_call_result(self, caller=None, context=None):
+ if context:
+ current_passed_keywords = {
+ keyword for (keyword, _) in context.callcontext.keywords
+ }
+ for keyword, value in self.filled_keywords.items():
+ if keyword not in current_passed_keywords:
+ context.callcontext.keywords.append((keyword, value))
+
+ call_context_args = context.callcontext.args or []
+ context.callcontext.args = self.filled_args + call_context_args
+
+ return super().infer_call_result(caller=caller, context=context)
+
+ def qname(self):
+ return self.__class__.__name__
+
+
# TODO: Hack to solve the circular import problem between node_classes and objects
# This is not needed in 2.0, which has a cleaner design overall
node_classes.Dict.__bases__ = (node_classes.NodeNG, DictInstance)