<s> import six <EOL> from collections import defaultdict <EOL> from nplusone . core import signals <EOL> class Rule ( object ) : <EOL> def __init__ ( self , label = None , model = None , field = None ) : <EOL> self . label = label <EOL> self . model = model <EOL> self . field = field <EOL> def compare ( self , label , model , field ) : <EOL> return ( <EOL> ( self . label or self . model or self . field ) and <EOL> ( self . label is None or self . label == label ) and <EOL> ( self . model is None or self . match_model ( model ) ) and <EOL> ( self . field is None or self . field == field ) <EOL> ) <EOL> def match_model ( self , model ) : <EOL> return ( <EOL> self . model is model or ( <EOL> isinstance ( self . model , six . string_types ) and <EOL> self . model == model . __name__ <EOL> ) <EOL> ) <EOL> class Message ( object ) : <EOL> label = '<STR_LIT>' <EOL> formatter = '<STR_LIT>' <EOL> def __init__ ( self , model , field ) : <EOL> self . model = model <EOL> self . field = field <EOL> @ property <EOL> def message ( self ) : <EOL> return self . formatter . format ( <EOL> label = self . label , <EOL> model = self . model . __name__ , <EOL> field = self . field , <EOL> ) <EOL> def match ( self , rules ) : <EOL> return any ( <EOL> rule . compare ( self . label , self . model , self . field ) <EOL> for rule in rules <EOL> ) <EOL> class LazyLoadMessage ( Message ) : <EOL> label = '<STR_LIT>' <EOL> formatter = '<STR_LIT>' <EOL> class EagerLoadMessage ( Message ) : <EOL> label = '<STR_LIT>' <EOL> formatter = '<STR_LIT>' <EOL> class Listener ( object ) : <EOL> def __init__ ( self , parent ) : <EOL> self . parent = parent <EOL> def setup ( self ) : <EOL> pass <EOL> def teardown ( self ) : <EOL> pass <EOL> class LazyListener ( Listener ) : <EOL> def setup ( self ) : <EOL> self . loaded = set ( ) <EOL> signals . load . connect ( self . handle_load , sender = signals . get_worker ( ) ) <EOL> signals . lazy_load . connect ( self . handle_lazy , sender = signals . get_worker ( ) ) <EOL> def handle_load ( self , caller , args = None , kwargs = None , context = None , ret = None , <EOL> parser = None ) : <EOL> instances = parser ( args , kwargs , context , ret ) <EOL> self . loaded . update ( instances ) <EOL> def handle_lazy ( self , caller , args = None , kwargs = None , context = None , parser = None ) : <EOL> model , instance , field = parser ( args , kwargs , context ) <EOL> if instance in self . loaded : <EOL> message = LazyLoadMessage ( model , field ) <EOL> self . parent . notify ( message ) <EOL> class EagerListener ( Listener ) : <EOL> def setup ( self ) : <EOL> signals . eager_load . connect ( self . handle_eager , sender = signals . get_worker ( ) ) <EOL> self . tracker = EagerTracker ( ) <EOL> self . touched = [ ] <EOL> def teardown ( self ) : <EOL> self . log_eager ( ) <EOL> def handle_eager ( self , caller , args = None , kwargs = None , context = None , parser = None ) : <EOL> self . tracker . track ( * parser ( args , kwargs , context ) ) <EOL> signals . touch . connect ( self . handle_touch , sender = signals . get_worker ( ) ) <EOL> def handle_touch ( self , caller , args = None , kwargs = None , context = None , parser = None ) : <EOL> self . touched . append ( parser ( args , kwargs , context ) ) <EOL> def log_eager ( self ) : <EOL> self . tracker . prune ( [ each for each in self . touched if each ] ) <EOL> for model , field in self . tracker . unused : <EOL> message = EagerLoadMessage ( model , field ) <EOL> self . parent . notify ( message ) <EOL> class EagerTracker ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self ) : <EOL> self . data = defaultdict ( lambda : defaultdict ( set ) ) <EOL> def track ( self , model , field , instances , key ) : <EOL> self . data [ ( model , field ) ] [ key ] . update ( instances ) <EOL> def prune ( self , touched ) : <EOL> for model , field , touch_instances in touched : <EOL> group = self . data [ ( model , field ) ] <EOL> for key , fetch_instances in list ( group . items ( ) ) : <EOL> if touch_instances and fetch_instances . intersection ( touch_instances ) : <EOL> group . pop ( key , None ) <EOL> @ property <EOL> def unused ( self ) : <EOL> return [ <EOL> ( model , field ) <EOL> for ( model , field ) , group in self . data . items ( ) <EOL> if group <EOL> ] <EOL> listeners = { <EOL> '<STR_LIT>' : LazyListener , <EOL> '<STR_LIT>' : EagerListener , <EOL> } </s>
