summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam J. Stewart <ajstewart426@gmail.com>2023-07-04 15:43:02 -0500
committerGitHub <noreply@github.com>2023-07-04 16:43:02 -0400
commit297891152077a018acb7dd2b656e9018e46a5d5c (patch)
tree43cf7b7f4c8ec085c245871c539dc305adb37cf0
parentd35149d1742f69bce44577fa848dad01f1b108d9 (diff)
downloadspack-297891152077a018acb7dd2b656e9018e46a5d5c.tar.gz
spack-297891152077a018acb7dd2b656e9018e46a5d5c.tar.bz2
spack-297891152077a018acb7dd2b656e9018e46a5d5c.tar.xz
spack-297891152077a018acb7dd2b656e9018e46a5d5c.zip
spack commands: add type hints and docstrings (#38705)
-rw-r--r--lib/spack/llnl/util/argparsewriter.py329
-rw-r--r--lib/spack/spack/cmd/commands.py195
-rw-r--r--lib/spack/spack/test/llnl/util/argparsewriter.py6
3 files changed, 371 insertions, 159 deletions
diff --git a/lib/spack/llnl/util/argparsewriter.py b/lib/spack/llnl/util/argparsewriter.py
index d9aa4b471b..dfd602bb34 100644
--- a/lib/spack/llnl/util/argparsewriter.py
+++ b/lib/spack/llnl/util/argparsewriter.py
@@ -3,31 +3,42 @@
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+import abc
import argparse
-import errno
import io
import re
import sys
+from argparse import ArgumentParser
+from typing import IO, Optional, Sequence, Tuple
-class Command(object):
+class Command:
"""Parsed representation of a command from argparse.
- This is a single command from an argparse parser. ``ArgparseWriter``
- creates these and returns them from ``parse()``, and it passes one of
- these to each call to ``format()`` so that we can take an action for
- a single command.
-
- Parts of a Command:
- - prog: command name (str)
- - description: command description (str)
- - usage: command usage (str)
- - positionals: list of positional arguments (list)
- - optionals: list of optional arguments (list)
- - subcommands: list of subcommand parsers (list)
+ This is a single command from an argparse parser. ``ArgparseWriter`` creates these and returns
+ them from ``parse()``, and it passes one of these to each call to ``format()`` so that we can
+ take an action for a single command.
"""
- def __init__(self, prog, description, usage, positionals, optionals, subcommands):
+ def __init__(
+ self,
+ prog: str,
+ description: Optional[str],
+ usage: str,
+ positionals: Sequence[Tuple[str, str]],
+ optionals: Sequence[Tuple[Sequence[str], str, str]],
+ subcommands: Sequence[Tuple[ArgumentParser, str]],
+ ) -> None:
+ """Initialize a new Command instance.
+
+ Args:
+ prog: Program name.
+ description: Command description.
+ usage: Command usage.
+ positionals: List of positional arguments.
+ optionals: List of optional arguments.
+ subcommands: List of subcommand parsers.
+ """
self.prog = prog
self.description = description
self.usage = usage
@@ -36,35 +47,34 @@ class Command(object):
self.subcommands = subcommands
-# NOTE: The only reason we subclass argparse.HelpFormatter is to get access
-# to self._expand_help(), ArgparseWriter is not intended to be used as a
-# formatter_class.
-class ArgparseWriter(argparse.HelpFormatter):
- """Analyzes an argparse ArgumentParser for easy generation of help."""
+# NOTE: The only reason we subclass argparse.HelpFormatter is to get access to self._expand_help(),
+# ArgparseWriter is not intended to be used as a formatter_class.
+class ArgparseWriter(argparse.HelpFormatter, abc.ABC):
+ """Analyze an argparse ArgumentParser for easy generation of help."""
- def __init__(self, prog, out=None, aliases=False):
- """Initializes a new ArgparseWriter instance.
+ def __init__(self, prog: str, out: IO = sys.stdout, aliases: bool = False) -> None:
+ """Initialize a new ArgparseWriter instance.
- Parameters:
- prog (str): the program name
- out (file object): the file to write to (default sys.stdout)
- aliases (bool): whether or not to include subparsers for aliases
+ Args:
+ prog: Program name.
+ out: File object to write to.
+ aliases: Whether or not to include subparsers for aliases.
"""
- super(ArgparseWriter, self).__init__(prog)
+ super().__init__(prog)
self.level = 0
self.prog = prog
- self.out = sys.stdout if out is None else out
+ self.out = out
self.aliases = aliases
- def parse(self, parser, prog):
- """Parses the parser object and returns the relavent components.
+ def parse(self, parser: ArgumentParser, prog: str) -> Command:
+ """Parse the parser object and return the relavent components.
- Parameters:
- parser (argparse.ArgumentParser): the parser
- prog (str): the command name
+ Args:
+ parser: Command parser.
+ prog: Program name.
Returns:
- (Command) information about the command from the parser
+ Information about the command from the parser.
"""
self.parser = parser
@@ -78,8 +88,7 @@ class ArgparseWriter(argparse.HelpFormatter):
groups = parser._mutually_exclusive_groups
usage = fmt._format_usage(None, actions, groups, "").strip()
- # Go through actions and split them into optionals, positionals,
- # and subcommands
+ # Go through actions and split them into optionals, positionals, and subcommands
optionals = []
positionals = []
subcommands = []
@@ -96,7 +105,7 @@ class ArgparseWriter(argparse.HelpFormatter):
subcommands.append((subparser, subaction.dest))
# Look for aliases of the form 'name (alias, ...)'
- if self.aliases:
+ if self.aliases and isinstance(subaction.metavar, str):
match = re.match(r"(.*) \((.*)\)", subaction.metavar)
if match:
aliases = match.group(2).split(", ")
@@ -111,28 +120,26 @@ class ArgparseWriter(argparse.HelpFormatter):
return Command(prog, description, usage, positionals, optionals, subcommands)
- def format(self, cmd):
- """Returns the string representation of a single node in the
- parser tree.
+ @abc.abstractmethod
+ def format(self, cmd: Command) -> str:
+ """Return the string representation of a single node in the parser tree.
- Override this in subclasses to define how each subcommand
- should be displayed.
+ Override this in subclasses to define how each subcommand should be displayed.
- Parameters:
- (Command): parsed information about a command or subcommand
+ Args:
+ cmd: Parsed information about a command or subcommand.
Returns:
- str: the string representation of this subcommand
+ String representation of this subcommand.
"""
- raise NotImplementedError
- def _write(self, parser, prog, level=0):
- """Recursively writes a parser.
+ def _write(self, parser: ArgumentParser, prog: str, level: int = 0) -> None:
+ """Recursively write a parser.
- Parameters:
- parser (argparse.ArgumentParser): the parser
- prog (str): the command name
- level (int): the current level
+ Args:
+ parser: Command parser.
+ prog: Program name.
+ level: Current level.
"""
self.level = level
@@ -142,19 +149,17 @@ class ArgparseWriter(argparse.HelpFormatter):
for subparser, prog in cmd.subcommands:
self._write(subparser, prog, level=level + 1)
- def write(self, parser):
+ def write(self, parser: ArgumentParser) -> None:
"""Write out details about an ArgumentParser.
Args:
- parser (argparse.ArgumentParser): the parser
+ parser: Command parser.
"""
try:
self._write(parser, self.prog)
- except IOError as e:
+ except BrokenPipeError:
# Swallow pipe errors
- # Raises IOError in Python 2 and BrokenPipeError in Python 3
- if e.errno != errno.EPIPE:
- raise
+ pass
_rst_levels = ["=", "-", "^", "~", ":", "`"]
@@ -163,21 +168,33 @@ _rst_levels = ["=", "-", "^", "~", ":", "`"]
class ArgparseRstWriter(ArgparseWriter):
"""Write argparse output as rst sections."""
- def __init__(self, prog, out=None, aliases=False, rst_levels=_rst_levels):
- """Create a new ArgparseRstWriter.
+ def __init__(
+ self,
+ prog: str,
+ out: IO = sys.stdout,
+ aliases: bool = False,
+ rst_levels: Sequence[str] = _rst_levels,
+ ) -> None:
+ """Initialize a new ArgparseRstWriter instance.
- Parameters:
- prog (str): program name
- out (file object): file to write to
- aliases (bool): whether or not to include subparsers for aliases
- rst_levels (list of str): list of characters
- for rst section headings
+ Args:
+ prog: Program name.
+ out: File object to write to.
+ aliases: Whether or not to include subparsers for aliases.
+ rst_levels: List of characters for rst section headings.
"""
- out = sys.stdout if out is None else out
- super(ArgparseRstWriter, self).__init__(prog, out, aliases)
+ super().__init__(prog, out, aliases)
self.rst_levels = rst_levels
- def format(self, cmd):
+ def format(self, cmd: Command) -> str:
+ """Return the string representation of a single node in the parser tree.
+
+ Args:
+ cmd: Parsed information about a command or subcommand.
+
+ Returns:
+ String representation of a node.
+ """
string = io.StringIO()
string.write(self.begin_command(cmd.prog))
@@ -203,7 +220,15 @@ class ArgparseRstWriter(ArgparseWriter):
return string.getvalue()
- def begin_command(self, prog):
+ def begin_command(self, prog: str) -> str:
+ """Text to print before a command.
+
+ Args:
+ prog: Program name.
+
+ Returns:
+ Text before a command.
+ """
return """
----
@@ -216,10 +241,26 @@ class ArgparseRstWriter(ArgparseWriter):
prog.replace(" ", "-"), prog, self.rst_levels[self.level] * len(prog)
)
- def description(self, description):
+ def description(self, description: str) -> str:
+ """Description of a command.
+
+ Args:
+ description: Command description.
+
+ Returns:
+ Description of a command.
+ """
return description + "\n\n"
- def usage(self, usage):
+ def usage(self, usage: str) -> str:
+ """Example usage of a command.
+
+ Args:
+ usage: Command usage.
+
+ Returns:
+ Usage of a command.
+ """
return """\
.. code-block:: console
@@ -229,10 +270,24 @@ class ArgparseRstWriter(ArgparseWriter):
usage
)
- def begin_positionals(self):
+ def begin_positionals(self) -> str:
+ """Text to print before positional arguments.
+
+ Returns:
+ Positional arguments header.
+ """
return "\n**Positional arguments**\n\n"
- def positional(self, name, help):
+ def positional(self, name: str, help: str) -> str:
+ """Description of a positional argument.
+
+ Args:
+ name: Argument name.
+ help: Help text.
+
+ Returns:
+ Positional argument description.
+ """
return """\
{0}
{1}
@@ -241,13 +296,32 @@ class ArgparseRstWriter(ArgparseWriter):
name, help
)
- def end_positionals(self):
+ def end_positionals(self) -> str:
+ """Text to print after positional arguments.
+
+ Returns:
+ Positional arguments footer.
+ """
return ""
- def begin_optionals(self):
+ def begin_optionals(self) -> str:
+ """Text to print before optional arguments.
+
+ Returns:
+ Optional arguments header.
+ """
return "\n**Optional arguments**\n\n"
- def optional(self, opts, help):
+ def optional(self, opts: str, help: str) -> str:
+ """Description of an optional argument.
+
+ Args:
+ opts: Optional argument.
+ help: Help text.
+
+ Returns:
+ Optional argument description.
+ """
return """\
``{0}``
{1}
@@ -256,10 +330,23 @@ class ArgparseRstWriter(ArgparseWriter):
opts, help
)
- def end_optionals(self):
+ def end_optionals(self) -> str:
+ """Text to print after optional arguments.
+
+ Returns:
+ Optional arguments footer.
+ """
return ""
- def begin_subcommands(self, subcommands):
+ def begin_subcommands(self, subcommands: Sequence[Tuple[ArgumentParser, str]]) -> str:
+ """Table with links to other subcommands.
+
+ Arguments:
+ subcommands: List of subcommands.
+
+ Returns:
+ Subcommand linking text.
+ """
string = """
**Subcommands**
@@ -278,29 +365,25 @@ class ArgparseRstWriter(ArgparseWriter):
class ArgparseCompletionWriter(ArgparseWriter):
"""Write argparse output as shell programmable tab completion functions."""
- def format(self, cmd):
- """Returns the string representation of a single node in the
- parser tree.
+ def format(self, cmd: Command) -> str:
+ """Return the string representation of a single node in the parser tree.
- Override this in subclasses to define how each subcommand
- should be displayed.
-
- Parameters:
- (Command): parsed information about a command or subcommand
+ Args:
+ cmd: Parsed information about a command or subcommand.
Returns:
- str: the string representation of this subcommand
+ String representation of this subcommand.
"""
assert cmd.optionals # we should always at least have -h, --help
assert not (cmd.positionals and cmd.subcommands) # one or the other
# We only care about the arguments/flags, not the help messages
- positionals = []
+ positionals: Tuple[str, ...] = ()
if cmd.positionals:
positionals, _ = zip(*cmd.positionals)
optionals, _, _ = zip(*cmd.optionals)
- subcommands = []
+ subcommands: Tuple[str, ...] = ()
if cmd.subcommands:
_, subcommands = zip(*cmd.subcommands)
@@ -313,71 +396,73 @@ class ArgparseCompletionWriter(ArgparseWriter):
+ self.end_function(cmd.prog)
)
- def start_function(self, prog):
- """Returns the syntax needed to begin a function definition.
+ def start_function(self, prog: str) -> str:
+ """Return the syntax needed to begin a function definition.
- Parameters:
- prog (str): the command name
+ Args:
+ prog: Program name.
Returns:
- str: the function definition beginning
+ Function definition beginning.
"""
name = prog.replace("-", "_").replace(" ", "_")
return "\n_{0}() {{".format(name)
- def end_function(self, prog=None):
- """Returns the syntax needed to end a function definition.
+ def end_function(self, prog: str) -> str:
+ """Return the syntax needed to end a function definition.
- Parameters:
- prog (str or None): the command name
+ Args:
+ prog: Program name
Returns:
- str: the function definition ending
+ Function definition ending.
"""
return "}\n"
- def body(self, positionals, optionals, subcommands):
- """Returns the body of the function.
+ def body(
+ self, positionals: Sequence[str], optionals: Sequence[str], subcommands: Sequence[str]
+ ) -> str:
+ """Return the body of the function.
- Parameters:
- positionals (list): list of positional arguments
- optionals (list): list of optional arguments
- subcommands (list): list of subcommand parsers
+ Args:
+ positionals: List of positional arguments.
+ optionals: List of optional arguments.
+ subcommands: List of subcommand parsers.
Returns:
- str: the function body
+ Function body.
"""
return ""
- def positionals(self, positionals):
- """Returns the syntax for reporting positional arguments.
+ def positionals(self, positionals: Sequence[str]) -> str:
+ """Return the syntax for reporting positional arguments.
- Parameters:
- positionals (list): list of positional arguments
+ Args:
+ positionals: List of positional arguments.
Returns:
- str: the syntax for positional arguments
+ Syntax for positional arguments.
"""
return ""
- def optionals(self, optionals):
- """Returns the syntax for reporting optional flags.
+ def optionals(self, optionals: Sequence[str]) -> str:
+ """Return the syntax for reporting optional flags.
- Parameters:
- optionals (list): list of optional arguments
+ Args:
+ optionals: List of optional arguments.
Returns:
- str: the syntax for optional flags
+ Syntax for optional flags.
"""
return ""
- def subcommands(self, subcommands):
- """Returns the syntax for reporting subcommands.
+ def subcommands(self, subcommands: Sequence[str]) -> str:
+ """Return the syntax for reporting subcommands.
- Parameters:
- subcommands (list): list of subcommand parsers
+ Args:
+ subcommands: List of subcommand parsers.
Returns:
- str: the syntax for subcommand parsers
+ Syntax for subcommand parsers
"""
return ""
diff --git a/lib/spack/spack/cmd/commands.py b/lib/spack/spack/cmd/commands.py
index e48bb35f63..6af7bb54e8 100644
--- a/lib/spack/spack/cmd/commands.py
+++ b/lib/spack/spack/cmd/commands.py
@@ -8,10 +8,17 @@ import copy
import os
import re
import sys
+from argparse import ArgumentParser, Namespace
+from typing import IO, Any, Callable, Dict, Sequence, Set
import llnl.util.filesystem as fs
import llnl.util.tty as tty
-from llnl.util.argparsewriter import ArgparseCompletionWriter, ArgparseRstWriter, ArgparseWriter
+from llnl.util.argparsewriter import (
+ ArgparseCompletionWriter,
+ ArgparseRstWriter,
+ ArgparseWriter,
+ Command,
+)
from llnl.util.tty.colify import colify
import spack.cmd
@@ -25,12 +32,12 @@ level = "long"
#: list of command formatters
-formatters = {}
+formatters: Dict[str, Callable[[Namespace, IO], None]] = {}
#: standard arguments for updating completion scripts
#: we iterate through these when called with --update-completion
-update_completion_args = {
+update_completion_args: Dict[str, Dict[str, Any]] = {
"bash": {
"aliases": True,
"format": "bash",
@@ -40,13 +47,25 @@ update_completion_args = {
}
-def formatter(func):
- """Decorator used to register formatters"""
+def formatter(func: Callable[[Namespace, IO], None]) -> Callable[[Namespace, IO], None]:
+ """Decorator used to register formatters.
+
+ Args:
+ func: Formatting function.
+
+ Returns:
+ The same function.
+ """
formatters[func.__name__] = func
return func
-def setup_parser(subparser):
+def setup_parser(subparser: ArgumentParser) -> None:
+ """Set up the argument parser.
+
+ Args:
+ subparser: Preliminary argument parser.
+ """
subparser.add_argument(
"--update-completion",
action="store_true",
@@ -89,18 +108,34 @@ class SpackArgparseRstWriter(ArgparseRstWriter):
def __init__(
self,
- prog,
- out=None,
- aliases=False,
- documented_commands=[],
- rst_levels=["-", "-", "^", "~", ":", "`"],
+ prog: str,
+ out: IO = sys.stdout,
+ aliases: bool = False,
+ documented_commands: Set[str] = set(),
+ rst_levels: Sequence[str] = ["-", "-", "^", "~", ":", "`"],
):
- out = sys.stdout if out is None else out
- super(SpackArgparseRstWriter, self).__init__(prog, out, aliases, rst_levels)
+ """Initialize a new SpackArgparseRstWriter instance.
+
+ Args:
+ prog: Program name.
+ out: File object to write to.
+ aliases: Whether or not to include subparsers for aliases.
+ documented_commands: Set of commands with additional documentation.
+ rst_levels: List of characters for rst section headings.
+ """
+ super().__init__(prog, out, aliases, rst_levels)
self.documented = documented_commands
- def usage(self, *args):
- string = super(SpackArgparseRstWriter, self).usage(*args)
+ def usage(self, usage: str) -> str:
+ """Example usage of a command.
+
+ Args:
+ usage: Command usage.
+
+ Returns:
+ Usage of a command.
+ """
+ string = super().usage(usage)
cmd = self.parser.prog.replace(" ", "-")
if cmd in self.documented:
@@ -110,11 +145,21 @@ class SpackArgparseRstWriter(ArgparseRstWriter):
class SubcommandWriter(ArgparseWriter):
- def format(self, cmd):
+ """Write argparse output as a list of subcommands."""
+
+ def format(self, cmd: Command) -> str:
+ """Return the string representation of a single node in the parser tree.
+
+ Args:
+ cmd: Parsed information about a command or subcommand.
+
+ Returns:
+ String representation of this subcommand.
+ """
return " " * self.level + cmd.prog + "\n"
-_positional_to_subroutine = {
+_positional_to_subroutine: Dict[str, str] = {
"package": "_all_packages",
"spec": "_all_packages",
"filter": "_all_packages",
@@ -136,7 +181,19 @@ _positional_to_subroutine = {
class BashCompletionWriter(ArgparseCompletionWriter):
"""Write argparse output as bash programmable tab completion."""
- def body(self, positionals, optionals, subcommands):
+ def body(
+ self, positionals: Sequence[str], optionals: Sequence[str], subcommands: Sequence[str]
+ ) -> str:
+ """Return the body of the function.
+
+ Args:
+ positionals: List of positional arguments.
+ optionals: List of optional arguments.
+ subcommands: List of subcommand parsers.
+
+ Returns:
+ Function body.
+ """
if positionals:
return """
if $list_options
@@ -166,7 +223,15 @@ class BashCompletionWriter(ArgparseCompletionWriter):
self.optionals(optionals)
)
- def positionals(self, positionals):
+ def positionals(self, positionals: Sequence[str]) -> str:
+ """Return the syntax for reporting positional arguments.
+
+ Args:
+ positionals: List of positional arguments.
+
+ Returns:
+ Syntax for positional arguments.
+ """
# If match found, return function name
for positional in positionals:
for key, value in _positional_to_subroutine.items():
@@ -176,22 +241,49 @@ class BashCompletionWriter(ArgparseCompletionWriter):
# If no matches found, return empty list
return 'SPACK_COMPREPLY=""'
- def optionals(self, optionals):
+ def optionals(self, optionals: Sequence[str]) -> str:
+ """Return the syntax for reporting optional flags.
+
+ Args:
+ optionals: List of optional arguments.
+
+ Returns:
+ Syntax for optional flags.
+ """
return 'SPACK_COMPREPLY="{0}"'.format(" ".join(optionals))
- def subcommands(self, subcommands):
+ def subcommands(self, subcommands: Sequence[str]) -> str:
+ """Return the syntax for reporting subcommands.
+
+ Args:
+ subcommands: List of subcommand parsers.
+
+ Returns:
+ Syntax for subcommand parsers
+ """
return 'SPACK_COMPREPLY="{0}"'.format(" ".join(subcommands))
@formatter
-def subcommands(args, out):
+def subcommands(args: Namespace, out: IO) -> None:
+ """Hierarchical tree of subcommands.
+
+ args:
+ args: Command-line arguments.
+ out: File object to write to.
+ """
parser = spack.main.make_argument_parser()
spack.main.add_all_commands(parser)
writer = SubcommandWriter(parser.prog, out, args.aliases)
writer.write(parser)
-def rst_index(out):
+def rst_index(out: IO) -> None:
+ """Generate an index of all commands.
+
+ Args:
+ out: File object to write to.
+ """
out.write("\n")
index = spack.main.index_commands()
@@ -219,13 +311,19 @@ def rst_index(out):
@formatter
-def rst(args, out):
+def rst(args: Namespace, out: IO) -> None:
+ """ReStructuredText documentation of subcommands.
+
+ args:
+ args: Command-line arguments.
+ out: File object to write to.
+ """
# create a parser with all commands
parser = spack.main.make_argument_parser()
spack.main.add_all_commands(parser)
# extract cross-refs of the form `_cmd-spack-<cmd>:` from rst files
- documented_commands = set()
+ documented_commands: Set[str] = set()
for filename in args.rst_files:
with open(filename) as f:
for line in f:
@@ -243,7 +341,13 @@ def rst(args, out):
@formatter
-def names(args, out):
+def names(args: Namespace, out: IO) -> None:
+ """Simple list of top-level commands.
+
+ args:
+ args: Command-line arguments.
+ out: File object to write to.
+ """
commands = copy.copy(spack.cmd.all_commands())
if args.aliases:
@@ -253,7 +357,13 @@ def names(args, out):
@formatter
-def bash(args, out):
+def bash(args: Namespace, out: IO) -> None:
+ """Bash tab-completion script.
+
+ args:
+ args: Command-line arguments.
+ out: File object to write to.
+ """
parser = spack.main.make_argument_parser()
spack.main.add_all_commands(parser)
@@ -261,7 +371,13 @@ def bash(args, out):
writer.write(parser)
-def prepend_header(args, out):
+def prepend_header(args: Namespace, out: IO) -> None:
+ """Prepend header text at the beginning of a file.
+
+ Args:
+ args: Command-line arguments.
+ out: File object to write to.
+ """
if not args.header:
return
@@ -269,10 +385,14 @@ def prepend_header(args, out):
out.write(header.read())
-def _commands(parser, args):
+def _commands(parser: ArgumentParser, args: Namespace) -> None:
"""This is the 'regular' command, which can be called multiple times.
See ``commands()`` below for ``--update-completion`` handling.
+
+ Args:
+ parser: Argument parser.
+ args: Command-line arguments.
"""
formatter = formatters[args.format]
@@ -294,12 +414,15 @@ def _commands(parser, args):
formatter(args, sys.stdout)
-def update_completion(parser, args):
+def update_completion(parser: ArgumentParser, args: Namespace) -> None:
"""Iterate through the shells and update the standard completion files.
This is a convenience method to avoid calling this command many
times, and to simplify completion update for developers.
+ Args:
+ parser: Argument parser.
+ args: Command-line arguments.
"""
for shell, shell_args in update_completion_args.items():
for attr, value in shell_args.items():
@@ -307,14 +430,20 @@ def update_completion(parser, args):
_commands(parser, args)
-def commands(parser, args):
+def commands(parser: ArgumentParser, args: Namespace) -> None:
+ """Main function that calls formatter functions.
+
+ Args:
+ parser: Argument parser.
+ args: Command-line arguments.
+ """
if args.update_completion:
if args.format != "names" or any([args.aliases, args.update, args.header]):
tty.die("--update-completion can only be specified alone.")
# this runs the command multiple times with different arguments
- return update_completion(parser, args)
+ update_completion(parser, args)
else:
# run commands normally
- return _commands(parser, args)
+ _commands(parser, args)
diff --git a/lib/spack/spack/test/llnl/util/argparsewriter.py b/lib/spack/spack/test/llnl/util/argparsewriter.py
index 70b1824e2f..a2455e0303 100644
--- a/lib/spack/spack/test/llnl/util/argparsewriter.py
+++ b/lib/spack/spack/test/llnl/util/argparsewriter.py
@@ -20,10 +20,8 @@ spack.main.add_all_commands(parser)
def test_format_not_overridden():
- writer = aw.ArgparseWriter("spack")
-
- with pytest.raises(NotImplementedError):
- writer.write(parser)
+ with pytest.raises(TypeError):
+ aw.ArgparseWriter("spack")
def test_completion_format_not_overridden():