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.
todotwice?./todowould be the command name if the file was calledtodoinstead oftodo.pyand it was placed in the current directory and marked as executable;python todo.pyis an equivalent command to run the script in the filetodo.pyexplicitly using thepythoninterpreter.