def test_missing_entry_gets_none(self): with tempfile.TemporaryDirectory() as tmp: cache = img.ImageCache(cache_root=tmp) request = img.ImageRequest('id1', 'full', 'full', '0', 'default', 'jpg') self.assertIsNone(cache.get(request))
def test_is_canonical(self, args, is_canonical): info = img_info.ImageInfo(None) info.width = 100 info.height = 100 request = img.ImageRequest(*args) assert request.is_canonical(info) == is_canonical
def test_deleting_cache_entries(self): # Because this operation is a no-op, we just check we can call the # __del__ method without an error. cache = img.ImageCache(cache_root='/tmp') request = img.ImageRequest('id1', 'full', 'full', '0', 'default', 'jpg') del cache[request]
def test_missing_entry_is_keyerror(self): cache = img.ImageCache(cache_root='/tmp') request = img.ImageRequest('id1', 'full', 'full', '0', 'default', 'jpg') with self.assertRaises(KeyError): cache[request]
def test_cache_dir_already_exists(self): ident = 'id1' image_info = img_info.ImageInfo(None) image_info.width = 100 image_info.height = 100 image_request = img.ImageRequest(ident, 'full', 'full', '0', 'default', 'jpg') image_request.info = image_info self.app.img_cache.create_dir_and_return_file_path(image_request) #call request again, so cache directory should already be there # throws an exception if we don't handle that existence properly self.app.img_cache.create_dir_and_return_file_path(image_request) def test_missing_entry_is_keyerror(self): cache = img.ImageCache(cache_root='/tmp') request = img.ImageRequest( ident='V1234.jpg', region='100,100,100,100', size='100,100', rotation='0', quality='color', target_format='jpeg' ) with self.assertRaises(KeyError): cache[request]
def test_deleting_cache_entries(self): # Because this operation is a no-op, we just check we can call the # __del__ method without an error. with tempfile.TemporaryDirectory() as tmp: cache = img.ImageCache(cache_root=tmp) request = img.ImageRequest('id1', 'full', 'full', '0', 'default', 'jpg') del cache[request]
def test_missing_entry_is_keyerror(self): with tempfile.TemporaryDirectory() as tmp: cache = img.ImageCache(cache_root=tmp) request = img.ImageRequest('id1', 'full', 'full', '0', 'default', 'jpg') with self.assertRaises(KeyError): cache[request]
def test_getitem_with_unexpected_error_is_raised(self): cache = img.ImageCache(cache_root='/tmp') request = img.ImageRequest('id', 'full', 'full', '0', 'default', 'jpg') message = "Exception thrown in img_t.py for Test_ImageCache" m = mock.Mock(side_effect=OSError(-1, message)) with mock.patch('loris.img.path.getmtime', m): with pytest.raises(OSError) as err: cache[request]
def test_cache_dir_already_exists(self): ident = 'id1' image_info = img_info.ImageInfo(None) image_info.width = 100 image_info.height = 100 image_request = img.ImageRequest(ident, 'full', 'full', '0', 'default', 'jpg') self.app.img_cache.create_dir_and_return_file_path(image_request, image_info) #call request again, so cache directory should already be there # throws an exception if we don't handle that existence properly self.app.img_cache.create_dir_and_return_file_path(image_request, image_info)
def test_is_canonical(self, args, is_canonical): info = img_info.ImageInfo(None) info.width = 100 info.height = 100 request = img.ImageRequest(*args) request.info = info # Called twice for caching behaviour assert request.is_canonical == is_canonical assert request.is_canonical == is_canonical
def test_missing_info_attribute_is_error(self): request = img.ImageRequest( ident='V1234.jpg', region='100,100,100,100', size='100,100', rotation='0', quality='color', target_format='jpeg' ) with self.assertRaises(ImageException): request.info
def test_missing_entry_is_keyerror(self): cache = img.ImageCache(cache_root='/tmp') request = img.ImageRequest( ident='V1234.jpg', region='100,100,100,100', size='100,100', rotation='0', quality='color', target_format='jpeg' ) with self.assertRaises(KeyError): cache[request]
def test_request_path(self, args, request_path): request = img.ImageRequest(*args) assert request.request_path == request_path
def test_missing_entry_gets_none(self): cache = img.ImageCache(cache_root='/tmp') request = img.ImageRequest('id1', 'full', 'full', '0', 'default', 'jpg') self.assertIsNone(cache.get(request))
def test_request_path(self, args, request_path): request = img.ImageRequest(*args) # Called twice for caching behaviour assert request.request_path == request_path assert request.request_path == request_path
def get_img(self, request, ident, region, size, rotation, quality, target_fmt, base_uri): '''Get an Image. Args: request (Request): Forwarded by dispatch_request ident (str): The identifier portion of the IIIF URI syntax ''' r = LorisResponse() r.set_acao(request, self.cors_regex) # ImageRequest's Parameter attributes, i.e. RegionParameter etc. are # decorated with @property and not constructed until they are first # accessed, which mean we don't have to catch any exceptions here. image_request = img.ImageRequest(ident, region, size, rotation, quality, target_fmt) self.logger.debug('Image Request Path: %s', image_request.request_path) if self.enable_caching: in_cache = image_request in self.img_cache else: in_cache = False try: # We need the info to check authorization, # ... still cheaper than always resolving as likely to be cached info = self._get_info(ident, request, base_uri)[0] except ResolverException as re: return NotFoundResponse(str(re)) if self.authorizer and self.authorizer.is_protected(info): authed = self.authorizer.is_authorized(info, request) if authed['status'] != 'ok': # Images don't redirect, they just deny out r.status_code = 401 return r if in_cache: fp, img_last_mod = self.img_cache[image_request] ims_hdr = request.headers.get('If-Modified-Since') # The stamp from the FS needs to be rounded using the same precision # as when went sent it, so for an accurate comparison turn it into # an http date and then parse it again :-( : img_last_mod = parse_date(http_date(img_last_mod)) self.logger.debug("Time from FS (default, rounded): %s", img_last_mod) self.logger.debug("Time from IMS Header (parsed): %s", parse_date(ims_hdr)) # ims_hdr = parse_date(ims_hdr) # catch parsing errors? if ims_hdr and parse_date(ims_hdr) >= img_last_mod: self.logger.debug('Sent 304 for %s ', fp) r.status_code = 304 return r else: r.content_type = constants.FORMATS_BY_EXTENSION[target_fmt] r.status_code = 200 r.last_modified = img_last_mod r.headers['Content-Length'] = path.getsize(fp) r.response = open(fp, 'rb') # hand the Image object its info info = self._get_info(ident, request, base_uri)[0] self._set_canonical_link(request=request, response=r, image_request=image_request, image_info=info) return r else: try: # 1. Get the info info = self._get_info(ident, request, base_uri)[0] # 2. Check that we can make the quality requested if image_request.quality not in info.profile.description[ 'qualities']: return BadRequestResponse( '"%s" quality is not available for this image' % (image_request.quality, )) # 3. Check if requested size is allowed if image_request.request_resolution_too_large( max_size_above_full=self.max_size_above_full, image_info=info): return NotFoundResponse('Resolution not available') # 4. Redirect if appropriate if self.redirect_canonical_image_request: if not image_request.is_canonical(info): self.logger.debug( 'Attempting redirect to %s', image_request.canonical_request_path, ) r.headers[ 'Location'] = image_request.canonical_request_path r.status_code = 301 return r # 5. Make an image fp = self._make_image(image_request=image_request, image_info=info) except ResolverException as re: return NotFoundResponse(str(re)) except TransformException as te: return ServerSideErrorResponse(te) except (RequestException, SyntaxException) as e: return BadRequestResponse(str(e)) except ImageInfoException as ie: # 500s! # ImageInfoException is only raised when # ImageInfo.from_image_file() can't determine the format of the # source image. It results in a 500, but isn't necessarily a # developer error. return ServerSideErrorResponse(ie) except (CalledProcessError, IOError) as e: # CalledProcessError and IOError typically happen when there are # permissions problems with one of the files or directories # used by the transformer. msg = '''%s \n\nThis is likely a permissions problem, though it\'s possible that there was a problem with the source file (%s).''' % (str(e), info.src_img_fp) return ServerSideErrorResponse(msg) r.content_type = constants.FORMATS_BY_EXTENSION[target_fmt] r.status_code = 200 r.last_modified = datetime.utcfromtimestamp(path.getctime(fp)) r.headers['Content-Length'] = path.getsize(fp) self._set_canonical_link(request=request, response=r, image_request=image_request, image_info=info) r.response = open(fp, 'rb') if not self.enable_caching: r.call_on_close(lambda: unlink(fp)) return r
def test_missing_info_attribute_is_error(self): request = img.ImageRequest('id1', 'full', 'full', '0', 'default', 'jpg') with pytest.raises(ImageException): request.info