Skip to content

Commit 8f2a9b0

Browse files
committed
Fixed extra space appended to each alias by "alias list" command.
Added self.last_result unit tests for alias, edit, eof, help, macro, quit, shortcuts, and run_pyscript commands.
1 parent 17146bc commit 8f2a9b0

File tree

4 files changed

+71
-8
lines changed

4 files changed

+71
-8
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
## 2.2.0 (TBD, 2021)
2+
* Bug Fixes
3+
* Fixed extra space appended to each alias by "alias list" command
24
* Enhancements
35
* New function `set_default_command_completer_type()` allows developer to extend and modify the
46
behavior of `ArgparseCompleter`.

cmd2/cmd2.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -351,14 +351,14 @@ def __init__(
351351
# Defines app-specific variables/functions available in Python shells and pyscripts
352352
self.py_locals: Dict[str, Any] = dict()
353353

354-
# True if running inside a Python script or interactive console, False otherwise
354+
# True if running inside a Python shell or pyscript, False otherwise
355355
self._in_py = False
356356

357357
self.statement_parser = StatementParser(
358358
terminators=terminators, multiline_commands=multiline_commands, shortcuts=shortcuts
359359
)
360360

361-
# Stores results from the last command run to enable usage of results in a Python script or Python console
361+
# Stores results from the last command run to enable usage of results in Python shells and pyscripts
362362
self.last_result: Any = None
363363

364364
# Used by run_script command to store current script dir as a LIFO queue to support _relative_run_script command
@@ -2134,7 +2134,7 @@ def in_script(self) -> bool:
21342134
return self._current_script_dir is not None
21352135

21362136
def in_pyscript(self) -> bool:
2137-
"""Return whether a pyscript is running"""
2137+
"""Return whether running inside a Python shell or pyscript"""
21382138
return self._in_py
21392139

21402140
@property
@@ -3271,7 +3271,7 @@ def _alias_list(self, args: argparse.Namespace) -> None:
32713271
utils.quote_specific_tokens(command_args, tokens_to_quote)
32723272

32733273
val = command
3274-
if args:
3274+
if command_args:
32753275
val += ' ' + ' '.join(command_args)
32763276

32773277
self.poutput(f"alias create {name} {val}")
@@ -4228,8 +4228,6 @@ def py_quit() -> None:
42284228
self.perror("Recursively entering interactive Python shells is not allowed")
42294229
return None
42304230

4231-
self.last_result = True
4232-
42334231
try:
42344232
self._in_py = True
42354233
py_code_to_run = ''
@@ -4270,6 +4268,7 @@ def py_quit() -> None:
42704268
local_vars['__name__'] = '__console__'
42714269

42724270
# Create the Python interpreter
4271+
self.last_result = True
42734272
interp = InteractiveConsole(locals=local_vars)
42744273

42754274
# Check if we are running Python code
@@ -4327,6 +4326,7 @@ def do_py(self, _: argparse.Namespace) -> Optional[bool]:
43274326
Run an interactive Python shell
43284327
:return: True if running of commands should stop
43294328
"""
4329+
# self.last_resort will be set by _run_python()
43304330
return self._run_python()
43314331

43324332
run_pyscript_parser = argparse_custom.DEFAULT_ARGUMENT_PARSER(description="Run a Python script file inside the console")
@@ -4361,6 +4361,8 @@ def do_run_pyscript(self, args: argparse.Namespace) -> Optional[bool]:
43614361
try:
43624362
# Overwrite sys.argv to allow the script to take command line arguments
43634363
sys.argv = [args.script_path] + args.script_arguments
4364+
4365+
# self.last_resort will be set by _run_python()
43644366
py_return = self._run_python(pyscript=args.script_path)
43654367
finally:
43664368
# Restore command line arguments to original state

tests/test_cmd2.py

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,13 @@ def test_empty_statement(base_app):
7676

7777
def test_base_help(base_app):
7878
out, err = run_cmd(base_app, 'help')
79+
assert base_app.last_result is True
7980
verify_help_text(base_app, out)
8081

8182

8283
def test_base_help_verbose(base_app):
8384
out, err = run_cmd(base_app, 'help -v')
85+
assert base_app.last_result is True
8486
verify_help_text(base_app, out)
8587

8688
# Make sure :param type lines are filtered out of help summary
@@ -89,6 +91,7 @@ def test_base_help_verbose(base_app):
8991
base_app.do_help.__func__.__doc__ = help_doc
9092

9193
out, err = run_cmd(base_app, 'help --verbose')
94+
assert base_app.last_result is True
9295
verify_help_text(base_app, out)
9396
assert ':param' not in ''.join(out)
9497

@@ -114,6 +117,7 @@ def test_base_shortcuts(base_app):
114117
out, err = run_cmd(base_app, 'shortcuts')
115118
expected = normalize(SHORTCUTS_TXT)
116119
assert out == expected
120+
assert base_app.last_result is True
117121

118122

119123
def test_command_starts_with_shortcut():
@@ -1066,6 +1070,7 @@ def test_custom_command_help(help_app):
10661070
out, err = run_cmd(help_app, 'help squat')
10671071
expected = normalize('This command does diddly squat...')
10681072
assert out == expected
1073+
assert help_app.last_result is True
10691074

10701075

10711076
def test_custom_help_menu(help_app):
@@ -1076,18 +1081,21 @@ def test_custom_help_menu(help_app):
10761081
def test_help_undocumented(help_app):
10771082
out, err = run_cmd(help_app, 'help undoc')
10781083
assert err[0].startswith("No help on undoc")
1084+
assert help_app.last_result is False
10791085

10801086

10811087
def test_help_overridden_method(help_app):
10821088
out, err = run_cmd(help_app, 'help edit')
10831089
expected = normalize('This overrides the edit command and does nothing.')
10841090
assert out == expected
1091+
assert help_app.last_result is True
10851092

10861093

10871094
def test_help_multiline_docstring(help_app):
10881095
out, err = run_cmd(help_app, 'help multiline_docstr')
10891096
expected = normalize('This documentation\nis multiple lines\nand there are no\ntabs')
10901097
assert out == expected
1098+
assert help_app.last_result is True
10911099

10921100

10931101
class HelpCategoriesApp(cmd2.Cmd):
@@ -1132,11 +1140,13 @@ def helpcat_app():
11321140

11331141
def test_help_cat_base(helpcat_app):
11341142
out, err = run_cmd(helpcat_app, 'help')
1143+
assert helpcat_app.last_result is True
11351144
verify_help_text(helpcat_app, out)
11361145

11371146

11381147
def test_help_cat_verbose(helpcat_app):
11391148
out, err = run_cmd(helpcat_app, 'help --verbose')
1149+
assert helpcat_app.last_result is True
11401150
verify_help_text(helpcat_app, out)
11411151

11421152

@@ -1532,6 +1542,13 @@ def test_is_text_file_bad_input(base_app):
15321542
def test_eof(base_app):
15331543
# Only thing to verify is that it returns True
15341544
assert base_app.do_eof('')
1545+
assert base_app.last_result is True
1546+
1547+
1548+
def test_quit(base_app):
1549+
# Only thing to verify is that it returns True
1550+
assert base_app.do_quit('')
1551+
assert base_app.last_result is True
15351552

15361553

15371554
def test_echo(capsys):
@@ -1795,6 +1812,7 @@ def test_alias_create(base_app):
17951812
# Create the alias
17961813
out, err = run_cmd(base_app, 'alias create fake run_pyscript')
17971814
assert out == normalize("Alias 'fake' created")
1815+
assert base_app.last_result is True
17981816

17991817
# Use the alias
18001818
out, err = run_cmd(base_app, 'fake')
@@ -1803,23 +1821,29 @@ def test_alias_create(base_app):
18031821
# See a list of aliases
18041822
out, err = run_cmd(base_app, 'alias list')
18051823
assert out == normalize('alias create fake run_pyscript')
1824+
assert len(base_app.last_result) == len(base_app.aliases)
18061825

18071826
# Look up the new alias
18081827
out, err = run_cmd(base_app, 'alias list fake')
18091828
assert out == normalize('alias create fake run_pyscript')
1829+
assert base_app.last_result['fake'] == "run_pyscript"
18101830

18111831
# Overwrite alias
18121832
out, err = run_cmd(base_app, 'alias create fake help')
18131833
assert out == normalize("Alias 'fake' overwritten")
1834+
assert base_app.last_result is True
18141835

18151836
# Look up the updated alias
18161837
out, err = run_cmd(base_app, 'alias list fake')
18171838
assert out == normalize('alias create fake help')
1839+
assert base_app.last_result['fake'] == "help"
18181840

18191841

18201842
def test_alias_create_with_quoted_tokens(base_app):
18211843
"""Demonstrate that quotes in alias value will be preserved"""
1822-
create_command = 'alias create fake help ">" "out file.txt" ";"'
1844+
alias_name = "fake"
1845+
alias_command = 'help ">" "out file.txt" ";"'
1846+
create_command = f"alias create {alias_name} {alias_command}"
18231847

18241848
# Create the alias
18251849
out, err = run_cmd(base_app, create_command)
@@ -1828,24 +1852,28 @@ def test_alias_create_with_quoted_tokens(base_app):
18281852
# Look up the new alias and verify all quotes are preserved
18291853
out, err = run_cmd(base_app, 'alias list fake')
18301854
assert out == normalize(create_command)
1855+
assert base_app.last_result[alias_name] == alias_command
18311856

18321857

18331858
@pytest.mark.parametrize('alias_name', invalid_command_name)
18341859
def test_alias_create_invalid_name(base_app, alias_name, capsys):
18351860
out, err = run_cmd(base_app, 'alias create {} help'.format(alias_name))
18361861
assert "Invalid alias name" in err[0]
1862+
assert base_app.last_result is False
18371863

18381864

18391865
def test_alias_create_with_command_name(base_app):
18401866
out, err = run_cmd(base_app, 'alias create help stuff')
18411867
assert "Alias cannot have the same name as a command" in err[0]
1868+
assert base_app.last_result is False
18421869

18431870

18441871
def test_alias_create_with_macro_name(base_app):
18451872
macro = "my_macro"
18461873
run_cmd(base_app, 'macro create {} help'.format(macro))
18471874
out, err = run_cmd(base_app, 'alias create {} help'.format(macro))
18481875
assert "Alias cannot have the same name as a macro" in err[0]
1876+
assert base_app.last_result is False
18491877

18501878

18511879
def test_alias_that_resolves_into_comment(base_app):
@@ -1863,6 +1891,7 @@ def test_alias_list_invalid_alias(base_app):
18631891
# Look up invalid alias
18641892
out, err = run_cmd(base_app, 'alias list invalid')
18651893
assert "Alias 'invalid' not found" in err[0]
1894+
assert base_app.last_result == {}
18661895

18671896

18681897
def test_alias_delete(base_app):
@@ -1872,21 +1901,25 @@ def test_alias_delete(base_app):
18721901
# Delete the alias
18731902
out, err = run_cmd(base_app, 'alias delete fake')
18741903
assert out == normalize("Alias 'fake' deleted")
1904+
assert base_app.last_result is True
18751905

18761906

18771907
def test_alias_delete_all(base_app):
18781908
out, err = run_cmd(base_app, 'alias delete --all')
18791909
assert out == normalize("All aliases deleted")
1910+
assert base_app.last_result is True
18801911

18811912

18821913
def test_alias_delete_non_existing(base_app):
18831914
out, err = run_cmd(base_app, 'alias delete fake')
18841915
assert "Alias 'fake' does not exist" in err[0]
1916+
assert base_app.last_result is True
18851917

18861918

18871919
def test_alias_delete_no_name(base_app):
18881920
out, err = run_cmd(base_app, 'alias delete')
18891921
assert "Either --all or alias name(s)" in err[0]
1922+
assert base_app.last_result is False
18901923

18911924

18921925
def test_multiple_aliases(base_app):
@@ -1911,6 +1944,7 @@ def test_macro_create(base_app):
19111944
# Create the macro
19121945
out, err = run_cmd(base_app, 'macro create fake run_pyscript')
19131946
assert out == normalize("Macro 'fake' created")
1947+
assert base_app.last_result is True
19141948

19151949
# Use the macro
19161950
out, err = run_cmd(base_app, 'fake')
@@ -1919,23 +1953,29 @@ def test_macro_create(base_app):
19191953
# See a list of macros
19201954
out, err = run_cmd(base_app, 'macro list')
19211955
assert out == normalize('macro create fake run_pyscript')
1956+
assert len(base_app.last_result) == len(base_app.macros)
19221957

19231958
# Look up the new macro
19241959
out, err = run_cmd(base_app, 'macro list fake')
19251960
assert out == normalize('macro create fake run_pyscript')
1961+
assert base_app.last_result['fake'] == "run_pyscript"
19261962

19271963
# Overwrite macro
19281964
out, err = run_cmd(base_app, 'macro create fake help')
19291965
assert out == normalize("Macro 'fake' overwritten")
1966+
assert base_app.last_result is True
19301967

19311968
# Look up the updated macro
19321969
out, err = run_cmd(base_app, 'macro list fake')
19331970
assert out == normalize('macro create fake help')
1971+
assert base_app.last_result['fake'] == "help"
19341972

19351973

19361974
def test_macro_create_with_quoted_tokens(base_app):
19371975
"""Demonstrate that quotes in macro value will be preserved"""
1938-
create_command = 'macro create fake help ">" "out file.txt" ";"'
1976+
macro_name = "fake"
1977+
macro_command = 'help ">" "out file.txt" ";"'
1978+
create_command = f"macro create {macro_name} {macro_command}"
19391979

19401980
# Create the macro
19411981
out, err = run_cmd(base_app, create_command)
@@ -1944,24 +1984,28 @@ def test_macro_create_with_quoted_tokens(base_app):
19441984
# Look up the new macro and verify all quotes are preserved
19451985
out, err = run_cmd(base_app, 'macro list fake')
19461986
assert out == normalize(create_command)
1987+
assert base_app.last_result[macro_name] == macro_command
19471988

19481989

19491990
@pytest.mark.parametrize('macro_name', invalid_command_name)
19501991
def test_macro_create_invalid_name(base_app, macro_name):
19511992
out, err = run_cmd(base_app, 'macro create {} help'.format(macro_name))
19521993
assert "Invalid macro name" in err[0]
1994+
assert base_app.last_result is False
19531995

19541996

19551997
def test_macro_create_with_command_name(base_app):
19561998
out, err = run_cmd(base_app, 'macro create help stuff')
19571999
assert "Macro cannot have the same name as a command" in err[0]
2000+
assert base_app.last_result is False
19582001

19592002

19602003
def test_macro_create_with_alias_name(base_app):
19612004
macro = "my_macro"
19622005
run_cmd(base_app, 'alias create {} help'.format(macro))
19632006
out, err = run_cmd(base_app, 'macro create {} help'.format(macro))
19642007
assert "Macro cannot have the same name as an alias" in err[0]
2008+
assert base_app.last_result is False
19652009

19662010

19672011
def test_macro_create_with_args(base_app):
@@ -2008,12 +2052,14 @@ def test_macro_create_with_missing_arg_nums(base_app):
20082052
# Create the macro
20092053
out, err = run_cmd(base_app, 'macro create fake help {1} {3}')
20102054
assert "Not all numbers between 1 and 3" in err[0]
2055+
assert base_app.last_result is False
20112056

20122057

20132058
def test_macro_create_with_invalid_arg_num(base_app):
20142059
# Create the macro
20152060
out, err = run_cmd(base_app, 'macro create fake help {1} {-1} {0}')
20162061
assert "Argument numbers must be greater than 0" in err[0]
2062+
assert base_app.last_result is False
20172063

20182064

20192065
def test_macro_create_with_unicode_numbered_arg(base_app):
@@ -2029,6 +2075,7 @@ def test_macro_create_with_unicode_numbered_arg(base_app):
20292075
def test_macro_create_with_missing_unicode_arg_nums(base_app):
20302076
out, err = run_cmd(base_app, 'macro create fake help {1} {\N{ARABIC-INDIC DIGIT THREE}}')
20312077
assert "Not all numbers between 1 and 3" in err[0]
2078+
assert base_app.last_result is False
20322079

20332080

20342081
def test_macro_that_resolves_into_comment(base_app):
@@ -2046,6 +2093,7 @@ def test_macro_list_invalid_macro(base_app):
20462093
# Look up invalid macro
20472094
out, err = run_cmd(base_app, 'macro list invalid')
20482095
assert "Macro 'invalid' not found" in err[0]
2096+
assert base_app.last_result == {}
20492097

20502098

20512099
def test_macro_delete(base_app):
@@ -2055,21 +2103,25 @@ def test_macro_delete(base_app):
20552103
# Delete the macro
20562104
out, err = run_cmd(base_app, 'macro delete fake')
20572105
assert out == normalize("Macro 'fake' deleted")
2106+
assert base_app.last_result is True
20582107

20592108

20602109
def test_macro_delete_all(base_app):
20612110
out, err = run_cmd(base_app, 'macro delete --all')
20622111
assert out == normalize("All macros deleted")
2112+
assert base_app.last_result is True
20632113

20642114

20652115
def test_macro_delete_non_existing(base_app):
20662116
out, err = run_cmd(base_app, 'macro delete fake')
20672117
assert "Macro 'fake' does not exist" in err[0]
2118+
assert base_app.last_result is True
20682119

20692120

20702121
def test_macro_delete_no_name(base_app):
20712122
out, err = run_cmd(base_app, 'macro delete')
20722123
assert "Either --all or macro name(s)" in err[0]
2124+
assert base_app.last_result is False
20732125

20742126

20752127
def test_multiple_macros(base_app):

0 commit comments

Comments
 (0)