From 6984f667947cc97a8c49626ee47537f3784010bb Mon Sep 17 00:00:00 2001 From: Sam Wenham Date: Sat, 2 Mar 2019 14:10:51 +0000 Subject: [PATCH] Updates required to move to django 1.8 --- core/models.py | 6 +- databaseReset.py | 5 +- docker/README.md | 1 + imagekit/__init__.py | 13 --- imagekit/defaults.py | 21 ---- imagekit/lib.py | 17 --- imagekit/management/__init__.py | 1 - imagekit/management/commands/__init__.py | 1 - imagekit/management/commands/ikflush.py | 38 ------- imagekit/models.py | 136 ----------------------- imagekit/options.py | 23 ---- imagekit/processors.py | 134 ---------------------- imagekit/specs.py | 119 -------------------- imagekit/tests.py | 86 -------------- imagekit/utils.py | 15 --- settings.py | 2 +- 16 files changed, 8 insertions(+), 610 deletions(-) delete mode 100644 imagekit/__init__.py delete mode 100644 imagekit/defaults.py delete mode 100644 imagekit/lib.py delete mode 100644 imagekit/management/__init__.py delete mode 100644 imagekit/management/commands/__init__.py delete mode 100644 imagekit/management/commands/ikflush.py delete mode 100644 imagekit/models.py delete mode 100644 imagekit/options.py delete mode 100644 imagekit/processors.py delete mode 100644 imagekit/specs.py delete mode 100644 imagekit/tests.py delete mode 100644 imagekit/utils.py diff --git a/core/models.py b/core/models.py index 8cc91ea..6924606 100644 --- a/core/models.py +++ b/core/models.py @@ -10,7 +10,7 @@ from django.db.models import Min, Max from django.conf import settings from decimal import Decimal, getcontext from django.core.urlresolvers import reverse -from imagekit.models import ImageModel +from imagekit.models import ProcessedImageField #ImageModel from django.template import Context, loader import settings getcontext().prec=2 #use 2 significant figures for decimal calculations @@ -57,7 +57,7 @@ class TroggleModel(models.Model): class Meta: abstract = True -class TroggleImageModel(ImageModel): +class TroggleImageModel(models.Model): new_since_parsing = models.BooleanField(default=False, editable=False) def object_name(self): @@ -807,7 +807,7 @@ def get_scan_path(instance, filename): number=str(instance.survey.wallet_letter) + number #two strings formatting because convention is 2009#01 or 2009#X01 return os.path.join('./',year,year+r'#'+number,str(instance.contents)+str(instance.number_in_wallet)+r'.jpg') -class ScannedImage(TroggleImageModel): +class ScannedImage(TroggleImageModel): file = models.ImageField(storage=scansFileStorage, upload_to=get_scan_path) scanned_by = models.ForeignKey(Person,blank=True, null=True) scanned_on = models.DateField(null=True) diff --git a/databaseReset.py b/databaseReset.py index f17d3e5..27271a7 100644 --- a/databaseReset.py +++ b/databaseReset.py @@ -28,7 +28,8 @@ def reload_db(): cursor.execute("CREATE DATABASE %s" % databasename) cursor.execute("ALTER DATABASE %s CHARACTER SET=utf8" % databasename) cursor.execute("USE %s" % databasename) - management.call_command('syncdb', interactive=False) + management.call_command('migrate', interactive=False) + #management.call_command('syncdb', interactive=False) user = User.objects.create_user(expouser, expouseremail, expouserpass) user.is_staff = True user.is_superuser = True @@ -218,7 +219,7 @@ if __name__ == "__main__": import_descriptions() parse_descriptions() elif "survex" in sys.argv: - management.call_command('syncdb', interactive=False) # this sets the path so that import settings works in import_survex + #management.call_command('syncdb', interactive=False) # this sets the path so that import settings works in import_survex import_survex() elif "survexpos" in sys.argv: management.call_command('syncdb', interactive=False) # this sets the path so that import settings works in import_survex diff --git a/docker/README.md b/docker/README.md index 86028fd..90a5620 100644 --- a/docker/README.md +++ b/docker/README.md @@ -40,6 +40,7 @@ mkdir -p expofiles/surveyscans To start the containers run ```bash +$ cd ~/expo/troggle/docker $ docker-compose up ``` You will now have a working troggle but with no data. To import the data you need to access the container run diff --git a/imagekit/__init__.py b/imagekit/__init__.py deleted file mode 100644 index 2965bbd..0000000 --- a/imagekit/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -""" - -Django ImageKit - -Author: Justin Driscoll -Version: 0.2 - -""" -VERSION = "0.2" - - - - \ No newline at end of file diff --git a/imagekit/defaults.py b/imagekit/defaults.py deleted file mode 100644 index e1a05f6..0000000 --- a/imagekit/defaults.py +++ /dev/null @@ -1,21 +0,0 @@ -""" Default ImageKit configuration """ - -from imagekit.specs import ImageSpec -from imagekit import processors - -class ResizeThumbnail(processors.Resize): - width = 100 - height = 50 - crop = True - -class EnhanceSmall(processors.Adjustment): - contrast = 1.2 - sharpness = 1.1 - -class SampleReflection(processors.Reflection): - size = 0.5 - background_color = "#000000" - -class DjangoAdminThumbnail(ImageSpec): - access_as = 'admin_thumbnail' - processors = [ResizeThumbnail, EnhanceSmall, SampleReflection] diff --git a/imagekit/lib.py b/imagekit/lib.py deleted file mode 100644 index 65646a4..0000000 --- a/imagekit/lib.py +++ /dev/null @@ -1,17 +0,0 @@ -# Required PIL classes may or may not be available from the root namespace -# depending on the installation method used. -try: - import Image - import ImageFile - import ImageFilter - import ImageEnhance - import ImageColor -except ImportError: - try: - from PIL import Image - from PIL import ImageFile - from PIL import ImageFilter - from PIL import ImageEnhance - from PIL import ImageColor - except ImportError: - raise ImportError('ImageKit was unable to import the Python Imaging Library. Please confirm it`s installed and available on your current Python path.') \ No newline at end of file diff --git a/imagekit/management/__init__.py b/imagekit/management/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/imagekit/management/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/imagekit/management/commands/__init__.py b/imagekit/management/commands/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/imagekit/management/commands/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/imagekit/management/commands/ikflush.py b/imagekit/management/commands/ikflush.py deleted file mode 100644 index c03440f..0000000 --- a/imagekit/management/commands/ikflush.py +++ /dev/null @@ -1,38 +0,0 @@ -from django.db.models.loading import cache -from django.core.management.base import BaseCommand, CommandError -from optparse import make_option -from imagekit.models import ImageModel -from imagekit.specs import ImageSpec - - -class Command(BaseCommand): - help = ('Clears all ImageKit cached files.') - args = '[apps]' - requires_model_validation = True - can_import_settings = True - - def handle(self, *args, **options): - return flush_cache(args, options) - -def flush_cache(apps, options): - """ Clears the image cache - - """ - apps = [a.strip(',') for a in apps] - if apps: - print 'Flushing cache for %s...' % ', '.join(apps) - else: - print 'Flushing caches...' - - for app_label in apps: - app = cache.get_app(app_label) - models = [m for m in cache.get_models(app) if issubclass(m, ImageModel)] - - for model in models: - for obj in model.objects.all(): - for spec in model._ik.specs: - prop = getattr(obj, spec.name(), None) - if prop is not None: - prop._delete() - if spec.pre_cache: - prop._create() diff --git a/imagekit/models.py b/imagekit/models.py deleted file mode 100644 index 140715e..0000000 --- a/imagekit/models.py +++ /dev/null @@ -1,136 +0,0 @@ -import os -from datetime import datetime -from django.conf import settings -from django.core.files.base import ContentFile -from django.db import models -from django.db.models.base import ModelBase -from django.utils.translation import ugettext_lazy as _ - -from imagekit import specs -from imagekit.lib import * -from imagekit.options import Options -from imagekit.utils import img_to_fobj - -# Modify image file buffer size. -ImageFile.MAXBLOCK = getattr(settings, 'PIL_IMAGEFILE_MAXBLOCK', 256 * 2 ** 10) - -# Choice tuples for specifying the crop origin. -# These are provided for convenience. -CROP_HORZ_CHOICES = ( - (0, _('left')), - (1, _('center')), - (2, _('right')), -) - -CROP_VERT_CHOICES = ( - (0, _('top')), - (1, _('center')), - (2, _('bottom')), -) - - -class ImageModelBase(ModelBase): - """ ImageModel metaclass - - This metaclass parses IKOptions and loads the specified specification - module. - - """ - def __init__(cls, name, bases, attrs): - parents = [b for b in bases if isinstance(b, ImageModelBase)] - if not parents: - return - user_opts = getattr(cls, 'IKOptions', None) - opts = Options(user_opts) - try: - module = __import__(opts.spec_module, {}, {}, ['']) - except ImportError: - raise ImportError('Unable to load imagekit config module: %s' % \ - opts.spec_module) - for spec in [spec for spec in module.__dict__.values() \ - if isinstance(spec, type) \ - and issubclass(spec, specs.ImageSpec) \ - and spec != specs.ImageSpec]: - setattr(cls, spec.name(), specs.Descriptor(spec)) - opts.specs.append(spec) - setattr(cls, '_ik', opts) - - -class ImageModel(models.Model): - """ Abstract base class implementing all core ImageKit functionality - - Subclasses of ImageModel are augmented with accessors for each defined - image specification and can override the inner IKOptions class to customize - storage locations and other options. - - """ - __metaclass__ = ImageModelBase - - class Meta: - abstract = True - - class IKOptions: - pass - - def admin_thumbnail_view(self): - if not self._imgfield: - return None - prop = getattr(self, self._ik.admin_thumbnail_spec, None) - if prop is None: - return 'An "%s" image spec has not been defined.' % \ - self._ik.admin_thumbnail_spec - else: - if hasattr(self, 'get_absolute_url'): - return u'' % \ - (self.get_absolute_url(), prop.url) - else: - return u'' % \ - (self._imgfield.url, prop.url) - admin_thumbnail_view.short_description = _('Thumbnail') - admin_thumbnail_view.allow_tags = True - - @property - def _imgfield(self): - return getattr(self, self._ik.image_field) - - def _clear_cache(self): - for spec in self._ik.specs: - prop = getattr(self, spec.name()) - prop._delete() - - def _pre_cache(self): - for spec in self._ik.specs: - if spec.pre_cache: - prop = getattr(self, spec.name()) - prop._create() - - def save(self, clear_cache=True, *args, **kwargs): - is_new_object = self._get_pk_val is None - super(ImageModel, self).save(*args, **kwargs) - if is_new_object: - clear_cache = False - spec = self._ik.preprocessor_spec - if spec is not None: - newfile = self._imgfield.storage.open(str(self._imgfield)) - img = Image.open(newfile) - img = spec.process(img, None) - format = img.format or 'JPEG' - if format != 'JPEG': - imgfile = img_to_fobj(img, format) - else: - imgfile = img_to_fobj(img, format, - quality=int(spec.quality), - optimize=True) - content = ContentFile(imgfile.read()) - newfile.close() - name = str(self._imgfield) - self._imgfield.storage.delete(name) - self._imgfield.storage.save(name, content) - if clear_cache and self._imgfield != '': - self._clear_cache() - self._pre_cache() - - def delete(self): - assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname) - self._clear_cache() - models.Model.delete(self) diff --git a/imagekit/options.py b/imagekit/options.py deleted file mode 100644 index 022cc9e..0000000 --- a/imagekit/options.py +++ /dev/null @@ -1,23 +0,0 @@ -# Imagekit options -from imagekit import processors -from imagekit.specs import ImageSpec - - -class Options(object): - """ Class handling per-model imagekit options - - """ - image_field = 'image' - crop_horz_field = 'crop_horz' - crop_vert_field = 'crop_vert' - preprocessor_spec = None - cache_dir = 'cache' - save_count_as = None - cache_filename_format = "%(filename)s_%(specname)s.%(extension)s" - admin_thumbnail_spec = 'admin_thumbnail' - spec_module = 'imagekit.defaults' - - def __init__(self, opts): - for key, value in opts.__dict__.iteritems(): - setattr(self, key, value) - self.specs = [] \ No newline at end of file diff --git a/imagekit/processors.py b/imagekit/processors.py deleted file mode 100644 index 6f6b480..0000000 --- a/imagekit/processors.py +++ /dev/null @@ -1,134 +0,0 @@ -""" Imagekit Image "ImageProcessors" - -A processor defines a set of class variables (optional) and a -class method named "process" which processes the supplied image using -the class properties as settings. The process method can be overridden as well allowing user to define their -own effects/processes entirely. - -""" -from imagekit.lib import * - -class ImageProcessor(object): - """ Base image processor class """ - @classmethod - def process(cls, image, obj=None): - return image - - -class Adjustment(ImageProcessor): - color = 1.0 - brightness = 1.0 - contrast = 1.0 - sharpness = 1.0 - - @classmethod - def process(cls, image, obj=None): - for name in ['Color', 'Brightness', 'Contrast', 'Sharpness']: - factor = getattr(cls, name.lower()) - if factor != 1.0: - image = getattr(ImageEnhance, name)(image).enhance(factor) - return image - - -class Reflection(ImageProcessor): - background_color = '#FFFFFF' - size = 0.0 - opacity = 0.6 - - @classmethod - def process(cls, image, obj=None): - # convert bgcolor string to rgb value - background_color = ImageColor.getrgb(cls.background_color) - # copy orignial image and flip the orientation - reflection = image.copy().transpose(Image.FLIP_TOP_BOTTOM) - # create a new image filled with the bgcolor the same size - background = Image.new("RGB", image.size, background_color) - # calculate our alpha mask - start = int(255 - (255 * cls.opacity)) # The start of our gradient - steps = int(255 * cls.size) # the number of intermedite values - increment = (255 - start) / float(steps) - mask = Image.new('L', (1, 255)) - for y in range(255): - if y < steps: - val = int(y * increment + start) - else: - val = 255 - mask.putpixel((0, y), val) - alpha_mask = mask.resize(image.size) - # merge the reflection onto our background color using the alpha mask - reflection = Image.composite(background, reflection, alpha_mask) - # crop the reflection - reflection_height = int(image.size[1] * cls.size) - reflection = reflection.crop((0, 0, image.size[0], reflection_height)) - # create new image sized to hold both the original image and the reflection - composite = Image.new("RGB", (image.size[0], image.size[1]+reflection_height), background_color) - # paste the orignal image and the reflection into the composite image - composite.paste(image, (0, 0)) - composite.paste(reflection, (0, image.size[1])) - # return the image complete with reflection effect - return composite - - -class Resize(ImageProcessor): - width = None - height = None - crop = False - upscale = False - - @classmethod - def process(cls, image, obj=None): - cur_width, cur_height = image.size - if cls.crop: - crop_horz = getattr(obj, obj._ik.crop_horz_field, 1) - crop_vert = getattr(obj, obj._ik.crop_vert_field, 1) - ratio = max(float(cls.width)/cur_width, float(cls.height)/cur_height) - resize_x, resize_y = ((cur_width * ratio), (cur_height * ratio)) - crop_x, crop_y = (abs(cls.width - resize_x), abs(cls.height - resize_y)) - x_diff, y_diff = (int(crop_x / 2), int(crop_y / 2)) - box_left, box_right = { - 0: (0, cls.width), - 1: (int(x_diff), int(x_diff + cls.width)), - 2: (int(crop_x), int(resize_x)), - }[crop_horz] - box_upper, box_lower = { - 0: (0, cls.height), - 1: (int(y_diff), int(y_diff + cls.height)), - 2: (int(crop_y), int(resize_y)), - }[crop_vert] - box = (box_left, box_upper, box_right, box_lower) - image = image.resize((int(resize_x), int(resize_y)), Image.ANTIALIAS).crop(box) - else: - if not cls.width is None and not cls.height is None: - ratio = min(float(cls.width)/cur_width, - float(cls.height)/cur_height) - else: - if cls.width is None: - ratio = float(cls.height)/cur_height - else: - ratio = float(cls.width)/cur_width - new_dimensions = (int(round(cur_width*ratio)), - int(round(cur_height*ratio))) - if new_dimensions[0] > cur_width or \ - new_dimensions[1] > cur_height: - if not cls.upscale: - return image - image = image.resize(new_dimensions, Image.ANTIALIAS) - return image - - -class Transpose(ImageProcessor): - """ Rotates or flips the image - - Method should be one of the following strings: - - FLIP_LEFT RIGHT - - FLIP_TOP_BOTTOM - - ROTATE_90 - - ROTATE_270 - - ROTATE_180 - - """ - method = 'FLIP_LEFT_RIGHT' - - @classmethod - def process(cls, image, obj=None): - return image.transpose(getattr(Image, cls.method)) diff --git a/imagekit/specs.py b/imagekit/specs.py deleted file mode 100644 index a6832ba..0000000 --- a/imagekit/specs.py +++ /dev/null @@ -1,119 +0,0 @@ -""" ImageKit image specifications - -All imagekit specifications must inherit from the ImageSpec class. Models -inheriting from ImageModel will be modified with a descriptor/accessor for each -spec found. - -""" -import os -from StringIO import StringIO -from imagekit.lib import * -from imagekit.utils import img_to_fobj -from django.core.files.base import ContentFile - -class ImageSpec(object): - pre_cache = False - quality = 70 - increment_count = False - processors = [] - - @classmethod - def name(cls): - return getattr(cls, 'access_as', cls.__name__.lower()) - - @classmethod - def process(cls, image, obj): - processed_image = image.copy() - for proc in cls.processors: - processed_image = proc.process(processed_image, obj) - return processed_image - - -class Accessor(object): - def __init__(self, obj, spec): - self._img = None - self._obj = obj - self.spec = spec - - def _get_imgfile(self): - format = self._img.format or 'JPEG' - if format != 'JPEG': - imgfile = img_to_fobj(self._img, format) - else: - imgfile = img_to_fobj(self._img, format, - quality=int(self.spec.quality), - optimize=True) - return imgfile - - def _create(self): - if self._exists(): - return - # process the original image file - fp = self._obj._imgfield.storage.open(self._obj._imgfield.name) - fp.seek(0) - fp = StringIO(fp.read()) - try: - self._img = self.spec.process(Image.open(fp), self._obj) - # save the new image to the cache - content = ContentFile(self._get_imgfile().read()) - self._obj._imgfield.storage.save(self.name, content) - except IOError: - pass - - def _delete(self): - self._obj._imgfield.storage.delete(self.name) - - def _exists(self): - return self._obj._imgfield.storage.exists(self.name) - - def _basename(self): - filename, extension = \ - os.path.splitext(os.path.basename(self._obj._imgfield.name)) - return self._obj._ik.cache_filename_format % \ - {'filename': filename, - 'specname': self.spec.name(), - 'extension': extension.lstrip('.')} - - @property - def name(self): - return os.path.join(self._obj._ik.cache_dir, self._basename()) - - @property - def url(self): - self._create() - if self.spec.increment_count: - fieldname = self._obj._ik.save_count_as - if fieldname is not None: - current_count = getattr(self._obj, fieldname) - setattr(self._obj, fieldname, current_count + 1) - self._obj.save(clear_cache=False) - return self._obj._imgfield.storage.url(self.name) - - @property - def file(self): - self._create() - return self._obj._imgfield.storage.open(self.name) - - @property - def image(self): - if self._img is None: - self._create() - if self._img is None: - self._img = Image.open(self.file) - return self._img - - @property - def width(self): - return self.image.size[0] - - @property - def height(self): - return self.image.size[1] - - -class Descriptor(object): - def __init__(self, spec): - self._spec = spec - - def __get__(self, obj, type=None): - return Accessor(obj, self._spec) diff --git a/imagekit/tests.py b/imagekit/tests.py deleted file mode 100644 index 8c2eb5e..0000000 --- a/imagekit/tests.py +++ /dev/null @@ -1,86 +0,0 @@ -import os -import tempfile -import unittest -from django.conf import settings -from django.core.files.base import ContentFile -from django.db import models -from django.test import TestCase - -from imagekit import processors -from imagekit.models import ImageModel -from imagekit.specs import ImageSpec -from imagekit.lib import Image - - -class ResizeToWidth(processors.Resize): - width = 100 - -class ResizeToHeight(processors.Resize): - height = 100 - -class ResizeToFit(processors.Resize): - width = 100 - height = 100 - -class ResizeCropped(ResizeToFit): - crop = ('center', 'center') - -class TestResizeToWidth(ImageSpec): - access_as = 'to_width' - processors = [ResizeToWidth] - -class TestResizeToHeight(ImageSpec): - access_as = 'to_height' - processors = [ResizeToHeight] - -class TestResizeCropped(ImageSpec): - access_as = 'cropped' - processors = [ResizeCropped] - -class TestPhoto(ImageModel): - """ Minimal ImageModel class for testing """ - image = models.ImageField(upload_to='images') - - class IKOptions: - spec_module = 'imagekit.tests' - - -class IKTest(TestCase): - """ Base TestCase class """ - def setUp(self): - # create a test image using tempfile and PIL - self.tmp = tempfile.TemporaryFile() - Image.new('RGB', (800, 600)).save(self.tmp, 'JPEG') - self.tmp.seek(0) - self.p = TestPhoto() - self.p.image.save(os.path.basename('test.jpg'), - ContentFile(self.tmp.read())) - self.p.save() - # destroy temp file - self.tmp.close() - - def test_setup(self): - self.assertEqual(self.p.image.width, 800) - self.assertEqual(self.p.image.height, 600) - - def test_to_width(self): - self.assertEqual(self.p.to_width.width, 100) - self.assertEqual(self.p.to_width.height, 75) - - def test_to_height(self): - self.assertEqual(self.p.to_height.width, 133) - self.assertEqual(self.p.to_height.height, 100) - - def test_crop(self): - self.assertEqual(self.p.cropped.width, 100) - self.assertEqual(self.p.cropped.height, 100) - - def test_url(self): - tup = (settings.MEDIA_URL, self.p._ik.cache_dir, 'test_to_width.jpg') - self.assertEqual(self.p.to_width.url, "%s%s/%s" % tup) - - def tearDown(self): - # make sure image file is deleted - path = self.p.image.path - self.p.delete() - self.failIf(os.path.isfile(path)) diff --git a/imagekit/utils.py b/imagekit/utils.py deleted file mode 100644 index 352d40f..0000000 --- a/imagekit/utils.py +++ /dev/null @@ -1,15 +0,0 @@ -""" ImageKit utility functions """ - -import tempfile - -def img_to_fobj(img, format, **kwargs): - tmp = tempfile.TemporaryFile() - if format != 'JPEG': - try: - img.save(tmp, format, **kwargs) - return - except KeyError: - pass - img.save(tmp, format, **kwargs) - tmp.seek(0) - return tmp diff --git a/settings.py b/settings.py index 3c3b8d2..2cfe7e7 100644 --- a/settings.py +++ b/settings.py @@ -92,7 +92,7 @@ INSTALLED_APPS = ( 'troggle.profiles', 'troggle.core', 'troggle.flatpages', - 'troggle.imagekit', + 'imagekit', ) MIDDLEWARE_CLASSES = (