""" Summarize Black runs to users. """ from dataclasses import dataclass from enum import Enum from pathlib import Path from click import style from black.output import out, err class Changed(Enum): NO = 0 CACHED = 1 YES = 2 class NothingChanged(UserWarning): """Raised when reformatted code is the same as source.""" @dataclass class Report: """Provides a reformatting counter. Can be rendered with `str(report)`.""" check: bool = False diff: bool = False quiet: bool = False verbose: bool = False change_count: int = 0 same_count: int = 0 failure_count: int = 0 def done(self, src: Path, changed: Changed) -> None: """Increment the counter for successful reformatting. Write out a message.""" if changed is Changed.YES: reformatted = "would reformat" if self.check or self.diff else "reformatted" if self.verbose or not self.quiet: out(f"{reformatted} {src}") self.change_count += 1 else: if self.verbose: if changed is Changed.NO: msg = f"{src} already well formatted, good job." else: msg = f"{src} wasn't modified on disk since last run." out(msg, bold=False) self.same_count += 1 def failed(self, src: Path, message: str) -> None: """Increment the counter for failed reformatting. Write out a message.""" err(f"error: cannot format {src}: {message}") self.failure_count += 1 def path_ignored(self, path: Path, message: str) -> None: if self.verbose: out(f"{path} ignored: {message}", bold=False) @property def return_code(self) -> int: """Return the exit code that the app should use. This considers the current state of changed files and failures: - if there were any failures, return 123; - if any files were changed and --check is being used, return 1; - otherwise return 0. """ # According to http://tldp.org/LDP/abs/html/exitcodes.html starting with # 126 we have special return codes reserved by the shell. if self.failure_count: return 123 elif self.change_count and self.check: return 1 return 0 def __str__(self) -> str: """Render a color report of the current state. Use `click.unstyle` to remove colors. """ if self.check or self.diff: reformatted = "would be reformatted" unchanged = "would be left unchanged" failed = "would fail to reformat" else: reformatted = "reformatted" unchanged = "left unchanged" failed = "failed to reformat" report = [] if self.change_count: s = "s" if self.change_count > 1 else "" report.append( style(f"{self.change_count} file{s} {reformatted}", bold=True) ) if self.same_count: s = "s" if self.same_count > 1 else "" report.append(f"{self.same_count} file{s} {unchanged}") if self.failure_count: s = "s" if self.failure_count > 1 else "" report.append(style(f"{self.failure_count} file{s} {failed}", fg="red")) return ", ".join(report) + "."