<commit_before>import logging
from PIL import Image
from datetime import datetime
from os import path
from cStringIO import StringIO
import os.path

from django.db import models, IntegrityError
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import force_unicode, smart_str
from django.contrib.sites.models import Site
from django.core.files.base import ContentFile
from django.conf import settings
from django.template.defaultfilters import slugify

from jsonfield.fields import JSONField

from ella.core.models.main import Author, Source
from ella.core.box import Box
from ella.core.cache.utils import get_cached_object
from ella.photos.conf import photos_settings

from formatter import Formatter

__all__ = ("Format", "FormatedPhoto", "Photo")

log = logging.getLogger('ella.photos')

redis = None
REDIS_PHOTO_KEY = 'photo:%d'
REDIS_FORMATTED_PHOTO_KEY = 'photo:%d:%d'

if hasattr(settings, 'PHOTOS_REDIS'):
    try:
        from redis import Redis
    except:
        log.error('Redis support requested but Redis client not installed.')
        redis = None
    else:
        redis = Redis(**getattr(settings, 'PHOTOS_REDIS'))

class PhotoBox(Box):
    def get_context(self):
        "Updates box context with photo-specific variables."
        cont = super(PhotoBox, self).get_context()
        cont.update({
                'title' : self.params.get('title', self.obj.title),
                'alt' : self.params.get('alt', ''),
                'description' : self.params.get('description', self.obj.description),
                'show_title' : self.params.get('show_title', ''),
                'show_description' : self.params.get('show_description', ''),
                'show_authors' : self.params.get('show_authors', ''),
                'show_detail' : self.params.get('show_detail', ''),
                'show_source' : self.params.get('show_source', ''), ###
                'link_url': self.params.get('link_url', ''),
            })
        return cont

def upload_to(instance, filename):
    name, ext = os.path.splitext(filename)
    if instance.slug:
        name = instance.slug
    ext = photos_settings.TYPE_EXTENSION.get(instance._get_image().format, ext.lower())

    return os.path.join(
        force_unicode(datetime.now().strftime(smart_str(photos_settings.UPLOAD_TO))),
        name + ext
    )

class Photo(models.Model):
    """
    Represents original (unformated) photo uploaded by user. Used as source
    object for all the formatting stuff and to keep the metadata common to 
    all related ``FormatedPhoto`` objects.
    """
    box_class = PhotoBox
    title = models.CharField(_('Title'), max_length=200)
    description = models.TextField(_('Description'), blank=True)
    slug = models.SlugField(_('Slug'), max_length=255)
    # save it to YYYY/MM/DD structure
    image = models.ImageField(_('Image'), upload_to=upload_to,
        height_field='height', width_field='width')
    width = models.PositiveIntegerField(editable=False)
    height = models.PositiveIntegerField(editable=False)

    # important area
    important_top = models.PositiveIntegerField(null=True, blank=True)
    important_left = models.PositiveIntegerField(null=True, blank=True)
    important_bottom = models.PositiveIntegerField(null=True, blank=True)
    important_right = models.PositiveIntegerField(null=True, blank=True)

    # Authors and Sources
    authors = models.ManyToManyField(Author, verbose_name=_('Authors') , related_name='photo_set')
    source = models.ForeignKey(Source, blank=True, null=True, verbose_name=_('Source'))

    created = models.DateTimeField(auto_now_add=True)

    # generic JSON field to store app cpecific data
    app_data = JSONField(default='{}', blank=True, editable=False)

    class Meta:
        verbose_name = _('Photo')
        verbose_name_plural = _('Photos')

    def __unicode__(self):
        return self.title

    def get_absolute_url(self):
        return self.image.url

    def get_image_info(self):
        return {
            'url': self.image.url,
            'width': self.width,
            'height': self.height,
        }

    def _get_image(self):
        if not hasattr(self, '_pil_image'):
            self._pil_image = Image.open(self.image)
        return self._pil_image

    def save(self, **kwargs):
        """Overrides models.Model.save.

        - Generates slug.
        - Saves image file.
        """
        if not self.width or not self.height:
            self.width, self.height = self.image.width, self.image.height

        # prefill the slug with the ID, it requires double save
        if not self.id:
            img = self.image

            # store dummy values first...
            w, h = self.width, self.height
            self.image = ''
            self.width, self.height = w, h
            self.slug = ''

            super(Photo, self).save(force_insert=True)

            # ... so that we can generate the slug
            self.slug = str(self.id) + '-' + slugify(self.title)
            # truncate slug in order to fit in an ImageField and/or paths in Redirects
            self.slug = self.slug[:64]
            # .. tha will be used in the image's upload_to function
            self.image = img
            # and the image will be saved properly
            super(Photo, self).save(force_update=True)
        else:
            old = Photo.objects.get(pk=self.pk)

            # delete formatedphotos if new image was uploaded
            if old.image != self.image:
                for f_photo in self.formatedphoto_set.all():
                    f_photo.delete()

            super(Photo, self).save(force_update=True)

        if redis:
            redis.hmset(REDIS_PHOTO_KEY % self.pk, self.get_image_info())
<commit_msg>Sometimes you want to create a Photo with a set ID<commit_after>import logging
from PIL import Image
from datetime import datetime
from os import path
from cStringIO import StringIO
import os.path

