Skip to content

Instantly share code, notes, and snippets.

@TheWaWaR
Last active December 31, 2017 10:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TheWaWaR/b88baf7f82ed6bea58959ff7340ff409 to your computer and use it in GitHub Desktop.
Save TheWaWaR/b88baf7f82ed6bea58959ff7340ff409 to your computer and use it in GitHub Desktop.
An argparse helper
#!/usr/bin/env python
# coding: utf-8
"""
A simple argparse helper.
Features:
=========
* Make nesting commands more elegant and easy to write.
* Without lose argparse's ability (means you can refactor current code)
"""
class Arg(object):
""" A class to save arguments passing to a class or function
[Use cases]:
1. parser.add_argument('-c', '--code', help=u'User code')
Equals to: arguments=[Arg('-c', '--code', help=u'User code')]
2. subparsers.add_parser('add_role', help=u'Add role to a user')
Equals to: ParserConfig(Arg('add_role', help=u'Add role to a user'))
"""
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
class ParserConfig(object):
""" A config to build a parser or subparser """
def __init__(self,
parser_args,
arguments=None,
defaults=None,
subparsers=None):
arguments = arguments or []
defaults = defaults or {}
subparsers = subparsers or []
self.parser_args = parser_args
self.arguments = arguments
self.defaults = defaults
self.subparsers = subparsers
self.check_args()
def check_args(self):
""" Check the type of attributes """
assert isinstance(self.parser_args, Arg)
assert isinstance(self.arguments, (list, tuple))
assert isinstance(self.defaults, dict)
assert isinstance(self.subparsers, (list, tuple))
for argument in self.arguments:
assert isinstance(argument, Arg)
for subparser in self.subparsers:
assert isinstance(subparser, ParserConfig)
def build(self, parser):
""" Build the parser or subparser recursively """
for argument in self.arguments:
parser.add_argument(*argument.args, **argument.kwargs)
parser.set_defaults(**self.defaults)
if self.subparsers:
sp = parser.add_subparsers()
for sub_config in self.subparsers:
sub_config.build(sp.add_parser(
*sub_config.parser_args.args,
**sub_config.parser_args.kwargs
))
if __name__ == '__main__':
# A simple use case.
import argparse
parser = argparse.ArgumentParser()
parser_config = ParserConfig(
Arg(),
arguments=[
Arg('-v', '--verbose', action='store_true',
help=u'Verbose log'),
Arg('--dry', action='store_true',
help=u'Do not run real function'),
],
subparsers=[
ParserConfig(
Arg('user', help=u'User management'),
# You can put `subparsers` some where above `parser_config`.
subparsers=[
ParserConfig(
Arg('list', help=u'List all user'),
defaults=dict(func=lambda x: x)
),
ParserConfig(
Arg('add', help=u'Add a user'),
arguments=[
Arg('-c', '--code', required=True,
help=u'User code'),
Arg('--name', required=True,
help=u'User name'),
Arg('--description', default='',
help=u'The description'),
],
defaults=dict(func=lambda x: x)
),
ParserConfig(
Arg('add_role', help=u'Add role to a user'),
arguments=[
Arg('-c', '--code', required=True,
help=u'Target user code'),
Arg('-r', '--role', required=True,
help=u'The role name')
],
defaults=dict(func=lambda x: x)
),
ParserConfig(
Arg('remove_role', help=u'Remove a role from a user'),
arguments=[
Arg('-c', '--code', required=True,
help=u'Target user code'),
Arg('-r', '--role',
help=u'The role name'),
],
defaults=dict(func=lambda x: x)
),
]
),
ParserConfig(
Arg('test', help=u'Run some test'),
arguments=[Arg('-l', '--log', help=u'Output log file')],
defaults=dict(func=lambda x: x),
),
]
)
parser_config.build(parser)
args = parser.parse_args()
print(u'Args: {}'.format(args))
# $> python simple_argparse.py user --help
# usage: simple_argparse.py user [-h] {list,add,add_role,remove_role} ...
# positional arguments:
# {list,add,add_role,remove_role}
# list List all user
# add Add a user
# add_role Add role to a user
# remove_role Remove a role from a user
# optional arguments:
# -h, --help show this help message and exit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment