Exemplo n.º 1
0
def test_map_python_line_to_nb_lines() -> None:
    """Check that the output is correctly parsed if there is a warning about line 0."""
    out = "notebook.ipynb:0:1: WPS102 Found incorrect module name pattern"
    err = ""
    notebook = "notebook.ipynb"
    cell_mapping = {0: "cell_0:0"}
    result, _ = map_python_line_to_nb_lines("flake8", out, err, notebook,
                                            cell_mapping)
    expected = "notebook.ipynb:cell_0:0:1: WPS102 Found incorrect module name pattern"
    assert result == expected
Exemplo n.º 2
0
def test_black_unparseable_output() -> None:
    """Check that the output is correctly parsed if ``black`` fails to reformat."""
    out = ""
    err = dedent("""\
        error: cannot format notebook.ipynb: Cannot parse: 38:5: invalid syntax
        Oh no! 💥 💔 💥
        1 file failed to reformat.
        """)
    notebook = "notebook.ipynb"
    cell_mapping = {38: "cell_10:1"}
    _, result = map_python_line_to_nb_lines("black", out, err, notebook,
                                            cell_mapping)
    expected = dedent("""\
        error: cannot format notebook.ipynb: Cannot parse: cell_10:1:5: invalid syntax
        Oh no! 💥 💔 💥
        1 file failed to reformat.
        """)
    assert result == expected
Exemplo n.º 3
0
def _run_on_one_root_dir(cli_args: CLIArgs, configs: Configs,
                         project_root: Path) -> int:
    """
    Run third-party tool on a single notebook or directory.

    Parameters
    ----------
    cli_args
        Commanline arguments passed to nbqa.
    configs
        Configuration passed to nbqa from commandline or via a config file
    project_root
        Root of repository, where .git / .hg / .nbqa.ini file is.

    Returns
    -------
    int
        Output code from third-party tool.

    Raises
    ------
    RuntimeError
        If unable to parse or reconstruct notebook.
    SystemExit
        If third-party tool would've reformatted notebook but ``--nbqa-mutate``
        wasn't passed.
    """
    with tempfile.TemporaryDirectory() as tmpdirname:

        nb_to_py_mapping = {
            notebook: _temp_python_file_for_notebook(notebook, tmpdirname,
                                                     project_root)
            for notebook in _get_all_notebooks(
                cli_args.root_dirs, configs.nbqa_files, configs.nbqa_exclude)
        }

        if not nb_to_py_mapping:
            sys.stderr.write(
                "No .ipynb notebooks found in given directories: "
                f"{' '.join(i for i in cli_args.root_dirs if Path(i).is_dir())}\n"
            )
            return 0

        config_files = ([configs.nbqa_config] if configs.nbqa_config else
                        CONFIG_FILES[cli_args.command])
        _preserve_config_files(config_files, tmpdirname, project_root)

        nb_info_mapping: MutableMapping[Path, NotebookInfo] = {}

        for notebook, temp_python_file in nb_to_py_mapping.items():
            try:
                nb_info_mapping[notebook] = save_source.main(
                    notebook,
                    temp_python_file,
                    configs.nbqa_process_cells,
                    cli_args.command,
                )
            except Exception as exc:
                raise RuntimeError(
                    BASE_ERROR_MESSAGE.format(
                        f"Error parsing {str(notebook)}")) from exc

            _create_blank_init_files(notebook, tmpdirname, project_root)

        out, err, output_code, mutated = _run_command(
            cli_args.command,
            tmpdirname,
            configs.nbqa_addopts,
            _get_all_args(cli_args.root_dirs, tmpdirname, nb_to_py_mapping,
                          project_root),
        )

        for notebook, temp_python_file in nb_to_py_mapping.items():
            out, err = _replace_temp_python_file_references_in_out_err(
                tmpdirname, temp_python_file, notebook, out, err)
            try:
                out, err = map_python_line_to_nb_lines(
                    cli_args.command,
                    out,
                    err,
                    notebook,
                    nb_info_mapping[notebook].cell_mappings,
                )
            except Exception as exc:  # pylint: disable=W0703
                msg = (f"{repr(exc)} while parsing output "
                       f"from applying {cli_args.command} to {str(notebook)}")
                sys.stderr.write(BASE_ERROR_MESSAGE.format(msg))

            if mutated:
                if not configs.nbqa_mutate and not configs.nbqa_diff:
                    # pylint: disable=C0301
                    msg = dedent(f"""\
                        {BOLD}Mutation detected, will not reformat! Please use the `--nbqa-mutate` flag, e.g.:{RESET}

                            nbqa {cli_args.command} notebook.ipynb --nbqa-mutate

                        or, to only preview changes, use the `--nbqa-diff` flag, e.g.:

                            nbqa {cli_args.command} notebook.ipynb --nbqa-diff
                        """)
                    # pylint: enable=C0301
                    raise SystemExit(msg)

                try:
                    REPLACE_FUNCTION[configs.nbqa_diff](
                        temp_python_file,
                        notebook,
                        nb_info_mapping[notebook],
                    )
                except Exception as exc:
                    raise RuntimeError(
                        BASE_ERROR_MESSAGE.format(
                            f"Error reconstructing {str(notebook)}")) from exc

        sys.stdout.write(out)
        sys.stderr.write(err)

        if configs.nbqa_diff:
            if mutated:
                sys.stdout.write(
                    "To apply these changes use `--nbqa-mutate` instead of `--nbqa-diff`\n"
                )
            return output_code

    return output_code
