summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/conf/__init__.py5
-rw-r--r--django/utils/functional.py9
-rw-r--r--tests/utils_tests/test_lazyobject.py22
3 files changed, 34 insertions, 2 deletions
diff --git a/django/conf/__init__.py b/django/conf/__init__.py
index e1fb7f973f..55bf15a355 100644
--- a/django/conf/__init__.py
+++ b/django/conf/__init__.py
@@ -157,8 +157,9 @@ class LazySettings(LazyObject):
def USE_L10N(self):
stack = traceback.extract_stack()
# Show a warning if the setting is used outside of Django.
- # Stack index: -1 this line, -2 the caller.
- filename, _, _, _ = stack[-2]
+ # Stack index: -1 this line, -2 the LazyObject __getattribute__(),
+ # -3 the caller.
+ filename, _, _, _ = stack[-3]
if not filename.startswith(os.path.dirname(django.__file__)):
warnings.warn(
USE_L10N_DEPRECATED_MSG,
diff --git a/django/utils/functional.py b/django/utils/functional.py
index 2696dd49c5..8dd8a8e006 100644
--- a/django/utils/functional.py
+++ b/django/utils/functional.py
@@ -266,6 +266,7 @@ def new_method_proxy(func):
self._setup()
return func(self._wrapped, *args)
+ inner._mask_wrapped = False
return inner
@@ -286,6 +287,14 @@ class LazyObject:
# override __copy__() and __deepcopy__() as well.
self._wrapped = empty
+ def __getattribute__(self, name):
+ value = super().__getattribute__(name)
+ # If attribute is a proxy method, raise an AttributeError to call
+ # __getattr__() and use the wrapped object method.
+ if not getattr(value, "_mask_wrapped", True):
+ raise AttributeError
+ return value
+
__getattr__ = new_method_proxy(getattr)
def __setattr__(self, name, value):
diff --git a/tests/utils_tests/test_lazyobject.py b/tests/utils_tests/test_lazyobject.py
index 0ff15469d4..161c9dbcec 100644
--- a/tests/utils_tests/test_lazyobject.py
+++ b/tests/utils_tests/test_lazyobject.py
@@ -32,6 +32,28 @@ class LazyObjectTestCase(TestCase):
return AdHocLazyObject()
+ def test_getattribute(self):
+ """
+ Proxy methods don't exist on wrapped objects unless they're set.
+ """
+ attrs = [
+ "__getitem__",
+ "__setitem__",
+ "__delitem__",
+ "__iter__",
+ "__len__",
+ "__contains__",
+ ]
+ foo = Foo()
+ obj = self.lazy_wrap(foo)
+ for attr in attrs:
+ with self.subTest(attr):
+ self.assertFalse(hasattr(obj, attr))
+ setattr(foo, attr, attr)
+ obj_with_attr = self.lazy_wrap(foo)
+ self.assertTrue(hasattr(obj_with_attr, attr))
+ self.assertEqual(getattr(obj_with_attr, attr), attr)
+
def test_getattr(self):
obj = self.lazy_wrap(Foo())
self.assertEqual(obj.foo, "bar")