Skip to content

Instantly share code, notes, and snippets.

@adrian-the-git
Last active August 20, 2020 07:42
Show Gist options
  • Save adrian-the-git/3b8eb712702e8d769db38f5f30822bd9 to your computer and use it in GitHub Desktop.
Save adrian-the-git/3b8eb712702e8d769db38f5f30822bd9 to your computer and use it in GitHub Desktop.
Cross-platform colored text for python3
# If you can write a simpler but still *readable* cross-platform colored text print function please comment!
try:
from ctypes import windll
BLUE, GREEN, CYAN, RED, MAGENTA, YELLOW, GRAY, BOLD, RESET = [*range(1, 9), 7]
set_color = (lambda a, b, f=windll.kernel32.SetConsoleTextAttribute,
s=windll.kernel32.GetStdHandle(-11): f(s, a | b))
except ImportError:
RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, GRAY, BOLD, RESET = [*range(31, 38), 1, 0]
set_color = lambda *a: print(f'\033[{";".join(map(str, sorted(a)))}m', end='', flush=True)
def cprint(*tokens, last_attr=0, end='\n'):
for t in [*tokens, RESET, end]:
if isinstance(t, int):
set_color(t, last_attr)
last_attr = t
else:
print(f'{t}', end='', flush=True)
last_attr = 0
@adrian-the-git
Copy link
Author

adrian-the-git commented Aug 20, 2020

2.0

try:
    from ctypes import windll
    _cprint = (lambda c, f=windll.kernel32.SetConsoleTextAttribute,
                         s=windll.kernel32.GetStdHandle(-11), **_: f(s, c))
    _colors = 1,3,2,5,4,6,7,9,11,10,13,12,14,15
except ImportError:
    _colors = (f'\033[{i};3{a}m' for i in (0,1) for a in (4,6,2,5,1,3,7))

(Blue, Cyan, Green, Magenta, Red, Yellow, White,
 BLUE, CYAN, GREEN, MAGENTA, RED, YELLOW, WHITE) = _colors

def cprint(*tokens, reset=WHITE, end='\n'):
    for t in (*tokens, reset, end):
        (print if type(t) == str else _cprint)(t, end='', flush=True)
  • Better interface – no sequences like BOLD, RED. Just use Red for normal intensity and RED for bold (anti-PEP8 but so what?)
  • Colors are just strings on unix-ish platforms, so no more special set_color transformation to ANSI escapes from ints
  • Short-circuiting ternary conditional means _cprint doesn't even need to exist except on Windows
  • Golfed from 16 lines to 12, while becoming more readable!

Example

if success:
    cprint(Green, ' [', GREEN, '✓', Green, '] ', White, 'Tests passed!')
else:
    cprint(Red, ' [', RED, 'x', Red, '] ', White, 'Tests failed!')

3.0?

  • Allow inline color tokens
  • Don't invent a whole library!

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