def preprocess(self, source, name, filename=None): ret_source = '' start_pos = 0 while True: tag_match = begin_tag_m.search(source, start_pos) if tag_match: end_tag = end_tag_m.search(source, tag_match.end()) if not end_tag: raise TemplateSyntaxError( 'Expecting "endhaml" tag', self._get_lineno(source[:start_pos])) haml_source = source[tag_match.end():end_tag.start()] h = self.get_preprocessor(self.environment.hamlish_mode) try: ret_source += source[start_pos:tag_match.start( )] + h.convert_source(haml_source) except TemplateIndentationError, e: raise TemplateSyntaxError(e.message, e.lineno, name=name, filename=filename) except TemplateSyntaxError, e: raise TemplateSyntaxError(e.message, e.lineno, name=name, filename=filename) start_pos = end_tag.end()
def _parse_line(self, lineno, line): inline_data = None if self._has_inline_data(line): line, inline_data = self._parse_inline_data(line) if self._has_nested_tags(line): node = self._parse_nested_tags(lineno, line) else: node = self._parse_node(lineno, line) if inline_data is not None: if not node.can_have_children(): raise TemplateSyntaxError('Node can\'t contain inline data', lineno) elif isinstance(node, NestedTags) and isinstance( node.nodes[-1], TextNode): raise TemplateSyntaxError( 'TextNode can\'t contain inline data', lineno) return InlineData(node, inline_data) return node
def preprocess(self, source, name, filename=None): ret_source = '' start_pos = 0 while True: tag_match = begin_tag_m.search(source, start_pos) if tag_match: end_tag = end_tag_m.search(source, tag_match.end()) if not end_tag: raise TemplateSyntaxError( 'Expecting "endjade" tag', self._get_lineno(source[:start_pos])) jade_source = source[tag_match.end():end_tag.start()] jade_source = convert(jade_source) try: ret_source += source[start_pos:tag_match.start( )] + jade_source except TemplateIndentationError as e: raise TemplateSyntaxError(e.message, e.lineno, name=name, filename=filename) except TemplateSyntaxError as e: raise TemplateSyntaxError(e.message, e.lineno, name=name, filename=filename) start_pos = end_tag.end() else: ret_source += source[start_pos:] break return ret_source
def _cache_support(self, expire_time, fragm_name, vary_on, lineno, cache_name, caller): try: expire_time = int(expire_time) except (ValueError, TypeError): raise TemplateSyntaxError( '"%s" tag got a non-integer timeout ' 'value: %r' % (list(self.tags)[0], expire_time), lineno) if cache_name: try: cache = get_cache(cahe_name) except InvalidCacheBackendError: raise TemplateSyntaxError( 'Invalid cache name specified for cache tag: {}'.format( cache_name)) else: try: cache = get_cache('template_fragments') except InvalidCacheBackendError: cache = get_cache('default') cache_key = make_template_fragment_key(fragm_name, vary_on) value = cache.get(cache_key) if value is None: value = caller() cache.set(cache_key, force_text(value), expire_time) return value
def _get_haml_tree(self, source): source_lines = self._get_source_lines(source) root = Node() # contains always atleast one element block_stack = [root] # stack for current indent level indent_stack = [-1] for lineno, line in enumerate(source_lines, 1): if not line.strip(): block_stack[-1].add(EmptyLine()) continue indent = 0 m = re.match(r'^(\s+)', line) if m: indent = m.group(1) if ' ' in indent and '\t' in indent: raise TemplateIndentationError('Mixed tabs and spaces', lineno) indent = len(indent) if indent > indent_stack[-1]: indent_stack.append(indent) else: while indent < indent_stack[-1]: indent_stack.pop() block_stack.pop() block_stack.pop() if indent != indent_stack[-1]: raise TemplateIndentationError( 'Unindent does not match any outer indentation level', lineno) node = self._parse_line(lineno, line.strip()) if not block_stack[-1].can_have_children(): if isinstance(node, InlineData): raise TemplateSyntaxError( 'Inline Data Node can\'t contain child nodes', lineno) else: raise TemplateSyntaxError( 'Self closing tag can\'t contain child nodes', lineno) block_stack[-1].add(node) block_stack.append(node) return root.children
def parse_html_block(self, block, depth): m = re.match('^(\w+)(.*)$', block[1][1:]) if m is None: raise TemplateSyntaxError( 'Expected html tag, got "%s".' % block[1][1:], block[0]) tag = m.group(1) attrs = m.group(2) data = '' if self.INLINE_DATA_SEP in attrs: attrs, data = attrs.split(self.INLINE_DATA_SEP, 1) if self.debug: self.output.newline() self.output.indent(depth) self_closing = False if attrs and attrs[-1] == self.SELF_CLOSING_TAG: attrs = attrs[:-1] self_closing = True elif tag in self.self_closing_html_tags: self_closing = True attrs = attrs.rstrip() if attrs and attrs[0] in (self.ID_SHORTCUT, self.CLASS_SHORTCUT): attrs = self._parse_shortcut_attributes(attrs) if self_closing and (data or block[2]): raise TemplateSyntaxError("Self closing tags can't have content", block[0]) if self_closing: self.output.self_closing_html(tag, attrs) else: self.output.open_html(tag, attrs) if not self_closing and (data or not block[2]): if data: self.output.write(data) self.output.close_html(tag) if not self.debug: self.output.newline() self.create_output(block[2], depth + 1) if not data and not self_closing and block[2]: self._close_block(depth, lambda: self.output.close_html(tag))
def preprocess(self, source, name, filename=None): if name is None or os.path.splitext(name)[1] not in \ self.environment.hamlish_file_extensions: return source h = self.get_preprocessor(self.environment.hamlish_mode) try: return h.convert_source(source) except TemplateIndentationError as e: raise TemplateSyntaxError(e.message, e.lineno, name=name, filename=filename) except TemplateSyntaxError as e: raise TemplateSyntaxError(e.message, e.lineno, name=name, filename=filename)
def parse(self, parser): lineno = next(parser.stream).lineno github_path = '' tag = None last_token_type = None for token in parser.stream: if last_token_type == lexer.TOKEN_NAME and token.value == 'tag': parser.stream.expect(lexer.TOKEN_COLON) tag = parser.stream.expect(lexer.TOKEN_NAME).value break github_path += token.value last_token_type = token.type m = self.github_path_re.match(github_path) if not m: raise TemplateSyntaxError( 'Github file path must be in the format ' '/<owner>/<repo>/blob/<branch>/<path>, ' 'found {}'.format(repr(github_path)), lineno, parser.name, parser.filename) owner, repo, branch, path = m.groups() call = self.call_method('_github_sample', [ nodes.Const(owner), nodes.Const(repo), nodes.Const(branch), nodes.Const(path), nodes.Const(tag), ]) return nodes.CallBlock(call, [], [], []).set_lineno(lineno)
def _parse_html(self, lineno, line): m = re.match('^(\w+)(.*)$', line[1:]) if m is None: raise TemplateSyntaxError('Expected html tag, got "%s".' % line, lineno) tag = m.group(1) attrs = m.group(2) self_closing = False if attrs and attrs[-1] == self.SELF_CLOSING_TAG: self_closing = True attrs = attrs[:-1].rstrip() elif tag in self._self_closing_html_tags: self_closing = True if attrs.startswith(self.ID_SHORTCUT) or \ attrs.startswith(self.CLASS_SHORTCUT): attrs = self._parse_shortcut_attributes(attrs) if self_closing: return SelfClosingHTMLTag(tag, attrs) return HTMLTag(tag, attrs)
def test_raises_templatesyntaxerror_exception(self, mock_logger): dg = DocumentGenerator(self.downloadable) dg.get_docx = MagicMock(side_effect=TemplateSyntaxError('', 0)) with self.assertRaises(TemplateSyntaxError): dg.get_pdf() mock_logger.warning.assert_called()
class HamlishExtension(Extension): def __init__(self, environment): super(HamlishExtension, self).__init__(environment) environment.extend(hamlish_mode='compact', hamlish_file_extensions=('.haml', ), hamlish_indent_string=' ', hamlish_newline_string='\n', hamlish_debug=False, hamlish_enable_div_shortcut=False, hamlish_from_string=self._from_string) def preprocess(self, source, name, filename=None): if name is None or os.path.splitext(name)[1] not in \ self.environment.hamlish_file_extensions: return source h = self.get_preprocessor(self.environment.hamlish_mode) try: return h.convert_source(source) except TemplateIndentationError, e: raise TemplateSyntaxError(e.message, e.lineno, name=name, filename=filename) except TemplateSyntaxError, e: raise TemplateSyntaxError(e.message, e.lineno, name=name, filename=filename)
def substitute_jinja2(text, substitutions, job=None, filename=None): """ Use `jinja2` so apply formatting to a string. :param text: A string, like the contents of a file, in which substitutions should be applied. :param substitutions: Also called 'context', contains a mapping of things to replace. :return: Substituted string. """ try: from jinja2 import Template, __version__ as jinja_version except ImportError as err: raise ImportError('Jinja2 is set as the formatter, but '.format(err)) if int(jinja_version.split('.')[1]) < 7: raise ImportError( 'Jinja2 needs at least version 2.7, but you have {0:s}'.format( jinja_version)) from jinja2 import TemplateSyntaxError try: template = Template(text, undefined=StrictUndefined, trim_blocks=True, lstrip_blocks=True) except TemplateSyntaxError as err: raise TemplateSyntaxError('In file {0:s}: {1:}'.format(filename, err), err.lineno) return template.render(**substitutions)
def fail(self, message): raise TemplateSyntaxError( message, self.token.lineno, self.stream.name, self.stream.filename, )
def preprocess(self, source, name, filename=None): if not name or os.path.splitext(name)[1] not in self.HAML_EXTENSIONS: return source compiler = Compiler() try: return compiler.process(source) except Exception, e: raise TemplateSyntaxError(e, None, name=name, filename=filename)
def test_template_syntax_error(self): with mock.patch("course.content.markup_to_html") as mock_mth: from jinja2 import TemplateSyntaxError mock_mth.side_effect = TemplateSyntaxError(lineno=10, message=b"my error") resp = self.post_batch_issue_exam_ticket_view( data=self.get_post_data()) self.assertEqual(resp.status_code, 200) self.assertEqual(ExamTicket.objects.count(), 0) self.assertAddMessageCallCount(1) self.assertAddMessageCalledWith("Template rendering failed")
def parse_jinja_block(self, block, depth, continued_block=None): line = block[1][1:] m = re.match('^(\w+)(.*)$', line) if m is None: raise TemplateSyntaxError('Expected jinja tag, got "%s".' % line, block[0]) name = m.group(1) if continued_block is not None: if name not in self.continued_jinja_tags: continued_block = self.close_continued_block( continued_block, depth) if name in self.extended_jinja_tags: continued_block = name data = '' if self.INLINE_DATA_SEP in line: line, data = line.split(self.INLINE_DATA_SEP, 1) if self.debug: self.output.newline() self.output.indent(depth) self.output.open_jinja(name, line) if data: self.output.write(data) if name not in self.self_closing_jinja_tags and \ continued_block is None and (data or not block[2]): self.output.close_jinja(name) if not self.debug: # and block[2]: self.output.newline() self.create_output(block[2], depth + 1) if not data and name not in self.self_closing_jinja_tags and continued_block is None\ and block[2]: self._close_block(depth, lambda: self.output.close_jinja(name)) if name in self.extended_jinja_tags: return name return continued_block
def parse(self, parser): tag = next(parser.stream) package_name = parser.parse_expression() if not package_name: raise TemplateSyntaxError("Bad package name", tag.lineno) args = [package_name] if tag.value == "stylesheet": return nodes.CallBlock(self.call_method('package_css', args), [], [], []).set_lineno(tag.lineno) if tag.value == "javascript": return nodes.CallBlock(self.call_method('package_js', args), [], [], []).set_lineno(tag.lineno) return []
def _cache_support(self, expire_time, fragm_name, vary_on, lineno, caller): try: expire_time = int(expire_time) except (ValueError, TypeError): raise TemplateSyntaxError('"%s" tag got a non-integer timeout ' 'value: %r' % (list(self.tags)[0], expire_time), lineno) cache_key = make_template_fragment_key(fragm_name, vary_on) value = cache.get(cache_key) if value is None: value = caller() cache.set(cache_key, force_text(value), expire_time) return value
def parse_experiment_enroll(self, parser): """Parse {% experiment_enroll ... %} tags""" lineno = parser.stream.current.lineno # list of nodes that will be used when calling the callback: args = [] # parsing first parameter: experiment_name = parser.stream.current args.append(self._name_or_const(experiment_name)) next(parser.stream) # parsing remaining parameters (the "alternatives"): alternatives = [] while parser.stream.current.type != 'block_end': if self._token_as(parser): break alternatives.append(self._name_or_const(parser.stream.current)) next(parser.stream) args.append(nodes.List(alternatives)) # expecting `as` after the alternatives: if not self._token_as(parser): raise TemplateSyntaxError( 'Syntax should be like: ' '{% experiment_enroll "experiment_name"' ' "alternative1" "alternative2" ... as some_variable %}', lineno, ) next(parser.stream) # parse what comes after `as`: target = parser.parse_assign_target() # We're done with parsing the tag. # we will also need the context in the callback: args.append(nodes.ContextReference()) # create a callback node that will be executed on render: call_node = self.call_method('render_experiment_enroll', args, lineno=lineno) # return an assignment node that will trigger the callback: return nodes.Assign(target, call_node, lineno=lineno)
def _parse_jinja(self, lineno, line): m = re.match('^(\w+)(.*)$', line[1:]) if m is None: raise TemplateSyntaxError('Expected jinja tag, got "%s".' % line, lineno) tag = m.group(1) attrs = m.group(2) if tag in self._self_closing_jinja_tags: return SelfClosingJinjaTag(tag, attrs) elif tag in self._extended_tags: return ExtendingJinjaTag(tag, attrs) return JinjaTag(tag, attrs)
def preprocess(self, source, name, filename=None): """Preprocesses the template from HAML to Jinja-style HTML.""" if (not name or os.path.splitext(name)[1] not in self.environment.haml_file_extensions): return source try: renderer = Renderer( source, indent_string=self.environment.haml_indent_string, newline_string=self.environment.haml_newline_string) except TemplateSyntaxError, e: raise TemplateSyntaxError(e.message, e.lineno, name=name, filename=filename)
def _parse_nested_tags(self, lineno, line): tags = line.split(self.NESTED_TAGS_SEP) nodes = [] node_lines = [] #Used to make a nicer error message for line in [x.strip() for x in tags]: node = self._parse_node(lineno, line) if nodes and not nodes[-1].can_have_children(): raise TemplateSyntaxError('Node "%s" can\'t contain children' % node_lines[-1], lineno) nodes.append(node) node_lines.append(line) return NestedTags(nodes)
def parse_experiment(self, parser): """Parse {% experiment ... %} tags""" lineno = parser.stream.current.lineno # list of nodes that will be used when calling the callback: args = [] # get tag parameters: while parser.stream.current.type != 'block_end': if parser.stream.skip_if('comma'): continue # just ignore commas # {% experiment %} tag only accepts strings, i.e. Const: args.append(nodes.Const(parser.stream.current.value)) next(parser.stream) # verify tag syntax: tokens = [nodes.Const('experiment')] + args try: _parse_token_contents(list(map(attrgetter('value'), tokens))) except ValueError: raise TemplateSyntaxError( "Syntax should be like: " "{% experiment experiment_name" " alternative [weight=val] [user=val] %}", lineno, ) # fill in default values: while len(args) < 4: args.append(nodes.Const(None)) # additional args: args.append(nodes.ContextReference()) # parse the body of the block up to `endexperiment` and # drop the needle (which will always be `endexperiment`): body = parser.parse_statements(['name:endexperiment'], drop_needle=True) # Jinja2 callbacky nodey magic: call_node = self.call_method('render_experiment', args, lineno=lineno) return nodes.CallBlock(call_node, [], [], body).set_lineno(lineno)
def _cache_support(self, expire_time, fragm_name, vary_on, lineno, caller): try: if expire_time is not None: expire_time = int(expire_time) except (ValueError, TypeError): raise TemplateSyntaxError( f'"{list(self.tags)[0]}" tag got a non-integer timeout value: {expire_time!r}', lineno, ) cache_key = make_template_fragment_key(fragm_name, vary_on) value = cache.get(cache_key) if value is None: value = caller() cache.set(cache_key, force_str(value), expire_time) else: value = force_str(value) return value
def parse_experiment_enrolled_alternative(self, parser): """ Parse {% experiment_enrolled_alternative <experiment_name> %} tags """ lineno = parser.stream.current.lineno # list of nodes that will be used when calling the callback: args = [] # get experiment name from token experiment_name = parser.stream.current args.append(self._name_or_const(experiment_name)) next(parser.stream) # we will also need the context in the callback: args.append(nodes.ContextReference()) # expecting `as` after the alternatives: if not self._token_as(parser): raise TemplateSyntaxError( 'Syntax should be like: ' '{% experiment_enrolled_alternative "experiment_name"' ' as some_variable %}', lineno, ) next(parser.stream) # parse what comes after `as`: target = parser.parse_assign_target() # create a callback node that will be executed on render: call_node = self.call_method('render_experiment_enrolled_alternative', args, lineno=lineno) # return an assignment node that will trigger the callback: return nodes.Assign(target, call_node, lineno=lineno)
class HamlishExtension(Extension): def __init__(self, environment): super(HamlishExtension, self).__init__(environment) environment.extend( hamlish_mode=getattr(settings, 'HAMLISH_MODE', 'compact'), hamlish_file_extensions=getattr(settings, 'HAMLISH_FILE_EXTENSIONS', ('.haml', )), hamlish_indent_string=getattr(settings, 'HAMLISH_INDENT_STRING', ' '), hamlish_newline_string=getattr(settings, 'HAMLISH_NEWLINE_STRING', '\n'), hamlish_debug=getattr(settings, 'HAMLISH_DEBUG', False), hamlish_enable_div_shortcut=getattr(settings, 'HAMLISH_ENABLE_DIV_SHORTCUT', True), ) def preprocess(self, source, name, filename=None): if not os.path.splitext(name)[1] in \ self.environment.hamlish_file_extensions: return source h = self.get_preprocessor(self.environment.hamlish_mode) try: return h.convert_source(source) except TemplateIndentationError, e: raise TemplateSyntaxError(e.message, e.lineno, name=name, filename=filename) except TemplateSyntaxError, e: raise TemplateSyntaxError(e.message, e.lineno, name=name, filename=filename)
def test(): raise TemplateSyntaxError('wtf', 42)
def test_pickleable_syntax_error(self, fs_env): original = TemplateSyntaxError("bad template", 42, "test", "test.txt") unpickled = pickle.loads(pickle.dumps(original)) assert str(original) == str(unpickled) assert original.name == unpickled.name
def _embed_extension_parse(self, open_token_condition, close_token_condition, parser): args = [ nodes.ContextReference(), nodes.Const(parser.filename), nodes.Const(parser.stream.current.lineno) ] kwargs = {} name_token = parser.stream.expect(open_token_condition) automata_state = AutomataState.Expect_Name content_path = None while parser.stream.current.type != TOKEN_BLOCK_END: if automata_state == AutomataState.Expect_Name: name_token = parser.stream.expect(TOKEN_NAME) automata_state = AutomataState.Expect_Assign elif automata_state == AutomataState.Expect_Assign: parser.stream.skip_if(TOKEN_ASSIGN) automata_state = AutomataState.Expect_Value elif automata_state == AutomataState.Expect_Value: value_token = parser.stream.next_if(TOKEN_FLOAT) if value_token: kwargs[name_token.value] = value_token.value else: value_token = parser.stream.next_if(TOKEN_INTEGER) if value_token: kwargs[name_token.value] = value_token.value else: value_token = parser.stream.expect(TOKEN_STRING) if name_token.value == 'absolute_path': content_path = normpath( abspath( join(parser.environment.globals['source_path'], value_token.value))) elif name_token.value == 'relative_path': content_path = normpath( abspath( join(dirname(parser.filename), value_token.value))) else: kwargs[name_token.value] = value_token.value automata_state = AutomataState.Expect_Comma elif automata_state == AutomataState.Expect_Comma: parser.stream.skip_if(TOKEN_COMMA) automata_state = AutomataState.Expect_Name lineno = parser.stream.current.lineno if content_path is not None: if not isfile(content_path): raise TemplateSyntaxError( f'Cannot find content file "{content_path}".', lineno, parser.filename) kwargs['content_path'] = content_path body = [] else: body = parser.parse_statements([close_token_condition], drop_needle=True) return nodes.CallBlock( self.call_method('_process_markup', args, [ nodes.Keyword(name, nodes.Const(value)) for name, value in kwargs.items() ]), [], [], body).set_lineno(lineno)
def test(): raise TemplateSyntaxError("wtf", 42)