def render(self, context): image = self.image.resolve(context) adj_instances = [] for adj_to_resolve, kwargs_to_resolve in self.adjustments: adj = adj_to_resolve.resolve(context) kwargs = dict((k, v.resolve(context)) for k, v in six.iteritems(kwargs_to_resolve)) try: adj_cls = registry[adj] adj_instances.append(adj_cls(**kwargs)) except (KeyError, ValueError): if settings.TEMPLATE_DEBUG: raise if self.asvar is not None: context[self.asvar] = AdjustmentInfoDict() return '' helper = AdjustmentHelper([image], adj_instances) info_dict = helper.info_dicts()[0][1] if self.asvar is not None: context[self.asvar] = info_dict return '' return escape(info_dict.get('url', ''))
def setUp(self): super(BrokenImageAdjustmentHelperTestCase, self).setUp() self.broken_file = self._data_file('broken.png', 'rb') self.storage_path = default_storage.save( 'daguerre/test/broken.png', ContentFile(self.broken_file.read())) self.helper = AdjustmentHelper([self.storage_path], generate=True)
def render(self, context): iterable = self.iterable.resolve(context) adj_list = [] for adj, kwargs in self.adjustments: adj_list.append((adj.resolve(context), dict((k, v.resolve(context)) for k, v in six.iteritems(kwargs)))) # First adjustment *might* be a lookup. # We consider it a lookup if it is not an adjustment name. if adj_list and adj_list[0][0] in registry: lookup = None else: lookup = adj_list[0][0] adj_list = adj_list[1:] helper = AdjustmentHelper(iterable, lookup=lookup, generate=False) for adj, kwargs in adj_list: try: helper.adjust(adj, **kwargs) except (KeyError, ValueError): if settings.TEMPLATE_DEBUG: raise context[self.asvar] = [] return '' context[self.asvar] = helper return ''
def test_adjust_crop__100x50(self): expected = Image.open(self._data_path('100x50_crop.png')) with self.assertNumQueries(4): helper = AdjustmentHelper([self.base_image], generate=True) helper.adjust('crop', width=100, height=50) helper._finalize() adjusted = AdjustedImage.objects.get() self.assertImageEqual(Image.open(adjusted.adjusted.path), expected)
def test_path(self): # Tag should accept a path as its argument. storage_path = self.create_image('100x100.png') helper = AdjustmentHelper([storage_path], [Fit(width=50, height=50)]) t = Template("{% load daguerre %}{% adjust image 'fit' width=50 " "height=50 %}") c = Context({'image': storage_path}) self.assertEqual(t.render(c), escape(helper.info_dicts()[0][1]['url']))
def test_multiple(self): # Tag should allow multiple adjustments to be passed in. storage_path = self.create_image('100x100.png') helper = AdjustmentHelper([storage_path], [Crop(width=50, height=50), Fit(width=25)]) t = Template("{% load daguerre %}{% adjust image 'crop' width=50 " "height=50 'fit' width=25 %}") c = Context({'image': storage_path}) self.assertEqual(t.render(c), escape(helper.info_dicts()[0][1]['url']))
def test_no_lookups(self): # Tag should accept an iterable of paths. paths = [self.create_image('100x100.png')] helper = AdjustmentHelper(paths, generate=False) helper.adjust('fit', width=50, height=50) t = Template("{% load daguerre %}{% adjust_bulk paths 'fit' " "width=50 height=50 as bulk %}{{ bulk.0.1 }}") c = Context({'paths': paths}) self.assertEqual(t.render(c), escape(helper[0][1]['url']))
def test_path(self): # Tag should accept a path as its argument. storage_path = self.create_image('100x100.png') helper = AdjustmentHelper([storage_path], generate=False) helper.adjust('fit', width=50, height=50) t = Template("{% load daguerre %}{% adjust image 'fit' width=50 " "height=50 %}") c = Context({'image': storage_path}) self.assertEqual(t.render(c), escape(helper[0][1]['url']))
def test_file(self): # Tag should accept an :class:`ImageFieldFile` as its argument. storage_path = self.create_image('100x100.png') adjusted = AdjustedImage() adjusted.adjusted = storage_path helper = AdjustmentHelper([storage_path], [Fit(width=50, height=50)]) t = Template("{% load daguerre %}{% adjust image 'fit' width=50 " "height=50 as adj %}{{ adj }}") c = Context({'image': adjusted.adjusted}) self.assertEqual(t.render(c), escape(helper.info_dicts()[0][1]['url']))
def test_adjust_crop__50x50_area(self): self.create_area(storage_path=self.base_image, x1=21, x2=70, y1=46, y2=95) expected = Image.open(self._data_path('50x50_crop_area.png')) with self.assertNumQueries(4): helper = AdjustmentHelper([self.base_image], generate=True) helper.adjust('crop', width=50, height=50) helper._finalize() adjusted = AdjustedImage.objects.get() self.assertImageEqual(Image.open(adjusted.adjusted.path), expected)
def test_lookup__invalid(self): storage_path = 'path/to/somewhe.re' iterable = [ BulkTestObject({'_bar': storage_path}) ] helper = AdjustmentHelper(iterable, lookup="storage_path._bar") helper.adjust('fit', width=50, height=50) helper._finalize() self.assertEqual(helper.adjusted, {iterable[0]: {}}) self.assertEqual(helper.remaining, {})
def test_adjust_crop__50x100(self): expected = Image.open(self._data_path('50x100_crop.png')) with self.assertNumQueries(4): helper = AdjustmentHelper([self.base_image], generate=True) helper.adjust('crop', width=50, height=100) helper._finalize() adjusted = AdjustedImage.objects.get() self.assertImageEqual(Image.open(adjusted.adjusted.path), expected) # Make sure that the path is properly formatted. self.assertTrue(adjusted.adjusted.path.endswith('.png'))
def test_unprepped(self): image = self.create_image('100x100.png') with self.assertNumQueries(1): helper = AdjustmentHelper([image], generate=False) helper.adjust('crop', width=50, height=50) info_dict = helper[0][1] with self.assertNumQueries(4): response = self.client.get(info_dict['url']) self.assertEqual(response.status_code, 302)
def test_paths(self): # Tag should accept an iterable of objects with paths. objs = [BulkTestObject(self.create_image('100x100.png'))] helper = AdjustmentHelper(objs, lookup='storage_path', generate=False) helper.adjust('fit', width=50, height=50) t = Template("{% load daguerre %}{% adjust_bulk objs 'storage_path' " "'fit' width=50 height=50 as bulk %}" "{{ bulk.0.1 }}") c = Context({'objs': objs}) self.assertEqual(t.render(c), escape(helper[0][1]['url']))
def test_nonexistant(self): """ A 404 should be raised if the original image doesn't exist. """ factory = RequestFactory() storage_path = 'nonexistant.png' helper = AdjustmentHelper([storage_path], [Fill(width=10, height=10)]) self.view.kwargs = {'storage_path': storage_path} self.view.request = factory.get('/', helper.to_querydict(secure=True)) self.assertRaises(Http404, self.view.get, self.view.request)
def test_file(self): # Tag should accept an :class:`ImageFieldFile` as its argument. storage_path = self.create_image('100x100.png') adjusted = AdjustedImage() adjusted.adjusted = storage_path helper = AdjustmentHelper([storage_path], generate=False) helper.adjust('fit', width=50, height=50) t = Template("{% load daguerre %}{% adjust image 'fit' width=50 " "height=50 as adj %}{{ adj }}") c = Context({'image': adjusted.adjusted}) self.assertEqual(t.render(c), escape(helper[0][1]['url']))
def test_no_lookups(self): # Tag should accept an iterable of paths. paths = [ self.create_image('100x100.png') ] helper = AdjustmentHelper(paths, generate=False) helper.adjust('fit', width=50, height=50) t = Template("{% load daguerre %}{% adjust_bulk paths 'fit' " "width=50 height=50 as bulk %}{{ bulk.0.1 }}") c = Context({'paths': paths}) self.assertEqual(t.render(c), escape(helper[0][1]['url']))
def test_nonexistant(self): """ A 404 should be raised if the original image doesn't exist. """ factory = RequestFactory() storage_path = 'nonexistant.png' helper = AdjustmentHelper([storage_path]) helper.adjust('fill', width=10, height=10) self.view.kwargs = {'storage_path': storage_path} self.view.request = factory.get('/', helper.to_querydict(secure=True)) self.assertRaises(Http404, self.view.get, self.view.request)
def test_info_dicts__semiprepped(self): images = [ self.create_image('100x100.png'), self.create_image('100x100.png'), self.create_image('100x50_crop.png'), self.create_image('50x100_crop.png'), ] iterable = [BulkTestObject(image) for image in images] helper = AdjustmentHelper(iterable, lookup='storage_path', generate=False) helper.adjust('crop', width=50, height=50) with self.assertNumQueries(1): helper._finalize()
def test_preprepped(self): image = self.create_image('100x100.png') crop = Crop(width=50, height=50) helper = AdjustmentHelper([image], generate=True).adjust(crop) with self.assertNumQueries(4): adjusted = helper[0][1] with self.assertNumQueries(1): info_dict = AdjustmentHelper([image], generate=False).adjust(crop)[0][1] self.assertEqual(info_dict['url'], adjusted['url'])
def test_paths(self): # Tag should accept an iterable of objects with paths. objs = [ BulkTestObject(self.create_image('100x100.png')) ] helper = AdjustmentHelper(objs, lookup='storage_path', generate=False) helper.adjust('fit', width=50, height=50) t = Template("{% load daguerre %}{% adjust_bulk objs 'storage_path' " "'fit' width=50 height=50 as bulk %}" "{{ bulk.0.1 }}") c = Context({'objs': objs}) self.assertEqual(t.render(c), escape(helper[0][1]['url']))
def test_nonexistant(self): """ A 404 should be raised if the original image doesn't exist. """ factory = RequestFactory() storage_path = 'nonexistant.png' helper = AdjustmentHelper([storage_path], [Fill(width=10, height=5)]) self.view.kwargs = {'storage_path': storage_path} get_params = helper.to_querydict() self.view.request = factory.get('/', get_params, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertRaises(Http404, self.view.get, self.view.request)
def test_info_dicts__non_bulk(self): images = [ self.create_image('100x100.png'), self.create_image('100x100.png'), self.create_image('100x50_crop.png'), self.create_image('50x100_crop.png'), ] adj = Crop(width=50, height=50) with self.assertNumQueries(4): for image in images: helper = AdjustmentHelper([image], generate=False) helper.adjust(adj) helper._finalize()
def test_adjust__broken(self): broken_file = self._data_file('broken.png', 'rb') storage_path = default_storage.save('daguerre/test/broken.png', ContentFile(broken_file.read())) broken_file = default_storage.open(storage_path, 'rb') image = Image.open(broken_file) self.assertRaises(IndexError, image.verify) helper = AdjustmentHelper([storage_path], generate=True) helper.adjust('fill', width=50, height=50) with self.assertNumQueries(1): helper._finalize() self.assertEqual(helper.adjusted, {helper.iterable[0]: {}}) self.assertEqual(helper.remaining, {})
def test_info_dicts__semiprepped(self): images = [ self.create_image('100x100.png'), self.create_image('100x100.png'), self.create_image('100x50_crop.png'), self.create_image('50x100_crop.png'), ] iterable = [BulkTestObject(image) for image in images] adj = Crop(width=50, height=50) helper = AdjustmentHelper(iterable, [adj], 'storage_path') with self.assertNumQueries(1): helper.info_dicts()
def test_nonexistant(self): """ A 404 should be raised if the original image doesn't exist. """ factory = RequestFactory() storage_path = 'nonexistant.png' helper = AdjustmentHelper([storage_path]) helper.adjust('fill', width=10, height=5) self.view.kwargs = {'storage_path': storage_path} get_params = helper.to_querydict() self.view.request = factory.get('/', get_params, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertRaises(Http404, self.view.get, self.view.request)
def test_multiple(self): # Tag should accept multiple adjustments. objs = [ BulkTestObject(self.create_image('100x100.png')) ] helper = AdjustmentHelper(objs, [Crop(width=50, height=50), Fit(width=25)], 'storage_path') t = Template("{% load daguerre %}{% adjust_bulk objs 'storage_path' " "'crop' width=50 height=50 'fit' width=25 as bulk %}" "{{ bulk.0.1 }}") c = Context({'objs': objs}) self.assertEqual(t.render(c), escape(helper.info_dicts()[0][1]['url']))
def test_deserialize(self): requested = 'fit|25|50>crop|25|' fit, crop = AdjustmentHelper._deserialize_requested(requested) self.assertIsInstance(fit, Fit) self.assertEqual(fit.kwargs, {'width': '25', 'height': '50'}) self.assertIsInstance(crop, Crop) self.assertEqual(crop.kwargs, {'width': '25', 'height': None})
def test_adjust__nonexistant(self): """ Adjusting a path that doesn't exist should raise an IOError. """ storage_path = 'nonexistant.png' self.assertFalse(default_storage.exists(storage_path)) helper = AdjustmentHelper([storage_path], [Fit(width=50, height=50)]) # We still do get one query because the first try is always for # an AdjustedImage, whether or not the original file exists. # This is for historic reasons and doesn't necessarily need to # continue to be the case. with self.assertNumQueries(1): helper.adjust() self.assertEqual(helper.adjusted, {helper.iterable[0]: {}}) self.assertEqual(helper.remaining, {})
def get_helper(self): try: return AdjustmentHelper.from_querydict( self.kwargs['storage_path'], self.request.GET, secure=self.secure) except ValueError as e: raise Http404(six.text_type(e))
def get_helper(self, generate=False): try: return AdjustmentHelper.from_querydict( self.kwargs['storage_path'], self.request.GET, secure=self.secure, generate=generate) except ValueError as e: raise Http404(six.text_type(e))
def test_readjust(self): """ Adjusting a previously-adjusted image should return the previous adjustment. """ new_im = Image.open(self._data_path('50x100_crop.png')) with self.assertNumQueries(4): helper = AdjustmentHelper([self.base_image], generate=True) helper.adjust('crop', width=50, height=100) helper._finalize() adjusted = AdjustedImage.objects.get() self.assertImageEqual(Image.open(adjusted.adjusted.path), new_im) with self.assertNumQueries(1): helper = AdjustmentHelper([self.base_image], generate=True) helper.adjust('crop', width=50, height=100) helper._finalize() self.assertEqual(AdjustedImage.objects.count(), 1)
def _bulk_adjusted_items(self, items): if self.feed_type is JSONGenerator: sizes = THUMBNAIL_SIZES else: sizes = THUMBNAIL_SIZES[:2] for size in sizes: helper = AdjustmentHelper(items, [Fill(width=size[0], height=size[1])], "thumbnail") for item, info_dict in helper.info_dicts(): # Set a private attribute so we can retrieve this later. if not hasattr(item, '_adjusted'): item._adjusted = {} item._adjusted[size] = info_dict # set the default adjustment as a public attribute so that it # can be accessed from the description template. for item in items: item.description_thumbnail = item._adjusted[THUMBNAIL_SIZES[1]] return items
def _get_helpers(self): if not hasattr(settings, 'DAGUERRE_PREADJUSTMENTS'): raise CommandError(NO_ADJUSTMENTS) dp = settings.DAGUERRE_PREADJUSTMENTS helpers = [] try: for (model_or_iterable, adjustments, lookup) in dp: if isinstance(model_or_iterable, six.string_types): app_label, model_name = model_or_iterable.split('.') model_or_iterable = get_model(app_label, model_name) if (isinstance(model_or_iterable, six.class_types) and issubclass(model_or_iterable, Model)): iterable = model_or_iterable.objects.all() elif isinstance(model_or_iterable, QuerySet): iterable = model_or_iterable._clone() else: iterable = model_or_iterable helper = AdjustmentHelper(iterable, lookup=lookup, generate=True) for adjustment in adjustments: helper.adjust(adjustment) helper._finalize() helpers.append(helper) except (ValueError, TypeError, LookupError): raise CommandError(BAD_STRUCTURE) return helpers
def test_check_security(self): """ A 404 should be raised if the security hash is missing or incorrect. """ storage_path = 'path/to/thing.jpg' adj1 = NamedCrop(name='face') adj2 = Fill(width=10, height=5) helper = AdjustmentHelper([storage_path], [adj1, adj2]) factory = RequestFactory() self.view.kwargs = {'storage_path': storage_path} get_params = {} self.view.request = factory.get('/', get_params) self.assertRaises(Http404, self.view.get_helper) get_params = {AdjustmentHelper.query_map['security']: 'fake!'} self.view.request = factory.get('/', get_params) self.assertRaises(Http404, self.view.get_helper) get_params = helper.to_querydict(secure=True) self.view.request = factory.get('/', get_params)
def test_named_crop(self): self.create_area(storage_path=self.base_image, x1=21, x2=70, y1=46, y2=95, name='area') expected = Image.open(self._data_path('25x25_fit_named_crop.png')) with self.assertNumQueries(4): helper = AdjustmentHelper([self.base_image], generate=True) helper.adjust('namedcrop', name='area') helper.adjust('fit', width=25, height=25) helper._finalize() adjusted = AdjustedImage.objects.get() self.assertImageEqual(Image.open(adjusted.adjusted.path), expected)
def test_lookup__invalid(self): storage_path = 'path/to/somewhe.re' iterable = [BulkTestObject({'_bar': storage_path})] helper = AdjustmentHelper(iterable, lookup="storage_path._bar") helper.adjust('fit', width=50, height=50) helper._finalize() self.assertEqual(helper.adjusted, {iterable[0]: {}}) self.assertEqual(helper.remaining, {})
def test_readjust_multiple(self): """ If there are multiple adjusted versions of the image with the same parameters, one of them should be returned rather than erroring out. """ with self.assertNumQueries(4): helper = AdjustmentHelper([self.base_image], generate=True) helper.adjust('crop', width=50, height=100) helper._finalize() adjusted1 = AdjustedImage.objects.get() adjusted2 = AdjustedImage.objects.get() adjusted2.pk = None adjusted2.save() self.assertNotEqual(adjusted1.pk, adjusted2.pk) helper = AdjustmentHelper([self.base_image]) helper.adjust('crop', width=50, height=100) with self.assertNumQueries(1): helper._finalize() url = list(helper.adjusted.values())[0]['url'] self.assertEqual(url, adjusted1.adjusted.url) self.assertEqual(url, adjusted2.adjusted.url)
def render(self, context): video = self.video.resolve(context) # Backwards-compat: livesearch should just use the thumbnail_url. if getattr(video, '_livesearch', False): info_dict = AdjustmentInfoDict({ 'width': self.width, 'height': self.height, 'url': video.thumbnail_url }) else: storage_path = None if video.has_thumbnail: storage_path = video.thumbnail_path elif video.feed_id and video.feed.has_thumbnail: storage_path = video.feed.thumbnail_path elif video.search_id and video.search.has_thumbnail: storage_path = video.search.thumbnail_path helper = AdjustmentHelper([storage_path], [Fill(width=self.width, height=self.height)]) info_dict = helper.info_dicts()[0][1] # localtv_thumbnail has always fallen back in the code. if not info_dict: info_dict = AdjustmentInfoDict({ 'width': self.width, 'height': self.height, 'url': staticfiles_storage.url('localtv/images/default_vid.gif') }) if self.asvar is not None: context[self.asvar] = info_dict return '' return info_dict
def render(self, context): image = self.image.resolve(context) helper = AdjustmentHelper([image], generate=False) for adj_to_resolve, kwargs_to_resolve in self.adjustments: adj = adj_to_resolve.resolve(context) kwargs = dict((k, v.resolve(context)) for k, v in six.iteritems(kwargs_to_resolve)) try: helper.adjust(adj, **kwargs) except (KeyError, ValueError): if settings.TEMPLATE_DEBUG: raise if self.asvar is not None: context[self.asvar] = AdjustmentInfoDict() return '' info_dict = helper[0][1] if self.asvar is not None: context[self.asvar] = info_dict return '' return escape(info_dict.get('url', ''))
def test_multiple(self): # Tag should allow multiple adjustments to be passed in. storage_path = self.create_image('100x100.png') helper = AdjustmentHelper([storage_path]) helper.adjust('crop', width=50, height=50) helper.adjust('fit', width=25) t = Template("{% load daguerre %}{% adjust image 'crop' width=50 " "height=50 'fit' width=25 %}") c = Context({'image': storage_path}) self.assertEqual(t.render(c), escape(helper[0][1]['url']))
def test_adjust__nonexistant(self): """ Adjusting a path that doesn't exist should raise an IOError. """ storage_path = 'nonexistant.png' self.assertFalse(default_storage.exists(storage_path)) helper = AdjustmentHelper([storage_path], generate=True) helper.adjust('fit', width=50, height=50) # We still do get one query because the first try is always for # an AdjustedImage, whether or not the original file exists. # This is for historic reasons and doesn't necessarily need to # continue to be the case. with self.assertNumQueries(1): helper._finalize() self.assertEqual(helper.adjusted, {helper.iterable[0]: {}}) self.assertEqual(helper.remaining, {})
def test_check_security(self): """ A 404 should be raised if the security hash is missing or incorrect. """ storage_path = 'path/to/thing.jpg' helper = AdjustmentHelper([storage_path]) helper.adjust('namedcrop', name='face') helper.adjust('fill', width=10, height=5) factory = RequestFactory() self.view.kwargs = {'storage_path': storage_path} get_params = {} self.view.request = factory.get('/', get_params) self.assertRaises(Http404, self.view.get_helper) get_params = {AdjustmentHelper.query_map['security']: 'fake!'} self.view.request = factory.get('/', get_params) self.assertRaises(Http404, self.view.get_helper) get_params = helper.to_querydict(secure=True) self.view.request = factory.get('/', get_params)
def test_serialize(self): adjustments = [Fit(width=25, height=50), Crop(width=25)] requested = AdjustmentHelper._serialize_requested(adjustments) self.assertEqual(requested, 'fit|25|50>crop|25|')
def test_make_security_hash(self): kwargs = {'requested': 'fill|10|10||'} security_hash = AdjustmentHelper.make_security_hash(kwargs) self.assertEqual(security_hash, 'd520a2f75d029b2da727')
class BrokenImageAdjustmentHelperTestCase(BaseTestCase): def setUp(self): super(BrokenImageAdjustmentHelperTestCase, self).setUp() self.broken_file = self._data_file('broken.png', 'rb') self.storage_path = default_storage.save( 'daguerre/test/broken.png', ContentFile(self.broken_file.read())) self.helper = AdjustmentHelper([self.storage_path], generate=True) def test_adjust__broken(self): self.helper.adjust('fill', width=50, height=50) with self.assertNumQueries(1): self.helper._finalize() self.assertEqual(self.helper.adjusted, {self.helper.iterable[0]: {}}) self.assertEqual(self.helper.remaining, {}) @mock.patch('daguerre.helpers.Image') def test_adjust__broken_with_struct_error(self, image_mock): bad_image = image_mock.open.return_value bad_image.verify.side_effect = struct.error self.helper.adjust('fill', width=50, height=50) with self.assertNumQueries(1): self.helper._finalize() self.assertEqual(self.helper.adjusted, {self.helper.iterable[0]: {}}) self.assertEqual(self.helper.remaining, {}) @mock.patch('daguerre.helpers.Image') def test_adjust__broken_with_indexerror_error(self, image_mock): bad_image = image_mock.open.return_value bad_image.verify.side_effect = IndexError('index out of range') self.helper.adjust('fill', width=50, height=50) with self.assertNumQueries(1): self.helper._finalize() self.assertEqual(self.helper.adjusted, {self.helper.iterable[0]: {}}) self.assertEqual(self.helper.remaining, {}) @mock.patch('daguerre.helpers.Image') def test_adjust__broken_with_io_error(self, image_mock): bad_image = image_mock.open.return_value bad_image.verify.side_effect = IOError('truncated png file') self.helper.adjust('fill', width=50, height=50) with self.assertNumQueries(1): self.helper._finalize() self.assertEqual(self.helper.adjusted, {self.helper.iterable[0]: {}}) self.assertEqual(self.helper.remaining, {}) @mock.patch('daguerre.helpers.Image') def test_adjust__broken_with_syntax_error(self, image_mock): bad_image = image_mock.open.return_value bad_image.verify.side_effect = SyntaxError('broken png file') self.helper.adjust('fill', width=50, height=50) with self.assertNumQueries(1): self.helper._finalize() self.assertEqual(self.helper.adjusted, {self.helper.iterable[0]: {}}) self.assertEqual(self.helper.remaining, {})
def test_check_security_hash(self): kwargs = {'requested': 'crop|50|50'} security_hash = AdjustmentHelper.make_security_hash(kwargs) self.assertTrue( AdjustmentHelper.check_security_hash(security_hash, kwargs))