Skip to content

Commit a2ad70b

Browse files
committed
Added optional color argument to poutput() for providing a color escape code to colorize the output with
Also: - Added optional err_color and war_color arguments to perror() for providing color escape codes - Removed usage of deprecated colorize() method within the examples
1 parent 806fe46 commit a2ad70b

4 files changed

Lines changed: 39 additions & 17 deletions

File tree

cmd2/cmd2.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -561,22 +561,25 @@ def decolorized_write(self, fileobj: IO, msg: str) -> None:
561561
msg = utils.strip_ansi(msg)
562562
fileobj.write(msg)
563563

564-
def poutput(self, msg: Any, end: str='\n') -> None:
564+
def poutput(self, msg: Any, end: str='\n', color: str='') -> None:
565565
"""Smarter self.stdout.write(); color aware and adds newline of not present.
566566
567567
Also handles BrokenPipeError exceptions for when a commands's output has
568568
been piped to another process and that process terminates before the
569569
cmd2 command is finished executing.
570570
571571
:param msg: message to print to current stdout (anything convertible to a str with '{}'.format() is OK)
572-
:param end: string appended after the end of the message if not already present, default a newline
572+
:param end: (optional) string appended after the end of the message if not already present, default a newline
573+
:param color: (optional) color escape to output this message with
573574
"""
574575
if msg is not None and msg != '':
575576
try:
576577
msg_str = '{}'.format(msg)
577-
self.decolorized_write(self.stdout, msg_str)
578578
if not msg_str.endswith(end):
579-
self.decolorized_write(self.stdout, end)
579+
msg_str += end
580+
if color:
581+
msg_str = color + msg_str + Fore.RESET
582+
self.decolorized_write(self.stdout, msg_str)
580583
except BrokenPipeError:
581584
# This occurs if a command's output is being piped to another
582585
# process and that process closes before the command is
@@ -586,12 +589,14 @@ def poutput(self, msg: Any, end: str='\n') -> None:
586589
if self.broken_pipe_warning:
587590
sys.stderr.write(self.broken_pipe_warning)
588591

589-
def perror(self, err: Union[str, Exception], traceback_war: bool=True) -> None:
592+
def perror(self, err: Union[str, Exception], traceback_war: bool=True, err_color: str=Fore.LIGHTRED_EX,
593+
war_color: str=Fore.LIGHTYELLOW_EX) -> None:
590594
""" Print error message to sys.stderr and if debug is true, print an exception Traceback if one exists.
591595
592596
:param err: an Exception or error message to print out
593597
:param traceback_war: (optional) if True, print a message to let user know they can enable debug
594-
:return:
598+
:param err_color: (optional) color escape to output error with
599+
:param war_color: (optional) color escape to output warning with
595600
"""
596601
if self.debug:
597602
import traceback
@@ -601,12 +606,12 @@ def perror(self, err: Union[str, Exception], traceback_war: bool=True) -> None:
601606
err_msg = "EXCEPTION of type '{}' occurred with message: '{}'\n".format(type(err).__name__, err)
602607
else:
603608
err_msg = "ERROR: {}\n".format(err)
604-
err_msg = Fore.RED + err_msg + Fore.RESET
609+
err_msg = err_color + err_msg + Fore.RESET
605610
self.decolorized_write(sys.stderr, err_msg)
606611

607612
if traceback_war:
608613
war = "To enable full traceback, run the following command: 'set debug true'\n"
609-
war = Fore.YELLOW + war + Fore.RESET
614+
war = war_color + war + Fore.RESET
610615
self.decolorized_write(sys.stderr, war)
611616

612617
def pfeedback(self, msg: str) -> None:
@@ -679,7 +684,7 @@ def ppaged(self, msg: str, end: str='\n', chop: bool=False) -> None:
679684
except BrokenPipeError:
680685
# This occurs if a command's output is being piped to another process and that process closes before the
681686
# command is finished. If you would like your application to print a warning message, then set the
682-
# broken_pipe_warning attribute to the message you want printed.
687+
# broken_pipe_warning attribute to the message you want printed.`
683688
if self.broken_pipe_warning:
684689
sys.stderr.write(self.broken_pipe_warning)
685690

