<s> """<STR_LIT>""" <EOL> import re <EOL> import sys <EOL> __all__ = [ '<STR_LIT>' ] <EOL> __version__ = '<STR_LIT>' <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 __eq__ ( self , other ) : <EOL> return repr ( self ) == repr ( other ) <EOL> def __hash__ ( self ) : <EOL> return hash ( repr ( self ) ) <EOL> def fix ( self ) : <EOL> self . fix_identities ( ) <EOL> self . fix_repeating_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 is 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_repeating_arguments ( self ) : <EOL> """<STR_LIT>""" <EOL> either = [ list ( c . children ) for c in self . either . children ] <EOL> for case in either : <EOL> for e in [ c for c in case if case . count ( c ) > <NUM_LIT:1> ] : <EOL> if type ( e ) is Argument or type ( e ) is Option and e . argcount : <EOL> if e . value is None : <EOL> e . value = [ ] <EOL> elif type ( e . value ) is not list : <EOL> e . value = e . value . split ( ) <EOL> if type ( e ) is Command or type ( e ) is Option and e . argcount == <NUM_LIT:0> : <EOL> e . value = <NUM_LIT:0> <EOL> return self <EOL> @ property <EOL> def either ( self ) : <EOL> """<STR_LIT>""" <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 AnyOptions in types : <EOL> optional = [ c for c in children if type ( c ) is AnyOptions ] [ <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 ChildPattern ( Pattern ) : <EOL> def __init__ ( self , name , value = None ) : <EOL> self . name = name <EOL> self . value = value <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' % ( self . __class__ . __name__ , self . name , self . value ) <EOL> def flat ( self , * types ) : <EOL> return [ self ] if not types or type ( self ) in types else [ ] <EOL> def match ( self , left , collected = None ) : <EOL> collected = [ ] if collected is None else collected <EOL> pos , match = self . single_match ( left ) <EOL> if match is None : <EOL> return False , left , collected <EOL> left_ = left [ : pos ] + left [ pos + <NUM_LIT:1> : ] <EOL> same_name = [ a for a in collected if a . name == self . name ] <EOL> if type ( self . value ) in ( int , list ) : <EOL> if type ( self . value ) is int : <EOL> increment = <NUM_LIT:1> <EOL> else : <EOL> increment = ( [ match . value ] if type ( match . value ) is str <EOL> else match . value ) <EOL> if not same_name : <EOL> match . value = increment <EOL> return True , left_ , collected + [ match ] <EOL> same_name [ <NUM_LIT:0> ] . value += increment <EOL> return True , left_ , collected <EOL> return True , left_ , collected + [ match ] <EOL> class ParentPattern ( Pattern ) : <EOL> def __init__ ( self , * children ) : <EOL> self . children = list ( children ) <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> def flat ( self , * types ) : <EOL> if type ( self ) in types : <EOL> return [ self ] <EOL> return sum ( [ c . flat ( * types ) for c in self . children ] , [ ] ) <EOL> class Argument ( ChildPattern ) : <EOL> def single_match ( self , left ) : <EOL> for n , p in enumerate ( left ) : <EOL> if type ( p ) is Argument : <EOL> return n , Argument ( self . name , p . value ) <EOL> return None , None <EOL> @ classmethod <EOL> def parse ( class_ , source ) : <EOL> name = re . findall ( '<STR_LIT>' , source ) [ <NUM_LIT:0> ] <EOL> value = re . findall ( '<STR_LIT>' , source , flags = re . I ) <EOL> return class_ ( name , value [ <NUM_LIT:0> ] if value else None ) <EOL> class Command ( Argument ) : <EOL> def __init__ ( self , name , value = False ) : <EOL> self . name = name <EOL> self . value = value <EOL> def single_match ( self , left ) : <EOL> for n , p in enumerate ( left ) : <EOL> if type ( p ) is Argument : <EOL> if p . value == self . name : <EOL> return n , Command ( self . name , True ) <EOL> else : <EOL> break <EOL> return None , None <EOL> class Option ( ChildPattern ) : <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 is 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 single_match ( self , left ) : <EOL> for n , p in enumerate ( left ) : <EOL> if self . name == p . name : <EOL> return n , p <EOL> return None , None <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 Required ( ParentPattern ) : <EOL> def match ( self , left , collected = None ) : <EOL> collected = [ ] if collected is None else collected <EOL> l = left <EOL> c = 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 ( ParentPattern ) : <EOL> def match ( self , left , collected = None ) : <EOL> collected = [ ] if collected is None else collected <EOL> for p in self . children : <EOL> m , left , collected = p . match ( left , collected ) <EOL> return True , left , collected <EOL> class AnyOptions ( Optional ) : <EOL> """<STR_LIT>""" <EOL> class OneOrMore ( ParentPattern ) : <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 = left <EOL> c = 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_ = l <EOL> if times >= <NUM_LIT:1> : <EOL> return True , l , c <EOL> return False , left , collected <EOL> class Either ( ParentPattern ) : <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 ( left , 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 hasattr ( source , '<STR_LIT>' ) 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> """<STR_LIT>""" <EOL> long , eq , value = tokens . move ( ) . partition ( '<STR_LIT:=>' ) <EOL> assert long . startswith ( '<STR_LIT>' ) <EOL> value = None if eq == value == '<STR_LIT>' else value <EOL> similar = [ o for o in options if o . long == long ] <EOL> if tokens . error is DocoptExit and similar == [ ] : <EOL> similar = [ o for o in options if o . long and o . long . startswith ( long ) ] <EOL> if len ( similar ) > <NUM_LIT:1> : <EOL> raise tokens . error ( '<STR_LIT>' % <EOL> ( long , '<STR_LIT:U+002CU+0020>' . join ( o . long for o in similar ) ) ) <EOL> elif len ( similar ) < <NUM_LIT:1> : <EOL> argcount = <NUM_LIT:1> if eq == '<STR_LIT:=>' else <NUM_LIT:0> <EOL> o = Option ( None , long , argcount ) <EOL> options . append ( o ) <EOL> if tokens . error is DocoptExit : <EOL> o = Option ( None , long , argcount , value if argcount else True ) <EOL> else : <EOL> o = Option ( similar [ <NUM_LIT:0> ] . short , similar [ <NUM_LIT:0> ] . long , <EOL> similar [ <NUM_LIT:0> ] . argcount , similar [ <NUM_LIT:0> ] . value ) <EOL> if o . argcount == <NUM_LIT:0> : <EOL> if value is not None : <EOL> raise tokens . error ( '<STR_LIT>' % o . long ) <EOL> else : <EOL> if value is None : <EOL> if tokens . current ( ) is None : <EOL> raise tokens . error ( '<STR_LIT>' % o . long ) <EOL> value = tokens . move ( ) <EOL> if tokens . error is DocoptExit : <EOL> o . value = value if value is not None else True <EOL> return [ o ] <EOL> def parse_shorts ( tokens , options ) : <EOL> """<STR_LIT>""" <EOL> token = tokens . move ( ) <EOL> assert token . startswith ( '<STR_LIT:->' ) and not token . startswith ( '<STR_LIT>' ) <EOL> left = token . lstrip ( '<STR_LIT:->' ) <EOL> parsed = [ ] <EOL> while left != '<STR_LIT>' : <EOL> short , left = '<STR_LIT:->' + left [ <NUM_LIT:0> ] , left [ <NUM_LIT:1> : ] <EOL> similar = [ o for o in options if o . short == short ] <EOL> if len ( similar ) > <NUM_LIT:1> : <EOL> raise tokens . error ( '<STR_LIT>' % <EOL> ( short , len ( similar ) ) ) <EOL> elif len ( similar ) < <NUM_LIT:1> : <EOL> o = Option ( short , None , <NUM_LIT:0> ) <EOL> options . append ( o ) <EOL> if tokens . error is DocoptExit : <EOL> o = Option ( short , None , <NUM_LIT:0> , True ) <EOL> else : <EOL> o = Option ( short , similar [ <NUM_LIT:0> ] . long , <EOL> similar [ <NUM_LIT:0> ] . argcount , similar [ <NUM_LIT:0> ] . value ) <EOL> value = None <EOL> if o . argcount != <NUM_LIT:0> : <EOL> if left == '<STR_LIT>' : <EOL> if tokens . current ( ) is None : <EOL> raise tokens . error ( '<STR_LIT>' % short ) <EOL> value = tokens . move ( ) <EOL> else : <EOL> value = left <EOL> left = '<STR_LIT>' <EOL> if tokens . error is DocoptExit : <EOL> o . value = value if value is not None else True <EOL> parsed . append ( o ) <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 in '<STR_LIT>' : <EOL> tokens . move ( ) <EOL> matching , pattern = { '<STR_LIT:(>' : [ '<STR_LIT:)>' , Required ] , '<STR_LIT:[>' : [ '<STR_LIT:]>' , Optional ] } [ token ] <EOL> result = pattern ( * parse_expr ( tokens , options ) ) <EOL> if tokens . move ( ) != matching : <EOL> raise tokens . error ( "<STR_LIT>" % token ) <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_argv ( tokens , options , options_first = False ) : <EOL> """<STR_LIT>""" <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> elif options_first : <EOL> return parsed + [ Argument ( None , v ) for v in tokens ] <EOL> else : <EOL> parsed . append ( Argument ( None , tokens . move ( ) ) ) <EOL> return parsed <EOL> def parse_defaults ( doc ) : <EOL> split = re . split ( '<STR_LIT>' , doc ) [ <NUM_LIT:1> : ] <EOL> split = [ s1 + s2 for s1 , s2 in zip ( split [ : : <NUM_LIT:2> ] , split [ <NUM_LIT:1> : : <NUM_LIT:2> ] ) ] <EOL> options = [ Option . parse ( s ) for s in split if s . startswith ( '<STR_LIT:->' ) ] <EOL> return options <EOL> def printable_usage ( doc ) : <EOL> usage_pattern = re . compile ( r'<STR_LIT>' , re . IGNORECASE ) <EOL> usage_split = re . split ( usage_pattern , 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>' + '<STR_LIT:U+0020>' . join ( '<STR_LIT>' if s == pu [ <NUM_LIT:0> ] else s for s in pu [ <NUM_LIT:1> : ] ) + '<STR_LIT>' <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 ( "<STR_LIT:\n>" ) ) <EOL> sys . exit ( ) <EOL> if version and any ( o . name == '<STR_LIT>' and o . value for o in options ) : <EOL> print ( version ) <EOL> sys . 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 = None , help = True , version = None , options_first = False ) : <EOL> """<STR_LIT>""" <EOL> if argv is None : <EOL> argv = sys . argv [ <NUM_LIT:1> : ] <EOL> DocoptExit . usage = printable_usage ( doc ) <EOL> options = parse_defaults ( doc ) <EOL> pattern = parse_pattern ( formal_usage ( DocoptExit . usage ) , options ) <EOL> argv = parse_argv ( TokenStream ( argv , DocoptExit ) , list ( options ) , <EOL> options_first ) <EOL> pattern_options = set ( pattern . flat ( Option ) ) <EOL> for ao in pattern . flat ( AnyOptions ) : <EOL> doc_options = parse_defaults ( doc ) <EOL> ao . children = list ( set ( doc_options ) - pattern_options ) <EOL> extras ( help , version , argv , doc ) <EOL> matched , left , collected = pattern . fix ( ) . match ( argv ) <EOL> if matched and left == [ ] : <EOL> return Dict ( ( a . name , a . value ) for a in ( pattern . flat ( ) + collected ) ) <EOL> if left and left [ <NUM_LIT:0> ] . name is not None : <EOL> msg = "<STR_LIT>" % left [ <NUM_LIT:0> ] . name <EOL> else : <EOL> msg = "<STR_LIT>" <EOL> raise DocoptExit ( msg ) </s>
