I am trying to use mypy for type annotation. I wrote a simple test.py
import argparse
args = None
parser = argparse.ArgumentParser()
parser.add_argument('--dev', '-d', action='store_true', required=False)
args = parser.parse_args()
args.dev = True
After I ran mypy test.py, I got an error:
test.py:8: error: "Namespace" has no attribute "dev"
My assumption is that attritubes of Namespace class is dynamically created so they cannot be detected by mypy? I am able to get ride of this error message after replacing the last line with setattr(args, 'dev', True) but this does not look right... Can someone help me understand this problem? I am using Python 3.6.1.
Related
test1.py:
_argParserObj = argparse.ArgumentParser()
_argParserObj.add_argument('--tool', type=str, dest='tool')
parsedArgs, passthroughs = _argParserObj.parse_known_args()
When test1.py is executed as below
test1.py --tool abc arg1 arg2 --invalid_switch
I would like to show the below error.
But still accept arg1 and arg2 as extra arguments
test1.py: error: unrecognized arguments: -invalid_switch
Currently it just parses invalid_switch also a passthrough and throw any error.
Can anyone please suggest how to achieve this?
You can try parse_args() instead of parse_known_args()
_argParserObj = argparse.ArgumentParser()
_argParserObj.add_argument('--tool', type=str, dest='tool')
parsedArgs, passthroughs = _argParserObj.parse_args()
parse_args() will show this error in your case
test.py: error: unrecognized arguments: --invalid_switch
I have a script saved as workspace.py
import argparse
import os
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('title', type=str, help="Will be displayed as the title")
parser.add_argument('-f', '--folder', help='Point to the folder you want to read from (defaults to current folder in command prompt)', type=str, default=os.getcwd())
args = parser.parse_args()
print(args)
someFunction(args.folder, args.title)
Which I call from terminal with:
workspace.py myTitle
Resulting in the error
workspace.py: error: the following arguments are required: title
I have no idea why this is happening because I supply "myTitle" in the terminal. If I specify a default= for the title argument it works perfectly with that value. The part that is throwing me is it doesn't even get to the print(args) so I cannot see what the program thinks is what, but instead fails at args = parser.parse_args()
I tried to even redo the exact example at: https://docs.python.org/2/howto/argparse.html#introducing-positional-arguments (copied below)
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("echo", help="echo the string you use here")
args = parser.parse_args()
print args.echo
Running
workspace.py hello
Results in (after adding parenthesis to the print for 3.X)
workspace.py: error: the following arguments are required: echo
Is there something I'm missing? Why does it not just print "hello"? Is there some Python 3 specific syntax I'm missing or something?
I've gotten it to work if I run python workspace.py someString instead of workspace.py someString. I do not understand why this version works, since command prompt obviously recognizes it as Python and runs it correctly until args = parser.parse_args(). There were no errors like 'workspace.py' is not recognized as an internal or external command, operable program or batch file. There was no problem importing modules either. Consider the below command prompt session if you are running into a similar error. Maybe you will simply have to include python in your commands like I have to...
C:\Users\rparkhurst\PycharmProjects\Workspace>workspace.py MyTitle
usage: workspace.py [-h] [-f FOLDER] title
workspace.py: error: the following arguments are required: title
C:\Users\rparkhurst\PycharmProjects\Workspace>python workspace.py MyTitle
Namespace(folder='C:\\Users\\rparkhurst\\PycharmProjects\\Workspace', title='MyTitle')
Intro
I'm trouble for a school project. I'm making a testsuit and i'm needing bot a configuration generation interface and a test runner. For that i used the library argparse and two subparsers cgi and run
The issue itself
So here is the failing code section:
def CGI(args):
print("CGI: Work In Progress")
exit(0)
def runTest(args):
print("Run: Work in Progress")
exit(0)
parser = argparse.ArgumentParser()
subparser = parser.add_subparsers()
cgi = subparser.add_parser("cgi", help="CSV Generator Interface")
run = subparser.add_parser("run", help="Test running")
verbosity = parser.add_argument_group("Verbosity").add_mutually_exclusive_group()
check = run.add_argument_group("Checks")
# Arguments
#Run parser
run.set_defaults(func=runTest)
# Run argument declaration ...
# Verbosity argument declaration ...
# Check argument declaration ...
#CGI
cgi.set_defaults(func=CGI)
args = parser.parse_args()
args.func(args) # Error is here
Whenever i run this code i have the following error:
File "/home/thor/Projects/EPITA/TC/test/test.py", line 44, in main
args.func(args)
AttributeError: 'Namespace' object has no attribute 'func'
Python version
$ python -V
Python 3.6.4
Argparse version
$ pip show argparse
Name: argparse
Version: 1.4.0
Summary: Python command-line parsing library
Home-page: https://github.com/ThomasWaldmann/argparse/
Author: Thomas Waldmann
Author-email: tw#waldmann-edv.de
License: Python Software Foundation License
Location: /usr/lib/python3.6/site-packages
Requires:
EDIT
If i install argparse manually it work sudo pip install argparse. But is there any native solution. I'm not sure it will work on school's computers (we can' install packages)
EDIT 2
OK my bad i've been a total idiot i didn't rewrited my running script so i forgot to input run or cgi
Thanks for reading my message and for your future help :)
This is a known bug in the Python 3 version of argparse (https://bugs.python.org/issue16308). In Python 2, if the script is called with no arguments whatsoever (i.e., no subcommand), it exits cleanly with "error: too few arguments". In Python3, however, you get an unhandled AttributeError. Luckily, the workaround is pretty straightforward:
try:
func = args.func
except AttributeError:
parser.error("too few arguments")
func(args)
parser = ArgumentParser()
parser.set_defaults(func=lambda args: parser.print_help())
imho better than try..except
Another solution could be:
if len(args.__dict__) <= 1:
# No arguments or subcommands were given.
parser.print_help()
parser.exit()
You would have to make subparsers required to call the script without arguments. To do that, you have to specify the dest and required arguments for the parser.add_subparsers:
parser = argparse.ArgumentParser()
subparser = parser.add_subparsers(dest='cmd', required=True)
Note that for Python 3.6 and earlier there's no required argument and you have to set it explicitly for the subparser object:
subparser.required = True
Details are available in this SO answer: Argparse with required subparser
Or, a combination of #simleo and #nehaljwani's answers:
# Parse the arguments and call the sub command
args = parser.parse_args()
try:
args.func(args)
except AttributeError:
parser.print_help()
parser.exit()
This error only happened when you run 'python script.py' directly.
'python script.py --help' works fine.
Add
args = parser.parse_args()
try:
args.func(args)
except AttributeError:
parser.print_help()
parser.exit()
will help you handle this case of running 'python script.py' directly.
It resolved my issue, thanks very much!
I have this cmd line parsing stuf and I need to make "--clear" a valid unique parameter. However I'm getting an "Error: Too few arguments" when I only use "--clear" as an unique parameter.
parser = argparse.ArgumentParser(
prog="sl",
formatter_class=argparse.RawDescriptionHelpFormatter,
description="Shoot/Project launcher application",
epilog="")
parser.add_argument("project", metavar="projectname",
help="Name of the project/shot to use")
parser.add_argument("-p", metavar="project_name",
help="Name of the project")
parser.add_argument("-s", metavar="shot_name",
help="Name of the shot")
parser.add_argument("--clear",action='store_true',
help="Clear the information about the current selected project")
parser.add_argument("--test",
help="test parameter")
args=parser.parse_args()
Any ideas? Thanks
Update:
Trying to answer some questions of the comments.
When I launch the app like:
sl project
it works fine.
But if I launch it like:
sl --clear
I got a simple "sl: error: too few arguments"
The --clear argument is not the problem here; project is a required argument.
If you should be able to call your program without naming a project, make project optional by adding nargs='?':
parser.add_argument("project", metavar="projectname",
help="Name of the project/shot to use", nargs='?')
If it is an error to not specify a project name when other command-line switches are used, do so explicitly after parsing:
args = parser.parse_args()
if not args.clear and args.project is None:
parser.error('Please provide a project')
Calling parser.error() prints the error message, the help text and exits with return code 2:
$ python main.py --clear
Namespace(clear=True, p=None, project=None, s=None, test=None)
$ python main.py
usage: sl [-h] [-p project_name] [-s shot_name] [--clear] [--test TEST]
[projectname]
sl: error: Please provide a project
Add default values for each argument (--clear is no exception)
With python's argparse, how do I make a subcommand a required argument? I want to do this because I want argparse to error out if a subcommand is not specified. I override the error method to print help instead. I have 3-deep nested subcommands, so it's not a matter of simply handling zero arguments at the top level.
In the following example, if this is called like so, I get:
$./simple.py
$
What I want it to do instead is for argparse to complain that the required subcommand was not specified:
import argparse
class MyArgumentParser(argparse.ArgumentParser):
def error(self, message):
self.print_help(sys.stderr)
self.exit(0, '%s: error: %s\n' % (self.prog, message))
def main():
parser = MyArgumentParser(description='Simple example')
subs = parser.add_subparsers()
sub_one = subs.add_parser('one', help='does something')
sub_two = subs.add_parser('two', help='does something else')
parser.parse_args()
if __name__ == '__main__':
main()
There was a change in 3.3 in the error message for required arguments, and subcommands got lost in the dust.
http://bugs.python.org/issue9253#msg186387
There I suggest this work around, setting the required attribute after the subparsers is defined.
parser = ArgumentParser(prog='test')
subparsers = parser.add_subparsers()
subparsers.required = True
subparsers.dest = 'command'
subparser = subparsers.add_parser("foo", help="run foo")
parser.parse_args()
update
A related pull-request: https://github.com/python/cpython/pull/3027
In addition to hpaulj's answer: you can also use the required keyword argument with ArgumentParser.add_subparsers() since Python 3.7. You also need to pass dest as argument. Otherwise you will get an error: TypeError: sequence item 0: expected str instance, NoneType found.
Example file example.py:
import argparse
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='command', required=True)
foo_parser = subparsers.add_parser("foo", help="command foo")
args = parser.parse_args()
Output of the call without an argument:
$ python example.py
usage: example.py [-h] {foo} ...
example.py: error: the following arguments are required: command
How about using required=True? More info here.
You can use the dest argument, which is documented in the last example in the documentation for add_subparsers():
# required_subparser.py
import argparse
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subparser_name')
one = subparsers.add_parser('one')
two = subparsers.add_parser('two')
args = parser.parse_args()
Running with Python 2.7:
$python required_subparser.py
usage: required_subparser.py [-h] {one,two} ...
required_subparser.py: error: too few arguments
$python required_subparser.py one
$# no error