<s> import re <EOL> import operator <EOL> from functools import reduce <EOL> class ChecksumError ( ValueError ) : <EOL> '''<STR_LIT>''' <EOL> class ParseError ( ValueError ) : <EOL> '''<STR_LIT>''' <EOL> class SentenceTypeError ( ValueError ) : <EOL> '''<STR_LIT>''' <EOL> class NMEASentenceType ( type ) : <EOL> sentence_types = { } <EOL> def __init__ ( cls , name , bases , dct ) : <EOL> type . __init__ ( cls , name , bases , dct ) <EOL> base = bases [ <NUM_LIT:0> ] <EOL> if base is object : <EOL> return <EOL> base . sentence_types [ name ] = cls <EOL> cls . name_to_idx = dict ( ( f [ <NUM_LIT:1> ] , i ) for i , f in enumerate ( cls . fields ) ) <EOL> NMEASentenceBase = NMEASentenceType ( '<STR_LIT>' , ( object , ) , { } ) <EOL> class NMEASentence ( NMEASentenceBase ) : <EOL> '''<STR_LIT>''' <EOL> sentence_re = re . compile ( r'''<STR_LIT>''' , re . X | re . IGNORECASE ) <EOL> talker_re = re . compile ( r'<STR_LIT>' ) <EOL> query_re = re . compile ( r'<STR_LIT>' ) <EOL> proprietary_re = re . compile ( r'<STR_LIT>' ) <EOL> name_to_idx = { } <EOL> fields = ( ) <EOL> @ staticmethod <EOL> def checksum ( nmea_str ) : <EOL> return reduce ( operator . xor , map ( ord , nmea_str ) , <NUM_LIT:0> ) <EOL> @ staticmethod <EOL> def parse ( line ) : <EOL> '''<STR_LIT>''' <EOL> match = NMEASentence . sentence_re . match ( line ) <EOL> if not match : <EOL> raise ParseError ( '<STR_LIT>' % line ) <EOL> nmea_str = match . group ( '<STR_LIT>' ) <EOL> data_str = match . group ( '<STR_LIT:data>' ) <EOL> checksum = match . group ( '<STR_LIT>' ) <EOL> sentence_type = match . group ( '<STR_LIT>' ) . upper ( ) <EOL> data = data_str . split ( '<STR_LIT:U+002C>' ) <EOL> if checksum : <EOL> cs1 = int ( checksum , <NUM_LIT:16> ) <EOL> cs2 = NMEASentence . checksum ( nmea_str ) <EOL> if cs1 != cs2 : <EOL> raise ChecksumError ( <EOL> '<STR_LIT>' % ( cs1 , cs2 ) ) <EOL> talker_match = NMEASentence . talker_re . match ( sentence_type ) <EOL> if talker_match : <EOL> talker = talker_match . group ( '<STR_LIT>' ) <EOL> sentence = talker_match . group ( '<STR_LIT>' ) <EOL> cls = TalkerSentence . sentence_types . get ( sentence ) <EOL> if not cls : <EOL> raise SentenceTypeError ( '<STR_LIT>' % sentence_type ) <EOL> return cls ( talker , sentence , data ) <EOL> query_match = NMEASentence . query_re . match ( sentence_type ) <EOL> if query_match and not data_str : <EOL> talker = query_match . group ( '<STR_LIT>' ) <EOL> listener = query_match . group ( '<STR_LIT>' ) <EOL> sentence = query_match . group ( '<STR_LIT>' ) <EOL> return QuerySentence ( talker , listener , sentence ) <EOL> proprietary_match = NMEASentence . proprietary_re . match ( sentence_type ) <EOL> if proprietary_match : <EOL> manufacturer = proprietary_match . group ( '<STR_LIT>' ) <EOL> cls = ProprietarySentence . sentence_types . get ( manufacturer , ProprietarySentence ) <EOL> return cls ( manufacturer , data ) <EOL> raise ParseError ( '<STR_LIT>' % sentence_type ) <EOL> def __getattr__ ( self , name ) : <EOL> t = type ( self ) <EOL> try : <EOL> i = t . name_to_idx [ name ] <EOL> except KeyError : <EOL> raise AttributeError ( name ) <EOL> f = t . fields [ i ] <EOL> if i < len ( self . data ) : <EOL> v = self . data [ i ] <EOL> else : <EOL> v = '<STR_LIT>' <EOL> if len ( f ) >= <NUM_LIT:3> : <EOL> if v == '<STR_LIT>' : <EOL> return None <EOL> return f [ <NUM_LIT:2> ] ( v ) <EOL> else : <EOL> return v <EOL> def __setattr__ ( self , name , value ) : <EOL> t = type ( self ) <EOL> if name not in t . name_to_idx : <EOL> return object . __setattr__ ( self , name , value ) <EOL> i = t . name_to_idx [ name ] <EOL> self . data [ i ] = str ( value ) <EOL> def __repr__ ( self ) : <EOL> r = [ ] <EOL> d = [ ] <EOL> t = type ( self ) <EOL> for i , v in enumerate ( self . data ) : <EOL> if i >= len ( t . fields ) : <EOL> d . append ( v ) <EOL> continue <EOL> name = t . fields [ i ] [ <NUM_LIT:1> ] <EOL> r . append ( '<STR_LIT>' % ( name , getattr ( self , name ) ) ) <EOL> return '<STR_LIT>' % ( <EOL> type ( self ) . __name__ , <EOL> '<STR_LIT:U+002CU+0020>' . join ( r ) , <EOL> d and '<STR_LIT>' % d or '<STR_LIT>' <EOL> ) <EOL> def identifier ( self ) : <EOL> raise NotImplementedError <EOL> def render ( self , checksum = True , dollar = True , newline = False ) : <EOL> res = self . identifier ( ) + '<STR_LIT:U+002C>' . join ( self . data ) <EOL> if checksum : <EOL> res += '<STR_LIT>' % NMEASentence . checksum ( res ) <EOL> if dollar : <EOL> res = '<STR_LIT:$>' + res <EOL> if newline : <EOL> res += ( newline is True ) and '<STR_LIT:\r\n>' or newline <EOL> return res <EOL> def __str__ ( self ) : <EOL> return self . render ( ) <EOL> class TalkerSentence ( NMEASentence ) : <EOL> sentence_types = { } <EOL> def __init__ ( self , talker , sentence_type , data ) : <EOL> self . talker = talker <EOL> self . sentence_type = sentence_type <EOL> self . data = list ( data ) <EOL> def identifier ( self ) : <EOL> return '<STR_LIT>' % ( self . talker , self . sentence_type ) <EOL> class QuerySentence ( NMEASentence ) : <EOL> sentence_types = { } <EOL> def __init__ ( self , talker , listener , sentence_type ) : <EOL> self . talker = talker <EOL> self . listener = listener <EOL> self . sentence_type = sentence_type <EOL> self . data = [ ] <EOL> def identifier ( self ) : <EOL> return '<STR_LIT>' % ( self . talker , self . listener , self . sentence_type ) <EOL> class ProprietarySentence ( NMEASentence ) : <EOL> sentence_types = { } <EOL> def __init__ ( self , manufacturer , data ) : <EOL> self . manufacturer = manufacturer <EOL> self . data = list ( data ) <EOL> def identifier ( self ) : <EOL> return '<STR_LIT>' % ( self . manufacturer ) </s>
