示例#1
0
def _make_intersphinx_pairs(pairs):
    """Convert key/value pairs into something that parso can convert into dict key/values.

    Args:
        pairs (iter[tuple[str, str or tuple[str, str or NoneType]]):
            The intersphinx key/value mapping. Keys are usually the
            name of Rez packages and each value is the URL to the API
            documentation that we need to link to.

    Returns:
        list[:class:`parso.python.tree.Node`]:
            The key/value pairs, flattened into parso objects.

    """
    output = []

    for row, (key, value) in enumerate(sorted(pairs)):
        if isinstance(key, six.string_types):
            key = '"{key}"'.format(key=key)

        if isinstance(value, six.string_types):
            value = '"{value}"'.format(value=value)

        key_length = len(key)
        value_length = len(value)
        output.append(tree.String(key, (row, 0), prefix="\n    "))
        output.append(tree.Operator(":", (row, key_length)))
        output.append(tree.String(str(value), (row, key_length + len(":")), prefix=" "))
        output.append(tree.Operator(",", (row, key_length + len(":") + value_length)))

    return output
def _make_tests_node(data):
    """Create the final "tests" data that will be written to a package.py file.

    Important:
        This function technically doesn't create a "correct"
        parso dict. For the sake of simplicity, some corners were
        cut. For example, value data is converted into a raw
        :class:`parso.python.tree.String`. It's not technically
        "correct" but since this function is called just before writing
        the data into disk and not further modified, it's okay.

    Args:
        data (iter[str, :class:`parso.python.tree.PythonBaseNode`]):
            The key / value information that will be converted into a
            parso dict.

    Returns:
        :class:`parso.python.tree.PythonNode`:
            An atom PythonNode which has a full dictionary "tests"
            defined. This will later override an existing "tests"
            attribute in a package.py or be appended to the file as an
            assignment.

    """
    nodes = []

    for key, value in data:
        nodes.extend([
            tree.String(_escape(key), (0, 0), prefix="\n    "),
            tree.Operator(":", (0, 0)),
        ])

        if isinstance(value, collections.MutableMapping):
            nodes.append(_make_dict_nodes(sorted(value.items()),
                                          prefix="    "))
        elif hasattr(value, "get_code"):
            if hasattr(value, "prefix"):
                value.prefix = " "

            nodes.append(value)
        else:
            nodes.append(tree.String(_escape_all(value), (0, 0), prefix=" "))

        nodes.append(tree.Operator(",", (0, 0)))

    base = tree.PythonNode("dictorsetmaker", nodes)

    return tree.PythonNode(
        "atom",
        [
            tree.Operator("{", (0, 0)), base,
            tree.Operator("}", (0, 0), prefix="\n")
        ],
    )
def _make_dict_nodes(data, prefix=""):
    """Create a parso node that represents the inner key / value pairs of a Python dict.

    In terms of the work needed to generate a Rez "tests" attribute,
    this function is used mainly to create the "inner dict" that a
    "tests" attribute frequently defines.

    Args:
        data (iter[tuple[str, str or list or :class:`parso.python.tree.PythonBaseNode`]]):

    Returns:
        :class:`parso.python.tree.PythonNode`:
            A node that defines the inside of a parso dict. This node
            is not equivalent to an actual dict and still needs to be
            wrapped with another :class:`parso.python.tree.PythonNode`
            to be valid.

    """
    nodes = []

    for key, item in data:
        item = _escape_all(item)

        nodes.append(
            tree.String(_escape(key), (0, 0),
                        prefix="\n    {prefix}".format(prefix=prefix)))
        nodes.append(tree.Operator(":", (0, 0)))
        nodes.append(
            tree.PythonNode(
                "atom",
                [
                    tree.String(item, (0, 0), prefix=" "),
                    tree.Operator(",", (0, 0))
                ],
            ), )

    return tree.PythonNode(
        "atom",
        [
            tree.Operator("{", (0, 0), prefix=" "),
            tree.PythonNode("dictorsetmaker", nodes),
            tree.Operator("}", (0, 0), prefix="\n    "),
        ],
    )
示例#4
0
 def convert_leaf(self, pgen_grammar, type, value, prefix, start_pos):
     # print('leaf', repr(value), token.tok_name[type])
     if type == NAME:
         if value in pgen_grammar.keywords:
             return tree.Keyword(value, start_pos, prefix)
         else:
             return tree.Name(value, start_pos, prefix)
     elif type == STRING:
         return tree.String(value, start_pos, prefix)
     elif type == NUMBER:
         return tree.Number(value, start_pos, prefix)
     elif type == NEWLINE:
         return tree.Newline(value, start_pos, prefix)
     elif type == ENDMARKER:
         return tree.EndMarker(value, start_pos, prefix)
     else:
         return tree.Operator(value, start_pos, prefix)
