From 8c7404cd9a78b93d62af5b4cb6025a5c098f2a89 Mon Sep 17 00:00:00 2001 From: Keewis Date: Sun, 16 Oct 2022 18:27:45 +0200 Subject: [PATCH 01/11] don't highlight markup text --- blackdoc/__main__.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/blackdoc/__main__.py b/blackdoc/__main__.py index d35ec61..be394fc 100644 --- a/blackdoc/__main__.py +++ b/blackdoc/__main__.py @@ -41,13 +41,15 @@ def format_and_overwrite(path, mode): if new_content == content: result = "unchanged" else: - err.print(f"reformatted {path}", style="bold white") + err.print(f"reformatted {path}", style="bold white", highlight=False) result = "reformatted" with open(path, "w", encoding=encoding, newline=newline) as f: f.write(new_content) except (black.InvalidInput, formats.InvalidFormatError) as e: - err.print(f"error: cannot format {path.absolute()}: {e}", style="red") + err.print( + f"error: cannot format {path.absolute()}: {e}", style="red", highlight=False + ) result = "error" return result @@ -65,7 +67,7 @@ def format_and_check(path, mode, diff=False, color=False): if new_content == content: result = "unchanged" else: - err.print(f"would reformat {path}", style="bold white") + err.print(f"would reformat {path}", style="bold white", highlight=False) if diff: diff_ = unified_diff(content, new_content, path) @@ -79,7 +81,9 @@ def format_and_check(path, mode, diff=False, color=False): result = "reformatted" except (black.InvalidInput, formats.InvalidFormatError) as e: - err.print(f"error: cannot format {path.absolute()}: {e}", style="red") + err.print( + f"error: cannot format {path.absolute()}: {e}", style="red", highlight=False + ) result = "error" return result @@ -200,7 +204,7 @@ def process(args): reformatted_message if return_code else no_reformatting_message, style="bold white", ) - err.print(report) + err.print(report, highlight=False) return return_code From fa11923ee19afc733c0068eae401f4e069cc28bf Mon Sep 17 00:00:00 2001 From: Keewis Date: Sun, 16 Oct 2022 18:28:23 +0200 Subject: [PATCH 02/11] don't change the color to white --- blackdoc/__main__.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/blackdoc/__main__.py b/blackdoc/__main__.py index be394fc..ac6207d 100644 --- a/blackdoc/__main__.py +++ b/blackdoc/__main__.py @@ -41,7 +41,7 @@ def format_and_overwrite(path, mode): if new_content == content: result = "unchanged" else: - err.print(f"reformatted {path}", style="bold white", highlight=False) + err.print(f"reformatted {path}", style="bold", highlight=False) result = "reformatted" with open(path, "w", encoding=encoding, newline=newline) as f: @@ -67,7 +67,7 @@ def format_and_check(path, mode, diff=False, color=False): if new_content == content: result = "unchanged" else: - err.print(f"would reformat {path}", style="bold white", highlight=False) + err.print(f"would reformat {path}", style="bold", highlight=False) if diff: diff_ = unified_diff(content, new_content, path) @@ -91,7 +91,7 @@ def format_and_check(path, mode, diff=False, color=False): def process(args): if not args.src: - err.print("No Path provided. Nothing to do :sleeping:", style="bold white") + err.print("No Path provided. Nothing to do :sleeping:", style="bold") return 0 selected_formats = getattr(args, "formats", None) @@ -157,7 +157,7 @@ def process(args): if len(sources) == 0: err.print( "No files are present to be formatted. Nothing to do :sleeping:", - style="bold white", + style="bold", ) return 0 @@ -202,7 +202,7 @@ def process(args): no_reformatting_message = "All done! :sparkles: :cake: :sparkles:" err.print( reformatted_message if return_code else no_reformatting_message, - style="bold white", + style="bold", ) err.print(report, highlight=False) return return_code From 6840a37a8bee7a18c39e9468f94d3f7e3efc17ce Mon Sep 17 00:00:00 2001 From: Keewis Date: Sun, 16 Oct 2022 18:28:49 +0200 Subject: [PATCH 03/11] use black's new-ish color-scheme: blue for non-error stats --- blackdoc/report.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/blackdoc/report.py b/blackdoc/report.py index 7227b16..3738a9b 100644 --- a/blackdoc/report.py +++ b/blackdoc/report.py @@ -5,11 +5,11 @@ def noun(n): reports = [] if n_reformatted > 0: reports.append( - f"[bold white]{n_reformatted} {noun(n_reformatted)} reformatted[/]", + f"[bold][blue]{n_reformatted} {noun(n_reformatted)}[/blue] reformatted[/]", ) if n_unchanged > 0: - reports.append(f"[white]{n_unchanged} {noun(n_unchanged)} left unchanged[/]") + reports.append(f"[blue]{n_unchanged} {noun(n_unchanged)}[/] left unchanged") if n_error > 0: reports.append(f"[red]{n_error} {noun(n_error)} fails to reformat[/]") @@ -24,12 +24,12 @@ def noun(n): reports = [] if n_reformatted > 0: reports.append( - f"[bold white]{n_reformatted} {noun(n_reformatted)} would be reformatted[/]", + f"[bold][blue]{n_reformatted} {noun(n_reformatted)}[/blue] would be reformatted[/]", ) if n_unchanged > 0: reports.append( - f"[white]{n_unchanged} {noun(n_unchanged)} would be left unchanged[/]" + f"[blue]{n_unchanged} {noun(n_unchanged)}[/] would be left unchanged" ) if n_error > 0: From d4ab18005eb4ce62205ef729f3a64f8ca14e96f8 Mon Sep 17 00:00:00 2001 From: Keewis Date: Sun, 16 Oct 2022 18:31:43 +0200 Subject: [PATCH 04/11] only set the error message to "Oh no!" if there was an error --- blackdoc/__main__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/blackdoc/__main__.py b/blackdoc/__main__.py index ac6207d..e5aaa79 100644 --- a/blackdoc/__main__.py +++ b/blackdoc/__main__.py @@ -198,10 +198,10 @@ def process(args): else: return_code = 0 - reformatted_message = "Oh no! :boom: :broken_heart: :boom:" - no_reformatting_message = "All done! :sparkles: :cake: :sparkles:" + error_message = "Oh no! :boom: :broken_heart: :boom:" + no_error_message = "All done! :sparkles: :cake: :sparkles:" err.print( - reformatted_message if return_code else no_reformatting_message, + error_message if n_error > 0 else no_error_message, style="bold", ) err.print(report, highlight=False) From 00e76cdbf3a564389e913926379ef95a0aa6127d Mon Sep 17 00:00:00 2001 From: Keewis Date: Sun, 16 Oct 2022 18:32:00 +0200 Subject: [PATCH 05/11] also don't set the color to white in the diff highlighter --- blackdoc/colors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blackdoc/colors.py b/blackdoc/colors.py index e4c6188..6a314d4 100644 --- a/blackdoc/colors.py +++ b/blackdoc/colors.py @@ -9,7 +9,7 @@ def line_style(lineno, line): if line.startswith("+++") or line.startswith("---"): - yield lineno, (0, len(line)), "bold white" + yield lineno, (0, len(line)), "bold" elif line.startswith("@@"): yield lineno, (0, len(line)), "cyan" elif line.startswith("+"): From 4d2806e6968331001d0a83614b55bf4389e2608c Mon Sep 17 00:00:00 2001 From: Keewis Date: Sun, 16 Oct 2022 18:38:12 +0200 Subject: [PATCH 06/11] print an empty line before the summary --- blackdoc/__main__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/blackdoc/__main__.py b/blackdoc/__main__.py index e5aaa79..8766812 100644 --- a/blackdoc/__main__.py +++ b/blackdoc/__main__.py @@ -200,6 +200,7 @@ def process(args): error_message = "Oh no! :boom: :broken_heart: :boom:" no_error_message = "All done! :sparkles: :cake: :sparkles:" + err.print() err.print( error_message if n_error > 0 else no_error_message, style="bold", From f8b7491b008c68d08802108622be188760ad23b9 Mon Sep 17 00:00:00 2001 From: Keewis Date: Sun, 16 Oct 2022 19:15:12 +0200 Subject: [PATCH 07/11] update the DiffHighlighter test to not expect bold white --- blackdoc/tests/test_colors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blackdoc/tests/test_colors.py b/blackdoc/tests/test_colors.py index 8c9fafb..18faef8 100644 --- a/blackdoc/tests/test_colors.py +++ b/blackdoc/tests/test_colors.py @@ -36,7 +36,7 @@ +++ file2 time2 """ ), - [Span(0, 15, "bold white"), Span(16, 31, "bold white")], + [Span(0, 15, "bold"), Span(16, 31, "bold")], id="header", ), pytest.param( From 6658b1a19b76482a7ce32422de442b18fd89f86a Mon Sep 17 00:00:00 2001 From: Keewis Date: Sun, 16 Oct 2022 19:37:19 +0200 Subject: [PATCH 08/11] add a highlighter for reports --- blackdoc/colors.py | 11 ++++++++ blackdoc/tests/test_colors.py | 52 +++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/blackdoc/colors.py b/blackdoc/colors.py index 6a314d4..51318be 100644 --- a/blackdoc/colors.py +++ b/blackdoc/colors.py @@ -52,3 +52,14 @@ def diff_styles(text): for (start, end), style in diff_styles(text.plain): text.stylize(style, start=start, end=end) + + +class FileHighlighter(Highlighter): + highlights = { + r"[0-9]+ files?(?!.*fail)": "blue", + r"^.+fail.+$": "red", + } + + def highlight(self, text): + for highlight_re, style in self.highlights.items(): + text.highlight_regex(highlight_re, style=style) diff --git a/blackdoc/tests/test_colors.py b/blackdoc/tests/test_colors.py index 18faef8..81d2b80 100644 --- a/blackdoc/tests/test_colors.py +++ b/blackdoc/tests/test_colors.py @@ -51,3 +51,55 @@ def test_diff_highlighter(text, spans): actual = diff_highlighter(text) assert actual.spans == spans + + +@pytest.mark.parametrize( + ["text", "spans"], + ( + pytest.param( + "1 file would be reformatted", + [Span(0, 6, "blue")], + id="single file conditional", + ), + pytest.param( + "1 file reformatted", + [Span(0, 6, "blue")], + id="single file", + ), + pytest.param( + "26 files would be reformatted", + [Span(0, 8, "blue")], + id="multiple files conditional", + ), + pytest.param( + "26 files reformatted", + [Span(0, 8, "blue")], + id="multiple files", + ), + pytest.param( + "1 file would fail to reformat", + [Span(0, 29, "red")], + id="failed single file conditional", + ), + pytest.param( + "1 file failed to reformat", + [Span(0, 25, "red")], + id="failed single file", + ), + pytest.param( + "15 files would fail to reformat", + [Span(0, 31, "red")], + id="failed multiple files conditional", + ), + pytest.param( + "15 files failed to reformat", + [Span(0, 27, "red")], + id="failed multiple files", + ), + ), +) +def test_file_highlighter(text, spans): + highlighter = colors.FileHighlighter() + + actual = highlighter(text) + assert actual.spans == spans From 5a5958a82483967726e46a15f92e22e01c23f26d Mon Sep 17 00:00:00 2001 From: Keewis Date: Sun, 16 Oct 2022 19:58:43 +0200 Subject: [PATCH 09/11] get the highlighter to also add the bold for reformatted --- blackdoc/colors.py | 1 + blackdoc/tests/test_colors.py | 42 ++++++++++++++++++++++++++--------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/blackdoc/colors.py b/blackdoc/colors.py index 51318be..da96f9a 100644 --- a/blackdoc/colors.py +++ b/blackdoc/colors.py @@ -57,6 +57,7 @@ def diff_styles(text): class FileHighlighter(Highlighter): highlights = { r"[0-9]+ files?(?!.*fail)": "blue", + r"^.+reformatted$": "bold", r"^.+fail.+$": "red", } diff --git a/blackdoc/tests/test_colors.py b/blackdoc/tests/test_colors.py index 81d2b80..c8b9900 100644 --- a/blackdoc/tests/test_colors.py +++ b/blackdoc/tests/test_colors.py @@ -58,43 +58,63 @@ def test_diff_highlighter(text, spans): ( pytest.param( "1 file would be reformatted", - [Span(0, 6, "blue")], - id="single file conditional", + [Span(0, 6, "blue"), Span(0, 27, "bold")], + id="single file-reformatted-conditional", ), pytest.param( "1 file reformatted", - [Span(0, 6, "blue")], - id="single file", + [Span(0, 6, "blue"), Span(0, 18, "bold")], + id="single file-reformatted", ), pytest.param( "26 files would be reformatted", - [Span(0, 8, "blue")], - id="multiple files conditional", + [Span(0, 8, "blue"), Span(0, 29, "bold")], + id="multiple files-reformatted-conditional", ), pytest.param( "26 files reformatted", + [Span(0, 8, "blue"), Span(0, 20, "bold")], + id="multiple files-reformatted", + ), + pytest.param( + "1 file would be left unchanged", + [Span(0, 6, "blue")], + id="single file-unchanged-conditional", + ), + pytest.param( + "1 file left unchanged", + [Span(0, 6, "blue")], + id="single file-unchanged", + ), + pytest.param( + "26 files would be left unchanged", + [Span(0, 8, "blue")], + id="multiple files-unchanged-conditional", + ), + pytest.param( + "26 files left unchanged", [Span(0, 8, "blue")], - id="multiple files", + id="multiple files-unchanged", ), pytest.param( "1 file would fail to reformat", [Span(0, 29, "red")], - id="failed single file conditional", + id="single file-error-conditional", ), pytest.param( "1 file failed to reformat", [Span(0, 25, "red")], - id="failed single file", + id="single file-error", ), pytest.param( "15 files would fail to reformat", [Span(0, 31, "red")], - id="failed multiple files conditional", + id="multiple files-error-conditional", ), pytest.param( "15 files failed to reformat", [Span(0, 27, "red")], - id="failed multiple files", + id="multiple files-error", ), ), ) From 77aac8b568a493860609c5c39c89a85745311826 Mon Sep 17 00:00:00 2001 From: Keewis Date: Sun, 16 Oct 2022 20:05:42 +0200 Subject: [PATCH 10/11] replace the statistics + formatting functions with a rich-aware class --- blackdoc/__main__.py | 17 +++----- blackdoc/report.py | 99 ++++++++++++++++++++++++++++---------------- 2 files changed, 69 insertions(+), 47 deletions(-) diff --git a/blackdoc/__main__.py b/blackdoc/__main__.py index 8766812..e91db61 100644 --- a/blackdoc/__main__.py +++ b/blackdoc/__main__.py @@ -11,7 +11,7 @@ from .console import err, out from .diff import unified_diff from .files import collect_files -from .report import report_changes, report_possible_changes, statistics +from .report import Report diff_highlighter = DiffHighlighter() @@ -182,18 +182,13 @@ def process(args): changed_sources = { source: action(source, mode, **action_kwargs) for source in sorted(sources) } - n_reformatted, n_unchanged, n_error = statistics(changed_sources) - report_formatters = { - "inplace": report_changes, - "check": report_possible_changes, - } - - report = report_formatters.get(args.action)(n_reformatted, n_unchanged, n_error) + conditional = args.action == "check" + report = Report.from_sources(changed_sources, conditional=conditional) - if n_error > 0: + if report.n_error > 0: return_code = 123 - elif args.action == "check" and n_reformatted > 0: + elif args.action == "check" and report.n_reformatted > 0: return_code = 1 else: return_code = 0 @@ -202,7 +197,7 @@ def process(args): no_error_message = "All done! :sparkles: :cake: :sparkles:" err.print() err.print( - error_message if n_error > 0 else no_error_message, + error_message if report.n_error > 0 else no_error_message, style="bold", ) err.print(report, highlight=False) diff --git a/blackdoc/report.py b/blackdoc/report.py index 3738a9b..c0e51da 100644 --- a/blackdoc/report.py +++ b/blackdoc/report.py @@ -1,41 +1,8 @@ -def report_changes(n_reformatted, n_unchanged, n_error): - def noun(n): - return "file" if n < 2 else "files" +from rich.text import Text - reports = [] - if n_reformatted > 0: - reports.append( - f"[bold][blue]{n_reformatted} {noun(n_reformatted)}[/blue] reformatted[/]", - ) +from .colors import FileHighlighter - if n_unchanged > 0: - reports.append(f"[blue]{n_unchanged} {noun(n_unchanged)}[/] left unchanged") - - if n_error > 0: - reports.append(f"[red]{n_error} {noun(n_error)} fails to reformat[/]") - - return ", ".join(reports) + "." - - -def report_possible_changes(n_reformatted, n_unchanged, n_error): - def noun(n): - return "file" if n < 2 else "files" - - reports = [] - if n_reformatted > 0: - reports.append( - f"[bold][blue]{n_reformatted} {noun(n_reformatted)}[/blue] would be reformatted[/]", - ) - - if n_unchanged > 0: - reports.append( - f"[blue]{n_unchanged} {noun(n_unchanged)}[/] would be left unchanged" - ) - - if n_error > 0: - reports.append(f"[red]{n_error} {noun(n_error)} would fail to reformat[/]") - - return ", ".join(reports) + "." +highlighter = FileHighlighter() def statistics(sources): @@ -51,3 +18,63 @@ def statistics(sources): raise RuntimeError(f"unknown results: {statistics.keys()}") return n_reformatted, n_unchanged, n_error + + +def noun(n): + return "file" if n < 2 else "files" + + +class Report: + def __init__(self, n_reformatted, n_unchanged, n_error, conditional=False): + self.n_reformatted = n_reformatted + self.n_unchanged = n_unchanged + self.n_error = n_error + + self.conditional = conditional + + @classmethod + def from_sources(cls, sources, conditional=False): + n_reformatted, n_unchanged, n_error = statistics(sources) + + return cls(n_reformatted, n_unchanged, n_error, conditional=conditional) + + def __repr__(self): + params = [ + f"{name}={getattr(self, name)}" + for name in ["n_reformatted", "n_unchanged", "n_error", "conditional"] + ] + return f"Report({', '.join(params)})" + + @property + def _reformatted_report(self): + if self.conditional: + return ( + f"{self.n_reformatted} {noun(self.n_reformatted)} would be reformatted" + ) + else: + return f"{self.n_reformatted} {noun(self.n_reformatted)} reformatted" + + @property + def _unchanged_report(self): + if self.conditional: + return ( + f"{self.n_unchanged} {noun(self.n_unchanged)} would be left unchanged" + ) + else: + return f"{self.n_unchanged} {noun(self.n_unchanged)} left unchanged" + + @property + def _error_report(self): + if self.conditional: + return f"{self.n_error} {noun(self.n_error)} would fail to reformat" + else: + return f"{self.n_error} {noun(self.n_error)} failed to reformat" + + def __rich__(self): + raw_parts = [ + self._reformatted_report, + self._unchanged_report, + self._error_report, + ] + parts = [highlighter(part) for part in raw_parts] + return Text(", ").join(parts) + Text(".") From 31f5b17c05c2bd23e85c3d36184fee7d5555dbd7 Mon Sep 17 00:00:00 2001 From: Keewis Date: Sun, 16 Oct 2022 20:10:00 +0200 Subject: [PATCH 11/11] changelog --- doc/changelog.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changelog.rst b/doc/changelog.rst index 2c4600c..6871462 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -6,7 +6,7 @@ v0.3.8 (*unreleased*) - drop support for ``python=3.6`` (:pull:`153`) - split chained statements into multiple ``doctest`` lines (:issue:`143`, :pull:`155`, :pull:`158`) - replace the custom color formatting code with `rich `_ - (:issue:`146`, :pull:`157`). + (:issue:`146`, :pull:`157`, :pull:`159`). v0.3.7 (13 September 2022) --------------------------