summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Lord <davidism@gmail.com>2020-03-27 10:05:12 -0700
committerGitHub <noreply@github.com>2020-03-27 10:05:12 -0700
commit41ed50c805ac04252cdc094db216977d70e7c0da (patch)
treee907b26980341a927e2ba1233ea68d0a00eb2205
parente1b5e50ca33f4b10d033c96de007d18b510ecab9 (diff)
parentf15452f130b82090ca1e1f650b5b7662496633db (diff)
downloadjinja2-41ed50c805ac04252cdc094db216977d70e7c0da.tar.gz
Merge pull request #1179 from pallets/undefined-recursion
AttributeError in undefined message doesn't cause RuntimeError
-rw-r--r--CHANGES.rst3
-rw-r--r--src/jinja2/utils.py10
-rw-r--r--tests/test_api.py15
3 files changed, 25 insertions, 3 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index aee6ad3..0902830 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -12,6 +12,9 @@ Unreleased
by wrapping the input in :func:`soft_unicode`. :pr:`1160`
- Fix a hang when displaying tracebacks on Python 32-bit.
:issue:`1162`
+- Showing an undefined error for an object that raises
+ ``AttributeError`` on access doesn't cause a recursion error.
+ :issue:`1177`
Version 2.11.1
diff --git a/src/jinja2/utils.py b/src/jinja2/utils.py
index e3285e8..94581ca 100644
--- a/src/jinja2/utils.py
+++ b/src/jinja2/utils.py
@@ -165,11 +165,15 @@ def object_type_repr(obj):
return "None"
elif obj is Ellipsis:
return "Ellipsis"
+
+ cls = type(obj)
+
# __builtin__ in 2.x, builtins in 3.x
- if obj.__class__.__module__ in ("__builtin__", "builtins"):
- name = obj.__class__.__name__
+ if cls.__module__ in ("__builtin__", "builtins"):
+ name = cls.__name__
else:
- name = obj.__class__.__module__ + "." + obj.__class__.__name__
+ name = cls.__module__ + "." + cls.__name__
+
return "%s object" % name
diff --git a/tests/test_api.py b/tests/test_api.py
index 058ec56..7a1cae8 100644
--- a/tests/test_api.py
+++ b/tests/test_api.py
@@ -269,6 +269,21 @@ class TestUndefined(object):
with pytest.raises(AttributeError):
Undefined("Foo").__dict__
+ def test_undefined_attribute_error(self):
+ # Django's LazyObject turns the __class__ attribute into a
+ # property that resolves the wrapped function. If that wrapped
+ # function raises an AttributeError, printing the repr of the
+ # object in the undefined message would cause a RecursionError.
+ class Error(object):
+ @property
+ def __class__(self):
+ raise AttributeError()
+
+ u = Undefined(obj=Error(), name="hello")
+
+ with pytest.raises(UndefinedError):
+ getattr(u, "recursion", None)
+
def test_logging_undefined(self):
_messages = []