<s> import base64 <EOL> import json <EOL> import os <EOL> import time <EOL> SLEEP_TIME = <NUM_LIT:0.1> <EOL> class Cache ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , source , cache_dir ) : <EOL> """<STR_LIT>""" <EOL> if not os . path . isfile ( source ) : <EOL> raise MissingSource <EOL> if not os . path . exists ( cache_dir ) : <EOL> raise MissingCacheDir <EOL> self . timestamp = None <EOL> self . data = dict ( ) <EOL> self . source_path = os . path . abspath ( source ) <EOL> cache_name = base64 . urlsafe_b64encode ( self . source_path ) + '<STR_LIT>' <EOL> lock_name = base64 . urlsafe_b64encode ( self . source_path ) + '<STR_LIT>' <EOL> cache_path = os . path . abspath ( cache_dir ) <EOL> self . cache_path = os . path . join ( cache_path , cache_name ) <EOL> self . lock_path = os . path . join ( cache_path , lock_name ) <EOL> def read ( self ) : <EOL> """<STR_LIT>""" <EOL> if not os . path . isfile ( self . cache_path ) : <EOL> raise NoCache <EOL> while self . islocked ( ) : <EOL> time . sleep ( SLEEP_TIME ) <EOL> self . lock ( ) <EOL> try : <EOL> with open ( self . cache_path , '<STR_LIT:r>' ) as fp : <EOL> on_disk = json . load ( fp ) <EOL> self . timestamp = on_disk [ <NUM_LIT:0> ] <EOL> self . data = on_disk [ <NUM_LIT:1> ] <EOL> finally : <EOL> self . unlock ( ) <EOL> if self . timestamp != os . path . getmtime ( self . source_path ) : <EOL> raise OutdatedCache <EOL> def update ( self , update_fun ) : <EOL> """<STR_LIT>""" <EOL> self . data = update_fun ( self . source_path ) <EOL> self . timestamp = os . path . getmtime ( self . source_path ) <EOL> def write ( self ) : <EOL> """<STR_LIT>""" <EOL> if not self . timestamp : <EOL> raise WriteUnfilledCache <EOL> while self . islocked ( ) : <EOL> time . sleep ( SLEEP_TIME ) <EOL> self . lock ( ) <EOL> try : <EOL> with open ( self . cache_path , '<STR_LIT:w>' ) as fp : <EOL> json . dump ( [ self . timestamp , self . data ] , fp ) <EOL> fp . flush ( ) <EOL> finally : <EOL> self . unlock ( ) <EOL> def lock ( self ) : <EOL> """<STR_LIT>""" <EOL> if self . islocked ( ) : <EOL> raise AttemptedLockingLocked <EOL> open ( self . lock_path , '<STR_LIT:a>' ) . close ( ) <EOL> def unlock ( self ) : <EOL> """<STR_LIT>""" <EOL> if not self . islocked ( ) : <EOL> raise AttemptedUnlockingUnlocked <EOL> os . remove ( self . lock_path ) <EOL> def islocked ( self ) : <EOL> """<STR_LIT>""" <EOL> if os . path . isfile ( self . lock_path ) : <EOL> return True <EOL> return False <EOL> class NoCache ( Exception ) : <EOL> """<STR_LIT>""" <EOL> pass <EOL> class OutdatedCache ( Exception ) : <EOL> """<STR_LIT>""" <EOL> pass <EOL> class MissingSource ( Exception ) : <EOL> """<STR_LIT>""" <EOL> pass <EOL> class MissingCacheDir ( Exception ) : <EOL> """<STR_LIT>""" <EOL> pass <EOL> class AttemptedLockingLocked ( Exception ) : <EOL> """<STR_LIT>""" <EOL> pass <EOL> class AttemptedUnlockingUnlocked ( Exception ) : <EOL> """<STR_LIT>""" <EOL> pass <EOL> class WriteUnfilledCache ( Exception ) : <EOL> """<STR_LIT>""" <EOL> pass </s>
