diff --git a/rich/color.py b/rich/color.py index e2c23a6a9..d1233cf4b 100644 --- a/rich/color.py +++ b/rich/color.py @@ -289,6 +289,8 @@ class ColorParseError(Exception): """The color could not be parsed.""" +RE_SHORT_COLOR = re.compile(r"^\#([0-9a-f])([0-9a-f])([0-9a-f])$") + RE_COLOR = re.compile( r"""^ \#([0-9a-f]{6})$| @@ -446,6 +448,10 @@ def parse(cls, color: str) -> "Color": number=color_number, ) + if short_match := RE_SHORT_COLOR.fullmatch(color): + r, g, b = short_match.groups() + color = f"#{r*2}{g*2}{b*2}" + color_match = RE_COLOR.match(color) if color_match is None: raise ColorParseError(f"{original_color!r} is not a valid color") diff --git a/tests/test_color.py b/tests/test_color.py index 010d79746..f90bd318f 100644 --- a/tests/test_color.py +++ b/tests/test_color.py @@ -39,6 +39,7 @@ def test_system() -> None: assert Color.parse("default").system == ColorSystem.STANDARD assert Color.parse("red").system == ColorSystem.STANDARD assert Color.parse("#ff0000").system == ColorSystem.TRUECOLOR + assert Color.parse("#f00").system == ColorSystem.TRUECOLOR def test_windows() -> None: @@ -47,6 +48,7 @@ def test_windows() -> None: def test_truecolor() -> None: assert Color.parse("#ff0000").get_truecolor() == ColorTriplet(255, 0, 0) + assert Color.parse("#f00").get_truecolor() == ColorTriplet(255, 0, 0) assert Color.parse("red").get_truecolor() == ColorTriplet(128, 0, 0) assert Color.parse("color(1)").get_truecolor() == ColorTriplet(128, 0, 0) assert Color.parse("color(17)").get_truecolor() == ColorTriplet(0, 0, 95) @@ -70,6 +72,9 @@ def test_parse_success() -> None: assert Color.parse("#112233") == Color( "#112233", ColorType.TRUECOLOR, None, ColorTriplet(0x11, 0x22, 0x33) ) + assert Color.parse("#123") == Color( + "#112233", ColorType.TRUECOLOR, None, ColorTriplet(0x11, 0x22, 0x33) + ) assert Color.parse("rgb(90,100,110)") == Color( "rgb(90,100,110)", ColorType.TRUECOLOR, None, ColorTriplet(90, 100, 110) ) @@ -110,6 +115,8 @@ def test_parse_error() -> None: Color.parse("nosuchcolor") with pytest.raises(ColorParseError): Color.parse("#xxyyzz") + with pytest.raises(ColorParseError): + Color.parse("#xyz") def test_get_ansi_codes() -> None: