11

I am using argparse to parse command line arguments and by default on receiving invalid arguments it prints help message and exit. Is it possible to customize the behavior of argparse when it receives invalid arguments?

Generally I want to catch all invalid arguments and do stuff with them. I am looking for something like:

parser = argparse.ArgumentParser()
# add some arguments here
try:
    parser.parse_args()
except InvalidArgvsError, iae:
    print "handle this invalid argument '{arg}' my way!".format(arg=iae.get_arg())

So that I can have:

>> python example.py --invalid some_text
handle this invalid argument 'invalid' my way!
6
  • It appears that you are already handling arguments your way: you printed the invalid argument in a message. What is the problem you have? Commented Jul 12, 2016 at 23:25
  • @Prune: There is no such thing as InvalidArgsError. The posted code does not actually work. Commented Jul 12, 2016 at 23:37
  • I realize that there is no such error; however, OP is posted successful output. I think I see the rhetoric problem; thanks. Commented Jul 12, 2016 at 23:39
  • 2
    @Prune OP only posted the desired output. Not actual output. Commented Jul 12, 2016 at 23:48
  • Yes, I think I can also see the rhetoric problem, and it has nothing to do with Mr Zhang. Commented Aug 30, 2016 at 11:22

4 Answers 4

4

You might want to use parse_known_args and then take a look at the second item in the tuple to see what arguments were not understood.

That said, I believe this will only help with extra arguments, not expected arguments that have invalid values.

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

1 Comment

This looks like the best option argparse provides.
3

Some previous questions:

Python argparse and controlling/overriding the exit status code

I want Python argparse to throw an exception rather than usage

and probably more.

The argparse documentation talks about using parse_known_args. This returns a list of arguments that it does not recognize. That's a handy way of dealing with one type of error.

It also talks about writing your own error and exit methods. That error that you don't like passes through those 2 methods. The proper way to change those is to subclass ArgumentParser, though you can monkey-patch an existing parser. The default versions are at the end of the argparse.py file, so you can study what they do.

A third option is to try/except the Systemexit.

try:
    parser=argparse.ArgumentParser()
    args=parser.parse_args()
except SystemExit:
    exc = sys.exc_info()[1]
    print(exc)

This way, error/exit still produce the error message (to sys.stderr) but you can block exit and go on and do other things.

1649:~/mypy$ python stack38340252.py -x
usage: stack38340252.py [-h]
stack38340252.py: error: unrecognized arguments: -x
2

One of the earlier question complained that parser.error does not get much information about the error; it just gets a formatted message:

def myerror(message):
    print('error message')
    print(message)

parser=argparse.ArgumentParser()
parser.error = myerror
args=parser.parse_args()

displays

1705:~/mypy$ python stack38340252.py -x
error message
unrecognized arguments: -x

You could parse that message to find out the -x is the unrecognized string. In an improvement over earlier versions it can list multiple arguments

1705:~/mypy$ python stack38340252.py foo -x abc -b
error message
unrecognized arguments: foo -x abc -b

Look up self.error to see all the cases that can trigger an error message. If you need more ideas, focus on a particular type of error.

===============

The unrecognized arguments error is produced by parse_args, which calls parse_known_args, and raises this error if the extras is not empty. So its special information is the list of strings that parse_known_args could not handle.

parse_known_args for its part calls self.error if it traps an ArgumentError. Generally those are produced when a specific argument (Action) has problems. But _parse_known_args calls self.error if required Action is missing, or if there's a mutually-exclusive-group error. choices can produce a different error, as can type.

Comments

1

You can try subclassing argparse.ArgumentParser() and overriding the error method.

From the argparse source:

def error(self, message):
        """error(message: string)

        Prints a usage message incorporating the message to stderr and
        exits.

        If you override this in a subclass, it should not return -- it
        should either exit or raise an exception.
        """
        self.print_usage(_sys.stderr)
        self.exit(2, _('%s: error: %s\n') % (self.prog, message))

3 Comments

That gets used for all sorts of other errors, though, and aside from the message string, it doesn't have access to much useful information for custom error handling.
@user2357112 yeah that's true but other alternative is to override either parse_args()/parse_known)_args() itself or meddle in all methods which isn't convenient at all.
I'm not aware of any serious attempts to rework the argparse error methods. The module defines a couple of rudimentary Error classes, but doesn't do much with them. ArgumentError just adds the argument name to the message.
0

Since the error code 2 is reserved for internal docker usage, I'm using the following to parse arguments in scripts inside docker containers:

ERROR_CODE = 1
class DockerArgumentParser(argparse.ArgumentParser):
    def error(self, message):
        """error(message: string)

    Prints a usage message incorporating the message to stderr and
    exits.

    If you override this in a subclass, it should not return -- it
    should either exit or raise an exception.

    Overrides error method of the parent class to exit with error code 1 since default value is
    reserved for internal docker usage
    """
    self.print_usage(sys.stderr)
    args = {'prog': self.prog, 'message': message}
    self.exit(ERROR_CODE, '%(prog)s: error: %(message)s\n' % args)

Comments

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.