]> git.ipfire.org Git - thirdparty/jinja.git/commitdiff
runtime: avoid assumption that all objects provide __call__ 502/head
authorDaniel P. Berrange <berrange@redhat.com>
Tue, 13 Oct 2015 15:52:07 +0000 (16:52 +0100)
committerDaniel P. Berrange <berrange@redhat.com>
Tue, 13 Oct 2015 15:52:07 +0000 (16:52 +0100)
Objects which are backed by native extensions do not provide
a __call__ attribute, but are none the less callable if the
native extension provides a 'tp_call' implementation.

The jinja2.runtime.Context.call method unconditionally
access the '__call__' attribute causing an exception to be
raised if the object was a native extension method.

A demo of the problem can be seen using PyGObject:

  $ cat demo.py
  #!/usr/bin/python

  from gi.repository import Gio
  from jinja2 import Environment

  f = Gio.File.new_for_path("/some/file.txt")
  print f.get_uri()

  t = Environment().from_string("""{{f.get_uri()}}""")
  print t.render(f=f)

Which when run results in

 $ ./demo.py
 file:///some/file.txt
 Traceback (most recent call last):
   File "./demo.py", line 10, in <module>
     print t.render(f=f)
   File "/usr/lib/python2.7/site-packages/jinja2/environment.py", line 969, in render
     return self.environment.handle_exception(exc_info, True)
   File "/usr/lib/python2.7/site-packages/jinja2/environment.py", line 742, in handle_exception
     reraise(exc_type, exc_value, tb)
   File "<template>", line 1, in top-level template code
     AttributeError: 'gi.FunctionInfo' object has no attribute '__call__'

After this patch it produces

 $ ./demo.py
 file:///some/file.txt
 file:///some/file.txt

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
jinja2/runtime.py

index 685a12da068c4808f2dfcec64d68e581f47e26fe..2622983bd8d78637de4934b6ab3ce5e5573e4e05 100644 (file)
@@ -177,13 +177,14 @@ class Context(object):
             __traceback_hide__ = True  # noqa
 
         # Allow callable classes to take a context
-        fn = __obj.__call__
-        for fn_type in ('contextfunction',
-                        'evalcontextfunction',
-                        'environmentfunction'):
-            if hasattr(fn, fn_type):
-                __obj = fn
-                break
+        if hasattr(__obj, '__call__'):
+            fn = __obj.__call__
+            for fn_type in ('contextfunction',
+                            'evalcontextfunction',
+                            'environmentfunction'):
+                if hasattr(fn, fn_type):
+                    __obj = fn
+                    break
 
         if isinstance(__obj, _context_function_types):
             if getattr(__obj, 'contextfunction', 0):