summaryrefslogtreecommitdiff
path: root/astroid/context.py
diff options
context:
space:
mode:
authorBryce Guinta <bryce.paul.guinta@gmail.com>2018-01-27 18:15:00 -0700
committerClaudiu Popa <pcmanticore@gmail.com>2018-01-28 16:26:10 +0100
commit53ab62402b2842dbe79cfbd91f3d698d74200485 (patch)
treeac2821e2d3e00db4fdf1dec04947f19c60210907 /astroid/context.py
parentf8b7af62086478129bc9565696f5c60e69ae5508 (diff)
downloadastroid-git-53ab62402b2842dbe79cfbd91f3d698d74200485.tar.gz
Fix inference issue with inference path cloning
Copy inference path in inference context upon cloning to prevent diverging inference paths causing uninferable results
Diffstat (limited to 'astroid/context.py')
-rw-r--r--astroid/context.py33
1 files changed, 32 insertions, 1 deletions
diff --git a/astroid/context.py b/astroid/context.py
index 627bae5d..838e2813 100644
--- a/astroid/context.py
+++ b/astroid/context.py
@@ -7,20 +7,43 @@
"""Various context related utilities, including inference and call contexts."""
import contextlib
+import copy
import pprint
class InferenceContext(object):
+ """Provide context for inference
+
+ Store already inferred nodes to save time
+ Account for already visited nodes to infinite stop infinite recursion
+ """
+
__slots__ = ('path', 'lookupname', 'callcontext', 'boundnode', 'inferred')
def __init__(self, path=None, inferred=None):
self.path = path or set()
+ """Path of visited nodes and their lookupname
+ :type: set(tuple(NodeNG, optional(str)))"""
self.lookupname = None
self.callcontext = None
self.boundnode = None
self.inferred = inferred or {}
+ """
+ :type: dict(seq, seq)
+
+ Inferred node contexts to their mapped results
+ Currently the key is (node, lookupname, callcontext, boundnode)
+ and the value is tuple of the inferred results
+ """
def push(self, node):
+ """Push node into inference path
+
+ :return: True if node is already in context path else False
+ :rtype: bool
+
+ Allows one to see if the given node has already
+ been looked at for this inference context"""
name = self.lookupname
if (node, name) in self.path:
return True
@@ -29,13 +52,21 @@ class InferenceContext(object):
return False
def clone(self):
+ """Clone inference path
+
+ For example, each side of a binary operation (BinOp)
+ starts with the same context but diverge as each side is inferred
+ so the InferenceContext will need be cloned"""
# XXX copy lookupname/callcontext ?
- clone = InferenceContext(self.path, inferred=self.inferred)
+ clone = InferenceContext(copy.copy(self.path), inferred=self.inferred)
clone.callcontext = self.callcontext
clone.boundnode = self.boundnode
return clone
def cache_generator(self, key, generator):
+ """Cache result of generator into dictionary
+
+ Used to cache inference results"""
results = []
for result in generator:
results.append(result)