examples/pirate.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,32 @@
88
"""
99
import argparse
1010

11+
from colorama import Fore
12+
1113
import cmd2
1214

15+
COLORS = {
16+
'black': Fore.BLACK,
17+
'red': Fore.RED,
18+
'green': Fore.GREEN,
19+
'yellow': Fore.YELLOW,
20+
'blue': Fore.BLUE,
21+
'magenta': Fore.MAGENTA,
22+
'cyan': Fore.CYAN,
23+
'white': Fore.WHITE,
24+
}
25+
1326

1427
class Pirate(cmd2.Cmd):
1528
"""A piratical example cmd2 application involving looting and drinking."""
1629
def __init__(self):
1730
self.default_to_shell = True
1831
self.multiline_commands = ['sing']
1932
self.terminators = self.terminators + ['...']
20-
self.songcolor = 'blue'
33+
self.songcolor = Fore.BLUE
2134

2235
# Add stuff to settable and/or shortcuts before calling base class initializer
23-
self.settable['songcolor'] = 'Color to ``sing`` in (red/blue/green/cyan/magenta, bold, underline)'
36+
self.settable['songcolor'] = 'Color to ``sing`` in (black/red/green/yellow/blue/magenta/cyan/white)'
2437
self.shortcuts.update({'~': 'sing'})
2538

2639
"""Initialize the base class as well as this one"""
@@ -68,7 +81,8 @@ def do_quit(self, arg):
6881

6982
def do_sing(self, arg):
7083
"""Sing a colorful song."""
71-
self.poutput(self.colorize(arg, self.songcolor))
84+
color_escape = COLORS.get(self.songcolor, default=Fore.RESET)
85+
self.poutput(arg, color=color_escape)
7286

7387
yo_parser = argparse.ArgumentParser()
7488
yo_parser.add_argument('--ho', type=int, default=2, help="How often to chant 'ho'")

examples/python_scripting.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
import argparse
1818
import os
1919

20+
from colorama import Fore
21+
2022
import cmd2
2123

2224

@@ -33,7 +35,7 @@ def __init__(self):
3335
def _set_prompt(self):
3436
"""Set prompt so it displays the current working directory."""
3537
self.cwd = os.getcwd()
36-
self.prompt = self.colorize('{!r} $ '.format(self.cwd), 'cyan')
38+
self.prompt = Fore.CYAN + '{!r} $ '.format(self.cwd) + Fore.RESET
3739

3840
def postcmd(self, stop: bool, line: str) -> bool:
3941
"""Hook method executed just after a command dispatch is finished.

tests/test_cmd2.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,18 +1094,19 @@ def test_ansi_prompt_not_esacped(base_app):
10941094

10951095

10961096
def test_ansi_prompt_escaped():
1097+
from colorama import Fore
10971098
app = cmd2.Cmd()
1098-
color = 'cyan'
1099+
color = Fore.CYAN
10991100
prompt = 'InColor'
1100-
color_prompt = app.colorize(prompt, color)
1101+
color_prompt = color + prompt + Fore.RESET
11011102

11021103
readline_hack_start = "\x01"
11031104
readline_hack_end = "\x02"
11041105

11051106
readline_safe_prompt = app._surround_ansi_escapes(color_prompt)
11061107
assert prompt != color_prompt
1107-
assert readline_safe_prompt.startswith(readline_hack_start + app._colorcodes[color][True] + readline_hack_end)
1108-
assert readline_safe_prompt.endswith(readline_hack_start + app._colorcodes[color][False] + readline_hack_end)
1108+
assert readline_safe_prompt.startswith(readline_hack_start + color + readline_hack_end)
1109+
assert readline_safe_prompt.endswith(readline_hack_start + Fore.RESET + readline_hack_end)
11091110

11101111

11111112
class HelpApp(cmd2.Cmd):

0 commit comments

Comments
 (0)