Source code for canvascli.parser

# -*- coding: utf-8 -*-
"""CLI handler for canvas program based on a custom argparser."""

# Standard library imports
import argparse
import sys

# Local imports
from canvascli.canvas import Canvas
from canvascli.utils import positive_int


# PY2/PY3 compatibility. We could use `six` if more things are needed.
if sys.version_info[0] == 2:  # pragma: no cover
    input = raw_input  # noqa


[docs]class ArgumentParserError(Exception): """Custom exception for ThrowingArgumentParser.""" def __init__(self, message): super(ArgumentParserError, self).__init__() self.message = message
[docs]class ThrowingArgumentParser(argparse.ArgumentParser): """Custom argument parser that avoids exit on errors."""
[docs] def error(self, message): """Override method to prevent SystemExit and raise custom exception.""" raise ArgumentParserError(message=message)
[docs]class CommandParserHandler(object): """CLI handler for canvas program based on argparse.""" HELP = "Type 'H' for help" def __init__(self): """CLI handler for canvas program based on argparse.""" self._canvas = Canvas() self._parser = self.create_parser() self._command_history = [] # --- Helper methods # -------------------------------------------------------------------------
[docs] def create_parser(self): """Create the custom parser to evaluate canvas CLI commands.""" parser = ThrowingArgumentParser( description='CanvasCLI: the simple console version of a drawing ' 'program!', add_help=False, ) subparsers = parser.add_subparsers(help='Program commands') # Help command help_parser = subparsers.add_parser('H', add_help=False) help_parser.set_defaults(func=self.print_help) help_parser.set_defaults(help='Display help') # Create command create_parser = subparsers.add_parser('C', add_help=False) create_parser.add_argument('width', type=positive_int, help='Canvas width') create_parser.add_argument('height', type=positive_int, help='Canvas height') create_parser.set_defaults(func=self.create_canvas) create_parser.set_defaults(help='Create a new canvas of given size') # Line command draw_line_parser = subparsers.add_parser('L', add_help=False) draw_line_parser.add_argument('x1', type=positive_int, help='Point 1 x coordinate') draw_line_parser.add_argument('y1', type=positive_int, help='Point 1 y coordinate') draw_line_parser.add_argument('x2', type=positive_int, help='Point 2 x coordinate') draw_line_parser.add_argument('y2', type=positive_int, help='Point 2 y coordinate') draw_line_parser.set_defaults(func=self._canvas.draw_line) draw_line_parser.set_defaults(help='Draw a Line from (x1,y1) to ' '(x2,y2)') # Rectangle command draw_rectangle_parser = subparsers.add_parser('R', add_help=False) draw_rectangle_parser.add_argument('x1', type=positive_int, help='Upper left corner x ' 'coordinate') draw_rectangle_parser.add_argument('y1', type=positive_int, help='Upper left corner y ' 'coordinate') draw_rectangle_parser.add_argument('x2', type=positive_int, help='Lower right corner x ' 'coordinate') draw_rectangle_parser.add_argument('y2', type=positive_int, help='Lower right corner y ' 'coordinate') draw_rectangle_parser.set_defaults(func=self._canvas.draw_rectangle) draw_rectangle_parser.set_defaults(help='Draw a Rectangle given by ' '(x1,y1) and (x2,y2)') # Fill command fill_parser = subparsers.add_parser('B', add_help=False) fill_parser.add_argument('x', type=positive_int, help='Point x coordinate') fill_parser.add_argument('y', type=positive_int, help='Point y coordinate') fill_parser.add_argument('color', type=str, help='Expressed as ' 'an ASCII single character') fill_parser.set_defaults(func=self._canvas.fill) fill_parser.set_defaults(help='Fill the area connected to (x,y) with ' 'color') # Erase command fill_parser = subparsers.add_parser('E', add_help=False) fill_parser.set_defaults(func=self._canvas.erase) fill_parser.set_defaults(help="Erase the contents of the canvas.") # Quit command quit_parser = subparsers.add_parser('Q', add_help=False) quit_parser.set_defaults(func=sys.exit) quit_parser.set_defaults(help='Quit program') return parser
[docs] def parse_args(self, args): """Convenience method for calling the argument parser.""" self._command_history.append(args) return self._parser.parse_args(args)
[docs] def format_help(self): """ Format help for the cli canvas program. This is based on argparse to reuse all the logic that takes care of validating input. """ help_text = ['\n'] subparsers_actions = [ action for action in self._parser._actions if isinstance(action, argparse._SubParsersAction) ] help_text.append(self._parser.description) help_text.append(len(self._parser.description)*'=') help_text.append('\n') for subparsers_action in subparsers_actions: help_text.append(subparsers_action.help + ':') help_text.append((len(subparsers_action.help) + 1)*'-') # Get all subparsers and print help for choice, subparser in subparsers_action.choices.items(): cmd = [choice] for action in subparser._get_positional_actions(): cmd.append(action.dest) line = ' '.join(cmd) pad = 16 - len(line) help_text.append('\n ' + line + ' '*pad + subparser.get_default('help')) for action in subparser._get_positional_actions(): help_text.append(' '*24 + action.dest + ': ' + action.help) help_text.append("\nNotes: \n- Currently only horizontal or vertical " "lines are supported. \n- Horizontal and vertical " "lines will be drawn using the 'x' character.") return '\n'.join(help_text)
[docs] def print_help(self, args=None): """Print help for the cli canvas program.""" args = args print(self.format_help())
# --- Canvas methods requiring special handling # -------------------------------------------------------------------------
[docs] def create_canvas(self, width, height): """Create a new canvas of given size.""" if self._canvas.data is None: self._canvas.create(width, height) else: while True: answer = input('This will replace the previous ' 'canvas! Want to proceed? [Y/N]: ') answer = answer .strip().lower() if answer in ['y', 'yes']: self._canvas.create(width, height) break elif answer in ['n', 'no']: break
[docs] def print_canvas(self): """Convenience method for printing the Canvas.""" if self._canvas._canvas: print(self._canvas)