Skip to content

Commit

Permalink
Merge pull request #508 from joehybird/master
Browse files Browse the repository at this point in the history
Compatibility Django 2.1 and Python 3.7
  • Loading branch information
jrief committed Dec 18, 2018
2 parents d3eb3d7 + ea27bab commit c611c5c
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 29 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
sudo: false
language: python
dist: xenial
python:
- "2.7"
- "3.4"
- "3.5"
- "3.6"
- "3.7"
install: pip install tox-travis
script: tox
11 changes: 6 additions & 5 deletions easy_thumbnails/tests/test_aliases.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,11 +286,12 @@ def test_standard_filefield(self):
profile = models.Profile(avatar='avatars/test.jpg')
# Attach a File object to the FileField descriptor, emulating an
# upload.
profile.logo = self.storage.open(
self.create_image(self.storage, 'avatars/second.jpg'))
list_files = self.fake_save(profile)
# 2 source, 2 thumbs.
self.assertEqual(len(list_files), 4)
with self.storage.open(self.create_image(self.storage, 'avatars/second.jpg')) as logo:
profile.logo = logo
list_files = self.fake_save(profile)

# 2 source, 2 thumbs.
self.assertEqual(len(list_files), 4)


class GlobalGenerationTest(GenerationBase):
Expand Down
17 changes: 15 additions & 2 deletions easy_thumbnails/tests/test_fields.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import pickle

from django import VERSION as DJANGO_VERSION
from django.core.files.base import ContentFile

from easy_thumbnails.tests import utils, models
Expand Down Expand Up @@ -95,16 +96,28 @@ def test_serialization(self):
new_instance = pickle.loads(pickle.dumps(instance))
self.assertEqual('/media/avatars/avatar.jpg.100x100_q85.jpg', new_instance.avatar['small'].url)

def _read_filefield(self, field):
if DJANGO_VERSION < (2, 0):
try:
return field.file.read()
finally:
field.file.close()

with field.open('rb') as fd:
return fd.read()

def test_saving_image_field_with_resize_source(self):
# Ensure that saving ThumbnailerImageField with resize_source enabled
# using instance.field.save() does not fail
instance = models.TestModel(avatar='avatars/avatar.jpg')
instance.picture.save(
'file.jpg', ContentFile(instance.avatar.file.read()), save=False)
'file.jpg', ContentFile(self._read_filefield(instance.avatar)), save=False)

self.assertEqual(instance.picture.width, 10)

def test_saving_image_field_with_resize_source_different_ext(self):
instance = models.TestModel(avatar='avatars/avatar.jpg')
instance.picture.save(
'file.gif', ContentFile(instance.avatar.file.read()), save=False)
'file.gif', ContentFile(self._read_filefield(instance.avatar)), save=False)

self.assertEqual(instance.picture.name, 'pictures/file.jpg')
3 changes: 3 additions & 0 deletions easy_thumbnails/tests/test_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,9 @@ def test_add_dimension_cache(self):
(thumb.width, thumb.height),
(dimensions.width, dimensions.height))

# close the filefield (cause unclosed file ResourceWarning)
thumb.close()

def test_thumbnail_created_signal(self):

def signal_handler(sender, **kwargs):
Expand Down
4 changes: 2 additions & 2 deletions easy_thumbnails/tests/test_templatetags.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ def verify_thumbnail(self, expected_size, options, source_filename=None,
'Thumbnail file %r not found' % expected_filename)

# Verify the thumbnail has the expected dimensions
image = Image.open(self.storage.open(expected_filename))
self.assertEqual(image.size, expected_size)
with Image.open(self.storage.open(expected_filename)) as image:
self.assertEqual(image.size, expected_size)

return expected_filename

Expand Down
63 changes: 49 additions & 14 deletions easy_thumbnails/tests/test_widgets.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
from easy_thumbnails import widgets
from unittest.case import skipIf

from django import VERSION as DJANGO_VERSION
from django.core.files.uploadedfile import SimpleUploadedFile
from django.forms.widgets import ClearableFileInput

from easy_thumbnails import widgets
from easy_thumbnails.tests import utils as test


