5

Consider the following usage:

usage: do.py [-h] [-s | -m] filename

This is not the complete usage. But I effectively want is filename to be an actual value of file and not:

--filename FILENAME

But also, filename should be optional so I can read from the standard input. Think about the cat program on UNIX.

You simply say:

cat filename

OR

cat

EDIT: Right now, if I execute the program do.py without any command line options, I will get an error: too few arguments. Instead I would still want it to execute even if I don't give it a valid filename. How do I do that?

3
  • 1
    These are nice-looking, if a little light, specifications. What is the question? Please edit the body of your post to include your attempt at a solution, and folks will point you in the right direction. Thank you. Commented Feb 13, 2013 at 0:17
  • Right now if I execute the program do.py without any command line options, I will get an error: too few arguments. Instead I would still want it to execute even I don't have a filename. Commented Feb 13, 2013 at 0:19
  • required=False doesn't work for positionals. Commented Feb 13, 2013 at 0:25

1 Answer 1

8

Update 2: From the ArgParse documentation,

One of the more common uses of nargs='?' is to allow optional input and output files:

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('infile', nargs='?', type=argparse.FileType('r'),
...                     default=sys.stdin)
>>> parser.add_argument('outfile', nargs='?', type=argparse.FileType('w'),
...                     default=sys.stdout)
>>> parser.parse_args(['input.txt', 'output.txt'])
Namespace(infile=<open file 'input.txt', mode 'r' at 0x...>,
          outfile=<open file 'output.txt', mode 'w' at 0x...>)
>>> parser.parse_args([])
Namespace(infile=<open file '<stdin>', mode 'r' at 0x...>,
          outfile=<open file '<stdout>', mode 'w' at 0x...>)

Original answer:

This is straightforward: just add a positional argument with a default value and a nargs='*'. The default value will be used if there are zero arguments, otherwise the arguments on the command line will be used:

>>> p = argparse.ArgumentParser()
>>> p.add_argument('filename', nargs='*', default=['-'])
>>> p.parse_args([])
Namespace(filename=['-'])
>>> p.parse_args(['abc'])
Namespace(filename=['abc'])

Typically, - is used to refer to standard input / standard output.

Then you do something like this:

def get_inputs(ns):
    """Iterate over input files."""
    for path in ns.filename:
        if path == '-':
            yield sys.stdin
        else:
            yield open(path, 'r')

Update: I assumed you wanted multiple filenames, since cat takes multiple filenames. You can use nargs='?' if you want either zero or one filename.

Sign up to request clarification or add additional context in comments.

5 Comments

That is correct sir. I actually used the nargs option seeing it in the documentation. What I don't want is the user to see this: usage: do.py [-h] [-s | -m] [filename [filename ...]] He should only really see that filename is optional and is only a single value is possible for that.
that would be nargs='?' for zero or one positional; see docs.python.org/dev/library/argparse.html#nargs
@flippex17: I'm having a hard time believing you when you say you saw the nargs option in the documentation... because you would surely see '?' if you had been looking at the documentation...
Oh great. Thanks. That's fine Dietrich. I did see the documentation. I did try '*' but it didn't strike me to use '?' which is terribly unfortunate. Thank you.
Also, I was looking at 2.7.3. So really sorry about that. Thank you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.