<s> from __future__ import print_function <EOL> __all__ = [ '<STR_LIT:start>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ] <EOL> import sys <EOL> import inspect <EOL> import re <EOL> from os . path import basename <EOL> from collections import defaultdict <EOL> from . util import json , autotype , getargspec <EOL> Empty = type ( '<STR_LIT>' , ( object , ) , { <EOL> '<STR_LIT>' : lambda self : False , <EOL> '<STR_LIT>' : lambda self : '<STR_LIT>' , <EOL> } ) ( ) <EOL> class Command ( object ) : <EOL> '''<STR_LIT>''' <EOL> arg_desc_re = re . compile ( r'<STR_LIT>' ) <EOL> '''<STR_LIT>''' <EOL> arg_re = re . compile ( r'<STR_LIT>' ) <EOL> '''<STR_LIT>''' <EOL> arg_type_map = { <EOL> '<STR_LIT:n>' : int , '<STR_LIT>' : int , '<STR_LIT>' : int , <EOL> '<STR_LIT:i>' : int , '<STR_LIT:int>' : int , '<STR_LIT>' : int , <EOL> '<STR_LIT:s>' : str , '<STR_LIT:str>' : str , '<STR_LIT:string>' : str , <EOL> '<STR_LIT:f>' : float , '<STR_LIT:float>' : float , <EOL> '<STR_LIT>' : json , <EOL> None : autotype <EOL> } <EOL> '''<STR_LIT>''' <EOL> def __init__ ( self , func , name = None ) : <EOL> self . name = name <EOL> self . func = func <EOL> arg_names , vararg_name , keyarg_name , arg_defaults = getargspec ( func ) <EOL> self . arg_names = arg_names <EOL> self . vararg_name = vararg_name <EOL> self . keyarg_name = keyarg_name <EOL> self . arg_defaults = arg_defaults or tuple ( ) <EOL> self . no_defult_args_len = len ( self . arg_names ) - len ( self . arg_defaults ) <EOL> self . arg_name_set = set ( arg_names ) <EOL> self . arg_default_map = dict ( zip ( <EOL> * map ( reversed , ( self . arg_names , self . arg_defaults ) ) <EOL> ) ) <EOL> self . arg_meta_map = { } <EOL> self . alias_arg_map = { } <EOL> doc = inspect . getdoc ( func ) <EOL> if not doc : return <EOL> for line in doc . splitlines ( ) : <EOL> if not self . arg_desc_re . match ( line ) : continue <EOL> arg_part , _ , desc_part = line . strip ( ) . partition ( '<STR_LIT:U+0020>' ) <EOL> aliases_set = set ( ) <EOL> for m in self . arg_re . finditer ( arg_part ) : <EOL> key , meta = m . group ( '<STR_LIT:key>' , '<STR_LIT>' ) <EOL> key = key . replace ( '<STR_LIT:->' , '<STR_LIT:_>' ) <EOL> self . arg_meta_map [ key ] = meta <EOL> aliases_set . add ( key ) <EOL> arg_name_set = self . arg_name_set & aliases_set <EOL> if not arg_name_set : continue <EOL> aliases_set -= arg_name_set <EOL> arg_name = arg_name_set . pop ( ) <EOL> for alias in aliases_set : <EOL> self . alias_arg_map [ alias ] = arg_name <EOL> def dealias ( self , alias ) : <EOL> '''<STR_LIT>''' <EOL> return self . alias_arg_map . get ( alias , alias ) <EOL> def cast ( self , arg_name , val ) : <EOL> '''<STR_LIT>''' <EOL> meta = self . arg_meta_map . get ( arg_name ) <EOL> if meta is not None : <EOL> meta = meta . strip ( '<STR_LIT>' ) . lower ( ) <EOL> type = self . arg_type_map [ meta ] <EOL> return type ( val ) <EOL> def parse ( self , raw_args = None ) : <EOL> """<STR_LIT>""" <EOL> if raw_args is None : <EOL> raw_args = sys . argv [ <NUM_LIT:1> : ] <EOL> elif isinstance ( raw_args , str ) : <EOL> raw_args = raw_args . split ( ) <EOL> pargs = [ ] <EOL> kargs = defaultdict ( list ) <EOL> while raw_args : <EOL> arg_name = None <EOL> val = Empty <EOL> if raw_args [ <NUM_LIT:0> ] . startswith ( '<STR_LIT:->' ) and len ( raw_args [ <NUM_LIT:0> ] ) >= <NUM_LIT:2> : <EOL> before_eq_str , eq_str , val = raw_args . pop ( <NUM_LIT:0> ) . partition ( '<STR_LIT:=>' ) <EOL> if not eq_str : <EOL> val = Empty <EOL> if before_eq_str . startswith ( '<STR_LIT>' ) : <EOL> arg_name = self . dealias ( before_eq_str [ <NUM_LIT:2> : ] . replace ( '<STR_LIT:->' , '<STR_LIT:_>' ) ) <EOL> else : <EOL> sep = <NUM_LIT:1> <EOL> for c in before_eq_str [ <NUM_LIT:1> : ] : <EOL> if c in self . arg_name_set or c in self . alias_arg_map : <EOL> sep += <NUM_LIT:1> <EOL> else : <EOL> break <EOL> for c in before_eq_str [ <NUM_LIT:1> : sep - <NUM_LIT:1> ] : <EOL> arg_name = self . dealias ( c ) <EOL> kargs [ arg_name ] . append ( Empty ) <EOL> arg_name = self . dealias ( before_eq_str [ sep - <NUM_LIT:1> ] ) <EOL> if val is Empty : <EOL> val = before_eq_str [ sep : ] or Empty <EOL> if ( <EOL> val is Empty and <EOL> not isinstance ( self . arg_default_map . get ( arg_name ) , bool ) and <EOL> raw_args and not raw_args [ <NUM_LIT:0> ] . startswith ( '<STR_LIT:->' ) <EOL> ) : <EOL> val = raw_args . pop ( <NUM_LIT:0> ) <EOL> else : <EOL> val = raw_args . pop ( <NUM_LIT:0> ) <EOL> if arg_name : <EOL> kargs [ arg_name ] . append ( val ) <EOL> else : <EOL> pargs . append ( val ) <EOL> kargs = dict ( kargs ) <EOL> for arg_name , collected_vals in kargs . items ( ) : <EOL> default = self . arg_default_map . get ( arg_name ) <EOL> if isinstance ( default , bool ) : <EOL> kargs [ arg_name ] = not default <EOL> elif all ( val is Empty for val in collected_vals ) : <EOL> if isinstance ( default , int ) : <EOL> kargs [ arg_name ] = len ( collected_vals ) <EOL> else : <EOL> kargs [ arg_name ] = None <EOL> else : <EOL> val = next ( val for val in reversed ( collected_vals ) if val is not Empty ) <EOL> if not self . keyarg_name or arg_name in self . arg_meta_map : <EOL> kargs [ arg_name ] = self . cast ( arg_name , val ) <EOL> else : <EOL> kargs [ arg_name ] = self . cast ( self . keyarg_name , val ) <EOL> for arg_name , default in self . arg_default_map . items ( ) : <EOL> if arg_name not in kargs : <EOL> kargs [ arg_name ] = default <EOL> isbuiltin = inspect . isbuiltin ( self . func ) <EOL> for pos , name in enumerate ( self . arg_names ) : <EOL> if name in kargs and ( pos < len ( pargs ) or isbuiltin ) : <EOL> pargs . insert ( pos , kargs . pop ( name ) ) <EOL> for i , parg in enumerate ( pargs ) : <EOL> if i < self . no_defult_args_len : <EOL> pargs [ i ] = self . cast ( self . arg_names [ i ] , parg ) <EOL> elif self . vararg_name : <EOL> pargs [ i ] = self . cast ( self . vararg_name , parg ) <EOL> return ( pargs , kargs ) <EOL> scan = parse <EOL> '''<STR_LIT>''' <EOL> def execute ( self , raw_args = None ) : <EOL> '''<STR_LIT>''' <EOL> pargs , kargs = self . parse ( raw_args ) <EOL> return self . func ( * pargs , ** kargs ) <EOL> def build_usage ( self , without_name = False ) : <EOL> '''<STR_LIT>''' <EOL> alias_arg_rmap = { } <EOL> for alias , arg_name in self . alias_arg_map . items ( ) : <EOL> aliases = alias_arg_rmap . setdefault ( arg_name , [ ] ) <EOL> aliases . append ( alias ) <EOL> usage = [ ] <EOL> if self . arg_defaults : <EOL> for arg_name in self . arg_names [ - len ( self . arg_defaults ) : ] : <EOL> pieces = [ ] <EOL> for name in alias_arg_rmap . get ( arg_name , [ ] ) + [ arg_name ] : <EOL> is_long_opt = len ( name ) > <NUM_LIT:1> <EOL> pieces . append ( '<STR_LIT>' % ( '<STR_LIT:->' * ( <NUM_LIT:1> + is_long_opt ) , name . replace ( '<STR_LIT:_>' , '<STR_LIT:->' ) ) ) <EOL> meta = self . arg_meta_map . get ( name ) <EOL> if meta is None : <EOL> default = self . arg_default_map [ self . dealias ( name ) ] <EOL> if isinstance ( default , bool ) : <EOL> continue <EOL> elif default is None : <EOL> meta = '<STR_LIT>' <EOL> else : <EOL> meta = '<STR_LIT>' . format ( default ) <EOL> if is_long_opt : <EOL> pieces [ - <NUM_LIT:1> ] += '<STR_LIT:=>' + meta <EOL> else : <EOL> pieces [ - <NUM_LIT:1> ] += '<STR_LIT:U+0020>' + meta <EOL> usage . append ( '<STR_LIT>' % '<STR_LIT>' . join ( pieces ) ) <EOL> if self . keyarg_name : <EOL> usage . append ( '<STR_LIT>' ) <EOL> usage . extend ( '<STR_LIT>' % name . replace ( '<STR_LIT:_>' , '<STR_LIT:->' ) for name in self . arg_names [ : - len ( self . arg_defaults ) or None ] ) <EOL> if self . vararg_name : <EOL> usage . append ( '<STR_LIT>' % self . vararg_name . replace ( '<STR_LIT:_>' , '<STR_LIT:->' ) ) <EOL> if without_name : <EOL> return '<STR_LIT:%s>' % '<STR_LIT:U+0020>' . join ( usage ) <EOL> else : <EOL> return '<STR_LIT>' % ( ( self . name or self . func . __name__ ) . replace ( '<STR_LIT:_>' , '<STR_LIT:->' ) , '<STR_LIT:U+0020>' . join ( usage ) ) <EOL> get_usage = build_usage <EOL> '''<STR_LIT>''' <EOL> CMD_SUFFIX = re . compile ( '<STR_LIT>' ) <EOL> '''<STR_LIT>''' <EOL> class Program ( object ) : <EOL> '''<STR_LIT>''' <EOL> def __init__ ( self , obj = None , default = None , white_list = None , white_pattern = None , black_list = None , ignore_help = False , ignore_return = False , name = None , doc = None , debug = False ) : <EOL> obj = obj or sys . modules [ '<STR_LIT:__main__>' ] <EOL> self . obj = obj <EOL> if hasattr ( obj , '<STR_LIT>' ) : <EOL> obj_items = obj . items ( ) <EOL> else : <EOL> obj_items = inspect . getmembers ( obj ) <EOL> if not white_list and hasattr ( obj , '<STR_LIT>' ) : <EOL> white_list = obj . __all__ <EOL> tests = ( inspect . isbuiltin , inspect . isfunction , inspect . ismethod ) <EOL> self . command_funcs = { } <EOL> for obj_name , obj in obj_items : <EOL> if obj_name . startswith ( '<STR_LIT:_>' ) : continue <EOL> if not any ( test ( obj ) for test in tests ) : continue <EOL> if white_list is not None and obj_name not in white_list : continue <EOL> if black_list is not None and obj_name in black_list : continue <EOL> if white_pattern : <EOL> match = white_pattern . match ( obj_name ) <EOL> if not match : continue <EOL> obj_name = match . group ( '<STR_LIT:name>' ) <EOL> self . command_funcs [ obj_name ] = obj <EOL> self . default = default <EOL> if len ( self . command_funcs ) == <NUM_LIT:1> : <EOL> self . default = list ( self . command_funcs . keys ( ) ) [ <NUM_LIT:0> ] <EOL> self . ignore_help = ignore_help <EOL> self . ignore_return = ignore_return <EOL> self . name = name or basename ( sys . argv [ <NUM_LIT:0> ] ) <EOL> self . doc = doc <EOL> self . debug = debug <EOL> def complain ( self , msg ) : <EOL> '''<STR_LIT>''' <EOL> print ( '<STR_LIT>' % ( self . name , msg ) , file = sys . stdout ) <EOL> def main ( self , raw_args = None ) : <EOL> '''<STR_LIT>''' <EOL> if raw_args is None : <EOL> raw_args = sys . argv [ <NUM_LIT:1> : ] <EOL> elif isinstance ( raw_args , str ) : <EOL> raw_args = raw_args . split ( ) <EOL> cmd_name = None <EOL> cmd_func = None <EOL> if len ( raw_args ) == <NUM_LIT:0> : <EOL> pass <EOL> elif not self . ignore_help and raw_args [ <NUM_LIT:0> ] in ( '<STR_LIT>' , '<STR_LIT>' ) : <EOL> self . print_usage ( ) <EOL> return <EOL> else : <EOL> cmd_func = self . command_funcs . get ( raw_args [ <NUM_LIT:0> ] . replace ( '<STR_LIT:->' , '<STR_LIT:_>' ) ) <EOL> if cmd_func is not None : <EOL> cmd_name = raw_args . pop ( <NUM_LIT:0> ) . replace ( '<STR_LIT:->' , '<STR_LIT:_>' ) <EOL> if cmd_func is None : <EOL> if self . default : <EOL> cmd_name = cmd_name <EOL> cmd_func = self . command_funcs [ self . default ] <EOL> else : <EOL> self . print_usage ( ) <EOL> return <EOL> if not self . ignore_help and '<STR_LIT>' in raw_args : <EOL> self . print_usage ( cmd_name ) <EOL> return <EOL> cmd = Command ( cmd_func , cmd_name ) <EOL> try : <EOL> return_val = cmd . execute ( raw_args ) <EOL> except BaseException as e : <EOL> if self . debug : <EOL> raise <EOL> self . complain ( '<STR_LIT>' . format ( <EOL> e . __class__ . __name__ , <EOL> e <EOL> ) ) <EOL> sys . exit ( <NUM_LIT:1> ) <EOL> if not self . ignore_return and return_val is not None : <EOL> if inspect . isgenerator ( return_val ) : <EOL> for i in return_val : <EOL> print ( i ) <EOL> else : <EOL> print ( return_val ) <EOL> def print_usage ( self , cmd_name = None ) : <EOL> '''<STR_LIT>''' <EOL> def append_usage ( cmd_name , without_name = False ) : <EOL> cmd_func = self . command_funcs [ cmd_name ] <EOL> usages . append ( Command ( cmd_func , cmd_name ) . build_usage ( without_name ) ) <EOL> usages = [ ] <EOL> if cmd_name is None : <EOL> if self . default is not None : <EOL> append_usage ( self . default , True ) <EOL> for name in sorted ( self . command_funcs . keys ( ) ) : <EOL> append_usage ( name ) <EOL> else : <EOL> if self . default == cmd_name : <EOL> append_usage ( cmd_name , without_name = True ) <EOL> append_usage ( cmd_name ) <EOL> iusages = iter ( usages ) <EOL> try : <EOL> print ( '<STR_LIT>' , next ( iusages ) ) <EOL> except StopIteration : <EOL> pass <EOL> else : <EOL> for usage in iusages : <EOL> print ( '<STR_LIT>' , usage ) <EOL> if cmd_name is None : <EOL> if self . doc : <EOL> doc = self . doc <EOL> elif inspect . ismodule ( self . obj ) : <EOL> doc = inspect . getdoc ( self . obj ) <EOL> else : <EOL> doc = None <EOL> if not doc : <EOL> cmd_name = self . default <EOL> if cmd_name : <EOL> doc = inspect . getdoc ( self . command_funcs [ cmd_name ] ) <EOL> if doc : <EOL> print ( ) <EOL> print ( doc ) <EOL> print ( ) <EOL> def start ( * args , ** kargs ) : <EOL> '''<STR_LIT>''' <EOL> prog = Program ( * args , ** kargs ) <EOL> prog . main ( ) <EOL> return prog <EOL> customize = start <EOL> '''<STR_LIT>''' <EOL> if __name__ == '<STR_LIT:__main__>' : <EOL> import doctest <EOL> doctest . testmod ( ) <EOL> def read_json ( json = None ) : <EOL> '''<STR_LIT>''' <EOL> return json <EOL> read_json_cmd = Command ( read_json ) <EOL> print ( '<STR_LIT>' ) <EOL> print ( read_json_cmd . build_usage ( ) ) <EOL> print ( read_json_cmd . execute ( '<STR_LIT>' ) ) <EOL> print ( read_json_cmd . execute ( [ '<STR_LIT>' , '<STR_LIT>' ] ) ) <EOL> print ( '<STR_LIT>' ) <EOL> prog = Program ( white_list = [ '<STR_LIT>' ] , debug = True ) <EOL> prog . main ( ) </s>
