def sync_properties(
    input_eval,
    input_filename,
    input_params,
    output_filename,
    output_params,
    output_param_wrap=None,
):
    """
    Sync one property, inline to a file

    :param input_eval: Whether to evaluate the `param`, or just leave it
    :type input_eval: ```bool```

    :param input_filename: Filename to find `param` from
    :type input_filename: ```str```

    :param input_params: Locations within file of properties.
       Can be top level like `['a']` for `a=5` or with the `.` syntax as in `output_params`.
    :type input_params: ```List[str]```

    :param output_filename: Filename that will be edited in place, the property within this file (to update)
     is selected by `output_param`
    :type output_filename: ```str```

    :param output_params: Parameters to update. E.g., `['A.F']` for `class A: F = None`, `['f.g']` for `def f(g): pass`
    :type output_params: ```List[str]```

    :param output_param_wrap: Wrap all input_str params with this. E.g., `Optional[Union[{output_param}, str]]`
    :param output_param_wrap: ```Optional[str]```
    """
    with open(path.realpath(path.expanduser(input_filename)), "rt") as f:
        input_ast = ast_parse(f.read(), filename=input_filename)

    with open(path.realpath(path.expanduser(output_filename)), "rt") as f:
        output_ast = ast_parse(f.read(), filename=output_filename)

    assert len(input_params) == len(output_params)
    for (input_param, output_param) in zip(input_params, output_params):
        output_ast = sync_property(
            input_eval,
            input_param,
            input_ast,
            input_filename,
            output_param,
            output_param_wrap,
            output_ast,
        )

    emit.file(output_ast, output_filename, mode="wt", skip_black=False)
Example #2
0
    def test_replace_in_ast_with_val_on_non_function(self) -> None:
        """
        Tests that `RewriteAtQuery` can actually replace a node at given location
        """
        parsed_ast = ast_parse(class_str)
        rewrite_at_query = RewriteAtQuery(
            search="ConfigClass.dataset_name".split("."),
            replacement_node=AnnAssign(
                annotation=Name("int", Load()),
                simple=1,
                target=Name("dataset_name", Store()),
                value=set_value(15),
                expr=None,
                expr_target=None,
                expr_annotation=None,
            ),
        )
        gen_ast = rewrite_at_query.visit(parsed_ast)
        self.assertTrue(rewrite_at_query.replaced, True)

        run_ast_test(
            self,
            gen_ast,
            ast.parse(
                class_str.replace('dataset_name: str = "mnist"',
                                  "dataset_name: int = 15")),
        )
Example #3
0
def ground_truth(args, truth_file):
    """
    There is but one truth. Conform.

    :param args: Namespace with the values of the CLI arguments
    :type args: ```Namespace```

    :param truth_file: contains the filename of the one true source
    :type truth_file: ```str```

    :return: Filenames and whether they were changed
    :rtype: ```OrderedDict```
    """
    arg2parse_emit_type = {
        "argparse_function":
        (parse.argparse_ast, emit.argparse_function, FunctionDef),
        "class": (parse.class_, emit.class_, ClassDef),
        "function": (parse.function, emit.function, FunctionDef),
    }

    parse_func, emit_func, type_wanted = arg2parse_emit_type[args.truth]
    search = _get_name_from_namespace(args, args.truth).split(".")

    with open(truth_file, "rt") as f:
        true_ast = ast_parse(f.read(), filename=truth_file)

    original_node = find_in_ast(search, true_ast)
    gold_ir = parse_func(
        original_node,
        **_default_options(node=original_node,
                           search=search,
                           type_wanted=type_wanted)())

    effect = OrderedDict()
    # filter(lambda arg: arg != args.truth, arg2parse_emit_type.keys()):
    for fun_name, (parse_func, emit_func,
                   type_wanted) in arg2parse_emit_type.items():
        search = list(
            strip_split(_get_name_from_namespace(args, fun_name), "."))

        filenames = getattr(args, pluralise(fun_name))
        assert isinstance(
            filenames,
            (list, tuple)), "Expected Union[list, tuple] got {!r}".format(
                type(filenames).__name__)

        effect.update(
            map(
                lambda filename: _conform_filename(
                    filename=filename,
                    search=search,
                    emit_func=emit_func,
                    replacement_node_ir=gold_ir,
                    type_wanted=type_wanted,
                ),
                filenames,
            ))

    return effect
Example #4
0
def _conform_filename(
    filename,
    search,
    emit_func,
    replacement_node_ir,
    type_wanted,
):
    """
    Conform the given file to the `intermediate_repr`

    :param filename: Location of file
    :type filename: ```str```

    :param search: Search query, e.g., ['node_name', 'function_name', 'arg_name']
    :type search: ```List[str]```

    :param replacement_node_ir: Replace what is found with the contents of this param
    :type replacement_node_ir: ```dict```

    :param type_wanted: AST instance
    :type type_wanted: ```AST```

    :return: filename, whether the file was modified
    :rtype: ```Tuple[str, bool]```
    """
    filename = path.realpath(path.expanduser(filename))

    if not path.isfile(filename):
        emit.file(
            emit_func(
                replacement_node_ir,
                emit_default_doc=False,  # emit_func.__name__ == "class_"
            ),
            filename=filename,
            mode="wt",
            skip_black=False,
        )
        return filename, True

    with open(filename, "rt") as f:
        parsed_ast = ast_parse(f.read(), filename=filename)
    assert isinstance(parsed_ast, Module)

    original_node = find_in_ast(search, parsed_ast)
    replacement_node = emit_func(
        replacement_node_ir,
        **_default_options(node=original_node,
                           search=search,
                           type_wanted=type_wanted)())
    if original_node is None:
        emit.file(replacement_node,
                  filename=filename,
                  mode="a",
                  skip_black=False)
        return filename, True
    assert len(search) > 0

    assert type(
        replacement_node) == type_wanted, "Expected {!r} got {!r}".format(
            type_wanted,
            type(replacement_node).__name__)

    replaced = False
    if not cmp_ast(original_node, replacement_node):
        rewrite_at_query = RewriteAtQuery(
            search=search,
            replacement_node=replacement_node,
        )
        rewrite_at_query.visit(parsed_ast)

        print("modified" if rewrite_at_query.replaced else "unchanged",
              filename,
              sep="\t")
        if rewrite_at_query.replaced:
            emit.file(parsed_ast, filename, mode="wt", skip_black=False)

        replaced = rewrite_at_query.replaced

    return filename, replaced