﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
21840	LazyObject wrapped instances can no longer be coerced to Bool due to #20924	Gabe Jackson	Baptiste Mispelon	"https://code.djangoproject.com/ticket/20924 adds proxy methods for `__contains__` and `__len__` to support lists and dicts wrapped by LazyObject. The problem is that evaluating truth for such LazyObjects will break if `__len__` is not defined on the wrapper instance.

This can be demonstrated as follows:
{{{
>>> from django.core.files.storage import default_storage
>>> if default_storage: print('yes')
... 
Traceback (most recent call last):
  File ""<console>"", line 1, in <module>
  File ""/home/tisba/Programming/testbed/boogz/django/utils/functional.py"", line 224, in inner
    return func(self._wrapped, *args)
TypeError: object of type 'FileSystemStorage' has no len()
}}}

this is because converting an object to a Bool calls `object.__nonzero__` which in turn calls `__len__` as stated here:
http://docs.python.org/2/reference/datamodel.html#object.__nonzero__

This will break a lot of apps using LazyObject. This problem exists in the current master of imagekit as well:
{{{
class JustInTime(object):
    """"""
    A strategy that ensures the file exists right before it's needed.

    """"""
    def on_existence_required(self, file):
        file.generate()

    def on_content_required(self, file):
        file.generate()

class StrategyWrapper(LazyObject):
    def __init__(self, strategy):
        if isinstance(strategy, six.string_types):
            strategy = get_singleton(strategy, 'cache file strategy')
        elif isinstance(strategy, dict):
            strategy = DictStrategy(strategy)
        elif callable(strategy):
            strategy = strategy()
        self._wrapped = strategy

    def __getstate__(self):
        return {'_wrapped': self._wrapped}

    def __setstate__(self, state):
        self._wrapped = state['_wrapped']

    def __unicode__(self):
        return force_text(self._wrapped)

    def __str__(self):
        return str(self._wrapped)
}}}

calling the LazyObject in a statement like `if lazy_object` will yield:
{{{
In [2]: p.avatar_thumbnail
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-860e30762713> in <module>()
----> 1 p.avatar_thumbnail

/Users/gabejackson/venv/hvad-test/lib/python2.7/site-packages/imagekit/models/fields/utils.pyc in __get__(self, instance, owner)
     15             spec = self.field.get_spec(source=source)
     16             import ipdb; ipdb.set_trace()
---> 17             file = ImageCacheFile(spec)
     18             instance.__dict__[self.attname] = file
     19             return file

/Users/gabejackson/venv/hvad-test/lib/python2.7/site-packages/imagekit/cachefiles/__init__.pyc in __init__(self, generator, name, storage, cachefile_backend, cachefile_strategy)
     55         self.cachefile_strategy = (
     56             cachefile_strategy
---> 57             or getattr(generator, 'cachefile_strategy', None)
     58             or get_singleton(settings.IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY, 'cache file strategy')
     59         )

/Users/gabejackson/venv/hvad-test/lib/python2.7/site-packages/django/utils/functional.pyc in inner(self, *args)
    222         if self._wrapped is empty:
    223             self._setup()
--> 224         return func(self._wrapped, *args)
    225     return inner
    226

TypeError: object of type 'JustInTime' has no len()
}}}

You can see that the `or` statement on line 57 is forcing the coercion of the JustInTime object to a Boolean. Doing this calls `__len__` which is now defined on LazyObject and will cause the TypeError stated."	Bug	closed	Utilities	dev	Release blocker	fixed	LazyObject utils		Ready for checkin	1	0	0	0	0	0
