summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd Leonhardt <todd.leonhardt@gmail.com>2018-09-19 15:32:37 -0400
committerTodd Leonhardt <todd.leonhardt@gmail.com>2018-09-19 15:32:37 -0400
commitccbe1276f786e94f1996877fdec6d070705f5ab8 (patch)
tree167fe848ea36915091fbc7cbd7ad1032dd4474ec
parentf787b1fb0adc8596d338af9cebdf3866e75fdbaa (diff)
downloadcmd2-git-ccbe1276f786e94f1996877fdec6d070705f5ab8.tar.gz
cmd2.Cmd.__init__ now initializes colorama and tells it to never strip ANSI codes since cmd2 deals with that
Also: - Finished editing poutput(), ppaged(), and pfeedback() methods to strip ANSI color when appropriate - Changed attr.ib() factory usage so cmd2 is compatible with older versions of attrs
-rw-r--r--cmd2/cmd2.py38
-rw-r--r--cmd2/parsing.py4
-rwxr-xr-xexamples/colors.py11
-rw-r--r--tests/conftest.py2
4 files changed, 30 insertions, 25 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index db96228b..da5b528a 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -32,11 +32,11 @@ Git repository on GitHub at https://github.com/python-cmd2/cmd2
import argparse
import cmd
import collections
+import colorama
from colorama import Fore
import glob
import inspect
import os
-import platform
import re
import shlex
import sys
@@ -337,7 +337,7 @@ class Cmd(cmd.Cmd):
# To make an attribute settable with the "do_set" command, add it to this ...
# This starts out as a dictionary but gets converted to an OrderedDict sorted alphabetically by key
- settable = {'colors': 'Allow colorized output',
+ settable = {'colors': 'Allow colorized output (valid values: Terminal, Always, Never)',
'continuation_prompt': 'On 2nd+ line of input',
'debug': 'Show full error stack on error',
'echo': 'Echo command issued into output',
@@ -369,6 +369,9 @@ class Cmd(cmd.Cmd):
except AttributeError:
pass
+ # Override whether ansi codes should be stripped from the output since cmd2 has its own logic for doing this
+ colorama.init(strip=False)
+
# initialize plugin system
# needs to be done before we call __init__(0)
self._initialize_plugin_system()
@@ -417,13 +420,13 @@ class Cmd(cmd.Cmd):
self._STOP_AND_EXIT = True # cmd convention
self._colorcodes = {'bold': {True: '\x1b[1m', False: '\x1b[22m'},
- 'cyan': {True: '\x1b[36m', False: '\x1b[39m'},
- 'blue': {True: '\x1b[34m', False: '\x1b[39m'},
- 'red': {True: '\x1b[31m', False: '\x1b[39m'},
- 'magenta': {True: '\x1b[35m', False: '\x1b[39m'},
- 'green': {True: '\x1b[32m', False: '\x1b[39m'},
- 'underline': {True: '\x1b[4m', False: '\x1b[24m'},
- 'yellow': {True: '\x1b[33m', False: '\x1b[39m'}}
+ 'cyan': {True: Fore.CYAN, False: Fore.RESET},
+ 'blue': {True: Fore.BLUE, False: Fore.RESET},
+ 'red': {True: Fore.RED, False: Fore.RESET},
+ 'magenta': {True: Fore.MAGENTA, False: Fore.RESET},
+ 'green': {True: Fore.GREEN, False: Fore.RESET},
+ 'underline': {True: '\x1b[4m', False: Fore.RESET},
+ 'yellow': {True: Fore.YELLOW, False: Fore.RESET}}
# Used load command to store the current script dir as a LIFO queue to support _relative_load command
self._script_dir = []
@@ -547,17 +550,15 @@ class Cmd(cmd.Cmd):
# Make sure settable parameters are sorted alphabetically by key
self.settable = collections.OrderedDict(sorted(self.settable.items(), key=lambda t: t[0]))
- def decolorized_write(self, fileobj: IO, msg: str):
+ def decolorized_write(self, fileobj: IO, msg: str) -> None:
"""Write a string to a fileobject, stripping ANSI escape sequences if necessary
Honor the current colors setting, which requires us to check whether the
fileobject is a tty.
"""
- if self.colors == constants.COLORS_NEVER:
+ if self.colors.lower() == constants.COLORS_NEVER.lower() or \
+ (self.colors.lower() == constants.COLORS_TERMINAL.lower() and not fileobj.isatty()):
msg = utils.strip_ansi(msg)
- if self.colors == constants.COLORS_TERMINAL:
- if not fileobj.isatty():
- msg = utils.strip_ansi(msg)
fileobj.write(msg)
def poutput(self, msg: Any, end: str='\n') -> None:
@@ -575,7 +576,7 @@ class Cmd(cmd.Cmd):
msg_str = '{}'.format(msg)
self.decolorized_write(self.stdout, msg_str)
if not msg_str.endswith(end):
- self.stdout.write(end)
+ self.decolorized_write(self.stdout, end)
except BrokenPipeError:
# This occurs if a command's output is being piped to another
# process and that process closes before the command is
@@ -615,7 +616,7 @@ class Cmd(cmd.Cmd):
if self.feedback_to_output:
self.poutput(msg)
else:
- sys.stderr.write("{}\n".format(msg))
+ self.decolorized_write(sys.stderr, "{}\n".format(msg))
def ppaged(self, msg: str, end: str='\n', chop: bool=False) -> None:
"""Print output using a pager if it would go off screen and stdout isn't currently being redirected.
@@ -651,6 +652,9 @@ class Cmd(cmd.Cmd):
# Don't attempt to use a pager that can block if redirecting or running a script (either text or Python)
# Also only attempt to use a pager if actually running in a real fully functional terminal
if functional_terminal and not self.redirecting and not self._in_py and not self._script_dir:
+ if self.colors.lower() == constants.COLORS_NEVER.lower():
+ msg_str = utils.strip_ansi(msg_str)
+
pager = self.pager
if chop:
pager = self.pager_chop
@@ -686,7 +690,7 @@ class Cmd(cmd.Cmd):
is running on Windows, will return ``val`` unchanged.
``color`` should be one of the supported strings (or styles):
red/blue/green/cyan/magenta, bold, underline"""
- if self.colors and (self.stdout == self.initial_stdout):
+ if self.colors.lower() != constants.COLORS_NEVER.lower() and (self.stdout == self.initial_stdout):
return self._colorcodes[color][True] + val + self._colorcodes[color][False]
return val
diff --git a/cmd2/parsing.py b/cmd2/parsing.py
index 8edfacb9..92dc1b40 100644
--- a/cmd2/parsing.py
+++ b/cmd2/parsing.py
@@ -90,7 +90,7 @@ class Statement(str):
command = attr.ib(default='', validator=attr.validators.instance_of(str), type=str)
# list of arguments to the command, not including any output redirection or terminators; quoted args remain quoted
- arg_list = attr.ib(factory=list, validator=attr.validators.instance_of(list), type=List[str])
+ arg_list = attr.ib(default=attr.Factory(list), validator=attr.validators.instance_of(list), type=List[str])
# if the command is a multiline command, the name of the command, otherwise empty
multiline_command = attr.ib(default='', validator=attr.validators.instance_of(str), type=str)
@@ -102,7 +102,7 @@ class Statement(str):
suffix = attr.ib(default='', validator=attr.validators.instance_of(str), type=str)
# if output was piped to a shell command, the shell command as a list of tokens
- pipe_to = attr.ib(factory=list, validator=attr.validators.instance_of(list), type=List[str])
+ pipe_to = attr.ib(default=attr.Factory(list), validator=attr.validators.instance_of(list), type=List[str])
# if output was redirected, the redirection token, i.e. '>>'
output = attr.ib(default='', validator=attr.validators.instance_of(str), type=str)
diff --git a/examples/colors.py b/examples/colors.py
index 59e108b6..fb2de045 100755
--- a/examples/colors.py
+++ b/examples/colors.py
@@ -53,6 +53,7 @@ BG_COLORS ={
'white':Back.WHITE,
}
+
class CmdLineApp(cmd2.Cmd):
"""Example cmd2 application demonstrating colorized output."""
@@ -71,14 +72,14 @@ class CmdLineApp(cmd2.Cmd):
self.shortcuts.update({'&': 'speak'})
# Set use_ipython to True to enable the "ipy" command which embeds and interactive IPython shell
- super().__init__(use_ipython=False)
+ super().__init__(use_ipython=True)
speak_parser = argparse.ArgumentParser()
speak_parser.add_argument('-p', '--piglatin', action='store_true', help='atinLay')
speak_parser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE')
speak_parser.add_argument('-r', '--repeat', type=int, help='output [n] times')
- speak_parser.add_argument('-f', '--fg', help='foreground color to apply to output')
- speak_parser.add_argument('-b', '--bg', help='background color to apply to output')
+ speak_parser.add_argument('-f', '--fg', choices=FG_COLORS, help='foreground color to apply to output')
+ speak_parser.add_argument('-b', '--bg', choices=BG_COLORS, help='background color to apply to output')
speak_parser.add_argument('words', nargs='+', help='words to say')
@cmd2.with_argparser(speak_parser)
@@ -95,9 +96,9 @@ class CmdLineApp(cmd2.Cmd):
repetitions = args.repeat or 1
color_on = ''
- if args.fg and args.fg in FG_COLORS:
+ if args.fg:
color_on += FG_COLORS[args.fg]
- if args.bg and args.bg in BG_COLORS:
+ if args.bg:
color_on += BG_COLORS[args.bg]
color_off = Fore.RESET + Back.RESET
diff --git a/tests/conftest.py b/tests/conftest.py
index c86748e8..e177496b 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -94,7 +94,7 @@ timing: False
"""
SHOW_LONG = """
-colors: Terminal # Allow colorized output
+colors: Terminal # Allow colorized output (valid values: Terminal, Always, Never)
continuation_prompt: > # On 2nd+ line of input
debug: False # Show full error stack on error
echo: False # Echo command issued into output