15

I have a main function specified as entry point in my package's setup.py which uses the argparse package in order to pass command line arguments (see discussion here):

# file with main routine specified as entry point in setup.py
import argparse
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('a', type=str, help='mandatory argument a')
    args = parser.parse_args()

Ideally, I would like to use the same main function in the package's tests as suggested here. In the latter context, I would like to call the main function from within the test class and set (some of) the command line arguments prior to the function call (which otherwise will fail, due to missing arguments).

# file in the tests folder calling the above main function
class TestConsole(TestCase):
    def test_basic(self):
        set_value_of_a()
        main()

Is that possible?

2
  • Why don't you add kwargs to main and only if they're None, you set them to the parse_args? Commented Oct 4, 2016 at 13:19
  • @William Fernandes Great, Thanks!!! Commented Oct 4, 2016 at 13:46

3 Answers 3

28

The argparse module actually reads input variables from special variable, which is called ARGV (short from ARGument Vector). This variable is usually accessed by reading sys.argv from sys module.

This variable is a ordinary list, so you can append your command-line parameters to it like this:

import sys
sys.argv.extend(['-a', SOME_VALUE])
main()

However, messing with sys.argv at runtime is not a good way of testing. A much more cleaner way to replace the sys.argv for some limited scope is using unittest.mock.patch context manager, like this:

with unittest.mock.patch('sys.argv'. ['-a', SOME_VALUE]):
    main()

Read more about unittest.mock.patch in documentation

Also, check this SO question:

How do I set sys.argv so I can unit test it?

Sign up to request clarification or add additional context in comments.

1 Comment

For whatever reason, from unittest.mock import patch with patch(...) worked, while import unittest with unittest.mock.patch(...) did not. In any case, this helped a lot.
1

@William Fernandes: Just for the sake of completeness, I'll post the full solution in the way that was suggested by (checking for an empty dict not kwargs is None):

def main(**kwargs):
    a = None
    if not kwargs:
        parser = argparse.ArgumentParser()
        parser.add_argument('a', type=str, help='mandatory argument a')
        args = parser.parse_args()
        a = args.a
    else:
        a = kwargs.get('a')

    print(a)

From within the test class the main function can then be called with arguments:

# file in the tests folder calling the above main function
class TestConsole(TestCase):
    def test_basic(self):
        main(a=42)

The call from the command line without kwargs then requires the specification of the command line argument a=....

Comments

0

Add kwargs to main and if they're None, you set them to the parse_args.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.