def parse(self, parser): '''parse content of extension''' # line number of token that started the tag lineno = next(parser.stream).lineno # template context context = nodes.ContextReference() # parse keyword arguments kwargs = [] while parser.stream.look().type == lexer.TOKEN_ASSIGN: key = parser.stream.expect(lexer.TOKEN_NAME) next(parser.stream) kwargs.append(nodes.Keyword(key.value, parser.parse_expression()), ) parser.stream.skip_if('comma') # parse content of the activeurl block up to endactiveurl body = parser.parse_statements(['name:endactiveurl'], drop_needle=True) args = [context] call_method = self.call_method( 'render_tag', args=args, kwargs=kwargs, ) return nodes.CallBlock(call_method, [], [], body).set_lineno(lineno)
def parse(self, parser): return nodes.Output([self.call_method('_dump', [ nodes.EnvironmentAttribute('sandboxed'), self.attr('ext_attr'), nodes.ImportedName(__name__ + '.importable_object'), nodes.ContextReference() ])]).set_lineno(next(parser.stream).lineno)
def make_call_node(*kw): return self.call_method('_reverse', args=[ viewname, nodes.List(args), nodes.Dict(kwargs), nodes.ContextReference(), ], kwargs=kw)
def parse(self, parser): # the first token is the token that started the tag. In our case # we only listen to ``'script'`` so this will be a name token with # `script` as value. We get the line number so that we can give # that line number to the nodes we create by hand. lineno = next(parser.stream).lineno # Get the current context and pass along kwargs = [nodes.Keyword('ctx', nodes.ContextReference())] # Parse until we are done with optional script tag attributes while parser.stream.current.value in SCRIPT_ATTRS: attr_name = parser.stream.current.value parser.stream.skip(2) kwargs.append( nodes.Keyword(attr_name, parser.parse_expression())) # now we parse the body of the script block up to `endscript` and # drop the needle (which would always be `endscript` in that case) body = parser.parse_statements(['name:endscript'], drop_needle=True) # now return a `CallBlock` node that calls our _render_script # helper method on this extension. return nodes.CallBlock( self.call_method('_render_script', kwargs=kwargs), [], [], body).set_lineno(lineno)
def parse(self, parser): lineno = next(parser.stream).lineno # get the context context = nodes.ContextReference() # get the arguments args = [context] try: while True: args.append(parser.parse_expression()) except TemplateSyntaxError: pass # no more arguments # get the tag_name for use in looking up callable self.active_tag = parser._tag_stack[-1] args.insert(0, nodes.Const(self.active_tag)) # create the node node = self.call_method('_invoke_tag', args=args, lineno=lineno) return nodes.Output( [node], lineno=lineno )
def parse_experiments_confirm_human(self, parser): """Parse {% experiments_confirm_human %} tags""" lineno = parser.stream.current.lineno args = [nodes.ContextReference()] node = self.call_method( 'render_experiments_confirm_human', args, lineno=lineno) return nodes.CallBlock(node, [], [], []).set_lineno(lineno)
def parse(self, parser): # the first token is the token that started the tag. In our case # we only listen to ``'webpack'`` so this will be a name token with # `webpack` as value. We get the line number so that we can give # that line number to the nodes we create by hand. lineno = six.next(parser.stream).lineno ctx_ref = nodes.ContextReference() # Parse a single expression that is the 'bundle' or 'config:bundle' args = [ctx_ref, parser.parse_expression()] # if there is a comma, the user provided an 'extensions' arg if parser.stream.skip_if('comma'): args.append(parser.parse_expression()) else: args.append(nodes.Const(None)) # now we parse the body of the cache block up to `endwebpack` and # drop the needle (which would always be `endwebpack` in that case) body = parser.parse_statements(['name:endwebpack'], drop_needle=True) call_args = [nodes.Name('ASSET', 'store')] return nodes.CallBlock(self.call_method('_get_graph', args), call_args, [], body).set_lineno(lineno)
def parse_experiment_goal(self, parser): """Parse {% experiment_goal ... %} tags""" lineno = parser.stream.current.lineno args = [nodes.ContextReference()] goal_name = parser.stream.current args.append(self._name_or_const(goal_name)) next(parser.stream) node = self.call_method('render_experiment_goal', args, lineno=lineno) return nodes.CallBlock(node, [], [], []).set_lineno(lineno)
def parse(self, parser): lineno = next(parser.stream).lineno # token = parser.stream.expect(lexer.TOKEN_STRING) context = nodes.ContextReference() call = self.call_method('_load_shared_session', [context], lineno=lineno) final = nodes.Output([call], lineno=lineno) return final
def parse(self, parser): # the first token is the token that started the tag. In our case # we only listen to ``'copyright'`` so this will be a name token with # `copyright` as value. We get the line number so that we can give # that line number to the nodes we create by hand. lineno = next(parser.stream).lineno callmethod = self.call_method('_copyright', [nodes.ContextReference()], lineno=lineno) return nodes.Output([callmethod], lineno=lineno)
def parse_experiments_prepare_conditionals(self, parser): """Parse {% experiments_prepare_conditionals %} tags""" lineno = parser.stream.current.lineno # list of nodes that will be used when calling the callback: args = [] args.append(nodes.ContextReference()) # Jinja2 callbacky nodey magic: call_node = self.call_method( 'render_experiments_prepare_conditionals', args, lineno=lineno) return nodes.CallBlock(call_node, [], [], []).set_lineno(lineno)
def parse_attrs(self, parser, add_id=True, with_context=False): attrs = {} while parser.stream.current.type != 'block_end': node = parser.parse_assign_target(with_tuple=False) if parser.stream.skip_if('assign'): attrs[node.name] = parser.parse_expression() else: attrs[node.name] = nodes.Const(node.name) if with_context: attrs['ctx'] = nodes.ContextReference() return nodes.Dict( [nodes.Pair(nodes.Const(k), v) for k, v in attrs.items()])
def parse(self, parser): token = next(parser.stream) if token.value == 'pushtemplatepath': lineno = token.lineno # parser.stream.next().lineno # now we parse a single expression, which needs to resolve to the schema file template_path = parser.parse_expression() args = [template_path, nodes.ContextReference(), nodes.Const(parser.filename)] # now return a `CallBlock` node that calls our _push_tamplate_path # helper method on this extension. return nodes.CallBlock(self.call_method('_push_template_path', args), [], [], []).set_lineno(lineno) elif token.value == 'poptemplatepath': lineno = token.lineno # parser.stream.next().lineno args = [nodes.ContextReference()] # now return a `CallBlock` node that calls our _pop_template_path # helper method on this extension. return nodes.CallBlock(self.call_method('_pop_template_path', args), [], [], []).set_lineno(lineno)
def parse(self, parser): lineno = next(parser.stream).lineno args = [] if parser.stream.current.type != 'block_end': lineno = parser.stream.current.lineno args.append ( parser.parse_expression() ) else: args.append( nodes.Const(None) ) body = parser.parse_statements(['name:endmatplotlib', 'name:endplot', 'name:end_matplotlib', 'name:end_plot'], drop_needle=True ) args.append( nodes.ContextReference() ) args.append( nodes.Name('i', 'load') ) return nodes.CallBlock(self.call_method('_execute_matplotlib', args ), [], [], body).set_lineno(lineno)
def parse(self, parser): token = next(parser.stream) if token.value == 'save_compound': lineno = token.lineno #parser.stream.next().lineno compound = parser.parse_expression() system_name = parser.parse_expression() forcefield = parser.parse_expression() args = [compound, system_name, forcefield, nodes.ContextReference()] # now return a `CallBlock` node that calls our _param_check # helper method on this extension. return nodes.CallBlock(self.call_method('_save_compound', args), [], [], []).set_lineno(lineno)
def parse(self, parser): lineno = parser.stream.next().lineno ctx_ref = nodes.ContextReference() body = parser.parse_statements(['name:endscript'], drop_needle=True) # TODO: Check we've an output node # if this is not 'unsafe' and we have dangerous children, bail out if len(body[0].nodes) > 1 or type(body[0].nodes[0])\ != nodes.TemplateData: raise Exception('{% script %} tag has an unsafe body') node = self.call_method('_render_script', [ctx_ref], lineno=lineno) return nodes.CallBlock(node, [], [], body).set_lineno(lineno)
def parse(self, parser): lineno = parser.stream.next().lineno viewlet_args = [] name = None first = True while parser.stream.current.type != 'block_end': if not first: parser.stream.expect('comma') viewlet_args.append(parser.parse_expression()) else: name = parser.parse_expression() first = False context = nodes.ContextReference() return nodes.CallBlock(self.call_method('_call_viewlet', args=[name, context, nodes.List(viewlet_args)]), [], [], []).set_lineno(lineno)
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(self, parser): lineno = parser.stream.next().lineno token = next(parser.stream) if token.value not in self.allowed_languages: raise TemplateSyntaxError( 'Expected language token from set: %s' % ', '.join(self.allowed_languages), lineno) body = parser.parse_statements(['name:endshow'], drop_needle=True) call_method = self.call_method( '_show_support', [nodes.ContextReference(), nodes.Const(token.value)], ) node = nodes.CallBlock(call_method, [], [], body).set_lineno(lineno) return node
def parse(self, parser): lineno = parser.stream.current.lineno tag_name = parser.stream.current.value additional_params = [ nodes.Keyword('_context', nodes.ContextReference()), nodes.Keyword('_template', nodes.Const(parser.name)), nodes.Keyword('_lineno', nodes.Const(lineno)), nodes.Keyword('_tag_name', nodes.Const(tag_name)), ] self.init_parser(parser) args, kwargs, target = self.parse_args(parser) kwargs.extend(additional_params) block_call = self.call_method('render_wrapper', args, kwargs) return self.output(parser, block_call, target, tag_name=tag_name, lineno=lineno)
def parse(self, parser): token = next(parser.stream) if token.value == 'redirect': lineno = token.lineno # now we parse a single expression, which needs to resolve to the file name file_name = parser.parse_expression() args = [file_name, nodes.ContextReference()] # now we parse the body of the redirect block up to `endrediret` and # drop the needle (which would always be `endredirect` in that case) body = parser.parse_statements(['name:endredirect'], drop_needle=True) # now return a `CallBlock` node that calls our _redirector # helper method on this extension. return nodes.CallBlock(self.call_method('_redirector', args), [], [], body).set_lineno(lineno)
def parse(self, parser): # the first token is the token that started the tag. In our case # we only listen to ``'typograph'`` so this will be a name token with # `typograph` as value. We get the line number so that we can give # that line number to the nodes we create by hand. lineno = next(parser.stream).lineno # now we parse the body of the block up to `endtypograph` and # drop the needle (which would always be `endtypograph` in that case) body = parser.parse_statements(['name:endtypograph'], drop_needle=True) # pass the context as an argument to called method ctx_ref = nodes.ContextReference() # now return a `CallBlock` node that calls our _typograph_support # helper method on this extension. node = self.call_method('_typograph_support', [ctx_ref], lineno=lineno) return nodes.CallBlock(node, [], [], body, lineno=lineno)
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 _empty_extension_parse(self, open_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 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) 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 return nodes.CallBlock( self.call_method('_process_markup', args, [ nodes.Keyword(name, nodes.Const(value)) for name, value in kwargs.items() ]), [], [], []).set_lineno(lineno)
def parse(self, parser): """ Parse {% py %} blocks in templates. Inserts an appropriate CallBlock into the parse tree where a {% py %} block is found, so it can be executed when the template is rendered. No actual code execution happens here. """ lineno = next(parser.stream).lineno # Get contents until an {% endpy %} declaration # drop_needle drops the {% endpy %} at the end body = parser.parse_statements(['name:endpy'], drop_needle=True) # Insert a CallBlock that'll call our `_exec_python` method with # the body of {% py %} when rendering return nodes.CallBlock( self.call_method('_exec_python', [ nodes.ContextReference(), nodes.Const(lineno), nodes.Const(parser.filename) ]), [], [], body).set_lineno(lineno)
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)
def parse(self, parser): lineno = parser.stream.next().lineno kindarg = parser.parse_expression() # Allow kind to be defined as jinja2 name node if isinstance(kindarg, nodes.Name): kindarg = nodes.Const(kindarg.name) args = [kindarg] if args[0].value not in self.compressors: raise TemplateSyntaxError('compress kind may be one of: %s' % (', '.join(self.compressors.keys())), lineno) if parser.stream.skip_if('comma'): modearg = parser.parse_expression() # Allow mode to be defined as jinja2 name node if isinstance(modearg, nodes.Name): modearg = nodes.Const(modearg.name) args.append(modearg) else: args.append(nodes.Const('file')) args.append(nodes.ContextReference()) body = parser.parse_statements(['name:endcompress'], drop_needle=True) return nodes.CallBlock(self.call_method('_compress', args), [], [], body).set_lineno(lineno)
def process_cache_arguments(self, args): args.append(nodes.Getattr(nodes.ContextReference(), 'request', 'load'))
def parse(self, parser): lineno = next(parser.stream).lineno body = parser.parse_statements(['name:endpy'], drop_needle=True) return nodes.CallBlock(self.call_method('_exec_python', [nodes.ContextReference(), nodes.Const(lineno), nodes.Const(parser.filename)]), [], [], body).set_lineno(lineno)
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)