Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Hack to enable Gnu-style long options in python's argparse
#!/usr/bin/python3
import argparse
import inspect
class GnuStyleLongOption(argparse._StoreConstAction):
def __init__(self, **kw):
self._real_option_strings = kw['option_strings']
opts = []
for option_string in self._real_option_strings:
opts.append(option_string)
for choice in kw['choices']:
opts.append(f'{option_string}={choice}')
kw['option_strings'] = opts
self.choices = kw.pop('choices')
help_choices = [f"'{choice}'" for choice in self.choices]
kw['help'] += f"; {kw['metavar']} is {', or '.join([', '.join(help_choices[:-1]), help_choices[-1]])}"
super(GnuStyleLongOption, self).__init__(**kw)
def __getattribute__(self, attr):
caller_is_argparse_help = False
for frame in inspect.stack():
if frame.function == 'format_help' and frame.filename.endswith('argparse.py'):
caller_is_argparse_help = True
break
if caller_is_argparse_help:
if attr == 'option_strings':
return [f'{i}[=WHEN]' for i in self._real_option_strings]
if attr == 'nargs':
return 0
if attr == 'metavar':
return None
return super(GnuStyleLongOption, self).__getattribute__(attr)
def __call__(self, parser, namespace, values, option_string=None):
setattr(namespace, self.dest, self.const if '=' not in option_string else option_string[option_string.find('=') + 1:])
p = argparse.ArgumentParser()
p.add_argument('--color', '--colour', action=GnuStyleLongOption, choices=['always', 'never', 'auto'], const='always', default='auto', help='use markers to highlight whatever we want', metavar='WHEN')
p.add_argument('filenames', metavar='filename', nargs='*', help='file to process')
args = p.parse_args()
print(f'color = {args.color}, filenames = {args.filenames}')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment