SmileyChris / easy-thumbnails

Easy thumbnails for Django
http://easy-thumbnails.readthedocs.org/
BSD 3-Clause "New" or "Revised" License
1.39k stars 319 forks source link

Object has no attribute 'storage', in size property on Django 3.1 #557

Closed tolomea closed 3 years ago

tolomea commented 4 years ago

I'm trying to upgrade from Django 3.0.10 to 3.1.2 and my test suite is throwing up this error:

self = <ThumbnailerImageFieldFile: REDACTED>

    @property
    def size(self):
        self._require_file()
        if not self._committed:
            return self.file.size
>       return self.storage.size(self.name)
E       AttributeError: 'ThumbnailerImageFieldFile' object has no attribute 'storage'

Is this my fault somehow? or is this a compatibility problem between easy-thumbnails and Django 3.1?

tolomea commented 4 years ago

Digging into this further.

It seems the root problem is we're losing the storage attribute somewhere along the way. It's set in django.db.models.fields.files.FieldFile.__init__ but somewhere along the way it disappears. https://github.com/django/django/blob/970729693a35f39611c6488a8d1839185429df51/django/db/models/fields/files.py#L19

We're using django-testdata package, this speeds up tests by storing values during setUpTestData and copying them per test. And the copy API's use __get_state__ and __set_state__.

Looking at FieldFile again it preserves the value of storage in __set_state__. https://github.com/django/django/blob/970729693a35f39611c6488a8d1839185429df51/django/db/models/fields/files.py#L138

However ThumbnailerFieldFile is also overriding __set_state__ and is not calling super. I don't know if not calling super is intentional, but changing the dict update here: https://github.com/SmileyChris/easy-thumbnails/blob/208057c560d55e77b943a983e171340d8e965dc0/easy_thumbnails/files.py#L738 to super().__setstate__(state) resolves the issue and it doesn't break the tests (at least on Django 3.1, Python 3.8)