Question

I created a subclass of the Django File object to take care of remote file. I also wanted to make a lazy version by creating a RemoteFileLazy subclassing the Lazyobject class but it does not work as I expected. I get an error.

import urllib2
from django.core.files.base import File
from django.utils.functional import LazyObject

class RemoteFile(File):

    def __init__(self, url):
        super(RemoteFile, self).__init__(urllib2.urlopen(urllib2.Request(url)))

    def __str__(self):
        return 'Remote content'

    def __nonzero__(self):
        return True

    def open(self, mode=None):
        self.seek(0)

    def close(self):
        pass

    def chunks(self, chunk_size=None):
    # CHUNKS taking care of no known size!
        if not chunk_size:
            chunk_size = self.DEFAULT_CHUNK_SIZE

        if hasattr(self, 'seek'):
            self.seek(0)
        # Assume the pointer is at zero...
        counter = self.size

        while True:
            data = self.read(chunk_size)
            if not data:
                break
            yield data

class RemoteFileLazy(LazyObject):

    def __init__(self, url):
        # # as said in the django code: For some reason, we have to inline LazyObject.__init__ here to avoid
        # recursion
        self._wrapped = None
        self.url = url

    def _setup(self):
        self._wrapped = RemoteFile(self.url)

When I run this code:

rfl = filehelper.RemoteFileLazy(url="http://www.google.fr")

I got this error:

RuntimeError: maximum recursion depth exceeded

Any idea ? I did not call LazyObject.init as it was mentioned in the django code though... I think the "self.url = url" in the init method triggers this error right ? So I cannot use a lazy object with attributes ?

Thanks.

Traceback:

c:\Users\Michael\Dropbox\development\tools\Portable Python 2.7.2.1-django1.3.1\App\lib\site-packages\django\utils\functional.pyc in __getattr__(self, name)
    274     def __getattr__(self, name):
    275         if self._wrapped is None:
--> 276             self._setup()
    277         return getattr(self._wrapped, name)
    278

C:\Users\Michael\Dropbox\development\projects\django-socialdealing\socialdealing\apps\etl\utils\filehelper.py in _setup(self)
     58
     59     def _setup(self):
---> 60         self._wrapped = RemoteFile(self.url)
     61
     62

c:\Users\Michael\Dropbox\development\tools\Portable Python 2.7.2.1-django1.3.1\App\lib\site-packages\django\utils\functional.pyc in __getattr__(self, name)
    274     def __getattr__(self, name):
    275         if self._wrapped is None:
--> 276             self._setup()
    277         return getattr(self._wrapped, name)
    278
Was it helpful?

Solution

You can't assign attributes on a LazyObject wrapper in the normal way, it's intended to be treated as it it is the wrapped object, so tries to pass accesses through to the wrapped object, which hasn't been created yet at the point you assign to url.

To fix it, replace

self.url = url # this tries to retrieve the wrapped object to set its 'url' attribute

with

self.__dict__['url'] = url # this actually stores an attribute on the LazyObject container.

As an aside, when 'borrowing' django internals like this you will want to test really hard every time you upgrade django.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top