moved concat to utils, fixed a few docstrings, fixed memory leak in _speedups.escape
--HG--
branch : trunk
diff --git a/docs/api.rst b/docs/api.rst
index a8d488b..6cab983 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -85,7 +85,7 @@
.. autoclass:: jinja2.Template
- :members: render, stream, generate, module
+ :members: render, stream, generate, make_module, module
.. attribute:: globals
diff --git a/jinja2/_speedups.c b/jinja2/_speedups.c
index 10ae6f6..5a7e9aa 100644
--- a/jinja2/_speedups.c
+++ b/jinja2/_speedups.c
@@ -2,7 +2,10 @@
* jinja2._speedups
* ~~~~~~~~~~~~~~~~
*
- * This module implements a few functions in C for better performance.
+ * This module implements a few functions in C for better performance. It
+ * also defines a `tb_set_next` function that is used to patch the debug
+ * traceback. If the speedups module is not compiled a ctypes implementation
+ * is used.
*
* :copyright: 2008 by Armin Ronacher.
* :license: BSD.
@@ -129,15 +132,8 @@
/* we don't have to escape integers, bools or floats */
if (PyInt_CheckExact(text) || PyLong_CheckExact(text) ||
PyFloat_CheckExact(text) || PyBool_Check(text) ||
- text == Py_None) {
- PyObject *args = PyTuple_New(1);
- if (!args) {
- Py_DECREF(s);
- return NULL;
- }
- PyTuple_SET_ITEM(args, 0, text);
- return PyObject_CallObject(markup, args);
- }
+ text == Py_None)
+ return PyObject_CallFunctionObjArgs(markup, text, NULL);
/* if the object has an __html__ method that performs the escaping */
PyObject *html = PyObject_GetAttrString(text, "__html__");
@@ -160,7 +156,9 @@
s = escape_unicode((PyUnicodeObject*)text);
/* convert the unicode string into a markup object. */
- return PyObject_CallFunctionObjArgs(markup, (PyObject*)s, NULL);
+ rv = PyObject_CallFunctionObjArgs(markup, (PyObject*)s, NULL);
+ Py_DECREF(s);
+ return rv;
}
diff --git a/jinja2/compiler.py b/jinja2/compiler.py
index 3d4fcbe..e3b9e53 100644
--- a/jinja2/compiler.py
+++ b/jinja2/compiler.py
@@ -17,8 +17,7 @@
from jinja2 import nodes
from jinja2.visitor import NodeVisitor, NodeTransformer
from jinja2.exceptions import TemplateAssertionError
-from jinja2.runtime import concat
-from jinja2.utils import Markup
+from jinja2.utils import Markup, concat
operators = {
diff --git a/jinja2/environment.py b/jinja2/environment.py
index 68571fd..a129c38 100644
--- a/jinja2/environment.py
+++ b/jinja2/environment.py
@@ -14,10 +14,10 @@
from jinja2.parser import Parser
from jinja2.optimizer import optimize
from jinja2.compiler import generate
-from jinja2.runtime import Undefined, Context, concat
+from jinja2.runtime import Undefined, Context
from jinja2.debug import translate_exception, translate_syntax_error
from jinja2.exceptions import TemplateSyntaxError
-from jinja2.utils import import_string, LRUCache, Markup, missing
+from jinja2.utils import import_string, LRUCache, Markup, missing, concat
# for direct template usage we have up to ten living environments
@@ -530,8 +530,11 @@
return Context(self.environment, parent, self.name, self.blocks)
def make_module(self, vars=None, shared=False):
- """Like the `module` property but always reevaluates the template
- and it's possible to provide a context.
+ """This method works like the :attr:`module` attribute when called
+ without arguments but it will evaluate the template every call
+ rather then caching the template. It's also possible to provide
+ a dict which is then used as context. The arguments are the same
+ as fo the :meth:`new_context` method.
"""
return TemplateModule(self, self.new_context(vars, shared))
@@ -593,7 +596,7 @@
# compiler too. The Include without context passing directly
# uses the mangled name. The reason why we use a mangled one
# is to avoid name clashes with macros with those names.
- self.__body_stream = tuple(template.root_render_func(context))
+ self.__body_stream = list(template.root_render_func(context))
self.__dict__.update(context.get_exported())
self.__name__ = template.name
diff --git a/jinja2/filters.py b/jinja2/filters.py
index 850079d..09b1bab 100644
--- a/jinja2/filters.py
+++ b/jinja2/filters.py
@@ -11,11 +11,7 @@
import re
import math
from random import choice
-try:
- from operator import itemgetter
-except ImportError:
- itemgetter = lambda a: lambda b: b[a]
-from urllib import urlencode, quote
+from operator import itemgetter
from itertools import imap, groupby
from jinja2.utils import Markup, escape, pformat, urlize, soft_unicode
from jinja2.runtime import Undefined
diff --git a/jinja2/nodes.py b/jinja2/nodes.py
index d0372e8..83d7573 100644
--- a/jinja2/nodes.py
+++ b/jinja2/nodes.py
@@ -13,10 +13,10 @@
:license: BSD, see LICENSE for more details.
"""
import operator
+from copy import copy
from types import FunctionType
from itertools import chain, izip
from collections import deque
-from copy import copy
from jinja2.utils import Markup
diff --git a/jinja2/optimizer.py b/jinja2/optimizer.py
index 784c3a8..283d1fa 100644
--- a/jinja2/optimizer.py
+++ b/jinja2/optimizer.py
@@ -18,7 +18,8 @@
"""
from jinja2 import nodes
from jinja2.visitor import NodeVisitor, NodeTransformer
-from jinja2.runtime import LoopContext, concat
+from jinja2.runtime import LoopContext
+from jinja2.utils import concat
def optimize(node, environment, context_hint=None):
diff --git a/jinja2/runtime.py b/jinja2/runtime.py
index 417fa70..4b9ce6d 100644
--- a/jinja2/runtime.py
+++ b/jinja2/runtime.py
@@ -11,7 +11,7 @@
import sys
from types import FunctionType
from itertools import chain, imap
-from jinja2.utils import Markup, partial, soft_unicode, escape, missing
+from jinja2.utils import Markup, partial, soft_unicode, escape, missing, concat
from jinja2.exceptions import UndefinedError, TemplateRuntimeError
@@ -21,27 +21,6 @@
'markup_join', 'unicode_join']
-# concatenate a list of strings and convert them to unicode.
-# unfortunately there is a bug in python 2.4 and lower that causes
-# unicode.join trash the traceback.
-try:
- def _test_gen_bug():
- raise TypeError(_test_gen_bug)
- yield None
- u''.join(_test_gen_bug())
-except TypeError, _error:
- if _error.args and _error.args[0] is _test_gen_bug:
- concat = u''.join
- else:
- def concat(gen):
- try:
- return u''.join(list(gen))
- except:
- exc_type, exc_value, tb = sys.exc_info()
- raise exc_type, exc_value, tb.tb_next
- del _test_gen_bug, _error
-
-
def markup_join(*args):
"""Concatenation that escapes if necessary and converts to unicode."""
buf = []
diff --git a/jinja2/sandbox.py b/jinja2/sandbox.py
index 71f0239..02a0438 100644
--- a/jinja2/sandbox.py
+++ b/jinja2/sandbox.py
@@ -23,7 +23,8 @@
def safe_range(*args):
"""A range that can't generate ranges with a length of more than
- MAX_RANGE items."""
+ MAX_RANGE items.
+ """
rng = xrange(*args)
if len(rng) > MAX_RANGE:
raise OverflowError('range too big')
@@ -61,10 +62,11 @@
def is_safe_callable(self, obj):
"""Check if an object is safely callable. Per default a function is
considered safe unless the `unsafe_callable` attribute exists and is
- truish. Override this method to alter the behavior, but this won't
+ True. Override this method to alter the behavior, but this won't
affect the `unsafe` decorator from this module.
"""
- return not getattr(obj, 'unsafe_callable', False)
+ return not (getattr(obj, 'unsafe_callable', False) or \
+ getattr(obj, 'alters_data', False))
def subscribe(self, obj, argument):
"""Subscribe an object from sandboxed code."""
diff --git a/jinja2/utils.py b/jinja2/utils.py
index 7bddcfe..d9a45a8 100644
--- a/jinja2/utils.py
+++ b/jinja2/utils.py
@@ -33,6 +33,29 @@
missing = type('MissingType', (), {'__repr__': lambda x: 'missing'})()
+# concatenate a list of strings and convert them to unicode.
+# unfortunately there is a bug in python 2.4 and lower that causes
+# unicode.join trash the traceback.
+try:
+ def _test_gen_bug():
+ raise TypeError(_test_gen_bug)
+ yield None
+ u''.join(_test_gen_bug())
+except TypeError, _error:
+ if _error.args and _error.args[0] is _test_gen_bug:
+ concat = u''.join
+ else:
+ def concat(gen):
+ try:
+ return u''.join(list(gen))
+ except:
+ # this hack is needed so that the current frame
+ # does not show up in the traceback.
+ exc_type, exc_value, tb = sys.exc_info()
+ raise exc_type, exc_value, tb.tb_next
+ del _test_gen_bug, _error
+
+
def contextfunction(f):
"""This decorator can be used to mark a callable as context callable. A
context callable is passed the active context as first argument if it
diff --git a/setup.py b/setup.py
index 0c4fb31..7fe263d 100644
--- a/setup.py
+++ b/setup.py
@@ -120,8 +120,7 @@
],
packages=['jinja2'],
data_files=[
- ('docs/html', list(list_files('docs/html'))),
- ('docs/txt', list(list_files('docs/src')))
+ ##('docs', list(list_files('docs/_build/html')))
],
features={
'speedups': Feature("optional C speed-enhancements",
diff --git a/tests/test_imports.py b/tests/test_imports.py
index 7ce8bde..92495e5 100644
--- a/tests/test_imports.py
+++ b/tests/test_imports.py
@@ -13,7 +13,7 @@
module='{% macro test() %}[{{ foo }}|{{ bar }}]{% endmacro %}',
header='[{{ foo }}|{{ 23 }}]'
)))
-test_env.globals['bar'] = '23'
+test_env.globals['bar'] = 23
def test_context_imports():
@@ -44,3 +44,5 @@
test_env.from_string('{% from "foo" import bar, baz with context %}')
test_env.from_string('{% from "foo" import bar, baz, with context %}')
test_env.from_string('{% from "foo" import bar, with context %}')
+ test_env.from_string('{% from "foo" import bar, with, context %}')
+ test_env.from_string('{% from "foo" import bar, with with context %}')