Skip to content

Commit 2a2c59e

Browse files
authored
Fix hex color short code expansion (#1425)
1 parent 36da8cc commit 2a2c59e

File tree

3 files changed

+30
-7
lines changed

3 files changed

+30
-7
lines changed

CHANGELOG.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
- Add requirement for ``TERM`` environment variable not to be ``"dumb"`` to enable colorization (`#1287 <https://github.com/Delgan/loguru/pull/1287>`_, thanks `@snosov1 <https://github.com/snosov1>`_).
1313
- Make ``logger.catch()`` usable as an asynchronous context manager (`#1084 <https://github.com/Delgan/loguru/issues/1084>`_).
1414
- Make ``logger.catch()`` compatible with asynchronous generators (`#1302 <https://github.com/Delgan/loguru/issues/1302>`_).
15-
15+
- Fix hex color short code expansion (`#1426 <https://github.com/Delgan/loguru/issues/1426>`_).
1616

1717
`0.7.3`_ (2024-12-06)
1818
=====================

loguru/_colorizer.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ def _get_ansicode(self, tag):
316316

317317
# An alternative syntax for setting the color (e.g. <fg red>, <bg red>).
318318
if tag.startswith("fg ") or tag.startswith("bg "):
319-
st, color = tag[:2], tag[3:]
319+
st, color = tag[:2], tag[3:].strip(" ")
320320
code = "38" if st == "fg" else "48"
321321

322322
if st == "fg" and color.lower() in foreground:
@@ -325,10 +325,15 @@ def _get_ansicode(self, tag):
325325
return background[color.upper()]
326326
if color.isdigit() and int(color) <= 255:
327327
return "\033[%s;5;%sm" % (code, color)
328-
if re.match(r"#(?:[a-fA-F0-9]{3}){1,2}$", color):
328+
if (
329+
color.startswith("#")
330+
and all(s in "0123456789abcdef" for s in color[1:].lower())
331+
and len(color[1:]) in [3, 6]
332+
):
329333
hex_color = color[1:]
330334
if len(hex_color) == 3:
331-
hex_color *= 2
335+
r, g, b = list(hex_color)
336+
hex_color = (r * 2) + (g * 2) + (b * 2)
332337
rgb = tuple(int(hex_color[i : i + 2], 16) for i in (0, 2, 4))
333338
return "\033[%s;2;%s;%s;%sm" % ((code, *rgb))
334339
if color.count(",") == 2:

tests/test_ansimarkup_extended.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def test_foreground_colors(text, expected):
3535
[
3636
("<fg #ff0000>1</fg #ff0000>", "\x1b[38;2;255;0;0m" "1" + Style.RESET_ALL),
3737
("<bg #00A000>1</bg #00A000>", "\x1b[48;2;0;160;0m" "1" + Style.RESET_ALL),
38-
("<fg #F12>1</fg #F12>", "\x1b[38;2;241;47;18m" "1" + Style.RESET_ALL),
38+
("<fg #F12>1</fg #F12>", "\x1b[38;2;255;17;34m" "1" + Style.RESET_ALL),
3939
],
4040
)
4141
def test_8bit_colors(text, expected):
@@ -47,14 +47,32 @@ def test_8bit_colors(text, expected):
4747
[
4848
("<fg #ff0000>1</fg #ff0000>", "\x1b[38;2;255;0;0m" "1" + Style.RESET_ALL),
4949
("<bg #00A000>1</bg #00A000>", "\x1b[48;2;0;160;0m" "1" + Style.RESET_ALL),
50-
("<fg #F12>1</fg #F12>", "\x1b[38;2;241;47;18m" "1" + Style.RESET_ALL),
51-
("<bg #BEE>1</bg #BEE>", "\x1b[48;2;190;235;238m" "1" + Style.RESET_ALL),
50+
("<fg #F12>1</fg #F12>", "\x1b[38;2;255;17;34m" "1" + Style.RESET_ALL),
51+
("<bg #BEE>1</bg #BEE>", "\x1b[48;2;187;238;238m" "1" + Style.RESET_ALL),
5252
],
5353
)
5454
def test_hex_colors(text, expected):
5555
assert parse(text, strip=False) == expected
5656

5757

58+
@pytest.mark.parametrize(
59+
("short_code", "long_code"),
60+
[
61+
("abc", "aabbcc"),
62+
("f00", "ff0000"),
63+
("f12", "ff1122"),
64+
("bee", "bbeeee"),
65+
("Ace", "AAccee"),
66+
],
67+
ids=lambda code: "#" + code,
68+
)
69+
@pytest.mark.parametrize("layer", ["fg", "bg"])
70+
def test_hex_short_code_equals_long_code(layer, short_code, long_code):
71+
short_code_colorized = parse("<%s #%s>_</>" % (layer, short_code))
72+
long_code_colorized = parse("<%s #%s>_</>" % (layer, long_code))
73+
assert short_code_colorized == long_code_colorized
74+
75+
5876
@pytest.mark.parametrize(
5977
("text", "expected"),
6078
[

0 commit comments

Comments
 (0)