def test_to_file(self) -> None:
        """
        Tests whether `file` constructs a file, and fills it with the right content
        """

        with TemporaryDirectory() as tempdir:
            filename = os.path.join(tempdir, "delete_me.py")
            try:
                emit.file(class_ast, filename, skip_black=True)

                with open(filename, "rt") as f:
                    ugly = f.read()

                os.remove(filename)

                emit.file(class_ast, filename, skip_black=False)

                with open(filename, "rt") as f:
                    blacked = f.read()

                self.assertNotEqual(ugly, blacked)
                # if PY3_8:
                self.assertTrue(
                    cmp_ast(ast.parse(ugly), ast.parse(blacked)),
                    "Ugly AST doesn't match blacked AST",
                )

            finally:
                if os.path.isfile(filename):
                    os.remove(filename)
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)
Exemple #3
0
    def test__conform_filename_unchanged(self) -> None:
        """ Tests that _conform_filename returns the right result """

        with TemporaryDirectory() as tempdir:
            argparse_function_filename = os.path.realpath(
                os.path.join(tempdir, "do_not_touch_this.py"))

            emit.file(argparse_func_ast, argparse_function_filename, mode="wt")
            self.assertTupleEqual(
                _conform_filename(
                    filename=argparse_function_filename,
                    search=["set_cli_args"],
                    emit_func=emit.argparse_function,
                    replacement_node_ir=deepcopy(intermediate_repr),
                    type_wanted=FunctionDef,
                ),
                (argparse_function_filename, False),
            )
Exemple #4
0
    def test__conform_filename_filled(self) -> None:
        """ Tests that _conform_filename returns the right result """

        with TemporaryDirectory() as tempdir:
            argparse_function_filename = os.path.realpath(
                os.path.join(tempdir, "correct_contents.py"))

            emit.file(
                argparse_func_ast,
                argparse_function_filename,
                mode="wt",
            )

            self.assertTupleEqual(
                _conform_filename(
                    filename=argparse_function_filename,
                    search=["impossibru"],
                    emit_func=emit.argparse_function,
                    replacement_node_ir=deepcopy(intermediate_repr),
                    type_wanted=FunctionDef,
                ),
                (argparse_function_filename, True),
            )
Exemple #5
0
    def ground_truth_tester(
        tempdir,
        _argparse_func_ast=argparse_func_ast,
        _class_ast=class_ast_no_default_doc,
        _class_with_method_ast=class_with_method_types_ast,
    ):
        """
        Helper for ground_truth tests

        :param tempdir: temporary directory
        :type tempdir: ```str```

        :param _argparse_func_ast: AST node
        :type _argparse_func_ast: ```FunctionDef```

        :param _class_ast: AST node
        :type _class_ast: ```ClassDef```

        :param _class_with_method_ast: AST node
        :type _class_with_method_ast: ```ClassDef```

        :returns: OrderedDict of filenames and whether they were changed, Args
        :rtype: ```Tuple[OrderedDict, Namespace]```
        """
        argparse_function = os.path.join(tempdir, "argparse.py")
        emit.file(_argparse_func_ast, argparse_function, mode="wt")

        class_ = os.path.join(tempdir, "classes.py")
        emit.file(_class_ast, class_, mode="wt")

        function = os.path.join(tempdir, "methods.py")
        emit.file(_class_with_method_ast, function, mode="wt")

        args = Namespace(
            **{
                "argparse_functions": (argparse_function, ),
                "argparse_function_names": ("set_cli_args", ),
                "classes": (class_, ),
                "class_names": ("ConfigClass", ),
                "functions": (function, ),
                "function_names": ("C.function_name", ),
                "truth": "argparse_function",
            })

        with patch("sys.stdout",
                   new_callable=StringIO), patch("sys.stderr",
                                                 new_callable=StringIO):
            return (
                ground_truth(
                    args,
                    argparse_function,
                ),
                args,
            )
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
Exemple #7
0
    def test_ground_truths(self) -> None:
        """ My truth is being tested. """

        with TemporaryDirectory() as tempdir:
            tempdir_join = partial(path.join, tempdir)

            argparse_functions = list(
                map(
                    lambda i: (lambda argparse_function: emit.file(
                        argparse_func_ast, argparse_function, mode="wt") or
                               argparse_function)
                    (tempdir_join("argparse{i}.py".format(i=i))),
                    range(10),
                ))
            # Test if can create missing file
            argparse_functions.append(tempdir_join("argparse_missing.py"))

            # Test if can fill in empty file
            argparse_functions.append(tempdir_join("argparse_empty.py"))

            class_ = tempdir_join("classes.py")
            emit.file(class_ast_no_default_doc, class_, mode="wt")

            function = tempdir_join("methods.py")
            emit.file(class_with_method_ast, function, mode="wt")

            args = Namespace(
                **{
                    "argparse_functions": argparse_functions,
                    "argparse_function_names": ("set_cli_args", ),
                    "classes": (class_, ),
                    "class_names": ("ConfigClass", ),
                    "functions": (function, ),
                    "function_names": ("C.function_name", ),
                    "truth": "argparse_function",
                })
            with patch("sys.stdout",
                       new_callable=StringIO), patch("sys.stderr",
                                                     new_callable=StringIO):
                res = ground_truth(
                    args,
                    argparse_functions[0],
                )

            self.assertTupleEqual(
                tuple(
                    map(
                        lambda filename_unmodified: (
                            os.path.basename(filename_unmodified[0]),
                            filename_unmodified[1],
                        ),
                        res.items(),
                    )),
                (
                    ("argparse0.py", False),
                    ("argparse1.py", False),
                    ("argparse2.py", False),
                    ("argparse3.py", False),
                    ("argparse4.py", False),
                    ("argparse5.py", False),
                    ("argparse6.py", False),
                    ("argparse7.py", False),
                    ("argparse8.py", False),
                    ("argparse9.py", False),
                    ("argparse_missing.py", True),
                    ("argparse_empty.py", True),
                    ("classes.py", False),
                    ("methods.py", False),
                ),
            )