<commit_before>from django.core.exceptions import ValidationError
from django.core.validators import MinValueValidator
from django.db import models
from django.template.defaultfilters import capfirst
from django.utils.encoding import smart_unicode


class Area(models.Model):
	"""Represents an area of an image. Can be used to specify a crop. Also used for priority-aware automated image cropping."""
	storage_path = models.CharField(max_length=300)
	
	x1 = models.PositiveIntegerField(validators=[MinValueValidator(0)])
	y1 = models.PositiveIntegerField(validators=[MinValueValidator(0)])
	x2 = models.PositiveIntegerField(validators=[MinValueValidator(1)])
	y2 = models.PositiveIntegerField(validators=[MinValueValidator(1)])
	
	name = models.CharField(max_length=20, blank=True)
	priority = models.PositiveIntegerField(validators=[MinValueValidator(1)], default=3)
	
	@property
	def area(self):
		if self.x1 is None or self.y1 is None or self.x2 is None or self.y2 is None:
			return None
		return self.width * self.height
	
	@property
	def width(self):
		return self.x2 - self.x1
	
	@property
	def height(self):
		return self.y2 - self.y1
	
	def clean_fields(self, exclude=None):
		errors = {}
		
		if exclude is None:
			exclude = []
		
		try:
			super(Area, self).clean_fields(exclude)
		except ValidationError, e:
			errors.update(e.message_dict)

		if errors:
			raise ValidationError(errors)
	
	def clean(self):
		errors = []
		if self.x1 and self.x2 and self.x1 >= self.x2:
			errors.append("X1 must be less than X2.")
		if self.y1 and self.y2 and self.y1 >= self.y2:
			errors.append("Y1 must be less than Y2.")
		if errors:
			raise ValidationError(errors)
	
	def serialize(self):
		return dict((f.name, getattr(self, f.name))
					for f in self._meta.fields)

	def __unicode__(self):
		if self.name:
			name = self.name
		else:
			name = u"(%d, %d, %d, %d / %d)" % (self.x1, self.y1, self.x2, self.y2, self.priority)
		return u"%s for %s" % (name, self.storage_path)
	
	class Meta:
		ordering = ('priority',)


def _adjustment_choice_iter():
	# By lazily importing the adjustments dict, we can prevent an import loop.
	from daguerre.utils.adjustments import adjustments
	for slug in adjustments:
		yield (slug, capfirst(slug))


class AdjustedImage(models.Model):
	"""Represents a "cached" managed image adjustment."""
	storage_path = models.CharField(max_length=300)
	adjusted = models.ImageField(height_field='height', width_field='width', upload_to='daguerre/adjusted/%Y/%m/%d/', max_length=255)
	timestamp = models.DateTimeField(auto_now_add=True)

	width = models.PositiveIntegerField()<commit_msg>Now all adjusted images based on the same storage path are deleted when a new area is defined (for fill and crop).<commit_after>from django.core.exceptions import ValidationError
from django.core.validators import MinValueValidator
from django.db import models
from django.template.defaultfilters import capfirst
from django.utils.encoding import smart_unicode


class Area(models.Model):
	"""Represents an area of an image. Can be used to specify a crop. Also used for priority-aware automated image cropping."""
	storage_path = models.CharField(max_length=300)
	
	x1 = models.PositiveIntegerField(validators=[MinValueValidator(0)])
	y1 = models.PositiveIntegerField(validators=[MinValueValidator(0)])
	x2 = models.PositiveIntegerField(validators=[MinValueValidator(1)])
	y2 = models.PositiveIntegerField(validators=[MinValueValidator(1)])
	
	name = models.CharField(max_length=20, blank=True)
	priority = models.PositiveIntegerField(validators=[MinValueValidator(1)], default=3)
	
	@property
	def area(self):
		if self.x1 is None or self.y1 is None or self.x2 is None or self.y2 is None:
			return None
		return self.width * self.height
	
	@property
	def width(self):
		return self.x2 - self.x1
	
	@property
	def height(self):
		return self.y2 - self.y1
	
	def clean_fields(self, exclude=None):
		errors = {}
		
		if exclude is None:
			exclude = []
		
		try:
			super(Area, self).clean_fields(exclude)
		except ValidationError, e:
			errors.update(e.message_dict)

		if errors:
			raise ValidationError(errors)
	
	def clean(self):
		errors = []
		if self.x1 and self.x2 and self.x1 >= self.x2:
			errors.append("X1 must be less than X2.")
		if self.y1 and self.y2 and self.y1 >= self.y2:
			errors.append("Y1 must be less than Y2.")
		if errors:
			raise ValidationError(errors)
	
	def serialize(self):
		return dict((f.name, getattr(self, f.name))
					for f in self._meta.fields)
					
	def save(self):
		"""
		If the adjusted image uses areas (e.g., fill and crop), clear cached adjusted images.
		
		"""
		from daguerre.utils.adjustments import adjustments
		slugs = [slug for slug, adjustment in adjustments.iteritems() if adjustment.uses_areas]
		AdjustedImage.objects.filter(storage_path__exact=self.storage_path, requested_adjustment__in=slugs).delete()
		super(Area, self).save()

	def __unicode__(self):
		if self.name:
			name = self.name
		else:
			name = u"(%d, %d, %d, %d / %d)" % (self.x1, self.y1, self.x2, self.y2, self.priority)
		return u"%s for %s" % (name, self.storage_path)
	
	class Meta:
		ordering = ('priority',)


def _adjustment_choice_iter():
	# By lazily importing the adjustments dict, we can prevent an import loop.
	from daguerre.utils.adjustments import adjustments
	for slug in adjustments:
		yield (slug, capfirst(slug))


class AdjustedImage(models.Model):
	"""Represents a "cached" managed image adjustment."""
	storage_path = models.CharField(max_length=300)
	adjusted = models.ImageField(height_field='height', width_field='width', upload_to='daguerre/adjusted/%Y/%m/%d/', max_length=255)
	timestamp = models.DateTimeField(auto_now_add=True)

	width = models.PositiveIntegerField()
{'fraction_non_alphanumeric': 0.11428571428571428, 'fraction_numerical': 0.0156794425087108, 'mean_word_length': 4.600975609756097, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, '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': '4508799', 'n_tokens_mistral': 2057, 'n_tokens_neox': 1830, 'n_words': 511}