I have following code:
class WebuiSeleniumTest(unittest.TestCase):
def setup_parser(self):
parser = argparse.ArgumentParser(description='Automation Testing!')
parser.add_argument('-p', '--platform', help='Platform for desired_caps', default='Mac OS X 10.9')
parser.add_argument('-b', '--browser-name', help='Browser Name for desired_caps', default='chrome')
parser.add_argument('-v', '--version', default='')
return parser.parse_args()
def test_parser(self):
args = self.setup_parser()
print args
if __name__ == "__main__":
unittest.main()
When i try to run this in terminal with the command "python myfile.py -b firefox" I get AttributeError: 'module' object has no attribute 'firefox' and the help output is generated.
When I isolate it and run it without the if __name__ == "__main__" it works fine. Why does it try to apply my passed argument on unittest ? I need it as a String in my code.
Calling your script with python myfile.py -b firefox does indeed go to unittest, and not to your argument parser.
Unittest tries to parse the arguments you gave, e.g. if you call your script like this:
python myfile.py --help
You see the valid options:
Usage: myfile.py [options] [test] [...]
Options:
-h, --help Show this message
-v, --verbose Verbose output
-q, --quiet Minimal output
-f, --failfast Stop on first failure
-c, --catch Catch control-C and display results
-b, --buffer Buffer stdout and stderr during test runs
Examples:
parse.py - run default set of tests
parse.py MyTestSuite - run suite 'MyTestSuite'
parse.py MyTestCase.testSomething - run MyTestCase.testSomething
parse.py MyTestCase - run all 'test*' test methods
in MyTestCase
Looking at the help output -b would buffer (I guess suppress?) stdout/stderr. The argument firefox is taken as the name of the test to run in your module. And there is no function method existing, it outputs this error:
AttributeError: 'module' object has no attribute 'firefox'
Now, what you probably want to do is to call test_parser, and if you do that with python myfile.py WebuiSeleniumTest.test_parser then you cannot pass any additional arguments. And that's probably your question in the end. There is this question which gives some possible solutions for testing argparse as unit test.
Related
I am trying to make the function log into a command using the following code inside simple.py:
import click
#click.command()
#click.option('-v', '--verbose', count=True)
def log(verbose):
click.echo(f"Verbosity: {verbose}")
When I type the following on the command terminal:log -vvv , I get an error as : Command 'log' not found, but there are 16 similar ones.
#click.command should have converted the function log into a command? But, it doesn't work here. Could someone explain,please? Thanks!
I have tried the following commands:
log -vvv
Command 'log' not found, but there are 16 similar ones.
python3 simple.py log
Usage: simple.py [OPTIONS]
Try 'simple.py --help' for help.
Error: Got unexpected extra argument (log)
Could someone please explain what does #click.command() actually do and how's it different from running simple.py. The documentation does not make it very clear to me as well. Thanks!
import click
#click.command()
#click.option('-v', '--verbose', count=True)
def log(verbose):
click.echo(f"Verbosity: {verbose}")
if __name__ == '__main__':
log()
Then calling it like
$ python simple.py
Verbosity: 0
$ python simple.py -v
Verbosity: 1
The way you try to run it, suggest you think about command group, i.e. nesting commands
import click
#click.group()
def cli():
pass
#cli.command('log')
#click.option('-v', '--verbose', count=True)
def log(verbose):
click.echo(f"Verbosity: {verbose}")
#cli.command('greet')
def greet():
click.echo("Hello")
if __name__ == '__main__':
cli()
Then
$ python simple.py greet
Hello
$ python simple.py log -v -v # or just -vv
Verbosity: 2
Next step would be setuptools integration, etc.
I am currently creating a launcher (launcher.py) in Python 2.7 which can be used from GUI and terminal input. The launcher combines already eisting Software, that has its own GUI and its own terminal mode.
I added an OptionParser (option.py) to start the embedded tools (app.py) directly from the launcher.
App.py executes and is generating correct results, BUT terminal always throws following error:
Usage: launcher.py [options] arg1 arg2
launcher.py: error: no such option -i
here is the option.py file: (is imported as module to launcher.py)
def execute():
tapp_object = tapp.TALP()
input_file = sys.argv[sys.argv.index('-input') + 1]
tapp_object.run(gui=False, filename=input_file)
class Options(OptionParser):
usage = "Usage: %prog arg1 "
parser = OptionParser(usage=usage)
def tapp_batch(option, opt, value, parser):
p = mp.Process(target=execute)
p.start()
p.join()
parser.add_option('--tapp',
'--tAPPLICATION',
action="callback",
callback=tapp_batch,
help='''start APP from batch mode using:
-launcher.py --tapp -input filename.yml
add filename.yml file containing''' )
i tried to do an dirty fix, calling a 'pass' function for flag -i but then it throws the same error for -n -->
Usage: launcher.py [options] arg1 arg2
launcher.py: error: no such option -n
reading full -input string. Why ? and how do I fix it. Please help.
I have a simple python (v2.7) script (test.py)
#!/usr/bin/python
import sys
from optparse import OptionParser
def main():
parser = OptionParser()
parser.add_option("--files", dest="files",
metavar="FILES", default=None,
help="A file pattern matching ottcall logs.")
(options, args) = parser.parse_args()
print "FILES_PATTERN %s" % options.files
if not options.files:
parser.error("Files_pattern option is mandatory - Abort execution.")
return 0
if __name__ == "__main__":
sys.exit(main())
User must provide a file pattern or a filename
Run script in command line if option is missing returns error:
python test.py
FILES_PATTERN None
Usage: test.py [options]
test.py: error: Files_pattern option is mandatory - Abort execution.
If option files is missing some letters (--fil instead of --files):
python test.py --fil "a_pattern_for_files"
FILES_PATTERN a_pattern_for_files
I think I should have an error like the following
python test.py --fl "a_pattern_for_files"
Usage: test.py [options]
test.py: error: no such option: --fl
Why don't I get an error from OptionParser when I use --fil instead of the correct argument --files ?
Not only I do not get an error but variable files stores the value: a_pattern_for_files (which is printed).
I am expecting argument files to have value: None (default) unless in command line --files exists
optparse allows abbreviated forms of long options. --fil is a prefix of --files and not a prefix of any other long options the program supports, so --fil is treated as equivalent to --files.
This is barely mentioned in the docs, and there is no option to turn it off. argparse has an option to turn it off, but only in Python 3.5+.
I am trying to use argparse to create my script with parameters but I am not being able to.
The name of my script is pipeline and it has some options arguments like -b, -c, -i and -r.
If you call the script ./pipeline -b should give an error asking for a git repository path but I am not being able to do this.
from git import Repo
import os
import sys
import subprocess
import argparse
class Ci:
def build(self,args):
cloned_repo = Repo.clone_from(args)
print("clonning repository " + args)
cloned_repo
dir = git.split('/')(-1)
if os.path.isdir(dir):
print("repository cloned successfully")
else:
print("error to clone repository")
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-b','-build',action='store_true', help='execute mvn clean install')
parser.add_argument('-c','-compress',action='store_true',help='zip a directory recursively')
parser.add_argument('-i','-integration',action='store_true',help='execute mvn verify')
parser.add_argument('-r','-release',action='store_true',help='execute build,integration and compress respectively')
args = parser.parse_args()
if args.b:
a = Ci()
a.build()
if len(sys.argv) < 2:
parser.print_help()
sys.exit(1)
I can't make this sub-parameter work and I can't find a way to pass this parameter to my build function.
e.g:
./pipeline -b
Output: error missins git path
./pipeline -b https://git/repo
Output: clonning repo
and the string "https://git/repo" has to be passed as the argument to my build function:
How can I make it work?
first a note about convention: usually the longer option name is preceded by two hyphens like this '--build'
second, 'store_true' is the action you perform with '-b', which means argparse doesnt expect an argument after it, it just sets the args.build variable to True (and if the argument wasn't there it would set it to False)
try removing the action='store_true' and then it will default to storing the next value it finds in the argument list into args.build
Reducing your code to:
import argparse
class Ci:
def build(self,args):
print("clonning repository " + args)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-b','-build',action='store_true', help='execute mvn clean install')
parser.add_argument('-c','-compress',action='store_true',help='zip a directory recursively')
parser.add_argument('-i','-integration',action='store_true',help='execute mvn verify')
parser.add_argument('-r','-release',action='store_true',help='execute build,integration and compress respectively')
args = parser.parse_args()
print(args)
if args.b:
a = Ci()
a.build()
I get:
1313:~/mypy$ python3 stack49408644.py -b
Namespace(b=True, c=False, i=False, r=False)
Traceback (most recent call last):
File "stack49408644.py", line 22, in <module>
a.build()
TypeError: build() missing 1 required positional argument: 'args'
The parser runs fine, seeing args.b to True. But the call to build is wrong. It does not match the method's definition.
Providing a 'directory' doesn't help either, because -b is True/False
1313:~/mypy$ python3 stack49408644.py -b foo
usage: stack49408644.py [-h] [-b] [-c] [-i] [-r]
stack49408644.py: error: unrecognized arguments: foo
You need to either change -b to take an value, or add another argument that takes a value.
#AntiMatterDynamite showed how to change -b. Instead let's add:
parser.add_argument('adir', help='a directory for build')
and change the build call
a.build(args.adir)
Now the value is passed on to the method:
1322:~/mypy$ python3 stack49408644.py -b
usage: stack49408644.py [-h] [-b] [-c] [-i] [-r] adir
stack49408644.py: error: the following arguments are required: adir
1322:~/mypy$ python3 stack49408644.py -b foo
Namespace(adir='foo', b=True, c=False, i=False, r=False)
clonning repository foo
Instead redefining -b:
parser.add_argument('-b','-build', help='execute mvn clean install')
if args.b is not None:
a = Ci()
a.build(args.b)
test runs:
1322:~/mypy$ python3 stack49408644.py -b
usage: stack49408644.py [-h] [-b B] [-c] [-i] [-r]
stack49408644.py: error: argument -b/-build: expected one argument
1324:~/mypy$ python3 stack49408644.py -b foo
Namespace(b='foo', c=False, i=False, r=False)
clonning repository foo
So your parser needs to accept a value. And you need to pass that value on to your code. You seem to have read enough of the argparse docs to get things like print_help and store_true, but missed the simpler use of store (default) or positional. Were you trying to do something more sophisticated?
I agree with #hpaulj (why isn't an accepted answer?). I guess you found your problem, i.e., store_true does not take argument, then follow hpaulj indications.
In addition, I opened the question because of its title, I was expecting something different such as the following. I wanted to find a way to pass the argparse arguments to a function and possibly modify them with the function arguments. Here is the solution I wrote in case others come looking for this. It may need to be adjusted to account for positional arguments, I also highlight the possible use of vars(args) to get a dictionary from the argparse arguments to compare dict-to-dict with the args_dict:
def get_options(args_dict: dict):
""" get options from command-line,
update with function args_dict if needed """
args = get_cmd() # this is the function taking cmd-line arguments
for key, val in args_dict.items():
if not hasattr(args, key):
raise AttributeError('unrecognized option: ', key)
else:
setattr(args, key, val)
return(args)
I am creating a test case in python using unittest module.
I did create a parsing argument list that i want to get from user.
But when i use that argument while executing the python script, it gives error: "option -i not recognized
Usage: testing.py [options] [test] [...]"
code snippet:
class Testclass(unittest.TestCase):
#classmethod
def setUpClass(cls):
print "Hello Class"
def test_addnum(self):
print "Execute the test case"
#parser = parse_args(['-i'])
print 'simple_value =', args.inputfile
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument('-i', help='input file', dest='inputfile')
ns, args = parser.parse_known_args(namespace=unittest)
#args = parser.parse_args()
return ns, sys.argv[:1] + args
if __name__ == '__main__':
unittest.main()
The error m getting on executing the above script with -i somefile.txt is:
option -i not recognized
Usage: testing.py [options] [test] [...]
Options:
-h, --help Show this message
-v, --verbose Verbose output
-q, --quiet Minimal output
-f, --failfast Stop on first failure
-c, --catch Catch control-C and display results
-b, --buffer Buffer stdout and stderr during test runs
Examples:
testing.py - run default set of tests
testing.py MyTestSuite - run suite 'MyTestSuite'
testing.py MyTestCase.testSomething - run MyTestCase.testSomething
testing.py MyTestCase - run all 'test*' test methods
in MyTestCase
Any help would be appreciated.
This script captures the -i command, while still allowing unittest.main to do its own commandline parsing:
import unittest
class Testclass(unittest.TestCase):
#classmethod
def setUpClass(cls):
print "Hello Class"
def test_addnum(self):
print "Execute the test case"
#parser = parse_args(['-i'])
print 'simple_value =', args.inputfile
import argparse
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument('-i', help='input file', dest='inputfile')
ns, args = parser.parse_known_args(namespace=unittest)
#args = parser.parse_args()
return ns, sys.argv[:1] + args
if __name__ == '__main__':
import sys
args, argv = parse_args() # run this first
print(args, argv)
sys.argv[:] = argv # create cleans argv for main()
unittest.main()
produces:
1113:~/mypy$ python stack44236745.py -i testname -v
(<module 'unittest' from '/usr/lib/python2.7/unittest/__init__.pyc'>, ['stack44236745.py', '-v'])
Hello Class
test_addnum (__main__.Testclass) ... Execute the test case
simple_value = testname
ok
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
It looks rather kludgy, but does seem to work.
The idea is to run your own parser first, capturing the -i input, and putting the rest back into sys.argv. Your definition of parse_args suggests that you are already trying to do that.
Thanks hpaulj, your solution really helped me and I found one more solution for this problem. Hope it helps someone else facing the same issue.
import unittest
import argparse
import sys
class Testclass(unittest.TestCase):
#classmethod
def setUpClass(cls):
print "Hello Class"
def test_addnum(self):
print "Execute the test case"
#parser = parse_args(['-i'])
print 'simple_value =', args.inputfile
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-i', help='input file', dest='inputfile')
parser.add_argument('unittest_args', nargs='*')
args = parser.parse_args()
sys.argv[1:] = args.unittest_args
unittest.main()
Now executing the script with option -i as python testing.py -i somefile.txt gives result as
Hello Class
Execute the test case
simple_value = somefile.txt
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Your code is setting up your argument parser using
argparse.ArgumentParser()
parser.add_argument('-i', help='input file', dest='inputfile')
in a method of your test class. But I see no indication that the code is actually calling the method.
So at the time you start the program, the parser does not yet exist, because the method TestClass.parse_args() hasn't been called yet.
Move the creation of the parser and specification of its parameters out of the class so that the code calls it when the program starts.
You are running unittest.main() as the main program. So it's complaining rightfully that it does not know about the option you wrote:
"option -i not recognized"
If you want to create your own test suite launcher you should look into
TextTestRunner