Exemplo n.º 4
0
def _main(  # pylint: disable=R0912,R0914,R0911
    cli_args: CLIArgs, configs: Configs
) -> int:
    """
    Run third-party tool on a single notebook or directory.

    Parameters
    ----------
    cli_args
        Commanline arguments passed to nbqa.
    configs
        Configuration passed to nbqa from commandline or via a config file

    Returns
    -------
    int
        Output code from third-party tool.
    """
    try:
        nb_to_py_mapping = _get_nb_to_py_mapping(
            cli_args.root_dirs, configs.nbqa_files, configs.nbqa_exclude
        )
    except FileNotFoundError as exc:
        sys.stderr.write(str(exc))
        return 1

    try:  # pylint disable=R0912

        if not nb_to_py_mapping:
            sys.stderr.write(
                "No .ipynb notebooks found in given directories: "
                f"{' '.join(i for i in cli_args.root_dirs if os.path.isdir(i))}\n"
            )
            return 0

        nb_info_mapping: MutableMapping[str, NotebookInfo] = {}

        for notebook, (file_descriptor, _) in nb_to_py_mapping.items():
            try:
                nb_info_mapping[notebook] = save_source.main(
                    notebook,
                    file_descriptor,
                    configs.nbqa_process_cells,
                    cli_args.command,
                )
            except Exception as exp:  # pylint: disable=W0703
                sys.stderr.write(
                    BASE_ERROR_MESSAGE.format(f"Error parsing {notebook}: {repr(exp)}")
                )
                return 1

        output, output_code, mutated = _run_command(
            cli_args.command,
            configs.nbqa_addopts,
            [i.file for i in nb_to_py_mapping.values()],
        )

        actually_mutated = False
        for notebook, (_, temp_python_file) in nb_to_py_mapping.items():
            output = _replace_temp_python_file_references_in_out_err(
                temp_python_file, notebook, output.out, output.err
            )
            output = map_python_line_to_nb_lines(
                cli_args.command,
                output.out,
                output.err,
                notebook,
                nb_info_mapping[notebook].cell_mappings,
            )

            if mutated:
                if not configs.nbqa_mutate and not configs.nbqa_diff:
                    # pylint: disable=C0301
                    msg = dedent(
                        f"""\
                        {BOLD}Mutation detected, will not reformat! Please use the `--nbqa-mutate` flag, e.g.:{RESET}

                            nbqa {cli_args.command} notebook.ipynb --nbqa-mutate

                        or, to only preview changes, use the `--nbqa-diff` flag, e.g.:

                            nbqa {cli_args.command} notebook.ipynb --nbqa-diff
                        """
                    )
                    # pylint: enable=C0301
                    sys.stderr.write(msg)
                    return 1

                try:
                    actually_mutated = (
                        REPLACE_FUNCTION[configs.nbqa_diff](
                            temp_python_file,
                            notebook,
                            nb_info_mapping[notebook],
                        )
                        or actually_mutated
                    )
                except Exception as exp:  # pylint: disable=W0703
                    sys.stderr.write(
                        BASE_ERROR_MESSAGE.format(
                            f"Error reconstructing {notebook}: {repr(exp)}"
                        )
                    )
                    return 1

        sys.stdout.write(output.out)
        sys.stderr.write(output.err)

        if mutated and not actually_mutated:
            output_code = 0
            mutated = False

        if configs.nbqa_diff:
            if mutated:
                sys.stdout.write(
                    "To apply these changes use `--nbqa-mutate` instead of `--nbqa-diff`\n"
                )
            return output_code

    finally:
        _clean_up_tmp_files(nb_to_py_mapping)
    return output_code