Expand Down Expand Up @@ -40,24 +44,28 @@ def test_render(self):
"""
source_filename = self.create_image(self.storage, 'test.jpg')
widget = widgets.ImageClearableFileInput()
source_file = self.storage.open(source_filename)
source_file.storage = self.storage
source_file.thumbnail_storage = self.storage
html = widget.render('photo', source_file)

with self.storage.open(source_filename) as source_file:
source_file.storage = self.storage
source_file.thumbnail_storage = self.storage
html = widget.render('photo', source_file)

self.assertIn(source_filename, html)
self.assertIn('.80x80_', html)

def test_render_custom(self):
def test_render_custom_thumb_options(self):
"""
The thumbnail is generated using the options provided to the widget.
"""
source_filename = self.create_image(self.storage, 'test.jpg')
options = {'size': (100, 500), 'quality': 90, 'crop': True}
widget = widgets.ImageClearableFileInput(thumbnail_options=options)
source_file = self.storage.open(source_filename)
source_file.storage = self.storage
source_file.thumbnail_storage = self.storage
html = widget.render('photo', source_file)

with self.storage.open(source_filename) as source_file:
source_file.storage = self.storage
source_file.thumbnail_storage = self.storage
html = widget.render('photo', source_file)

self.assertIn(source_filename, html)
self.assertIn('.100x500_q90_crop.jpg', html)

Expand All @@ -72,14 +80,40 @@ def test_custom_template(self):
u'%(template)s<br />'
u'<a href="%(source_url)s">%(thumb)s</a> FOO'
)
source_file = self.storage.open(source_filename)
source_file.storage = self.storage
source_file.thumbnail_storage = self.storage
html = widget.render('photo', source_file)

with self.storage.open(source_filename) as source_file:
source_file.storage = self.storage
source_file.thumbnail_storage = self.storage
html = widget.render('photo', source_file)

self.assertIn(source_filename, html)
self.assertIn('.80x80_', html)
self.assertIn('FOO', html)

@skipIf(DJANGO_VERSION < (1, 11), 'Custom widget renderer works for Django >=1.11')
def test_custom_renderer(self):
"""
The form renderer used to render the thumbnail and the standard
``ClearableFileInput`` output can be customized since Django 1.11
"""
from django.forms.renderers import DjangoTemplates

source_filename = self.create_image(self.storage, 'test.jpg')
widget = widgets.ImageClearableFileInput()
class CustomRenderer(DjangoTemplates):
def render(self, template_name, context, request=None):
output = super(DjangoTemplates, self).render(template_name, context, request)
return output + ' FOOBAR'

with self.storage.open(source_filename) as source_file:
source_file.storage = self.storage
source_file.thumbnail_storage = self.storage
html = widget.render('photo', source_file, renderer=CustomRenderer())

self.assertIn(source_filename, html)
self.assertIn('.80x80_', html)
self.assertIn('FOOBAR', html)

def test_render_without_value(self):
"""
If value not passed, use super widget.
Expand Down Expand Up @@ -109,3 +143,4 @@ def test_render_uploaded(self):
base_html = base_widget.render('photo', upload_file)
self.assertEqual(base_html, html)
self.assertNotIn(file_name, html) # Widget is empty.

14 changes: 11 additions & 3 deletions easy_thumbnails/widgets.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from django import VERSION as DJANGO_VERSION
from django.forms.widgets import ClearableFileInput
from django.utils.safestring import mark_safe

from easy_thumbnails.files import get_thumbnailer
from easy_thumbnails.conf import settings

Expand Down Expand Up @@ -54,9 +56,15 @@ def get_thumbnail(self, value):
thumbnailer.thumbnail_storage = value.thumbnail_storage
return thumbnailer.get_thumbnail(self.thumbnail_options)

def render(self, name, value, attrs=None):
output = super(ImageClearableFileInput, self).render(
name, value, attrs)
def render(self, name, value, attrs=None, renderer=None):
# Backward compatibility for Django < 1.11
if DJANGO_VERSION < (1, 11):
output = super(ImageClearableFileInput, self).render(
name, value, attrs)
else:
output = super(ImageClearableFileInput, self).render(
name, value, attrs, renderer)

if not value or not hasattr(value, 'storage'):
return output
thumb = self.get_thumbnail(value)
Expand Down
9 changes: 6 additions & 3 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ distribute = False
envlist =
py{27,34,35}-django{18,110}
py{27,34,35,36}-django111
py{34,35,36}-django20
py{34,35,36,37}-django{20}
py{35,36,37}-django{21}
docs
skip_missing_interpreters = True

Expand All @@ -13,6 +14,7 @@ python =
3.4: py34
3.5: py35
3.6: py36, docs
3.7: py37

[testenv]
setenv = DJANGO_SETTINGS_MODULE=easy_thumbnails.tests.settings
Expand All @@ -22,10 +24,11 @@ deps =
django19: Django>=1.9,<1.10
django110: Django>=1.10,<1.11
django111: Django>=1.11,<2.0
django20: Django>=2.0a1,<2.1
django20: Django>=2.0,<2.1
django21: Django>=2.1,<2.2
testfixtures
commands =
django-admin.py test {posargs}
python -Wd {envbindir}/django-admin.py test {posargs}

[testenv:pre]
basepython = python3.6
Expand Down

0 comments on commit c611c5c

Please sign in to comment.