Mercurial > piecrust2
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> — ' % (CSS_P, APP_VERSION) | 68 print('<p style="%s"><strong>PieCrust %s</strong> — ' % (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 '— click to toggle</a>.</p>' % CSS_BIGHEADER) | 105 '— 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 += '()' |