示例#5
0
    def _get_entries(assignment):
        """Find every help key + value entry from some "help" attribute.

        If `assignment` is invalid, this function may return an empty list.

        Args:
            assignment (:class:`parso.python.tree.ExprStmt`):
                The node that assigns the "help" attribute, which will
                be modified.

        Returns:
            list[:class:`parso.python.tree.PythonNode`]:
                The list node that is a parso "list of list of strs".

        """
        root = _get_list_root(assignment)

        if root:
            return _get_inner_list_entries(root)

        string_root = _get_str_root(assignment)

        if not string_root:
            return []

        if string_root.get_code().strip() in ("''", '""'):
            return []

        node = tree.PythonNode(
            "testlist_comp",
            [
                tree.String(
                    '"{rez_configuration.DEFAULT_HELP_LABEL}"'.format(
                        rez_configuration=rez_configuration),
                    (0, 0),
                ),
                tree.Operator(",", (0, 0)),
                string_root,
            ],
        )

        for child in node.children:
            child.parent = node

        return [node]
示例#6
0
def _get_faked(grammar, module, obj, name=None):
    result, fake_module = _faked(grammar, module, obj, name)
    if result is None:
        # We're not interested in classes. What we want is functions.
        raise FakeDoesNotExist
    elif result.type == 'classdef':
        return result, fake_module
    else:
        # Set the docstr which was previously not set (faked modules don't
        # contain it).
        assert result.type == 'funcdef'
        doc = '"""%s"""' % obj.__doc__  # TODO need escapes.
        suite = result.children[-1]
        string = tree.String(doc, (0, 0), '')
        new_line = tree.Newline('\n', (0, 0))
        docstr_node = tree.PythonNode('simple_stmt', [string, new_line])
        suite.children.insert(1, docstr_node)
        return result, fake_module
示例#7
0
def _make_nodes(data, prefix=""):
    """Make basic parso nodes to describe `data`.

    Args:
        data (iter[str]): Some Rez requirement objects to convert into parso nodes.
        prefix (str, optional): Leading indentation for each generated node. Default: "".

    Returns:
        list[:class:`parso.python.tree.String`]: The parso nodes which represent the given `data`.

    """
    return [
        tree.String(
            '"{requirement}"'.format(
                requirement=requirement.replace('"', '"')),
            (0, 0),
            prefix="\n{prefix}".format(prefix=prefix),
        ) for requirement in data
    ]
def _find_type_from_comment_hint(context, node, varlist, name):
    index = None
    if varlist.type in ("testlist_star_expr", "exprlist", "testlist"):
        # something like "a, b = 1, 2"
        index = 0
        for child in varlist.children:
            if child == name:
                break
            if child.type == "operator":
                continue
            index += 1
        else:
            return []

    comment = parser_utils.get_following_comment_same_line(node)
    if comment is None:
        return []
    match = re.match(r"^#\s*type:\s*([^#]*)", comment)
    if not match:
        return []
    annotation = tree.String(repr(str(match.group(1).strip())), node.start_pos)
    annotation.parent = node.parent
    return _evaluate_for_annotation(context, annotation, index)
示例#9
0
def _write_package_to_disk(package, version):
    """Update a Rez package on-disk with its new contents.

    Args:
        package (:class:`rez.packages_.DeveloperPackage`):
            Some package on-disk to write out.
        version (str): The new semantic version that will be written to-disk.

    """
    with open(package, "r") as handler:
        code = handler.read()

    graph = parso.parse(code)

    try:
        assignment = parso_utility.find_assignment_nodes("version", graph)[-1]
    except IndexError:
        assignment = None

    prefix = " "

    if assignment:
        prefix = assignment.children[0].prefix.strip("\n") or prefix

    node = tree.String('"{version}"'.format(version=version), (0, 0),
                       prefix=prefix)
    graph = convention.insert_or_append(node, graph, assignment, "version")

    # Writing to DeveloperPackage objects is currently bugged.
    # So instead, we disable caching during write.
    #
    # Reference: https://github.com/nerdvegas/rez/issues/857
    #
    with filesystem.make_path_writable(
            os.path.dirname(os.path.dirname(package))):
        with serialise.open_file_for_write(package) as handler:
            handler.write(graph.get_code())
示例#10
0
def test_unicode_string():
    s = tree.String(None, 'bö', (0, 0))
    assert repr(s)  # Should not raise an Error!
示例#11
0
def insert_or_append(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:
        if hasattr(node, "children"):
            node.children[0].prefix = " "

        assignment.children[-1] = node

        return graph

    index = _find_nearest_node_index(graph.children, attribute)

    if index == -1:
        graph.children.append(
            tree.PythonNode(
                "assignment",
                [
                    tree.String(
                        "{attribute} = ".format(attribute=attribute),
                        (0, 0),
                        prefix="\n\n",
                    )
                ] + [node],
            ))

        return graph

    _kill_suffix(graph.children[index - 1])

    graph.children.insert(
        index,
        tree.PythonNode(
            "assignment",
            [
                tree.String("{attribute} = ".format(attribute=attribute),
                            (0, 0),
                            prefix="\n\n")
            ] + [node],
        ),
    )
    _adjust_prefix(graph.children, index)

    return graph