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...
blaze33 committed Dec 10, 2012
1 parent be9f291 commit 772f4b0f357b34abd1041d99b990f4f5b88bed6e
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)

This comment has been minimized.

Show comment
Hide comment
@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.

@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.

This comment has been minimized.

Show comment
Hide comment
@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.

@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.

This comment has been minimized.

Show comment
Hide comment
@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.

@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.

This comment has been minimized.

Show comment
Hide comment
@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

return func(self._wrapped, *args)

(as func) but it should not be called if I understand it right.

@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

return func(self._wrapped, *args)

(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.