2

Is it possible to catch an error raised when a value's type is wrong with argparse (invalid value but the argument is recognised) in order to see what caused the error and eventually ignore it (continue with the parsing)?

I know that I can override the error method of the ArgumentParser, but it gives only the error message as a string, and I would want to avoid parsing this string.

This is in order to handle some magic keywords in the CLI whatever the type defined with argparse.

Note that I read the following related question:

Handle invalid arguments with argparse in Python

and Python documentation, neither one seems to give an answer.

Community
  • 1
  • 1
dtrckd
  • 657
  • 7
  • 17

1 Answers1

5

You could define an error catching type function. For example wrap int as:

def trytype(astr, fn=int):
    try:
       ret = fn(astr)
    except ValueError:   
       ret = ('error', astr)
    return ret

In [51]: parser = argparse.ArgumentParser()
In [52]: parser.add_argument('-f', type=trytype);
In [53]: parser.parse_args('-f 123'.split())
Out[53]: Namespace(f=123)
In [54]: parser.parse_args('-f abc'.split())
Out[54]: Namespace(f=('error', 'abc'))

This could be generalized to handle other type functions (may be a trytype factory function). Also make it catch all the error types (ValueError, TypeError, ArgumentTypeError). And customize the return value. Here I just returned a tuple with an 'error' string and the original string.

In [55]: from functools import partial
In [56]: partial(trytype, fn=float)
Out[56]: functools.partial(<function trytype at 0xac13a8e4>, fn=<class 'float'>)
In [57]: partial(trytype, fn=float)('12.34')
Out[57]: 12.34
In [58]: partial(trytype, fn=int)('12.34')
Out[58]: ('error', '12.34')
In [59]: partial(trytype, fn=str)('abc')
Out[59]: 'abc'

accept int in one argument and float in another:

In [60]: parser = argparse.ArgumentParser()
In [61]: parser.add_argument('-i', type=partial(trytype, fn=int));
In [62]: parser.add_argument('-f', type=partial(trytype, fn=float));
In [63]: parser.parse_args('-f abc -i123'.split())
Out[63]: Namespace(f=('error', 'abc'), i=123)
In [64]: parser.parse_args('-f 12.32 -ia23'.split())
Out[64]: Namespace(f=12.32, i=('error', 'a23'))
In [65]: parser.parse_args('-f 12e32 -ia23'.split())
Out[65]: Namespace(f=1.2e+33, i=('error', 'a23'))
In [66]: parser.parse_args('-f x2e32 -ia23'.split())
Out[66]: Namespace(f=('error', 'x2e32'), i=('error', 'a23'))
hpaulj
  • 221,503
  • 14
  • 230
  • 353