<s> import re <EOL> from jinja2 import TemplateNotFound , is_undefined <EOL> from markupsafe import Markup <EOL> from lektor . _compat import iteritems <EOL> from lektor . context import get_ctx <EOL> from lektor . environment import PRIMARY_ALT <EOL> from lektor . metaformat import tokenize <EOL> from lektor . types import Type <EOL> _block_re = re . compile ( r'<STR_LIT>' ) <EOL> _line_unescape_re = re . compile ( r'<STR_LIT>' ) <EOL> def discover_relevant_flowblock_models ( flow , pad , record , alt ) : <EOL> """<STR_LIT>""" <EOL> flow_blocks = flow . flow_blocks <EOL> all_blocks = pad . db . flowblocks <EOL> if flow_blocks is None : <EOL> return dict ( ( k , v . to_json ( pad , record , alt ) ) <EOL> for k , v in iteritems ( all_blocks ) ) <EOL> wanted_blocks = set ( ) <EOL> to_process = flow_blocks [ : ] <EOL> while to_process : <EOL> block_name = to_process . pop ( ) <EOL> flowblock = all_blocks . get ( block_name ) <EOL> if block_name in wanted_blocks or flowblock is None : <EOL> continue <EOL> wanted_blocks . add ( block_name ) <EOL> for field in flowblock . fields : <EOL> if isinstance ( field . type , FlowType ) : <EOL> if field . type . flow_blocks is None : <EOL> raise RuntimeError ( '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> to_process . extend ( field . type . flow_blocks ) <EOL> rv = { } <EOL> for block_name in wanted_blocks : <EOL> rv [ block_name ] = all_blocks [ block_name ] . to_json ( pad , record , alt ) <EOL> return rv <EOL> class BadFlowBlock ( Exception ) : <EOL> def __init__ ( self , message ) : <EOL> self . message = message <EOL> class FlowBlock ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , data , pad , record ) : <EOL> self . _data = data <EOL> self . _bound_data = { } <EOL> self . pad = pad <EOL> self . record = record <EOL> @ property <EOL> def flowblockmodel ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . pad . db . flowblocks [ self . _data [ '<STR_LIT>' ] ] <EOL> def __contains__ ( self , name ) : <EOL> return name in self . _data and not is_undefined ( self . _data [ name ] ) <EOL> def __getitem__ ( self , name ) : <EOL> ctx = get_ctx ( ) <EOL> if ctx is not None : <EOL> ctx . record_dependency ( self . flowblockmodel . filename ) <EOL> rv = self . _bound_data . get ( name , Ellipsis ) <EOL> if rv is not Ellipsis : <EOL> return rv <EOL> rv = self . _data [ name ] <EOL> if hasattr ( rv , '<STR_LIT>' ) : <EOL> rv = rv . __get__ ( self . record ) <EOL> self . _bound_data [ name ] = rv <EOL> return rv <EOL> def __html__ ( self ) : <EOL> ctx = get_ctx ( ) <EOL> if ctx is None or self in ctx . flow_block_render_stack : <EOL> return Markup . escape ( repr ( self ) ) <EOL> ctx . flow_block_render_stack . append ( self ) <EOL> try : <EOL> try : <EOL> return self . pad . db . env . render_template ( <EOL> [ '<STR_LIT>' % self . _data [ '<STR_LIT>' ] , <EOL> '<STR_LIT>' ] , <EOL> pad = self . pad , <EOL> this = self , <EOL> alt = self . record . alt , <EOL> values = { '<STR_LIT>' : self . record } <EOL> ) <EOL> except TemplateNotFound : <EOL> return Markup ( '<STR_LIT>' ) <EOL> finally : <EOL> ctx . flow_block_render_stack . pop ( ) <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' % ( <EOL> self . __class__ . __name__ , <EOL> self [ '<STR_LIT>' ] , <EOL> ) <EOL> class Flow ( object ) : <EOL> def __init__ ( self , blocks , record ) : <EOL> self . blocks = blocks <EOL> self . record = record <EOL> def __html__ ( self ) : <EOL> return Markup ( u'<STR_LIT>' . join ( x . __html__ ( ) for x in self . blocks ) ) <EOL> def __bool__ ( self ) : <EOL> return bool ( self . blocks ) <EOL> __nonzero__ = __bool__ <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' % ( <EOL> self . __class__ . __name__ , <EOL> self . blocks , <EOL> ) <EOL> class FlowDescriptor ( object ) : <EOL> def __init__ ( self , blocks , pad ) : <EOL> self . _blocks = blocks <EOL> self . _pad = pad <EOL> def __get__ ( self , obj , type = None ) : <EOL> if obj is None : <EOL> return self <EOL> return Flow ( [ FlowBlock ( data , self . _pad , obj ) <EOL> for data in self . _blocks ] , obj ) <EOL> def process_flowblock_data ( raw_value ) : <EOL> lineiter = iter ( raw_value . splitlines ( True ) ) <EOL> block = None <EOL> buf = [ ] <EOL> blocks = [ ] <EOL> for line in lineiter : <EOL> if block is None and not line . strip ( ) : <EOL> continue <EOL> block_start = _block_re . match ( line ) <EOL> if block_start is None : <EOL> if block is None : <EOL> raise BadFlowBlock ( '<STR_LIT>' ) <EOL> else : <EOL> if block is not None : <EOL> blocks . append ( ( block , buf ) ) <EOL> buf = [ ] <EOL> block = block_start . group ( <NUM_LIT:1> ) <EOL> continue <EOL> buf . append ( _line_unescape_re . sub ( '<STR_LIT>' , line ) ) <EOL> if block is not None : <EOL> blocks . append ( ( block , buf ) ) <EOL> return blocks <EOL> class FlowType ( Type ) : <EOL> widget = '<STR_LIT>' <EOL> def __init__ ( self , env , options ) : <EOL> Type . __init__ ( self , env , options ) <EOL> self . flow_blocks = [ <EOL> x . strip ( ) for x in options . get ( '<STR_LIT>' , '<STR_LIT>' ) . split ( '<STR_LIT:U+002C>' ) <EOL> if x . strip ( ) ] or None <EOL> def value_from_raw ( self , raw ) : <EOL> if raw . value is None : <EOL> return raw . missing_value ( '<STR_LIT>' ) <EOL> if raw . pad is None : <EOL> return raw . missing_value ( '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> db = raw . pad . db <EOL> rv = [ ] <EOL> try : <EOL> for block , block_lines in process_flowblock_data ( raw . value ) : <EOL> if self . flow_blocks is not None and block not in self . flow_blocks : <EOL> continue <EOL> flowblock = db . flowblocks . get ( block ) <EOL> if flowblock is None : <EOL> continue <EOL> d = { } <EOL> for key , lines in tokenize ( block_lines ) : <EOL> d [ key ] = u'<STR_LIT>' . join ( lines ) <EOL> rv . append ( flowblock . process_raw_data ( d , pad = raw . pad ) ) <EOL> except BadFlowBlock as e : <EOL> return raw . bad_value ( e . message ) <EOL> return FlowDescriptor ( rv , raw . pad ) <EOL> def to_json ( self , pad , record = None , alt = PRIMARY_ALT ) : <EOL> rv = Type . to_json ( self , pad , record , alt ) <EOL> rv [ '<STR_LIT>' ] = discover_relevant_flowblock_models ( <EOL> self , pad , record , alt ) <EOL> block_order = self . flow_blocks <EOL> if block_order is None : <EOL> block_order = [ k for k , v in sorted ( iteritems ( pad . db . flowblocks ) , <EOL> key = lambda x : x [ <NUM_LIT:1> ] . order ) ] <EOL> rv [ '<STR_LIT>' ] = block_order <EOL> return rv </s>
