Пример #1
0
    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))
Пример #2
0
    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
Пример #3
0
 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]
Пример #4
0
    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]
Пример #5
0
    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]
Пример #6
0
 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]
Пример #7
0
    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]
Пример #8
0
    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]
Пример #9
0
 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)
Пример #10
0
    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
Пример #11
0
	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
Пример #12
0
	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]
Пример #13
0
 def test_request_path(self, args, request_path):
     request = img.ImageRequest(*args)
     assert request.request_path == request_path
Пример #14
0
    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))
Пример #15
0
    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
Пример #16
0
    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
Пример #17
0
 def test_missing_info_attribute_is_error(self):
     request = img.ImageRequest('id1', 'full', 'full', '0', 'default', 'jpg')
     with pytest.raises(ImageException):
         request.info