Mercurial > repos > shellac > guppy_basecaller
diff env/lib/python3.7/site-packages/humanfriendly/cli.py @ 2:6af9afd405e9 draft
"planemo upload commit 0a63dd5f4d38a1f6944587f52a8cd79874177fc1"
author | shellac |
---|---|
date | Thu, 14 May 2020 14:56:58 -0400 |
parents | 26e78fe6e8c4 |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/env/lib/python3.7/site-packages/humanfriendly/cli.py Thu May 14 14:56:58 2020 -0400 @@ -0,0 +1,291 @@ +# Human friendly input/output in Python. +# +# Author: Peter Odding <peter@peterodding.com> +# Last Change: March 1, 2020 +# URL: https://humanfriendly.readthedocs.io + +""" +Usage: humanfriendly [OPTIONS] + +Human friendly input/output (text formatting) on the command +line based on the Python package with the same name. + +Supported options: + + -c, --run-command + + Execute an external command (given as the positional arguments) and render + a spinner and timer while the command is running. The exit status of the + command is propagated. + + --format-table + + Read tabular data from standard input (each line is a row and each + whitespace separated field is a column), format the data as a table and + print the resulting table to standard output. See also the --delimiter + option. + + -d, --delimiter=VALUE + + Change the delimiter used by --format-table to VALUE (a string). By default + all whitespace is treated as a delimiter. + + -l, --format-length=LENGTH + + Convert a length count (given as the integer or float LENGTH) into a human + readable string and print that string to standard output. + + -n, --format-number=VALUE + + Format a number (given as the integer or floating point number VALUE) with + thousands separators and two decimal places (if needed) and print the + formatted number to standard output. + + -s, --format-size=BYTES + + Convert a byte count (given as the integer BYTES) into a human readable + string and print that string to standard output. + + -b, --binary + + Change the output of -s, --format-size to use binary multiples of bytes + (base-2) instead of the default decimal multiples of bytes (base-10). + + -t, --format-timespan=SECONDS + + Convert a number of seconds (given as the floating point number SECONDS) + into a human readable timespan and print that string to standard output. + + --parse-length=VALUE + + Parse a human readable length (given as the string VALUE) and print the + number of metres to standard output. + + --parse-size=VALUE + + Parse a human readable data size (given as the string VALUE) and print the + number of bytes to standard output. + + --demo + + Demonstrate changing the style and color of the terminal font using ANSI + escape sequences. + + -h, --help + + Show this message and exit. +""" + +# Standard library modules. +import functools +import getopt +import pipes +import subprocess +import sys + +# Modules included in our package. +from humanfriendly import ( + Timer, + format_length, + format_number, + format_size, + format_timespan, + parse_length, + parse_size, +) +from humanfriendly.tables import format_pretty_table, format_smart_table +from humanfriendly.terminal import ( + ANSI_COLOR_CODES, + ANSI_TEXT_STYLES, + HIGHLIGHT_COLOR, + ansi_strip, + ansi_wrap, + enable_ansi_support, + find_terminal_size, + output, + usage, + warning, +) +from humanfriendly.terminal.spinners import Spinner + +# Public identifiers that require documentation. +__all__ = ( + 'demonstrate_256_colors', + 'demonstrate_ansi_formatting', + 'main', + 'print_formatted_length', + 'print_formatted_number', + 'print_formatted_size', + 'print_formatted_table', + 'print_formatted_timespan', + 'print_parsed_length', + 'print_parsed_size', + 'run_command', +) + + +def main(): + """Command line interface for the ``humanfriendly`` program.""" + enable_ansi_support() + try: + options, arguments = getopt.getopt(sys.argv[1:], 'cd:l:n:s:bt:h', [ + 'run-command', 'format-table', 'delimiter=', 'format-length=', + 'format-number=', 'format-size=', 'binary', 'format-timespan=', + 'parse-length=', 'parse-size=', 'demo', 'help', + ]) + except Exception as e: + warning("Error: %s", e) + sys.exit(1) + actions = [] + delimiter = None + should_format_table = False + binary = any(o in ('-b', '--binary') for o, v in options) + for option, value in options: + if option in ('-d', '--delimiter'): + delimiter = value + elif option == '--parse-size': + actions.append(functools.partial(print_parsed_size, value)) + elif option == '--parse-length': + actions.append(functools.partial(print_parsed_length, value)) + elif option in ('-c', '--run-command'): + actions.append(functools.partial(run_command, arguments)) + elif option in ('-l', '--format-length'): + actions.append(functools.partial(print_formatted_length, value)) + elif option in ('-n', '--format-number'): + actions.append(functools.partial(print_formatted_number, value)) + elif option in ('-s', '--format-size'): + actions.append(functools.partial(print_formatted_size, value, binary)) + elif option == '--format-table': + should_format_table = True + elif option in ('-t', '--format-timespan'): + actions.append(functools.partial(print_formatted_timespan, value)) + elif option == '--demo': + actions.append(demonstrate_ansi_formatting) + elif option in ('-h', '--help'): + usage(__doc__) + return + if should_format_table: + actions.append(functools.partial(print_formatted_table, delimiter)) + if not actions: + usage(__doc__) + return + for partial in actions: + partial() + + +def run_command(command_line): + """Run an external command and show a spinner while the command is running.""" + timer = Timer() + spinner_label = "Waiting for command: %s" % " ".join(map(pipes.quote, command_line)) + with Spinner(label=spinner_label, timer=timer) as spinner: + process = subprocess.Popen(command_line) + while True: + spinner.step() + spinner.sleep() + if process.poll() is not None: + break + sys.exit(process.returncode) + + +def print_formatted_length(value): + """Print a human readable length.""" + if '.' in value: + output(format_length(float(value))) + else: + output(format_length(int(value))) + + +def print_formatted_number(value): + """Print large numbers in a human readable format.""" + output(format_number(float(value))) + + +def print_formatted_size(value, binary): + """Print a human readable size.""" + output(format_size(int(value), binary=binary)) + + +def print_formatted_table(delimiter): + """Read tabular data from standard input and print a table.""" + data = [] + for line in sys.stdin: + line = line.rstrip() + data.append(line.split(delimiter)) + output(format_pretty_table(data)) + + +def print_formatted_timespan(value): + """Print a human readable timespan.""" + output(format_timespan(float(value))) + + +def print_parsed_length(value): + """Parse a human readable length and print the number of metres.""" + output(parse_length(value)) + + +def print_parsed_size(value): + """Parse a human readable data size and print the number of bytes.""" + output(parse_size(value)) + + +def demonstrate_ansi_formatting(): + """Demonstrate the use of ANSI escape sequences.""" + # First we demonstrate the supported text styles. + output('%s', ansi_wrap('Text styles:', bold=True)) + styles = ['normal', 'bright'] + styles.extend(ANSI_TEXT_STYLES.keys()) + for style_name in sorted(styles): + options = dict(color=HIGHLIGHT_COLOR) + if style_name != 'normal': + options[style_name] = True + style_label = style_name.replace('_', ' ').capitalize() + output(' - %s', ansi_wrap(style_label, **options)) + # Now we demonstrate named foreground and background colors. + for color_type, color_label in (('color', 'Foreground colors'), + ('background', 'Background colors')): + intensities = [ + ('normal', dict()), + ('bright', dict(bright=True)), + ] + if color_type != 'background': + intensities.insert(0, ('faint', dict(faint=True))) + output('\n%s' % ansi_wrap('%s:' % color_label, bold=True)) + output(format_smart_table([ + [color_name] + [ + ansi_wrap( + 'XXXXXX' if color_type != 'background' else (' ' * 6), + **dict(list(kw.items()) + [(color_type, color_name)]) + ) for label, kw in intensities + ] for color_name in sorted(ANSI_COLOR_CODES.keys()) + ], column_names=['Color'] + [ + label.capitalize() for label, kw in intensities + ])) + # Demonstrate support for 256 colors as well. + demonstrate_256_colors(0, 7, 'standard colors') + demonstrate_256_colors(8, 15, 'high-intensity colors') + demonstrate_256_colors(16, 231, '216 colors') + demonstrate_256_colors(232, 255, 'gray scale colors') + + +def demonstrate_256_colors(i, j, group=None): + """Demonstrate 256 color mode support.""" + # Generate the label. + label = '256 color mode' + if group: + label += ' (%s)' % group + output('\n' + ansi_wrap('%s:' % label, bold=True)) + # Generate a simple rendering of the colors in the requested range and + # check if it will fit on a single line (given the terminal's width). + single_line = ''.join(' ' + ansi_wrap(str(n), color=n) for n in range(i, j + 1)) + lines, columns = find_terminal_size() + if columns >= len(ansi_strip(single_line)): + output(single_line) + else: + # Generate a more complex rendering of the colors that will nicely wrap + # over multiple lines without using too many lines. + width = len(str(j)) + 1 + colors_per_line = int(columns / width) + colors = [ansi_wrap(str(n).rjust(width), color=n) for n in range(i, j + 1)] + blocks = [colors[n:n + colors_per_line] for n in range(0, len(colors), colors_per_line)] + output('\n'.join(''.join(b) for b in blocks))