From 8ebf1f9b3f8277ad30b544c51e68023ea8208f50 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sat, 3 Mar 2007 11:22:18 +0100 Subject: [PATCH] [svn] doc update, setup.py update, added turbogears plugin --HG-- branch : trunk --- docs/src/filters.txt | 57 +++++++++++++++++++++ docs/src/installation.txt | 64 ++++++++++++++++++++++++ docs/src/loaders.txt | 58 ++++++++++++++++++++++ docs/src/tests.txt | 30 +++++++++++ docs/src/translators.txt | 10 ++++ jinja/__init__.py | 2 +- jinja/bakerplugin.py | 93 +++++++++++++++++++++++++++++++++++ jinja/datastructure.py | 2 +- jinja/defaults.py | 4 +- jinja/environment.py | 4 +- jinja/exceptions.py | 2 +- jinja/filters.py | 2 +- jinja/lexer.py | 2 +- jinja/loaders.py | 2 +- jinja/nodes.py | 2 +- jinja/parser.py | 2 +- jinja/tests.py | 2 +- jinja/translators/__init__.py | 2 +- jinja/translators/python.py | 2 +- jinja/utils.py | 2 +- setup.py | 91 ++++++---------------------------- 21 files changed, 342 insertions(+), 93 deletions(-) create mode 100644 docs/src/filters.txt create mode 100644 docs/src/installation.txt create mode 100644 docs/src/tests.txt create mode 100644 docs/src/translators.txt create mode 100644 jinja/bakerplugin.py diff --git a/docs/src/filters.txt b/docs/src/filters.txt new file mode 100644 index 0000000..9bd3497 --- /dev/null +++ b/docs/src/filters.txt @@ -0,0 +1,57 @@ +================ +Filter Functions +================ + +Filters are a powerful feature of Jinja taken from django which probably took +it from UNIX. The idea is that you "pipe" a value through some filters to +do something with it. For example convert it to upper case, escape it or +replace a substring. + +Jinja comes with some builtin filters explained in the `designer documentation`_. + +Writing Filters +=============== + +A filter basically is a factory function. Thus a function that returns another +function. We do this because filters can get an unlimited amount of position +arguments and aditionally should gain access to the environment, context and +piped value. A simple filter looks like this: + +.. sourcecode:: python + + def do_join(d=u''): + def wrapped(env, context, value): + tmp = [] + for item in value: + tmp.append(env.to_unicode(item)) + return d.join(tmp) + return wrapped + +Now you have to register that filter on an environment: + +.. sourcecode:: python + + env.filters['join'] = do_join + +In fact this filter is already bundled so you won't see any effect. But its +should explain how such a filter looks like. The template designer can just +trigger the outer code (eg: call do_join with or without arguments). The +returned function is then processed by the jinja template engine once all +filters are created. + +If you want to create filters that just operate on string (in fact unicode +objects) you can use the `stringfilter` decorator: + +.. sourcecode:: python + + from jinja.filters import stringfilter + + @stringfilter + def do_strip(value): + return value.strip() + +The wrapped function is created internally by the decorator, any positional +arguments are forwarded to the filter function. The first argument is always +the value already converted into a string. + +.. _designer documentation: designerdoc.txt diff --git a/docs/src/installation.txt b/docs/src/installation.txt new file mode 100644 index 0000000..d185467 --- /dev/null +++ b/docs/src/installation.txt @@ -0,0 +1,64 @@ +============ +Installation +============ + +Jinja requires at least Python 2.3 to work correctly. + +Installing a released version +============================= + +As a Python egg (via easy_install) +---------------------------------- + +You can install the most recent Jinja version using `easy_install`_:: + + sudo easy_install Jinja + +This will install a Jinja egg in your Python installation's site-packages +directory. + + +From the tarball release +------------------------- + +1. Download the most recent tarball from the `download page`_ +2. Unpack the tarball +3. ``sudo python setup.py install`` + +Note that the last command will automatically download and install +`setuptools`_ if you don't already have it installed. This requires a working +internet connection. + +This will install Jinja into your Python installation's site-packages directory. + + +Installing the development version +================================== + +If you want to play around with the code +---------------------------------------- + +1. Install `Subversion`_ +2. ``svn co http://trac.pocoo.org/repos/jinja/trunk jinja`` +3. ``cd jinja`` +4. ``ln -s jinja /usr/lib/python2.X/site-packages`` + +As an alternative to steps 4 you can also do ``python setup.py develop`` +which will install the package via setuptools in development mode. + +If you just want the latest features and use them +------------------------------------------------- + +:: + + sudo easy_install Jinja==dev + +This will install a Jinja egg containing the latest Subversion trunk code +in your Python installation's site-packages directory. Every time the command +is run, the sources are updated from Subversion. + + +.. _download page: http://jinja.pocoo.org/download/ +.. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools +.. _easy_install: http://peak.telecommunity.com/DevCenter/EasyInstall +.. _Subversion: http://subversion.tigris.org/ diff --git a/docs/src/loaders.txt b/docs/src/loaders.txt index dbe4df3..e733a03 100644 --- a/docs/src/loaders.txt +++ b/docs/src/loaders.txt @@ -8,3 +8,61 @@ Builtin Loaders =============== [[list_of_loaders]] + +Developing Loaders +================== + +Template loaders are just normal python classes that have to provide some +functions used to load and translate templates. Here a simple loader implementation +you can use as base for your own loader: + +.. sourcecode:: python + + from os.path import join + from jinja.parser import Parser + from jinja.exceptions import TemplateNotFound + + class SimpleLoader(object): + """ + Slimmed down version of the included `FileSystemLoader`. + """ + + def __init__(self, searchpath): + self.searchpath = searchpath + + def get_source(self, environment, name, parent): + """ + The get_source function is unused at the moment. However future + versions of jinja will use this function for the debugging + system. It also works as helper functions for `parse` and + `load`. + """ + filename = join(self.searchpath, name) + if not path.exists(filename): + raise TemplateNotFound(name) + f = codecs.open(filename, 'r', environment.template_charset) + try: + return f.read() + finally: + f.close() + + def parse(self, environment, name, parent): + """ + Load and parse a template and return the syntax tree. + """ + source = self.get_source(environment, name, parent) + return Parser(environment, source, name).parse() + + def load(self, environment, name, translator): + """ + Parse and translate a template. Currently only translation to + python code is possible, later jinja versions however will + support translating templates to javascript too. + """ + return translator.process(environment, self.parse(environment, name, None)) + + +.. admonition:: Note + + Once a loader is bound to an environment you have to omit the environment + argument for the public functions `get_source`, `parse` and `load`. diff --git a/docs/src/tests.txt b/docs/src/tests.txt new file mode 100644 index 0000000..2eb5578 --- /dev/null +++ b/docs/src/tests.txt @@ -0,0 +1,30 @@ +============== +Test Functions +============== + +Additionally to filters Jinja also supports test functions. Test functions +always return either ``True`` or ``False``. Inside the template they are available +using the `is` operator. + +Jinja comes with some builtin tests listed in the `designer documentation`_. + +Writing Test Functions +====================== + +Test functions look exactly like filters mentioned in the `filter documentation`_: + +.. sourcecode:: python + + def is_even(): + def wrapped(env, context, value): + return value % 2 == 0 + return wrapped + +Now you have to register that test on an environment: + +.. sourcecode:: python + + env.tests['even'] = is_even + +.. _designer documentation: designerdoc.txt +.. _filter documentation: filters.txt diff --git a/docs/src/translators.txt b/docs/src/translators.txt new file mode 100644 index 0000000..9bebb03 --- /dev/null +++ b/docs/src/translators.txt @@ -0,0 +1,10 @@ +=========== +Translators +=========== + +Jinja translates the template sourcecode into executable python code behind +the secenes. This is done by the python translator which is currently the +only shipped translator. Because the interface isn't stable it's also not +recommended to write other translators. However for the next Jinja version +a JavaScript translator is planned which allows you to translate Jinja +templates into executable JavaScript code. diff --git a/jinja/__init__.py b/jinja/__init__.py index be142ee..ceaf5f5 100644 --- a/jinja/__init__.py +++ b/jinja/__init__.py @@ -3,7 +3,7 @@ Jinja Sandboxed Template Engine ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :copyright: 2006 by Armin Ronacher. + :copyright: 2007 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ from jinja.environment import Environment diff --git a/jinja/bakerplugin.py b/jinja/bakerplugin.py new file mode 100644 index 0000000..d3d729c --- /dev/null +++ b/jinja/bakerplugin.py @@ -0,0 +1,93 @@ +# -*- coding: utf-8 -*- +""" + jinja.bakerplugin + ~~~~~~~~~~~~~~~~~ + + Provide a bridge to baker. Baker is used by some frameworks (namely + CherryPy, TurboGears and Pylons) to load templates. + + :copyright: 2007 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" +from jinja import Environment + + +class ConfigurationError(Exception): + """ + Raised if an configuration error occoured. + """ + + +class JinjaPlugin(object): + """ + Implementation of the Plugin API + """ + extension = 'html' + + def __init__(self, extra_vars_func=None, options=None): + self.get_extra_vars = extra_vars_func + options = options or {} + self.extension = options.get('jinja.extension', JinjaPlugin.extension) + if 'jinja.environment' in options: + self.environment = options['jinja.environment'] + else: + # this wonderful piece of code was brought to you by the turbogears + # ppl who want to put template configuration stuff into goddamn + # text/plain configuration files. + if 'jinja.environment.loader' in options: + loader = options['jinja.environment.loader'] + else: + loadername = options.get('jinja.loader') or 'FileSystemLoader' + if '.' in loadername: + p = loadername.rsplit('.', 1) + loadercls = getattr(__import__(p[0], '', '', ['']), p[1]) + else: + from jinja import loaders + loadercls = getattr(loaders, loadername) + loaderoptions = {} + for k, v in options.iteritems(): + if k.startswith('jinja.loader.'): + loaderoptions[k[14:]] = v + loader = loadercls(**loaderoptions) + self.environment = Environment( + block_start_string=options.get('jinja.block_start_string', '{%'), + block_end_string=options.get('jinja.block_end_string', '%}'), + variable_start_string=options.get('jinja.variable_start_string', '{{'), + variable_end_string=options.get('jinja.variable_end_string', '}}'), + comment_start_string=options.get('jinja.comment_start_string', '{#'), + comment_end_string=options.get('jinja.comment_end_string', '#}'), + trim_blocks=str(options.get('jinja.trim_blocks')).lower() in + ('true', 'on', 'yes', '1'), + template_charset=options.get('jinja.template_charset', 'utf-8'), + charset=options.get('jinja.charset', 'utf-8'), + namespace=options.get('jinja.namespace'), + loader=loader, + filters=options.get('jinja.filters'), + tests=options.get('jinja.tests') + ) + + def load_template(self, templatename, template_string=None): + """ + Find a template specified in python 'dot' notation, or load one from + a string. + """ + if template_string is not None: + return self.environment.from_string(template_string) + + # Translate TG dot notation to normal / template path + if '/' not in templatename and '.' not in templatename: + templatename = '/' + templatename.replace('.', '/') + '.' + self.extension + + return self.environment.get_template(templatename) + + def render(self, info, format='html', fragment=False, template=None): + """ + Render a template. + """ + if isinstance(template, basestring): + template = self.load_template(template) + + if self.get_extra_vars: + info.update(self.get_extra_vars()) + + return template.render(**info) diff --git a/jinja/datastructure.py b/jinja/datastructure.py index d0b6d44..37a3dce 100644 --- a/jinja/datastructure.py +++ b/jinja/datastructure.py @@ -5,7 +5,7 @@ Module that helds several data types used in the template engine. - :copyright: 2006 by Armin Ronacher. + :copyright: 2007 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ diff --git a/jinja/defaults.py b/jinja/defaults.py index 8c7c949..d5d0b86 100644 --- a/jinja/defaults.py +++ b/jinja/defaults.py @@ -5,13 +5,13 @@ Jinja default filters and tags. - :copyright: 2006 by Armin Ronacher. + :copyright: 2007 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ from jinja.filters import FILTERS as DEFAULT_FILTERS from jinja.tests import TESTS as DEFAULT_TESTS +#: for global objects in later jinja releases. (add stuff like debug()) DEFAULT_NAMESPACE = { - 'range': xrange } diff --git a/jinja/environment.py b/jinja/environment.py index 4277f34..d413be9 100644 --- a/jinja/environment.py +++ b/jinja/environment.py @@ -5,7 +5,7 @@ Provides a class that holds runtime and parsing time options. - :copyright: 2006 by Armin Ronacher. + :copyright: 2007 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ import re @@ -68,7 +68,7 @@ class Environment(object): Get or set the template loader. """ self._loader = LoaderWrapper(self, value) - loader = property(lambda s: s._loader.loader, loader, loader.__doc__) + loader = property(lambda s: s._loader, loader, loader.__doc__) def parse(self, source, filename=None): """Function that creates a new parser and parses the source.""" diff --git a/jinja/exceptions.py b/jinja/exceptions.py index da634ed..ef8f5cf 100644 --- a/jinja/exceptions.py +++ b/jinja/exceptions.py @@ -5,7 +5,7 @@ Jinja exceptions. - :copyright: 2006 by Armin Ronacher. + :copyright: 2007 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ diff --git a/jinja/filters.py b/jinja/filters.py index d1ecc5d..d548d5a 100644 --- a/jinja/filters.py +++ b/jinja/filters.py @@ -5,7 +5,7 @@ Bundled jinja filters. - :copyright: 2006 by Armin Ronacher. + :copyright: 2007 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ from random import choice diff --git a/jinja/lexer.py b/jinja/lexer.py index a2595fa..bb7dc95 100644 --- a/jinja/lexer.py +++ b/jinja/lexer.py @@ -3,7 +3,7 @@ jinja.lexer ~~~~~~~~~~~ - :copyright: 2006 by Armin Ronacher. + :copyright: 2007 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ import re diff --git a/jinja/loaders.py b/jinja/loaders.py index 98c4729..455232d 100644 --- a/jinja/loaders.py +++ b/jinja/loaders.py @@ -5,7 +5,7 @@ Jinja loader classes. - :copyright: 2006 by Armin Ronacher. + :copyright: 2007 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ diff --git a/jinja/nodes.py b/jinja/nodes.py index 400e4e2..42326e1 100644 --- a/jinja/nodes.py +++ b/jinja/nodes.py @@ -5,7 +5,7 @@ Additional nodes for jinja. Look like nodes from the ast. - :copyright: 2006 by Armin Ronacher. + :copyright: 2007 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ from compiler import ast diff --git a/jinja/parser.py b/jinja/parser.py index 3150e53..d25b9d3 100644 --- a/jinja/parser.py +++ b/jinja/parser.py @@ -5,7 +5,7 @@ Implements the template parser. - :copyright: 2006 by Armin Ronacher. + :copyright: 2007 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ import re diff --git a/jinja/tests.py b/jinja/tests.py index 95220e5..c732358 100644 --- a/jinja/tests.py +++ b/jinja/tests.py @@ -5,7 +5,7 @@ Jinja test functions. Used with the "is" operator. - :copyright: 2006 by Armin Ronacher. + :copyright: 2007 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ import re diff --git a/jinja/translators/__init__.py b/jinja/translators/__init__.py index f8576bc..1b0e37c 100644 --- a/jinja/translators/__init__.py +++ b/jinja/translators/__init__.py @@ -6,7 +6,7 @@ The submodules of this module provide translators for the jinja ast which basically just is the python ast with a few more nodes. - :copyright: 2006 by Armin Ronacher. + :copyright: 2007 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ diff --git a/jinja/translators/python.py b/jinja/translators/python.py index b410b59..86c2577 100644 --- a/jinja/translators/python.py +++ b/jinja/translators/python.py @@ -5,7 +5,7 @@ This module translates a jinja ast into python code. - :copyright: 2006 by Armin Ronacher. + :copyright: 2007 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ from compiler import ast diff --git a/jinja/utils.py b/jinja/utils.py index 1b0df50..44b8dc9 100644 --- a/jinja/utils.py +++ b/jinja/utils.py @@ -5,7 +5,7 @@ Utility functions. - :copyright: 2006 by Armin Ronacher. + :copyright: 2007 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ import re diff --git a/setup.py b/setup.py index e301fae..48e1a5e 100644 --- a/setup.py +++ b/setup.py @@ -9,84 +9,13 @@ from setuptools import setup setup( name = 'Jinja', - version = '0.9', - url = 'http://wsgiarea.pocoo.org/jinja/', + version = '1.0', + url = 'http://jinja.pocoo.org/', license = 'BSD', author = 'Armin Ronacher', author_email = 'armin.ronacher@active-4.com', description = 'A small but fast and easy to use stand-alone template engine written in pure python.', - long_description = '''\ -Jinja is a small but very fast and easy to use stand-alone template engine -written in pure Python. - -Since version 0.6 it uses a new parser that increases parsing performance -a lot by caching the nodelists on disk if wanted. - -It includes multiple template inheritance and other features like simple -value escaping. - - -Template Syntax -=============== - -This is a small example template in which you can see how Jinja's syntax -looks like:: - - - - - My Webpage - - - -

My Webpage

- {{ variable }} - - - - -Usage -===== - -Here is a small example:: - - from jinja import Template, Context, FileSystemLoader - - t = Template('mytemplate', FileSystemLoader('/path/to/the/templates')) - c = Context({ - 'navigation' [ - {'href': '#', 'caption': 'Index'}, - {'href': '#', 'caption': 'Spam'} - ], - 'variable': 'hello world' - }) - print t.render(c) - - -Unicode Support -=============== - -Jinja comes with built-in Unicode support. As a matter of fact, the return -value of ``Template.render()`` will be a Python unicode object. - -You can still output ``str`` objects as well when you encode the result:: - - s = t.render(c).encode('utf-8') - -For more examples check out the `documentation`_ on the `jinja webpage`_. - -.. _documentation: http://wsgiarea.pocoo.org/jinja/docs/ -.. _jinja webpage: http://wsgiarea.pocoo.org/jinja/ -''', - keywords = 'wsgi web templateengine templates', - packages = ['jinja'], - platforms = 'any', + zip_safe = True, classifiers = [ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', @@ -94,7 +23,15 @@ For more examples check out the `documentation`_ on the `jinja webpage`_. 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', - 'Topic :: Internet :: WWW/HTTP', - 'Topic :: Internet :: WWW/HTTP :: Dynamic Content' - ] + 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', + 'Topic :: Software Development :: Libraries :: Python Modules', + 'Topic :: Text Processing :: Markup :: HTML' + ], + keywords = ['python.templating.engines'], + packages = ['jinja'], + extras_require = {'plugin': ['setuptools>=0.6a2']}, + entry_points=''' + [python.templating.engines] + jinja = jinja.bakerplugin:JinjaPlugin[plugin] + ''' ) -- 2.26.2