def parse_help(cmd: typing.Collection[str], text: str, parse_positionals=True) -> Command: """ Parse a string of help text into a Command. Use this if you already have run the executable and extracted the help text yourself :param cmd: List of arguments used to generate this help text, e.g. ['bwa', 'mem'] :param text: The help text to parse :param parse_positionals: If false, don't parse positional arguments """ help_command = CliParser( parse_positionals=parse_positionals).parse_command(name=cmd, cmd=text) usage_command = parse_usage(cmd, text) # Combine the two commands by picking from the help_command where possible, otherwise falling back on the usage fields = dict( help_text=text, # Use the help command's positionals preferentially, but fall back to usage positional=help_command.positional or usage_command.positional, # Combine the flags from both help and usage named=list(_combine_flags([help_command.named, usage_command.named])), ) for field in dataclasses.fields(Command): fields[field.name] = (fields.get(field.name) or getattr(help_command, field.name) or getattr(usage_command, field.name)) return Command(**fields)
def test_pisces_usage(): text = "USAGE: dotnet Pisces.dll -bam <bam path> -g <genome path>" command = parse_usage(["pisces"], text) assert len(command.named) == 2 assert len(command.positional) == 0 assert command.named[0].longest_synonym == "-bam" assert command.named[1].longest_synonym == "-g"
def test_bwt2sa(): text = """ Usage: bwa bwt2sa [-i 32] <in.bwt> <out.sa> """ command = parse_usage(["bwa", "bwt2sa"], text) # in and out assert len(command.positional) == 2 # -i assert len(command.named) == 1
def test_samtools_merge_full(process): text = process(""" Usage: samtools merge [-nurlf] [-h inh.sam] [-b <bamlist.fofn>] <out.bam> <in1.bam> [<in2.bam> ... <inN.bam>] """) command = parse_usage(cmd=["samtools", "merge"], text=text) assert len(command.positional) == 3 assert command.positional[0].name == "out.bam" assert command.positional[1].name == "in1.bam" assert len(command.named) == 3 assert command.named[0].longest_synonym == "-nurlf" assert command.named[1].longest_synonym == "-h" assert command.named[2].longest_synonym == "-b"
def test_trailing_text(process): """ Tests that the usage parser will not parse text after the usage section has ended """ text = process(""" usage: htseq-count [options] alignment_file gff_file This script takes one or more alignment files in SAM/BAM format and a feature file in GFF format and calculates for each feature the number of reads mapping to it. See http://htseq.readthedocs.io/en/master/count.html for details. """) command = parse_usage(["htseq-count"], text) # We don't count either the command "htseq-count", or "[options]" as an argument, so there are only 2 positionals assert len(command.positional) == 2
def test_bedtools_multiinter(): text = """ Summary: Identifies common intervals among multiple BED/GFF/VCF files. Usage: bedtools multiinter [OPTIONS] -i FILE1 FILE2 .. FILEn Requires that each interval file is sorted by chrom/start. Options: -cluster Invoke Ryan Layers's clustering algorithm. """ command = parse_usage(["bedtools", "multiinter"], text) assert len(command.positional) == 0 assert len(command.named) == 1 assert command.named[0].longest_synonym == "-i" assert isinstance(command.named[0].args, RepeatFlagArg)
def test_mid_line_usage(): text = """ Can't open --usage: No such file or directory at /usr/bin/samtools.pl line 50. """ command = parse_usage(["samtools.pl", "showALEN"], text, debug=True) assert command.empty
def test_samtools_dict(): text = """ Usage: samtools dict [options] <file.fa|file.fa.gz> """ command = parse_usage(["samtools", "dict"], text, debug=True) assert len(command.positional) == 1