summaryrefslogtreecommitdiff
path: root/src/main/python/venv/Lib/site-packages/astroid/context.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/python/venv/Lib/site-packages/astroid/context.py')
-rw-r--r--src/main/python/venv/Lib/site-packages/astroid/context.py179
1 files changed, 179 insertions, 0 deletions
diff --git a/src/main/python/venv/Lib/site-packages/astroid/context.py b/src/main/python/venv/Lib/site-packages/astroid/context.py
new file mode 100644
index 0000000..70a9208
--- /dev/null
+++ b/src/main/python/venv/Lib/site-packages/astroid/context.py
@@ -0,0 +1,179 @@
+# Copyright (c) 2015-2016, 2018 Claudiu Popa <pcmanticore@gmail.com>
+# Copyright (c) 2015-2016 Ceridwen <ceridwenv@gmail.com>
+# Copyright (c) 2018 Bryce Guinta <bryce.paul.guinta@gmail.com>
+# Copyright (c) 2018 Nick Drozd <nicholasdrozd@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
+
+"""Various context related utilities, including inference and call contexts."""
+import contextlib
+import pprint
+from typing import Optional
+
+
+class InferenceContext:
+ """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",
+ "extra_context",
+ )
+
+ def __init__(self, path=None, inferred=None):
+ self.path = path or set()
+ """
+ :type: set(tuple(NodeNG, optional(str)))
+
+ Path of visited nodes and their lookupname
+
+ Currently this key is ``(node, context.lookupname)``
+ """
+ self.lookupname = None
+ """
+ :type: optional[str]
+
+ The original name of the node
+
+ e.g.
+ foo = 1
+ The inference of 'foo' is nodes.Const(1) but the lookup name is 'foo'
+ """
+ self.callcontext = None
+ """
+ :type: optional[CallContext]
+
+ The call arguments and keywords for the given context
+ """
+ self.boundnode = None
+ """
+ :type: optional[NodeNG]
+
+ The bound node of the given context
+
+ e.g. the bound node of object.__new__(cls) is the object node
+ """
+ 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
+ """
+ self.extra_context = {}
+ """
+ :type: dict(NodeNG, Context)
+
+ Context that needs to be passed down through call stacks
+ for call arguments
+ """
+
+ 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
+
+ self.path.add((node, name))
+ 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.callcontext = self.callcontext
+ clone.boundnode = self.boundnode
+ clone.extra_context = self.extra_context
+ 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)
+ yield result
+
+ self.inferred[key] = tuple(results)
+
+ @contextlib.contextmanager
+ def restore_path(self):
+ path = set(self.path)
+ yield
+ self.path = path
+
+ def __str__(self):
+ state = (
+ "%s=%s"
+ % (field, pprint.pformat(getattr(self, field), width=80 - len(field)))
+ for field in self.__slots__
+ )
+ return "%s(%s)" % (type(self).__name__, ",\n ".join(state))
+
+
+class CallContext:
+ """Holds information for a call site."""
+
+ __slots__ = ("args", "keywords")
+
+ def __init__(self, args, keywords=None):
+ """
+ :param List[NodeNG] args: Call positional arguments
+ :param Union[List[nodes.Keyword], None] keywords: Call keywords
+ """
+ self.args = args
+ if keywords:
+ keywords = [(arg.arg, arg.value) for arg in keywords]
+ else:
+ keywords = []
+ self.keywords = keywords
+
+
+def copy_context(context: Optional[InferenceContext]) -> InferenceContext:
+ """Clone a context if given, or return a fresh contexxt"""
+ if context is not None:
+ return context.clone()
+
+ return InferenceContext()
+
+
+def bind_context_to_node(context, node):
+ """Give a context a boundnode
+ to retrieve the correct function name or attribute value
+ with from further inference.
+
+ Do not use an existing context since the boundnode could then
+ be incorrectly propagated higher up in the call stack.
+
+ :param context: Context to use
+ :type context: Optional(context)
+
+ :param node: Node to do name lookups from
+ :type node NodeNG:
+
+ :returns: A new context
+ :rtype: InferenceContext
+ """
+ context = copy_context(context)
+ context.boundnode = node
+ return context