diff --git a/django/utils/functional.py b/django/utils/functional.py index 69a32b101a..3e58674501 100644 --- a/django/utils/functional.py +++ b/django/utils/functional.py @@ -305,6 +305,15 @@ class SimpleLazyObject(LazyObject): def __reduce__(self): return (self.__newobj__, (self.__class__,), self.__getstate__()) + # Return a meaningful representation of the lazy object for debugging + # without evaluating the wrapped object. + def __repr__(self): + if self._wrapped is empty: + repr_attr = self._setupfunc + else: + repr_attr = self._wrapped + return '' % repr_attr + # Need to pretend to be the wrapped class, for the sake of objects that care # about this (especially in equality tests) __class__ = property(new_method_proxy(operator.attrgetter("__class__"))) diff --git a/docs/releases/1.6.txt b/docs/releases/1.6.txt index 609557073e..599da6847c 100644 --- a/docs/releases/1.6.txt +++ b/docs/releases/1.6.txt @@ -131,6 +131,9 @@ Minor features :setting:`TEMPLATE_STRING_IF_INVALID` for variables not present in the context, just like other template constructs. +* SimpleLazyObjects will now present more helpful representations in shell + debugging situations. + Backwards incompatible changes in 1.6 ===================================== diff --git a/tests/utils_tests/simplelazyobject.py b/tests/utils_tests/simplelazyobject.py index 3f81e8f608..dd52857c03 100644 --- a/tests/utils_tests/simplelazyobject.py +++ b/tests/utils_tests/simplelazyobject.py @@ -59,10 +59,18 @@ class TestUtilsSimpleLazyObject(TestCase): hash(SimpleLazyObject(complex_object))) def test_repr(self): - # For debugging, it will really confuse things if there is no clue that - # SimpleLazyObject is actually a proxy object. So we don't - # proxy __repr__ - self.assertTrue("SimpleLazyObject" in repr(SimpleLazyObject(complex_object))) + # First, for an unevaluated SimpleLazyObject + x = SimpleLazyObject(complex_object) + # __repr__ contains __repr__ of setup function and does not evaluate + # the SimpleLazyObject + self.assertEqual("" % complex_object, repr(x)) + self.assertEqual(empty, x._wrapped) + + # Second, for an evaluated SimpleLazyObject + name = x.name # evaluate + self.assertTrue(isinstance(x._wrapped, _ComplexObject)) + # __repr__ contains __repr__ of wrapped object + self.assertEqual("" % x._wrapped, repr(x)) def test_bytes(self): self.assertEqual(b"I am _ComplexObject('joe')",