Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
- repo: git@github.com:pre-commit/pre-commit-hooks
sha: 29bf11d13689a0a9a895c41eb3591c7e942d377d
sha: e306ff3b7d0d9a6fc7d128ef9ca2e0b6e6e76e8f
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
Expand All @@ -13,13 +13,13 @@
args:
- requirements-dev.txt
- repo: git://github.com/FalconSocial/pre-commit-mirrors-pep257
sha: 67c970e89857fdcebcd59ace94950a3331985a3b
sha: ebb1b1bb080b0c960bcf37cf81d09185cec4fc6d
hooks:
- id: pep257
args:
- --explain
- --ignore=D100,D101,D102,D103,D104,D105,D203
- repo: git://github.com/FalconSocial/pre-commit-python-sorter
sha: 934072fb29303aaa64bead610be042049e9db488
sha: ec01d99f48a0dabb2ebbb2675139e2cc0fe2aa93
hooks:
- id: python-import-sorter
11 changes: 3 additions & 8 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
language: python
sudo: false
cache:
- pip
cache: pip
python:
- "2.7"
- "3.3"
- "3.4"
- "3.5"
- "pypy"
- "pypy3"
env:
matrix:
- DJANGO="Django<1.8,>=1.7"
- DJANGO="Django<1.9,>=1.8"
- DJANGO="Django<1.10,>=1.9"
- DJANGO="-e git+https://github.com/django/django.git@master#egg=Django"
matrix:
fast_finish: true
allow_failures:
- python: "3.5"
- env: DJANGO="-e git+https://github.com/django/django.git@master#egg=Django"
install:
- pip install --upgrade pip
Expand All @@ -28,6 +23,6 @@ script:
- isort --check-only --recursive --diff .
- flake8 --jobs=2 .
- pep257 --verbose --explain --source --count stdimage
- coverage run --source=stdimage runtests.py
- coverage run --source=stdimage -m 'pytest'
after_success:
- coveralls
1 change: 0 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ Django Standarized Image Field
Django Field that implement the following features:

* Django-Storages compatible (S3)
* Python 2, 3 and PyPy support
* Resize images to different sizes
* Access thumbnails on model level, no template tags required
* Preserves original image
Expand Down
29 changes: 5 additions & 24 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from setuptools import Command, find_packages, setup


class PyTest(Command):
user_options = []

def initialize_options(self):
pass

def finalize_options(self):
pass

def run(self):
import sys
import subprocess

errno = subprocess.call([sys.executable, 'runtests.py'])
raise SystemExit(errno)

from setuptools import find_packages, setup

setup(
name='django-stdimage',
Expand All @@ -39,13 +21,13 @@ def run(self):
'Programming Language :: Python',
'Topic :: Software Development',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.2',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: Implementation :: PyPy',
'Programming Language :: Python :: 3.5',
'Framework :: Django',
'Framework :: Django :: 1.8',
'Framework :: Django :: 1.9',
],
packages=find_packages(exclude=[
"*.tests", "*.tests.*", "tests.*", "tests", ".egg-info"
Expand All @@ -55,5 +37,4 @@ def run(self):
'pillow>=2.5',
'progressbar2>=3.0.0',
],
cmdclass={'test': PyTest},
)
36 changes: 11 additions & 25 deletions stdimage/management/commands/rendervariations.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,19 @@
from multiprocessing import Pool, cpu_count

import progressbar
from django.apps import apps
from django.core.files.storage import get_storage_class
from django.core.management import BaseCommand
from django.db.models import get_model

from stdimage.utils import render_variations

is_pypy = '__pypy__' in sys.builtin_module_names
BAR = None


def class_to_path(cls):
return '.'.join((cls.__module__, cls.__class__.__name__))


class MemoryUsageWidget(progressbar.widgets.WidgetBase):
def __call__(self, progress, data):
return 'RAM: {0:10.1f} MB'.format(
Expand All @@ -38,7 +42,7 @@ def handle(self, *args, **options):
replace = options.get('replace')
for route in args:
app_label, model_name, field_name = route.rsplit('.')
model_class = get_model(app_label, model_name)
model_class = apps.get_model(app_label, model_name)
field = model_class._meta.get_field(field_name)

queryset = model_class._default_manager \
Expand All @@ -47,13 +51,10 @@ def handle(self, *args, **options):
images = queryset.values_list(field_name, flat=True).iterator()
count = queryset.count()

if is_pypy: # pypy doesn't handle multiprocessing to well
self.render_linear(field, images, count, replace)
else:
self.render_in_parallel(field, images, count, replace)
self.render(field, images, count, replace)

@staticmethod
def render_in_parallel(field, images, count, replace):
def render(field, images, count, replace):
pool = Pool(
initializer=init_progressbar,
initargs=[count]
Expand All @@ -63,7 +64,7 @@ def render_in_parallel(field, images, count, replace):
file_name=file_name,
variations=field.variations,
replace=replace,
storage=field.storage
storage=class_to_path(field.storage),
)
for file_name in images
]
Expand All @@ -72,22 +73,6 @@ def render_in_parallel(field, images, count, replace):
pool.close()
pool.join()

