[svn] doc update, setup.py update, added turbogears plugin
authorArmin Ronacher <armin.ronacher@active-4.com>
Sat, 3 Mar 2007 10:22:18 +0000 (11:22 +0100)
committerArmin Ronacher <armin.ronacher@active-4.com>
Sat, 3 Mar 2007 10:22:18 +0000 (11:22 +0100)
--HG--
branch : trunk

21 files changed:
docs/src/filters.txt [new file with mode: 0644]
docs/src/installation.txt [new file with mode: 0644]
docs/src/loaders.txt
docs/src/tests.txt [new file with mode: 0644]
docs/src/translators.txt [new file with mode: 0644]
jinja/__init__.py
jinja/bakerplugin.py [new file with mode: 0644]
jinja/datastructure.py
jinja/defaults.py
jinja/environment.py
jinja/exceptions.py
jinja/filters.py
jinja/lexer.py
jinja/loaders.py
jinja/nodes.py
jinja/parser.py
jinja/tests.py
jinja/translators/__init__.py
jinja/translators/python.py
jinja/utils.py
setup.py

diff --git a/docs/src/filters.txt b/docs/src/filters.txt
new file mode 100644 (file)
index 0000000..9bd3497
--- /dev/null
@@ -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 (file)
index 0000000..d185467
--- /dev/null
@@ -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/
index dbe4df34b69809190de9cec319ab11ad4a6c5364..e733a03083beb7367971876a5843c1a5150dd80a 100644 (file)
@@ -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 (file)
index 0000000..2eb5578
--- /dev/null
@@ -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 (file)
index 0000000..9bebb03
--- /dev/null
@@ -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.
index be142ee7761769aacc31ea2cacde4e5a7cd73d6e..ceaf5f5a325258ca973ac813b950170e1c7843fa 100644 (file)
@@ -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 (file)
index 0000000..d3d729c
--- /dev/null
@@ -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)
index d0b6d447daec053eea006b9b33adde1aac792a81..37a3dce188e253b3483c6f6f705bf0bd61015e8d 100644 (file)
@@ -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.
 """
 
index 8c7c9498080221a45748dabd24bbb67033262516..d5d0b86dabc8451c305ec3c4d2500acef9d5b0b9 100644 (file)
@@ -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
 }
index 4277f3433326487bc646a4fb77394eb935f2711c..d413be94d4f90c0200abadb0b3eb6e5a42e2a445 100644 (file)
@@ -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."""
index da634eddefda6cd53ac3aadc94d3920b37a3c2c7..ef8f5cf5e2a3328bce5a404a84828ddb33d13790 100644 (file)
@@ -5,7 +5,7 @@
 
     Jinja exceptions.
 
-    :copyright: 2006 by Armin Ronacher.
+    :copyright: 2007 by Armin Ronacher.
     :license: BSD, see LICENSE for more details.
 """
 
index d1ecc5d11ff0e3a65b239c2c50ec8c923943191f..d548d5a1f8d851472c41fe32d9a08711ec16f7ba 100644 (file)
@@ -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
index a2595fa2b3f79d73aef69392e123eae22056d72c..bb7dc95417d104c6d809d74160bbed2f8f4ed8b9 100644 (file)
@@ -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
index 98c4729033a835a3c83187f22d795d2d1472a936..455232d9341b0b1f487573fced27a2fc192c1d85 100644 (file)
@@ -5,7 +5,7 @@
 
     Jinja loader classes.
 
-    :copyright: 2006 by Armin Ronacher.
+    :copyright: 2007 by Armin Ronacher.
     :license: BSD, see LICENSE for more details.
 """
 
index 400e4e233c1baf3bd083a3b0896e5c91381f8b58..42326e128c96556031785c86c626bea4e2cfa6f5 100644 (file)
@@ -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
index 3150e53968f45cfd84a955b54af3dac19b628664..d25b9d3fd54457eab329e0030e87a80b209bd614 100644 (file)
@@ -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
index 95220e5a6c7b148ec0dc52307dc9c5df9c10ea2d..c73235897a7bdd47c07de7fac10bde032172300b 100644 (file)
@@ -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
index f8576bc173ab398b9ba0220a71f82a3b9c292622..1b0e37c6ed39e78f5d7698eb8d70c39eeb44ae48 100644 (file)
@@ -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.
 """
 
index b410b59b83ae5798cc0564bf83e943ef2c68b2a0..86c25778f4e74c3c5501d28542df6c96ad2c8dcc 100644 (file)
@@ -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
index 1b0df50d0cd202e43403f5871a7d18ff52eb6c5e..44b8dc92509f2d41ad9b8aa8f33c584adc7f068e 100644 (file)
@@ -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
index e301fae9f71ec87bae8bd88328d04bb4694fb192..48e1a5e27a0263293f536b01d4cc1f333fb3046c 100644 (file)
--- 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::
-
-    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
-     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-    <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
-    <head>
-        <title>My Webpage</title>
-    </head
-    <body>
-        <ul id="navigation">
-        {% for item in navigation %}
-            <li><a href="{{ item.href }}">{{ item.caption|e }}</a></li>
-        {% endfor %}
-        </ul>
-
-        <h1>My Webpage</h1>
-        {{ variable }}
-    </body>
-    </html>
-
-
-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': '<strong>hello world</strong>'
-    })
-    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]
+    '''
 )