Help with the argparse library

Asked

Viewed 581 times

2

I’m trying to use the library argparse to guide the main module (__main__) between two possible executions:

import unittest
import argparse


arg = argparse.ArgumentParser(description='Execution type')
arg.add_argument('--type', action='store', dest='argument', type=int, default=0,
                 required=False, help='Chose the execution type (0=application, 1=unittest)')

options = arg.parse_args()


def main():
    pass


def run_tests():

    from tests import tests_models, tests_dbconnections, tests_dals

    suit = unittest.TestSuite()
    suit.addTest(unittest.makeSuite(tests_models.TestPerson))
    suit.addTest(unittest.makeSuite(tests_models.TestClient))
    suit.addTest(unittest.makeSuite(tests_dbconnections.TestPgSqlConnection))
    suit.addTest(unittest.makeSuite(tests_dals.TestPgSqlDal))

    return suit

if __name__ == '__main__':
    if options.argument:
        unittest.main(defaultTest='run_tests', verbosity=2)
    else:
        main()

But when executing: python3 start.py --type 1

I get an error stating that the argument --type is not recognized: usage: start.py [-h] [-v] [-q] [--locals] [-f] [-c] [-b] [tests [tests ...]] start.py: error: unrecognized arguments: --type

1 answer

1


This happens when the unittest takes control, it will interpret the command line options again. --type is a valid argument for the main application, not for the unittest.

You have to separate the command line options from the unittest and the main application. One way to do this is to use argparse.parse_known_args() instead of argparse.parse_args(), see:

(Documentation)

Sometimes a script can only parse some of the command line arguments, passing the remaining arguments to another script or program.

In such cases, the method parse_known_args() can be useful. It works as parse_args() except that it does not produce an error when arguments extras are present. Instead, it returns a tuple of two items containing the namespace populated and the list of remaining arguments.

Code:

import argparse, unittest, sys

parser = argparse.ArgumentParser(description = 'Execution type')
parser.add_argument('--test', action = 'store_true',
                              help = 'Executar o unittest')

options, args = parser.parse_known_args()

def main():
    pass

def run_tests():
    from tests import tests_models, tests_dbconnections, tests_dals

    suit = unittest.TestSuite()
    suit.addTest(unittest.makeSuite(tests_models.TestPerson))
    suit.addTest(unittest.makeSuite(tests_models.TestClient))
    suit.addTest(unittest.makeSuite(tests_dbconnections.TestPgSqlConnection))
    suit.addTest(unittest.makeSuite(tests_dals.TestPgSqlDal))

    return suit

if __name__ == '__main__':
    if options.test:
        sys.argv[1:] = args
        unittest.main(defaultTest = 'run_tests', verbosity = 2)
    else:
        main()

To call the unittest do:

python3 nomedoScript.py --test

To run the main application call the script unencumbered:

python3 nomedoScript.py
  • I have tested with the modifications you made. The error doesn’t really happen anymore, but the test function is never called. The path always followed is the function main, even if we don’t pass anything as a parameter: python3 start.py.&#Another thing that did not please me was the use of sys.argv. sys.argv is already in itself an (archaic?) way of receiving command line parameters. Thus dispensing with the use of argparse. I think the error is not related to unittest. Comment line unittest.main(main(defaultTest = 'run_tests', verbosity = 2)) and you will see that the error still persists.

  • Correct! the Error was mine, I was passing the wrong parameter at the time of executing (passing --test instead of --type). By calling python3 start.py --type 1 the function main is called. 1º But when calling without passing anything python3 start.py --type it claims the missing parameter: usage: start.py [-h] [--type ARGUMENT]
start.py: error: argument --type: expected one argument It seems that the default=0 is not fulfilling its role. 2º There is no way to solve the unittest problem without using sys.argv? I don’t like him for the reasons I’ve already mentioned.

  • It doesn’t work, he keeps complaining about the lack of value.

  • @Matheussaraiva Here it works for me, see if your code looks like this one: http://pastebin.com/Cd4XkUnp

  • Exactly the same, it was pure copy and Paste.

  • ok, it’s me running wrong again. To use the default parameter you don’t have to pass anything: python3 start.py. The --type argument is only required if you want to pass some value.

  • Analyzing now the final result, this is not the most suitable format for my case. Ideally, if it is executed cleanly python3 start.py the application is executed, and if the argument --test is passed (only the argument with no value at all) python3 start.py --test tests will be executed.

  • @Matheussaraiva I updated the answer, see if that’s it.

Show 4 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.