Skip to content

Instantly share code, notes, and snippets.

@georgepsarakis
Last active January 4, 2016 11:48
Show Gist options
  • Save georgepsarakis/8617110 to your computer and use it in GitHub Desktop.
Save georgepsarakis/8617110 to your computer and use it in GitHub Desktop.
Extended version of the argparse Python module for command line option parsing.
from __future__ import unicode_literals
import re
import argparse
from functools import partial
class Options(argparse.ArgumentParser):
def __init__(self, **kwargs):
self._parsed = False
self._options = None
self._re_numeric = re.compile(r'^([np]*)(float|int)$')
super(Options, self).__init__(**kwargs)
def __add_argument(self, name, *args, **kwargs):
extra = {}
parse_numeric_arg = self._re_numeric.search(name)
if parse_numeric_arg is not None:
mode, number_type = parse_numeric_arg.groups()
kwargs['type'] = partial(
Options._number,
number_type=number_type,
mode=mode
)
elif name == "list":
if kwargs.get('required', False):
nargs = '+'
else:
nargs = '*'
kwargs['nargs'] = nargs
elif name == "counter":
kwargs['action'] = 'count'
extra['default'] = 0
elif name in ["true", "false"]:
kwargs["action"] = "store_{}".format(name)
kwargs['default'] = True if name == 'false' else False
extra.update(kwargs)
help_message = extra.get('help', '')
help_message += ' (default={})'.format(extra.get('default', None))
extra['help'] = help_message.strip()
self.add_argument(*args, **extra)
@staticmethod
def _number(item, number_type, mode=None):
if number_type == "int":
display = "integer"
transform = int
elif number_type == "float":
display = "float"
transform = float
message_parameters = (item, display)
try:
item = transform(item)
except ValueError:
raise argparse.ArgumentTypeError(
"%s not a %s" % message_parameters
)
if mode == 'p':
if not item >= 0:
raise argparse.ArgumentTypeError(
"%s not a positive %s" % message_parameters
)
elif mode == 'n':
if not item < 0:
raise argparse.ArgumentTypeError(
"%s not a negative %s" % message_parameters
)
return item
@property
def options(self):
if not self._parsed:
self._parse_arguments()
return self._options
def __getattr__(self, name):
if name in [
'int', 'pint', 'nint',
'nfloat', 'pfloat',
'true', 'false',
'counter', 'list'
]:
def f(*args, **kwargs):
return self.__add_argument(name, *args, **kwargs)
return f
elif name in self.options:
return getattr(self.options, name)
def _parse_arguments(self):
parameters, extra = self.parse_known_args()
parameters._extra = extra
self._options = parameters
self._parsed = True
def __repr__(self):
return self.options.__repr__()
if __name__ == "__main__":
options = Options(description="Example Program")
options.pint(
'--delay',
default=0,
help='--delay parameter is of type integer & greater/equal to zero')
options.counter('-v', '--verbose', help='Verbosity level')
options.list('--list-items', default=[10, 20, 30], type=int)
options.true(
'--log',
help='Flag that acquires the value True when set'
)
print 'delay -> {}'.format(options.delay)
print 'list_items -> {}'.format(options.list_items)
print 'log -> {}'.format(options.log)
print 'verbose -> {}'.format(options.verbose)
@georgepsarakis
Copy link
Author

Add support for date/datetime parameters.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment