I want to add a custom filter to jinja2 and I found that there is a way to do that through adding a .lib.templatetools.jinja_filters.py module, so I tryed it...
Every function defined in this module become a filter. But not only functions :-(, everything imported in this module is included in the filter's dict !
I'm not sure this was the expected behavior.
Could not it be a .lib.templatetools.py that would contain functions and a dict named jinja_filters that would contain the filters like in the config file ? jinja_filters = dict(filter_name=filter_fct, ...) ?
The only change in tg.configuration.app_config.py
change :
# Try to load custom filters module under app_package.lib.templatetools
try:
filter_package = self.package.__name__ + ".lib.templatetools"
autoload_lib = __import__(filter_package, {}, {}, ['jinja_filters'])
autoload_filters = autoload_lib.jinja_filters.__dict__
except (ImportError, AttributeError):
autoload_filters = {}
by :
# Try to load custom filters module under app_package.lib.templatetools
try:
filter_package = self.package.__name__ + ".lib.templatetools"
autoload_lib = __import__(filter_package, {}, {}, ['jinja_filters'])
autoload_filters = autoload_lib.jinja_filters # suppress the .__dict__
except (ImportError, AttributeError):
autoload_filters = {}
On Sat, Sep 29, 2012 at 12:09 PM, Remi Jolin <remi.jo...@sysgroup.fr> wrote:
> Hello,
> I want to add a custom filter to jinja2 and I found that there is a way to
> do that through adding a .lib.templatetools.jinja_filters.py module, so I
> tryed it...
> Every function defined in this module become a filter. But not only
> functions :-(, everything imported in this module is included in the
> filter's dict !
> I'm not sure this was the expected behavior.
> Could not it be a .lib.templatetools.py that would contain functions and a
> dict named jinja_filters that would contain the filters like in the config
> file ? jinja_filters = dict(filter_name=filter_fct, ...) ?
> The only change in tg.configuration.app_config.py
> change :
> # Try to load custom filters module under
> app_package.lib.templatetools
> try:
> filter_package = self.package.__name__ + ".lib.templatetools"
> autoload_lib = __import__(filter_package, {}, {},
> ['jinja_filters'])
> autoload_filters = autoload_lib.jinja_filters.__dict__
> except (ImportError, AttributeError):
> autoload_filters = {}
> --
> You received this message because you are subscribed to the Google Groups
> "TurboGears" group.
> To post to this group, send email to turbogears@googlegroups.com.
> To unsubscribe from this group, send email to
> turbogears+unsubscribe@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/turbogears?hl=en.
No, I tried this... It does nothing but adding one more filter '__all__' to the filters' list. The __dict__ of an imported module containes all the definitions, imported modules, etc.
> I'm not actually sure, but shouldn't defining __all__ inside your
> jinja_filter.py solve the issue?
> On Sat, Sep 29, 2012 at 12:09 PM, Remi Jolin<remi.jo...@sysgroup.fr> wrote:
>> Hello,
>> I want to add a custom filter to jinja2 and I found that there is a way to
>> do that through adding a .lib.templatetools.jinja_filters.py module, so I
>> tryed it...
>> Every function defined in this module become a filter. But not only
>> functions :-(, everything imported in this module is included in the
>> filter's dict !
>> I'm not sure this was the expected behavior.
>> Could not it be a .lib.templatetools.py that would contain functions and a
>> dict named jinja_filters that would contain the filters like in the config
>> file ? jinja_filters = dict(filter_name=filter_fct, ...) ?
>> The only change in tg.configuration.app_config.py
>> change :
>> # Try to load custom filters module under
>> app_package.lib.templatetools
>> try:
>> filter_package = self.package.__name__ + ".lib.templatetools"
>> autoload_lib = __import__(filter_package, {}, {},
>> ['jinja_filters'])
>> autoload_filters = autoload_lib.jinja_filters.__dict__
>> except (ImportError, AttributeError):
>> autoload_filters = {}
>> --
>> You received this message because you are subscribed to the Google Groups
>> "TurboGears" group.
>> To post to this group, send email to turbogears@googlegroups.com.
>> To unsubscribe from this group, send email to
>> turbogears+unsubscribe@googlegroups.com.
>> For more options, visit this group at
>> http://groups.google.com/group/turbogears?hl=en.
Ah, right, I saw right now that it imports the module itself not using
from form.
Probably the most pythonic way to solve the issue is change the jinja
filters setup to care about __all__, in the mean time you can simply
write your jinja filters inside something like jinja_filters_impl.py
and then just do from jinja_filter_impl import whatyouwant into
.lib.templatetools.jinja_filters
On Sat, Sep 29, 2012 at 3:53 PM, Remi Jolin <remi.jo...@sysgroup.fr> wrote:
> No, I tried this... It does nothing but adding one more filter '__all__' to
> the filters' list. The __dict__ of an imported module containes all the
> definitions, imported modules, etc.
> Le 29/09/2012 15:14, Alessandro Molina a écrit :
>> I'm not actually sure, but shouldn't defining __all__ inside your
>> jinja_filter.py solve the issue?
>> On Sat, Sep 29, 2012 at 12:09 PM, Remi Jolin<remi.jo...@sysgroup.fr>
>> wrote:
>>> Hello,
>>> I want to add a custom filter to jinja2 and I found that there is a way
>>> to
>>> do that through adding a .lib.templatetools.jinja_filters.py module, so I
>>> tryed it...
>>> Every function defined in this module become a filter. But not only
>>> functions :-(, everything imported in this module is included in the
>>> filter's dict !
>>> I'm not sure this was the expected behavior.
>>> Could not it be a .lib.templatetools.py that would contain functions and
>>> a
>>> dict named jinja_filters that would contain the filters like in the
>>> config
>>> file ? jinja_filters = dict(filter_name=filter_fct, ...) ?
>>> The only change in tg.configuration.app_config.py
>>> change :
>>> # Try to load custom filters module under
>>> app_package.lib.templatetools
>>> try:
>>> filter_package = self.package.__name__ +
>>> ".lib.templatetools"
>>> autoload_lib = __import__(filter_package, {}, {},
>>> ['jinja_filters'])
>>> autoload_filters = autoload_lib.jinja_filters.__dict__
>>> except (ImportError, AttributeError):
>>> autoload_filters = {}
>>> --
>>> You received this message because you are subscribed to the Google Groups
>>> "TurboGears" group.
>>> To post to this group, send email to turbogears@googlegroups.com.
>>> To unsubscribe from this group, send email to
>>> turbogears+unsubscribe@googlegroups.com.
>>> For more options, visit this group at
>>> http://groups.google.com/group/turbogears?hl=en.
> --
> You received this message because you are subscribed to the Google Groups
> "TurboGears" group.
> To post to this group, send email to turbogears@googlegroups.com.
> To unsubscribe from this group, send email to
> turbogears+unsubscribe@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/turbogears?hl=en.
Seems that using __import__ function does not setup imported namespace
as does the sintax "for module import *", thus the dict of the module
includes any other imports.
A quick solution for now could be trying to get the __all__ directly
from the filters module (this works if you defined it) with a fallback
to the __dict__ dictionary checking to get only callables. I have this
working and could push to my fork if there is no better suggestion and
then send a pull request.
> Ah, right, I saw right now that it imports the module itself not using
> from form.
> Probably the most pythonic way to solve the issue is change the jinja
> filters setup to care about __all__, in the mean time you can simply
> write your jinja filters inside something like jinja_filters_impl.py
> and then just do from jinja_filter_impl import whatyouwant into
> .lib.templatetools.jinja_filters
All other jinja filters configuration is done by defining a dict :
so having to define a jinja_filters dict in templatetools.py (or templatetools.__init__.py) does not seem to be a bad idea to me.
Much simpler than the current solution (so I would say more pythonic ;-) )
Is the templatetools directory supposed to contain something else than jinja_filters.py (AND __init__.py or it doesn't work !) ?
> On Sat, Sep 29, 2012 at 3:53 PM, Remi Jolin<remi.jo...@sysgroup.fr> wrote:
>> No, I tried this... It does nothing but adding one more filter '__all__' to
>> the filters' list. The __dict__ of an imported module containes all the
>> definitions, imported modules, etc.
>> Le 29/09/2012 15:14, Alessandro Molina a crit :
>>> I'm not actually sure, but shouldn't defining __all__ inside your
>>> jinja_filter.py solve the issue?
>>> On Sat, Sep 29, 2012 at 12:09 PM, Remi Jolin<remi.jo...@sysgroup.fr>
>>> wrote:
>>>> Hello,
>>>> I want to add a custom filter to jinja2 and I found that there is a way
>>>> to
>>>> do that through adding a .lib.templatetools.jinja_filters.py module, so I
>>>> tryed it...
>>>> Every function defined in this module become a filter. But not only
>>>> functions :-(, everything imported in this module is included in the
>>>> filter's dict !
>>>> I'm not sure this was the expected behavior.
>>>> Could not it be a .lib.templatetools.py that would contain functions and
>>>> a
>>>> dict named jinja_filters that would contain the filters like in the
>>>> config
>>>> file ? jinja_filters = dict(filter_name=filter_fct, ...) ?
>>>> The only change in tg.configuration.app_config.py
>>>> change :
>>>> # Try to load custom filters module under
>>>> app_package.lib.templatetools
>>>> try:
>>>> filter_package = self.package.__name__ +
>>>> ".lib.templatetools"
>>>> autoload_lib = __import__(filter_package, {}, {},
>>>> ['jinja_filters'])
>>>> autoload_filters = autoload_lib.jinja_filters.__dict__
>>>> except (ImportError, AttributeError):
>>>> autoload_filters = {}
>>>> --
>>>> You received this message because you are subscribed to the Google Groups
>>>> "TurboGears" group.
>>>> To post to this group, send email to turbogears@googlegroups.com.
>>>> To unsubscribe from this group, send email to
>>>> turbogears+unsubscribe@googlegroups.com.
>>>> For more options, visit this group at
>>>> http://groups.google.com/group/turbogears?hl=en.
>> --
>> You received this message because you are subscribed to the Google Groups
>> "TurboGears" group.
>> To post to this group, send email to turbogears@googlegroups.com.
>> To unsubscribe from this group, send email to
>> turbogears+unsubscribe@googlegroups.com.
>> For more options, visit this group at
>> http://groups.google.com/group/turbogears?hl=en.
Le 29/09/2012 18:31, Carlos Daniel Ruvalcaba Valenzuela a crit :
> Seems that using __import__ function does not setup imported namespace
> as does the sintax "for module import *", thus the dict of the module
> includes any other imports.
> A quick solution for now could be trying to get the __all__ directly
> from the filters module (this works if you defined it) with a fallback
> to the __dict__ dictionary checking to get only callables. I have this
> working and could push to my fork if there is no better suggestion and
> then send a pull request.
I don't think it is enough to check callables in __dict__. You may have imported some functions or other callable items in jinja_filters.py.
And you also have to have an (empty) __init__.py in templatetools to get everything working.
> so having to define a jinja_filters dict in templatetools.py (or
> templatetools.__init__.py) does not seem to be a bad idea to me.
> Much simpler than the current solution (so I would say more pythonic ;-) )
> Is the templatetools directory supposed to contain something else than
> jinja_filters.py (AND __init__.py or it doesn't work !) ?
If you define a templatetools inside lib with an __init__.py, when
choosing jinja templates the code will check if there is a
jinja_filters.py module, if there is it will try to import it,
however, the problem here seems to be that this code pulls also
uneeded stuff, image you import the sys module, that will get pulled
into the filter namespace too.
The pythonic solution for this (on modules in general), is to define
the special __all__ dictionary, which tells the importer which
elements of the module should import only, but this only works if you
are using the following import form:
from module import *
We cannot do this on the setup code, we have to rely on tools such as
__module__ which does not do that work for us, but we can try to check
for __all__ and do it manually (which is my proposal.
> I don't think it is enough to check callables in __dict__. You may have
> imported some functions or other callable items in jinja_filters.py.
> And you also have to have an (empty) __init__.py in templatetools to get
> everything working.
You are right, checking for callables is not enough, but after all a
filter is just a function, even if you can decorate them with
@contextfilter and whatnot, thus the most sensible option (in my
opinion) is to have everybody use __all__. Some times you don't import
anything or have global functions (like when creating simple string
filters), thus maybe using __all__ would not be necessary, the
namespace will not be polluted in this specific case.
You need to have the __init__.py as templatetools acts as a module and
that is the pythonic way, same as controllers is a module (has an
__init__.py) even tough we only use the submodules (such as root.py).
>> so having to define a jinja_filters dict in templatetools.py (or
>> templatetools.__init__.py) does not seem to be a bad idea to me.
>> Much simpler than the current solution (so I would say more pythonic ;-) )
>> Is the templatetools directory supposed to contain something else than
>> jinja_filters.py (AND __init__.py or it doesn't work !) ?
> If you define a templatetools inside lib with an __init__.py, when
> choosing jinja templates the code will check if there is a
> jinja_filters.py module, if there is it will try to import it,
And if you forget the __init__.py file, the code won't import the existing jinja_filters.py... (without any notice)
> however, the problem here seems to be that this code pulls also
> uneeded stuff, image you import the sys module, that will get pulled
> into the filter namespace too.
Yes, that's what I discovered.
> The pythonic solution for this (on modules in general), is to define
> the special __all__ dictionary, which tells the importer which
> elements of the module should import only, but this only works if you
> are using the following import form:
> from module import *
> We cannot do this on the setup code, we have to rely on tools such as
> __module__ which does not do that work for us, but we can try to check
> for __all__ and do it manually (which is my proposal.
or import a lib.templatetools.py file containg a jinja_filters dict made on the same model as the
base_config.jinja_filters . This is my proposal :-)
> And if you forget the __init__.py file, the code won't import the existing
> jinja_filters.py... (without any notice)
You're right, that is missing on the docs, I will try to get on this too.
> or import a lib.templatetools.py file containg a jinja_filters dict made on
> the same model as the
> base_config.jinja_filters . This is my proposal :-)
When autoloading was first implemented there was a discussion on how
to do it, if I recall correctly, the reason to use
templatetools/jinja_filters.py is to not pollute the lib directory and
to have separate files for each template type so that genshi will not
import jinja stuff which does not support, thus in theory you can have
templatetools/genshi_filters.py and templatetools/jinja_filters.py at
the same time, this however, is not supported right now as Genshi,
Mako and Jinja have very different ways of handling this stuff
(special filter functions vs plain functions).
Perhaps Alessandro or Michael can comment better on this.
Le 29/09/2012 19:09, Carlos Daniel Ruvalcaba Valenzuela a crit :
> When autoloading was first implemented there was a discussion on how
> to do it, if I recall correctly, the reason to use
> templatetools/jinja_filters.py is to not pollute the lib directory and
> to have separate files for each template type so that genshi will not
> import jinja stuff which does not support, thus in theory you can have
> templatetools/genshi_filters.py and templatetools/jinja_filters.py at
> the same time, this however, is not supported right now as Genshi,
> Mako and Jinja have very different ways of handling this stuff
> (special filter functions vs plain functions).
ok, I understand.
This could work for both solutions : templatetools/jinja_filters.py with mandatory __all__ containing the filters' list and templatetools.py contianing a jinja_filters dict...
# Try to load custom filters module under app_package.lib.templatetools
try:
filter_package = self.package.__name__ + ".lib.templatetools"
autoload_lib = __import__(filter_package, {}, {}, ['jinja_filters'])
try:
filters_list = autoload_lib.jinja_filters.__all__
autoload_filters = dict([(k, autoload_lib.jinja_filters.__dict__[k]) for k in filters_list])
except AttributeError:
autoload_filters = autoload_lib.jinja_filters
except (ImportError, AttributeError):
autoload_filters = {}
On Sat, Sep 29, 2012 at 1:09 PM, Carlos Daniel Ruvalcaba Valenzuela
<clsdan...@gmail.com> wrote:
> Perhaps Alessandro or Michael can comment better on this.
I know that I've got nothing new to add. You seem to have covered the
bases very well. If you'll prepare a pull request, I'll help it get
reviewed and merged (as will Alessandro, I'm sure).
I'm not sure about having a dictionary inside the __init__.py called
jinja_filters, if you have the file and define the dict on __init__.py
you will not be able to import jinja_filters.py the way we are doing
it right now (via __import__), but we can add a special case to manage
that. Keeping it simple seems to be the way to go in my opinion.
Perhaps the jinja quickstart template could include
templatetools/__init__.py and jinja_filter.py files with some comments
to guide the developer.
> I'm not sure about having a dictionary inside the __init__.py called
> jinja_filters, if you have the file and define the dict on __init__.py
> you will not be able to import jinja_filters.py the way we are doing
> it right now (via __import__), but we can add a special case to manage
> that. Keeping it simple seems to be the way to go in my opinion.
> Perhaps the jinja quickstart template could include
> templatetools/__init__.py and jinja_filter.py files with some comments
> to guide the developer.
Currently Jinja autoescape has been set to True for upcoming releases
by default to match the behavior all the other template engines have.
I agree that an option would be great, but the default behavior should
be to enable autoscaping to be coherent with the current behavior for
the other template engines.
It probably also make sense to make this options unique for all the
template engines (much like the templates reload is) as it is probably
rare that the user is going to work with escaping enable on some
template engines and disable on others. Then we can provide a template
engine specific option to override it.
> so we can define
> base_config.jinja_extensions = ['jinja2.ext.with_', 'jinja2.ext.autoescape']
> base_config.jinja_autoescape = True
> in app_cfg.py
> or perhaps there is a better option to achieve this.
> Le 29/09/2012 21:58, Carlos Daniel Ruvalcaba Valenzuela a écrit :
>> I pushed to my development branch something very similar, but would
>> like some input from core developers before getting to the pull
>> request.
>> I'm not sure about having a dictionary inside the __init__.py called
>> jinja_filters, if you have the file and define the dict on __init__.py
>> you will not be able to import jinja_filters.py the way we are doing
>> it right now (via __import__), but we can add a special case to manage
>> that. Keeping it simple seems to be the way to go in my opinion.
>> Perhaps the jinja quickstart template could include
>> templatetools/__init__.py and jinja_filter.py files with some comments
>> to guide the developer.
>> Regards,
>> Carlos Daniel Ruvalcaba Valenzuela
> --
> You received this message because you are subscribed to the Google Groups
> "TurboGears" group.
> To post to this group, send email to turbogears@googlegroups.com.
> To unsubscribe from this group, send email to
> turbogears+unsubscribe@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/turbogears?hl=en.
> Currently Jinja autoescape has been set to True for upcoming releases
> by default to match the behavior all the other template engines have.
> I agree that an option would be great, but the default behavior should
> be to enable autoscaping to be coherent with the current behavior for
> the other template engines.
Yes of course (that's why I started looking at this issue :-) ). I initialized it to False as it was the default in the "official" TG2.2 and caming from TG1/genshi I was used to having autoescape enabled.
> It probably also make sense to make this options unique for all the
> template engines (much like the templates reload is) as it is probably
> rare that the user is going to work with escaping enable on some
> template engines and disable on others. Then we can provide a template
> engine specific option to override it.
Yes. makes sense.
> On Tue, Oct 2, 2012 at 9:10 PM, Remi Jolin<remi.jo...@sysgroup.fr> wrote:
>> Carlos,
>> While you are making changes to app_config.py could you add a new
>> configuration option to be able define autoescape at the main level :
>> if not 'jinja_filters' in self:
>> self.jinja_filters = {}
>> if not 'jinja_autoescape' in self:
>> self.jinja_autoescape = False
>> loader = ChoiceLoader(
>> [TemplateLoader(path) for path in self.paths['templates']])
>> so we can define
>> base_config.jinja_extensions = ['jinja2.ext.with_', 'jinja2.ext.autoescape']
>> base_config.jinja_autoescape = True
>> in app_cfg.py
>> or perhaps there is a better option to achieve this.
>> Le 29/09/2012 21:58, Carlos Daniel Ruvalcaba Valenzuela a crit :
>>> I pushed to my development branch something very similar, but would
>>> like some input from core developers before getting to the pull
>>> request.
>>> I'm not sure about having a dictionary inside the __init__.py called
>>> jinja_filters, if you have the file and define the dict on __init__.py
>>> you will not be able to import jinja_filters.py the way we are doing
>>> it right now (via __import__), but we can add a special case to manage
>>> that. Keeping it simple seems to be the way to go in my opinion.
>>> Perhaps the jinja quickstart template could include
>>> templatetools/__init__.py and jinja_filter.py files with some comments
>>> to guide the developer.
>>> Regards,
>>> Carlos Daniel Ruvalcaba Valenzuela
>> --
>> You received this message because you are subscribed to the Google Groups
>> "TurboGears" group.
>> To post to this group, send email to turbogears@googlegroups.com.
>> To unsubscribe from this group, send email to
>> turbogears+unsubscribe@googlegroups.com.
>> For more options, visit this group at
>> http://groups.google.com/group/turbogears?hl=en.