Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add help text to clarify extend actions #1705

Merged
merged 3 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@

* ancestral, refine: Explicitly specify how the root and ambiguous states are handled during sequence reconstruction and mutation counting. [#1690][] (@rneher)
* titers: Fix type errors in code associated with cross-validation of models. [#1688][] (@huddlej)
* Add help text to clarify difference in behavior between options that override defaults (e.g. `--metadata-delimiters`) vs. options that extend existing defaults (e.g. `--expected-date-formats`). [#1705][] (@victorlin)

[#1688]: https://github.com/nextstrain/augur/pull/1688
[#1690]: https://github.com/nextstrain/augur/pull/1690
[#1705]: https://github.com/nextstrain/augur/pull/1705

## 27.0.0 (9 December 2024)

Expand Down
38 changes: 30 additions & 8 deletions augur/argparse_.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,47 @@
"""
Custom helpers for the argparse standard library.
"""
from argparse import Action, ArgumentDefaultsHelpFormatter, ArgumentParser, _ArgumentGroup
from argparse import Action, ArgumentParser, _ArgumentGroup, HelpFormatter, SUPPRESS, OPTIONAL, ZERO_OR_MORE, _ExtendAction
from typing import Union
from .types import ValidationMode


# Include this in an argument help string to suppress the automatic appending
# of the default value by argparse.ArgumentDefaultsHelpFormatter. This works
# because the automatic appending is conditional on the presence of %(default),
# so we include it but then format it as a zero-length string .0s. 🙃
# of the default value by CustomHelpFormatter. This works because the
# automatic appending is conditional on the presence of %(default), so we
# include it but then format it as a zero-length string .0s. 🙃
#
# Another solution would be to add an extra attribute to the argument (the
# argparse.Action instance) and then subclass ArgumentDefaultsHelpFormatter to
# condition on that new attribute, but that seems more brittle.
# argparse.Action instance) and then modify CustomHelpFormatter to condition
# on that new attribute, but that seems more brittle.
#
# Copied from the Nextstrain CLI repo
# Initially copied from the Nextstrain CLI repo
# https://github.com/nextstrain/cli/blob/017c53805e8317951327d24c04184615cc400b09/nextstrain/cli/argparse.py#L13-L21
SKIP_AUTO_DEFAULT_IN_HELP = "%(default).0s"


class CustomHelpFormatter(HelpFormatter):
"""Customize help text.

Initially copied from argparse.ArgumentDefaultsHelpFormatter.
"""
def _get_help_string(self, action: Action):
help = action.help

if action.default is not None and action.default != []:
if isinstance(action, ExtendOverwriteDefault):
help += ' Specified values will override the default list.'
if isinstance(action, _ExtendAction):
help += ' Specified values will extend the default list.'

if '%(default)' not in action.help:
if action.default is not SUPPRESS:
defaulting_nargs = [OPTIONAL, ZERO_OR_MORE]
if action.option_strings or action.nargs in defaulting_nargs:
help += ' (default: %(default)s)'
return help


def add_default_command(parser):
"""
Sets the default command to run when none is provided.
Expand Down Expand Up @@ -61,7 +83,7 @@ def add_command_subparsers(subparsers, commands, command_attribute='__command__'

# Use the same formatting class for every command for consistency.
# Set here to avoid repeating it in every command's register_parser().
subparser.formatter_class = ArgumentDefaultsHelpFormatter
subparser.formatter_class = CustomHelpFormatter

if not subparser.description and command.__doc__:
subparser.description = command.__doc__
Expand Down
3 changes: 2 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,10 @@ def prose_list(items):
("py:class", "json.decoder.JSONDecodeError"),
("py:class", "json.encoder.JSONEncoder"),

# This class can't be referenced.
# These classes can't be referenced.
# <https://github.com/python/cpython/issues/101503>
("py:class", "argparse._SubParsersAction"),
("py:class", "argparse.HelpFormatter"),
]

# -- Cross-project references ------------------------------------------------
Expand Down
Loading