def _get_prefix(node): """Find the indentation used by `node`. This function ignores newlines and just gets the spaces / tabs used. Args: node (:class:`parso.python.tree.PythonBaseNode`): A parso object that is assumed to define a "requires" attribute. Returns: str: The leading indentation found, if any. """ prefixes = set() for child in _get_inner_list_entries(node): prefix_node = node_seek.get_node_with_first_prefix(child) prefixes.add(prefix_node.prefix) counter = collections.Counter(prefixes) try: common = counter.most_common(1)[0] return common[0].strip("\n") except IndexError: return ""
def _adjust_prefix(node): """Put `node` on its own line but retain its original leading indent.""" prefix_node = node_seek.get_node_with_first_prefix(node) original = prefix_node.prefix prefix_node.prefix = "\n{original}".format(original=original) return original
def _replace_namespace(nodes, old_parts, new_parts, partial=False): """Change `nodes` into an import resembling the Python namespace defined by `new_parts`. If there's no common namespace between `nodes` and `old_parts` then this function does nothing. Args: node (:class:`parso.python.tree.ImportFrom`): A parso object that represents a Python import. old_parts (list[str]): The namespace that is expected to be all or part of the namespace that `node` defines. new_parts (list[str]): The namespace to replace `node` with. e.g. ["foo", "bar"]. """ def _is_fully_defined_by(names, parts): for index, name in enumerate(names): try: part = parts[index] except IndexError: return False if part != name: return False return True names = [ child for node in nodes for child in itertools.chain([node], node_seek.iter_nested_children(node)) if isinstance(child, tree.Name) ] prefix = node_seek.get_node_with_first_prefix(names[0]).prefix start, end = import_helper.get_replacement_indices(names, old_parts) if start == -1 or end == -1: # There's nothing to replace, in this case return if not partial and not _is_fully_defined_by( [name.value for name in names], old_parts ): return new_nodes = import_helper.make_replacement_nodes(new_parts, prefix) names[0].parent.children[start : end + 1] = new_nodes
def test_nested_prefix(self): """Get the prefix of a node whose prefix is stored in one of its child nodes.""" graph = parso.parse( textwrap.dedent( """\ foo = [ blah, another, ] """ ) ) name_node = graph.get_first_leaf() self.assertEqual( name_node, node_seek.get_node_with_first_prefix(graph), )
def test_current_node(self): """Get the given node assuming it defines its own prefix.""" graph = parso.parse( textwrap.dedent( """\ foo = [ blah, another, ] """ ) ) name_node = graph.get_first_leaf() self.assertEqual( name_node, node_seek.get_node_with_first_prefix(name_node), )
def insert_or_append_raw_node(node, graph, assignment, attribute): """Add a new `attribute` to `graph`, according to pre-existing data. Args: node (:class:`parso.python.tree.PythonNode`): The main data that will be added to `graph`. graph (:class:`parso.python.tree.PythonNode`): A Python module that may already contain an assignment for `attribute`. If it doesn't the attribute will be added, automatically. assignment (:class:`parso.python.tree.PythonNode` or NoneType): If `graph` has an existing node where `attribute` is defined, this node will represent that position. If this parameter is None, a new position for `attribute` will be automatically found and used. attribute (str): The name of the Rez-related object to use. Returns: :class:`parso.python.tree.PythonNode`: The main module with a modified `attribute`. """ if assignment: index = _find_nearest_node_index(graph.children, attribute) del graph.children[index] graph.children.insert(index, tree.PythonNode("assignment", [node])) return graph index = _find_nearest_node_index(graph.children, attribute) if index == -1: graph.children.append(tree.PythonNode("assignment", [node])) return graph prefix_node = node_seek.get_node_with_first_prefix(node) prefix_node.prefix = "\n\n" graph.children.insert(index, tree.PythonNode("assignment", [node])) return graph
def _adjust_prefix(nodes, index): """Remove whitespace information or add it, if needed. This function should be applied directly to whatever node lies **after** the Rez attribute that was inserted. The logic goes like this. - If the index after the inserted attribute doesn't have an EndMarker then that means the attribute was inserted at the end of the parso graph - This means the attribute is at the end of the parsed graph. - Because it's at the end, we don't need any newlines. - If the index does exist but it's at the end of the graph, same thing. We don't need newlines. - If there's a node after `index` and it's not an EndMarker then that means the inserted attribute was inserted between two parso nodes. Which means it's in the middle of the file. - Add 2 newlines Args: nodes (iter[:class:`parso.python.tree.PythonNode`]): The direct children of a Rez package.py which had some attribute inserted. index (int): The 0-based position where the attribute was inserted. """ try: marker = nodes[index + 1] except IndexError: return node = node_seek.get_node_with_first_prefix(marker) if isinstance(node, tree.EndMarker): node.prefix = "" return if hasattr(node, "prefix"): node.prefix = "\n\n"