piranha/opster — Issue #3: opster bombs with invalid input for float/int option
Author: oscarbenjamin
Created: 2011-10-29 23:03:46+00:00
State: open

Hi again.

I've found that opster generates nice helpful message for the user when an option argument is missing or is not a valid a=b string for dict options, but bombs with a stcktrace if it fails to parse a float/int option. Example:

myscript.py:

```python
import sys
import opster

@opster.command()
def main(number=('n', 1, 'integer option'),
ratio=('r', 1.0, 'float option')):
print number, ratio

if __name__ == "__main__":
main(argv=sys.argv[1:])
```

If you run `python mtscript.py -n` you get the message
```error: option -n requires argument

myscript.py [OPTIONS]

(no help text available)

options:

-n --number integer option (default: 1)
-r --ratio float option (default: 1.0)
-h --help show help```

However, if you run `python myscript.py -n 1.1` or `python myscript.py -r bad` then you will get something like:
```Traceback (most recent call last):
File "myscript.py", line 10, in
main(argv=sys.argv[1:])
File "/usr/lib/pymodules/python2.7/opster.py", line 110, in inner
opts, args = catcher(lambda: parse(argv, options_), func.help)
File "/usr/lib/pymodules/python2.7/opster.py", line 504, in catcher
return target()
File "/usr/lib/pymodules/python2.7/opster.py", line 110, in
opts, args = catcher(lambda: parse(argv, options_), func.help)
File "/usr/lib/pymodules/python2.7/opster.py", line 371, in parse
state[name] = t(val)
ValueError: invalid literal for int() with base 10: '1.1'```

This can be fixed with the following patch (relative to current git master):

```diff --git a/opster.py b/opster.py
index c9ec3d8..101ec36 100644
--- a/opster.py
+++ b/opster.py
@@ -439,8 +439,13 @@ def process(args, options, preparse=False):
state[name][k] = v
elif t in (types.NoneType, types.BooleanType):
state[name] = not defmap[name]
- else:
- state[name] = t(val)
+ elif t in (int, float):
+ try:
+ state[name] = t(val)
+ except ValueError:
+ raise getopt.GetoptError(
+ "invalid option value '%s' for option '%s'"
+ % (val, name))

for name in funlist:
state[name] = defmap[name](None)```