From 7540a1b9ead9dcd6ddce9c9ed3fbb3f81863df9b Mon Sep 17 00:00:00 2001 From: Victor Lin <13424970+victorlin@users.noreply.github.com> Date: Fri, 3 Jan 2025 09:42:54 -0800 Subject: [PATCH 1/3] Use custom help formatter class Start with a copy of ArgumentDefaultsHelpFormatter. To be modified. --- augur/argparse_.py | 31 +++++++++++++++++++++++-------- docs/conf.py | 3 ++- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/augur/argparse_.py b/augur/argparse_.py index 6084fdd5e..56e4bffb2 100644 --- a/augur/argparse_.py +++ b/augur/argparse_.py @@ -1,25 +1,40 @@ """ 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 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 '%(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. @@ -61,7 +76,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__ diff --git a/docs/conf.py b/docs/conf.py index 7b439c465..12b6e4f10 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -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. # ("py:class", "argparse._SubParsersAction"), + ("py:class", "argparse.HelpFormatter"), ] # -- Cross-project references ------------------------------------------------ From 6f6d1a9ec307bbd0611e24776051bc27e6c55382 Mon Sep 17 00:00:00 2001 From: Victor Lin <13424970+victorlin@users.noreply.github.com> Date: Fri, 3 Jan 2025 09:55:31 -0800 Subject: [PATCH 2/3] Add help text to clarify extend actions This is only meaningful for options that have default values specified. --- augur/argparse_.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/augur/argparse_.py b/augur/argparse_.py index 56e4bffb2..291023172 100644 --- a/augur/argparse_.py +++ b/augur/argparse_.py @@ -1,7 +1,7 @@ """ Custom helpers for the argparse standard library. """ -from argparse import Action, ArgumentParser, _ArgumentGroup, HelpFormatter, SUPPRESS, OPTIONAL, ZERO_OR_MORE +from argparse import Action, ArgumentParser, _ArgumentGroup, HelpFormatter, SUPPRESS, OPTIONAL, ZERO_OR_MORE, _ExtendAction from typing import Union from .types import ValidationMode @@ -27,6 +27,13 @@ class CustomHelpFormatter(HelpFormatter): """ 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] From 3d71c25119522b0bcbebe7cd1dc1dc64be12896a Mon Sep 17 00:00:00 2001 From: Victor Lin <13424970+victorlin@users.noreply.github.com> Date: Fri, 3 Jan 2025 14:04:54 -0800 Subject: [PATCH 3/3] Update changelog --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 9d209f767..db778de88 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -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)