From a86be0fe565b4c92638ffeb9d12131447858c7ea Mon Sep 17 00:00:00 2001 From: Joshua Date: Fri, 9 Jun 2023 10:41:58 -0500 Subject: [PATCH 1/9] ansicolors --- .../backend/python/typecheck/mypy/rules.py | 2 +- src/python/pants/core/goals/check.py | 5 +- .../pants/core/goals/generate_lockfiles.py | 28 ++++---- .../pants/core/goals/update_build_files.py | 3 +- src/python/pants/engine/console.py | 3 +- src/python/pants/help/maybe_color.py | 10 +-- src/python/pants/util/colors.py | 65 +++++++++++++++++++ 7 files changed, 86 insertions(+), 30 deletions(-) create mode 100644 src/python/pants/util/colors.py diff --git a/src/python/pants/backend/python/typecheck/mypy/rules.py b/src/python/pants/backend/python/typecheck/mypy/rules.py index c57f1cba178..a877cec7907 100644 --- a/src/python/pants/backend/python/typecheck/mypy/rules.py +++ b/src/python/pants/backend/python/typecheck/mypy/rules.py @@ -312,7 +312,7 @@ async def mypy_typecheck_partition( "MYPY_FORCE_COLOR": "1", # Mypy needs to know the terminal so it can use appropriate escape sequences. ansi is a # reasonable lowest common denominator for the sort of escapes mypy uses (NB. TERM=xterm - # uses some additional codes that colors.strip_color doesn't remove). + # uses some additional codes that pants.util.strip_color doesn't remove). "TERM": "ansi", # Force a fixed terminal width. This is effectively infinite, disabling mypy's # builtin truncation and line wrapping. Terminals do an acceptable job of soft-wrapping diff --git a/src/python/pants/core/goals/check.py b/src/python/pants/core/goals/check.py index 77150b1dff2..f7cfbe82c60 100644 --- a/src/python/pants/core/goals/check.py +++ b/src/python/pants/core/goals/check.py @@ -8,8 +8,6 @@ from dataclasses import dataclass from typing import Any, ClassVar, Generic, Iterable, TypeVar, cast -import colors - from pants.core.goals.lint import REPORT_DIR as REPORT_DIR # noqa: F401 from pants.core.goals.multi_tool_goal_helper import ( OnlyOption, @@ -28,6 +26,7 @@ from pants.engine.rules import Get, MultiGet, QueryRule, collect_rules, goal_rule from pants.engine.target import FieldSet, FilteredTargets from pants.engine.unions import UnionMembership, union +from pants.util.colors import strip_color from pants.util.logging import LogLevel from pants.util.memo import memoized_property from pants.util.meta import classproperty @@ -57,7 +56,7 @@ def from_fallible_process_result( ) -> CheckResult: def prep_output(s: bytes) -> str: chroot = strip_v2_chroot_path(s) if strip_chroot_path else s.decode() - formatting = cast(str, colors.strip_color(chroot)) if strip_formatting else chroot + formatting = strip_color(chroot) if strip_formatting else chroot return formatting return CheckResult( diff --git a/src/python/pants/core/goals/generate_lockfiles.py b/src/python/pants/core/goals/generate_lockfiles.py index 64e42094345..8a9e452154f 100644 --- a/src/python/pants/core/goals/generate_lockfiles.py +++ b/src/python/pants/core/goals/generate_lockfiles.py @@ -218,25 +218,25 @@ def print(self, diff: LockfileDiff) -> None: if not output: return self.console.print_stderr( - self.style(" " * 66, style="underline") + self.style(" " * 66, underline=True) + f"\nLockfile diff: {diff.path} [{diff.resolve_name}]\n" + output ) def output_sections(self, diff: LockfileDiff) -> Iterator[str]: if self.include_unchanged: - yield from self.output_reqs("Unchanged dependencies", diff.unchanged, fg="blue") + yield from self.output_reqs("Unchanged dependencies", diff.unchanged, color="blue") yield from self.output_changed("Upgraded dependencies", diff.upgraded) yield from self.output_changed("!! Downgraded dependencies !!", diff.downgraded) - yield from self.output_reqs("Added dependencies", diff.added, fg="green", style="bold") - yield from self.output_reqs("Removed dependencies", diff.removed, fg="magenta") + yield from self.output_reqs("Added dependencies", diff.added, color="green", bold=True) + yield from self.output_reqs("Removed dependencies", diff.removed, color="magenta") - def style(self, text: str, **kwargs) -> str: - return cast(str, self.maybe_color(text, **kwargs)) + def style(self, text: str, *, color: str, **kwargs) -> str: + return cast(str, getattr(self, color)(text, **kwargs)) def title(self, text: str) -> str: heading = f"== {text:^60} ==" - return self.style("\n".join((" " * len(heading), heading, "")), style="underline") + return self.style("\n".join((" " * len(heading), heading, "")), underline=True) def output_reqs(self, heading: str, reqs: LockfilePackages, **kwargs) -> Iterator[str]: if not reqs: @@ -244,7 +244,7 @@ def output_reqs(self, heading: str, reqs: LockfilePackages, **kwargs) -> Iterato yield self.title(heading) for name, version in reqs.items(): - name_s = self.style(f"{name:30}", fg="yellow") + name_s = self.style(f"{name:30}", color="yellow") version_s = self.style(str(version), **kwargs) yield f" {name_s} {version_s}" @@ -256,18 +256,18 @@ def output_changed(self, title: str, reqs: ChangedPackages) -> Iterator[str]: label = "-->" for name, (prev, curr) in reqs.items(): bump_attrs = self.get_bump_attrs(prev, curr) - name_s = self.style(f"{name:30}", fg="yellow") - prev_s = self.style(f"{str(prev):10}", fg="cyan") + name_s = self.style(f"{name:30}", color="yellow") + prev_s = self.style(f"{str(prev):10}", color="cyan") bump_s = self.style(f"{label:^7}", **bump_attrs) curr_s = self.style(str(curr), **bump_attrs) yield f" {name_s} {prev_s} {bump_s} {curr_s}" _BUMPS = ( - ("major", dict(fg="red", style="bold")), - ("minor", dict(fg="yellow")), - ("micro", dict(fg="green")), + ("major", dict(color="red", bold=True)), + ("minor", dict(color="yellow")), + ("micro", dict(color="green")), # Default style - (None, dict(fg="magenta")), + (None, dict(color="magenta")), ) def get_bump_attrs(self, prev: PackageVersion, curr: PackageVersion) -> dict[str, str]: diff --git a/src/python/pants/core/goals/update_build_files.py b/src/python/pants/core/goals/update_build_files.py index d65d2a6707d..43316e7e1ca 100644 --- a/src/python/pants/core/goals/update_build_files.py +++ b/src/python/pants/core/goals/update_build_files.py @@ -13,8 +13,6 @@ from io import BytesIO from typing import DefaultDict, cast -from colors import green, red - from pants.backend.build_files.fix.deprecations import renamed_fields_rules, renamed_targets_rules from pants.backend.build_files.fix.deprecations.base import FixedBUILDFile from pants.backend.build_files.fmt.black.register import BlackRequest @@ -47,6 +45,7 @@ from pants.engine.rules import Get, MultiGet, collect_rules, goal_rule, rule from pants.engine.unions import UnionMembership, UnionRule, union from pants.option.option_types import BoolOption, EnumOption +from pants.util.colors import green, red from pants.util.docutil import bin_name, doc_url from pants.util.logging import LogLevel from pants.util.memo import memoized diff --git a/src/python/pants/engine/console.py b/src/python/pants/engine/console.py index 411b7b269aa..69f2a346f54 100644 --- a/src/python/pants/engine/console.py +++ b/src/python/pants/engine/console.py @@ -5,10 +5,9 @@ import sys from typing import Callable, TextIO -from colors import blue, cyan, green, magenta, red, yellow - from pants.engine.engine_aware import SideEffecting from pants.engine.internals.scheduler import SchedulerSession +from pants.util.colors import blue, cyan, green, magenta, red, yellow class Console(SideEffecting): diff --git a/src/python/pants/help/maybe_color.py b/src/python/pants/help/maybe_color.py index ee96a4287a1..393533136ed 100644 --- a/src/python/pants/help/maybe_color.py +++ b/src/python/pants/help/maybe_color.py @@ -3,12 +3,7 @@ from typing import List -from colors import color as ansicolor -from colors import cyan, green, magenta, red, yellow - - -def _orange(s: str, **kwargs): - return ansicolor(s, "orange", **kwargs) +from pants.util.colors import cyan, green, magenta, orange, red, yellow class MaybeColor: @@ -20,10 +15,9 @@ def __init__(self, color: bool) -> None: def noop(x, **_): return x - self.maybe_color = ansicolor if color else noop self.maybe_cyan = cyan if color else noop self.maybe_green = green if color else noop - self.maybe_orange = _orange if color else noop + self.maybe_orange = orange if color else noop self.maybe_red = red if color else noop self.maybe_magenta = magenta if color else noop self.maybe_yellow = yellow if color else noop diff --git a/src/python/pants/util/colors.py b/src/python/pants/util/colors.py new file mode 100644 index 00000000000..ed579cbada3 --- /dev/null +++ b/src/python/pants/util/colors.py @@ -0,0 +1,65 @@ +# Copyright 2023 Pants project contributors (see CONTRIBUTORS.md). +# Licensed under the Apache License, Version 2.0 (see LICENSE). +# See https://en.wikipedia.org/wiki/ANSI_escape_code#24-bit + +import functools +import re +from typing import Callable + +from typing_extensions import ParamSpec + + +def strip_color(s: str) -> str: + """Remove ANSI color/style sequences from a string.""" + return re.sub("\x1b\\[(.*?m)", "", s) + + +_P = ParamSpec("_P") + + +def _ansi_color(r: int, g: int, b: int) -> Callable[[Callable[_P, None]], Callable[_P, str]]: + def decorator(func: Callable[_P, None]) -> Callable[_P, str]: + @functools.wraps(func) + def wrapper(s: str, *, bold: bool = False, underline: bool = False) -> str: + return ( + f"\x1b[{'1;' if bold else ''}{'4;' if underline else ''}38;2;{r};{g};{b}m{s}\x1b[0m" + ) + + return wrapper + + return decorator + + +@_ansi_color(0, 0, 255) +def blue(s: str, *, bold: bool = False, underline: bool = False): + """Clear skies, tranquil oceans, and sapphires gleaming with brilliance.""" + + +@_ansi_color(0, 255, 255) +def cyan(s: str, *, bold: bool = False, underline: bool = False): + """Tropical waters, verdant foliage, and the vibrant plumage of exotic birds.""" + + +@_ansi_color(0, 128, 0) +def green(s: str, *, bold: bool = False, underline: bool = False): + """Fresh leaves, lush meadows, and emerald gemstones.""" + + +@_ansi_color(255, 0, 255) +def magenta(s: str, *, bold: bool = False, underline: bool = False): + """Blooming flowers, radiant sunsets, and the bold intensity of fuchsia.""" + + +@_ansi_color(255, 165, 0) +def orange(s: str, *, bold: bool = False, underline: bool = False): + """Zest of ripe citrus fruits, fiery autumn leaves, and the energetic glow of a setting sun..""" + + +@_ansi_color(255, 0, 0) +def red(s: str, *, bold: bool = False, underline: bool = False): + """Fiery sunsets, vibrant roses, and the exhilarating energy of blazing flames.""" + + +@_ansi_color(255, 255, 0) +def yellow(s: str, *, bold: bool = False, underline: bool = False): + """Sunshine, golden fields of daffodils, and the cheerful vibrancy of lemon zest.""" From 81f33a17be9bc75792906f322277b82a918ea15d Mon Sep 17 00:00:00 2001 From: Joshua Date: Fri, 9 Jun 2023 10:54:23 -0500 Subject: [PATCH 2/9] fix reference --- src/python/pants/backend/python/typecheck/mypy/rules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/pants/backend/python/typecheck/mypy/rules.py b/src/python/pants/backend/python/typecheck/mypy/rules.py index a877cec7907..ba23cbc4680 100644 --- a/src/python/pants/backend/python/typecheck/mypy/rules.py +++ b/src/python/pants/backend/python/typecheck/mypy/rules.py @@ -312,7 +312,7 @@ async def mypy_typecheck_partition( "MYPY_FORCE_COLOR": "1", # Mypy needs to know the terminal so it can use appropriate escape sequences. ansi is a # reasonable lowest common denominator for the sort of escapes mypy uses (NB. TERM=xterm - # uses some additional codes that pants.util.strip_color doesn't remove). + # uses some additional codes that pants.util.colors.strip_color doesn't remove). "TERM": "ansi", # Force a fixed terminal width. This is effectively infinite, disabling mypy's # builtin truncation and line wrapping. Terminals do an acceptable job of soft-wrapping From b51a35e9990b16294d36f2c83a400d834d69bfad Mon Sep 17 00:00:00 2001 From: Joshua Date: Fri, 9 Jun 2023 10:57:05 -0500 Subject: [PATCH 3/9] Maaaaaayybe --- src/python/pants/core/goals/generate_lockfiles.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/pants/core/goals/generate_lockfiles.py b/src/python/pants/core/goals/generate_lockfiles.py index 8a9e452154f..f556485d097 100644 --- a/src/python/pants/core/goals/generate_lockfiles.py +++ b/src/python/pants/core/goals/generate_lockfiles.py @@ -232,7 +232,7 @@ def output_sections(self, diff: LockfileDiff) -> Iterator[str]: yield from self.output_reqs("Removed dependencies", diff.removed, color="magenta") def style(self, text: str, *, color: str, **kwargs) -> str: - return cast(str, getattr(self, color)(text, **kwargs)) + return cast(str, getattr(self, f"maybe_{color}")(text, **kwargs)) def title(self, text: str) -> str: heading = f"== {text:^60} ==" From 5f54d1d7c17134dd68b9558d3584cdf434cf4937 Mon Sep 17 00:00:00 2001 From: Joshua Date: Fri, 9 Jun 2023 11:13:32 -0500 Subject: [PATCH 4/9] better typing --- src/python/pants/help/maybe_color.py | 2 +- src/python/pants/util/colors.py | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/python/pants/help/maybe_color.py b/src/python/pants/help/maybe_color.py index 393533136ed..be14d31fb24 100644 --- a/src/python/pants/help/maybe_color.py +++ b/src/python/pants/help/maybe_color.py @@ -12,7 +12,7 @@ class MaybeColor: def __init__(self, color: bool) -> None: self._color = color - def noop(x, **_): + def noop(x, bold: bool = False, underline: bool = False): return x self.maybe_cyan = cyan if color else noop diff --git a/src/python/pants/util/colors.py b/src/python/pants/util/colors.py index ed579cbada3..8e94bb77947 100644 --- a/src/python/pants/util/colors.py +++ b/src/python/pants/util/colors.py @@ -4,7 +4,7 @@ import functools import re -from typing import Callable +from typing import TYPE_CHECKING, Callable from typing_extensions import ParamSpec @@ -25,7 +25,7 @@ def wrapper(s: str, *, bold: bool = False, underline: bool = False) -> str: f"\x1b[{'1;' if bold else ''}{'4;' if underline else ''}38;2;{r};{g};{b}m{s}\x1b[0m" ) - return wrapper + return wrapper # type: ignore return decorator @@ -34,6 +34,8 @@ def wrapper(s: str, *, bold: bool = False, underline: bool = False) -> str: def blue(s: str, *, bold: bool = False, underline: bool = False): """Clear skies, tranquil oceans, and sapphires gleaming with brilliance.""" +if TYPE_CHECKING: + reveal_type(blue) @_ansi_color(0, 255, 255) def cyan(s: str, *, bold: bool = False, underline: bool = False): @@ -52,7 +54,7 @@ def magenta(s: str, *, bold: bool = False, underline: bool = False): @_ansi_color(255, 165, 0) def orange(s: str, *, bold: bool = False, underline: bool = False): - """Zest of ripe citrus fruits, fiery autumn leaves, and the energetic glow of a setting sun..""" + """Zest of ripe citrus fruits, fiery autumn leaves, and the energetic glow of a setting sun.""" @_ansi_color(255, 0, 0) From fbe9c81e2c828344e3849bf50c9f40c070e8279a Mon Sep 17 00:00:00 2001 From: Joshua Date: Fri, 9 Jun 2023 11:29:22 -0500 Subject: [PATCH 5/9] cruft --- src/python/pants/util/colors.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/python/pants/util/colors.py b/src/python/pants/util/colors.py index 8e94bb77947..6afa07d69f2 100644 --- a/src/python/pants/util/colors.py +++ b/src/python/pants/util/colors.py @@ -34,8 +34,6 @@ def wrapper(s: str, *, bold: bool = False, underline: bool = False) -> str: def blue(s: str, *, bold: bool = False, underline: bool = False): """Clear skies, tranquil oceans, and sapphires gleaming with brilliance.""" -if TYPE_CHECKING: - reveal_type(blue) @_ansi_color(0, 255, 255) def cyan(s: str, *, bold: bool = False, underline: bool = False): From 643366f85c3e9268b52cf68069fa120d7d77d454 Mon Sep 17 00:00:00 2001 From: Joshua Date: Fri, 9 Jun 2023 11:41:32 -0500 Subject: [PATCH 6/9] fix --- src/python/pants/util/colors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/pants/util/colors.py b/src/python/pants/util/colors.py index 6afa07d69f2..49744074b3e 100644 --- a/src/python/pants/util/colors.py +++ b/src/python/pants/util/colors.py @@ -4,7 +4,7 @@ import functools import re -from typing import TYPE_CHECKING, Callable +from typing import Callable from typing_extensions import ParamSpec From 36323378243434ce6b798b510a919871f04983e2 Mon Sep 17 00:00:00 2001 From: Joshua Date: Fri, 9 Jun 2023 12:00:27 -0500 Subject: [PATCH 7/9] fix mypy --- src/python/pants/core/goals/generate_lockfiles.py | 8 +++++--- src/python/pants/core/goals/update_build_files.py | 6 +++--- src/python/pants/help/maybe_color.py | 3 ++- src/python/pants/util/colors.py | 15 +++++++++++---- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/python/pants/core/goals/generate_lockfiles.py b/src/python/pants/core/goals/generate_lockfiles.py index f556485d097..38cd42a040a 100644 --- a/src/python/pants/core/goals/generate_lockfiles.py +++ b/src/python/pants/core/goals/generate_lockfiles.py @@ -218,7 +218,7 @@ def print(self, diff: LockfileDiff) -> None: if not output: return self.console.print_stderr( - self.style(" " * 66, underline=True) + self.style(" " * 66, color="default", underline=True) + f"\nLockfile diff: {diff.path} [{diff.resolve_name}]\n" + output ) @@ -236,7 +236,9 @@ def style(self, text: str, *, color: str, **kwargs) -> str: def title(self, text: str) -> str: heading = f"== {text:^60} ==" - return self.style("\n".join((" " * len(heading), heading, "")), underline=True) + return self.style( + "\n".join((" " * len(heading), heading, "")), color="default", underline=True + ) def output_reqs(self, heading: str, reqs: LockfilePackages, **kwargs) -> Iterator[str]: if not reqs: @@ -270,7 +272,7 @@ def output_changed(self, title: str, reqs: ChangedPackages) -> Iterator[str]: (None, dict(color="magenta")), ) - def get_bump_attrs(self, prev: PackageVersion, curr: PackageVersion) -> dict[str, str]: + def get_bump_attrs(self, prev: PackageVersion, curr: PackageVersion) -> dict[str, str | bool]: for key, attrs in self._BUMPS: if key is None or getattr(prev, key, None) != getattr(curr, key, None): return attrs diff --git a/src/python/pants/core/goals/update_build_files.py b/src/python/pants/core/goals/update_build_files.py index 43316e7e1ca..f1c08459421 100644 --- a/src/python/pants/core/goals/update_build_files.py +++ b/src/python/pants/core/goals/update_build_files.py @@ -11,7 +11,7 @@ from dataclasses import dataclass from enum import Enum from io import BytesIO -from typing import DefaultDict, cast +from typing import DefaultDict from pants.backend.build_files.fix.deprecations import renamed_fields_rules, renamed_targets_rules from pants.backend.build_files.fix.deprecations.base import FixedBUILDFile @@ -93,10 +93,10 @@ def tokenize(self) -> list[tokenize.TokenInfo]: raise ParseError(f"Failed to parse {self.path}: {e}") def red(self, s: str) -> str: - return cast(str, red(s)) if self.colors_enabled else s + return red(s) if self.colors_enabled else s def green(self, s: str) -> str: - return cast(str, green(s)) if self.colors_enabled else s + return green(s) if self.colors_enabled else s class DeprecationFixerRequest(RewrittenBuildFileRequest): diff --git a/src/python/pants/help/maybe_color.py b/src/python/pants/help/maybe_color.py index be14d31fb24..2661edd4f1e 100644 --- a/src/python/pants/help/maybe_color.py +++ b/src/python/pants/help/maybe_color.py @@ -3,7 +3,7 @@ from typing import List -from pants.util.colors import cyan, green, magenta, orange, red, yellow +from pants.util.colors import cyan, default, green, magenta, orange, red, yellow class MaybeColor: @@ -15,6 +15,7 @@ def __init__(self, color: bool) -> None: def noop(x, bold: bool = False, underline: bool = False): return x + self.maybe_default = default if color else noop self.maybe_cyan = cyan if color else noop self.maybe_green = green if color else noop self.maybe_orange = orange if color else noop diff --git a/src/python/pants/util/colors.py b/src/python/pants/util/colors.py index 49744074b3e..3977fadbd59 100644 --- a/src/python/pants/util/colors.py +++ b/src/python/pants/util/colors.py @@ -17,13 +17,15 @@ def strip_color(s: str) -> str: _P = ParamSpec("_P") -def _ansi_color(r: int, g: int, b: int) -> Callable[[Callable[_P, None]], Callable[_P, str]]: +def _ansi_color(*rgb) -> Callable[[Callable[_P, None]], Callable[_P, str]]: + codes = "" + if rgb: + codes = "2;" + ";".join(str(n) for n in rgb) + def decorator(func: Callable[_P, None]) -> Callable[_P, str]: @functools.wraps(func) def wrapper(s: str, *, bold: bool = False, underline: bool = False) -> str: - return ( - f"\x1b[{'1;' if bold else ''}{'4;' if underline else ''}38;2;{r};{g};{b}m{s}\x1b[0m" - ) + return f"\x1b[{'1;' if bold else ''}{'4;' if underline else ''}38;{codes}m{s}\x1b[0m" return wrapper # type: ignore @@ -63,3 +65,8 @@ def red(s: str, *, bold: bool = False, underline: bool = False): @_ansi_color(255, 255, 0) def yellow(s: str, *, bold: bool = False, underline: bool = False): """Sunshine, golden fields of daffodils, and the cheerful vibrancy of lemon zest.""" + + +@_ansi_color() +def default(s: str, *, bold: bool = False, underline: bool = False): + """Initial state, conventional choice, and the pre-established configuration.""" From eb5bee7f23682f6f19b7e0586f3b8c6e6dc7b24c Mon Sep 17 00:00:00 2001 From: Joshua Date: Fri, 9 Jun 2023 12:18:46 -0500 Subject: [PATCH 8/9] OK mypy, you win --- .../pants/core/goals/generate_lockfiles.py | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/python/pants/core/goals/generate_lockfiles.py b/src/python/pants/core/goals/generate_lockfiles.py index 38cd42a040a..a980c06be8c 100644 --- a/src/python/pants/core/goals/generate_lockfiles.py +++ b/src/python/pants/core/goals/generate_lockfiles.py @@ -231,7 +231,7 @@ def output_sections(self, diff: LockfileDiff) -> Iterator[str]: yield from self.output_reqs("Added dependencies", diff.added, color="green", bold=True) yield from self.output_reqs("Removed dependencies", diff.removed, color="magenta") - def style(self, text: str, *, color: str, **kwargs) -> str: + def style(self, text: str, *, color: str, **kwargs: bool) -> str: return cast(str, getattr(self, f"maybe_{color}")(text, **kwargs)) def title(self, text: str) -> str: @@ -257,26 +257,24 @@ def output_changed(self, title: str, reqs: ChangedPackages) -> Iterator[str]: yield self.title(title) label = "-->" for name, (prev, curr) in reqs.items(): - bump_attrs = self.get_bump_attrs(prev, curr) + bump_color, bump_bold = self.get_bump_attrs(prev, curr) name_s = self.style(f"{name:30}", color="yellow") prev_s = self.style(f"{str(prev):10}", color="cyan") - bump_s = self.style(f"{label:^7}", **bump_attrs) - curr_s = self.style(str(curr), **bump_attrs) + bump_s = self.style(f"{label:^7}", color=bump_color, bump=bump_bold) + curr_s = self.style(str(curr), color=bump_color, bump=bump_bold) yield f" {name_s} {prev_s} {bump_s} {curr_s}" _BUMPS = ( - ("major", dict(color="red", bold=True)), - ("minor", dict(color="yellow")), - ("micro", dict(color="green")), - # Default style - (None, dict(color="magenta")), + ("major", ("red", True)), + ("minor", ("yellow", False)), + ("micro", ("green", False)), ) - def get_bump_attrs(self, prev: PackageVersion, curr: PackageVersion) -> dict[str, str | bool]: + def get_bump_attrs(self, prev: PackageVersion, curr: PackageVersion) -> tuple[str, bool]: for key, attrs in self._BUMPS: - if key is None or getattr(prev, key, None) != getattr(curr, key, None): + if getattr(prev, key, None) != getattr(curr, key, None): return attrs - return {} # Should never happen, but let's be safe. + return ("magenta", False) DEFAULT_TOOL_LOCKFILE = "" From bc906422a459d9aee9fc759216e6e5e61850e1f7 Mon Sep 17 00:00:00 2001 From: Joshua Date: Fri, 9 Jun 2023 14:06:12 -0500 Subject: [PATCH 9/9] blue --- src/python/pants/help/maybe_color.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/python/pants/help/maybe_color.py b/src/python/pants/help/maybe_color.py index 2661edd4f1e..b9544254c44 100644 --- a/src/python/pants/help/maybe_color.py +++ b/src/python/pants/help/maybe_color.py @@ -3,7 +3,7 @@ from typing import List -from pants.util.colors import cyan, default, green, magenta, orange, red, yellow +from pants.util.colors import blue, cyan, default, green, magenta, orange, red, yellow class MaybeColor: @@ -16,6 +16,7 @@ def noop(x, bold: bool = False, underline: bool = False): return x self.maybe_default = default if color else noop + self.maybe_blue = blue if color else noop self.maybe_cyan = cyan if color else noop self.maybe_green = green if color else noop self.maybe_orange = orange if color else noop