1

See here for related discussion on the merits of the various option and arg parsing choices we have in Python.

I'm making a diff script that does neat things with the output of Python's difflib, and part of what that involves is handling the different ways that it can be called. For instance Git will send 7 args (the second and fifth being the files you want to diff) to the diff program you configure it with, and most differs are also expected to accept input as two file args. Interestingly, git's difftool's --extcmd= flag invokes the differ you specify with only the two args.

So, it's really easy to use OptionParser to do this since it just gives you a list of the args and I could grab the second and fifth ones and send them to fileinput.

I did notice the big banner on the pydoc that says it's deprecated, so I was looking at argparse.

It was not clear to me at all if it is even possible to configure argparse to let your program accept a series of positional arguments without an option to "start it off". That is what I needed since I can't change the way e.g. Git would invoke the differ.

Anyway, I ended up doing some really trivial manipulation of sys.argv, which after all is what I should have been doing to begin with in this particular situation.

if len(sys.argv) == 8:
 # assume this was passed to git; we can of course do
 # some parsing to check if we got valid git style args
 args = [sys.argv[2], sys.argv[5]]
elif len(sys.argv) == 3:
 args = sys.argv[:1]
else:
 sys.exit("Not a valid number of args (2 or 7) to this diff program")
print "Files: " + ' '.join(args)

How might one use argparse to implement a program that simply attempts to open and read all of its arguments?

The reasoning is that for argparse to deprecate parseopt it must be possible to replicate all its functionality (within reason).

asked Jun 12, 2013 at 20:41
1
  • Please post the code you are using to manipulate sys.argv. Then maybe we could suggest how to do the same with argparse. Commented Jun 12, 2013 at 20:50

3 Answers 3

1

Just add an argument that has no dashes in front of it.

import argparse
parser = argparse.ArgumentParser()
# You can change nargs to '+' for at least one argument
parser.add_argument('positional', nargs=2) # Positionals have no dashes
parser.add_argument('second_positional', nargs=1) 
parser.add_arguemnt('--optional', '-o') # Optionals have dashes
args = parser.parse_args()
print args['positional'] # Your first two positional arguments
print args['second_positional'] # Second set
print args['optional'] # An optional argument
answered Jun 12, 2013 at 20:51
Sign up to request clarification or add additional context in comments.

2 Comments

How can I get it to accept either 2 or 7 args but to reject if you invoke it with say 5 args?
I would use a variable number of arguments (nargs='+') and then fail if len(args['positional']) not in (2, 7).
1

I just made this example that takes zero or more positional arguments:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('args', metavar='arg', type=str, nargs='*',
 help='zero or more positional arguments')
args = parser.parse_args()
print args.arguments
answered Jun 12, 2013 at 20:55

2 Comments

Ah, okay. I guess I gotta then do logic on args.arguments to see if it's got the right count.
If you need to do things like either have 2 or 7, but nothing else, that would seem to be the way to go.
0

You could define a custom Action for this, though its really not that different than post-processing args yourself unless you have many such arguments that would require this action:

import argparse
class TwoOrSeven(argparse.Action):
 def __call__(self, parser, namespace, values, option_string=None):
 if len(values) not in (2,7):
 raise argparse.ArgumentTypeError('Not a valid number of args (2 or 7)')
 try:
 values = values[2], values[5]
 except IndexError:
 values = values[0]
 setattr(namespace, self.dest, values)
parser = argparse.ArgumentParser()
parser.add_argument('args', metavar='arg', action=TwoOrSeven, nargs='+',
 help='Must be supplied 2 or 7 arguments')
args = parser.parse_args('1 2 3 4 5 6 7'.split())
print(args)
# Namespace(args=('3', '6'))
args = parser.parse_args('1 2'.split())
print(args)
# Namespace(args='1')
args = parser.parse_args('1 2 3 4 5 6'.split())
# argparse.ArgumentTypeError: Not a valid number of args (2 or 7)
answered Jun 12, 2013 at 21:07

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.