def blackify(content: str, file_path: Path) -> str: """ Format `content` with `black` if `file_path` is `*.py` or `*.pyi`. On error writes invalid `content` to `file_path` to check for errors. Arguments: content -- Python code to format. file_path -- Target file path. Returns: Formatted python code. Raises: ValueError -- If `content` is not a valid Python code. """ if file_path.suffix not in (".py", ".pyi"): return content file_mode = Mode(is_pyi=file_path.suffix == ".pyi", line_length=LINE_LENGTH, preview=True) try: content = format_file_contents(content, fast=True, mode=file_mode) except NothingChanged: pass except (IndentationError, InvalidInput) as e: if not file_path.parent.exists(): file_path.parent.mkdir(exist_ok=True, parents=True) file_path.write_text(content) raise ValueError(f"Cannot parse {file_path}: {e}") from e return content
def test_get_cache_key() -> None: result = Mode( indentation="\t", tab_width=4, keep_blank_lines_in_brackets=True, split_subscripts=False, ).get_cache_key() expected = "-.1.4.88.1.0.0.1.0.1.0.0.d41d8cd98f00b204e9800998ecf8427e" assert result == expected
def main( ctx: click.Context, code: Optional[str], line_length: int, target_version: List[TargetVersion], check: bool, diff: bool, color: bool, fast: bool, pyi: bool, ipynb: bool, skip_string_normalization: bool, skip_magic_trailing_comma: bool, experimental_string_processing: bool, quiet: bool, verbose: bool, required_version: Optional[str], include: Pattern[str], exclude: Optional[Pattern[str]], extend_exclude: Optional[Pattern[str]], force_exclude: Optional[Pattern[str]], stdin_filename: Optional[str], workers: int, src: Tuple[str, ...], config: Optional[str], ) -> None: """The uncompromising code formatter.""" if config and verbose: out(f"Using configuration from {config}.", bold=False, fg="blue") error_msg = "Oh no! 💥 💔 💥" if required_version and required_version != __version__: err(f"{error_msg} The required version `{required_version}` does not match" f" the running version `{__version__}`!") ctx.exit(1) if ipynb and pyi: err("Cannot pass both `pyi` and `ipynb` flags!") ctx.exit(1) write_back = WriteBack.from_configuration(check=check, diff=diff, color=color) if target_version: versions = set(target_version) else: # We'll autodetect later. versions = set() mode = Mode( target_versions=versions, line_length=line_length, is_pyi=pyi, is_ipynb=ipynb, string_normalization=not skip_string_normalization, magic_trailing_comma=not skip_magic_trailing_comma, experimental_string_processing=experimental_string_processing, ) if code is not None: # Run in quiet mode by default with -c; the extra output isn't useful. # You can still pass -v to get verbose output. quiet = True report = Report(check=check, diff=diff, quiet=quiet, verbose=verbose) if code is not None: reformat_code(content=code, fast=fast, write_back=write_back, mode=mode, report=report) else: try: sources = get_sources( ctx=ctx, src=src, quiet=quiet, verbose=verbose, include=include, exclude=exclude, extend_exclude=extend_exclude, force_exclude=force_exclude, report=report, stdin_filename=stdin_filename, ) except GitWildMatchPatternError: ctx.exit(1) path_empty( sources, "No Python files are present to be formatted. Nothing to do 😴", quiet, verbose, ctx, ) if len(sources) == 1: reformat_one( src=sources.pop(), fast=fast, write_back=write_back, mode=mode, report=report, ) else: reformat_many( sources=sources, fast=fast, write_back=write_back, mode=mode, report=report, workers=workers, ) if verbose or not quiet: out(error_msg if report.return_code else "All done! ✨ 🍰 ✨") if code is None: click.echo(str(report), err=True) ctx.exit(report.return_code)
def main( # noqa: C901 ctx: click.Context, code: Optional[str], line_length: int, target_version: List[TargetVersion], check: bool, diff: bool, color: bool, fast: bool, pyi: bool, ipynb: bool, python_cell_magics: Sequence[str], skip_string_normalization: bool, skip_magic_trailing_comma: bool, experimental_string_processing: bool, preview: bool, quiet: bool, verbose: bool, required_version: Optional[str], include: Pattern[str], exclude: Optional[Pattern[str]], extend_exclude: Optional[Pattern[str]], force_exclude: Optional[Pattern[str]], stdin_filename: Optional[str], workers: int, src: Tuple[str, ...], config: Optional[str], ) -> None: """The uncompromising code formatter.""" ctx.ensure_object(dict) if src and code is not None: out( main.get_usage(ctx) + "\n\n'SRC' and 'code' cannot be passed simultaneously.") ctx.exit(1) if not src and code is None: out(main.get_usage(ctx) + "\n\nOne of 'SRC' or 'code' is required.") ctx.exit(1) root, method = find_project_root(src) if code is None else (None, None) ctx.obj["root"] = root if verbose: if root: out( f"Identified `{root}` as project root containing a {method}.", fg="blue", ) normalized = [(normalize_path_maybe_ignore(Path(source), root), source) for source in src] srcs_string = ", ".join([ f'"{_norm}"' if _norm else f'\033[31m"{source} (skipping - invalid)"\033[34m' for _norm, source in normalized ]) out(f"Sources to be formatted: {srcs_string}", fg="blue") if config: config_source = ctx.get_parameter_source("config") user_level_config = str(find_user_pyproject_toml()) if config == user_level_config: out( "Using configuration from user-level config at " f"'{user_level_config}'.", fg="blue", ) elif config_source in ( ParameterSource.DEFAULT, ParameterSource.DEFAULT_MAP, ): out("Using configuration from project root.", fg="blue") else: out(f"Using configuration in '{config}'.", fg="blue") error_msg = "Oh no! 💥 💔 💥" if (required_version and required_version != __version__ and required_version != __version__.split(".")[0]): err(f"{error_msg} The required version `{required_version}` does not match" f" the running version `{__version__}`!") ctx.exit(1) if ipynb and pyi: err("Cannot pass both `pyi` and `ipynb` flags!") ctx.exit(1) write_back = WriteBack.from_configuration(check=check, diff=diff, color=color) if target_version: versions = set(target_version) else: # We'll autodetect later. versions = set() mode = Mode( target_versions=versions, line_length=line_length, is_pyi=pyi, is_ipynb=ipynb, string_normalization=not skip_string_normalization, magic_trailing_comma=not skip_magic_trailing_comma, experimental_string_processing=experimental_string_processing, preview=preview, python_cell_magics=set(python_cell_magics), ) if code is not None: # Run in quiet mode by default with -c; the extra output isn't useful. # You can still pass -v to get verbose output. quiet = True report = Report(check=check, diff=diff, quiet=quiet, verbose=verbose) if code is not None: reformat_code(content=code, fast=fast, write_back=write_back, mode=mode, report=report) else: try: sources = get_sources( ctx=ctx, src=src, quiet=quiet, verbose=verbose, include=include, exclude=exclude, extend_exclude=extend_exclude, force_exclude=force_exclude, report=report, stdin_filename=stdin_filename, ) except GitWildMatchPatternError: ctx.exit(1) path_empty( sources, "No Python files are present to be formatted. Nothing to do 😴", quiet, verbose, ctx, ) if len(sources) == 1: reformat_one( src=sources.pop(), fast=fast, write_back=write_back, mode=mode, report=report, ) else: reformat_many( sources=sources, fast=fast, write_back=write_back, mode=mode, report=report, workers=workers, ) if verbose or not quiet: if code is None and (verbose or report.change_count or report.failure_count): out() out(error_msg if report.return_code else "All done! ✨ 🍰 ✨") if code is None: click.echo(str(report), err=True) ctx.exit(report.return_code)
def main( ctx: click.Context, code: Optional[str], line_length: int, target_version: List[TargetVersion], check: bool, diff: bool, color: bool, fast: bool, pyi: bool, skip_string_normalization: bool, skip_magic_trailing_comma: bool, experimental_string_processing: bool, quiet: bool, verbose: bool, include: Pattern, exclude: Optional[Pattern], extend_exclude: Optional[Pattern], force_exclude: Optional[Pattern], stdin_filename: Optional[str], src: Tuple[str, ...], config: Optional[str], ) -> None: """The uncompromising code formatter.""" write_back = WriteBack.from_configuration(check=check, diff=diff, color=color) if target_version: versions = set(target_version) else: # We'll autodetect later. versions = set() mode = Mode( target_versions=versions, line_length=line_length, is_pyi=pyi, string_normalization=not skip_string_normalization, magic_trailing_comma=not skip_magic_trailing_comma, experimental_string_processing=experimental_string_processing, ) if config and verbose: out(f"Using configuration from {config}.", bold=False, fg="blue") if code is not None: print(format_str(code, mode=mode)) ctx.exit(0) report = Report(check=check, diff=diff, quiet=quiet, verbose=verbose) sources = get_sources( ctx=ctx, src=src, quiet=quiet, verbose=verbose, include=include, exclude=exclude, extend_exclude=extend_exclude, force_exclude=force_exclude, report=report, stdin_filename=stdin_filename, ) path_empty( sources, "No Python files are present to be formatted. Nothing to do 😴", quiet, verbose, ctx, ) if len(sources) == 1: reformat_one( src=sources.pop(), fast=fast, write_back=write_back, mode=mode, report=report, ) else: reformat_many(sources=sources, fast=fast, write_back=write_back, mode=mode, report=report) if verbose or not quiet: out("Oh no! 💥 💔 💥" if report.return_code else "All done! ✨ 🍰 ✨") click.secho(str(report), err=True) ctx.exit(report.return_code)
def test_use_tabs(indentation: str, expected: bool) -> None: result = Mode(indentation=indentation).use_tabs assert result == expected