Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: cms/converters.py

Issue 29378736: NoIssue - Improves converters.py PEP8 compliance (Closed) Base URL: https://hg.adblockplus.org/cms
Patch Set: Created March 8, 2017, 12:15 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tox.ini » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # This file is part of the Adblock Plus web scripts, 1 # This file is part of the Adblock Plus web scripts,
2 # Copyright (C) 2006-2016 Eyeo GmbH 2 # Copyright (C) 2006-2016 Eyeo GmbH
3 # 3 #
4 # Adblock Plus is free software: you can redistribute it and/or modify 4 # Adblock Plus is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License version 3 as 5 # it under the terms of the GNU General Public License version 3 as
6 # published by the Free Software Foundation. 6 # published by the Free Software Foundation.
7 # 7 #
8 # Adblock Plus is distributed in the hope that it will be useful, 8 # Adblock Plus is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details. 11 # GNU General Public License for more details.
12 # 12 #
13 # You should have received a copy of the GNU General Public License 13 # You should have received a copy of the GNU General Public License
14 # along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 14 # along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
15 15
16 import os 16 import os
17 import HTMLParser 17 import HTMLParser
18 import re 18 import re
19 19
20 import jinja2 20 import jinja2
21 import markdown 21 import markdown
22 22
23 23
24 # Monkey-patch Markdown's isBlockLevel function to ensure that no paragraphs are 24 # Monkey-patch Markdown's isBlockLevel function to ensure that no paragraphs
25 # inserted into the <head> tag 25 # are inserted into the <head> tag
26 orig_isBlockLevel = markdown.util.isBlockLevel 26 orig_isBlockLevel = markdown.util.isBlockLevel
27 27
28 28
29 def isBlockLevel(tag): 29 def isBlockLevel(tag):
30 if tag == 'head': 30 if tag == 'head':
31 return True 31 return True
32 else: 32 return orig_isBlockLevel(tag)
33 return orig_isBlockLevel(tag) 33
34 markdown.util.isBlockLevel = isBlockLevel 34 markdown.util.isBlockLevel = isBlockLevel
35 35
36 html_escapes = { 36 html_escapes = {
37 '<': '&lt;', 37 '<': '&lt;',
38 '>': '&gt;', 38 '>': '&gt;',
39 '&': '&amp;', 39 '&': '&amp;',
40 '"': '&quot;', 40 '"': '&quot;',
41 "'": '&#39;', 41 "'": '&#39;',
42 } 42 }
43 43
(...skipping 14 matching lines...) Expand all
58 self._inside_fixed = False 58 self._inside_fixed = False
59 self._attrs = {} 59 self._attrs = {}
60 self._pagename = pagename 60 self._pagename = pagename
61 61
62 # Force-escape ampersands, otherwise the parser will autocomplete bogus 62 # Force-escape ampersands, otherwise the parser will autocomplete bogus
63 # entities. 63 # entities.
64 text = re.sub(r'&(?!\S+;)', '&amp;', text) 64 text = re.sub(r'&(?!\S+;)', '&amp;', text)
65 65
66 try: 66 try:
67 self.feed(text) 67 self.feed(text)
68 return ''.join(self._string), self._attrs, [''.join(s) for s in self ._fixed_strings] 68 return (''.join(self._string),
69 self._attrs, [''.join(s) for s in self._fixed_strings])
69 finally: 70 finally:
70 self._string = None 71 self._string = None
71 self._attrs = None 72 self._attrs = None
72 self._pagename = None 73 self._pagename = None
73 self._inside_fixed = False 74 self._inside_fixed = False
74 self._fixed_strings = None 75 self._fixed_strings = None
75 76
76 def handle_starttag(self, tag, attrs): 77 def handle_starttag(self, tag, attrs):
77 if self._inside_fixed: 78 if self._inside_fixed:
78 raise Exception("Unexpected HTML tag '%s' inside a fixed string on p age %s" % (tag, self._pagename)) 79 raise Exception('Unexpected HTML tag "{}" inside a fixed string'
Vasily Kuznetsov 2017/03/08 17:31:44 Do you think it's ok that we're changing the quote
Jon Sonesen 2017/03/08 17:51:57 Well, the otherway causes a style warning, however
Jon Sonesen 2017/03/08 17:55:25 whoops, I was wrong plz disregard XD
Vasily Kuznetsov 2017/03/09 12:33:27 Yeah, the logic is that if the string has single q
79 elif tag == 'fix': 80 'on page {}'.format(tag, self._pagename))
81 if tag == 'fix':
80 self._inside_fixed = True 82 self._inside_fixed = True
81 self._fixed_strings.append([]) 83 self._fixed_strings.append([])
82 elif tag in self._whitelist: 84 if tag in self._whitelist:
83 self._attrs.setdefault(tag, []).append(attrs) 85 self._attrs.setdefault(tag, []).append(attrs)
84 self._string.append('<%s>' % tag) 86 self._string.append('<{}>'.format(tag))
85 else: 87 else:
86 raise Exception("Unexpected HTML tag '%s' in localizable string on p age %s" % (tag, self._pagename)) 88 raise Exception('Unexpected HTML tag "{}" inside a fixed string'
89 'on page {}'.format(tag, self._pagename))
87 90
88 def handle_endtag(self, tag): 91 def handle_endtag(self, tag):
89 if tag == 'fix': 92 if tag == 'fix':
90 self._string.append('{%d}' % len(self._fixed_strings)) 93 self._string.append('{{{}}}'.format(self._fixed_strings))
91 self._inside_fixed = False 94 self._inside_fixed = False
92 else: 95 else:
93 self._string.append('</%s>' % tag) 96 self._string.append('</{}>'.format(tag))
94 97
95 def _append_text(self, s): 98 def _append_text(self, s):
96 if self._inside_fixed: 99 if self._inside_fixed:
97 self._fixed_strings[-1].append(s) 100 self._fixed_strings[-1].append(s)
98 else: 101 else:
99 self._string.append(s) 102 self._string.append(s)
100 103
101 def handle_data(self, data): 104 def handle_data(self, data):
102 # Note: lack of escaping here is intentional. The result is a locale str ing, 105 # Note: lack of escaping here is intentional. The result is a locale
103 # HTML escaping is applied when this string is inserted into the documen t. 106 # string, HTML escaping is applied when this string is inserted into
107 # the document.
104 self._append_text(data) 108 self._append_text(data)
105 109
106 def handle_entityref(self, name): 110 def handle_entityref(self, name):
107 self._append_text(self.unescape('&%s;' % name)) 111 self._append_text(self.unescape('&{};'.format(name)))
108 112
109 def handle_charref(self, name): 113 def handle_charref(self, name):
110 self._append_text(self.unescape('&#%s;' % name)) 114 self._append_text(self.unescape('&#{};'.format(name)))
111 115
112 116
113 class Converter: 117 class Converter:
114 whitelist = {'a', 'em', 'sup', 'strong', 'code', 'span'} 118 whitelist = {'a', 'em', 'sup', 'strong', 'code', 'span'}
115 missing_translations = 0 119 missing_translations = 0
116 total_translations = 0 120 total_translations = 0
117 121
118 def __init__(self, params, key='pagedata'): 122 def __init__(self, params, key='pagedata'):
119 self._params = params 123 self._params = params
120 self._key = key 124 self._key = key
121 self._attribute_parser = AttributeParser(self.whitelist) 125 self._attribute_parser = AttributeParser(self.whitelist)
122 self._seen_defaults = {} 126 self._seen_defaults = {}
123 127
124 # Read in any parameters specified at the beginning of the file 128 # Read in any parameters specified at the beginning of the file
125 data, filename = params[key] 129 data, filename = params[key]
126 lines = data.splitlines(True) 130 lines = data.splitlines(True)
127 for i, line in enumerate(lines): 131 for i, line in enumerate(lines):
128 if not re.search(r'^\s*[\w\-]+\s*=', line): 132 if not re.search(r'^\s*[\w\-]+\s*=', line):
129 break 133 break
130 name, value = line.split('=', 1) 134 name, value = line.split('=', 1)
131 params[name.strip()] = value.strip() 135 params[name.strip()] = value.strip()
132 lines[i] = '\n' 136 lines[i] = '\n'
133 params[key] = (''.join(lines), filename) 137 params[key] = (''.join(lines), filename)
134 138
135 def localize_string(self, page, name, default, comment, localedata, escapes) : 139 def localize_string(
140 self, page, name, default, comment, localedata, escapes):
141
136 def escape(s): 142 def escape(s):
137 return re.sub(r'.', 143 return re.sub(r'.',
Vasily Kuznetsov 2017/03/08 17:31:44 This is also kind of hard to read but more importa
Jon Sonesen 2017/03/08 17:51:57 I agree here, but assumed it would require an issu
Vasily Kuznetsov 2017/03/09 12:33:27 Yeah, you're right.
138 lambda match: escapes.get(match.group(0), match.group( 0)), 144 lambda match: escapes.get(match.group(0),
145 match.group(0)),
139 s, flags=re.S) 146 s, flags=re.S)
140 147
141 def re_escape(s): 148 def re_escape(s):
142 return re.escape(escape(s)) 149 return re.escape(escape(s))
143 150
144 # Handle duplicated strings 151 # Handle duplicated strings
145 if default: 152 if default:
146 self._seen_defaults[(page, name)] = (default, comment) 153 self._seen_defaults[(page, name)] = (default, comment)
147 else: 154 else:
148 try: 155 try:
149 default, comment = self._seen_defaults[(page, name)] 156 default, comment = self._seen_defaults[(page, name)]
150 except KeyError: 157 except KeyError:
151 raise Exception('Text not yet defined for string %s on page %s' % 158 raise Exception('Text not yet defined for string {} on page'
152 (name, page)) 159 '{}'.format(name, page))
153 160
154 # Extract tag attributes from default string 161 # Extract tag attributes from default string
155 default, saved_attributes, fixed_strings = self._attribute_parser.parse( default, self._params['page']) 162 default, saved_attributes, fixed_strings = (self._attribute_parser
Vasily Kuznetsov 2017/03/08 17:31:44 This looks kind of hard to read. How about this in
Jon Sonesen 2017/03/08 17:51:57 Yes that seems nicer, thank you!
163 .parse(default,
164 self._params['page']
165 ))
156 166
157 # Get translation 167 # Get translation
158 locale = self._params['locale'] 168 locale = self._params['locale']
159 if locale == self._params['defaultlocale']: 169 if locale == self._params['defaultlocale']:
160 result = default 170 result = default
161 elif name in localedata: 171 elif name in localedata:
162 result = localedata[name].strip() 172 result = localedata[name].strip()
163 else: 173 else:
164 result = default 174 result = default
165 self.missing_translations += 1 175 self.missing_translations += 1
166 self.total_translations += 1 176 self.total_translations += 1
167 177
168 # Perform callback with the string if required, e.g. for the translation s script 178 # Perform callback with the string if required, e.g. for the
179 # translations script
169 callback = self._params['localized_string_callback'] 180 callback = self._params['localized_string_callback']
170 if callback: 181 if callback:
171 callback(page, locale, name, result, comment, fixed_strings) 182 callback(page, locale, name, result, comment, fixed_strings)
172 183
173 # Insert fixed strings 184 # Insert fixed strings
174 for i, fixed_string in enumerate(fixed_strings, 1): 185 for i, fixed_string in enumerate(fixed_strings, 1):
175 result = result.replace('{%d}' % i, fixed_string) 186 result = result.replace('{{{%d}}}'.format(i), fixed_string)
176 187
177 # Insert attributes 188 # Insert attributes
178 result = escape(result) 189 result = escape(result)
179 190
180 def stringify_attribute((name, value)): 191 def stringify_attribute((name, value)):
181 return '%s="%s"' % ( 192 return '{}="{}"'.format(
182 escape(name), 193 escape(name),
183 escape(self.insert_localized_strings(value, {})) 194 escape(self.insert_localized_strings(value, {}))
184 ) 195 )
185 196
186 for tag in self.whitelist: 197 for tag in self.whitelist:
187 allowed_contents = '(?:[^<>]|%s)' % '|'.join(( 198 allowed_contents = '(?:[^<>]|{})'.format('|').join((
188 '<(?:%s[^<>]*?|/%s)>' % (t, t) 199 '<(?:{}[^<>]*?|/{})>'.format(t, t)
189 for t in map(re.escape, self.whitelist - {tag}) 200 for t in map(re.escape, self.whitelist - {tag})
190 )) 201 ))
191 saved = saved_attributes.get(tag, []) 202 saved = saved_attributes.get(tag, [])
192 for attrs in saved: 203 for attrs in saved:
193 attrs = map(stringify_attribute, attrs) 204 attrs = map(stringify_attribute, attrs)
194 result = re.sub( 205 result = re.sub(
195 r'%s(%s*?)%s' % (re_escape('<%s>' % tag), allowed_contents, 206 r'{}({}*?){}'.format(re_escape('<{}>'.format(tag)),
196 re_escape('</%s>' % tag)), 207 allowed_contents,
197 lambda match: r'<%s%s>%s</%s>' % ( 208 re_escape('</{}>'.format(tag))),
209 lambda match: r'<{}{}>{}</{}>'.format(
198 tag, 210 tag,
199 ' ' + ' '.join(attrs) if attrs else '', 211 ' ' + ' '.join(attrs) if attrs else '',
200 match.group(1), 212 match.group(1),
201 tag 213 tag
202 ), 214 ),
203 result, 1, flags=re.S 215 result, 1, flags=re.S
204 ) 216 )
205 result = re.sub( 217 result = re.sub(
206 r'%s(%s*?)%s' % (re_escape('<%s>' % tag), allowed_contents, 218 r'{}({}*?){}'.format(re_escape('<{}>'.format(tag)),
207 re_escape('</%s>' % tag)), 219 allowed_contents,
208 r'<%s>\1</%s>' % (tag, tag), 220 re_escape('</{}>'.format(tag))),
221 r'<{}>\1</{}>'.format(tag, tag),
209 result, flags=re.S 222 result, flags=re.S
210 ) 223 )
211 return result 224 return result
212 225
213 def insert_localized_strings(self, text, escapes, to_html=lambda s: s): 226 def insert_localized_strings(self, text, escapes, to_html=lambda s: s):
214 def lookup_string(match): 227 def lookup_string(match):
215 name, comment, default = match.groups() 228 name, comment, default = match.groups()
216 if default: 229 if default:
217 default = to_html(default).strip() 230 default = to_html(default).strip()
218 return self.localize_string(self._params['page'], name, default, 231 return self.localize_string(self._params['page'], name, default,
219 comment, self._params['localedata'], esc apes) 232 comment, self._params['localedata'],
233 escapes)
220 234
221 return re.sub( 235 return re.sub(
222 r'{{\s*' 236 r'{{\s*'
223 r'([\w\-]+)' # String ID 237 r'([\w\-]+)' # String ID
224 r'(?:(?:\[(.*?)\])?' # Optional comment 238 r'(?:(?:\[(.*?)\])?' # Optional comment
225 r'\s+' 239 r'\s+'
226 r'((?:(?!{{).|' # Translatable text 240 r'((?:(?!{{).|' # Translatable text
227 r'{{(?:(?!}}).)*}}' # Nested translation 241 r'{{(?:(?!}}).)*}}' # Nested translation
228 r')*?)' 242 r')*?)'
229 r')?' 243 r')?'
230 r'}}', 244 r'}}',
231 lookup_string, 245 lookup_string,
232 text, 246 text,
233 flags=re.S 247 flags=re.S
234 ) 248 )
235 249
236 def process_links(self, text): 250 def process_links(self, text):
237 def process_link(match): 251 def process_link(match):
238 pre, attr, url, post = match.groups() 252 pre, attr, url, post = match.groups()
239 url = jinja2.Markup(url).unescape() 253 url = jinja2.Markup(url).unescape()
240 254
241 locale, new_url = self._params['source'].resolve_link(url, self._par ams['locale']) 255 locale, new_url = self._params['source']\
Vasily Kuznetsov 2017/03/08 17:31:44 PEP8 discourages line continuation with backslashe
Jon Sonesen 2017/03/08 17:51:57 oh yeah, I though i replaced all the back slashes
242 if new_url != None: 256 .resolve_link(url, self._params['locale'])
257 if new_url is not None:
243 url = new_url 258 url = new_url
244 if attr == 'href': 259 if attr == 'href':
245 post += ' hreflang="%s"' % jinja2.Markup.escape(locale) 260 post += ' hreflang="{}"'\
Vasily Kuznetsov 2017/03/08 17:31:44 Maybe we can use continuation with parentheses ins
Jon Sonesen 2017/03/08 17:51:57 yesh
261 .format(jinja2.Markup.escape(locale))
246 262
247 return ''.join((pre, jinja2.Markup.escape(url), post)) 263 return ''.join((pre, jinja2.Markup.escape(url), post))
248 264
249 text = re.sub(r'(<a\s[^<>]*\b(href)=\")([^<>\"]+)(\")', process_link, te xt) 265 text = re.sub(r'(<a\s[^<>]*\b(href)=\")([^<>\"]+)(\")',
250 text = re.sub(r'(<img\s[^<>]*\b(src)=\")([^<>\"]+)(\")', process_link, t ext) 266 process_link, text)
267 text = re.sub(r'(<img\s[^<>]*\b(src)=\")([^<>\"]+)(\")',
268 process_link, text)
251 return text 269 return text
252 270
253 include_start_regex = '<' 271 include_start_regex = '<'
254 include_end_regex = '>' 272 include_end_regex = '>'
255 273
256 def resolve_includes(self, text): 274 def resolve_includes(self, text):
257 def resolve_include(match): 275 def resolve_include(match):
258 global converters
259 name = match.group(1) 276 name = match.group(1)
260 for format, converter_class in converters.iteritems(): 277 for format_, converter_class in converters.iteritems():
261 if self._params['source'].has_include(name, format): 278 if self._params['source'].has_include(name, format_):
262 self._params['includedata'] = self._params['source'].read_in clude(name, format) 279 self._params['includedata'] = self._params['source']\
263 converter = converter_class(self._params, key='includedata') 280 .read_include(name, format)
281 converter = converter_class(self._params,
282 key='includedata')
264 result = converter() 283 result = converter()
265 self.missing_translations += converter.missing_translations 284 self.missing_translations += converter.missing_translations
266 self.total_translations += converter.total_translations 285 self.total_translations += converter.total_translations
267 return result 286 return result
268 raise Exception('Failed to resolve include %s on page %s' % (name, s elf._params['page'])) 287 raise Exception('Failed to resolve include {}'
288 'on page {}'.format(name, self._params['page']))
269 289
270 return re.sub( 290 return re.sub(
271 r'%s\?\s*include\s+([^\s<>"]+)\s*\?%s' % ( 291 r'{}\?\s*include\s+([^\s<>"]+)\s*\?{}'.format(
272 self.include_start_regex, 292 self.include_start_regex,
273 self.include_end_regex 293 self.include_end_regex
274 ), 294 ),
275 resolve_include, 295 resolve_include,
276 text 296 text
277 ) 297 )
278 298
279 def __call__(self): 299 def __call__(self):
280 result = self.get_html(*self._params[self._key]) 300 result = self.get_html(*self._params[self._key])
281 result = self.resolve_includes(result) 301 result = self.resolve_includes(result)
282 if self._key == 'pagedata': 302 if self._key == 'pagedata':
283 head = [] 303 head = []
284 304
285 def add_to_head(match): 305 def add_to_head(match):
286 head.append(match.group(1)) 306 head.append(match.group(1))
287 return '' 307 return ''
288 body = re.sub(r'<head>(.*?)</head>', add_to_head, result, flags=re.S ) 308 body = re.sub(r'<head>(.*?)</head>', add_to_head, result,
309 flags=re.S)
289 return ''.join(head), body 310 return ''.join(head), body
290 else: 311 return result
291 return result
292 312
293 313
294 class RawConverter(Converter): 314 class RawConverter(Converter):
295 def get_html(self, source, filename): 315 def get_html(self, source, filename):
296 result = self.insert_localized_strings(source, html_escapes) 316 result = self.insert_localized_strings(source, html_escapes)
297 result = self.process_links(result) 317 result = self.process_links(result)
298 return result 318 return result
299 319
300 320
301 class MarkdownConverter(Converter): 321 class MarkdownConverter(Converter):
302 include_start_regex = r'(?:%s|%s)' % ( 322 include_start_regex = r'(?:{}|{})'.format(
303 Converter.include_start_regex, 323 Converter.include_start_regex,
304 re.escape(jinja2.escape(Converter.include_start_regex)) 324 re.escape(jinja2.escape(Converter.include_start_regex))
305 ) 325 )
306 include_end_regex = r'(?:%s|%s)' % ( 326 include_end_regex = r'(?:{}|{})'.format(
307 Converter.include_end_regex, 327 Converter.include_end_regex,
308 re.escape(jinja2.escape(Converter.include_end_regex)) 328 re.escape(jinja2.escape(Converter.include_end_regex))
309 ) 329 )
310 330
311 def get_html(self, source, filename): 331 def get_html(self, source, filename):
312 def remove_unnecessary_entities(match): 332 def remove_unnecessary_entities(match):
313 char = unichr(int(match.group(1))) 333 char = unichr(int(match.group(1)))
314 if char in html_escapes: 334 if char in html_escapes:
315 return match.group(0) 335 return match.group(0)
316 else: 336 return char
317 return char
318 337
319 escapes = {} 338 escapes = {}
320 md = markdown.Markdown(output='html5', extensions=['extra']) 339 md = markdown.Markdown(output='html5', extensions=['extra'])
321 for char in md.ESCAPED_CHARS: 340 for char in md.ESCAPED_CHARS:
322 escapes[char] = '&#' + str(ord(char)) + ';' 341 escapes[char] = '&#{};'.format(str(ord(char)))
323 for key, value in html_escapes.iteritems(): 342 for key, value in html_escapes.iteritems():
324 escapes[key] = value 343 escapes[key] = value
325 344
326 md.preprocessors['html_block'].markdown_in_raw = True 345 md.preprocessors['html_block'].markdown_in_raw = True
327 346
328 def to_html(s): 347 def to_html(s):
329 return re.sub(r'</?p>', '', md.convert(s)) 348 return re.sub(r'</?p>', '', md.convert(s))
330 349
331 result = self.insert_localized_strings(source, escapes, to_html) 350 result = self.insert_localized_strings(source, escapes, to_html)
332 result = md.convert(result) 351 result = md.convert(result)
(...skipping 22 matching lines...) Expand all
355 'translate': self.translate, 374 'translate': self.translate,
356 'linkify': self.linkify, 375 'linkify': self.linkify,
357 'toclist': self.toclist, 376 'toclist': self.toclist,
358 } 377 }
359 378
360 globals = { 379 globals = {
361 'get_string': self.get_string, 380 'get_string': self.get_string,
362 'get_page_content': self.get_page_content, 381 'get_page_content': self.get_page_content,
363 } 382 }
364 383
365 for dirname, dictionary in [('filters', filters), ('globals', globals)]: 384 for dirname, dictionary in [('filters', filters),
385 ('globals', globals)]:
366 for filename in self._params['source'].list_files(dirname): 386 for filename in self._params['source'].list_files(dirname):
367 root, ext = os.path.splitext(filename) 387 root, ext = os.path.splitext(filename)
368 if ext.lower() != '.py': 388 if ext.lower() != '.py':
369 continue 389 continue
370 390
371 path = '%s/%s' % (dirname, filename) 391 path = os.path.join(dirname, filename)
372 namespace = self._params['source'].exec_file(path) 392 namespace = self._params['source'].exec_file(path)
373 393
374 name = os.path.basename(root) 394 name = os.path.basename(root)
375 try: 395 try:
376 dictionary[name] = namespace[name] 396 dictionary[name] = namespace[name]
377 except KeyError: 397 except KeyError:
378 raise Exception('Expected symbol %r not found in %r' % (name , path)) 398 raise Exception('Expected symbol {} not found'
399 'in {}'.format(name, path))
379 400
380 self._env = jinja2.Environment(loader=SourceTemplateLoader(self._params[ 'source']), autoescape=True) 401 self._env = jinja2.Environment(
402 loader=SourceTemplateLoader(self._params['source']),
403 autoescape=True)
381 self._env.filters.update(filters) 404 self._env.filters.update(filters)
382 self._env.globals.update(globals) 405 self._env.globals.update(globals)
383 406
384 def get_html(self, source, filename): 407 def get_html(self, source, filename):
385 env = self._env 408 env = self._env
386 code = env.compile(source, None, filename) 409 code = env.compile(source, None, filename)
387 template = jinja2.Template.from_code(env, code, env.globals) 410 template = jinja2.Template.from_code(env, code, env.globals)
388 411
389 try: 412 try:
390 module = template.make_module(self._params) 413 module = template.make_module(self._params)
(...skipping 11 matching lines...) Expand all
402 def translate(self, default, name, comment=None): 425 def translate(self, default, name, comment=None):
403 return jinja2.Markup(self.localize_string( 426 return jinja2.Markup(self.localize_string(
404 self._params['page'], name, default, comment, 427 self._params['page'], name, default, comment,
405 self._params['localedata'], html_escapes 428 self._params['localedata'], html_escapes
406 )) 429 ))
407 430
408 def get_string(self, name, page=None): 431 def get_string(self, name, page=None):
409 if page is None: 432 if page is None:
410 page = self._params['page'] 433 page = self._params['page']
411 434
412 localedata = self._params['source'].read_locale(self._params['locale'], page) 435 localedata = self._params['source'].read_locale(self._params['locale'],
436 page)
413 default = localedata[name] 437 default = localedata[name]
414 return jinja2.Markup(self.localize_string( 438 return jinja2.Markup(self.localize_string(
415 page, name, default, '', localedata, html_escapes 439 page, name, default, '', localedata, html_escapes
416 )) 440 ))
417 441
418 def get_page_content(self, page, locale=None): 442 def get_page_content(self, page, locale=None):
419 from cms.utils import get_page_params 443 from cms.utils import get_page_params
420 444
421 if locale is None: 445 if locale is None:
422 locale = self._params['locale'] 446 locale = self._params['locale']
423 return get_page_params(self._params['source'], locale, page) 447 return get_page_params(self._params['source'], locale, page)
424 448
425 def linkify(self, page, locale=None, **attrs): 449 def linkify(self, page, locale=None, **attrs):
426 if locale is None: 450 if locale is None:
427 locale = self._params['locale'] 451 locale = self._params['locale']
428 452
429 locale, url = self._params['source'].resolve_link(page, locale) 453 locale, url = self._params['source'].resolve_link(page, locale)
430 return jinja2.Markup('<a%s>' % ''.join( 454 return jinja2.Markup('<a{}>'.format(''.join(
431 ' %s="%s"' % (name, jinja2.escape(value)) for name, value in [ 455 ' {}="{}"'.format(name, jinja2.escape(value)) for name, value in [
432 ('href', url), 456 ('href', url),
433 ('hreflang', locale) 457 ('hreflang', locale)
434 ] + attrs.items() 458 ] + attrs.items()
435 )) 459 )))
436 460
437 def toclist(self, content): 461 def toclist(self, content):
462 toc_re = r'<h(\d)\s[^<>]*\bid="([^<>"]+)"[^<>]*>(.*?)</h\1>'
438 flat = [] 463 flat = []
439 for match in re.finditer(r'<h(\d)\s[^<>]*\bid="([^<>"]+)"[^<>]*>(.*?)</h \1>', content, re.S): 464 for match in re.finditer(toc_re, content, re.S):
440 flat.append({ 465 flat.append({
441 'level': int(match.group(1)), 466 'level': int(match.group(1)),
442 'anchor': jinja2.Markup(match.group(2)).unescape(), 467 'anchor': jinja2.Markup(match.group(2)).unescape(),
443 'title': jinja2.Markup(match.group(3)).unescape(), 468 'title': jinja2.Markup(match.group(3)).unescape(),
444 'subitems': [], 469 'subitems': [],
445 }) 470 })
446 471
447 structured = [] 472 structured = []
448 stack = [{'level': 0, 'subitems': structured}] 473 stack = [{'level': 0, 'subitems': structured}]
449 for item in flat: 474 for item in flat:
450 while stack[-1]['level'] >= item['level']: 475 while stack[-1]['level'] >= item['level']:
451 stack.pop() 476 stack.pop()
452 stack[-1]['subitems'].append(item) 477 stack[-1]['subitems'].append(item)
453 stack.append(item) 478 stack.append(item)
454 return structured 479 return structured
455 480
456 converters = { 481 converters = {
457 'html': RawConverter, 482 'html': RawConverter,
458 'md': MarkdownConverter, 483 'md': MarkdownConverter,
459 'tmpl': TemplateConverter, 484 'tmpl': TemplateConverter,
460 } 485 }
OLDNEW
« no previous file with comments | « no previous file | tox.ini » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld