File: argparse_example.py

package info (click to toggle)
cmd2 3.2.0%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 2,664 kB
  • sloc: python: 17,488; makefile: 114; sh: 39; javascript: 7
file content (176 lines) | stat: -rwxr-xr-x 7,796 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#!/usr/bin/env python3
"""A comprehensive example demonstrating various aspects of using `argparse` for command argument processing.

Demonstrates basic usage of the `cmd2.with_argparser` decorator for passing a `cmd2.Cmd2ArgumentParser` to a `do_*` command
method. The `fsize` and `pow` commands demonstrate various different types of arguments, actions, choices, and completers that
can be used.

The `print_args` and `print_unknown` commands display how argparse arguments are passed to commands in the cases that unknown
arguments are not captured and are captured, respectively.

The `base` and `alternate` commands show an easy way for a single command to have many subcommands, each of which take
different arguments and provides separate contextual help.

Lastly, this example shows how you can also use `argparse` to parse command-line arguments when launching a cmd2 application.
"""

import argparse
import os

import cmd2
from cmd2.string_utils import stylize

# Command categories
ARGPARSE_USAGE = 'Argparse Basic Usage'
ARGPARSE_PRINTING = 'Argparse Printing'
ARGPARSE_SUBCOMMANDS = 'Argparse Subcommands'