from django.db import models, IntegrityError
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import force_unicode, smart_str
from django.contrib.sites.models import Site
from django.core.files.base import ContentFile
from django.conf import settings
from django.template.defaultfilters import slugify

from jsonfield.fields import JSONField

from ella.core.models.main import Author, Source
from ella.core.box import Box
from ella.core.cache.utils import get_cached_object
from ella.photos.conf import photos_settings

from formatter import Formatter

__all__ = ("Format", "FormatedPhoto", "Photo")

log = logging.getLogger('ella.photos')

redis = None
REDIS_PHOTO_KEY = 'photo:%d'
REDIS_FORMATTED_PHOTO_KEY = 'photo:%d:%d'

if hasattr(settings, 'PHOTOS_REDIS'):
    try:
        from redis import Redis
    except:
        log.error('Redis support requested but Redis client not installed.')
        redis = None
    else:
        redis = Redis(**getattr(settings, 'PHOTOS_REDIS'))

class PhotoBox(Box):
    def get_context(self):
        "Updates box context with photo-specific variables."
        cont = super(PhotoBox, self).get_context()
        cont.update({
                'title' : self.params.get('title', self.obj.title),
                'alt' : self.params.get('alt', ''),
                'description' : self.params.get('description', self.obj.description),
                'show_title' : self.params.get('show_title', ''),
                'show_description' : self.params.get('show_description', ''),
                'show_authors' : self.params.get('show_authors', ''),
                'show_detail' : self.params.get('show_detail', ''),
                'show_source' : self.params.get('show_source', ''), ###
                'link_url': self.params.get('link_url', ''),
            })
        return cont

def upload_to(instance, filename):
    name, ext = os.path.splitext(filename)
    if instance.slug:
        name = instance.slug
    ext = photos_settings.TYPE_EXTENSION.get(instance._get_image().format, ext.lower())

    return os.path.join(
        force_unicode(datetime.now().strftime(smart_str(photos_settings.UPLOAD_TO))),
        name + ext
    )

class Photo(models.Model):
    """
    Represents original (unformated) photo uploaded by user. Used as source
    object for all the formatting stuff and to keep the metadata common to 
    all related ``FormatedPhoto`` objects.
    """
    box_class = PhotoBox
    title = models.CharField(_('Title'), max_length=200)
    description = models.TextField(_('Description'), blank=True)
    slug = models.SlugField(_('Slug'), max_length=255)
    # save it to YYYY/MM/DD structure
    image = models.ImageField(_('Image'), upload_to=upload_to,
        height_field='height', width_field='width')
    width = models.PositiveIntegerField(editable=False)
    height = models.PositiveIntegerField(editable=False)

    # important area
    important_top = models.PositiveIntegerField(null=True, blank=True)
    important_left = models.PositiveIntegerField(null=True, blank=True)
    important_bottom = models.PositiveIntegerField(null=True, blank=True)
    important_right = models.PositiveIntegerField(null=True, blank=True)

    # Authors and Sources
    authors = models.ManyToManyField(Author, verbose_name=_('Authors') , related_name='photo_set')
    source = models.ForeignKey(Source, blank=True, null=True, verbose_name=_('Source'))

    created = models.DateTimeField(auto_now_add=True)

    # generic JSON field to store app cpecific data
    app_data = JSONField(default='{}', blank=True, editable=False)

    class Meta:
        verbose_name = _('Photo')
        verbose_name_plural = _('Photos')

    def __unicode__(self):
        return self.title

    def get_absolute_url(self):
        return self.image.url

    def get_image_info(self):
        return {
            'url': self.image.url,
            'width': self.width,
            'height': self.height,
        }

    def _get_image(self):
        if not hasattr(self, '_pil_image'):
            self._pil_image = Image.open(self.image)
        return self._pil_image

    def save(self, **kwargs):
        """Overrides models.Model.save.

        - Generates slug.
        - Saves image file.
        """
        if not self.width or not self.height:
            self.width, self.height = self.image.width, self.image.height

        # prefill the slug with the ID, it requires double save
        if not self.id:
            img = self.image

            # store dummy values first...
            w, h = self.width, self.height
            self.image = ''
            self.width, self.height = w, h
            self.slug = ''

            super(Photo, self).save(force_insert=True)

            # ... so that we can generate the slug
            self.slug = str(self.id) + '-' + slugify(self.title)
            # truncate slug in order to fit in an ImageField and/or paths in Redirects
            self.slug = self.slug[:64]
            # .. tha will be used in the image's upload_to function
            self.image = img
            # and the image will be saved properly
            super(Photo, self).save(force_update=True)
        else:
            try:
                old = Photo.objects.get(pk=self.pk)

                force_update = True
                # delete formatedphotos if new image was uploaded
                if old.image != self.image:
                    for f_photo in self.formatedphoto_set.all():
                        f_photo.delete()
            except Photo.DoesNotExist:
                # somebody is just trying to create new model with given PK
                force_update = False

            super(Photo, self).save(force_update=force_update)

        if redis:
            redis.hmset(REDIS_PHOTO_KEY % self.pk, self.get_image_info())

{'fraction_non_alphanumeric': 0.10733603786342123, 'fraction_numerical': 0.001352265043948614, 'mean_word_length': 2.639803137496155, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1266458', 'n_tokens_mistral': 3506, 'n_tokens_neox': 3376, 'n_words': 854}