Reputation: 53
I am working on a command-line project where I get some problem in the handling of the add
subcommand, as indicated with comments below:
import argparse
import sys
def todo(args):
if args.o =='add':
print("Added Todo: "+args.x)
f=open("todo.txt", "a+")
c= str(count+1)
p= '\n'+'. '+args.x
f.write(p)
f.close()
elif args.o =='report':
return
elif args.o =='del NUMBER':
return
elif args.o =='done NUMBER':
return
elif args.o =='help':
print ("Usage :-"+
"\n"+'$ ./todo add "todo item" # add a new todo'+
"\n"+'$ ./todo ls # Show remaining todos'+
"\n"+'$ ./todo del NUMBER # delete a todo'+
"\n"+'$ ./todo done NUMBER # complete a todo'+
"\n"+'$ ./todo help # Show Usage'+
"\n"+'$ ./todo report # Statistics')
elif args.o =='ls':
f=open("todo.txt", "r")
print(f.read())
f.close()
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('./todo', type=str, default="./todo")
parser.add_argument('o', type=str, default="add")
args = parser.parse_args()
if args.o =='add': # <- starting here
parser.add_argument('x', type=str, default=None)
args = parser.parse_args()
sys.stdout.write(str(todo(args))) # <- ending here
else:
a = parser.parse_args()
sys.stdout.write(str(todo(args)))
When I run this script in Powershell I get some error like
PS E:\python projects\fellowship challenge\python> python todo.py ./todo add " I am soham Das Biswas"
usage: todo.py [-h] ./todo o
todo.py: error: unrecognized arguments: I am soham Das Biswas
How can I fix this?
Upvotes: 0
Views: 909
Reputation: 231385
With
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('./todo', type=str, default="./todo")
parser.add_argument('o', type=str, default="add")
args = parser.parse_args()
print(args)
some sample runs:
1301:~/mypy$ python3 stack65328753.py -h
usage: stack65328753.py [-h] ./todo o
positional arguments:
./todo
o
optional arguments:
-h, --help show this help message and exit
With 2 strings:
1303:~/mypy$ python3 stack65328753.py todo add
Namespace(o='add', **{'./todo': 'todo'})
with an extra:
1304:~/mypy$ python3 stack65328753.py todo add "extra string"
usage: stack65328753.py [-h] ./todo o
stack65328753.py: error: unrecognized arguments: extra string
This defines 2 arguments, both positionals
. They are identified by position, not any sort of 'flag' string. The first string is assigned to the "./todo" attribute of args
, and the second to "o". There's nothing to take a third string.
You can access the second value with args.o
, but args../todo
does not work. Instead you'd have to getattr(args, "./todo")
. So using an "fancy" name like that is usually not a good idea.
Since these are required positionals, there's no point to specifying a default
.
Change the arguments to optionals
:
parser = argparse.ArgumentParser()
parser.add_argument("--dir", default="./todo")
parser.add_argument('-o', type=str, default="add")
args = parser.parse_args()
print(args)
print(args.dir, args.o)
and runs:
1315:~/mypy$ python3 stack65328753.py -h
usage: stack65328753.py [-h] [--dir DIR] [-o O]
optional arguments:
-h, --help show this help message and exit
--dir DIR
-o O
1316:~/mypy$ python3 stack65328753.py
Namespace(dir='./todo', o='add')
./todo add
1316:~/mypy$ python3 stack65328753.py --dir ./mydir
Namespace(dir='./mydir', o='add')
./mydir add
1316:~/mypy$ python3 stack65328753.py --dir ./mydir -o subtract
Namespace(dir='./mydir', o='subtract')
./mydir subtract
1316:~/mypy$ python3 stack65328753.py --dir ./mydir -o "an extra string"
Namespace(dir='./mydir', o='an extra string')
./mydir an extra string
You try to add a "x" argument based on the args.o
value
args = parser.parse_args()
if args.o =='add': # <- starting here
parser.add_argument('x', type=str, default=None)
args = parser.parse_args()
But the first parse_args()
is the one that raises the unrecognized error and exits. So you never go on to this addition.
parser = argparse.ArgumentParser()
parser.add_argument("--dir", default="./todo")
parser.add_argument('-o', type=str, default="add")
args, extras = parser.parse_known_args()
print(args, extras)
print(args.dir, args.o)
if args.o == "add":
parser.add_argument('x')
args = parser.parse_args()
print(args)
The help isn't changed, because it's the first parse
that acts on that:
1318:~/mypy$ python3 stack65328753.py -h
usage: stack65328753.py [-h] [--dir DIR] [-o O]
optional arguments:
-h, --help show this help message and exit
--dir DIR
-o O
1323:~/mypy$ python3 stack65328753.py --dir ./mydir -o "an extra string"
Namespace(dir='./mydir', o='an extra string') []
./mydir an extra string
The parse_known_args
puts the extra string in the extras
. Now it goes on to add the x
argument:
1323:~/mypy$ python3 stack65328753.py --dir ./mydir -o add "an extra string"
Namespace(dir='./mydir', o='add') ['an extra string']
./mydir add
Namespace(dir='./mydir', o='add', x='an extra string')
An alternative would be just to
args.x = extras
which will be (possibly empty) list.
With a problem like this, I strongly advise using that print(args)
to see what parser does. And debug the parser before embedding it in a larger script. And for a start don't try to be too fancy. Use optionals
for things that are optional, not required, and positionals
for required things. There are ways of changing that, but it makes the inputs harder to understand, both for you and your users.
Upvotes: 1
Reputation: 1705
You may be misunderstanding how to define the arguments. You are probably assuming that you can use arguments in your example as positional arguments in a function call but that's not how argument parser works. Here is what happens in your example
python todo.py ./todo add " I am soham Das Biswas"
You defined two parameters: "./todo" and "o". The part ./todo add
assigns the value of add
to the ./todo
argument.
The " I am soham Das Biswas" does not get assigned to "o" because you do not have "o" mentioned in the call. If you want to assign something to "o", you need something like o value_i_want_to_assign
.
What do you want your code to do?
Upvotes: 0