Skip to content

Commit 089c8ea

Browse files
authored
Merge pull request #738 from python-cmd2/presentation_changes
Presentation changes
2 parents 73d1c34 + 11cb8c0 commit 089c8ea

File tree

3 files changed

+38
-14
lines changed

3 files changed

+38
-14
lines changed

cmd2/argparse_custom.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,19 @@ def my_completer_function(text, line, begidx, endidx):
8181
parser.add_argument('-o', '--options', completer_method=cmd2.Cmd.path_complete)
8282
8383
84-
In all cases in which function/methods are passed you can use functools.partial() to prepopulate
85-
values of the underlying function.
84+
You can use functools.partial() to prepopulate values of the underlying choices and completer functions/methods.
8685
8786
Example:
8887
This says to call path_complete with a preset value for its path_filter argument.
8988
completer_method = functools.partial(path_complete,
9089
path_filter=lambda path: os.path.isdir(path))
9190
parser.add_argument('-o', '--options', choices_method=completer_method)
9291
92+
Of the 5 tab-completion parameters, choices is the only one where argparse validates user input against items
93+
in the choices list. This is because the other 4 parameters are meant to tab complete data sets that are viewed
94+
as dynamic. Therefore it is up to the user to validate if the user has typed an acceptable value for these
95+
arguments.
96+
9397
CompletionItem Class:
9498
This class was added to help in cases where uninformative data is being tab completed. For instance,
9599
tab completing ID numbers isn't very helpful to a user without context. Returning a list of CompletionItems

cmd2/cmd2.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1724,10 +1724,11 @@ def parseline(self, line: str) -> Tuple[str, str, str]:
17241724
statement = self.statement_parser.parse_command_only(line)
17251725
return statement.command, statement.args, statement.command_and_args
17261726

