I'm very new to this module so please bear with me. I have the following code:
reader.py
import argparse
parent_parser = argparse.ArgumentParser(description="Read text files.")
parent_parser.add_argument('filename', help='TXT file', type=file, nargs='+')
parent_parser.add_argument('--verbose', '-v', action='store_true',
help="Verbosity on")
child_parser = parent_parser.add_subparsers(title="subcommand",
help="Subcommand help")
new_file_command = child_parser.add_parser('new', help="New text file")
edit_file_command = child_parser.add_parser('edit', help="Edit existing text file")
args = parent_parser.parse_args()
What I'm trying to achieve might not be the standard way of how parsers and unix command line utilities work. If that is true, please correct me as I'd like to have standardized app.
This is what I'm trying to achieve:
- if you run bare script with positional argument(s) like this:
python reader.py some.txt
I'd like to be able to just parse it and pass it to function that reads the text file, of course I want to accept optional argverbose
as well - if you run subcommand 'new' (
new_file_command
), I do not want to have positional argumentfilename
to be required, instead I want to pass a string and create new text file like this:python reader.py new another.txt
- if you run subcommand 'edit' (
edit_file_command
) I want to pass existing file in path and check for it (like you usetype=int
inadd_argument
) and then maybe pass it to function that opens editor, something like this:python reader.py edit some.txt
Again, I'm not sure if this is how command line apps/scripts are supposed to behave. I read the docs and looked at examples but it's still isn't clear to me how sub parsers work. I tried looking at Click module but that seems to me even more complicated.
Any help appreciated. Thanks!
So three sample calls are:
The easiest way to handle these is with one 'optional' positional, and one required one.
For your 3 samples, it should produce something like:
cmd
is an optional positional argument. If it is missing, the one string will be allocated tofilename
, andcmd
gets itsdefault
. It's easier to do this than trying make asubparsers
optional.As for your current parser:
I would not recommend using
type=file
. Better to useFileType
or the default string (which lets you open the file in awith context
later).As to the
nargs='+'
, do you really want to allocate1 or more
strings tofilename
? Or were you thinking of '?', which would be0 or 1
, i.e. making it optional?Mixing this
filename
positional which accepts a variable number of values, with a subparsers argument (a positional that expects eithernew
oredit
) could be a problem.I expect
'python reader.py some.txt'
to object that the subparser command is missing.'python reader.py new another.txt'
will try to allocatenew
tofilename
, andanother.txt
to subparser, and raise an error.It would be better to expect a subparsers command in all 3 cases:
Each of commands, 'open','new','edit', expects a 'filename'.
Trying to avoid the use of an
open
command is going to create more difficulties than it's worth.(There is a bug/feature in the latest argparse that makes subparsers optional, but you shouldn't take advantage of that without really knowing the issues.)
With:
I expect
reader.py new customstring
to givewhich could be used as:
open
andedit
would use differentopen
modes.Beware that in Py3,
subparsers
are not required. That is, if one of the subcommands is not provided, it won't raise an error. That's an inadvertent change from early versions.Argparse with required subparser