287

Optparse, the old version just ignores all unrecognised arguments and carries on. In most situations, this isn't ideal and was changed in argparse. But there are a few situations where you want to ignore any unrecognised arguments and parse the ones you've specified.

For example:

parser = argparse.ArgumentParser()
parser.add_argument('--foo', dest="foo")
parser.parse_args()

$python myscript.py --foo 1 --bar 2
error: unrecognized arguments: --bar

Is there anyway to overwrite this?

joedborg
  • 17,651
  • 32
  • 84
  • 118
  • 23
    Very handy if you're writing a wrapper to another program, and you want to capture and modify a few arguments, but pass the rest on! – Alan De Smet Jan 04 '17 at 03:55
  • 2
    Exactly why I ended up here @AlanDeSmet ! Glad I'm not trying to do something crazy :) – dwanderson Jan 17 '17 at 21:11

3 Answers3

508

Replace

args = parser.parse_args()

with

args, unknown = parser.parse_known_args()

For example,

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo')
args, unknown = parser.parse_known_args(['--foo', 'BAR', 'spam'])
print(args)
# Namespace(foo='BAR')
print(unknown)
# ['spam']
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • 31
    +1 - didn't knew there was some thing like `parse_known_args` – avasal Oct 10 '12 at 11:32
  • 10
    Nor did I! I even missed it in the docs http://docs.python.org/library/argparse.html?highlight=argparse#partial-parsing. Thanks – joedborg Oct 10 '12 at 14:11
  • 1
    This came up when trying to use nosetest with parseargs (it refused to allow nosetest args to be used) the reason was because I was doing `parser.parse_args(None)` rather than `parser.parse_args([])` in my tests. – Andy Hayden Apr 07 '14 at 06:30
  • 3
    FWIW, using `parse_known_args` rather than `parse_args` enables the use of `ArgumentParser` in code within the scope of `if __name__ == 'main':` (a condition that is `True` for all cells in an IPython Notebook ... which I find greatly aids the development and testing code that I want to eventually migrate to a script invoked from a command line) – gumption Jan 28 '15 at 16:48
  • Oops: s/main/__main__/ – gumption Jan 29 '15 at 16:07
  • 1
    This doesn't seem to work with optional args that are "known" not being passed in. – Sharud Feb 13 '17 at 22:52
  • Unfortunately `unknown` is simply array and there is no built-in way to convert to nice dictionary (as we don't know types). Alternative: https://stackoverflow.com/a/37367814/207661. – Shital Shah Nov 21 '19 at 09:42
  • Note that the `unknown` args can then be passed to another argparse instance, for example a [subparser](https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.add_subparsers). – yoyo Feb 03 '22 at 04:06
  • was able to work around a SystemExit condition with pytest -s -v with this solution – karl k Aug 01 '23 at 21:28
30

You can puts the remaining parts into a new argument with parser.add_argument('args', nargs=argparse.REMAINDER) if you want to use them.

lichenbo
  • 1,019
  • 11
  • 13
  • 1
    This works with `parse_args()` and doesn't require `parse_known_args()` (on Python 2.7). – OozeMeister May 03 '17 at 18:04
  • 4
    Using argparse.REMAINDER seems to be fraught with long-standing bugs. I certainly can't get it to work. parse_known_args() is a good alternative. – Matt Jun 13 '17 at 16:07
  • 1
    Just ran into a long-standing REMAINDER bug today: https://bugs.python.org/issue17050 – Scott Carpenter Feb 18 '18 at 15:50
10

Actually argparse does still "ignore" _unrecognized_args. As long as these "unrecognized" arguments don't use the default prefix you will hear no complaints from the parser.

Using @anutbu's configuration but with the standard parse.parse_args(), if we were to execute our program with the following arguments.

$ program --foo BAR a b +cd e

We will have this Namespaced data collection to work with.

Namespace(_unrecognized_args=['a', 'b', '+cd', 'e'], foo='BAR')

If we wanted the default prefix - ignored we could change the ArgumentParser and decide we are going to use a + for our "recognized" arguments instead.

parser = argparse.ArgumentParser(prefix_chars='+')
parser.add_argument('+cd')

The same command will produce

Namespace(_unrecognized_args=['--foo', 'BAR', 'a', 'b'], cd='e')

Put that in your pipe and smoke it =)

nJoy!

nickl-
  • 8,417
  • 4
  • 42
  • 56