Fixed #28358 -- Prevented LazyObject from mimicking nonexistent attributes.
Thanks Sergey Fedoseev for the initial patch.
This commit is contained in:
parent
1d071ec1aa
commit
97d7990abd
|
@ -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,
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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")
|
||||
|
|
Loading…
Reference in New Issue