<s> from copy import copy <EOL> import sys <EOL> import re <EOL> class DocoptLanguageError ( Exception ) : <EOL> """<STR_LIT>""" <EOL> class DocoptExit ( SystemExit ) : <EOL> """<STR_LIT>""" <EOL> usage = '<STR_LIT>' <EOL> def __init__ ( self , message = '<STR_LIT>' ) : <EOL> SystemExit . __init__ ( self , ( message + '<STR_LIT:\n>' + self . usage ) . strip ( ) ) <EOL> class Pattern ( object ) : <EOL> def __init__ ( self , * children ) : <EOL> self . children = list ( children ) <EOL> def __eq__ ( self , other ) : <EOL> return repr ( self ) == repr ( other ) <EOL> def __hash__ ( self ) : <EOL> return hash ( repr ( self ) ) <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' % ( self . __class__ . __name__ , <EOL> '<STR_LIT:U+002CU+0020>' . join ( repr ( a ) for a in self . children ) ) <EOL> @ property <EOL> def flat ( self ) : <EOL> if not hasattr ( self , '<STR_LIT>' ) : <EOL> return [ self ] <EOL> return sum ( [ c . flat for c in self . children ] , [ ] ) <EOL> def fix ( self ) : <EOL> self . fix_identities ( ) <EOL> self . fix_list_arguments ( ) <EOL> return self <EOL> def fix_identities ( self , uniq = None ) : <EOL> """<STR_LIT>""" <EOL> if not hasattr ( self , '<STR_LIT>' ) : <EOL> return self <EOL> uniq = list ( set ( self . flat ) ) if uniq == None else uniq <EOL> for i , c in enumerate ( self . children ) : <EOL> if not hasattr ( c , '<STR_LIT>' ) : <EOL> assert c in uniq <EOL> self . children [ i ] = uniq [ uniq . index ( c ) ] <EOL> else : <EOL> c . fix_identities ( uniq ) <EOL> def fix_list_arguments ( self ) : <EOL> """<STR_LIT>""" <EOL> either = [ list ( c . children ) for c in self . either . children ] <EOL> for case in either : <EOL> case = [ c for c in case if case . count ( c ) > <NUM_LIT:1> ] <EOL> for a in [ e for e in case if type ( e ) == Argument ] : <EOL> a . value = [ ] <EOL> return self <EOL> @ property <EOL> def either ( self ) : <EOL> """<STR_LIT>""" <EOL> if not hasattr ( self , '<STR_LIT>' ) : <EOL> return Either ( Required ( self ) ) <EOL> else : <EOL> ret = [ ] <EOL> groups = [ [ self ] ] <EOL> while groups : <EOL> children = groups . pop ( <NUM_LIT:0> ) <EOL> types = [ type ( c ) for c in children ] <EOL> if Either in types : <EOL> either = [ c for c in children if type ( c ) is Either ] [ <NUM_LIT:0> ] <EOL> children . pop ( children . index ( either ) ) <EOL> for c in either . children : <EOL> groups . append ( [ c ] + children ) <EOL> elif Required in types : <EOL> required = [ c for c in children if type ( c ) is Required ] [ <NUM_LIT:0> ] <EOL> children . pop ( children . index ( required ) ) <EOL> groups . append ( list ( required . children ) + children ) <EOL> elif Optional in types : <EOL> optional = [ c for c in children if type ( c ) is Optional ] [ <NUM_LIT:0> ] <EOL> children . pop ( children . index ( optional ) ) <EOL> groups . append ( list ( optional . children ) + children ) <EOL> elif OneOrMore in types : <EOL> oneormore = [ c for c in children if type ( c ) is OneOrMore ] [ <NUM_LIT:0> ] <EOL> children . pop ( children . index ( oneormore ) ) <EOL> groups . append ( list ( oneormore . children ) * <NUM_LIT:2> + children ) <EOL> else : <EOL> ret . append ( children ) <EOL> return Either ( * [ Required ( * e ) for e in ret ] ) <EOL> class Argument ( Pattern ) : <EOL> def __init__ ( self , name , value = None ) : <EOL> self . name = name <EOL> self . value = value <EOL> def match ( self , left , collected = None ) : <EOL> collected = [ ] if collected is None else collected <EOL> args = [ l for l in left if type ( l ) is Argument ] <EOL> if not len ( args ) : <EOL> return False , left , collected <EOL> left . remove ( args [ <NUM_LIT:0> ] ) <EOL> if type ( self . value ) is not list : <EOL> return True , left , collected + [ Argument ( self . name , args [ <NUM_LIT:0> ] . value ) ] <EOL> same_name = [ a for a in collected <EOL> if type ( a ) is Argument and a . name == self . name ] <EOL> if len ( same_name ) : <EOL> same_name [ <NUM_LIT:0> ] . value += [ args [ <NUM_LIT:0> ] . value ] <EOL> return True , left , collected <EOL> else : <EOL> return True , left , collected + [ Argument ( self . name , <EOL> [ args [ <NUM_LIT:0> ] . value ] ) ] <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' % ( self . name , self . value ) <EOL> class Command ( Pattern ) : <EOL> def __init__ ( self , name , value = False ) : <EOL> self . name = name <EOL> self . value = value <EOL> def match ( self , left , collected = None ) : <EOL> collected = [ ] if collected is None else collected <EOL> args = [ l for l in left if type ( l ) is Argument ] <EOL> if not len ( args ) or args [ <NUM_LIT:0> ] . value != self . name : <EOL> return False , left , collected <EOL> left . remove ( args [ <NUM_LIT:0> ] ) <EOL> return True , left , collected + [ Command ( self . name , True ) ] <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' % ( self . name , self . value ) <EOL> class Option ( Pattern ) : <EOL> def __init__ ( self , short = None , long = None , argcount = <NUM_LIT:0> , value = False ) : <EOL> assert argcount in ( <NUM_LIT:0> , <NUM_LIT:1> ) <EOL> self . short , self . long = short , long <EOL> self . argcount , self . value = argcount , value <EOL> self . value = None if value == False and argcount else value <EOL> @ classmethod <EOL> def parse ( class_ , option_description ) : <EOL> short , long , argcount , value = None , None , <NUM_LIT:0> , False <EOL> options , _ , description = option_description . strip ( ) . partition ( '<STR_LIT:U+0020>' ) <EOL> options = options . replace ( '<STR_LIT:U+002C>' , '<STR_LIT:U+0020>' ) . replace ( '<STR_LIT:=>' , '<STR_LIT:U+0020>' ) <EOL> for s in options . split ( ) : <EOL> if s . startswith ( '<STR_LIT>' ) : <EOL> long = s <EOL> elif s . startswith ( '<STR_LIT:->' ) : <EOL> short = s <EOL> else : <EOL> argcount = <NUM_LIT:1> <EOL> if argcount : <EOL> matched = re . findall ( '<STR_LIT>' , description , flags = re . I ) <EOL> value = matched [ <NUM_LIT:0> ] if matched else None <EOL> return class_ ( short , long , argcount , value ) <EOL> def match ( self , left , collected = None ) : <EOL> collected = [ ] if collected is None else collected <EOL> left_ = [ ] <EOL> for l in left : <EOL> if not ( type ( l ) is Option and <EOL> ( self . short , self . long ) == ( l . short , l . long ) ) : <EOL> left_ . append ( l ) <EOL> return ( left != left_ ) , left_ , collected <EOL> @ property <EOL> def name ( self ) : <EOL> return self . long or self . short <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' % ( self . short , self . long , <EOL> self . argcount , self . value ) <EOL> class AnyOptions ( Pattern ) : <EOL> def match ( self , left , collected = None ) : <EOL> collected = [ ] if collected is None else collected <EOL> left_ = [ l for l in left if not type ( l ) == Option ] <EOL> return ( left != left_ ) , left_ , collected <EOL> class Required ( Pattern ) : <EOL> def match ( self , left , collected = None ) : <EOL> collected = [ ] if collected is None else collected <EOL> l = copy ( left ) <EOL> c = copy ( collected ) <EOL> for p in self . children : <EOL> matched , l , c = p . match ( l , c ) <EOL> if not matched : <EOL> return False , left , collected <EOL> return True , l , c <EOL> class Optional ( Pattern ) : <EOL> def match ( self , left , collected = None ) : <EOL> collected = [ ] if collected is None else collected <EOL> left = copy ( left ) <EOL> for p in self . children : <EOL> m , left , collected = p . match ( left , collected ) <EOL> return True , left , collected <EOL> class OneOrMore ( Pattern ) : <EOL> def match ( self , left , collected = None ) : <EOL> assert len ( self . children ) == <NUM_LIT:1> <EOL> collected = [ ] if collected is None else collected <EOL> l = copy ( left ) <EOL> c = copy ( collected ) <EOL> l_ = None <EOL> matched = True <EOL> times = <NUM_LIT:0> <EOL> while matched : <EOL> matched , l , c = self . children [ <NUM_LIT:0> ] . match ( l , c ) <EOL> times += <NUM_LIT:1> if matched else <NUM_LIT:0> <EOL> if l_ == l : <EOL> break <EOL> l_ = copy ( l ) <EOL> if times >= <NUM_LIT:1> : <EOL> return True , l , c <EOL> return False , left , collected <EOL> class Either ( Pattern ) : <EOL> def match ( self , left , collected = None ) : <EOL> collected = [ ] if collected is None else collected <EOL> outcomes = [ ] <EOL> for p in self . children : <EOL> matched , _ , _ = outcome = p . match ( copy ( left ) , copy ( collected ) ) <EOL> if matched : <EOL> outcomes . append ( outcome ) <EOL> if outcomes : <EOL> return min ( outcomes , key = lambda outcome : len ( outcome [ <NUM_LIT:1> ] ) ) <EOL> return False , left , collected <EOL> class TokenStream ( list ) : <EOL> def __init__ ( self , source , error ) : <EOL> self += source . split ( ) if type ( source ) is str else source <EOL> self . error = error <EOL> def move ( self ) : <EOL> return self . pop ( <NUM_LIT:0> ) if len ( self ) else None <EOL> def current ( self ) : <EOL> return self [ <NUM_LIT:0> ] if len ( self ) else None <EOL> def parse_long ( tokens , options ) : <EOL> raw , eq , value = tokens . move ( ) . partition ( '<STR_LIT:=>' ) <EOL> value = None if eq == value == '<STR_LIT>' else value <EOL> opt = [ o for o in options if o . long and o . long . startswith ( raw ) ] <EOL> if len ( opt ) < <NUM_LIT:1> : <EOL> if tokens . error is DocoptExit : <EOL> raise tokens . error ( '<STR_LIT>' % raw ) <EOL> else : <EOL> o = Option ( None , raw , ( <NUM_LIT:1> if eq == '<STR_LIT:=>' else <NUM_LIT:0> ) ) <EOL> options . append ( o ) <EOL> return [ o ] <EOL> if len ( opt ) > <NUM_LIT:1> : <EOL> raise tokens . error ( '<STR_LIT>' % <EOL> ( raw , '<STR_LIT:U+002CU+0020>' . join ( '<STR_LIT:%s>' % o . long for o in opt ) ) ) <EOL> opt = copy ( opt [ <NUM_LIT:0> ] ) <EOL> if opt . argcount == <NUM_LIT:1> : <EOL> if value is None : <EOL> if tokens . current ( ) is None : <EOL> raise tokens . error ( '<STR_LIT>' % opt . name ) <EOL> value = tokens . move ( ) <EOL> elif value is not None : <EOL> raise tokens . error ( '<STR_LIT>' % opt . name ) <EOL> opt . value = value or True <EOL> return [ opt ] <EOL> def parse_shorts ( tokens , options ) : <EOL> raw = tokens . move ( ) [ <NUM_LIT:1> : ] <EOL> parsed = [ ] <EOL> while raw != '<STR_LIT>' : <EOL> opt = [ o for o in options <EOL> if o . short and o . short . lstrip ( '<STR_LIT:->' ) . startswith ( raw [ <NUM_LIT:0> ] ) ] <EOL> if len ( opt ) > <NUM_LIT:1> : <EOL> raise tokens . error ( '<STR_LIT>' % <EOL> ( raw [ <NUM_LIT:0> ] , len ( opt ) ) ) <EOL> if len ( opt ) < <NUM_LIT:1> : <EOL> if tokens . error is DocoptExit : <EOL> raise tokens . error ( '<STR_LIT>' % raw [ <NUM_LIT:0> ] ) <EOL> else : <EOL> o = Option ( '<STR_LIT:->' + raw [ <NUM_LIT:0> ] , None ) <EOL> options . append ( o ) <EOL> parsed . append ( o ) <EOL> raw = raw [ <NUM_LIT:1> : ] <EOL> continue <EOL> opt = copy ( opt [ <NUM_LIT:0> ] ) <EOL> raw = raw [ <NUM_LIT:1> : ] <EOL> if opt . argcount == <NUM_LIT:0> : <EOL> value = True <EOL> else : <EOL> if raw == '<STR_LIT>' : <EOL> if tokens . current ( ) is None : <EOL> raise tokens . error ( '<STR_LIT>' % opt . short [ <NUM_LIT:0> ] ) <EOL> raw = tokens . move ( ) <EOL> value , raw = raw , '<STR_LIT>' <EOL> opt . value = value <EOL> parsed . append ( opt ) <EOL> return parsed <EOL> def parse_pattern ( source , options ) : <EOL> tokens = TokenStream ( re . sub ( r'<STR_LIT>' , r'<STR_LIT>' , source ) , <EOL> DocoptLanguageError ) <EOL> result = parse_expr ( tokens , options ) <EOL> if tokens . current ( ) is not None : <EOL> raise tokens . error ( '<STR_LIT>' % '<STR_LIT:U+0020>' . join ( tokens ) ) <EOL> return Required ( * result ) <EOL> def parse_expr ( tokens , options ) : <EOL> """<STR_LIT>""" <EOL> seq = parse_seq ( tokens , options ) <EOL> if tokens . current ( ) != '<STR_LIT:|>' : <EOL> return seq <EOL> result = [ Required ( * seq ) ] if len ( seq ) > <NUM_LIT:1> else seq <EOL> while tokens . current ( ) == '<STR_LIT:|>' : <EOL> tokens . move ( ) <EOL> seq = parse_seq ( tokens , options ) <EOL> result += [ Required ( * seq ) ] if len ( seq ) > <NUM_LIT:1> else seq <EOL> return [ Either ( * result ) ] if len ( result ) > <NUM_LIT:1> else result <EOL> def parse_seq ( tokens , options ) : <EOL> """<STR_LIT>""" <EOL> result = [ ] <EOL> while tokens . current ( ) not in [ None , '<STR_LIT:]>' , '<STR_LIT:)>' , '<STR_LIT:|>' ] : <EOL> atom = parse_atom ( tokens , options ) <EOL> if tokens . current ( ) == '<STR_LIT>' : <EOL> atom = [ OneOrMore ( * atom ) ] <EOL> tokens . move ( ) <EOL> result += atom <EOL> return result <EOL> def parse_atom ( tokens , options ) : <EOL> """<STR_LIT>""" <EOL> token = tokens . current ( ) <EOL> result = [ ] <EOL> if token == '<STR_LIT:(>' : <EOL> tokens . move ( ) <EOL> result = [ Required ( * parse_expr ( tokens , options ) ) ] <EOL> if tokens . move ( ) != '<STR_LIT:)>' : <EOL> raise tokens . error ( "<STR_LIT>" ) <EOL> return result <EOL> elif token == '<STR_LIT:[>' : <EOL> tokens . move ( ) <EOL> result = [ Optional ( * parse_expr ( tokens , options ) ) ] <EOL> if tokens . move ( ) != '<STR_LIT:]>' : <EOL> raise tokens . error ( "<STR_LIT>" ) <EOL> return result <EOL> elif token == '<STR_LIT>' : <EOL> tokens . move ( ) <EOL> return [ AnyOptions ( ) ] <EOL> elif token . startswith ( '<STR_LIT>' ) and token != '<STR_LIT>' : <EOL> return parse_long ( tokens , options ) <EOL> elif token . startswith ( '<STR_LIT:->' ) and token not in ( '<STR_LIT:->' , '<STR_LIT>' ) : <EOL> return parse_shorts ( tokens , options ) <EOL> elif token . startswith ( '<STR_LIT:<>' ) and token . endswith ( '<STR_LIT:>>' ) or token . isupper ( ) : <EOL> return [ Argument ( tokens . move ( ) ) ] <EOL> else : <EOL> return [ Command ( tokens . move ( ) ) ] <EOL> def parse_args ( source , options ) : <EOL> tokens = TokenStream ( source , DocoptExit ) <EOL> options = copy ( options ) <EOL> parsed = [ ] <EOL> while tokens . current ( ) is not None : <EOL> if tokens . current ( ) == '<STR_LIT>' : <EOL> return parsed + [ Argument ( None , v ) for v in tokens ] <EOL> elif tokens . current ( ) . startswith ( '<STR_LIT>' ) : <EOL> parsed += parse_long ( tokens , options ) <EOL> elif tokens . current ( ) . startswith ( '<STR_LIT:->' ) and tokens . current ( ) != '<STR_LIT:->' : <EOL> parsed += parse_shorts ( tokens , options ) <EOL> else : <EOL> parsed . append ( Argument ( None , tokens . move ( ) ) ) <EOL> return parsed <EOL> def parse_doc_options ( doc ) : <EOL> return [ Option . parse ( '<STR_LIT:->' + s ) for s in re . split ( '<STR_LIT>' , doc ) [ <NUM_LIT:1> : ] ] <EOL> def printable_usage ( doc ) : <EOL> usage_split = re . split ( r'<STR_LIT>' , doc ) <EOL> if len ( usage_split ) < <NUM_LIT:3> : <EOL> raise DocoptLanguageError ( '<STR_LIT>' ) <EOL> if len ( usage_split ) > <NUM_LIT:3> : <EOL> raise DocoptLanguageError ( '<STR_LIT>' ) <EOL> return re . split ( r'<STR_LIT>' , '<STR_LIT>' . join ( usage_split [ <NUM_LIT:1> : ] ) ) [ <NUM_LIT:0> ] . strip ( ) <EOL> def formal_usage ( printable_usage ) : <EOL> pu = printable_usage . split ( ) [ <NUM_LIT:1> : ] <EOL> return '<STR_LIT:U+0020>' . join ( '<STR_LIT:|>' if s == pu [ <NUM_LIT:0> ] else s for s in pu [ <NUM_LIT:1> : ] ) <EOL> def extras ( help , version , options , doc ) : <EOL> if help and any ( ( o . name in ( '<STR_LIT>' , '<STR_LIT>' ) ) and o . value for o in options ) : <EOL> print ( doc . strip ( ) ) <EOL> exit ( ) <EOL> if version and any ( o . name == '<STR_LIT>' and o . value for o in options ) : <EOL> print ( version ) <EOL> exit ( ) <EOL> class Dict ( dict ) : <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' % '<STR_LIT>' . join ( '<STR_LIT>' % i for i in sorted ( self . items ( ) ) ) <EOL> def docopt ( doc , argv = sys . argv [ <NUM_LIT:1> : ] , help = True , version = None ) : <EOL> DocoptExit . usage = docopt . usage = usage = printable_usage ( doc ) <EOL> pot_options = parse_doc_options ( doc ) <EOL> formal_pattern = parse_pattern ( formal_usage ( usage ) , options = pot_options ) <EOL> argv = parse_args ( argv , options = pot_options ) <EOL> extras ( help , version , argv , doc ) <EOL> matched , left , arguments = formal_pattern . fix ( ) . match ( argv ) <EOL> if matched and left == [ ] : <EOL> options = [ o for o in argv if type ( o ) is Option ] <EOL> pot_arguments = [ a for a in formal_pattern . flat <EOL> if type ( a ) in [ Argument , Command ] ] <EOL> return Dict ( ( a . name , a . value ) for a in <EOL> ( pot_options + options + pot_arguments + arguments ) ) <EOL> raise DocoptExit ( ) </s>
