1

From what I understand from another SO post, to unittest a script that takes command line arguments through argparse, I should do something like the code below, giving sys.argv[0] as arg.

import unittest
import match_loc

class test_method_main(unittest.TestCase):

    loc = match_loc.main()
    self.assertEqual(loc, [4])


if __name__ == '__main__':
    sys.argv[1] = 'aaaac'
    sys.argv[2] = 'ac'
    unittest.main(sys.argv[0])

This returns the error:

usage: test_match_loc.py [-h] text patterns [patterns ...]
test_match_loc.py: error: the following arguments are required: text, patterns

I would like to understand what is going on here deeper. I understand

if __name__ == '__main__': main()

says that if this is being executed by the 'main', highest level, default interpreter, to just automatically run the 'main' method. I'm assuming

if __name__ == '__main__': unittest.main()

just happens to be the way you say this for running unittest scripts.

I understand when any script is run, it automatically has an argv object, a vector collecting all the items on the command line.

But I do not understand what unittest.main(sys.arg[0]) would do. What does 'unittest.main' do with arguments? How can I pre-set the values of sys.argv - doesn't it automatically reset every time you run a script? Furthermore, where does this object 'sys.argv' exist, if outside of any script? Finally, what is the correct way to implement tests of command-line arguments?

I am sorry if my questions are vague and misguided. I would like to understand all the components relevant here so I can actually understand what I am doing.

Thank you very much.

jukhamil
  • 779
  • 2
  • 11
  • 18
  • Without knowin more about how you are using `argparse` in `test_match_loc.py` it's hard to help you. You may need to set `sys.argv` in that module, or call `parse_args` with a custom list of strings, as illustrated in many of the `argparse` documentation examples. Also look at `argparse`'s own unittest file. – hpaulj Sep 14 '15 at 19:40

1 Answers1

0

Just by playing around with a pair of simple files, I find that modifying sys.argv in the body of the caller module affects the sys.argv that the imported module sees:

import sys
sys.argv[1] = 'aaaac'
sys.argv[2] = 'ac'
class test_method_main(unittest.TestCase):
   ...

But modifying sys.argv in the main block as you do, does not show up in the imported one. We could dig into the documentation (and code) to see exactly why, but I think it's enough to just identify what works.

Here's what I reconstructed from your previous question of the imported module - with a few diagnostic prints

import argparse
import sys
def main():
    print(sys.argv)
    parser = argparse.ArgumentParser(
            description='Takes a series of patterns as fasta files'
            ' or strings and a text as fasta file or string and'
            ' returns the match locations by constructing a trie.')
    parser.add_argument('text')
    parser.add_argument('patterns', nargs='+')
    args = parser.parse_args()
    print(args)
    return 1

You could also test a parser with your own list of strings, recognising that parse_args uses sys.argv[1:] if its argument is missing or None:

def main(argv=None):
    print(argv)
    ...
    args = parser.parse_args(argv)
    print(args)
    return 1

loc = match_loc.main(['abc','ab'])  # and in the caller

Even though I was able to construct a working test case, you really should have given enough information that I didn't need to guess or dig around.

foxyblue
  • 2,859
  • 2
  • 21
  • 29
hpaulj
  • 221,503
  • 14
  • 230
  • 353
  • hi , I wanted to use same functionality.but getting IndexError: list assignment index out of range error while adding params in sys args. – Vish Oct 24 '18 at 16:13
  • @Vish, check the size of `sys.argv` before trying to add items. – hpaulj Oct 24 '18 at 17:16
  • yes ..one more thing if somebody want to add extra param ,it can be added like sys.argv.append("ert") – Vish Oct 25 '18 at 12:43