From b2ed0d78f2dff9986ef15b9098c1b6d9ce720a99 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Thu, 17 Feb 2022 09:45:34 +0100 Subject: [PATCH] Refs #28358 -- Fixed infinite recursion in LazyObject.__getattribute__(). Regression in 97d7990abde3fe4b525ae83958fd0b52d6a1d13f. Co-authored-by: Mariusz Felisiak Co-authored-by: Theo Alexiou --- django/utils/functional.py | 3 +++ tests/utils_tests/test_lazyobject.py | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/django/utils/functional.py b/django/utils/functional.py index 8dd8a8e006..5827389231 100644 --- a/django/utils/functional.py +++ b/django/utils/functional.py @@ -288,6 +288,9 @@ class LazyObject: self._wrapped = empty def __getattribute__(self, name): + if name == "_wrapped": + # Avoid recursion when getting wrapped object. + return super().__getattribute__(name) value = super().__getattribute__(name) # If attribute is a proxy method, raise an AttributeError to call # __getattr__() and use the wrapped object method. diff --git a/tests/utils_tests/test_lazyobject.py b/tests/utils_tests/test_lazyobject.py index 161c9dbcec..134ae77750 100644 --- a/tests/utils_tests/test_lazyobject.py +++ b/tests/utils_tests/test_lazyobject.py @@ -58,6 +58,14 @@ class LazyObjectTestCase(TestCase): obj = self.lazy_wrap(Foo()) self.assertEqual(obj.foo, "bar") + def test_getattr_falsey(self): + class Thing: + def __getattr__(self, key): + return [] + + obj = self.lazy_wrap(Thing()) + self.assertEqual(obj.main, []) + def test_setattr(self): obj = self.lazy_wrap(Foo()) obj.foo = "BAR"