diff --git a/CHANGELOG.md b/CHANGELOG.md
index 417d9b427..291397a47 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 3.0.0 (TBD)
+* Breaking Change
+ * Removed macros
+
## 2.5.0 (October 23, 2024)
* Breaking Change
* `cmd2` 2.5 supports Python 3.8+ (removed support for Python 3.6 and 3.7)
diff --git a/README.md b/README.md
index ac65e91c0..5ccd594a4 100755
--- a/README.md
+++ b/README.md
@@ -62,9 +62,9 @@ Deep extensive tab completion and help text generation based on the argparse lib
-cmd2 creates the second pillar of 'ease of transition to automation' through alias/macro creation, command line argument parsing and execution of cmd2 scripting.
+cmd2 creates the second pillar of 'ease of transition to automation' through alias creation, command line argument parsing and execution of cmd2 scripting.
-- Flexible alias and macro creation for quick abstraction of commands.
+- Flexible alias creation for quick abstraction of commands.
- Text file scripting of your application with `run_script` (`@`) and `_relative_run_script` (`@@`)
- Powerful and flexible built-in Python scripting of your application using the `run_pyscript` command
- Transcripts for use with built-in regression can be automatically generated from `history -t` or `run_script -t`
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index dbd993495..b53ae7a20 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -37,7 +37,6 @@
import inspect
import os
import pydoc
-import re
import sys
import tempfile
import threading
@@ -122,8 +121,6 @@
single_line_format,
)
from .parsing import (
- Macro,
- MacroArg,
Statement,
StatementParser,
shlex_split,
@@ -363,9 +360,6 @@ def __init__(
# Commands to exclude from the history command
self.exclude_from_history = ['eof', 'history']
- # Dictionary of macro names and their values
- self.macros: Dict[str, Macro] = dict()
-
# Keeps track of typed command history in the Python shell
self._py_history: List[str] = []
@@ -411,7 +405,7 @@ def __init__(
self.help_error = "No help on {}"
# The error that prints when a non-existent command is run
- self.default_error = "{} is not a recognized command, alias, or macro."
+ self.default_error = "{} is not a recognized command or alias."
# If non-empty, this string will be displayed if a broken pipe error occurs
self.broken_pipe_warning = ''
@@ -482,7 +476,7 @@ def __init__(
# If natural sorting is preferred, then set this to NATURAL_SORT_KEY.
# cmd2 uses this key for sorting:
# command and category names
- # alias, macro, settable, and shortcut names
+ # alias, settable, and shortcut names
# tab completion results when self.matches_sorted is False
self.default_sort_key = Cmd.ALPHABETICAL_SORT_KEY
@@ -749,11 +743,6 @@ def _install_command_function(self, command: str, command_wrapper: Callable[...,
self.pwarning(f"Deleting alias '{command}' because it shares its name with a new command")
del self.aliases[command]
- # Check if command shares a name with a macro
- if command in self.macros:
- self.pwarning(f"Deleting macro '{command}' because it shares its name with a new command")
- del self.macros[command]
-
self._register_command_parser(command, command_wrapper)
setattr(self, cmd_func_name, command_wrapper)
@@ -2077,12 +2066,8 @@ def _perform_completion(
# Determine the completer function to use for the command's argument
if custom_settings is None:
- # Check if a macro was entered
- if command in self.macros:
- completer_func = self.path_complete
-
# Check if a command was entered
- elif command in self.get_all_commands():
+ if command in self.get_all_commands():
# Get the completer function for this command
func_attr = getattr(self, constants.COMPLETER_FUNC_PREFIX + command, None)
@@ -2108,7 +2093,7 @@ def _perform_completion(
else:
completer_func = self.completedefault # type: ignore[assignment]
- # Not a recognized macro or command
+ # Not a recognized command
else:
# Check if this command should be run as a shell command
if self.default_to_shell and command in utils.get_exes_in_path(command):
@@ -2271,8 +2256,8 @@ def complete( # type: ignore[override]
parser.add_argument(
'command',
metavar="COMMAND",
- help="command, alias, or macro name",
- choices=self._get_commands_aliases_and_macros_for_completion(),
+ help="command or alias name",
+ choices=self._get_commands_and_aliases_for_completion(),
)
custom_settings = utils.CustomCompletionSettings(parser)
@@ -2360,19 +2345,6 @@ def _get_alias_completion_items(self) -> List[CompletionItem]:
return results
- # Table displayed when tab completing macros
- _macro_completion_table = SimpleTable([Column('Value', width=80)], divider_char=None)
-
- def _get_macro_completion_items(self) -> List[CompletionItem]:
- """Return list of macro names and values as CompletionItems"""
- results: List[CompletionItem] = []
-
- for cur_key in self.macros:
- row_data = [self.macros[cur_key].value]
- results.append(CompletionItem(cur_key, self._macro_completion_table.generate_data_row(row_data)))
-
- return results
-
# Table displayed when tab completing Settables
_settable_completion_table = SimpleTable([Column('Value', width=30), Column('Description', width=60)], divider_char=None)
@@ -2386,12 +2358,11 @@ def _get_settable_completion_items(self) -> List[CompletionItem]:
return results
- def _get_commands_aliases_and_macros_for_completion(self) -> List[str]:
- """Return a list of visible commands, aliases, and macros for tab completion"""
+ def _get_commands_and_aliases_for_completion(self) -> List[str]:
+ """Return a list of visible commands and aliases for tab completion"""
visible_commands = set(self.get_visible_commands())
alias_names = set(self.aliases)
- macro_names = set(self.macros)
- return list(visible_commands | alias_names | macro_names)
+ return list(visible_commands | alias_names)
def get_help_topics(self) -> List[str]:
"""Return a list of help topics"""
@@ -2540,7 +2511,7 @@ def onecmd_plus_hooks(
try:
# Convert the line into a Statement
- statement = self._input_line_to_statement(line, orig_rl_history_length=orig_rl_history_length)
+ statement = self._complete_statement(line, orig_rl_history_length=orig_rl_history_length)
# call the postparsing hooks
postparsing_data = plugin.PostparsingData(False, statement)
@@ -2785,101 +2756,6 @@ def combine_rl_history(statement: Statement) -> None:
return statement
- def _input_line_to_statement(self, line: str, *, orig_rl_history_length: Optional[int] = None) -> Statement:
- """
- Parse the user's input line and convert it to a Statement, ensuring that all macros are also resolved
-
- :param line: the line being parsed
- :param orig_rl_history_length: Optional length of the readline history before the current command was typed.
- This is used to assist in combining multiline readline history entries and is only
- populated by cmd2. Defaults to None.
- :return: parsed command line as a Statement
- :raises: Cmd2ShlexError if a shlex error occurs (e.g. No closing quotation)
- :raises: EmptyStatement when the resulting Statement is blank
- """
- used_macros = []
- orig_line = None
-
- # Continue until all macros are resolved
- while True:
- # Make sure all input has been read and convert it to a Statement
- statement = self._complete_statement(line, orig_rl_history_length=orig_rl_history_length)
-
- # If this is the first loop iteration, save the original line and stop
- # combining multiline history entries in the remaining iterations.
- if orig_line is None:
- orig_line = statement.raw
- orig_rl_history_length = None
-
- # Check if this command matches a macro and wasn't already processed to avoid an infinite loop
- if statement.command in self.macros.keys() and statement.command not in used_macros:
- used_macros.append(statement.command)
- resolve_result = self._resolve_macro(statement)
- if resolve_result is None:
- raise EmptyStatement
- line = resolve_result
- else:
- break
-
- # This will be true when a macro was used
- if orig_line != statement.raw:
- # Build a Statement that contains the resolved macro line
- # but the originally typed line for its raw member.
- statement = Statement(
- statement.args,
- raw=orig_line,
- command=statement.command,
- arg_list=statement.arg_list,
- multiline_command=statement.multiline_command,
- terminator=statement.terminator,
- suffix=statement.suffix,
- pipe_to=statement.pipe_to,
- output=statement.output,
- output_to=statement.output_to,
- )
- return statement
-
- def _resolve_macro(self, statement: Statement) -> Optional[str]:
- """
- Resolve a macro and return the resulting string
-
- :param statement: the parsed statement from the command line
- :return: the resolved macro or None on error
- """
- if statement.command not in self.macros.keys():
- raise KeyError(f"{statement.command} is not a macro")
-
- macro = self.macros[statement.command]
-
- # Make sure enough arguments were passed in
- if len(statement.arg_list) < macro.minimum_arg_count:
- plural = '' if macro.minimum_arg_count == 1 else 's'
- self.perror(f"The macro '{statement.command}' expects at least {macro.minimum_arg_count} argument{plural}")
- return None
-
- # Resolve the arguments in reverse and read their values from statement.argv since those
- # are unquoted. Macro args should have been quoted when the macro was created.
- resolved = macro.value
- reverse_arg_list = sorted(macro.arg_list, key=lambda ma: ma.start_index, reverse=True)
-
- for macro_arg in reverse_arg_list:
- if macro_arg.is_escaped:
- to_replace = '{{' + macro_arg.number_str + '}}'
- replacement = '{' + macro_arg.number_str + '}'
- else:
- to_replace = '{' + macro_arg.number_str + '}'
- replacement = statement.argv[int(macro_arg.number_str)]
-
- parts = resolved.rsplit(to_replace, maxsplit=1)
- resolved = parts[0] + replacement + parts[1]
-
- # Append extra arguments and use statement.arg_list since these arguments need their quotes preserved
- for stmt_arg in statement.arg_list[macro.minimum_arg_count :]:
- resolved += ' ' + stmt_arg
-
- # Restore any terminator, suffix, redirection, etc.
- return resolved + statement.post_command
-
def _redirect_output(self, statement: Statement) -> utils.RedirectionSavedState:
"""Set up a command's output redirection for >, >>, and |.
@@ -3063,7 +2939,7 @@ def onecmd(self, statement: Union[Statement, str], *, add_to_history: bool = Tru
"""
# For backwards compatibility with cmd, allow a str to be passed in
if not isinstance(statement, Statement):
- statement = self._input_line_to_statement(statement)
+ statement = self._complete_statement(statement)
func = self.cmd_func(statement.command)
if func:
@@ -3395,8 +3271,7 @@ def _cmdloop(self) -> None:
# Top-level parser for alias
alias_description = "Manage aliases\n" "\n" "An alias is a command that enables replacement of a word by another string."
- alias_epilog = "See also:\n" " macro"
- alias_parser = argparse_custom.DEFAULT_ARGUMENT_PARSER(description=alias_description, epilog=alias_epilog)
+ alias_parser = argparse_custom.DEFAULT_ARGUMENT_PARSER(description=alias_description)
alias_subparsers = alias_parser.add_subparsers(dest='subcommand', metavar='SUBCOMMAND')
alias_subparsers.required = True
@@ -3430,7 +3305,7 @@ def do_alias(self, args: argparse.Namespace) -> None:
)
alias_create_parser.add_argument('name', help='name of this alias')
alias_create_parser.add_argument(
- 'command', help='what the alias resolves to', choices_provider=_get_commands_aliases_and_macros_for_completion
+ 'command', help='what the alias resolves to', choices_provider=_get_commands_and_aliases_for_completion
)
alias_create_parser.add_argument(
'command_args', nargs=argparse.REMAINDER, help='arguments to pass to command', completer=path_complete
@@ -3451,10 +3326,6 @@ def _alias_create(self, args: argparse.Namespace) -> None:
self.perror("Alias cannot have the same name as a command")
return
- if args.name in self.macros:
- self.perror("Alias cannot have the same name as a macro")
- return
-
# Unquote redirection and terminator tokens
tokens_to_unquote = constants.REDIRECTION_TOKENS
tokens_to_unquote.extend(self.statement_parser.terminators)
@@ -3558,243 +3429,6 @@ def _alias_list(self, args: argparse.Namespace) -> None:
for name in not_found:
self.perror(f"Alias '{name}' not found")
- #############################################################
- # Parsers and functions for macro command and subcommands
- #############################################################
-
- # Top-level parser for macro
- macro_description = "Manage macros\n" "\n" "A macro is similar to an alias, but it can contain argument placeholders."
- macro_epilog = "See also:\n" " alias"
- macro_parser = argparse_custom.DEFAULT_ARGUMENT_PARSER(description=macro_description, epilog=macro_epilog)
- macro_subparsers = macro_parser.add_subparsers(dest='subcommand', metavar='SUBCOMMAND')
- macro_subparsers.required = True
-
- # Preserve quotes since we are passing strings to other commands
- @with_argparser(macro_parser, preserve_quotes=True)
- def do_macro(self, args: argparse.Namespace) -> None:
- """Manage macros"""
- # Call handler for whatever subcommand was selected
- handler = args.cmd2_handler.get()
- handler(args)
-
- # macro -> create
- macro_create_help = "create or overwrite a macro"
- macro_create_description = "Create or overwrite a macro"
-
- macro_create_epilog = (
- "A macro is similar to an alias, but it can contain argument placeholders.\n"
- "Arguments are expressed when creating a macro using {#} notation where {1}\n"
- "means the first argument.\n"
- "\n"
- "The following creates a macro called my_macro that expects two arguments:\n"
- "\n"
- " macro create my_macro make_dinner --meat {1} --veggie {2}\n"
- "\n"
- "When the macro is called, the provided arguments are resolved and the\n"
- "assembled command is run. For example:\n"
- "\n"
- " my_macro beef broccoli ---> make_dinner --meat beef --veggie broccoli\n"
- "\n"
- "Notes:\n"
- " To use the literal string {1} in your command, escape it this way: {{1}}.\n"
- "\n"
- " Extra arguments passed to a macro are appended to resolved command.\n"
- "\n"
- " An argument number can be repeated in a macro. In the following example the\n"
- " first argument will populate both {1} instances.\n"
- "\n"
- " macro create ft file_taxes -p {1} -q {2} -r {1}\n"
- "\n"
- " To quote an argument in the resolved command, quote it during creation.\n"
- "\n"
- " macro create backup !cp \"{1}\" \"{1}.orig\"\n"
- "\n"
- " If you want to use redirection, pipes, or terminators in the value of the\n"
- " macro, then quote them.\n"
- "\n"
- " macro create show_results print_results -type {1} \"|\" less\n"
- "\n"
- " Because macros do not resolve until after hitting Enter, tab completion\n"
- " will only complete paths while typing a macro."
- )
-
- macro_create_parser = argparse_custom.DEFAULT_ARGUMENT_PARSER(
- description=macro_create_description, epilog=macro_create_epilog
- )
- macro_create_parser.add_argument('name', help='name of this macro')
- macro_create_parser.add_argument(
- 'command', help='what the macro resolves to', choices_provider=_get_commands_aliases_and_macros_for_completion
- )
- macro_create_parser.add_argument(
- 'command_args', nargs=argparse.REMAINDER, help='arguments to pass to command', completer=path_complete
- )
-
- @as_subcommand_to('macro', 'create', macro_create_parser, help=macro_create_help)
- def _macro_create(self, args: argparse.Namespace) -> None:
- """Create or overwrite a macro"""
- self.last_result = False
-
- # Validate the macro name
- valid, errmsg = self.statement_parser.is_valid_command(args.name)
- if not valid:
- self.perror(f"Invalid macro name: {errmsg}")
- return
-
- if args.name in self.get_all_commands():
- self.perror("Macro cannot have the same name as a command")
- return
-
- if args.name in self.aliases:
- self.perror("Macro cannot have the same name as an alias")
- return
-
- # Unquote redirection and terminator tokens
- tokens_to_unquote = constants.REDIRECTION_TOKENS
- tokens_to_unquote.extend(self.statement_parser.terminators)
- utils.unquote_specific_tokens(args.command_args, tokens_to_unquote)
-
- # Build the macro value string
- value = args.command
- if args.command_args:
- value += ' ' + ' '.join(args.command_args)
-
- # Find all normal arguments
- arg_list = []
- normal_matches = re.finditer(MacroArg.macro_normal_arg_pattern, value)
- max_arg_num = 0
- arg_nums = set()
-
- while True:
- try:
- cur_match = normal_matches.__next__()
-
- # Get the number string between the braces
- cur_num_str = re.findall(MacroArg.digit_pattern, cur_match.group())[0]
- cur_num = int(cur_num_str)
- if cur_num < 1:
- self.perror("Argument numbers must be greater than 0")
- return
-
- arg_nums.add(cur_num)
- if cur_num > max_arg_num:
- max_arg_num = cur_num
-
- arg_list.append(MacroArg(start_index=cur_match.start(), number_str=cur_num_str, is_escaped=False))
-
- except StopIteration:
- break
-
- # Make sure the argument numbers are continuous
- if len(arg_nums) != max_arg_num:
- self.perror(f"Not all numbers between 1 and {max_arg_num} are present in the argument placeholders")
- return
-
- # Find all escaped arguments
- escaped_matches = re.finditer(MacroArg.macro_escaped_arg_pattern, value)
-
- while True:
- try:
- cur_match = escaped_matches.__next__()
-
- # Get the number string between the braces
- cur_num_str = re.findall(MacroArg.digit_pattern, cur_match.group())[0]
-
- arg_list.append(MacroArg(start_index=cur_match.start(), number_str=cur_num_str, is_escaped=True))
- except StopIteration:
- break
-
- # Set the macro
- result = "overwritten" if args.name in self.macros else "created"
- self.poutput(f"Macro '{args.name}' {result}")
-
- self.macros[args.name] = Macro(name=args.name, value=value, minimum_arg_count=max_arg_num, arg_list=arg_list)
- self.last_result = True
-
- # macro -> delete
- macro_delete_help = "delete macros"
- macro_delete_description = "Delete specified macros or all macros if --all is used"
- macro_delete_parser = argparse_custom.DEFAULT_ARGUMENT_PARSER(description=macro_delete_description)
- macro_delete_parser.add_argument('-a', '--all', action='store_true', help="delete all macros")
- macro_delete_parser.add_argument(
- 'names',
- nargs=argparse.ZERO_OR_MORE,
- help='macro(s) to delete',
- choices_provider=_get_macro_completion_items,
- descriptive_header=_macro_completion_table.generate_header(),
- )
-
- @as_subcommand_to('macro', 'delete', macro_delete_parser, help=macro_delete_help)
- def _macro_delete(self, args: argparse.Namespace) -> None:
- """Delete macros"""
- self.last_result = True
-
- if args.all:
- self.macros.clear()
- self.poutput("All macros deleted")
- elif not args.names:
- self.perror("Either --all or macro name(s) must be specified")
- self.last_result = False
- else:
- for cur_name in utils.remove_duplicates(args.names):
- if cur_name in self.macros:
- del self.macros[cur_name]
- self.poutput(f"Macro '{cur_name}' deleted")
- else:
- self.perror(f"Macro '{cur_name}' does not exist")
-
- # macro -> list
- macro_list_help = "list macros"
- macro_list_description = (
- "List specified macros in a reusable form that can be saved to a startup script\n"
- "to preserve macros across sessions\n"
- "\n"
- "Without arguments, all macros will be listed."
- )
-
- macro_list_parser = argparse_custom.DEFAULT_ARGUMENT_PARSER(description=macro_list_description)
- macro_list_parser.add_argument(
- 'names',
- nargs=argparse.ZERO_OR_MORE,
- help='macro(s) to list',
- choices_provider=_get_macro_completion_items,
- descriptive_header=_macro_completion_table.generate_header(),
- )
-
- @as_subcommand_to('macro', 'list', macro_list_parser, help=macro_list_help)
- def _macro_list(self, args: argparse.Namespace) -> None:
- """List some or all macros as 'macro create' commands"""
- self.last_result = {} # Dict[macro_name, macro_value]
-
- tokens_to_quote = constants.REDIRECTION_TOKENS
- tokens_to_quote.extend(self.statement_parser.terminators)
-
- if args.names:
- to_list = utils.remove_duplicates(args.names)
- else:
- to_list = sorted(self.macros, key=self.default_sort_key)
-
- not_found: List[str] = []
- for name in to_list:
- if name not in self.macros:
- not_found.append(name)
- continue
-
- # Quote redirection and terminator tokens for the 'macro create' command
- tokens = shlex_split(self.macros[name].value)
- command = tokens[0]
- command_args = tokens[1:]
- utils.quote_specific_tokens(command_args, tokens_to_quote)
-
- val = command
- if command_args:
- val += ' ' + ' '.join(command_args)
-
- self.poutput(f"macro create {name} {val}")
- self.last_result[name] = val
-
- for name in not_found:
- self.perror(f"Macro '{name}' not found")
-
def complete_help_command(self, text: str, line: str, begidx: int, endidx: int) -> List[str]:
"""Completes the command argument of help"""
@@ -4712,7 +4346,7 @@ def do_ipy(self, _: argparse.Namespace) -> Optional[bool]: # pragma: no cover
'-x',
'--expanded',
action='store_true',
- help='output fully parsed commands with any aliases and\n' 'macros expanded, instead of typed commands',
+ help='output fully parsed commands with aliases and shortcuts expanded',
)
history_format_group.add_argument(
'-v',
diff --git a/cmd2/parsing.py b/cmd2/parsing.py
index e84f7c4fc..7ef1cc3de 100755
--- a/cmd2/parsing.py
+++ b/cmd2/parsing.py
@@ -38,56 +38,6 @@ def shlex_split(str_to_split: str) -> List[str]:
return shlex.split(str_to_split, comments=False, posix=False)
-@dataclass(frozen=True)
-class MacroArg:
- """
- Information used to replace or unescape arguments in a macro value when the macro is resolved
- Normal argument syntax: {5}
- Escaped argument syntax: {{5}}
- """
-
- # The starting index of this argument in the macro value
- start_index: int
-
- # The number string that appears between the braces
- # This is a string instead of an int because we support unicode digits and must be able
- # to reproduce this string later
- number_str: str
-
- # Tells if this argument is escaped and therefore needs to be unescaped
- is_escaped: bool
-
- # Pattern used to find normal argument
- # Digits surrounded by exactly 1 brace on a side and 1 or more braces on the opposite side
- # Match strings like: {5}, {{{{{4}, {2}}}}}
- macro_normal_arg_pattern = re.compile(r'(? str:
def argv(self) -> List[str]:
"""a list of arguments a-la ``sys.argv``.
- The first element of the list is the command after shortcut and macro
- expansion. Subsequent elements of the list contain any additional
- arguments, with quotes removed, just like bash would. This is very
- useful if you are going to use ``argparse.parse_args()``.
+ The first element of the list is the command after shortcut expansion.
+ Subsequent elements of the list contain any additional arguments,
+ with quotes removed, just like bash would. This is very useful if
+ you are going to use ``argparse.parse_args()``.
If you want to strip quotes from the input, you can use ``argv[1:]``.
"""
diff --git a/docs/api/cmd.rst b/docs/api/cmd.rst
index 4fbb8ccd5..fef2c78c7 100644
--- a/docs/api/cmd.rst
+++ b/docs/api/cmd.rst
@@ -9,7 +9,7 @@ cmd2.Cmd
.. attribute:: default_error
The error message displayed when a non-existent command is run.
- Default: ``{} is not a recognized command, alias, or macro.``
+ Default: ``{} is not a recognized command or alias.``
.. attribute:: help_error
diff --git a/docs/api/parsing.rst b/docs/api/parsing.rst
index fa726700b..490e56559 100644
--- a/docs/api/parsing.rst
+++ b/docs/api/parsing.rst
@@ -15,7 +15,7 @@ Classes for parsing and storing user input.
.. attribute:: command
- The name of the command after shortcuts and macros have been expanded
+ The name of the command after shortcuts have been expanded
.. attribute:: args
diff --git a/docs/examples/first_app.rst b/docs/examples/first_app.rst
index d90f96d86..b0164f81d 100644
--- a/docs/examples/first_app.rst
+++ b/docs/examples/first_app.rst
@@ -11,7 +11,7 @@ features of ``cmd2``:
* :ref:`features/argument_processing:Argument Processing`
* :ref:`features/generating_output:Generating Output`
* :ref:`features/help:Help`
-* :ref:`features/shortcuts_aliases_macros:Shortcuts`
+* :ref:`features/shortcuts_aliases:Shortcuts`
* :ref:`features/multiline_commands:Multiline Commands`
* :ref:`features/history:History`
@@ -178,8 +178,8 @@ Shortcuts
---------
``cmd2`` has several capabilities to simplify repetitive user input:
-:ref:`Shortcuts, Aliases, and Macros
-`. Let's add
+:ref:`Shortcuts and Aliases
+`. Let's add
a shortcut to our application. Shortcuts are character strings that can be used
instead of a command name. For example, ``cmd2`` has support for a shortcut
``!`` which runs the ``shell`` command. So instead of typing this:
diff --git a/docs/features/builtin_commands.rst b/docs/features/builtin_commands.rst
index 4925fc3d7..93d98a7eb 100644
--- a/docs/features/builtin_commands.rst
+++ b/docs/features/builtin_commands.rst
@@ -13,7 +13,7 @@ alias
~~~~~
This command manages aliases via subcommands ``create``, ``delete``, and
-``list``. See :ref:`features/shortcuts_aliases_macros:Aliases` for more
+``list``. See :ref:`features/shortcuts_aliases:Aliases` for more
information.
edit
@@ -50,14 +50,6 @@ ipy
This optional opt-in command enters an interactive IPython shell. See
:ref:`features/embedded_python_shells:IPython (optional)` for more information.
-macro
-~~~~~
-
-This command manages macros via subcommands ``create``, ``delete``, and
-``list``. A macro is similar to an alias, but it can contain argument
-placeholders. See :ref:`features/shortcuts_aliases_macros:Macros` for more
-information.
-
py
~~
@@ -143,7 +135,7 @@ shortcuts
~~~~~~~~~
This command lists available shortcuts. See
-:ref:`features/shortcuts_aliases_macros:Shortcuts` for more information.
+:ref:`features/shortcuts_aliases:Shortcuts` for more information.
Remove Builtin Commands
diff --git a/docs/features/commands.rst b/docs/features/commands.rst
index 5dd5a163b..1b3da218a 100644
--- a/docs/features/commands.rst
+++ b/docs/features/commands.rst
@@ -67,7 +67,7 @@ the cmd_ module. This parsing handles:
- quoted arguments
- output redirection and piping
- multi-line commands
-- shortcut, macro, and alias expansion
+- shortcut and alias expansion
In addition to parsing all of these elements from the user input, ``cmd2`` also
has code to make all of these items work; it's almost transparent to you and to
diff --git a/docs/features/help.rst b/docs/features/help.rst
index b98e4164d..759a5f150 100644
--- a/docs/features/help.rst
+++ b/docs/features/help.rst
@@ -19,8 +19,8 @@ of the commands available:
Documented commands (use 'help -v' for verbose/'help ' for details):
===========================================================================
- alias help ipy py run_pyscript set shortcuts
- edit history macro quit run_script shell
+ alias help ipy quit run_script shell
+ edit history py run_pyscript set shortcuts
The ``help`` command can also be used to provide detailed help for a specific
command:
@@ -63,8 +63,8 @@ By default, the ``help`` command displays::
Documented commands (use 'help -v' for verbose/'help ' for details):
===========================================================================
- alias help ipy py run_pyscript set shortcuts
- edit history macro quit run_script shell
+ alias help ipy quit run_script shell
+ edit history py run_pyscript set shortcuts
If you have a large number of commands, you can optionally group your commands
into categories. Here's the output from the example ``help_categories.py``::
@@ -90,8 +90,8 @@ into categories. Here's the output from the example ``help_categories.py``::
Other
=====
- alias edit history py run_pyscript set shortcuts
- config help macro quit run_script shell version
+ alias edit history run_pyscript set shortcuts
+ config help quit run_script shell version
There are 2 methods of specifying command categories, using the
``@with_category`` decorator or with the ``categorize()`` function. Once a
@@ -142,51 +142,49 @@ The ``help`` command also has a verbose option (``help -v`` or ``help
Documented commands (use 'help -v' for verbose/'help ' for details):
Application Management
- ================================================================================
- deploy Deploy command
- expire Expire command
- findleakers Find Leakers command
- list List command
- redeploy Redeploy command
- restart usage: restart [-h] {now,later,sometime,whenever}
- sessions Sessions command
- start Start command
- stop Stop command
- undeploy Undeploy command
+ ======================================================================================================
+ deploy Deploy command
+ expire Expire command
+ findleakers Find Leakers command
+ list List command
+ redeploy Redeploy command
+ restart Restart command
+ sessions Sessions command
+ start Start command
+ stop Stop command
+ undeploy Undeploy command
Connecting
- ================================================================================
- connect Connect command
- which Which command
+ ======================================================================================================
+ connect Connect command
+ which Which command
Server Information
- ================================================================================
- resources Resources command
- serverinfo Server Info command
- sslconnectorciphers SSL Connector Ciphers command is an example of a command that contains
- multiple lines of help information for the user. Each line of help in a
- contiguous set of lines will be printed and aligned in the verbose output
- provided with 'help --verbose'
- status Status command
- thread_dump Thread Dump command
- vminfo VM Info command
+ ======================================================================================================
+ resources Resources command
+ serverinfo Server Info command
+ sslconnectorciphers SSL Connector Ciphers command is an example of a command that contains
+ multiple lines of help information for the user. Each line of help in a
+ contiguous set of lines will be printed and aligned in the verbose output
+ provided with 'help --verbose'
+ status Status command
+ thread_dump Thread Dump command
+ vminfo VM Info command
Other
- ================================================================================
- alias Manage aliases
- config Config command
- edit Run a text editor and optionally open a file with it
- help List available commands or provide detailed help for a specific command
- history View, run, edit, save, or clear previously entered commands
- macro Manage macros
- py Invoke Python command or shell
- quit Exits this application
- run_pyscript Runs a python script file inside the console
- run_script Runs commands in script file that is encoded as either ASCII or UTF-8 text
- set Set a settable parameter or show current settings of parameters
- shell Execute a command as if at the OS prompt
- shortcuts List available shortcuts
- version Version command
+ ======================================================================================================
+ alias Manage aliases
+ config Config command
+ edit Run a text editor and optionally open a file with it
+ help List available commands or provide detailed help for a specific command
+ history View, run, edit, save, or clear previously entered commands
+ quit Exit this application
+ run_pyscript Run a Python script file inside the console
+ run_script Run commands in script file that is encoded as either ASCII or UTF-8 text.
+ set Set a settable parameter or show current settings of parameters
+ shell Execute a command as if at the OS prompt
+ shortcuts List available shortcuts
+ version Version command
When called with the ``-v`` flag for verbose help, the one-line description for
each command is provided by the first line of the docstring for that command's
diff --git a/docs/features/history.rst b/docs/features/history.rst
index 056e02a0b..e421588aa 100644
--- a/docs/features/history.rst
+++ b/docs/features/history.rst
@@ -232,9 +232,9 @@ clipboard::
(Cmd) history -s 1:3
-``cmd2`` supports both aliases and macros, which allow you to substitute a
-short, more convenient input string with a longer replacement string. Say we
-create an alias like this, and then use it::
+``cmd2`` supports aliases which allow you to substitute a short, more
+convenient input string with a longer replacement string. Say we create
+an alias like this, and then use it::
(Cmd) alias create ls shell ls -aF
Alias 'ls' created
@@ -248,7 +248,7 @@ By default, the ``history`` command shows exactly what we typed::
2 ls -d h*
There are two ways to modify that display so you can see what aliases and
-macros were expanded to. The first is to use ``-x`` or ``--expanded``. These
+shortcuts were expanded to. The first is to use ``-x`` or ``--expanded``. These
options show the expanded command instead of the entered command::
(Cmd) history -x
@@ -264,6 +264,6 @@ If you want to see both the entered command and the expanded command, use the
2x shell ls -aF -d h*
If the entered command had no expansion, it is displayed as usual. However, if
-there is some change as the result of expanding macros and aliases, then the
-entered command is displayed with the number, and the expanded command is
-displayed with the number followed by an ``x``.
+there is some change as the result of expanding aliases, then the entered
+command is displayed with the number, and the expanded command is displayed
+with the number followed by an ``x``.
diff --git a/docs/features/index.rst b/docs/features/index.rst
index 48590b6ad..8e6fc595b 100644
--- a/docs/features/index.rst
+++ b/docs/features/index.rst
@@ -26,7 +26,7 @@ Features
redirection
scripting
settings
- shortcuts_aliases_macros
+ shortcuts_aliases
startup_commands
table_creation
transcripts
diff --git a/docs/features/initialization.rst b/docs/features/initialization.rst
index 3ee96cf9e..b06f65266 100644
--- a/docs/features/initialization.rst
+++ b/docs/features/initialization.rst
@@ -141,7 +141,6 @@ override:
of results in a Python script or interactive console. Built-in commands don't
make use of this. It is purely there for user-defined commands and
convenience.
-- **macros**: dictionary of macro names and their values
- **max_completion_items**: max number of CompletionItems to display during
tab completion (Default: 50)
- **pager**: sets the pager command used by the ``Cmd.ppaged()`` method for
diff --git a/docs/features/os.rst b/docs/features/os.rst
index 77bc6a668..722e761ad 100644
--- a/docs/features/os.rst
+++ b/docs/features/os.rst
@@ -14,7 +14,7 @@ operating system shell::
(Cmd) shell ls -al
-If you use the default :ref:`features/shortcuts_aliases_macros:Shortcuts`
+If you use the default :ref:`features/shortcuts_aliases:Shortcuts`
defined in ``cmd2`` you'll get a ``!`` shortcut for ``shell``, which allows you
to type::
@@ -107,8 +107,8 @@ loop::
Documented commands (use 'help -v' for verbose/'help ' for details):
===========================================================================
- alias help macro orate quit run_script set shortcuts
- edit history mumble py run_pyscript say shell speak
+ alias help ipy quit run_script shell
+ edit history py run_pyscript set shortcuts
(Cmd)
diff --git a/docs/features/shortcuts_aliases_macros.rst b/docs/features/shortcuts_aliases.rst
similarity index 57%
rename from docs/features/shortcuts_aliases_macros.rst
rename to docs/features/shortcuts_aliases.rst
index 58d6d83cd..243257feb 100644
--- a/docs/features/shortcuts_aliases_macros.rst
+++ b/docs/features/shortcuts_aliases.rst
@@ -1,5 +1,5 @@
-Shortcuts, Aliases, and Macros
-==============================
+Shortcuts and Aliases
+=====================
Shortcuts
---------
@@ -38,7 +38,7 @@ To define more shortcuts, update the dict ``App.shortcuts`` with the
updating the ``shortcuts`` attribute This warning applies in general to many
other attributes which are not settable at runtime.
-Note: Command, alias, and macro names cannot start with a shortcut
+Note: Command and alias names cannot start with a shortcut
Aliases
-------
@@ -74,44 +74,4 @@ Use ``alias delete`` to remove aliases
For more details run: ``help alias delete``
-Note: Aliases cannot have the same name as a command or macro
-
-Macros
-------
-
-``cmd2`` provides a feature that is similar to aliases called macros. The major
-difference between macros and aliases is that macros can contain argument
-placeholders. Arguments are expressed when creating a macro using {#} notation
-where {1} means the first argument.
-
-The following creates a macro called my_macro that expects two arguments:
-
- macro create my_macro make_dinner -meat {1} -veggie {2}
-
-When the macro is called, the provided arguments are resolved and the assembled
-command is run. For example:
-
- my_macro beef broccoli ---> make_dinner -meat beef -veggie broccoli
-
-Similar to aliases, pipes and redirectors need to be quoted in the definition
-of a macro::
-
- macro create lc !cat "{1}" "|" less
-
-To use the literal string ``{1}`` in your command, escape it this way:
-``{{1}}``. Because macros do not resolve until after hitting ````,
-tab completion will only complete paths while typing a macro.
-
-
-For more details run: ``help macro create``
-
-The macro command has ``list`` and ``delete`` subcommands that function
-identically to the alias subcommands of the same name. Like aliases, macros can
-be created via a ``cmd2`` startup script to preserve them across application
-sessions.
-
-For more details on listing macros run: ``help macro list``
-
-For more details on deleting macros run: ``help macro delete``
-
-Note: Macros cannot have the same name as a command or alias
+Note: Aliases cannot have the same name as a command
diff --git a/docs/migrating/incompatibilities.rst b/docs/migrating/incompatibilities.rst
index ba6f2ed10..bc922c380 100644
--- a/docs/migrating/incompatibilities.rst
+++ b/docs/migrating/incompatibilities.rst
@@ -38,7 +38,7 @@ characters in command names while simultaneously using ``identchars``
functionality can be somewhat painful. Requiring white space to delimit
arguments also ensures reliable operation of many other useful ``cmd2``
features, including :ref:`features/completion:Completion` and
-:ref:`features/shortcuts_aliases_macros:Shortcuts, Aliases, and Macros`.
+:ref:`features/shortcuts_aliases:Shortcuts and Aliases`.
If you really need this functionality in your app, you can add it back in by
writing a :ref:`Postparsing Hook `.
diff --git a/docs/migrating/why.rst b/docs/migrating/why.rst
index 2bfd45f14..bbfccb650 100644
--- a/docs/migrating/why.rst
+++ b/docs/migrating/why.rst
@@ -55,8 +55,8 @@ new features and capabilities, without you having to do anything:
- Users can load script files, which contain a series of commands
to be executed.
-- Users can create :ref:`features/shortcuts_aliases_macros:Shortcuts, Aliases,
- and Macros` to reduce the typing required for repetitive commands.
+- Users can create :ref:`features/shortcuts_aliases:Shortcuts and Aliases`
+ to reduce the typing required for repetitive commands.
- Embedded python shell allows a user to execute python code from within your
``cmd2`` app. How meta.
diff --git a/examples/help_categories.py b/examples/help_categories.py
index 5c349422c..8059ca90a 100755
--- a/examples/help_categories.py
+++ b/examples/help_categories.py
@@ -37,6 +37,9 @@ class HelpCategories(cmd2.Cmd):
def __init__(self):
super().__init__()
+ # Set the default category for uncategorized commands
+ self.default_category = 'Other'
+
def do_connect(self, _):
"""Connect command"""
self.poutput('Connect')
diff --git a/tests/conftest.py b/tests/conftest.py
index 644ae7cca..0b3a01786 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -81,8 +81,7 @@ def verify_help_text(
formatting:
-s, --script output commands in script format, i.e. without command
numbers
- -x, --expanded output fully parsed commands with any aliases and
- macros expanded, instead of typed commands
+ -x, --expanded output fully parsed commands with aliases and shortcuts expanded
-v, --verbose display history and include expanded commands if they
differ from the typed command
-a, --all display all commands, including ones persisted from
diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py
index 374ba10a2..efa4868b5 100755
--- a/tests/test_cmd2.py
+++ b/tests/test_cmd2.py
@@ -1630,8 +1630,8 @@ def test_multiline_complete_statement_with_unclosed_quotes(multiline_app):
assert statement.terminator == ';'
-def test_multiline_input_line_to_statement(multiline_app):
- # Verify _input_line_to_statement saves the fully entered input line for multiline commands
+def test_multiline_complete_statement(multiline_app):
+ # Verify _complete_statement saves the fully entered input line for multiline commands
# Mock out the input call so we don't actually wait for a user's response
# on stdin when it looks for more input
@@ -1639,7 +1639,7 @@ def test_multiline_input_line_to_statement(multiline_app):
builtins.input = m
line = 'orate hi'
- statement = multiline_app._input_line_to_statement(line)
+ statement = multiline_app._complete_statement(line)
assert statement.raw == 'orate hi\nperson\n'
assert statement == 'hi person'
assert statement.command == 'orate'
@@ -1998,8 +1998,7 @@ def test_poutput_ansi_never(outsim_app):
assert out == expected
-# These are invalid names for aliases and macros
-invalid_command_name = [
+invalid_alias_names = [
'""', # Blank name
constants.COMMENT_CHAR,
'!no_shortcut',
@@ -2025,19 +2024,6 @@ def test_get_alias_completion_items(base_app):
assert cur_res.description.rstrip() == base_app.aliases[cur_res]
-def test_get_macro_completion_items(base_app):
- run_cmd(base_app, 'macro create foo !echo foo')
- run_cmd(base_app, 'macro create bar !echo bar')
-
- results = base_app._get_macro_completion_items()
- assert len(results) == len(base_app.macros)
-
- for cur_res in results:
- assert cur_res in base_app.macros
- # Strip trailing spaces from table output
- assert cur_res.description.rstrip() == base_app.macros[cur_res].value
-
-
def test_get_settable_completion_items(base_app):
results = base_app._get_settable_completion_items()
assert len(results) == len(base_app.settables)
@@ -2113,7 +2099,7 @@ def test_alias_create_with_quoted_tokens(base_app):
assert base_app.last_result[alias_name] == alias_command
-@pytest.mark.parametrize('alias_name', invalid_command_name)
+@pytest.mark.parametrize('alias_name', invalid_alias_names)
def test_alias_create_invalid_name(base_app, alias_name, capsys):
out, err = run_cmd(base_app, 'alias create {} help'.format(alias_name))
assert "Invalid alias name" in err[0]
@@ -2126,14 +2112,6 @@ def test_alias_create_with_command_name(base_app):
assert base_app.last_result is False
-def test_alias_create_with_macro_name(base_app):
- macro = "my_macro"
- run_cmd(base_app, 'macro create {} help'.format(macro))
- out, err = run_cmd(base_app, 'alias create {} help'.format(macro))
- assert "Alias cannot have the same name as a macro" in err[0]
- assert base_app.last_result is False
-
-
def test_alias_that_resolves_into_comment(base_app):
# Create the alias
out, err = run_cmd(base_app, 'alias create fake ' + constants.COMMENT_CHAR + ' blah blah')
@@ -2192,228 +2170,6 @@ def test_multiple_aliases(base_app):
verify_help_text(base_app, out)
-def test_macro_no_subcommand(base_app):
- out, err = run_cmd(base_app, 'macro')
- assert "Usage: macro [-h]" in err[0]
- assert "Error: the following arguments are required: SUBCOMMAND" in err[1]
-
-
-def test_macro_create(base_app):
- # Create the macro
- out, err = run_cmd(base_app, 'macro create fake run_pyscript')
- assert out == normalize("Macro 'fake' created")
- assert base_app.last_result is True
-
- # Use the macro
- out, err = run_cmd(base_app, 'fake')
- assert "the following arguments are required: script_path" in err[1]
-
- # See a list of macros
- out, err = run_cmd(base_app, 'macro list')
- assert out == normalize('macro create fake run_pyscript')
- assert len(base_app.last_result) == len(base_app.macros)
- assert base_app.last_result['fake'] == "run_pyscript"
-
- # Look up the new macro
- out, err = run_cmd(base_app, 'macro list fake')
- assert out == normalize('macro create fake run_pyscript')
- assert len(base_app.last_result) == 1
- assert base_app.last_result['fake'] == "run_pyscript"
-
- # Overwrite macro
- out, err = run_cmd(base_app, 'macro create fake help')
- assert out == normalize("Macro 'fake' overwritten")
- assert base_app.last_result is True
-
- # Look up the updated macro
- out, err = run_cmd(base_app, 'macro list fake')
- assert out == normalize('macro create fake help')
- assert len(base_app.last_result) == 1
- assert base_app.last_result['fake'] == "help"
-
-
-def test_macro_create_with_quoted_tokens(base_app):
- """Demonstrate that quotes in macro value will be preserved"""
- macro_name = "fake"
- macro_command = 'help ">" "out file.txt" ";"'
- create_command = f"macro create {macro_name} {macro_command}"
-
- # Create the macro
- out, err = run_cmd(base_app, create_command)
- assert out == normalize("Macro 'fake' created")
-
- # Look up the new macro and verify all quotes are preserved
- out, err = run_cmd(base_app, 'macro list fake')
- assert out == normalize(create_command)
- assert len(base_app.last_result) == 1
- assert base_app.last_result[macro_name] == macro_command
-
-
-@pytest.mark.parametrize('macro_name', invalid_command_name)
-def test_macro_create_invalid_name(base_app, macro_name):
- out, err = run_cmd(base_app, 'macro create {} help'.format(macro_name))
- assert "Invalid macro name" in err[0]
- assert base_app.last_result is False
-
-
-def test_macro_create_with_command_name(base_app):
- out, err = run_cmd(base_app, 'macro create help stuff')
- assert "Macro cannot have the same name as a command" in err[0]
- assert base_app.last_result is False
-
-
-def test_macro_create_with_alias_name(base_app):
- macro = "my_macro"
- run_cmd(base_app, 'alias create {} help'.format(macro))
- out, err = run_cmd(base_app, 'macro create {} help'.format(macro))
- assert "Macro cannot have the same name as an alias" in err[0]
- assert base_app.last_result is False
-
-
-def test_macro_create_with_args(base_app):
- # Create the macro
- out, err = run_cmd(base_app, 'macro create fake {1} {2}')
- assert out == normalize("Macro 'fake' created")
-
- # Run the macro
- out, err = run_cmd(base_app, 'fake help -v')
- verify_help_text(base_app, out)
-
-
-def test_macro_create_with_escaped_args(base_app):
- # Create the macro
- out, err = run_cmd(base_app, 'macro create fake help {{1}}')
- assert out == normalize("Macro 'fake' created")
-
- # Run the macro
- out, err = run_cmd(base_app, 'fake')
- assert err[0].startswith('No help on {1}')
-
-
-def test_macro_usage_with_missing_args(base_app):
- # Create the macro
- out, err = run_cmd(base_app, 'macro create fake help {1} {2}')
- assert out == normalize("Macro 'fake' created")
-
- # Run the macro
- out, err = run_cmd(base_app, 'fake arg1')
- assert "expects at least 2 arguments" in err[0]
-
-
-def test_macro_usage_with_exta_args(base_app):
- # Create the macro
- out, err = run_cmd(base_app, 'macro create fake help {1}')
- assert out == normalize("Macro 'fake' created")
-
- # Run the macro
- out, err = run_cmd(base_app, 'fake alias create')
- assert "Usage: alias create" in out[0]
-
-
-def test_macro_create_with_missing_arg_nums(base_app):
- # Create the macro
- out, err = run_cmd(base_app, 'macro create fake help {1} {3}')
- assert "Not all numbers between 1 and 3" in err[0]
- assert base_app.last_result is False
-
-
-def test_macro_create_with_invalid_arg_num(base_app):
- # Create the macro
- out, err = run_cmd(base_app, 'macro create fake help {1} {-1} {0}')
- assert "Argument numbers must be greater than 0" in err[0]
- assert base_app.last_result is False
-
-
-def test_macro_create_with_unicode_numbered_arg(base_app):
- # Create the macro expecting 1 argument
- out, err = run_cmd(base_app, 'macro create fake help {\N{ARABIC-INDIC DIGIT ONE}}')
- assert out == normalize("Macro 'fake' created")
-
- # Run the macro
- out, err = run_cmd(base_app, 'fake')
- assert "expects at least 1 argument" in err[0]
-
-
-def test_macro_create_with_missing_unicode_arg_nums(base_app):
- out, err = run_cmd(base_app, 'macro create fake help {1} {\N{ARABIC-INDIC DIGIT THREE}}')
- assert "Not all numbers between 1 and 3" in err[0]
- assert base_app.last_result is False
-
-
-def test_macro_that_resolves_into_comment(base_app):
- # Create the macro
- out, err = run_cmd(base_app, 'macro create fake {1} blah blah')
- assert out == normalize("Macro 'fake' created")
-
- # Use the macro
- out, err = run_cmd(base_app, 'fake ' + constants.COMMENT_CHAR)
- assert not out
- assert not err
-
-
-def test_macro_list_invalid_macro(base_app):
- # Look up invalid macro
- out, err = run_cmd(base_app, 'macro list invalid')
- assert "Macro 'invalid' not found" in err[0]
- assert base_app.last_result == {}
-
-
-def test_macro_delete(base_app):
- # Create an macro
- run_cmd(base_app, 'macro create fake run_pyscript')
-
- # Delete the macro
- out, err = run_cmd(base_app, 'macro delete fake')
- assert out == normalize("Macro 'fake' deleted")
- assert base_app.last_result is True
-
-
-def test_macro_delete_all(base_app):
- out, err = run_cmd(base_app, 'macro delete --all')
- assert out == normalize("All macros deleted")
- assert base_app.last_result is True
-
-
-def test_macro_delete_non_existing(base_app):
- out, err = run_cmd(base_app, 'macro delete fake')
- assert "Macro 'fake' does not exist" in err[0]
- assert base_app.last_result is True
-
-
-def test_macro_delete_no_name(base_app):
- out, err = run_cmd(base_app, 'macro delete')
- assert "Either --all or macro name(s)" in err[0]
- assert base_app.last_result is False
-
-
-def test_multiple_macros(base_app):
- macro1 = 'h1'
- macro2 = 'h2'
- run_cmd(base_app, 'macro create {} help'.format(macro1))
- run_cmd(base_app, 'macro create {} help -v'.format(macro2))
- out, err = run_cmd(base_app, macro1)
- verify_help_text(base_app, out)
-
- out2, err2 = run_cmd(base_app, macro2)
- verify_help_text(base_app, out2)
- assert len(out2) > len(out)
-
-
-def test_nonexistent_macro(base_app):
- from cmd2.parsing import (
- StatementParser,
- )
-
- exception = None
-
- try:
- base_app._resolve_macro(StatementParser().parse('fake'))
- except KeyError as e:
- exception = e
-
- assert exception is not None
-
-
@with_ansi_style(ansi.AllowStyle.ALWAYS)
def test_perror_style(base_app, capsys):
msg = 'testing...'
@@ -2567,7 +2323,6 @@ def test_get_all_commands(base_app):
'help',
'history',
'ipy',
- 'macro',
'py',
'quit',
'run_pyscript',
diff --git a/tests/test_completion.py b/tests/test_completion.py
index 18b7c0f27..2bb08d3a5 100755
--- a/tests/test_completion.py
+++ b/tests/test_completion.py
@@ -26,8 +26,6 @@
from .conftest import (
complete_tester,
- normalize,
- run_cmd,
)
# List of strings used with completion functions
@@ -186,25 +184,6 @@ def test_complete_exception(cmd2_app, capsys):
assert "IndexError" in err
-def test_complete_macro(base_app, request):
- # Create the macro
- out, err = run_cmd(base_app, 'macro create fake run_pyscript {1}')
- assert out == normalize("Macro 'fake' created")
-
- # Macros do path completion
- test_dir = os.path.dirname(request.module.__file__)
-
- text = os.path.join(test_dir, 's')
- line = 'fake {}'.format(text)
-
- endidx = len(line)
- begidx = endidx - len(text)
-
- expected = [text + 'cript.py', text + 'cript.txt', text + 'cripts' + os.path.sep]
- first_match = complete_tester(text, line, begidx, endidx, base_app)
- assert first_match is not None and base_app.completion_matches == expected
-
-
def test_default_sort_key(cmd2_app):
text = ''
line = 'test_sort_key {}'.format(text)
diff --git a/tests/test_parsing.py b/tests/test_parsing.py
index e3d42d7c7..ed5a00f99 100755
--- a/tests/test_parsing.py
+++ b/tests/test_parsing.py
@@ -1034,111 +1034,3 @@ def test_is_valid_command_valid(parser):
valid, errmsg = parser.is_valid_command('!subcmd', is_subcommand=True)
assert valid
assert not errmsg
-
-
-def test_macro_normal_arg_pattern():
- # This pattern matches digits surrounded by exactly 1 brace on a side and 1 or more braces on the opposite side
- from cmd2.parsing import (
- MacroArg,
- )
-
- pattern = MacroArg.macro_normal_arg_pattern
-
- # Valid strings
- matches = pattern.findall('{5}')
- assert matches == ['{5}']
-
- matches = pattern.findall('{233}')
- assert matches == ['{233}']
-
- matches = pattern.findall('{{{{{4}')
- assert matches == ['{4}']
-
- matches = pattern.findall('{2}}}}}')
- assert matches == ['{2}']
-
- matches = pattern.findall('{3}{4}{5}')
- assert matches == ['{3}', '{4}', '{5}']
-
- matches = pattern.findall('{3} {4} {5}')
- assert matches == ['{3}', '{4}', '{5}']
-
- matches = pattern.findall('{3} {{{4} {5}}}}')
- assert matches == ['{3}', '{4}', '{5}']
-
- matches = pattern.findall('{3} text {4} stuff {5}}}}')
- assert matches == ['{3}', '{4}', '{5}']
-
- # Unicode digit
- matches = pattern.findall('{\N{ARABIC-INDIC DIGIT ONE}}')
- assert matches == ['{\N{ARABIC-INDIC DIGIT ONE}}']
-
- # Invalid strings
- matches = pattern.findall('5')
- assert not matches
-
- matches = pattern.findall('{5')
- assert not matches
-
- matches = pattern.findall('5}')
- assert not matches
-
- matches = pattern.findall('{{5}}')
- assert not matches
-
- matches = pattern.findall('{5text}')
- assert not matches
-
-
-def test_macro_escaped_arg_pattern():
- # This pattern matches digits surrounded by 2 or more braces on both sides
- from cmd2.parsing import (
- MacroArg,
- )
-
- pattern = MacroArg.macro_escaped_arg_pattern
-
- # Valid strings
- matches = pattern.findall('{{5}}')
- assert matches == ['{{5}}']
-
- matches = pattern.findall('{{233}}')
- assert matches == ['{{233}}']
-
- matches = pattern.findall('{{{{{4}}')
- assert matches == ['{{4}}']
-
- matches = pattern.findall('{{2}}}}}')
- assert matches == ['{{2}}']
-
- matches = pattern.findall('{{3}}{{4}}{{5}}')
- assert matches == ['{{3}}', '{{4}}', '{{5}}']
-
- matches = pattern.findall('{{3}} {{4}} {{5}}')
- assert matches == ['{{3}}', '{{4}}', '{{5}}']
-
- matches = pattern.findall('{{3}} {{{4}} {{5}}}}')
- assert matches == ['{{3}}', '{{4}}', '{{5}}']
-
- matches = pattern.findall('{{3}} text {{4}} stuff {{5}}}}')
- assert matches == ['{{3}}', '{{4}}', '{{5}}']
-
- # Unicode digit
- matches = pattern.findall('{{\N{ARABIC-INDIC DIGIT ONE}}}')
- assert matches == ['{{\N{ARABIC-INDIC DIGIT ONE}}}']
-
- # Invalid strings
- matches = pattern.findall('5')
- assert not matches
-
- matches = pattern.findall('{{5')
- assert not matches
-
- matches = pattern.findall('5}}')
- assert not matches
-
- matches = pattern.findall('{5}')
- assert not matches
-
- matches = pattern.findall('{{5text}}')
- assert not matches
diff --git a/tests_isolated/test_commandset/conftest.py b/tests_isolated/test_commandset/conftest.py
index c8c6d34b4..e70185a89 100644
--- a/tests_isolated/test_commandset/conftest.py
+++ b/tests_isolated/test_commandset/conftest.py
@@ -83,8 +83,7 @@ def verify_help_text(
formatting:
-s, --script output commands in script format, i.e. without command
numbers
- -x, --expanded output fully parsed commands with any aliases and
- macros expanded, instead of typed commands
+ -x, --expanded output fully parsed commands with aliases and shortcuts expanded
-v, --verbose display history and include expanded commands if they
differ from the typed command
-a, --all display all commands, including ones persisted from
diff --git a/tests_isolated/test_commandset/test_commandset.py b/tests_isolated/test_commandset/test_commandset.py
index c7293d411..7064b3dba 100644
--- a/tests_isolated/test_commandset/test_commandset.py
+++ b/tests_isolated/test_commandset/test_commandset.py
@@ -299,17 +299,17 @@ def test_load_commandset_errors(command_sets_manual, capsys):
delattr(command_sets_manual, 'do_durian')
- # pre-create intentionally conflicting macro and alias names
- command_sets_manual.app_cmd('macro create apple run_pyscript')
+ # pre-create intentionally conflicting aliases
+ command_sets_manual.app_cmd('alias create apple run_pyscript')
command_sets_manual.app_cmd('alias create banana run_pyscript')
# now install a command set and verify the commands are now present
command_sets_manual.register_command_set(cmd_set)
out, err = capsys.readouterr()
- # verify aliases and macros are deleted with warning if they conflict with a command
+ # verify aliases are deleted with warning if they conflict with a command
+ assert "Deleting alias 'apple'" in err
assert "Deleting alias 'banana'" in err
- assert "Deleting macro 'apple'" in err
# verify duplicate commands are detected
with pytest.raises(CommandSetRegistrationError):