comparison piecrust/data/debug.py @ 5:474c9882decf

Upgrade to Python 3.
author Ludovic Chabant <ludovic@chabant.com>
date Mon, 11 Aug 2014 22:36:47 -0700
parents f485ba500df3
children 343d08ef5668
comparison
equal deleted inserted replaced
4:7dc71c2dc9a8 5:474c9882decf
1 import re 1 import re
2 import cgi 2 import cgi
3 import logging 3 import logging
4 import StringIO 4 import io
5 from piecrust import APP_VERSION, PIECRUST_URL 5 from piecrust import APP_VERSION, PIECRUST_URL
6 import collections
6 7
7 8
8 logger = logging.getLogger(__name__) 9 logger = logging.getLogger(__name__)
9 10
10 11
47 48
48 49
49 def build_debug_info(page, data): 50 def build_debug_info(page, data):
50 """ Generates HTML debug info for the given page's data. 51 """ Generates HTML debug info for the given page's data.
51 """ 52 """
52 output = StringIO.StringIO() 53 output = io.StringIO()
53 try: 54 try:
54 _do_build_debug_info(page, data, output) 55 _do_build_debug_info(page, data, output)
55 return output.getvalue() 56 return output.getvalue()
56 finally: 57 finally:
57 output.close() 58 output.close()
59 60
60 def _do_build_debug_info(page, data, output): 61 def _do_build_debug_info(page, data, output):
61 app = page.app 62 app = page.app
62 exec_info = app.env.exec_info_stack.current_page_info 63 exec_info = app.env.exec_info_stack.current_page_info
63 64
64 print >>output, '<div id="piecrust-debug-info" style="%s">' % CSS_DEBUGINFO 65 print('<div id="piecrust-debug-info" style="%s">' % CSS_DEBUGINFO, file=output)
65 66
66 print >>output, '<div>' 67 print('<div>', file=output)
67 print >>output, '<p style="%s"><strong>PieCrust %s</strong> &mdash; ' % (CSS_P, APP_VERSION) 68 print('<p style="%s"><strong>PieCrust %s</strong> &mdash; ' % (CSS_P, APP_VERSION), file=output)
68 69
69 # If we have some execution info in the environment, 70 # If we have some execution info in the environment,
70 # add more information. 71 # add more information.
71 if exec_info: 72 if exec_info:
72 if exec_info.was_cache_valid: 73 if exec_info.was_cache_valid:
89 if app.env.start_time != 0: 90 if app.env.start_time != 0:
90 output.write('in __PIECRUST_TIMING_INFORMATION__') 91 output.write('in __PIECRUST_TIMING_INFORMATION__')
91 else: 92 else:
92 output.write('no timing information available') 93 output.write('no timing information available')
93 94
94 print >>output, '</p>' 95 print('</p>', file=output)
95 print >>output, '</div>' 96 print('</div>', file=output)
96 97
97 if data: 98 if data:
98 print >>output, '<div>' 99 print('<div>', file=output)
99 print >>output, ('<p style="%s cursor: pointer;" onclick="var l = ' 100 print(('<p style="%s cursor: pointer;" onclick="var l = '
100 'document.getElementById(\'piecrust-debug-details\'); ' 101 'document.getElementById(\'piecrust-debug-details\'); '
101 'if (l.style.display == \'none\') l.style.display = ' 102 'if (l.style.display == \'none\') l.style.display = '
102 '\'block\'; else l.style.display = \'none\';">' % CSS_P) 103 '\'block\'; else l.style.display = \'none\';">' % CSS_P), file=output)
103 print >>output, ('<span style="%s">Template engine data</span> ' 104 print(('<span style="%s">Template engine data</span> '
104 '&mdash; click to toggle</a>.</p>' % CSS_BIGHEADER) 105 '&mdash; click to toggle</a>.</p>' % CSS_BIGHEADER), file=output)
105 106
106 print >>output, '<div id="piecrust-debug-details" style="display: none;">' 107 print('<div id="piecrust-debug-details" style="display: none;">', file=output)
107 print >>output, ('<p style="%s">The following key/value pairs are ' 108 print(('<p style="%s">The following key/value pairs are '
108 'available in the layout\'s markup, and most are ' 109 'available in the layout\'s markup, and most are '
109 'available in the page\'s markup.</p>' % CSS_DOC) 110 'available in the page\'s markup.</p>' % CSS_DOC), file=output)
110 111
111 filtered_data = dict(data) 112 filtered_data = dict(data)
112 for k in filtered_data.keys(): 113 for k in list(filtered_data.keys()):
113 if k.startswith('__'): 114 if k.startswith('__'):
114 del filtered_data[k] 115 del filtered_data[k]
115 116
116 renderer = DebugDataRenderer(output) 117 renderer = DebugDataRenderer(output)
117 renderer.external_docs['data-site'] = ( 118 renderer.external_docs['data-site'] = (
118 "This section comes from the site configuration file.") 119 "This section comes from the site configuration file.")
119 renderer.external_docs['data-page'] = ( 120 renderer.external_docs['data-page'] = (
120 "This section comes from the page's configuration header.") 121 "This section comes from the page's configuration header.")
121 renderer.renderData(filtered_data) 122 renderer.renderData(filtered_data)
122 123
123 print >>output, '</div>' 124 print('</div>', file=output)
124 print >>output, '</div>' 125 print('</div>', file=output)
125 126
126 print >>output, '</div>' 127 print('</div>', file=output)
127 128
128 129
129 class DebugDataRenderer(object): 130 class DebugDataRenderer(object):
130 MAX_VALUE_LENGTH = 150 131 MAX_VALUE_LENGTH = 150
131 132
172 173
173 if data_type is float: 174 if data_type is float:
174 self._write('<span style="%s">%4.2f</span>' % (CSS_VALUE, data)) 175 self._write('<span style="%s">%4.2f</span>' % (CSS_VALUE, data))
175 return 176 return
176 177
177 if data_type in (str, unicode): 178 if data_type in (str, str):
178 if data_type == str: 179 if data_type == str:
179 data = data.decode('utf8') 180 data = data.decode('utf8')
180 if len(data) > DebugDataRenderer.MAX_VALUE_LENGTH: 181 if len(data) > DebugDataRenderer.MAX_VALUE_LENGTH:
181 data = data[:DebugDataRenderer.MAX_VALUE_LENGTH - 5] 182 data = data[:DebugDataRenderer.MAX_VALUE_LENGTH - 5]
182 data += '[...]' 183 data += '[...]'
201 def _renderDict(self, data, path): 202 def _renderDict(self, data, path):
202 self._writeLine('<div style="%s">' % CSS_DATABLOCK) 203 self._writeLine('<div style="%s">' % CSS_DATABLOCK)
203 self._renderDoc(data, path) 204 self._renderDoc(data, path)
204 self._renderAttributes(data, path) 205 self._renderAttributes(data, path)
205 rendered_count = self._renderIterable(data, path, 206 rendered_count = self._renderIterable(data, path,
206 lambda d: sorted(d.iteritems(), key=lambda i: i[0])) 207 lambda d: sorted(iter(d.items()), key=lambda i: i[0]))
207 if rendered_count == 0: 208 if rendered_count == 0:
208 self._writeLine('<p style="%s %s">(empty dictionary)</p>' % (CSS_P, CSS_DOC)) 209 self._writeLine('<p style="%s %s">(empty dictionary)</p>' % (CSS_P, CSS_DOC))
209 self._writeLine('</div>') 210 self._writeLine('</div>')
210 211
211 def _renderObject(self, data, path): 212 def _renderObject(self, data, path):
287 except AttributeError: 288 except AttributeError:
288 # This could be an attribute on the instance itself, or some 289 # This could be an attribute on the instance itself, or some
289 # dynamic attribute. 290 # dynamic attribute.
290 attr = getattr(data, name) 291 attr = getattr(data, name)
291 292
292 if callable(attr): 293 if isinstance(attr, collections.Callable):
293 attr_func = getattr(data, name) 294 attr_func = getattr(data, name)
294 argcount = attr_func.__code__.co_argcount 295 argcount = attr_func.__code__.co_argcount
295 var_names = attr_func.__code__.co_varnames 296 var_names = attr_func.__code__.co_varnames
296 if argcount == 1 and should_call: 297 if argcount == 1 and should_call:
297 render_name += '()' 298 render_name += '()'