Skip to content

Commit

Permalink
Allow repeating an option that takes multiple values
Browse files Browse the repository at this point in the history
Many command line arguments take multiple values. Previously, to utilize
this feature, all values must be specified after a single option flag
(e.g. --exclude-where 'region=A' 'region=B'). If options were set using
separate option flags (e.g. --exclude-where 'region=A' --exclude-where
'region=B'), only the last flag would be used, which is unintuitive.
This commit enables all option flags to be used.

Done across the codebase by adding action='extend' to all options that
use nargs='+' and did not already specify an action.
  • Loading branch information
victorlin committed Apr 15, 2024
1 parent e0e03c9 commit 6a998d9
Show file tree
Hide file tree
Showing 14 changed files with 29 additions and 30 deletions.
2 changes: 1 addition & 1 deletion augur/ancestral.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ def register_parser(parent_subparsers):
)
amino_acid_options_group.add_argument('--annotation',
help='GenBank or GFF file containing the annotation')
amino_acid_options_group.add_argument('--genes', nargs='+', help="genes to translate (list or file containing list)")
amino_acid_options_group.add_argument('--genes', nargs='+', action='extend', help="genes to translate (list or file containing list)")
amino_acid_options_group.add_argument('--translations', type=str, help="translated alignments for each CDS/Gene. "
"Currently only supported for FASTA-input. Specify the file name via a "
"template like 'aa_sequences_%%GENE.fasta' where %%GENE will be replaced "
Expand Down
4 changes: 2 additions & 2 deletions augur/clades.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,8 +341,8 @@ def parse_nodes(tree_file, node_data_files):
def register_parser(parent_subparsers):
parser = parent_subparsers.add_parser("clades", help=__doc__)
parser.add_argument('--tree', required=True, help="prebuilt Newick -- no tree will be built if provided")
parser.add_argument('--mutations', required=True, metavar="NODE_DATA_JSON", nargs='+', help='JSON(s) containing ancestral and tip nucleotide and/or amino-acid mutations ')
parser.add_argument('--reference', nargs='+', help=SUPPRESS)
parser.add_argument('--mutations', required=True, metavar="NODE_DATA_JSON", nargs='+', action='extend', help='JSON(s) containing ancestral and tip nucleotide and/or amino-acid mutations ')
parser.add_argument('--reference', nargs='+', action='extend', help=SUPPRESS)
parser.add_argument('--clades', required=True, metavar="TSV", type=str, help='TSV file containing clade definitions by amino-acid')
parser.add_argument('--output-node-data', type=str, metavar="NODE_DATA_JSON", help='name of JSON file to save clade assignments to')
parser.add_argument('--membership-name', type=str, default="clade_membership", help='Key to store clade membership under; use "None" to not export this')
Expand Down
6 changes: 3 additions & 3 deletions augur/export_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -889,12 +889,12 @@ def register_parser(parent_subparsers):
config.add_argument('--maintainers', metavar="name", action="append", nargs='+', help="Analysis maintained by, in format 'Name <URL>' 'Name2 <URL>', ...")
config.add_argument('--build-url', type=str, metavar="url", help="Build URL/repository to be displayed by Auspice")
config.add_argument('--description', metavar="description.md", help="Markdown file with description of build and/or acknowledgements to be displayed by Auspice")
config.add_argument('--geo-resolutions', metavar="trait", nargs='+', help="Geographic traits to be displayed on map")
config.add_argument('--color-by-metadata', metavar="trait", nargs='+', help="Metadata columns to include as coloring options")
config.add_argument('--geo-resolutions', metavar="trait", nargs='+', action='extend', help="Geographic traits to be displayed on map")
config.add_argument('--color-by-metadata', metavar="trait", nargs='+', action='extend', help="Metadata columns to include as coloring options")
config.add_argument('--metadata-columns', nargs="+",
help="Metadata columns to export in addition to columns provided by --color-by-metadata or colorings in the Auspice configuration file. " +
"These columns will not be used as coloring options in Auspice but will be visible in the tree.")
config.add_argument('--panels', metavar="panels", nargs='+', choices=['tree', 'map', 'entropy', 'frequencies', 'measurements'], help="Restrict panel display in auspice. Options are %(choices)s. Ignore this option to display all available panels.")
config.add_argument('--panels', metavar="panels", nargs='+', action='extend', choices=['tree', 'map', 'entropy', 'frequencies', 'measurements'], help="Restrict panel display in auspice. Options are %(choices)s. Ignore this option to display all available panels.")

optional_inputs = parser.add_argument_group(
title="OPTIONAL INPUT FILES"
Expand Down
6 changes: 3 additions & 3 deletions augur/filter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ def register_arguments(parser):
metadata_filter_group.add_argument('--exclude-ambiguous-dates-by', choices=['any', 'day', 'month', 'year'],
help='Exclude ambiguous dates by day (e.g., 2020-09-XX), month (e.g., 2020-XX-XX), year (e.g., 200X-10-01), or any date fields. An ambiguous year makes the corresponding month and day ambiguous, too, even if those fields have unambiguous values (e.g., "201X-10-01"). Similarly, an ambiguous month makes the corresponding day ambiguous (e.g., "2010-XX-01").')
metadata_filter_group.add_argument('--exclude', type=str, nargs="+", help="file(s) with list of strains to exclude")
metadata_filter_group.add_argument('--exclude-where', nargs='+',
metadata_filter_group.add_argument('--exclude-where', nargs='+', action='extend',
help="Exclude samples matching these conditions. Ex: \"host=rat\" or \"host!=rat\". Multiple values are processed as OR (matching any of those specified will be excluded), not AND")
metadata_filter_group.add_argument('--exclude-all', action="store_true", help="exclude all strains by default. Use this with the include arguments to select a specific subset of strains.")
metadata_filter_group.add_argument('--include', type=str, nargs="+", help="file(s) with list of strains to include regardless of priorities, subsampling, or absence of an entry in --sequences.")
metadata_filter_group.add_argument('--include-where', nargs='+', help="""
metadata_filter_group.add_argument('--include-where', nargs='+', action='extend', help="""
Include samples with these values. ex: host=rat. Multiple values are
processed as OR (having any of those specified will be included), not
AND. This rule is applied last and ensures any strains matching these
Expand All @@ -56,7 +56,7 @@ def register_arguments(parser):
sequence_filter_group.add_argument('--non-nucleotide', action='store_true', help="exclude sequences that contain illegal characters")

subsample_group = parser.add_argument_group("subsampling", "options to subsample filtered data")
subsample_group.add_argument('--group-by', nargs='+', help=f"""
subsample_group.add_argument('--group-by', nargs='+', action='extend', help=f"""
categories with respect to subsample.
Notes:
(1) Grouping by {sorted(constants.GROUP_BY_GENERATED_COLUMNS)} is only supported when there is a {METADATA_DATE_COLUMN!r} column in the metadata.
Expand Down
6 changes: 3 additions & 3 deletions augur/frequencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def register_parser(parent_subparsers):
help="delimiters to accept when reading a metadata file. Only one delimiter will be inferred.")
parser.add_argument('--metadata-id-columns', default=DEFAULT_ID_COLUMNS, nargs="+",
help="names of possible metadata columns containing identifier information, ordered by priority. Only one ID column will be inferred.")
parser.add_argument('--regions', type=str, nargs='+', default=[DEFAULT_REGION],
parser.add_argument('--regions', type=str, nargs='+', action='extend', default=[DEFAULT_REGION],
help="region to filter to. " \
f"Regions should match values in the {REGION_COLUMN!r} column of the metadata file " \
f"if specifying values other than the default {DEFAULT_REGION!r} region.")
Expand All @@ -48,9 +48,9 @@ def register_parser(parent_subparsers):
help="calculate frequencies for internal nodes as well as tips")

# Alignment-specific arguments
parser.add_argument('--alignments', type=str, nargs='+',
parser.add_argument('--alignments', type=str, nargs='+', action='extend',
help="alignments to estimate mutations frequencies for")
parser.add_argument('--gene-names', nargs='+', type=str,
parser.add_argument('--gene-names', nargs='+', action='extend', type=str,
help="names of the sequences in the alignment, same order assumed")
parser.add_argument('--ignore-char', type=str, default='',
help="character to be ignored in frequency calculations")
Expand Down
2 changes: 1 addition & 1 deletion augur/mask.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ def register_arguments(parser):
parser.add_argument('--mask-from-beginning', type=int, default=0, help="FASTA Only: Number of sites to mask from beginning")
parser.add_argument('--mask-from-end', type=int, default=0, help="FASTA Only: Number of sites to mask from end")
parser.add_argument('--mask-invalid', action='store_true', help="FASTA Only: Mask invalid nucleotides")
parser.add_argument("--mask-sites", nargs='+', type = int, help="1-indexed list of sites to mask")
parser.add_argument("--mask-sites", nargs='+', action='extend', type = int, help="1-indexed list of sites to mask")
parser.add_argument('--output', '-o', help="output file")
parser.add_argument('--no-cleanup', dest="cleanup", action="store_false",
help="Leave intermediate files around. May be useful for debugging")
Expand Down
4 changes: 2 additions & 2 deletions augur/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,8 @@ def register_parser(parent_subparsers):
parser.add_argument('--output-metadata', required=True, help="output metadata file")
parser.add_argument('--output-id-field', required=False,
help=f"The record field to use as the sequence identifier in the FASTA output. If not provided, this will use the first available of {PARSE_DEFAULT_ID_COLUMNS}. If none of those are available, this will use the first field in the fasta header.")
parser.add_argument('--fields', required=True, nargs='+', help="fields in fasta header")
parser.add_argument('--prettify-fields', nargs='+', help="apply string prettifying operations (underscores to spaces, capitalization, etc) to specified metadata fields")
parser.add_argument('--fields', required=True, nargs='+', action='extend', help="fields in fasta header")
parser.add_argument('--prettify-fields', nargs='+', action='extend', help="apply string prettifying operations (underscores to spaces, capitalization, etc) to specified metadata fields")
parser.add_argument('--separator', default='|', help="separator of fasta header")
parser.add_argument('--fix-dates', choices=['dayfirst', 'monthfirst'],
help="attempt to parse non-standard dates and output them in standard YYYY-MM-DD format")
Expand Down
2 changes: 1 addition & 1 deletion augur/refine.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def register_parser(parent_subparsers):
parser.add_argument('--clock-filter-iqd', type=float, help='clock-filter: remove tips that deviate more than n_iqd '
'interquartile ranges from the root-to-tip vs time regression')
parser.add_argument('--vcf-reference', type=str, help='fasta file of the sequence the VCF was mapped to')
parser.add_argument('--year-bounds', type=int, nargs='+', help='specify min or max & min prediction bounds for samples with XX in year')
parser.add_argument('--year-bounds', type=int, nargs='+', action='extend', help='specify min or max & min prediction bounds for samples with XX in year')
parser.add_argument('--divergence-units', type=str, choices=['mutations', 'mutations-per-site'],
default='mutations-per-site', help='Units in which sequence divergences is exported.')
parser.add_argument('--seed', type=int, help='seed for random number generation')
Expand Down
8 changes: 4 additions & 4 deletions augur/titers.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def register_parser(parent_subparsers):
add_default_command(parser)

tree_model = subparsers.add_parser('tree', help='tree model')
tree_model.add_argument('--titers', nargs='+', type=str, required=True, help="file with titer measurements")
tree_model.add_argument('--titers', nargs='+', action='extend', type=str, required=True, help="file with titer measurements")
tree_model.add_argument('--tree', '-t', type=str, required=True, help="tree to perform fit titer model to")
tree_model.add_argument('--allow-empty-model', action="store_true", help="allow model to be empty")
tree_model.add_argument('--attribute-prefix', default="", help="prefix for node attributes in the JSON output including cumulative titer drop ('cTiter') and per-branch titer drop ('dTiter'). Set a prefix to disambiguate annotations from multiple tree model JSONs in the final Auspice JSON.")
Expand All @@ -27,9 +27,9 @@ def register_parser(parent_subparsers):
)

sub_model = subparsers.add_parser('sub', help='substitution model')
sub_model.add_argument('--titers', nargs='+', type=str, required=True, help="file with titer measurements")
sub_model.add_argument('--alignment', nargs='+', type=str, required=True, help="sequence to be used in the substitution model, supplied as fasta files")
sub_model.add_argument('--gene-names', nargs='+', type=str, required=True, help="names of the sequences in the alignment, same order assumed")
sub_model.add_argument('--titers', nargs='+', action='extend', type=str, required=True, help="file with titer measurements")
sub_model.add_argument('--alignment', nargs='+', action='extend', type=str, required=True, help="sequence to be used in the substitution model, supplied as fasta files")
sub_model.add_argument('--gene-names', nargs='+', action='extend', type=str, required=True, help="names of the sequences in the alignment, same order assumed")
sub_model.add_argument('--tree', '-t', type=str, help="optional tree to annotate fit titer model to")
sub_model.add_argument('--allow-empty-model', action="store_true", help="allow model to be empty")
sub_model.add_argument('--attribute-prefix', default="", help="prefix for node attributes in the JSON output including cumulative titer drop ('cTiterSub') and per-substitution titer drop ('dTiterSub'). Set a prefix to disambiguate annotations from multiple substitution model JSONs in the final Auspice JSON.")
Expand Down
2 changes: 1 addition & 1 deletion augur/traits.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def register_parser(parent_subparsers):
parser.add_argument('--metadata-id-columns', default=DEFAULT_ID_COLUMNS, nargs="+",
help="names of possible metadata columns containing identifier information, ordered by priority. Only one ID column will be inferred.")
parser.add_argument('--weights', required=False, help="tsv/csv table with equilibrium probabilities of discrete states")
parser.add_argument('--columns', required=True, nargs='+',
parser.add_argument('--columns', required=True, nargs='+', action='extend',
help='metadata fields to perform discrete reconstruction on')
parser.add_argument('--confidence',action="store_true",
help='record the distribution of subleading mugration states')
Expand Down
2 changes: 1 addition & 1 deletion augur/translate.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ def register_parser(parent_subparsers):
parser.add_argument('--ancestral-sequences', required=True, type=str, help='JSON (fasta input) or VCF (VCF input) containing ancestral and tip sequences')
parser.add_argument('--reference-sequence', required=True,
help='GenBank or GFF file containing the annotation')
parser.add_argument('--genes', nargs='+', help="genes to translate (list or file containing list)")
parser.add_argument('--genes', nargs='+', action='extend', help="genes to translate (list or file containing list)")
parser.add_argument('--output-node-data', type=str, help='name of JSON file to save aa-mutations to')
parser.add_argument('--alignment-output', type=str, help="write out translated gene alignments. "
"If a VCF-input, a .vcf or .vcf.gz will be output here (depending on file ending). If fasta-input, specify the file name "
Expand Down
2 changes: 1 addition & 1 deletion scripts/swap_colors.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from glob import glob

parser = argparse.ArgumentParser(description ="Update color ramps in processed meta.JSON files")
parser.add_argument('--jsons', '--json', default=None, nargs='+', type=str, help="Path to prepared JSON(s) to edit. If none, will update all files like ./*meta.json")
parser.add_argument('--jsons', '--json', default=None, nargs='+', action='extend', type=str, help="Path to prepared JSON(s) to edit. If none, will update all files like ./*meta.json")
parser.add_argument('--custom_colors', default=None, type=str, help="Path to .tsv or .csv with custom color ramps; will fall back to nextstrain default colors if not provided.")
args = parser.parse_args().__dict__

Expand Down
10 changes: 5 additions & 5 deletions scripts/tree_to_JSON.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ def get_command_line_args():
beast = parser.add_argument_group('beast')
beast.add_argument('--nexus', type=str, help="Path to nexus file")
beast.add_argument('--most_recent_tip', type=float, help="Date of the most recent tip (in decimal format)")
beast.add_argument('--discrete_traits', type=str, nargs='+', default=[], help="Discrete traits to extract from the BEAST annotations")
beast.add_argument('--continuous_traits', type=str, nargs='+', default=[], help="Continuous traits to extract from the BEAST annotations")
beast.add_argument('--make_traits_log', type=str, nargs='+', default=[], help="Convert these (continous) traits to log space: y=-ln(x)")
beast.add_argument('--discrete_traits', type=str, nargs='+', action='extend', default=[], help="Discrete traits to extract from the BEAST annotations")
beast.add_argument('--continuous_traits', type=str, nargs='+', action='extend', default=[], help="Continuous traits to extract from the BEAST annotations")
beast.add_argument('--make_traits_log', type=str, nargs='+', action='extend', default=[], help="Convert these (continous) traits to log space: y=-ln(x)")
beast.add_argument("--fake_divergence", action="store_true", help="Set the divergence as time (prevents auspice crashing)")


Expand All @@ -34,8 +34,8 @@ def get_command_line_args():
general.add_argument("--debug", action="store_const", dest="loglevel", const=logging.DEBUG, help="Enable debugging logging")
general.add_argument('--output_prefix', '-o', required=True, type=str, help="Output prefix (i.e. \"_meta.json\" will be appended to this)")
general.add_argument('--title', default=None, type=str, help="Title (to be displayed by auspice)")
general.add_argument("--defaults", type=str, nargs='+', default=[], help="Auspice defaults. Format: \"key:value\"")
general.add_argument("--filters", type=str, nargs='+', default=[], help="Auspice filters.")
general.add_argument("--defaults", type=str, nargs='+', action='extend', default=[], help="Auspice defaults. Format: \"key:value\"")
general.add_argument("--filters", type=str, nargs='+', action='extend', default=[], help="Auspice filters.")
general.add_argument('--geo', type=str, help="CSV File w. header \"trait,value,latitude,longitude\". Turns on the map panel.")


Expand Down
3 changes: 1 addition & 2 deletions tests/functional/filter/cram/filter-exclude-where-multiple.t
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ Run command
> --exclude-where "region=B" \
> --output-strains filtered_strains.txt > /dev/null

Only the last exclusion is applied
Both exclusions are applied

$ cat filtered_strains.txt
SEQ_1
SEQ_3

0 comments on commit 6a998d9

Please sign in to comment.