1727-
def onecmd_plus_hooks(self, line: str, py_bridge_call: bool = False) -> bool:
1727+
def onecmd_plus_hooks(self, line: str, *, add_to_history: bool = True, py_bridge_call: bool = False) -> bool:
17281728
"""Top-level function called by cmdloop() to handle parsing a line and running the command and all of its hooks.
17291729
17301730
:param line: line of text read from input
1731+
:param add_to_history: If True, then add this command to history. Defaults to True.
17311732
:param py_bridge_call: This should only ever be set to True by PyBridge to signify the beginning
17321733
of an app() call from Python. It is used to enable/disable the storage of the
17331734
command's stdout.
@@ -1795,7 +1796,7 @@ def onecmd_plus_hooks(self, line: str, py_bridge_call: bool = False) -> bool:
17951796
statement = self.precmd(statement)
17961797

17971798
# go run the command function
1798-
stop = self.onecmd(statement)
1799+
stop = self.onecmd(statement, add_to_history=add_to_history)
17991800

18001801
# postcommand hooks
18011802
data = plugin.PostcommandData(stop, statement)
@@ -1852,12 +1853,13 @@ def _run_cmdfinalization_hooks(self, stop: bool, statement: Optional[Statement])
18521853
except Exception as ex:
18531854
self.pexcept(ex)
18541855

1855-
def runcmds_plus_hooks(self, cmds: List[Union[HistoryItem, str]]) -> bool:
1856+
def runcmds_plus_hooks(self, cmds: List[Union[HistoryItem, str]], *, add_to_history: bool = True) -> bool:
18561857
"""
18571858
Used when commands are being run in an automated fashion like text scripts or history replays.
18581859
The prompt and command line for each command will be printed if echo is True.
18591860
18601861
:param cmds: commands to run
1862+
:param add_to_history: If True, then add these commands to history. Defaults to True.
18611863
:return: True if running of commands should stop
18621864
"""
18631865
for line in cmds:
@@ -1867,7 +1869,7 @@ def runcmds_plus_hooks(self, cmds: List[Union[HistoryItem, str]]) -> bool:
18671869
if self.echo:
18681870
self.poutput('{}{}'.format(self.prompt, line))
18691871

1870-
if self.onecmd_plus_hooks(line):
1872+
if self.onecmd_plus_hooks(line, add_to_history=add_to_history):
18711873
return True
18721874

18731875
return False
@@ -2167,13 +2169,15 @@ def _cmd_func_name(self, command: str) -> str:
21672169
target = COMMAND_FUNC_PREFIX + command
21682170
return target if callable(getattr(self, target, None)) else ''
21692171

2170-
def onecmd(self, statement: Union[Statement, str]) -> bool:
2172+
# noinspection PyMethodOverriding
2173+
def onecmd(self, statement: Union[Statement, str], *, add_to_history: bool = True) -> bool:
21712174
""" This executes the actual do_* method for a command.
21722175
21732176
If the command provided doesn't exist, then it executes default() instead.
21742177
21752178
:param statement: intended to be a Statement instance parsed command from the input stream, alternative
21762179
acceptance of a str is present only for backward compatibility with cmd
2180+
:param add_to_history: If True, then add this command to history. Defaults to True.
21772181
:return: a flag indicating whether the interpretation of commands should stop
21782182
"""
21792183
# For backwards compatibility with cmd, allow a str to be passed in
@@ -2183,8 +2187,9 @@ def onecmd(self, statement: Union[Statement, str]) -> bool:
21832187
func = self.cmd_func(statement.command)
21842188
if func:
21852189
# Check to see if this command should be stored in history
2186-
if statement.command not in self.exclude_from_history \
2187-
and statement.command not in self.disabled_commands:
2190+
if statement.command not in self.exclude_from_history and \
2191+
statement.command not in self.disabled_commands and add_to_history:
2192+
21882193
self.history.append(statement)
21892194

21902195
stop = func(statement)
@@ -2391,7 +2396,7 @@ def _alias_delete(self, args: argparse.Namespace) -> None:
23912396
self.aliases.clear()
23922397
self.poutput("All aliases deleted")
23932398
elif not args.name:
2394-
self.do_help('alias delete')
2399+
self.perror("Either --all or alias name(s) must be specified")
23952400
else:
23962401
for cur_name in utils.remove_duplicates(args.name):
23972402
if cur_name in self.aliases:
@@ -2571,7 +2576,7 @@ def _macro_delete(self, args: argparse.Namespace) -> None:
25712576
self.macros.clear()
25722577
self.poutput("All macros deleted")
25732578
elif not args.name:
2574-
self.do_help('macro delete')
2579+
self.perror("Either --all or macro name(s) must be specified")
25752580
else:
25762581
for cur_name in utils.remove_duplicates(args.name):
25772582
if cur_name in self.macros:
@@ -2640,7 +2645,7 @@ def _macro_list(self, args: argparse.Namespace) -> None:
26402645
" macro create show_results print_results -type {1} \"|\" less\n"
26412646
"\n"
26422647
" Because macros do not resolve until after hitting Enter, tab completion\n"
2643-
" will only complete paths while entering a macro.")
2648+
" will only complete paths while typing a macro.")
26442649

26452650
macro_create_parser = macro_subparsers.add_parser('create', help=macro_create_help,
26462651
description=macro_create_description,

tests/test_cmd2.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,7 +1617,7 @@ def test_alias_delete_non_existing(base_app):
16171617

16181618
def test_alias_delete_no_name(base_app):
16191619
out, err = run_cmd(base_app, 'alias delete')
1620-
assert "Usage: alias delete" in out[0]
1620+
assert "Either --all or alias name(s)" in err[0]
16211621

16221622
def test_multiple_aliases(base_app):
16231623
alias1 = 'h1'
@@ -1768,7 +1768,7 @@ def test_macro_delete_non_existing(base_app):
17681768

17691769
def test_macro_delete_no_name(base_app):
17701770
out, err = run_cmd(base_app, 'macro delete')
1771-
assert "Usage: macro delete" in out[0]
1771+
assert "Either --all or macro name(s)" in err[0]
17721772

17731773
def test_multiple_macros(base_app):
17741774
macro1 = 'h1'
@@ -1853,6 +1853,21 @@ def test_onecmd_raw_str_quit(outsim_app):
18531853
assert stop
18541854
assert out == ''
18551855

1856+
def test_onecmd_add_to_history(outsim_app):
1857+
line = "help"
1858+
saved_hist_len = len(outsim_app.history)
1859+
1860+
# Allow command to be added to history
1861+
outsim_app.onecmd(line, add_to_history=True)
1862+
new_hist_len = len(outsim_app.history)
1863+
assert new_hist_len == saved_hist_len + 1
1864+
1865+
saved_hist_len = new_hist_len
1866+
1867+
# Prevent command from being added to history
1868+
outsim_app.onecmd(line, add_to_history=False)
1869+
new_hist_len = len(outsim_app.history)
1870+
assert new_hist_len == saved_hist_len
18561871

18571872
def test_get_all_commands(base_app):
18581873
# Verify that the base app has the expected commands

0 commit comments

Comments
 (0)