Skip to content

Commit

Permalink
Register subparsers recursively
Browse files Browse the repository at this point in the history
Keeps consistent with Nextstrain CLI.
  • Loading branch information
victorlin committed Sep 24, 2024
1 parent bf05db8 commit 21160bc
Show file tree
Hide file tree
Showing 16 changed files with 27 additions and 52 deletions.
5 changes: 2 additions & 3 deletions augur/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from .debug import DEBUGGING
from .errors import AugurError
from .io.print import print_err
from .argparse_ import add_command_subparsers, add_default_command
from .argparse_ import register_commands, add_default_command

DEFAULT_AUGUR_RECURSION_LIMIT = 10000
sys.setrecursionlimit(int(os.environ.get("AUGUR_RECURSION_LIMIT") or DEFAULT_AUGUR_RECURSION_LIMIT))
Expand Down Expand Up @@ -58,8 +58,7 @@ def make_parser():
add_default_command(parser)
add_version_alias(parser)

subparsers = parser.add_subparsers()
add_command_subparsers(subparsers, COMMANDS)
register_commands(parser, COMMANDS)

return parser

Expand Down
15 changes: 10 additions & 5 deletions augur/argparse_.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Custom helpers for the argparse standard library.
"""
import argparse
from argparse import Action, ArgumentDefaultsHelpFormatter


Expand Down Expand Up @@ -30,16 +31,14 @@ def run(args):
parser.set_defaults(__command__ = default_command)


def add_command_subparsers(subparsers, commands, command_attribute='__command__'):
def register_commands(parser: argparse.ArgumentParser, commands, command_attribute='__command__'):
"""
Add subparsers for each command module.
Parameters
----------
subparsers: argparse._SubParsersAction
The special subparsers action object created by the parent parser
via `parser.add_subparsers()`.
parser
ArgumentParser object.
commands: list[types.ModuleType]
A list of modules that are commands that require their own subparser.
Each module is required to have a `register_parser` function to add its own
Expand All @@ -49,6 +48,8 @@ def add_command_subparsers(subparsers, commands, command_attribute='__command__'
Optional attribute name for the commands. The default is `__command__`,
which allows top level augur to run commands directly via `args.__command__.run()`.
"""
subparsers = parser.add_subparsers()

for command in commands:
# Allow each command to register its own subparser
subparser = command.register_parser(subparsers)
Expand All @@ -68,6 +69,10 @@ def add_command_subparsers(subparsers, commands, command_attribute='__command__'
if not getattr(command, "run", None):
add_default_command(subparser)

# Recursively register any subcommands
if getattr(subparser, "subcommands", None):
register_commands(subparser, subparser.subcommands)


class HideAsFalseAction(Action):
"""
Expand Down
16 changes: 2 additions & 14 deletions augur/curate/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from textwrap import dedent
from typing import Iterable, Set

from augur.argparse_ import ExtendOverwriteDefault, add_command_subparsers
from augur.argparse_ import ExtendOverwriteDefault
from augur.errors import AugurError
from augur.io.json import dump_ndjson, load_ndjson
from augur.io.metadata import DEFAULT_DELIMITERS, InvalidDelimiter, read_table_to_dict, read_metadata_with_sequences, write_records_to_tsv
Expand Down Expand Up @@ -103,21 +103,9 @@ def create_shared_parser():


def register_parser(parent_subparsers):
shared_parser = create_shared_parser()
parser = parent_subparsers.add_parser("curate", help=__doc__)

# Add print_help so we can run it when no subcommands are called
parser.set_defaults(print_help = parser.print_help)

# Add subparsers for subcommands
subparsers = parser.add_subparsers(dest="subcommand", required=False)
# Add the shared_parser to make it available for subcommands
# to include in their own parser
subparsers.shared_parser = shared_parser
# Using a subcommand attribute so subcommands are not directly
# run by top level Augur. Process I/O in `curate`` so individual
# subcommands do not have to worry about it.
add_command_subparsers(subparsers, SUBCOMMANDS, SUBCOMMAND_ATTRIBUTE)
parser.subcommands = SUBCOMMANDS

return parser

Expand Down
1 change: 0 additions & 1 deletion augur/curate/abbreviate_authors.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ def register_parser(
) -> argparse._SubParsersAction:
parser = parent_subparsers.add_parser(
"abbreviate-authors",
parents=[parent_subparsers.shared_parser], # type: ignore
help=first_line(__doc__),
)

Expand Down
1 change: 0 additions & 1 deletion augur/curate/apply_geolocation_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,6 @@ def transform_geolocations(geolocation_rules, geolocation):

def register_parser(parent_subparsers):
parser = parent_subparsers.add_parser("apply-geolocation-rules",
parents=[parent_subparsers.shared_parser],
help=first_line(__doc__))

parser.add_argument("--region-field", default="region",
Expand Down
1 change: 0 additions & 1 deletion augur/curate/apply_record_annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

def register_parser(parent_subparsers):
parser = parent_subparsers.add_parser("apply-record-annotations",
parents=[parent_subparsers.shared_parser],
help=first_line(__doc__))

parser.add_argument("--annotations", metavar="TSV", required=True,
Expand Down
1 change: 0 additions & 1 deletion augur/curate/format_dates.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

def register_parser(parent_subparsers):
parser = parent_subparsers.add_parser("format-dates",
parents=[parent_subparsers.shared_parser],
help=__doc__)

required = parser.add_argument_group(title="REQUIRED")
Expand Down
1 change: 0 additions & 1 deletion augur/curate/normalize_strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

def register_parser(parent_subparsers):
parser = parent_subparsers.add_parser("normalize-strings",
parents=[parent_subparsers.shared_parser],
help=first_line(__doc__))

optional = parser.add_argument_group(title="OPTIONAL")
Expand Down
1 change: 0 additions & 1 deletion augur/curate/parse_genbank_location.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ def register_parser(
) -> argparse._SubParsersAction:
parser = parent_subparsers.add_parser(
"parse-genbank-location",
parents=[parent_subparsers.shared_parser], # type: ignore
help=first_line(__doc__),
)

Expand Down
1 change: 0 additions & 1 deletion augur/curate/passthru.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

def register_parser(parent_subparsers):
return parent_subparsers.add_parser("passthru",
parents=[parent_subparsers.shared_parser],
help=__doc__)


Expand Down
1 change: 0 additions & 1 deletion augur/curate/rename.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

def register_parser(parent_subparsers):
parser = parent_subparsers.add_parser("rename",
parents = [parent_subparsers.shared_parser],
help = __doc__)

required = parser.add_argument_group(title="REQUIRED")
Expand Down
1 change: 0 additions & 1 deletion augur/curate/titlecase.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

def register_parser(parent_subparsers):
parser = parent_subparsers.add_parser("titlecase",
parents = [parent_subparsers.shared_parser],
help = __doc__)

required = parser.add_argument_group(title="REQUIRED")
Expand Down
1 change: 0 additions & 1 deletion augur/curate/transform_strain_name.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ def register_parser(
) -> argparse._SubParsersAction:
parser = parent_subparsers.add_parser(
"transform-strain-name",
parents=[parent_subparsers.shared_parser], # type: ignore
help=first_line(__doc__),
)

Expand Down
12 changes: 5 additions & 7 deletions augur/export.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"""
Export JSON files suitable for visualization with auspice.
Augur export now needs you to define the JSON version you want, e.g. `augur export v2`.
"""
from .argparse_ import add_command_subparsers
from . import export_v1, export_v2

SUBCOMMANDS = [
Expand All @@ -12,10 +13,7 @@

def register_parser(parent_subparsers):
parser = parent_subparsers.add_parser("export", help=__doc__)
# Add subparsers for subcommands
metavar_msg ="Augur export now needs you to define the JSON version " + \
"you want, e.g. `augur export v2`."
subparsers = parser.add_subparsers(title="JSON SCHEMA",
metavar=metavar_msg)
add_command_subparsers(subparsers, SUBCOMMANDS)

parser.subcommands = SUBCOMMANDS

return parser
11 changes: 4 additions & 7 deletions augur/import_/__init__.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
"""
Import analyses into augur pipeline from other systems
"""
from augur.argparse_ import add_command_subparsers
from augur.utils import first_line
from . import beast

SUBCOMMANDS = [
beast,
]

def register_parser(parent_subparsers):
parser = parent_subparsers.add_parser("import", help=first_line(__doc__))
metavar_msg = "Import analyses into augur pipeline from other systems"
subparsers = parser.add_subparsers(title="TYPE",
metavar=metavar_msg)
add_command_subparsers(subparsers, SUBCOMMANDS)
parser = parent_subparsers.add_parser("import", help=__doc__)

parser.subcommands = SUBCOMMANDS

return parser
10 changes: 4 additions & 6 deletions augur/measurements/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
"""
Create JSON files suitable for visualization within the measurements panel of Auspice.
"""
from augur.argparse_ import add_command_subparsers
from augur.utils import first_line
from . import export, concat

SUBCOMMANDS = [
Expand All @@ -12,8 +10,8 @@


def register_parser(parent_subparsers):
parser = parent_subparsers.add_parser("measurements", help=first_line(__doc__))
# Add subparsers for subcommands
subparsers = parser.add_subparsers(dest='subcommand')
add_command_subparsers(subparsers, SUBCOMMANDS)
parser = parent_subparsers.add_parser("measurements", help=__doc__)

parser.subcommands = SUBCOMMANDS

return parser

0 comments on commit 21160bc

Please sign in to comment.