improved sandbox, added proper striptags and updated documentation to latest sphinx...
authorArmin Ronacher <armin.ronacher@active-4.com>
Sun, 4 May 2008 10:31:48 +0000 (12:31 +0200)
committerArmin Ronacher <armin.ronacher@active-4.com>
Sun, 4 May 2008 10:31:48 +0000 (12:31 +0200)
--HG--
branch : trunk

docs/conf.py
docs/index.rst
docs/templates.rst
jinja2/defaults.py
jinja2/filters.py
jinja2/sandbox.py
jinja2/utils.py

index 54a1ad40c93a58898003b2763421a1d96ec66494..8a418743207b7ddcb35362ada6dadc9f68e856e6 100644 (file)
@@ -145,4 +145,4 @@ latex_preamble = '''
 #latex_appendices = []
 
 # If false, no module index is generated.
-#latex_use_modindex = True
+latex_use_modindex = False
index c548b91c6cb0cf7655747938cbc692f2c8d4f4d3..d7b4d89e809f290549fbff758b17c923ff931ae6 100644 (file)
@@ -9,10 +9,3 @@ Contents:
    intro
    api
    templates
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
index 18bd422e5e4277c5279a3246eb7d0fa2374b35a4..8d582132d8b850ffc6928ba004966c86a5565726 100644 (file)
@@ -838,3 +838,8 @@ The following functions are available in the global scope by default:
     with HTML are generated each paragraph between 20 and 100 words.  If html
     is disabled regular text is returned.  This is useful to generate simple
     contents for layout testing.
+
+.. function:: dict(**items)
+
+    A convenient alternative to dict literals.  ``{'foo': 'bar'}`` is the same
+    as ``dict(foo='bar')``.
index 848cb8f0e7067c98b34669fc8b072819fdff205d..e12493076df6ea6c213272fd9bfd6d158b4b5c35 100644 (file)
@@ -24,6 +24,7 @@ LINE_STATEMENT_PREFIX = None
 
 DEFAULT_NAMESPACE = {
     'range':        xrange,
+    'dict':         lambda **kw: kw,
     'lipsum':       generate_lorem_ipsum
 }
 
index ec0186c147648d4493dfd23f52fcdf5a1ea0780d..94086a63cd42df4a212c40ba6cafbb0fbc762aa1 100644 (file)
@@ -19,7 +19,6 @@ from jinja2.runtime import Undefined
 from jinja2.exceptions import FilterArgumentError
 
 
-_striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
 _word_re = re.compile(r'\w+')
 
 
@@ -428,7 +427,7 @@ def do_striptags(value):
     """
     if hasattr(value, '__html__'):
         value = value.__html__()
-    return u' '.join(_striptags_re.sub('', value).split())
+    return Markup(unicode(value)).striptags()
 
 
 def do_slice(value, slices, fill_with=None):
index 02a04383cefb69c6fd83b0d10080bd9dfa5b3164..cd5b5796c544c1527e1e3a9765309760c184af42 100644 (file)
@@ -20,6 +20,13 @@ from jinja2.environment import Environment
 #: maximum number of items a range may produce
 MAX_RANGE = 100000
 
+#: attributes of function objects that are considered unsafe.
+UNSAFE_FUNCTION_ATTRIBUTES = set(['func_closure', 'func_code', 'func_dict',
+                                  'func_defaults', 'func_globals'])
+
+#: unsafe method attributes.  function attributes are unsafe for methods too
+UNSAFE_METHOD_ATTRIBUTES = set(['im_class', 'im_func', 'im_self'])
+
 
 def safe_range(*args):
     """A range that can't generate ranges with a length of more than
@@ -27,7 +34,8 @@ def safe_range(*args):
     """
     rng = xrange(*args)
     if len(rng) > MAX_RANGE:
-        raise OverflowError('range too big')
+        raise OverflowError('range too big, maximum size for range is %d' %
+                            MAX_RANGE)
     return rng
 
 
@@ -54,9 +62,10 @@ class SandboxedEnvironment(Environment):
         if attr.startswith('_'):
             return False
         if isinstance(obj, FunctionType):
-            return not attr.startswith('func_')
+            return attr not in UNSAFE_FUNCTION_ATTRIBUTES
         if isinstance(obj, MethodType):
-            return not attr.startswith('im_')
+            return attr not in UNSAFE_FUNCTION_ATTRIBUTES and \
+                   attr not in UNSAFE_METHOD_ATTRIBUTES
         return True
 
     def is_safe_callable(self, obj):
index 1d579cc11d4bef763324825123ef714a2b3fd3aa..9437023c93e26f319904b25e4a7e3609a281ddfc 100644 (file)
@@ -15,6 +15,7 @@ try:
     from thread import allocate_lock
 except ImportError:
     from dummy_thread import allocate_lock
+from htmlentitydefs import name2codepoint
 from collections import deque
 from copy import deepcopy
 from itertools import imap
@@ -28,7 +29,10 @@ _punctuation_re = re.compile(
     )
 )
 _simple_email_re = re.compile(r'^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$')
-
+_striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
+_entity_re = re.compile(r'&([^;]+);')
+_entities = name2codepoint.copy()
+_entities['apos'] = 39
 
 # special singleton representing missing values for the runtime
 missing = type('MissingType', (), {'__repr__': lambda x: 'missing'})()
@@ -278,6 +282,27 @@ class Markup(unicode):
         return map(self.__class__, unicode.splitlines(self, *args, **kwargs))
     splitlines.__doc__ = unicode.splitlines.__doc__
 
+    def unescape(self):
+        """Unescape markup."""
+        def handle_match(m):
+            name = m.group(1)
+            if name in _entities:
+                return unichr(_entities[name])
+            try:
+                if name[:2] in ('#x', '#X'):
+                    return unichr(int(name[2:], 16))
+                elif name.startswith('#'):
+                    return unichr(int(name[1:]))
+            except ValueError:
+                pass
+            return u''
+        return _entity_re.sub(handle_match, unicode(self))
+
+    def striptags(self):
+        """Strip tags and resolve enities."""
+        stripped = u' '.join(_striptags_re.sub('', self).split())
+        return Markup(stripped).unescape()
+
     def make_wrapper(name):
         orig = getattr(unicode, name)
         def func(self, *args, **kwargs):