diff options
Diffstat (limited to 'venv/Lib/site-packages/astroid/builder.py')
-rw-r--r-- | venv/Lib/site-packages/astroid/builder.py | 435 |
1 files changed, 0 insertions, 435 deletions
diff --git a/venv/Lib/site-packages/astroid/builder.py b/venv/Lib/site-packages/astroid/builder.py deleted file mode 100644 index ac71093..0000000 --- a/venv/Lib/site-packages/astroid/builder.py +++ /dev/null @@ -1,435 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2006-2011, 2013-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr> -# Copyright (c) 2013 Phil Schaf <flying-sheep@web.de> -# Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com> -# Copyright (c) 2014-2015 Google, Inc. -# Copyright (c) 2014 Alexander Presnyakov <flagist0@gmail.com> -# Copyright (c) 2015-2016 Ceridwen <ceridwenv@gmail.com> -# Copyright (c) 2016 Derek Gustafson <degustaf@gmail.com> -# Copyright (c) 2017 Ćukasz Rogalski <rogalski.91@gmail.com> -# Copyright (c) 2018 Anthony Sottile <asottile@umich.edu> - -# 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 - -"""The AstroidBuilder makes astroid from living object and / or from _ast - -The builder is not thread safe and can't be used to parse different sources -at the same time. -""" - -import os -import textwrap -from tokenize import detect_encoding - -from astroid._ast import _parse -from astroid import bases -from astroid import exceptions -from astroid import manager -from astroid import modutils -from astroid import raw_building -from astroid import rebuilder -from astroid import nodes -from astroid import util - -# The name of the transient function that is used to -# wrap expressions to be extracted when calling -# extract_node. -_TRANSIENT_FUNCTION = "__" - -# The comment used to select a statement to be extracted -# when calling extract_node. -_STATEMENT_SELECTOR = "#@" - -MANAGER = manager.AstroidManager() - - -def open_source_file(filename): - with open(filename, "rb") as byte_stream: - encoding = detect_encoding(byte_stream.readline)[0] - stream = open(filename, "r", newline=None, encoding=encoding) - data = stream.read() - return stream, encoding, data - - -def _can_assign_attr(node, attrname): - try: - slots = node.slots() - except NotImplementedError: - pass - else: - if slots and attrname not in {slot.value for slot in slots}: - return False - return True - - -class AstroidBuilder(raw_building.InspectBuilder): - """Class for building an astroid tree from source code or from a live module. - - The param *manager* specifies the manager class which should be used. - If no manager is given, then the default one will be used. The - param *apply_transforms* determines if the transforms should be - applied after the tree was built from source or from a live object, - by default being True. - """ - - # pylint: disable=redefined-outer-name - def __init__(self, manager=None, apply_transforms=True): - super(AstroidBuilder, self).__init__() - self._manager = manager or MANAGER - self._apply_transforms = apply_transforms - - def module_build(self, module, modname=None): - """Build an astroid from a living module instance.""" - node = None - path = getattr(module, "__file__", None) - if path is not None: - path_, ext = os.path.splitext(modutils._path_from_filename(path)) - if ext in (".py", ".pyc", ".pyo") and os.path.exists(path_ + ".py"): - node = self.file_build(path_ + ".py", modname) - if node is None: - # this is a built-in module - # get a partial representation by introspection - node = self.inspect_build(module, modname=modname, path=path) - if self._apply_transforms: - # We have to handle transformation by ourselves since the - # rebuilder isn't called for builtin nodes - node = self._manager.visit_transforms(node) - return node - - def file_build(self, path, modname=None): - """Build astroid from a source code file (i.e. from an ast) - - *path* is expected to be a python source file - """ - try: - stream, encoding, data = open_source_file(path) - except IOError as exc: - raise exceptions.AstroidBuildingError( - "Unable to load file {path}:\n{error}", - modname=modname, - path=path, - error=exc, - ) from exc - except (SyntaxError, LookupError) as exc: - raise exceptions.AstroidSyntaxError( - "Python 3 encoding specification error or unknown encoding:\n" - "{error}", - modname=modname, - path=path, - error=exc, - ) from exc - except UnicodeError as exc: # wrong encoding - # detect_encoding returns utf-8 if no encoding specified - raise exceptions.AstroidBuildingError( - "Wrong or no encoding specified for {filename}.", filename=path - ) from exc - with stream: - # get module name if necessary - if modname is None: - try: - modname = ".".join(modutils.modpath_from_file(path)) - except ImportError: - modname = os.path.splitext(os.path.basename(path))[0] - # build astroid representation - module = self._data_build(data, modname, path) - return self._post_build(module, encoding) - - def string_build(self, data, modname="", path=None): - """Build astroid from source code string.""" - module = self._data_build(data, modname, path) - module.file_bytes = data.encode("utf-8") - return self._post_build(module, "utf-8") - - def _post_build(self, module, encoding): - """Handles encoding and delayed nodes after a module has been built""" - module.file_encoding = encoding - self._manager.cache_module(module) - # post tree building steps after we stored the module in the cache: - for from_node in module._import_from_nodes: - if from_node.modname == "__future__": - for symbol, _ in from_node.names: - module.future_imports.add(symbol) - self.add_from_names_to_locals(from_node) - # handle delayed assattr nodes - for delayed in module._delayed_assattr: - self.delayed_assattr(delayed) - - # Visit the transforms - if self._apply_transforms: - module = self._manager.visit_transforms(module) - return module - - def _data_build(self, data, modname, path): - """Build tree node from data and add some informations""" - try: - node = _parse(data + "\n") - except (TypeError, ValueError, SyntaxError) as exc: - raise exceptions.AstroidSyntaxError( - "Parsing Python code failed:\n{error}", - source=data, - modname=modname, - path=path, - error=exc, - ) from exc - if path is not None: - node_file = os.path.abspath(path) - else: - node_file = "<?>" - if modname.endswith(".__init__"): - modname = modname[:-9] - package = True - else: - package = ( - path is not None - and os.path.splitext(os.path.basename(path))[0] == "__init__" - ) - builder = rebuilder.TreeRebuilder(self._manager) - module = builder.visit_module(node, modname, node_file, package) - module._import_from_nodes = builder._import_from_nodes - module._delayed_assattr = builder._delayed_assattr - return module - - def add_from_names_to_locals(self, node): - """Store imported names to the locals - - Resort the locals if coming from a delayed node - """ - _key_func = lambda node: node.fromlineno - - def sort_locals(my_list): - my_list.sort(key=_key_func) - - for (name, asname) in node.names: - if name == "*": - try: - imported = node.do_import_module() - except exceptions.AstroidBuildingError: - continue - for name in imported.public_names(): - node.parent.set_local(name, node) - sort_locals(node.parent.scope().locals[name]) - else: - node.parent.set_local(asname or name, node) - sort_locals(node.parent.scope().locals[asname or name]) - - def delayed_assattr(self, node): - """Visit a AssAttr node - - This adds name to locals and handle members definition. - """ - try: - frame = node.frame() - for inferred in node.expr.infer(): - if inferred is util.Uninferable: - continue - try: - if inferred.__class__ is bases.Instance: - inferred = inferred._proxied - iattrs = inferred.instance_attrs - if not _can_assign_attr(inferred, node.attrname): - continue - elif isinstance(inferred, bases.Instance): - # Const, Tuple, ... we may be wrong, may be not, but - # anyway we don't want to pollute builtin's namespace - continue - elif inferred.is_function: - iattrs = inferred.instance_attrs - else: - iattrs = inferred.locals - except AttributeError: - # XXX log error - continue - values = iattrs.setdefault(node.attrname, []) - if node in values: - continue - # get assign in __init__ first XXX useful ? - if ( - frame.name == "__init__" - and values - and values[0].frame().name != "__init__" - ): - values.insert(0, node) - else: - values.append(node) - except exceptions.InferenceError: - pass - - -def build_namespace_package_module(name, path): - return nodes.Module(name, doc="", path=path, package=True) - - -def parse(code, module_name="", path=None, apply_transforms=True): - """Parses a source string in order to obtain an astroid AST from it - - :param str code: The code for the module. - :param str module_name: The name for the module, if any - :param str path: The path for the module - :param bool apply_transforms: - Apply the transforms for the give code. Use it if you - don't want the default transforms to be applied. - """ - code = textwrap.dedent(code) - builder = AstroidBuilder(manager=MANAGER, apply_transforms=apply_transforms) - return builder.string_build(code, modname=module_name, path=path) - - -def _extract_expressions(node): - """Find expressions in a call to _TRANSIENT_FUNCTION and extract them. - - The function walks the AST recursively to search for expressions that - are wrapped into a call to _TRANSIENT_FUNCTION. If it finds such an - expression, it completely removes the function call node from the tree, - replacing it by the wrapped expression inside the parent. - - :param node: An astroid node. - :type node: astroid.bases.NodeNG - :yields: The sequence of wrapped expressions on the modified tree - expression can be found. - """ - if ( - isinstance(node, nodes.Call) - and isinstance(node.func, nodes.Name) - and node.func.name == _TRANSIENT_FUNCTION - ): - real_expr = node.args[0] - real_expr.parent = node.parent - # Search for node in all _astng_fields (the fields checked when - # get_children is called) of its parent. Some of those fields may - # be lists or tuples, in which case the elements need to be checked. - # When we find it, replace it by real_expr, so that the AST looks - # like no call to _TRANSIENT_FUNCTION ever took place. - for name in node.parent._astroid_fields: - child = getattr(node.parent, name) - if isinstance(child, (list, tuple)): - for idx, compound_child in enumerate(child): - if compound_child is node: - child[idx] = real_expr - elif child is node: - setattr(node.parent, name, real_expr) - yield real_expr - else: - for child in node.get_children(): - yield from _extract_expressions(child) - - -def _find_statement_by_line(node, line): - """Extracts the statement on a specific line from an AST. - - If the line number of node matches line, it will be returned; - otherwise its children are iterated and the function is called - recursively. - - :param node: An astroid node. - :type node: astroid.bases.NodeNG - :param line: The line number of the statement to extract. - :type line: int - :returns: The statement on the line, or None if no statement for the line - can be found. - :rtype: astroid.bases.NodeNG or None - """ - if isinstance(node, (nodes.ClassDef, nodes.FunctionDef)): - # This is an inaccuracy in the AST: the nodes that can be - # decorated do not carry explicit information on which line - # the actual definition (class/def), but .fromline seems to - # be close enough. - node_line = node.fromlineno - else: - node_line = node.lineno - - if node_line == line: - return node - - for child in node.get_children(): - result = _find_statement_by_line(child, line) - if result: - return result - - return None - - -def extract_node(code, module_name=""): - """Parses some Python code as a module and extracts a designated AST node. - - Statements: - To extract one or more statement nodes, append #@ to the end of the line - - Examples: - >>> def x(): - >>> def y(): - >>> return 1 #@ - - The return statement will be extracted. - - >>> class X(object): - >>> def meth(self): #@ - >>> pass - - The function object 'meth' will be extracted. - - Expressions: - To extract arbitrary expressions, surround them with the fake - function call __(...). After parsing, the surrounded expression - will be returned and the whole AST (accessible via the returned - node's parent attribute) will look like the function call was - never there in the first place. - - Examples: - >>> a = __(1) - - The const node will be extracted. - - >>> def x(d=__(foo.bar)): pass - - The node containing the default argument will be extracted. - - >>> def foo(a, b): - >>> return 0 < __(len(a)) < b - - The node containing the function call 'len' will be extracted. - - If no statements or expressions are selected, the last toplevel - statement will be returned. - - If the selected statement is a discard statement, (i.e. an expression - turned into a statement), the wrapped expression is returned instead. - - For convenience, singleton lists are unpacked. - - :param str code: A piece of Python code that is parsed as - a module. Will be passed through textwrap.dedent first. - :param str module_name: The name of the module. - :returns: The designated node from the parse tree, or a list of nodes. - :rtype: astroid.bases.NodeNG, or a list of nodes. - """ - - def _extract(node): - if isinstance(node, nodes.Expr): - return node.value - - return node - - requested_lines = [] - for idx, line in enumerate(code.splitlines()): - if line.strip().endswith(_STATEMENT_SELECTOR): - requested_lines.append(idx + 1) - - tree = parse(code, module_name=module_name) - if not tree.body: - raise ValueError("Empty tree, cannot extract from it") - - extracted = [] - if requested_lines: - extracted = [_find_statement_by_line(tree, line) for line in requested_lines] - - # Modifies the tree. - extracted.extend(_extract_expressions(tree)) - - if not extracted: - extracted.append(tree.body[-1]) - - extracted = [_extract(node) for node in extracted] - if len(extracted) == 1: - return extracted[0] - return extracted |