items have a higher priority than attributes now.  That's compatible with Jinja1 and Django

--HG--
branch : trunk
diff --git a/jinja2/environment.py b/jinja2/environment.py
index dc8bc25..acb5c02 100644
--- a/jinja2/environment.py
+++ b/jinja2/environment.py
@@ -288,19 +288,19 @@
 
     def subscribe(self, obj, argument):
         """Get an item or attribute of an object."""
-        if isinstance(argument, basestring):
-            try:
-                attr = str(argument)
-            except:
-                pass
-            else:
-                try:
-                    return getattr(obj, attr)
-                except AttributeError:
-                    pass
         try:
             return obj[argument]
         except (TypeError, LookupError):
+            if isinstance(argument, basestring):
+                try:
+                    attr = str(argument)
+                except:
+                    pass
+                else:
+                    try:
+                        return getattr(obj, attr)
+                    except AttributeError:
+                        pass
             return self.undefined(obj=obj, name=argument)
 
     def parse(self, source, name=None, filename=None):
diff --git a/jinja2/sandbox.py b/jinja2/sandbox.py
index b0de8e7..ce3369b 100644
--- a/jinja2/sandbox.py
+++ b/jinja2/sandbox.py
@@ -164,30 +164,27 @@
 
     def subscribe(self, obj, argument):
         """Subscribe an object from sandboxed code."""
-        is_unsafe = False
-        if isinstance(argument, basestring):
-            try:
-                attr = str(argument)
-            except:
-                pass
-            else:
-                try:
-                    value = getattr(obj, attr)
-                except AttributeError:
-                    pass
-                else:
-                    if self.is_safe_attribute(obj, argument, value):
-                        return value
-                    is_unsafe = True
         try:
             return obj[argument]
         except (TypeError, LookupError):
-            if is_unsafe:
-                return self.undefined('access to attribute %r of %r object is'
-                                      ' unsafe.' % (
-                    argument,
-                    obj.__class__.__name__
-                ), name=argument, exc=SecurityError)
+            if isinstance(argument, basestring):
+                try:
+                    attr = str(argument)
+                except:
+                    pass
+                else:
+                    try:
+                        value = getattr(obj, attr)
+                    except AttributeError:
+                        pass
+                    else:
+                        if self.is_safe_attribute(obj, argument, value):
+                            return value
+                        return self.undefined('access to attribute %r of %r '
+                                              'object is unsafe.' % (
+                            argument,
+                            obj.__class__.__name__
+                        ), name=argument, exc=SecurityError)
         return self.undefined(obj=obj, name=argument)
 
     def call(__self, __context, __obj, *args, **kwargs):
diff --git a/tests/test_various.py b/tests/test_various.py
index 147f459..7a3882e 100644
--- a/tests/test_various.py
+++ b/tests/test_various.py
@@ -58,3 +58,13 @@
             escape(u"<foo>")
         counts.add(len(gc.get_objects()))
     assert len(counts) == 1, 'ouch, c extension seems to leak objects'
+
+
+def test_item_before_attribute():
+    from jinja2 import Environment
+    from jinja2.sandbox import SandboxedEnvironment
+
+    for env in Environment(), SandboxedEnvironment():
+        tmpl = env.from_string('{{ foo.items() }}')
+        assert tmpl.render(foo={'items': lambda: 42}) == '42'
+        assert tmpl.render(foo={}) == '[]'