class ArgparsingApp(cmd2.Cmd):
    def __init__(self, color: str) -> None:
        """Cmd2 application for demonstrating the use of argparse for command argument parsing."""
        super().__init__(include_ipy=True)
        self.intro = stylize(
            'cmd2 has awesome decorators to make it easy to use Argparse to parse command arguments', style=color
        )

    ## ------ Basic examples of using argparse for command argument parsing -----

    # do_fsize parser
    fsize_parser = cmd2.Cmd2ArgumentParser(description='Obtain the size of a file')
    fsize_parser.add_argument('-c', '--comma', action='store_true', help='add comma for thousands separator')
    fsize_parser.add_argument('-u', '--unit', choices=['MB', 'KB'], help='unit to display size in')
    fsize_parser.add_argument('file_path', help='path of file', completer=cmd2.Cmd.path_complete)

    @cmd2.with_argparser(fsize_parser)
    @cmd2.with_category(ARGPARSE_USAGE)
    def do_fsize(self, args: argparse.Namespace) -> None:
        """Obtain the size of a file."""
        expanded_path = os.path.expanduser(args.file_path)

        try:
            size = os.path.getsize(expanded_path)
        except OSError as ex:
            self.perror(f"Error retrieving size: {ex}")
            return

        if args.unit == 'KB':
            size //= 1024
        elif args.unit == 'MB':
            size //= 1024 * 1024
        else:
            args.unit = 'bytes'
        size = round(size, 2)

        size_str = f'{size:,}' if args.comma else f'{size}'
        self.poutput(f'{size_str} {args.unit}')

    # do_pow parser
    pow_parser = cmd2.Cmd2ArgumentParser()
    pow_parser.add_argument('base', type=int)
    pow_parser.add_argument('exponent', type=int, choices=range(-5, 6))

    @cmd2.with_argparser(pow_parser)
    @cmd2.with_category(ARGPARSE_USAGE)
    def do_pow(self, args: argparse.Namespace) -> None:
        """Raise an integer to a small integer exponent, either positive or negative.

        :param args: argparse arguments
        """
        self.poutput(f'{args.base} ** {args.exponent} == {args.base**args.exponent}')

    ## ------ Examples displaying how argparse arguments are passed to commands by printing them out -----

    argprint_parser = cmd2.Cmd2ArgumentParser()
    argprint_parser.add_argument('-p', '--piglatin', action='store_true', help='atinLay')
    argprint_parser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE')
    argprint_parser.add_argument('-r', '--repeat', type=int, help='output [n] times')
    argprint_parser.add_argument('words', nargs='+', help='words to print')

    @cmd2.with_argparser(argprint_parser)
    @cmd2.with_category(ARGPARSE_PRINTING)
    def do_print_args(self, args: argparse.Namespace) -> None:
        """Print the arpgarse argument list this command was called with."""
        self.poutput(f'print_args was called with the following\n\targuments: {args!r}')

    unknownprint_parser = cmd2.Cmd2ArgumentParser()
    unknownprint_parser.add_argument('-p', '--piglatin', action='store_true', help='atinLay')
    unknownprint_parser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE')
    unknownprint_parser.add_argument('-r', '--repeat', type=int, help='output [n] times')

    @cmd2.with_argparser(unknownprint_parser, with_unknown_args=True)
    @cmd2.with_category(ARGPARSE_PRINTING)
    def do_print_unknown(self, args: argparse.Namespace, unknown: list[str]) -> None:
        """Print the arpgarse argument list this command was called with, including unknown arguments."""
        self.poutput(f'print_unknown was called with the following arguments\n\tknown: {args!r}\n\tunknown: {unknown}')

    ## ------ Examples demonstrating how to use argparse subcommands -----

    # create the top-level parser for the base command
    calculate_parser = cmd2.Cmd2ArgumentParser(description="Perform simple mathematical calculations.")
    calculate_subparsers = calculate_parser.add_subparsers(title='operation', help='Available operations', required=True)

    # create the parser for the "add" subcommand
    add_description = "Add two numbers"
    add_parser = cmd2.Cmd2ArgumentParser("add", description=add_description)
    add_parser.add_argument('num1', type=int, help='The first number')
    add_parser.add_argument('num2', type=int, help='The second number')

    # create the parser for the "add" subcommand
    subtract_description = "Subtract two numbers"
    subtract_parser = cmd2.Cmd2ArgumentParser("subtract", description=subtract_description)
    subtract_parser.add_argument('num1', type=int, help='The first number')
    subtract_parser.add_argument('num2', type=int, help='The second number')

    # subcommand functions for the calculate command
    @cmd2.as_subcommand_to('calculate', 'add', add_parser, help=add_description.lower())
    def add(self, args: argparse.Namespace) -> None:
        """add subcommand of calculate command."""
        result = args.num1 + args.num2
        self.poutput(f"{args.num1} + {args.num2} = {result}")

    @cmd2.as_subcommand_to('calculate', 'subtract', subtract_parser, help=subtract_description.lower())
    def subtract(self, args: argparse.Namespace) -> None:
        """subtract subcommand of calculate command."""
        result = args.num1 - args.num2
        self.poutput(f"{args.num1} - {args.num2} = {result}")

    @cmd2.with_argparser(calculate_parser)
    @cmd2.with_category(ARGPARSE_SUBCOMMANDS)
    def do_calculate(self, args: argparse.Namespace) -> None:
        """Calculate a simple mathematical operation on two integers."""
        handler = args.cmd2_handler.get()
        handler(args)


if __name__ == '__main__':
    import sys

    from cmd2.colors import Color

    # You can do your custom Argparse parsing here to meet your application's needs
    parser = cmd2.Cmd2ArgumentParser(description='Process the arguments however you like.')

    # Add an argument which we will pass to the app to change some behavior
    parser.add_argument(
        '-c',
        '--color',
        choices=[Color.RED, Color.ORANGE1, Color.YELLOW, Color.GREEN, Color.BLUE, Color.PURPLE, Color.VIOLET, Color.WHITE],
        help='Color of intro text',
    )

    # Parse the arguments
    args, unknown_args = parser.parse_known_args()

    color = Color.WHITE
    if args.color:
        color = args.color

    # Perform surgery on sys.argv to remove the arguments which have already been processed by argparse
    sys.argv = sys.argv[:1] + unknown_args

    # Instantiate your cmd2 application
    app = ArgparsingApp(color)

    # And run your cmd2 application
    sys.exit(app.cmdloop())