Permalink
Browse files

Fixed #19456 -- Made SimpleLazyObject traceable

Defined the _wrapped attribute to avoid an infinite recursion in
new_method_proxy when accessing SimpleLazyObject attributes triggering
new_method_proxy before _wrapped is initialized to empty (typically
while tracing the execution of SimpleLazyObject.__init__).
  • Loading branch information...
1 parent be9f291 commit 772f4b0f357b34abd1041d99b990f4f5b88bed6e @blaze33 committed Dec 10, 2012
Showing with 11 additions and 1 deletion.
  1. +2 −0 django/utils/functional.py
  2. +9 −1 tests/regressiontests/utils/functional.py
@@ -210,6 +210,8 @@ class LazyObject(object):
By subclassing, you have the opportunity to intercept and alter the
instantiation. If you don't need to do that, use SimpleLazyObject.
"""
+ _wrapped = None
+
def __init__(self):
self._wrapped = empty
@@ -1,5 +1,6 @@
+import sys
from django.utils import unittest
-from django.utils.functional import lazy, lazy_property
+from django.utils.functional import lazy, lazy_property, SimpleLazyObject
class FunctionalTestCase(unittest.TestCase):
@@ -37,3 +38,10 @@ def _get_do(self):
self.assertRaises(NotImplementedError, lambda: A().do)
self.assertEqual(B().do, 'DO IT')
+
+ def test_simplelazyobject_traceable(self):
+ def tracer(frame, event, arg):
+ frame.f_locals['self'].__class__
+ sys.settrace(tracer)
+ SimpleLazyObject(lambda x: x)
@spookylukey

spookylukey Jan 11, 2013

This use of SimpleLazyObject will always cause an error, because "lambda x:x" will throw an Exception when it is called without arguments. Is that part of the test? If not, something like "lambda: 1" should be used for clarity.

@blaze33

blaze33 Jan 11, 2013

Owner

The idea is: we just need a dummy function to be able to call the SimpleLazyObject constructor. What the function does is irrelevant to the test so I choose the identity function. Afaik it's not even called but just referenced to setup a method proxy to itself.
If called, then lambda: 1 would also fail if called with any argument so lambda *x: x would solve this.
Just re-ran this test: works with any of these lambdas.

@spookylukey

spookylukey Jan 11, 2013

What I meant was that if the function is going to be called, it should take zero arguments, because that is how it is called in SimpleLazyObject. If it's not going to be called, it doesn't even need to be a function. "None" is as good as "lambda x:x" since both will produce an exception.

@blaze33

blaze33 Jan 11, 2013

Owner

Ok, right, None should work as well. Seemed weird to me at first as the function we pass to the constructor will at least be passed there https://github.com/blaze33/django/blob/772f4b0f357b34abd1041d99b990f4f5b88bed6e/django/utils/functional.py#L202
(as func) but it should not be called if I understand it right.

+ sys.settrace(None)

0 comments on commit 772f4b0

Please sign in to comment.