sorl-thumbnail-11.12/ 0000755 0001750 0001750 00000000000 11677075433 013501 5 ustar mikko mikko sorl-thumbnail-11.12/README.rst 0000644 0001750 0001750 00000001144 11666137404 015163 0 ustar mikko mikko sorl-thumbnail
==============
Thumbnails for Django. Totally rewritten.
Features at a glance
--------------------
- Storage support
- Pluggable Engine support (ImageMagick, PIL, pgmagick included)
- Pluggable Key Value Store support (cached db, redis)
- Pluggable Backend support
- Admin integration with possibility to delete
- Dummy generation (placeholders)
- Flexible, simple syntax, generates no html
- ImageField for model that deletes thumbnails
- CSS style cropping options
- Margin calculation for vertical positioning
Read more in `the documentation (latest version) `_
sorl-thumbnail-11.12/setup.py 0000644 0001750 0001750 00000002054 11666137404 015207 0 ustar mikko mikko import sorl
from setuptools import setup, find_packages
from setuptools.command.test import test
class TestCommand(test):
def run(self):
from tests.runtests import runtests
runtests()
setup(
name='sorl-thumbnail',
version=sorl.__version__,
description='Thumbnails for Django',
long_description=open('README.rst').read(),
author='Mikko Hellsing',
author_email='mikko@aino.se',
license='BSD',
url='https://github.com/sorl/sorl-thumbnail',
packages=find_packages(exclude=['tests', 'tests.*']),
platforms='any',
zip_safe=False,
classifiers=[
'Development Status :: 5 - Production/Stable',
'Environment :: Web Environment',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
'Topic :: Multimedia :: Graphics',
'Framework :: Django',
],
cmdclass={"test": TestCommand},
)
sorl-thumbnail-11.12/tests/ 0000755 0001750 0001750 00000000000 11677075433 014643 5 ustar mikko mikko sorl-thumbnail-11.12/tests/__init__.py 0000644 0001750 0001750 00000000000 11677073446 016744 0 ustar mikko mikko sorl-thumbnail-11.12/tests/settings/ 0000755 0001750 0001750 00000000000 11677075433 016503 5 ustar mikko mikko sorl-thumbnail-11.12/tests/settings/__init__.py 0000644 0001750 0001750 00000000000 11677073446 020604 0 ustar mikko mikko sorl-thumbnail-11.12/tests/settings/imagemagick.py 0000644 0001750 0001750 00000000171 11677073446 021314 0 ustar mikko mikko from .default import *
THUMBNAIL_ENGINE = 'sorl.thumbnail.engines.convert_engine.Engine'
THUMBNAIL_CONVERT = 'convert'
sorl-thumbnail-11.12/tests/settings/pgmagick.py 0000644 0001750 0001750 00000000134 11677073446 020637 0 ustar mikko mikko from .default import *
THUMBNAIL_ENGINE = 'sorl.thumbnail.engines.pgmagick_engine.Engine'
sorl-thumbnail-11.12/tests/settings/pil.py 0000644 0001750 0001750 00000000127 11677073446 017643 0 ustar mikko mikko from .default import *
THUMBNAIL_ENGINE = 'sorl.thumbnail.engines.pil_engine.Engine'
sorl-thumbnail-11.12/tests/settings/graphicsmagick.py 0000644 0001750 0001750 00000000237 11677073446 022035 0 ustar mikko mikko from .default import *
THUMBNAIL_ENGINE = 'sorl.thumbnail.engines.convert_engine.Engine'
THUMBNAIL_CONVERT = 'gm convert'
THUMBNAIL_IDENTIFY = 'gm identify'
sorl-thumbnail-11.12/tests/settings/default.py 0000644 0001750 0001750 00000001607 11677073446 020507 0 ustar mikko mikko from os.path import join as pjoin, abspath, dirname, pardir
PROJ_ROOT = abspath(pjoin(dirname(__file__), pardir))
DATA_ROOT = pjoin(PROJ_ROOT, 'data')
THUMBNAIL_PREFIX = 'test/cache/'
THUMBNAIL_DEBUG = True
THUMBNAIL_LOG_HANDLER = {
'class': 'sorl.thumbnail.log.ThumbnailLogHandler',
'level': 'ERROR',
}
THUMBNAIL_KVSTORE = 'thumbnail_tests.kvstore.TestKVStore'
THUMBNAIL_STORAGE = 'thumbnail_tests.storage.TestStorage'
DEFAULT_FILE_STORAGE = 'thumbnail_tests.storage.TestStorage'
ADMINS = (
('Sorl', 'thumbnail@sorl.net'),
)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'thumbnail_tests',
}
}
MEDIA_ROOT = pjoin(PROJ_ROOT, 'media')
MEDIA_URL = '/media/'
ROOT_URLCONF = 'thumbnail_tests.urls'
INSTALLED_APPS = (
'thumbnail',
'thumbnail_tests',
)
TEMPLATE_CONTEXT_PROCESSORS = (
"django.core.context_processors.request",
)
sorl-thumbnail-11.12/tests/settings/redis.py 0000644 0001750 0001750 00000000135 11677073446 020164 0 ustar mikko mikko from .default import *
THUMBNAIL_KVSTORE = 'sorl.thumbnail.kvstores.redis_kvstore.KVStore'
sorl-thumbnail-11.12/tests/runtests.py 0000755 0001750 0001750 00000003263 11677073446 017115 0 ustar mikko mikko #!/usr/bin/env python
import os
import sys
from os.path import abspath, dirname, join as pjoin
from django.conf import settings
def runtests(verbosity=1, interactive=True, failfast=True, settings_module='settings.default'):
here = abspath(dirname(__file__))
root = pjoin(here, os.pardir)
sys.path[0:0] = [ here, root, pjoin(root, 'sorl') ]
os.environ['DJANGO_SETTINGS_MODULE'] = settings_module
from django.test.utils import get_runner
print "Running tests for '%s'" % settings_module
TestRunner = get_runner(settings)
test_runner = TestRunner(
verbosity=verbosity, interactive=interactive, failfast=failfast
)
return test_runner.run_tests(settings.INSTALLED_APPS)
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(
description='Runs the test suite for sorl-thumbnail.'
)
parser.add_argument(
'--settings',
dest='settings_module',
action='store',
default='settings.default',
help='Specify settings module.',
)
parser.add_argument(
'--noinput',
dest='interactive',
action='store_false',
default=True,
help='Do not prompt the user for input of any kind.',
)
parser.add_argument(
'--failfast',
dest='failfast',
action='store_true',
default=False,
help='Stop running the test suite after first failed test.',
)
args = parser.parse_args()
failures = runtests(
verbosity=1,
interactive=args.interactive,
failfast=args.failfast,
settings_module=args.settings_module,
)
if failures:
sys.exit(bool(failures))
sorl-thumbnail-11.12/tests/thumbnail_tests/ 0000755 0001750 0001750 00000000000 11677075433 020050 5 ustar mikko mikko sorl-thumbnail-11.12/tests/thumbnail_tests/__init__.py 0000644 0001750 0001750 00000000000 11677073446 022151 0 ustar mikko mikko sorl-thumbnail-11.12/tests/thumbnail_tests/storage.py 0000644 0001750 0001750 00000005143 11677073446 022073 0 ustar mikko mikko from django.core.files.storage import FileSystemStorage
class SlogHandler(object):
_log = []
_active = False
def start_log(self):
self._active = True
def stop_log(self):
self._active = False
log = self._log[:]
self._log = []
return log
def log(self, s):
if self._active:
self._log.append(s)
slog = SlogHandler()
class TestStorageMixin(object):
def open(self, name, *args, **kwargs):
slog.log('open: %s' % name)
return super(TestStorageMixin, self).open(name, *args, **kwargs)
def save(self, name, *args, **kwargs):
slog.log('save: %s' % name)
return super(TestStorageMixin, self).save(name, *args, **kwargs)
def get_valid_name(self, name, *args, **kwargs):
slog.log('get_valid_name: %s' % name)
return super(TestStorageMixin, self).get_valid_name(name, *args, **kwargs)
def get_available_name(self, name, *args, **kwargs):
slog.log('get_available_name: %s' % name)
return super(TestStorageMixin, self).get_available_name(name, *args, **kwargs)
def path(self, name, *args, **kwargs):
#slog.log('path: %s' % name)
return super(TestStorageMixin, self).path(name, *args, **kwargs)
def delete(self, name, *args, **kwargs):
slog.log('delete: %s' % name)
return super(TestStorageMixin, self).delete(name, *args, **kwargs)
def exists(self, name, *args, **kwargs):
slog.log('exists: %s' % name)
return super(TestStorageMixin, self).exists(name, *args, **kwargs)
def listdir(self, name, *args, **kwargs):
slog.log('listdir: %s' % name)
return super(TestStorageMixin, self).listdir(name, *args, **kwargs)
def size(self, name, *args, **kwargs):
slog.log('size: %s' % name)
return super(TestStorageMixin, self).size(name, *args, **kwargs)
def url(self, name, *args, **kwargs):
#slog.log('url: %s' % name)
return super(TestStorageMixin, self).url(name, *args, **kwargs)
def accessed_time(self, name, *args, **kwargs):
slog.log('accessed_time: %s' % name)
return super(TestStorageMixin, self).accessed_time(name, *args, **kwargs)
def created_time(self, name, *args, **kwargs):
slog.log('created_time: %s' % name)
return super(TestStorageMixin, self).created_time(name, *args, **kwargs)
def modified_time(self, name, *args, **kwargs):
slog.log('modified_time: %s' % name)
return super(TestStorageMixin, self).modified_time(name, *args, **kwargs)
class TestStorage(TestStorageMixin, FileSystemStorage):
pass
sorl-thumbnail-11.12/tests/thumbnail_tests/views.py 0000644 0001750 0001750 00000000000 11677073446 021547 0 ustar mikko mikko sorl-thumbnail-11.12/tests/thumbnail_tests/urls.py 0000644 0001750 0001750 00000000502 11677073446 021406 0 ustar mikko mikko from django.conf.urls.defaults import *
from django.conf import settings
urlpatterns = patterns('',
(r'^media/(?P.*)$', 'django.views.static.serve', {
'document_root': settings.MEDIA_ROOT,
'show_indexes': True}
),
(r'^(.*\.html)$', 'django.views.generic.simple.direct_to_template'),
)
sorl-thumbnail-11.12/tests/thumbnail_tests/models.py 0000644 0001750 0001750 00000000207 11677073446 021706 0 ustar mikko mikko from django.db import models
from sorl.thumbnail import ImageField
class Item(models.Model):
image = ImageField(upload_to=True)
sorl-thumbnail-11.12/tests/thumbnail_tests/templates/ 0000755 0001750 0001750 00000000000 11677075433 022046 5 ustar mikko mikko sorl-thumbnail-11.12/tests/thumbnail_tests/templates/thumbnail1.html 0000644 0001750 0001750 00000000365 11677073446 025006 0 ustar mikko mikko {% load thumbnail %}{% spaceless %}
{% thumbnail item.image "200x100" crop="50% 50%" as im %}
{% empty %}
{% endthumbnail %}
{% endspaceless %}
sorl-thumbnail-11.12/tests/thumbnail_tests/templates/thumbnaild1.html 0000644 0001750 0001750 00000000315 11677073446 025145 0 ustar mikko mikko {% load thumbnail %}{% spaceless %}
{% thumbnail anything "200x100" as im %}
{% endthumbnail %}
{% endspaceless %}
sorl-thumbnail-11.12/tests/thumbnail_tests/templates/thumbnail6.html 0000644 0001750 0001750 00000000443 11677073446 025010 0 ustar mikko mikko {% load thumbnail %}{% spaceless %}
{% thumbnail item.image "100x100" as th %}
{% thumbnail item.image "400x400" as im %}
{% endthumbnail %}
{% endthumbnail %}
{% endspaceless %}
sorl-thumbnail-11.12/tests/thumbnail_tests/templates/thumbnail8a.html 0000644 0001750 0001750 00000000250 11677073446 025147 0 ustar mikko mikko {% load thumbnail %}{% spaceless %}
{% thumbnail item.image "100x100" crop="center" upscale=True quality=77 as th %}
{{ th.url }}
{% endthumbnail %}
{% endspaceless %}
sorl-thumbnail-11.12/tests/thumbnail_tests/templates/thumbnail3.html 0000644 0001750 0001750 00000000365 11677073446 025010 0 ustar mikko mikko {% load thumbnail %}{% spaceless %}
{% thumbnail "http://www.aino.se/media/i/logo.png" "20x20" crop="center" as im %}
{% endthumbnail %}
{% endspaceless %}
sorl-thumbnail-11.12/tests/thumbnail_tests/templates/thumbnail7.html 0000644 0001750 0001750 00000000252 11677073446 025007 0 ustar mikko mikko {% load thumbnail %}{% spaceless %}
{% thumbnail item.image "100x100" crop="center" upscale="True" quality=70 as th %}
{{ th.url }}
{% endthumbnail %}
{% endspaceless %}
sorl-thumbnail-11.12/tests/thumbnail_tests/templates/thumbnail5.html 0000644 0001750 0001750 00000000371 11677073446 025007 0 ustar mikko mikko {% load thumbnail %}{% spaceless %}
{% thumbnail sorl "30x30" crop="50% 50%" as im %}
{% empty %}
empty{{ im }}
{% endthumbnail %}
{% endspaceless %}
sorl-thumbnail-11.12/tests/thumbnail_tests/templates/thumbnail7a.html 0000644 0001750 0001750 00000000252 11677073446 025150 0 ustar mikko mikko {% load thumbnail %}{% spaceless %}
{% thumbnail item.image "100x100" quality=70 crop="center" upscale="True" as th %}
{{ th.url }}
{% endthumbnail %}
{% endspaceless %}
sorl-thumbnail-11.12/tests/thumbnail_tests/templates/thumbnaild3.html 0000644 0001750 0001750 00000000252 11677073446 025147 0 ustar mikko mikko {% load thumbnail %}{% spaceless %}
{% thumbnail "" "x400" as im %}
{% endthumbnail %}
{% endspaceless %}
sorl-thumbnail-11.12/tests/thumbnail_tests/templates/thumbnail8.html 0000644 0001750 0001750 00000000222 11677073446 025005 0 ustar mikko mikko {% load thumbnail %}{% spaceless %}
{% thumbnail item.image "100x100" options=options as th %}
{{ th.url }}
{% endthumbnail %}
{% endspaceless %}
sorl-thumbnail-11.12/tests/thumbnail_tests/templates/thumbnail4.html 0000644 0001750 0001750 00000000601 11677073446 025002 0 ustar mikko mikko {% load thumbnail %}{% spaceless %}
{% if source|is_portrait %}
{% thumbnail source '1x1' as im %}
{% endthumbnail %}
{% else %}
{% thumbnail source dims as im %}
{% endthumbnail %}
{% endif %}
{% endspaceless %}
sorl-thumbnail-11.12/tests/thumbnail_tests/templates/thumbnail2.html 0000644 0001750 0001750 00000000354 11677073446 025005 0 ustar mikko mikko {% load thumbnail %}{% spaceless %}
{% thumbnail item.image.name "200x100" format="PNG" quality=99 as im %}
{% endthumbnail %}
{% endspaceless %}
sorl-thumbnail-11.12/tests/thumbnail_tests/templates/thumbnail9.html 0000644 0001750 0001750 00000000376 11677073446 025020 0 ustar mikko mikko {% load thumbnail %}{% spaceless %}
{% thumbnail "invalid" "30x30" crop="50% 50%" as im %}
{% empty %}
empty{{ im }}
{% endthumbnail %}
{% endspaceless %}
sorl-thumbnail-11.12/tests/thumbnail_tests/templates/thumbnail20.html 0000644 0001750 0001750 00000000223 11677073446 025060 0 ustar mikko mikko {% load thumbnail %}
{% thumbnail image "32x32" crop="center" as im %}
{% empty %}
fail
{% endthumbnail %}
sorl-thumbnail-11.12/tests/thumbnail_tests/templates/thumbnaild2.html 0000644 0001750 0001750 00000000340 11677073446 025144 0 ustar mikko mikko {% load thumbnail %}{% spaceless %}
{% thumbnail anything "300" as im %}
{% endthumbnail %}
{% if not ""|is_portrait %}NOT
{% endif %}
{% endspaceless %}
sorl-thumbnail-11.12/tests/thumbnail_tests/kvstore.py 0000644 0001750 0001750 00000001574 11677073446 022130 0 ustar mikko mikko from sorl.thumbnail.kvstores.cached_db_kvstore import KVStore
class KVlogHandler(object):
_log = []
_active = False
def start_log(self):
self._active = True
def stop_log(self):
self._active = False
log = self._log[:]
self._log = []
return log
def log(self, s):
if self._active:
self._log.append(s)
kvlog = KVlogHandler()
class TestKvStoreMixin(object):
def get(self, *args, **kwargs):
kvlog.log('get')
return super(TestKvStoreMixin, self).get(*args, **kwargs)
def set(self, *args, **kwargs):
kvlog.log('set')
return super(TestKvStoreMixin, self).set(*args, **kwargs)
def delete(self, *args, **kwargs):
kvlog.log('delete')
return super(TestKvStoreMixin, self).delete(*args, **kwargs)
class TestKVStore(TestKvStoreMixin, KVStore):
pass
sorl-thumbnail-11.12/tests/thumbnail_tests/tests.py 0000644 0001750 0001750 00000053634 11677073446 021601 0 ustar mikko mikko #coding=utf-8
import logging
import operator
import os
import re
import shutil
from PIL import Image
from django.core.files.storage import default_storage
from django.template.loader import render_to_string
from django.test.client import Client
from django.utils import unittest
from os.path import join as pjoin
from sorl.thumbnail import default, get_thumbnail, delete
from sorl.thumbnail.conf import settings
from sorl.thumbnail.engines.pil_engine import Engine as PILEngine
from sorl.thumbnail.helpers import get_module_class, ThumbnailError
from sorl.thumbnail.images import ImageFile
from sorl.thumbnail.log import ThumbnailLogHandler
from sorl.thumbnail.parsers import parse_crop, parse_geometry
from sorl.thumbnail.templatetags.thumbnail import margin
from subprocess import Popen, PIPE
from thumbnail_tests.models import Item
from thumbnail_tests.storage import slog
handler = ThumbnailLogHandler()
handler.setLevel(logging.ERROR)
logging.getLogger('sorl.thumbnail').addHandler(handler)
class StorageTestCase(unittest.TestCase):
def setUp(self):
name = 'org.jpg'
os.makedirs(settings.MEDIA_ROOT)
fn = pjoin(settings.MEDIA_ROOT, name)
Image.new('L', (100, 100)).save(fn)
self.im = ImageFile(name)
def test_a_new(self):
slog.start_log()
get_thumbnail(self.im, '50x50')
log = slog.stop_log()
actions = [
'exists: test/cache/20/c7/20c7ceda51cd4d26f8f4f375cf9dddf3.jpg', # first see if the file exists
'open: org.jpg', # open the original for thumbnailing
'save: test/cache/20/c7/20c7ceda51cd4d26f8f4f375cf9dddf3.jpg', # save the file
'get_available_name: test/cache/20/c7/20c7ceda51cd4d26f8f4f375cf9dddf3.jpg', # cehck for filename
'exists: test/cache/20/c7/20c7ceda51cd4d26f8f4f375cf9dddf3.jpg', # called by get_available_name
]
self.assertEqual(log, actions)
def test_b_cached(self):
slog.start_log()
get_thumbnail(self.im, '50x50')
log = slog.stop_log()
self.assertEqual(log, []) # now this should all be in cache
def test_c_safe_methods(self):
slog.start_log()
im = default.kvstore.get(self.im)
im.url, im.x, im.y
log = slog.stop_log()
self.assertEqual(log, [])
def tearDown(self):
shutil.rmtree(settings.MEDIA_ROOT)
class ParsersTestCase(unittest.TestCase):
def testAliasCrop(self):
crop = parse_crop('center', (500, 500), (400, 400))
self.assertEqual(crop, (50, 50))
crop = parse_crop('right', (500, 500), (400, 400))
self.assertEqual(crop, (100, 50))
def testPercentCrop(self):
crop = parse_crop('50% 0%', (500, 500), (400, 400))
self.assertEqual(crop, (50, 0))
crop = parse_crop('10% 80%', (500, 500), (400, 400))
self.assertEqual(crop, (10, 80))
def testPxCrop(self):
crop = parse_crop('200px 33px', (500, 500), (400, 400))
self.assertEqual(crop, (100, 33))
def testBadCrop(self):
self.assertRaises(ThumbnailError, parse_crop, '-200px', (500, 500), (400, 400))
def testGeometry(self):
g = parse_geometry('222x30')
self.assertEqual(g, (222, 30))
g = parse_geometry('222')
self.assertEqual(g, (222, None))
g = parse_geometry('x999')
self.assertEqual(g, (None, 999))
class SimpleTestCaseBase(unittest.TestCase):
def setUp(self):
self.backend = get_module_class(settings.THUMBNAIL_BACKEND)()
self.engine = get_module_class(settings.THUMBNAIL_ENGINE)()
self.kvstore = get_module_class(settings.THUMBNAIL_KVSTORE)()
if not os.path.exists(settings.MEDIA_ROOT):
os.makedirs(settings.MEDIA_ROOT)
dims = [
(500, 500),
(100, 100),
]
for dim in dims:
name = '%sx%s.jpg' % dim
fn = pjoin(settings.MEDIA_ROOT, name)
im = Image.new('L', dim)
im.save(fn)
Item.objects.get_or_create(image=name)
def tearDown(self):
shutil.rmtree(settings.MEDIA_ROOT)
class SimpleTestCase(SimpleTestCaseBase):
def testSimple(self):
item = Item.objects.get(image='500x500.jpg')
t = self.backend.get_thumbnail(item.image, '400x300', crop='center')
self.assertEqual(t.x, 400)
self.assertEqual(t.y, 300)
t = self.backend.get_thumbnail(item.image, '1200x900', crop='13% 89%')
self.assertEqual(t.x, 1200)
self.assertEqual(t.y, 900)
def testUpscale(self):
item = Item.objects.get(image='100x100.jpg')
t = self.backend.get_thumbnail(item.image, '400x300', upscale=False)
self.assertEqual(t.x, 100)
self.assertEqual(t.y, 100)
t = self.backend.get_thumbnail(item.image, '400x300', upscale=True)
self.assertEqual(t.x, 300)
self.assertEqual(t.y, 300)
def testKVStore(self):
im = ImageFile(Item.objects.get(image='500x500.jpg').image)
self.kvstore.delete_thumbnails(im)
th1 = self.backend.get_thumbnail(im, '50')
th2 = self.backend.get_thumbnail(im, 'x50')
th3 = self.backend.get_thumbnail(im, '20x20')
self.assertEqual(
set([th1.key, th2.key, th3.key]),
set(self.kvstore._get(im.key, identity='thumbnails'))
)
self.kvstore.delete_thumbnails(im)
self.assertEqual(
None,
self.kvstore._get(im.key, identity='thumbnails')
)
def testIsPortrait(self):
im = ImageFile(Item.objects.get(image='500x500.jpg').image)
th = self.backend.get_thumbnail(im, '50x200', crop='center')
self.assertEqual(th.is_portrait(), True)
th = self.backend.get_thumbnail(im, '500x2', crop='center')
self.assertEqual(th.is_portrait(), False)
def testMargin(self):
im = ImageFile(Item.objects.get(image='500x500.jpg').image)
self.assertEqual(margin(im, '1000x1000'), '250px 250px 250px 250px')
self.assertEqual(margin(im, '800x1000'), '250px 150px 250px 150px')
self.assertEqual(margin(im, '500x500'), '0px 0px 0px 0px')
self.assertEqual(margin(im, '500x501'), '0px 0px 1px 0px')
self.assertEqual(margin(im, '503x500'), '0px 2px 0px 1px')
self.assertEqual(margin(im, '300x300'), '-100px -100px -100px -100px')
def testKVStoreGetSet(self):
im = ImageFile(Item.objects.get(image='500x500.jpg').image)
self.kvstore.delete(im)
self.assertEqual(self.kvstore.get(im), None)
self.kvstore.set(im)
self.assertEqual(im.size, [500, 500])
def test_cleanup1(self):
im = ImageFile(Item.objects.get(image='500x500.jpg').image)
self.kvstore.delete_thumbnails(im)
th = self.backend.get_thumbnail(im, '3x3')
self.assertEqual(th.exists(), True)
th.delete()
self.assertEqual(th.exists(), False)
self.assertEqual(self.kvstore.get(th).x, 3)
self.assertEqual(self.kvstore.get(th).y, 3)
self.kvstore.cleanup()
self.assertEqual(self.kvstore.get(th), None)
self.kvstore.delete(im)
def test_cleanup2(self):
self.kvstore.clear()
im = ImageFile(Item.objects.get(image='500x500.jpg').image)
th3 = self.backend.get_thumbnail(im, '27x27')
th4 = self.backend.get_thumbnail(im, '81x81')
def keys_test(x, y, z):
self.assertEqual(x, len(list(self.kvstore._find_keys(identity='image'))))
self.assertEqual(y, len(list(self.kvstore._find_keys(identity='thumbnails'))))
self.assertEqual(z, len(self.kvstore._get(im.key, identity='thumbnails') or []))
keys_test(3, 1, 2)
th3.delete()
keys_test(3, 1, 2)
self.kvstore.cleanup()
keys_test(2, 1, 1)
th4.delete()
keys_test(2, 1, 1)
self.kvstore.cleanup()
keys_test(1, 0, 0)
self.kvstore.clear()
keys_test(0, 0, 0)
def test_storage_serialize(self):
im = ImageFile(Item.objects.get(image='500x500.jpg').image)
self.assertEqual(im.serialize_storage(), 'thumbnail_tests.storage.TestStorage')
self.assertEqual(
ImageFile('http://www.image.jpg').serialize_storage(),
'sorl.thumbnail.images.UrlStorage',
)
self.assertEqual(
ImageFile('http://www.image.jpg', default.storage).serialize_storage(),
'thumbnail_tests.storage.TestStorage',
)
self.assertEqual(
ImageFile('getit', default_storage).serialize_storage(),
'thumbnail_tests.storage.TestStorage',
)
def test_quality(self):
im = ImageFile(Item.objects.get(image='500x500.jpg').image)
th = self.backend.get_thumbnail(im, '100x100', quality=50)
p1 = Popen(['identify', '-verbose', th.storage.path(th.name)], stdout=PIPE)
p2 = Popen(['grep', '-c', 'Quality: 50'], stdin=p1.stdout, stdout=PIPE)
p1.stdout.close()
output = p2.communicate()[0].strip()
self.assertEqual(output, '1')
def test_image_file_deserialize(self):
im = ImageFile(Item.objects.get(image='500x500.jpg').image)
default.kvstore.set(im)
self.assertEqual(
default.kvstore.get(im).serialize_storage(),
'thumbnail_tests.storage.TestStorage',
)
im = ImageFile('http://www.aino.se/media/i/logo.png')
default.kvstore.set(im)
self.assertEqual(
default.kvstore.get(im).serialize_storage(),
'sorl.thumbnail.images.UrlStorage',
)
def test_abspath(self):
item = Item.objects.get(image='500x500.jpg')
image = ImageFile(item.image.path)
val = render_to_string('thumbnail20.html', {
'image': image,
}).strip()
im = self.backend.get_thumbnail(image, '32x32', crop='center')
self.assertEqual('
' % im.url, val)
class TemplateTestCaseA(SimpleTestCaseBase):
def testModel(self):
item = Item.objects.get(image='500x500.jpg')
val = render_to_string('thumbnail1.html', {
'item': item,
}).strip()
self.assertEqual(val, u'
')
val = render_to_string('thumbnail2.html', {
'item': item,
}).strip()
self.assertEqual(val, u'
')
def test_nested(self):
item = Item.objects.get(image='500x500.jpg')
val = render_to_string('thumbnail6.html', {
'item': item,
}).strip()
self.assertEqual(val, (''
'
'
''))
def test_serialization_options(self):
item = Item.objects.get(image='500x500.jpg')
for j in xrange(0, 20):
# we could be lucky...
val0 = render_to_string('thumbnail7.html', {
'item': item,
}).strip()
val1 = render_to_string('thumbnail7a.html', {
'item': item,
}).strip()
self.assertEqual(val0, val1)
def test_options(self):
item = Item.objects.get(image='500x500.jpg')
options = {
'crop': "center",
'upscale': True,
'quality': 77,
}
val0 = render_to_string('thumbnail8.html', {
'item': item,
'options': options,
}).strip()
val1 = render_to_string('thumbnail8a.html', {
'item': item,
}).strip()
self.assertEqual(val0, val1)
def test_progressive(self):
im = Item.objects.get(image='500x500.jpg').image
th = self.backend.get_thumbnail(im, '100x100', progressive=True)
path = pjoin(settings.MEDIA_ROOT, th.name)
p = Popen(['identify', '-verbose', path], stdout=PIPE)
p.wait()
m = re.search('Interlace: JPEG', p.stdout.read())
self.assertEqual(bool(m), True)
def test_nonprogressive(self):
im = Item.objects.get(image='500x500.jpg').image
th = self.backend.get_thumbnail(im, '100x100', progressive=False)
path = pjoin(settings.MEDIA_ROOT, th.name)
p = Popen(['identify', '-verbose', path], stdout=PIPE)
p.wait()
m = re.search('Interlace: None', p.stdout.read())
self.assertEqual(bool(m), True)
def test_orientation(self):
data_dir = pjoin(settings.MEDIA_ROOT, 'data')
shutil.copytree(settings.DATA_ROOT, data_dir)
ref = Image.open(pjoin(data_dir, '1_topleft.jpg'))
top = ref.getpixel((14, 7))
left = ref.getpixel((7, 14))
engine = PILEngine()
def epsilon(x, y):
if isinstance(x, (tuple, list)):
x = sum(x) / len(x)
if isinstance(y, (tuple, list)):
y = sum(y) / len(y)
return abs(x - y)
for name in sorted(os.listdir(data_dir)):
th = self.backend.get_thumbnail('data/%s' % name, '30x30')
im = engine.get_image(th)
self.assertLess(epsilon(top, im.getpixel((14, 7))), 10)
self.assertLess(epsilon(left, im.getpixel((7, 14))), 10)
exif = im._getexif()
if exif:
self.assertEqual(exif.get(0x0112), 1)
class TemplateTestCaseB(unittest.TestCase):
def tearDown(self):
try:
shutil.rmtree(settings.MEDIA_ROOT)
except Exception:
pass
def testUrl(self):
val = render_to_string('thumbnail3.html', {}).strip()
self.assertEqual(val, '
')
def testPortrait(self):
val = render_to_string('thumbnail4.html', {
'source': 'http://www.aino.se/media/i/logo.png',
'dims': 'x666',
}).strip()
self.assertEqual(val, '
')
def testEmpty(self):
val = render_to_string('thumbnail5.html', {}).strip()
self.assertEqual(val, 'empty
')
class TemplateTestCaseClient(unittest.TestCase):
def setUp(self):
self.org_settings = {}
params = {
'THUMBNAIL_DEBUG': False,
}
for k, v in params.iteritems():
self.org_settings[k] = getattr(settings, k)
setattr(settings, k, v)
def testEmptyError(self):
client = Client()
response = client.get('/thumbnail9.html')
self.assertEqual(response.content.strip(), 'empty
')
from django.core.mail import outbox
self.assertEqual(outbox[0].subject, '[sorl-thumbnail] ERROR: /thumbnail9.html')
end = outbox[0].body.split('\n\n')[-2][-20:-1]
self.assertEqual(end, 'tests/media/invalid')
def tearDown(self):
for k, v in self.org_settings.iteritems():
setattr(settings, k, v)
class CropTestCase(unittest.TestCase):
def setUp(self):
self.backend = get_module_class(settings.THUMBNAIL_BACKEND)()
self.engine = get_module_class(settings.THUMBNAIL_ENGINE)()
self.kvstore = get_module_class(settings.THUMBNAIL_KVSTORE)()
if not os.path.exists(settings.MEDIA_ROOT):
os.makedirs(settings.MEDIA_ROOT)
# portrait
name = 'portrait.jpg'
fn = pjoin(settings.MEDIA_ROOT, name)
im = Image.new('L', (100, 200))
im.paste(255, (0, 0, 100, 100))
im.save(fn)
self.portrait = ImageFile(Item.objects.get_or_create(image=name)[0].image)
self.kvstore.delete(self.portrait)
# landscape
name = 'landscape.jpg'
fn = pjoin(settings.MEDIA_ROOT, name)
im = Image.new('L', (200, 100))
im.paste(255, (0, 0, 100, 100))
im.save(fn)
self.landscape = ImageFile(Item.objects.get_or_create(image=name)[0].image)
self.kvstore.delete(self.landscape)
def testPortraitCrop(self):
def mean_pixel(x, y):
values = im.getpixel((x, y))
if not isinstance(values, (tuple, list)):
values = [values]
return reduce(operator.add, values) / len(values)
for crop in ('center', '88% 50%', '50px'):
th = self.backend.get_thumbnail(self.portrait, '100x100', crop=crop)
engine = PILEngine()
im = engine.get_image(th)
self.assertEqual(mean_pixel(50,0), 255)
self.assertEqual(mean_pixel(50,45), 255)
self.assertEqual(250 < mean_pixel(50,49) <= 255, True)
self.assertEqual(mean_pixel(50,55), 0)
self.assertEqual(mean_pixel(50,99), 0)
for crop in ('top', '0%', '0px'):
th = self.backend.get_thumbnail(self.portrait, '100x100', crop=crop)
engine = PILEngine()
im = engine.get_image(th)
for x in xrange(0, 99, 10):
for y in xrange(0, 99, 10):
self.assertEqual(250 < mean_pixel(x, y) <= 255, True)
for crop in ('bottom', '100%', '100px'):
th = self.backend.get_thumbnail(self.portrait, '100x100', crop=crop)
engine = PILEngine()
im = engine.get_image(th)
for x in xrange(0, 99, 10):
for y in xrange(0, 99, 10):
self.assertEqual(0 <= mean_pixel(x, y) < 5, True)
def testLandscapeCrop(self):
def mean_pixel(x, y):
values = im.getpixel((x, y))
if not isinstance(values, (tuple, list)):
values = [values]
return reduce(operator.add, values) / len(values)
for crop in ('center', '50% 200%', '50px 700px'):
th = self.backend.get_thumbnail(self.landscape, '100x100', crop=crop)
engine = PILEngine()
im = engine.get_image(th)
self.assertEqual(mean_pixel(0, 50), 255)
self.assertEqual(mean_pixel(45, 50), 255)
self.assertEqual(250 < mean_pixel(49, 50) <= 255, True)
self.assertEqual(mean_pixel(55, 50), 0)
self.assertEqual(mean_pixel(99, 50), 0)
for crop in ('left', '0%', '0px'):
th = self.backend.get_thumbnail(self.landscape, '100x100', crop=crop)
engine = PILEngine()
im = engine.get_image(th)
for x in xrange(0, 99, 10):
for y in xrange(0, 99, 10):
self.assertEqual(250 < mean_pixel(x, y) <= 255, True)
for crop in ('right', '100%', '100px'):
th = self.backend.get_thumbnail(self.landscape, '100x100', crop=crop)
engine = PILEngine()
im = engine.get_image(th)
for x in xrange(0, 99, 10):
for y in xrange(0, 99, 10):
self.assertEqual(0 <= mean_pixel(x, y) < 5, True)
def tearDown(self):
shutil.rmtree(settings.MEDIA_ROOT)
class DummyTestCase(unittest.TestCase):
def setUp(self):
self.backend = get_module_class(settings.THUMBNAIL_BACKEND)()
self.org_settings = {}
params = {
'THUMBNAIL_DUMMY': True,
}
for k, v in params.iteritems():
self.org_settings[k] = getattr(settings, k)
setattr(settings, k, v)
def test_dummy_tags(self):
val = render_to_string('thumbnaild1.html', {
'anything': 'AINO',
}).strip()
self.assertEqual(val, '
')
val = render_to_string('thumbnaild2.html', {
'anything': None,
}).strip()
self.assertEqual(val, '
NOT
')
val = render_to_string('thumbnaild3.html', {
}).strip()
self.assertEqual(val, '
')
def tearDown(self):
for k, v in self.org_settings.iteritems():
setattr(settings, k, v)
class ModelTestCase(SimpleTestCaseBase):
def test_field1(self):
self.kvstore.clear()
item = Item.objects.get(image='100x100.jpg')
im = ImageFile(item.image)
self.assertEqual(None, self.kvstore.get(im))
self.backend.get_thumbnail(im, '27x27')
self.backend.get_thumbnail(im, '81x81')
self.assertNotEqual(None, self.kvstore.get(im))
self.assertEqual(3, len(list(self.kvstore._find_keys(identity='image'))))
self.assertEqual(1, len(list(self.kvstore._find_keys(identity='thumbnails'))))
class BackendTest(SimpleTestCaseBase):
def test_delete(self):
im1 = Item.objects.get(image='100x100.jpg').image
im2 = Item.objects.get(image='500x500.jpg').image
default.kvstore.get_or_set(ImageFile(im1))
# exists in kvstore and in storage
self.assertTrue(bool(default.kvstore.get(ImageFile(im1))))
self.assertTrue(ImageFile(im1).exists())
# delete
delete(im1)
self.assertFalse(bool(default.kvstore.get(ImageFile(im1))))
self.assertFalse(ImageFile(im1).exists())
default.kvstore.get_or_set(ImageFile(im2))
# exists in kvstore and in storage
self.assertTrue(bool(default.kvstore.get(ImageFile(im2))))
self.assertTrue(ImageFile(im2).exists())
# delete
delete(im2, delete_file=False)
self.assertFalse(bool(default.kvstore.get(ImageFile(im2))))
self.assertTrue(ImageFile(im2).exists())
class TestInputCase(unittest.TestCase):
def setUp(self):
if not os.path.exists(settings.MEDIA_ROOT):
os.makedirs(settings.MEDIA_ROOT)
self.name = u'åäö.jpg'
fn = pjoin(settings.MEDIA_ROOT, self.name)
im = Image.new('L', (666, 666))
im.save(fn)
def test_nonascii(self):
# also test the get_thumbnail shortcut
th = get_thumbnail(self.name, '200x200')
self.assertEqual(
th.url,
'/media/test/cache/8a/17/8a17eff95c6ecf46f82d0807d93631e9.jpg'
)
def tearDown(self):
shutil.rmtree(settings.MEDIA_ROOT)
sorl-thumbnail-11.12/tests/runalltests.sh 0000755 0001750 0001750 00000000172 11677073446 017564 0 ustar mikko mikko #/bin/bash
for name in pil pgmagick imagemagick graphicsmagick redis
do
./runtests.py --settings=settings.$name
done
sorl-thumbnail-11.12/tests/data/ 0000755 0001750 0001750 00000000000 11677075433 015554 5 ustar mikko mikko sorl-thumbnail-11.12/tests/data/8_leftbottom.jpg 0000644 0001750 0001750 00000001024 11677073446 020663 0 ustar mikko mikko JFIF H H "Exif II* C Created with GIMP on a Mac
? &
#'678$%)59CFGHXdei ?