Discussion:
Add custom functions to use into templates
ilias
2010-11-09 19:50:49 UTC
Permalink
I would like to add my functions to be able to call them from
templates via dollar:

<p>${foo("bar")}</p>

I've found that I may extend genshi.template.eval.BUILTINS dictionary
with my functions. Is there nicer way?
--
You received this message because you are subscribed to the Google Groups "Genshi" group.
To post to this group, send email to ***@googlegroups.com.
To unsubscribe from this group, send email to genshi+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/genshi?hl=en.
Simon Cross
2010-11-09 21:40:14 UTC
Permalink
Post by ilias
I would like to add my functions to be able to call them from
<p>${foo("bar")}</p>
I've found that I may extend genshi.template.eval.BUILTINS dictionary
with my functions. Is there nicer way?
Yes. Simply pass your function into the template as part of the context.

Schiavo
Simon
--
You received this message because you are subscribed to the Google Groups "Genshi" group.
To post to this group, send email to ***@googlegroups.com.
To unsubscribe from this group, send email to genshi+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/genshi?hl=en.
Kyle Alan Hale
2010-11-10 02:31:27 UTC
Permalink
Alternatively, you can import (or define) the functions at the top of the
template itself, using a code block <
http://genshi.edgewall.org/wiki/Documentation/0.6.x/templates.html#id1>.
Post by Simon Cross
Post by ilias
I would like to add my functions to be able to call them from
<p>${foo("bar")}</p>
I've found that I may extend genshi.template.eval.BUILTINS dictionary
with my functions. Is there nicer way?
Yes. Simply pass your function into the template as part of the context.
Schiavo
Simon
--
You received this message because you are subscribed to the Google Groups "Genshi" group.
To unsubscribe from this group, send email to
.
For more options, visit this group at
http://groups.google.com/group/genshi?hl=en.
--
You received this message because you are subscribed to the Google Groups "Genshi" group.
To post to this group, send email to ***@googlegroups.com.
To unsubscribe from this group, send email to genshi+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/genshi?hl=en.
Dalton Barreto
2010-11-10 10:45:07 UTC
Permalink
Post by ilias
I would like to add my functions to be able to call them from
<p>${foo("bar")}</p>
I've found that I may extend genshi.template.eval.BUILTINS dictionary
with my functions. Is there nicer way?
I prefer to have the custom functions inside a separated .py file,
this way I can unittest them. And to add them to all template contexts
I have
a function called "render_to_response(template, data={})" that is like this:

from customfunctions import funcA, funcB, ...

def render_to_response(template_name, data={}):
tmpl = loader.load(template_name)
data.update({'funcA': funcA,
'funcB': funcB,
.....}) # just update the data hash with your
custom functions

content = tmpl.generate(**data).render('html', doctype='html')
return content

This way, I can have on any template:

${funcA("bar")}

If you have *only* your custom functions inside a separated .py
file/module you could do this:

import mycustomfunctions
....
....
data.update(mycustomfunctions.__dict__)
...
...
return ...

So, this way you won't have to remember to modify render_to_response
whenever you implement a new custom function.

Hope it helps.


p.s. I this code, the "loader" variable is a
"genshi.template.TemplateLoader" instance.
--
Dalton Barreto
http://daltonmatos.wordpress.com
--
You received this message because you are subscribed to the Google Groups "Genshi" group.
To post to this group, send email to ***@googlegroups.com.
To unsubscribe from this group, send email to genshi+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/genshi?hl=en.
Simon Cross
2010-11-10 11:14:17 UTC
Permalink
Post by Dalton Barreto
from customfunctions import funcA, funcB, ...
 tmpl = loader.load(template_name)
 data.update({'funcA': funcA,
                    'funcB': funcB,
                     .....}) # just update the data hash with your
custom functions
 content = tmpl.generate(**data).render('html', doctype='html')
 return content
${funcA("bar")}
You could also just pass in the module:

import customfunctions as funcs

def render_to_response(template_name, data={}):
tmpl = loader.load(template_name)
data['funcs'] = funcs

And then in the template:

${funcs.funcA("bar")}

There are many ways to slice this pie. :)

Schiavo
Simon
--
You received this message because you are subscribed to the Google Groups "Genshi" group.
To post to this group, send email to ***@googlegroups.com.
To unsubscribe from this group, send email to genshi+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/genshi?hl=en.
Dalton Barreto
2010-11-10 11:21:46 UTC
Permalink
Post by Simon Cross
import customfunctions as funcs
     tmpl = loader.load(template_name)
     data['funcs'] = funcs
${funcs.funcA("bar")}
There are many ways to slice this pie. :)
Great!!
This way we have all custom functions inside a sandbox, and we avoid
many problems if we have a custom function with the same name of
another atribute of our application.

Thanks.
--
Dalton Barreto
http://daltonmatos.wordpress.com
--
You received this message because you are subscribed to the Google Groups "Genshi" group.
To post to this group, send email to ***@googlegroups.com.
To unsubscribe from this group, send email to genshi+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/genshi?hl=en.
ilias
2010-11-10 16:39:16 UTC
Permalink
Your ways are nice, but the data is updated on every template
rendering. I would like to add my functions at startup only like it
happens with genshi.template.eval.BUILTINS.
--
You received this message because you are subscribed to the Google Groups "Genshi" group.
To post to this group, send email to ***@googlegroups.com.
To unsubscribe from this group, send email to genshi+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/genshi?hl=en.
Carsten Klein
2010-11-11 20:40:23 UTC
Permalink
Post by ilias
Your ways are nice, but the data is updated on every template
rendering. I would like to add my functions at startup only like it
happens with genshi.template.eval.BUILTINS.
Basically, the problem lies within the generate() method:

vars = {}
if args:
assert len(args) == 1
ctxt = args[0]
if ctxt is None:
ctxt = Context(**kwargs)
else:
vars = kwargs
assert isinstance(ctxt, Context)
else:
ctxt = Context(**kwargs)


So, if you pass in a pre-defined context object as first argument, then
this will be extended by the keyword arguments passed in as optional
arguments.

So, you would basically have to copy() the context object for every
template that you are rendering. But perhaps this might turn out faster in
the end, say:

from genshi.base import Context

ctx = Context(funcs=FUNCS_DICT)
tmpl = loader.load(path)
stream = tmpl.generate(ctx.copy(), **ARGS_DICT)

Perhaps this is what you are looking for?

Regards

Carsten
--
You received this message because you are subscribed to the Google Groups "Genshi" group.
To post to this group, send email to ***@googlegroups.com.
To unsubscribe from this group, send email to genshi+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/genshi?hl=en.
Carsten Klein
2010-11-11 20:45:27 UTC
Permalink
Post by ilias
Your ways are nice, but the data is updated on every template
rendering. I would like to add my functions at startup only like it
happens with genshi.template.eval.BUILTINS.
As for my previous comment on genshi.base.Context.
It does not implement a copy() method, so you will have to ctx.push()
first, prior passing it to the generate() method of the template, like so

ctx.push()
stream = tmpl.generate(ctx, **ARGS_DICT)

If you are lucky, then at the end of the generation process, the context
will be in its initial state, i.e. just after the above push(), so that
you can easily pop() the previous template arguments and start anew, like
so

ctx.push()
stream = tmpl.generate(ctx, **ARGS_DICT)
ctx.pop()

Regards

Carsten
--
You received this message because you are subscribed to the Google Groups "Genshi" group.
To post to this group, send email to ***@googlegroups.com.
To unsubscribe from this group, send email to genshi+***@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/genshi?hl=en.
Loading...