Created
July 28, 2012 05:34
-
-
Save mikelikespie/3191937 to your computer and use it in GitHub Desktop.
Interface for Argparse Similar to Declarative base
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import abc | |
import re | |
import argparse | |
class ArgBaseError(Exception): pass | |
def _inject_vals(name, bases, dict): | |
expected_args = {} | |
is_subcommand = False | |
for b in bases: | |
if b is Command: | |
dict['__parser__'] = argparse.ArgumentParser() | |
elif issubclass(b, Command): | |
if '__subparsers__' not in b.__dict__: | |
setattr(b, '__subparsers__', b.__parser__.add_subparsers()) | |
b.__parser__._defaults.pop('command') | |
if '__subcommand__' not in dict: | |
raise ArgBaseError(name + " must have __subcommand__ defined") | |
if hasattr(b, '__expectedargs__'): | |
expected_args.update(b.__expectedargs__) | |
subparser = b.__subparsers__.add_parser(dict['__subcommand__'], | |
help=dict.get('__doc__')) | |
is_subcommand = True | |
dict['__parser__'] = subparser | |
parser = dict['__parser__'] | |
arglist = [(v.ordinal, k, v) | |
for k,v | |
in dict.iteritems() | |
if isinstance(v, Arg)] | |
# Go through all the base classes that aren't command and find attrs in | |
# them. These are mixins | |
for b in bases: | |
if b is not Command and not issubclass(b, Command): | |
b_args = [(v.ordinal, n, v) | |
for n,v | |
in ((n,getattr(b, n)) | |
for n | |
in dir(b)) | |
if isinstance(v, Arg)] | |
arglist += b_args | |
expected_args.update((k,v) for _,k,v in b_args) | |
arglist.sort() | |
for _, name, arg in arglist: | |
arg_names = arg.args or (name,) | |
var_name = arg_names[0].lstrip('-').replace('-', '_') | |
expected_args[var_name] = name | |
parser.add_argument(*arg_names, **arg.kwargs) | |
dict['__expectedargs__'] = expected_args | |
return is_subcommand | |
class Ordered(object): | |
_object_counter = 0 | |
def __init__(self): | |
self.ordinal = self._object_counter | |
self._object_counter += 1 | |
class MetaBase(abc.ABCMeta): | |
def __new__(mcs, name, bases, dict): | |
is_sub = False | |
if name is not 'Command': | |
is_sub = _inject_vals(name, bases, dict) | |
cls = abc.ABCMeta.__new__(mcs, name, bases, dict) | |
if name is not 'Command': | |
def run_command(args): | |
instance = cls(args) | |
return instance() | |
cls.__parser__.set_defaults(command=run_command) | |
return cls | |
class Command(Ordered): | |
__metaclass__ = MetaBase | |
def __call__(self): | |
pass | |
def __init__(self, args): | |
self.args = args | |
for arg_name, var_name in self.__expectedargs__.iteritems(): | |
setattr(self, var_name, getattr(args, arg_name)) | |
@classmethod | |
def main(cls, *args): | |
args = cls.__parser__.parse_args(*args) | |
args.command(args) | |
class Arg(Ordered): | |
def __init__(self, *args, **kwargs): | |
Ordered.__init__(self) | |
self.args = args; | |
self.kwargs = kwargs | |
__all__ = ['Command', 'Arg'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""You can use mixins to use same properties in different apps""" | |
from argbase import * | |
import git | |
class FooValueMixin(object): | |
foo_value = Arg(default='HEAD', nargs='?', help='Check that treelike is valid [default %(default)s]') | |
class CheckSignoffs(Command, FooValueMixin): | |
disallow_safe_merge = Arg('--disallow-safe-merge', | |
action='store_true', | |
default=False, | |
help='any merge will fail if not signed off on') | |
def __call__(self): | |
print "Would check signoffs for foo_value %s" % self.foo_value | |
print "Allow safe merge: %s", self.disallow_safe_merge | |
class CheckTests(Command, FooValueMixin): | |
def __call__(self): | |
print "Would check tests for foo_value %s" % self.foo_value | |
# Try each one: | |
CheckSignoffs.main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""Example of argbase working for a singe command""" | |
from argbase import * | |
class SingleCommand(Command): | |
file = Arg('--file', nargs='?') | |
def __call__(self): | |
print "I am a single command" | |
SingleCommand.main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""Test with hierarchy""" | |
from argbase import * | |
class Base(Command): | |
file = Arg('--file', nargs='?', default='some_file.txt') | |
class SubCommandOne(Base): | |
"""Subcommand 1 help""" | |
__subcommand__ = 'subcommand' | |
sub_arg = Arg() | |
class HelloCommand(Base): | |
"""Prints hello or FOO""" | |
__subcommand__ = 'say-hi' | |
fun_arg = Arg('--foo', nargs='?') | |
abcd = Arg('--gggg', nargs='?') | |
def __call__(self): | |
print "Arg inherited from base class: ", self.file | |
print self.fun_arg or "hello" | |
Base.main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment