Undefineds now support attribute errors for special attributes. This fixes #6
diff --git a/jinja2/runtime.py b/jinja2/runtime.py
index 6fea3aa..9bdeb01 100644
--- a/jinja2/runtime.py
+++ b/jinja2/runtime.py
@@ -458,11 +458,17 @@
hint = self._undefined_hint
raise self._undefined_exception(hint)
+ @internalcode
+ def __getattr__(self, name):
+ if name[:2] == '__':
+ raise AttributeError(name)
+ return self._fail_with_undefined_error()
+
__add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
__truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = \
__mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
- __getattr__ = __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = \
- __int__ = __float__ = __complex__ = __pow__ = __rpow__ = \
+ __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = __int__ = \
+ __float__ = __complex__ = __pow__ = __rpow__ = \
_fail_with_undefined_error
def __str__(self):
diff --git a/jinja2/testsuite/api.py b/jinja2/testsuite/api.py
index 7463c7f..7e11b83 100644
--- a/jinja2/testsuite/api.py
+++ b/jinja2/testsuite/api.py
@@ -180,6 +180,14 @@
t = Template('A{{ test().missingattribute }}B')
self.assert_raises(UndefinedError, t.render, test=test)
+ def test_undefined_and_special_attributes(self):
+ try:
+ Undefined('Foo').__dict__
+ except AttributeError:
+ pass
+ else:
+ assert False, "Expected actual attribute error"
+
def test_default_undefined(self):
env = Environment(undefined=Undefined)
self.assert_equal(env.from_string('{{ missing }}').render(), u'')
diff --git a/jinja2/testsuite/security.py b/jinja2/testsuite/security.py
index b2b4cf1..a95705f 100644
--- a/jinja2/testsuite/security.py
+++ b/jinja2/testsuite/security.py
@@ -56,6 +56,7 @@
self.assert_equal(env.from_string("{{ foo.bar() }}").render(foo=PublicStuff()), '23')
self.assert_equal(env.from_string("{{ foo.__class__ }}").render(foo=42), '')
self.assert_equal(env.from_string("{{ foo.func_code }}").render(foo=lambda:None), '')
+ # security error comes from __class__ already.
self.assert_raises(SecurityError, env.from_string(
"{{ foo.__class__.__subclasses__() }}").render, foo=42)
@@ -108,7 +109,6 @@
assert Markup("<em>Foo & Bar</em>").striptags() == "Foo & Bar"
assert Markup("<test>").unescape() == "<test>"
-
def test_template_data(self):
env = Environment(autoescape=True)
t = env.from_string('{% macro say_hello(name) %}'
@@ -121,11 +121,10 @@
assert t.module.say_hello('<blink>foo</blink>') == escaped_out
assert escape(t.module.say_hello('<blink>foo</blink>')) == escaped_out
-
def test_attr_filter(self):
env = SandboxedEnvironment()
- tmpl = env.from_string('{{ 42|attr("__class__")|attr("__subclasses__")() }}')
- self.assert_raises(SecurityError, tmpl.render)
+ tmpl = env.from_string('{{ cls|attr("__subclasses__")() }}')
+ self.assert_raises(SecurityError, tmpl.render, cls=int)
def suite():