From: Armin Ronacher Date: Fri, 19 Nov 2010 12:51:38 +0000 (+0100) Subject: Undefineds now support attribute errors for special attributes. This fixes #6 X-Git-Tag: 2.6~47 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=6a3e95d008ac1e3cc893a949ac94ec4ba9c63d7d;p=jinja2.git Undefineds now support attribute errors for special attributes. This fixes #6 --- diff --git a/CHANGES b/CHANGES index 182f0b0..17a805b 100644 --- a/CHANGES +++ b/CHANGES @@ -5,6 +5,10 @@ Version 2.6 ----------- (codename to be selected, release date to be announced) +- internal attributes now raise an internal attribute error now instead + of returning an undefined. This fixes problems when passing undefined + objects to Python semantics expecting APIs. + Version 2.5.5 ------------- (re-release of 2.5.4 with built documentation removed for filesize. 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 @@ class Undefined(object): 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 @@ class UndefinedTestCase(JinjaTestCase): 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 @@ class SandboxTestCase(JinjaTestCase): 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 @@ class SandboxTestCase(JinjaTestCase): assert Markup("Foo & Bar").striptags() == "Foo & Bar" assert Markup("<test>").unescape() == "" - def test_template_data(self): env = Environment(autoescape=True) t = env.from_string('{% macro say_hello(name) %}' @@ -121,11 +121,10 @@ class SandboxTestCase(JinjaTestCase): assert t.module.say_hello('foo') == escaped_out assert escape(t.module.say_hello('foo')) == 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():