@staticmethod
def render_linear(field, images, count, replace):
init_progressbar(count)
args_list = [
dict(
file_name=file_name,
variations=field.variations,
replace=replace,
storage=field.storage
)
for file_name in images
]
for args in args_list:
render_variations(**args)
finish_progressbar()


def init_progressbar(count):
global BAR
Expand All @@ -107,6 +92,7 @@ def finish_progressbar():

def render_field_variations(kwargs):
try:
kwargs['storage'] = get_storage_class(kwargs['storage'])()
render_variations(**kwargs)
global BAR
BAR += 1
Expand Down
9 changes: 5 additions & 4 deletions stdimage/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
from io import BytesIO

from django.core.files.base import ContentFile
from django.core.files.storage import DefaultStorage
from django.core.files.storage import default_storage
from django.db.models import signals
from django.db.models.fields.files import (ImageField, ImageFieldFile,
ImageFileDescriptor)
from django.db.models.fields.files import (
ImageField, ImageFieldFile, ImageFileDescriptor
)
from PIL import Image, ImageOps

from .validators import MinSizeValidator
Expand Down Expand Up @@ -58,7 +59,7 @@ def render_variations(self, replace=False):

@classmethod
def render_variation(cls, file_name, variation, replace=False,
storage=DefaultStorage()):
storage=default_storage):
"""Render an image variation and saves it to the storage."""
variation_name = cls.get_variation_name(file_name, variation['name'])
if storage.exists(variation_name):
Expand Down
4 changes: 2 additions & 2 deletions stdimage/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import os
import uuid

from django.core.files.storage import DefaultStorage
from django.core.files.storage import default_storage
from django.utils.text import slugify

from .models import StdImageField, StdImageFieldFile
Expand Down Expand Up @@ -89,7 +89,7 @@ def pre_save_delete_callback(sender, instance, **kwargs):


def render_variations(file_name, variations, replace=False,
storage=DefaultStorage()):
storage=default_storage):
"""Render all variations for a given field."""
for key, variation in variations.items():
StdImageFieldFile.render_variation(
Expand Down
23 changes: 17 additions & 6 deletions tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class UUID4Monkey(object):

uuid.__dict__['uuid4'] = lambda: UUID4Monkey()

import django # NoQA
from django.conf import settings # NoQA
from django.core.files import File # NoQA
from django.test import TestCase # NoQA
Expand Down Expand Up @@ -174,9 +175,14 @@ def test_pre_save_delete_callback_clear(self):
AdminDeleteModel.objects.create(
image=self.fixtures['100.gif']
)
self.client.post('/admin/tests/admindeletemodel/1/', {
'image-clear': 'checked',
})
if django.VERSION >= (1, 9):
self.client.post('/admin/tests/admindeletemodel/1/change/', {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use reverse here? name is admin:appname_modelname_change

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point

'image-clear': 'checked',
})
else:
self.client.post('/admin/tests/admindeletemodel/1/', {
'image-clear': 'checked',
})
self.assertFalse(
os.path.exists(os.path.join(IMG_DIR, 'image.gif'))
)
Expand All @@ -185,9 +191,14 @@ def test_pre_save_delete_callback_new(self):
AdminDeleteModel.objects.create(
image=self.fixtures['100.gif']
)
self.client.post('/admin/tests/admindeletemodel/1/', {
'image': self.fixtures['600x400.jpg'],
})
if django.VERSION >= (1, 9):
self.client.post('/admin/tests/admindeletemodel/1/change/', {
'image': self.fixtures['600x400.jpg'],
})
else:
self.client.post('/admin/tests/admindeletemodel/1/', {
'image': self.fixtures['600x400.jpg'],
})
self.assertFalse(
os.path.exists(os.path.join(IMG_DIR, 'image.gif'))
)
Expand Down