Skip to content

Commit d35f7d7

Browse files
authored
getting_started.py now demonstrates how to use common cmd2 deocrators (#1705)
`getting_started.py` now demonstrates how to use common both the `@with_argparser` and `@with_annotated` decorators for defining command arguments.
1 parent a442a0d commit d35f7d7

1 file changed

Lines changed: 60 additions & 7 deletions

File tree

examples/getting_started.py

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,16 @@
1717
13) Right prompt which displays contextual information
1818
14) Background thread to update the content displayed by the bottom toolbar outside of the UI thread to keep things responsive
1919
15) Using preloop() and postloop() hooks to start and stop a background thread
20+
16) Using the with_annotated decorator to parse typed command arguments
21+
17) Using the with_argparser decorator to parse command arguments with a custom parser
2022
"""
2123

24+
import argparse
2225
import datetime
2326
import pathlib
2427
import sys
2528
import threading
29+
from typing import Annotated
2630

2731
from prompt_toolkit.application import get_app
2832
from prompt_toolkit.formatted_text import AnyFormattedText
@@ -33,6 +37,7 @@
3337
Color,
3438
stylize,
3539
)
40+
from cmd2.annotated import Option
3641

3742

3843
class BasicApp(cmd2.Cmd):
@@ -156,18 +161,66 @@ def get_rprompt(self) -> AnyFormattedText:
156161
text = f"cwd={current_working_directory}"
157162
return [(style, text)]
158163

164+
@cmd2.with_annotated
165+
def do_cat(
166+
self,
167+
path: pathlib.Path, # Required positional argument with type annotation, tab-completes filesystem paths automatically
168+
numbered: Annotated[ # Optional flag argument with type annotation, default value, and help text
169+
bool, Option("-n", "--number", help_text="prefix each line with its number")
170+
] = False,
171+
) -> None:
172+
"""Print a file's contents. `path` tab-completes filesystem paths automatically.
173+
174+
Try:
175+
cat <TAB> # path completes files/dirs -- no completer wired
176+
cat notes.txt
177+
cat notes.txt -n # -n / --number, declared via Option metadata
178+
cat notes.txt --no-number
179+
"""
180+
text = path.read_text()
181+
lines = text.splitlines()
182+
if numbered:
183+
numbered_lines = []
184+
for index, line in enumerate(lines, start=1):
185+
numbered_lines.append(f"{index}: {line}")
186+
self.ppaged("\n".join(numbered_lines))
187+
else:
188+
# Just print the contents using a pager
189+
self.ppaged(path.read_text())
190+
159191
def do_intro(self, _: cmd2.Statement) -> None:
160-
"""Display the intro banner."""
192+
"""Display the intro banner.
193+
194+
This command uses raw statement parsing. In general, we strongly recommend against this approach. But since this
195+
command effectively takes no arguments, it is safe to use raw statement parsing here.
196+
197+
The & key is also used as a shortcut for this command, so you can also type & to display the intro banner.
198+
"""
161199
self.poutput(self.intro)
162200

163-
def do_echo(self, arg: cmd2.Statement) -> None:
201+
@staticmethod
202+
def _build_echo_parser() -> cmd2.Cmd2ArgumentParser:
203+
"""Parser factory method for use with the echo command."""
204+
echo_parser = cmd2.Cmd2ArgumentParser(description="Multiline command that echoes input.")
205+
echo_parser.add_argument("-u", "--upper", action="store_true", help="uppercase the output")
206+
echo_parser.add_argument("-r", "--repeat", type=int, default=1, help="output [n] times")
207+
echo_parser.add_argument("words", nargs="+", help="words to print")
208+
return echo_parser
209+
210+
@cmd2.with_argparser(_build_echo_parser)
211+
def do_echo(self, args: argparse.Namespace) -> None:
164212
"""Multiline command."""
165-
self.poutput(
166-
stylize(
167-
arg,
168-
style=Style(color=self.foreground_color),
213+
output_str = " ".join(args.words)
214+
if args.upper:
215+
output_str = output_str.upper()
216+
217+
for _ in range(args.repeat):
218+
self.poutput(
219+
stylize(
220+
output_str,
221+
style=Style(color=self.foreground_color),
222+
)
169223
)
170-
)
171224

172225

173226
if __name__ == "__main__":

0 commit comments

Comments
 (0)