Exemplo n.º 5
0
def _main(  # pylint: disable=R0912,R0914,R0911
    cli_args: CLIArgs, configs: Configs
) -> int:
    """
    Run third-party tool on a single notebook or directory.

    Parameters
    ----------
    cli_args
        Commanline arguments passed to nbqa.
    configs
        Configuration passed to nbqa from commandline or via a config file

    Returns
    -------
    int
        Output code from third-party tool.
    """
    try:
        nb_to_py_mapping = _get_nb_to_py_mapping(
            cli_args.root_dirs, configs.nbqa_files, configs.nbqa_exclude
        )
    except FileNotFoundError as exc:
        sys.stderr.write(str(exc))
        return 1

    failed_notebooks = {}
    try:  # pylint disable=R0912

        if not nb_to_py_mapping:
            sys.stderr.write(
                "No .ipynb notebooks found in given directories: "
                f"{' '.join(i for i in cli_args.root_dirs if os.path.isdir(i))}\n"
            )
            return 0

        nb_info_mapping: MutableMapping[str, NotebookInfo] = {}

        for notebook, (file_descriptor, _) in nb_to_py_mapping.items():
            try:
                nb_info_mapping[notebook] = save_source.main(
                    notebook,
                    file_descriptor,
                    configs.nbqa_process_cells,
                    cli_args.command,
                    skip_bad_cells=configs.nbqa_skip_cells,
                )
            except Exception as exp_repr:  # pylint: disable=W0703
                failed_notebooks[notebook] = repr(exp_repr)

        if len(failed_notebooks) == len(nb_to_py_mapping):
            sys.stderr.write("No valid .ipynb notebooks found\n")
            return 123

        output, output_code, mutated = _run_command(
            cli_args.command,
            configs.nbqa_addopts,
            [
                i.file
                for key, i in nb_to_py_mapping.items()
                if key not in failed_notebooks
            ],
        )

        actually_mutated = False
        for notebook, (_, temp_python_file) in nb_to_py_mapping.items():
            if notebook in failed_notebooks:
                continue
            output = _replace_temp_python_file_references_in_out_err(
                temp_python_file, notebook, output.out, output.err
            )
            output = map_python_line_to_nb_lines(
                cli_args.command,
                output.out,
                output.err,
                notebook,
                nb_info_mapping[notebook].cell_mappings,
            )

            if mutated:
                if not configs.nbqa_mutate and not configs.nbqa_diff:
                    # pylint: disable=C0301
                    msg = dedent(
                        f"""\
                        {BOLD}Mutation detected, will not reformat! Please use the `--nbqa-mutate` flag, e.g.:{RESET}

                            nbqa {cli_args.command} notebook.ipynb --nbqa-mutate

                        or, to only preview changes, use the `--nbqa-diff` flag, e.g.:

                            nbqa {cli_args.command} notebook.ipynb --nbqa-diff
                        """
                    )
                    # pylint: enable=C0301
                    sys.stderr.write(msg)
                    return 1

                try:
                    actually_mutated = (
                        REPLACE_FUNCTION[configs.nbqa_diff](
                            temp_python_file,
                            notebook,
                            nb_info_mapping[notebook],
                        )
                        or actually_mutated
                    )
                except Exception as exp_repr:  # pylint: disable=W0703
                    failed_notebooks[notebook] = repr(exp_repr)

        sys.stdout.write(output.out)
        sys.stderr.write(output.err)

        if mutated and not actually_mutated:
            output_code = 0
            mutated = False

        if failed_notebooks:
            output_code = 123
            sys.stderr.write("\n")
            # https://github.com/python/mypy/issues/5080
            for failure, exp_repr in failed_notebooks.items():  # type: ignore
                sys.stderr.write(
                    BASE_ERROR_MESSAGE.format(notebook=failure, exp=exp_repr)  # type: ignore
                )
            sys.stderr.write(
                f"{BOLD}\n"
                "If you believe the notebook(s) to be valid, please "
                f"report a bug at https://github.com/nbQA-dev/nbQA/issues {RESET}\n"
            )
            sys.stderr.write("\n")

        if configs.nbqa_diff:
            if mutated:
                sys.stdout.write(
                    "To apply these changes use `--nbqa-mutate` instead of `--nbqa-diff`\n"
                )
            return output_code

    finally:
        _clean_up_tmp_files(nb_to_py_mapping)
    return output_code