<s> import itertools <EOL> import re <EOL> import codecs <EOL> from datetime import datetime , date <EOL> from pledger . account import AccountRepository , NamedAccount <EOL> from pledger . value import Value <EOL> from pledger . ledger import Ledger <EOL> from pledger . transaction import Transaction , UndefinedTransaction , UnbalancedTransaction <EOL> from pledger . directive import Directive , UnsupportedDirective <EOL> from pledger . entry import Entry <EOL> from pledger . util import PledgerException , itersplit <EOL> date_formats = { <EOL> "<STR_LIT:default>" : "<STR_LIT>" , <EOL> "<STR_LIT>" : "<STR_LIT>" , <EOL> "<STR_LIT>" : "<STR_LIT>" } <EOL> class MalformedHeader ( PledgerException ) : <EOL> pass <EOL> class Parser ( object ) : <EOL> def __init__ ( self ) : <EOL> self . accounts = AccountRepository ( ) <EOL> self . precision = <NUM_LIT:2> <EOL> def parse_account ( self , str ) : <EOL> return self . accounts [ str ] <EOL> def parse_value ( self , str ) : <EOL> return Value . parse ( str ) <EOL> def parse_ledger ( self , filename , str = None ) : <EOL> if str is None : <EOL> str = codecs . open ( filename , "<STR_LIT:r>" , "<STR_LIT:utf-8>" ) . read ( ) <EOL> f = lambda ( number , line ) : line == "<STR_LIT>" <EOL> lines = itertools . izip ( itertools . count ( <NUM_LIT:1> ) , str . split ( "<STR_LIT:\n>" ) ) <EOL> try : <EOL> transactions = [ self . parse_transaction ( group ) for group in itersplit ( f , lines ) ] <EOL> except PledgerException , e : <EOL> e . filename = filename <EOL> raise e <EOL> return Ledger ( filename , [ t for t in transactions if t ] , self ) <EOL> def parse_entry ( self , str ) : <EOL> tags = self . parse_tags ( str ) <EOL> str = re . sub ( "<STR_LIT>" , "<STR_LIT>" , str ) <EOL> elements = [ e for e in re . split ( r"<STR_LIT>" , str ) if e ] <EOL> if len ( elements ) >= <NUM_LIT:1> : <EOL> account = self . parse_account ( elements [ <NUM_LIT:0> ] ) <EOL> amount = None <EOL> if len ( elements ) >= <NUM_LIT:2> : <EOL> amount = self . parse_value ( elements [ <NUM_LIT:1> ] ) <EOL> if account : <EOL> return Entry ( account , amount , tags ) <EOL> def parse_transaction ( self , lines ) : <EOL> if hasattr ( lines , "<STR_LIT>" ) : <EOL> lines = list ( itertools . izip ( itertools . count ( <NUM_LIT:1> ) , iter ( lines . split ( "<STR_LIT:\n>" ) ) ) ) <EOL> tags = { } <EOL> while lines and re . match ( r'<STR_LIT>' , lines [ <NUM_LIT:0> ] [ <NUM_LIT:1> ] ) : <EOL> lines = lines [ <NUM_LIT:1> : ] <EOL> if len ( lines ) == <NUM_LIT:0> : <EOL> return None <EOL> n , header = lines [ <NUM_LIT:0> ] <EOL> lines = lines [ <NUM_LIT:1> : ] <EOL> if len ( header ) == <NUM_LIT:0> or header [ <NUM_LIT:0> ] == "<STR_LIT:=>" : <EOL> return None <EOL> directive = self . parse_directive ( header ) <EOL> if directive : return directive <EOL> if lines : <EOL> n , line = lines [ <NUM_LIT:0> ] <EOL> tags = self . parse_tags ( line , begin = True ) <EOL> if tags : lines = lines [ <NUM_LIT:1> : ] <EOL> try : <EOL> date , label , cleared = self . parse_header ( header ) <EOL> date = self . parse_date ( date ) <EOL> if date is None : <EOL> raise MalformedHeader ( ) <EOL> entries = [ self . parse_entry ( line ) for n , line in lines ] <EOL> line_numbers = [ n for n , line in lines ] <EOL> transaction = Transaction ( entries , date , label ) <EOL> if tags : transaction . tags = tags <EOL> if cleared : transaction . tags [ "<STR_LIT>" ] = True <EOL> return transaction <EOL> except UnbalancedTransaction , e : <EOL> e . line_number = n <EOL> raise e <EOL> except UndefinedTransaction , e : <EOL> e . line_number = line_numbers [ e . index ] <EOL> raise e <EOL> except MalformedHeader , e : <EOL> e . line_number = n <EOL> raise e <EOL> def parse_date ( self , str , format = "<STR_LIT:default>" ) : <EOL> try : <EOL> return datetime . strptime ( str , date_formats [ format ] ) . date ( ) <EOL> except ValueError : <EOL> pass <EOL> def parse_month ( self , str ) : <EOL> base = self . parse_date ( str , "<STR_LIT>" ) <EOL> if base : return date ( date . today ( ) . year , base . month , <NUM_LIT:1> ) <EOL> def parse_year ( self , str ) : <EOL> base = self . parse_date ( str , "<STR_LIT>" ) <EOL> if base : return date ( base . year , <NUM_LIT:1> , <NUM_LIT:1> ) <EOL> def parse_fuzzy_date ( self , str ) : <EOL> for parser in [ self . parse_date , self . parse_month , self . parse_year ] : <EOL> result = parser ( str ) <EOL> if result : return result <EOL> return None <EOL> def parse_header ( self , str ) : <EOL> m = re . match ( r'<STR_LIT>' , str ) <EOL> if m : <EOL> return m . group ( <NUM_LIT:1> ) , m . group ( <NUM_LIT:3> ) , m . group ( <NUM_LIT:2> ) <EOL> else : <EOL> raise MalformedHeader ( ) <EOL> def parse_tags ( self , str , begin = False ) : <EOL> pattern = r'<STR_LIT>' <EOL> if begin : <EOL> m = re . match ( pattern , str ) <EOL> else : <EOL> m = re . search ( pattern , str ) <EOL> if m : <EOL> tagstring = m . group ( <NUM_LIT:1> ) <EOL> tag_dict = [ ] <EOL> while True : <EOL> result = self . parse_tag ( tagstring ) <EOL> if result is None : break <EOL> tag , index = result <EOL> tag_dict . append ( tag ) <EOL> tagstring = tagstring [ index : ] <EOL> return dict ( tag_dict ) <EOL> def parse_tag ( self , str ) : <EOL> m = re . match ( r'<STR_LIT>' , str ) <EOL> if m : <EOL> return ( ( m . group ( <NUM_LIT:1> ) , m . group ( <NUM_LIT:2> ) ) , m . end ( ) ) <EOL> m = re . match ( r"<STR_LIT>" , str ) <EOL> if m : <EOL> return ( ( m . group ( <NUM_LIT:1> ) , m . group ( <NUM_LIT:2> ) ) , m . end ( ) ) <EOL> m = re . match ( r'<STR_LIT>' , str ) <EOL> if m : <EOL> return ( ( m . group ( <NUM_LIT:1> ) , m . group ( <NUM_LIT:2> ) ) , m . end ( ) ) <EOL> m = re . match ( r'<STR_LIT>' , str ) <EOL> if m : <EOL> try : <EOL> return ( ( "<STR_LIT:date>" , self . parse_date ( m . group ( <NUM_LIT:1> ) ) ) , m . end ( ) ) <EOL> except ValueError : <EOL> pass <EOL> def parse_directive ( self , str ) : <EOL> if str [ <NUM_LIT:0> ] == '<STR_LIT:!>' : <EOL> args = str [ <NUM_LIT:1> : ] . split ( '<STR_LIT:U+0020>' ) <EOL> name = args [ <NUM_LIT:0> ] <EOL> args = args [ <NUM_LIT:1> : ] <EOL> directive_class = Directive . directives . get ( name ) <EOL> if directive_class : <EOL> return directive_class ( * args ) <EOL> else : <EOL> raise UnsupportedDirective ( name ) </s>
