From bd5d02631554f9923207b743c6390e3419243ab1 Mon Sep 17 00:00:00 2001 From: Stefan Bienert <stefan.bienert@unibas.ch> Date: Wed, 26 Aug 2015 09:52:49 +0200 Subject: [PATCH] Alignment option is now required --- core/pymod/core/pm3argparse.py | 10 +++++-- core/tests/test_pm3argparse.py | 53 +++++++++++++++++++++++++--------- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/core/pymod/core/pm3argparse.py b/core/pymod/core/pm3argparse.py index 59cc9485..e7d1da32 100644 --- a/core/pymod/core/pm3argparse.py +++ b/core/pymod/core/pm3argparse.py @@ -121,9 +121,13 @@ def _AssembleTrgTplAln(target, template): new_aln.SetSequenceOffset(1, start) return new_aln + class PM3StoreOnceAction(argparse.Action): """Action for argument parsing to prevent multiple calls to an option. """ + #pylint: disable=too-few-public-methods + def __init__(self, *args, **kwargs): + super(PM3StoreOnceAction, self).__init__(*args, **kwargs) def __call__(self, parser, namespace, values, option_string=None): if getattr(namespace, self.dest, None) is not None: raise argparse.ArgumentError(self, 'may only be used once.') @@ -281,7 +285,7 @@ class PM3ArgumentParser(argparse.ArgumentParser): """ Actually add alignment arguments/ options """ - aln_grp = self.add_mutually_exclusive_group() + aln_grp = self.add_mutually_exclusive_group(required=True) # FastA input: - always pairwise alignments # - callable multiple times # - goes by 'trg:<SEQNAME> <FILE>' @@ -301,7 +305,6 @@ class PM3ArgumentParser(argparse.ArgumentParser): aln_grp.add_argument('-j', '--json', metavar='<OBJECT>|<FILE>', help='Alignments provided as JSON file/ object.', action=PM3StoreOnceAction) - # possibility to add JSON: mention limitation! class PM3OptionsNamespace(object): """ @@ -332,6 +335,9 @@ class PM3OptionsNamespace(object): seqfile, new_aln = _FetchAlnFromFastaOpt(src) self.alignments.append(new_aln) self.aln_sources.append(seqfile) + return + # Now for JSON input. Since one of the options needs to be given and + # we already checked for FastA, no need to open a new branch, here. # LocalWords: param attr prog argparse ArgumentParser bool sys os init str # LocalWords: progattr descattr argpinit argv formatter meth args namespace diff --git a/core/tests/test_pm3argparse.py b/core/tests/test_pm3argparse.py index 271dfc26..7a5943ea 100644 --- a/core/tests/test_pm3argparse.py +++ b/core/tests/test_pm3argparse.py @@ -38,6 +38,7 @@ class PM3ArgParseTests(unittest.TestCase): with self.assertRaises(SystemExit) as ecd: parser.Parse(['-x']) self.assertEqual(ecd.exception.code, 2) + self.assertEqual(len(self.log.messages['ERROR']), 2) self.assertEqual(self.log.messages['ERROR'], ['usage: test_pm3argparse.py [-h]', 'test_pm3argparse.py: error: unrecognized '+ @@ -85,9 +86,10 @@ class PM3ArgParseTests(unittest.TestCase): with self.assertRaises(SystemExit) as ecd: parser.Parse(['--fasta', 'data/fasta/alignment.fas']) self.assertEqual(ecd.exception.code, 2) + self.assertEqual(len(self.log.messages['ERROR']), 2) self.assertEqual(self.log.messages['ERROR'], - ['usage: test_pm3argparse.py [-h] [-f trg:<NAME> '+ - '<FILE> | -j <OBJECT>|<FILE>]', + ['usage: test_pm3argparse.py [-h] (-f trg:<NAME> '+ + '<FILE> | -j <OBJECT>|<FILE>)', 'test_pm3argparse.py: error: argument -f/--fasta: '+ 'expected 2 argument(s)']) @@ -99,9 +101,10 @@ class PM3ArgParseTests(unittest.TestCase): with self.assertRaises(SystemExit) as ecd: parser.Parse(['--fasta', 'trg:target']) self.assertEqual(ecd.exception.code, 2) + self.assertEqual(len(self.log.messages['ERROR']), 2) self.assertEqual(self.log.messages['ERROR'], - ['usage: test_pm3argparse.py [-h] [-f trg:<NAME> '+ - '<FILE> | -j <OBJECT>|<FILE>]', + ['usage: test_pm3argparse.py [-h] (-f trg:<NAME> '+ + '<FILE> | -j <OBJECT>|<FILE>)', 'test_pm3argparse.py: error: argument -f/--fasta: '+ 'expected 2 argument(s)']) @@ -114,6 +117,7 @@ class PM3ArgParseTests(unittest.TestCase): with self.assertRaises(SystemExit) as ecd: parser.Parse(['--fasta', 'foo', 'bar']) self.assertEqual(ecd.exception.code, 11) + self.assertEqual(len(self.log.messages['ERROR']), 1) self.assertEqual(self.log.messages['ERROR'][0], "'--fasta foo bar' requires one "+ "argument prefixed with 'trg:' marking the target "+ @@ -128,6 +132,7 @@ class PM3ArgParseTests(unittest.TestCase): with self.assertRaises(SystemExit) as ecd: parser.Parse(['--fasta', 'trg:', 'bar']) self.assertEqual(ecd.exception.code, 14) + self.assertEqual(len(self.log.messages['ERROR']), 1) self.assertEqual(self.log.messages['ERROR'][0], "'--fasta trg: bar' "+ "requires argument 'trg:' defining the target "+ "sequence name, empty one found: 'trg: bar'") @@ -141,6 +146,7 @@ class PM3ArgParseTests(unittest.TestCase): with self.assertRaises(SystemExit) as ecd: parser.Parse(['--fasta', 'bar', 'trg:']) self.assertEqual(ecd.exception.code, 14) + self.assertEqual(len(self.log.messages['ERROR']), 1) self.assertEqual(self.log.messages['ERROR'][0], "'--fasta bar trg:' "+ "requires argument 'trg:' defining the target "+ "sequence name, empty one found: 'bar trg:'") @@ -153,6 +159,7 @@ class PM3ArgParseTests(unittest.TestCase): with self.assertRaises(SystemExit) as ecd: parser.Parse(['--fasta', 'trg:foo', 'notexistingfile.fas']) self.assertEqual(ecd.exception.code, 12) + self.assertEqual(len(self.log.messages['ERROR']), 1) self.assertEqual(self.log.messages['ERROR'][0], "Alignment file does not exist: notexistingfile.fas") @@ -164,6 +171,7 @@ class PM3ArgParseTests(unittest.TestCase): with self.assertRaises(SystemExit) as ecd: parser.Parse(['--fasta', 'trg:foo', 'data/fasta/alignment.fas']) self.assertEqual(ecd.exception.code, 15) + self.assertEqual(len(self.log.messages['ERROR']), 1) self.assertEqual(self.log.messages['ERROR'][0], "'--fasta trg:foo data/fasta/alignment.fas' refers "+ "to an empty file or its in the wrong format.") @@ -175,6 +183,7 @@ class PM3ArgParseTests(unittest.TestCase): with self.assertRaises(SystemExit) as ecd: parser.Parse(['--fasta', 'trg:target', 'data/fasta/1ake_3.fas']) self.assertEqual(ecd.exception.code, 16) + self.assertEqual(len(self.log.messages['ERROR']), 1) self.assertEqual(self.log.messages['ERROR'][0], "'--fasta trg:target "+ "data/fasta/1ake_3.fas' points to an alignment with "+ "more than 2 sequences.") @@ -186,6 +195,7 @@ class PM3ArgParseTests(unittest.TestCase): with self.assertRaises(SystemExit) as ecd: parser.Parse(['--fasta', 'trg:trg', 'data/fasta/1ake.fas']) self.assertEqual(ecd.exception.code, 17) + self.assertEqual(len(self.log.messages['ERROR']), 1) self.assertEqual(self.log.messages['ERROR'][0], "'--fasta trg:trg "+ "data/fasta/1ake.fas' does not define a target name "+ "found in the alignment.") @@ -197,6 +207,7 @@ class PM3ArgParseTests(unittest.TestCase): with self.assertRaises(SystemExit) as ecd: parser.Parse(['--fasta', 'trg:target', 'data/fasta/1ake_nel.fas']) self.assertEqual(ecd.exception.code, 18) + self.assertEqual(len(self.log.messages['ERROR']), 1) self.assertEqual(self.log.messages['ERROR'][0], "'--fasta trg:target "+ "data/fasta/1ake_nel.fas': sequences in the "+ "alignment have different length.") @@ -274,18 +285,35 @@ class PM3ArgParseTests(unittest.TestCase): self.assertEqual(opts.alignments[0].GetSequence(1).name, '1AKE.B') self.assertEqual(opts.aln_sources[0], 'data/fasta/1ake.fas') + def testAddAlignmentNoneGiven(self): + # if we have none of '--fasta', '--json', fail. + parser = pm3argparse.PM3ArgumentParser(__doc__, action=False) + parser.AddAlignment() + parser.AssembleParser() + with self.assertRaises(SystemExit) as ecd: + parser.Parse([]) + self.assertEqual(ecd.exception.code, 2) + self.assertEqual(len(self.log.messages['ERROR']), 2) + self.assertEqual(len(self.log.messages['ERROR']), 2) + self.assertEqual(self.log.messages['ERROR'][0], + 'usage: test_pm3argparse.py [-h] (-f trg:<NAME> '+ + '<FILE> | -j <OBJECT>|<FILE>)', + 'test_pm3argparse.py: error: one of the arguments '+ + '-f/--fasta -j/--json is required') + def testAddAlignmentFastaAndJson(self): # testing that --fasta and --json DO NOT work together parser = pm3argparse.PM3ArgumentParser(__doc__, action=False) parser.AddAlignment() parser.AssembleParser() with self.assertRaises(SystemExit) as ecd: - opts = parser.Parse(['--fasta', 'trg:target', - 'data/fasta/1ake.fas', '--json', 'foo']) + parser.Parse(['--fasta', 'trg:target', 'data/fasta/1ake.fas', + '--json', 'foo']) self.assertEqual(ecd.exception.code, 2) + self.assertEqual(len(self.log.messages['ERROR']), 2) self.assertEqual(self.log.messages['ERROR'][0], - 'usage: test_pm3argparse.py [-h] [-f trg:<NAME> '+ - '<FILE> | -j <OBJECT>|<FILE>]', + 'usage: test_pm3argparse.py [-h] (-f trg:<NAME> '+ + '<FILE> | -j <OBJECT>|<FILE>)', 'test_pm3argparse.py: error: argument -j/--json: '+ 'not allowed with argument -f/--fasta') @@ -296,16 +324,15 @@ class PM3ArgParseTests(unittest.TestCase): parser.AddAlignment() parser.AssembleParser() with self.assertRaises(SystemExit) as ecd: - opts = parser.Parse(['--json', 'foo', '--json', 'bar']) + parser.Parse(['--json', 'foo', '--json', 'bar']) self.assertEqual(ecd.exception.code, 2) + self.assertEqual(len(self.log.messages['ERROR']), 2) self.assertEqual(self.log.messages['ERROR'][0], - 'usage: test_pm3argparse.py [-h] [-f trg:<NAME> '+ - '<FILE> | -j <OBJECT>|<FILE>]', + 'usage: test_pm3argparse.py [-h] (-f trg:<NAME> '+ + '<FILE> | -j <OBJECT>|<FILE>)', 'test_pm3argparse.py: error: argument -j/--json: '+ 'may only be used once.') -# test no multiple --json - if __name__ == "__main__": from ost import testutils testutils.RunTests() -- GitLab