Skip to content

AI junk#3666

Closed
sean-kim05 wants to merge 2 commits into
pallets:mainfrom
sean-kim05:fix/style-color-index-zero
Closed

AI junk#3666
sean-kim05 wants to merge 2 commits into
pallets:mainfrom
sean-kim05:fix/style-color-index-zero

Conversation

@sean-kim05

Copy link
Copy Markdown

Summary

click.style() (and therefore secho()) silently drops the 256-color index 0 (black) when passed as fg or bg, producing uncolored text.

The color arguments are guarded with a truthiness check:

if fg:
    bits.append(f"\033[{_interpret_color(fg)}m")
if bg:
    bits.append(f"\033[{_interpret_color(bg, 10)}m")

0 is a valid 8-bit color index (documented range "[0, 255]") but is falsy, so the guard skips it and no escape is emitted. Every other input works — nonzero indices, named colors, and even RGB black (0, 0, 0) (a truthy tuple) — which makes index 0 an inconsistency, not a design choice.

Reproduction

>>> import click
>>> click.style("x", fg=0)      # 256-color black
'x\x1b[0m'                       # color dropped
>>> click.style("x", fg=1)      # works
'\x1b[38;5;1mx\x1b[0m'
>>> click.style("x", fg=(0, 0, 0))  # RGB black works
'\x1b[38;2;0;0;0mx\x1b[0m'

Fix

Guard on is not None instead of truthiness, matching how the other style attributes (bold, dim, …) in the same function are already handled. None (the default) stays suppressed, unknown color names still raise TypeError, and index 0 is now emitted correctly.

The truthiness guards date to the original 2014 implementation when only named colors (all truthy) existed; integer/RGB support was later added inside the same blocks without updating them.

Tests

Added {"fg": 0} and {"bg": 0} cases to the parametrized test_styling table in tests/test_utils.py. They fail on main and pass with this change; the full suite is unaffected (1682 passed).

`style()` (and `secho()`) guarded foreground/background colors with a
truthiness check (`if fg:` / `if bg:`), so the valid 256-color index 0
(black) was treated as unset and silently produced uncolored text. The RGB
form `(0, 0, 0)` and every nonzero index worked, making the omission an
inconsistency rather than intended behavior.

Guard on `is not None` instead, matching how the other style attributes in
the same function are handled.
@kdeldycke kdeldycke changed the title Do not drop 256-color index 0 in style() Do not drop 256-color index 0 in style() Jul 7, 2026
@kdeldycke kdeldycke added the f:help feature: help text label Jul 7, 2026
@kdeldycke kdeldycke added this to the 8.5.0 milestone Jul 7, 2026
Booleans, malformed tuples and out-of-range values now raise the same `TypeError`
@kdeldycke

kdeldycke commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

This is right on time as I am myself digging into the ANSI-side of Click (see: #3653 and #3420). I confirm the issue, which also made me aware of a new class of edge-cases the style() method is not processing. This affects both my Click Extra project and Cloup (cc @janluke).

So I just updated your PR with an additional commit to illustrate all the edge-cases not covered in unittests, and also fix the behavior by validating all colors passed to style().

Now I need a quick pass from other maintainers to check that I did not miss anything but to me this is good to merged in the upcoming 8.5.0 release.

kdeldycke added a commit to kdeldycke/click-extra that referenced this pull request Jul 7, 2026
@davidism davidism closed this Jul 7, 2026
@davidism davidism changed the title Do not drop 256-color index 0 in style() AI junk Jul 7, 2026
@kdeldycke

Copy link
Copy Markdown
Collaborator

@davidism do you want me to redo it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

f:help feature: help text

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants