def test01_split_url(self): """Test split_url() method. For everything except the handling of extension type on info.json requests (where v1.0 allows XML), the behavior of split_url() is version independent. """ # mismatching baseurl r = IIIFRequest() r.baseurl = 'http://ex.org/a/' self.assertRaises(IIIFRequestError, r.split_url, 'http://other.base.url/') # matching baseurl, but bad request r = IIIFRequest() r.baseurl = 'http://ex.org/a/' self.assertRaises(IIIFRequestBaseURI, r.split_url, 'http://ex.org/a/b') # matching baseurl, good request r = IIIFRequest(baseurl='http://ex.org/a/') r.identifier = None r.split_url('http://ex.org/a/b/full/full/0/native') self.assertEqual(r.identifier, 'b') self.assertEqual(r.region, 'full') self.assertEqual(r.size, 'full') # matching baseurl, insert id, good request r = IIIFRequest(baseurl='http://ex.org/a/') r.identifier = 'b' r.split_url('http://ex.org/a/full/full/0/native') self.assertEqual(r.identifier, 'b') self.assertEqual(r.region, 'full') self.assertEqual(r.size, 'full') # matching baseurl, too many segments r = IIIFRequest(baseurl='http://ex.org/a/') self.assertRaises(IIIFRequestError, r.split_url, 'http://ex.org/a/1/2/3/4/5/6')
def test12_decode_except(self): self.assertRaises(IIIFRequestBaseURI, IIIFRequest().split_url, ("id")) self.assertRaises(IIIFRequestBaseURI, IIIFRequest().split_url, ("id%2Ffsdjkh")) self.assertRaises(IIIFError, IIIFRequest().split_url, ("id/")) self.assertRaises(IIIFError, IIIFRequest().split_url, ("id/bogus")) self.assertRaises(IIIFError, IIIFRequest().split_url, ("id1/all/270/!pct%3A75.23.jpg"))
def test12_decode_good(self): """Decoding examples that should work.""" r = IIIFRequest(api_version='2.1', baseurl='1.1_netpbm/a/') r.split_url('1.1_netpbm/a/b/full/full/0/default') self.assertEqual(r.identifier, 'b') # id with slashes in it r = IIIFRequest(api_version='2.1', allow_slashes_in_identifier=True) r.split_url('a/b/c/full/full/0/default') self.assertFalse(r.info) self.assertEqual(r.identifier, 'a/b/c') r = IIIFRequest(api_version='2.1', allow_slashes_in_identifier=True) r.split_url('a/b/info.json') self.assertTrue(r.info) self.assertEqual(r.identifier, 'a/b')
def test12_decode_except(self): """Decoding exceptions.""" self.assertRaises(IIIFRequestBaseURI, IIIFRequest(api_version='2.0').split_url, ("id")) self.assertRaises(IIIFRequestBaseURI, IIIFRequest(api_version='2.0').split_url, ("id%2Ffsdjkh")) self.assertRaises(IIIFError, IIIFRequest(api_version='2.0').split_url, ("id/")) self.assertRaises(IIIFError, IIIFRequest(api_version='2.0').split_url, ("id/bogus")) self.assertRaises(IIIFError, IIIFRequest(api_version='2.0').split_url, ("id1/all/270/!pct%3A75.23.jpg"))
def test05_parse_rotation(self): """Parse rotation.""" r = IIIFRequest(api_version='3.0') r.parse_rotation('0') self.assertEqual(r.rotation_mirror, False) self.assertEqual(r.rotation_deg, 0.0) r.parse_rotation('0.0000') self.assertEqual(r.rotation_mirror, False) self.assertEqual(r.rotation_deg, 0.0) r.parse_rotation('0.000001') self.assertEqual(r.rotation_mirror, False) self.assertEqual(r.rotation_deg, 0.000001) r.parse_rotation('180') self.assertEqual(r.rotation_mirror, False) self.assertEqual(r.rotation_deg, 180.0) r.parse_rotation('360') self.assertEqual(r.rotation_mirror, False) self.assertEqual(r.rotation_deg, 0.0) r.parse_rotation('!0') self.assertEqual(r.rotation_mirror, True) self.assertEqual(r.rotation_deg, 0.0) r.parse_rotation('!0.000') self.assertEqual(r.rotation_mirror, True) self.assertEqual(r.rotation_deg, 0.0) r.parse_rotation('!123.45678') self.assertEqual(r.rotation_mirror, True) self.assertEqual(r.rotation_deg, 123.45678) # nothing supplied r.rotation = None r.parse_rotation() self.assertEqual(r.rotation_mirror, False) self.assertEqual(r.rotation_deg, 0.0)
def __init__(self, prefix, identifier, config, klass, auth): """Initialize IIIFHandler setting key configurations. Positional parameters: prefix -- URI prefix (without leading or trailing slashes) identifier -- identifier of image config -- instance of Config class klass -- IIIFManipulator sub-class to do manipulations auth -- IIIFAuth sub-class for auth """ self.prefix = prefix self.identifier = identifier self.config = config self.klass = klass self.api_version = config.api_version self.auth = auth self.degraded = False self.logger = logging.getLogger('IIIFHandler') # # Create objects to process request self.iiif = IIIFRequest(api_version=self.api_version, identifier=self.identifier) self.manipulator = klass(api_version=self.api_version) # # Set up auth object with locations if not already done if (self.auth and not self.auth.login_uri): self.auth.login_uri = self.server_and_prefix + '/login' if (self.auth.logout_handler is not None): self.auth.logout_uri = self.server_and_prefix + '/logout' self.auth.access_token_uri = self.server_and_prefix + '/token' # # Response headers # -- All responses should have CORS header self.headers = {'Access-control-allow-origin': '*'}
def test13_rotation_to_apply(self): """Test rotation_to_apply.""" m = IIIFManipulator() m.request = IIIFRequest() # 0 m.request.rotation_deg = 0 self.assertEqual(m.rotation_to_apply(), (False, False)) # 90 and only90s m.request.rotation_deg = 90 self.assertEqual(m.rotation_to_apply(True), (False, 90)) # 100 m.request.rotation_deg = 100 self.assertEqual(m.rotation_to_apply(), (False, 100)) # 100 and only90s m.request.rotation_deg = 100 self.assertRaises(IIIFError, m.rotation_to_apply, True) # 45 and mirror m.request.rotation_mirror = True m.request.rotation_deg = 45 self.assertEqual(m.rotation_to_apply(), (True, 45)) # 45 and no-mirror self.assertRaises(IIIFError, m.rotation_to_apply, True, True) # mirror request and no-mirror m.request.rotation_mirror = True self.assertRaises(IIIFError, m.rotation_to_apply, False, True)
def test01_parse_region(self): """Region.""" r = IIIFRequest(api_version='2.0') r.region = None r.parse_region() self.assertTrue(r.region_full) r.region = 'full' r.parse_region() self.assertTrue(r.region_full) r.region = '0,1,90,100' r.parse_region() self.assertFalse(r.region_full) self.assertFalse(r.region_pct) self.assertEqual(r.region_xywh, [0, 1, 90, 100]) r.region = 'pct:2,3,91,99' r.parse_region() self.assertFalse(r.region_full) self.assertTrue(r.region_pct) self.assertEqual(r.region_xywh, [2, 3, 91, 99]) r.region = 'pct:10,10,50,50' r.parse_region() self.assertFalse(r.region_full) self.assertTrue(r.region_pct) self.assertEqual(r.region_xywh, [10.0, 10.0, 50.0, 50.0]) r.region = 'pct:0,0,100,100' r.parse_region() self.assertFalse(r.region_full) self.assertTrue(r.region_pct) self.assertEqual(r.region_xywh, [0.0, 0.0, 100.0, 100.0])
def test02_parse_non_negative_int(self): """Test parsing of non-negative integer.""" r = IIIFRequest() self.assertEqual(r._parse_non_negative_int('1', 'a'), (1)) self.assertRaises(ValueError, r._parse_non_negative_int, 'a', 'region') self.assertRaises(ValueError, r._parse_non_negative_int, '-1', 'region')
def test05_parse_rotation(self): """Rotation.""" r = IIIFRequest(api_version='2.0') r.parse_rotation('0') self.assertEqual(r.rotation_mirror, False) self.assertEqual(r.rotation_deg, 0.0) r.parse_rotation('0.0000') self.assertEqual(r.rotation_mirror, False) self.assertEqual(r.rotation_deg, 0.0) r.parse_rotation('0.000001') self.assertEqual(r.rotation_mirror, False) self.assertEqual(r.rotation_deg, 0.000001) r.parse_rotation('180') self.assertEqual(r.rotation_mirror, False) self.assertEqual(r.rotation_deg, 180.0) r.parse_rotation('360') self.assertEqual(r.rotation_mirror, False) self.assertEqual(r.rotation_deg, 0.0) r.parse_rotation('!0') self.assertEqual(r.rotation_mirror, True) self.assertEqual(r.rotation_deg, 0.0) r.parse_rotation('!0.000') self.assertEqual(r.rotation_mirror, True) self.assertEqual(r.rotation_deg, 0.0) r.parse_rotation('!123.45678') self.assertEqual(r.rotation_mirror, True) self.assertEqual(r.rotation_deg, 123.45678)
def test04_parse_size_bad(self): """Bad size.""" r = IIIFRequest(api_version='1.1') self.assertRaises(IIIFError, r.parse_size, ',0.0') self.assertRaises(IIIFError, r.parse_size, '0.0,') self.assertRaises(IIIFError, r.parse_size, '1.0,1.0') self.assertRaises(IIIFError, r.parse_size, '1,1,1')
def test08_parse_quality_bad(self): r = IIIFRequest(api_version='1.1') r.quality = 'does_not_exist' self.assertRaises(IIIFError, r.parse_quality) # bad ones r.quality = '' self.assertRaises(IIIFError, r.parse_quality)
def test10_encode(self): for tname in sorted(data.iterkeys()): tdata=data[tname] print tname + " " + self.pstr(data[tname][0]) + " " + data[tname][1] iiif = IIIFRequest(**data[tname][0]) self.assertEqual(iiif.url(),data[tname][1]) print
def test1_encode(self): print "Encoding tests..." for tname in sorted(data.iterkeys()): tdata=data[tname] print tname + " " + self.pstr(data[tname][0]) + " " + data[tname][1] iiif = IIIFRequest(api_version='1.1',**data[tname][0]) self.assertEqual(iiif.url(),data[tname][1]) print
def test06_do_rotation(self): m = IIIFManipulator() m.request = IIIFRequest() m.request.rotation_deg = 0.0 m.do_rotation() # non 0.0 raises m.request.rotation_deg = 1.0 self.assertRaises(IIIFError, m.do_rotation)
def test08_parse_quality_bad(self): """Parse quality - bad requests.""" r = IIIFRequest(api_version='3.0') r.quality = 'does_not_exist' self.assertRaises(IIIFError, r.parse_quality) # bad ones r.quality = '' self.assertRaises(IIIFError, r.parse_quality)
def test02_parse_region_bad(self): """Bad regions.""" r = IIIFRequest(api_version='2.0') r.region = 'pct:0,0,50,1000' self.assertRaises(IIIFError, r.parse_region) r.region = 'pct:-10,0,50,100' self.assertRaises(IIIFError, r.parse_region) r.region = 'square' self.assertRaises(IIIFError, r.parse_region)
def test06_do_rotation(self): """Test do_rotation, error if any rotation.""" m = IIIFManipulator() m.request = IIIFRequest() m.do_rotation(False, 0.0) # mirror raises self.assertRaises(IIIFError, m.do_rotation, True, 0.0) # non 0.0 raises self.assertRaises(IIIFError, m.do_rotation, False, 10.0)
def test19_split_url(self): """Test split_url() method. Most parts are common to all versions, except handling of info.json extensions. """ # api_version=1.0, format=xyz -> bad r = IIIFRequest(api_version='1.0') r.baseurl = 'http://ex.org/a/' self.assertRaises(IIIFError, r.split_url, 'http://ex.org/a/b/info.xyz') # api_version=2.1, format=xml -> bad r = IIIFRequest(api_version='2.1') r.baseurl = 'http://ex.org/a/' self.assertRaises(IIIFError, r.split_url, 'http://ex.org/a/b/info.xml') # api_version=2.1, format=xyz -> bad r = IIIFRequest(api_version='2.1') r.baseurl = 'http://ex.org/a/' self.assertRaises(IIIFError, r.split_url, 'http://ex.org/a/b/info.xyz')
def test18_url(self): """Test url() method.""" r = IIIFRequest(api_version='2.1') r.size = None r.size_wh = [11, 22] self.assertEqual(r.url(identifier='abc1'), 'abc1/full/11,22/0/default') r.size_wh = [100, None] self.assertEqual(r.url(identifier='abc2'), 'abc2/full/100,/0/default') r.size_wh = [None, 999] self.assertEqual(r.url(identifier='abc3'), 'abc3/full/,999/0/default') r.size_wh = None self.assertEqual(r.url(identifier='abc4'), 'abc4/full/full/0/default') r = IIIFRequest(api_version='2.1') r.size_full = True self.assertEqual(r.url(identifier='abc5'), 'abc5/full/full/0/default') r = IIIFRequest(api_version='2.1') r.size_max = True self.assertEqual(r.url(identifier='abc5'), 'abc5/full/max/0/default')
def test04_parse_size_bad(self): """Bad sizes.""" r = IIIFRequest(api_version='2.0') self.assertRaises(IIIFError, r.parse_size, ',0.0') self.assertRaises(IIIFError, r.parse_size, '0.0,') self.assertRaises(IIIFError, r.parse_size, '1.0,1.0') self.assertRaises(IIIFError, r.parse_size, '1,1,1') # 'max' not allowed in 2.0, introduced in 2.1 self.assertRaises(IIIFError, r.parse_size, 'max')
def test11_decode(self): for tname in sorted(data.iterkeys()): tdata = data[tname] pstr = self.pstr(data[tname][0]) for turl in data[tname][1:]: iiif = IIIFRequest(api_version='1.1').split_url(turl) tstr = self.pstr(iiif.__dict__) print tname + " " + turl + " -> " + tstr self.assertEqual(tstr, pstr) print
def test03_is_scaled_full_image(self): """Test check for whether request is scaled full image.""" r = IIIFRequest(identifier='dummy', api_version='2.1') r.parse_url('full/full/0/default.jpg') self.assertFalse(r.is_scaled_full_image()) r.parse_url('full/!10,10/0/default.jpg') self.assertFalse(r.is_scaled_full_image()) r.parse_url('10,10,90,90/10,10/0/default.jpg') self.assertFalse(r.is_scaled_full_image()) r.parse_url('full/10,10/1/default.jpg') self.assertFalse(r.is_scaled_full_image()) r.parse_url('full/10,10/0/default.png') self.assertFalse(r.is_scaled_full_image()) r.parse_url('full/10,10/0/color.jpg') self.assertFalse(r.is_scaled_full_image()) # r = IIIFRequest(identifier='dummy', api_version='2.1') r.parse_url('full/10,10/0/default.jpg') self.assertTrue(r.is_scaled_full_image())
def test04_do_region(self): m = IIIFManipulator() m.request = IIIFRequest() m.request.region_full = True m.do_region() # and now without region_full m.width = -1 m.height = -1 m.request.region_full = False self.assertRaises(IIIFError, m.do_region)
def test2_decode(self): print "Decoding tests..." for tname in sorted(data.iterkeys()): tdata = data[tname] pstr = self.pstr(data[tname][0]) for turl in data[tname][1:]: iiif = IIIFRequest().parse_url(turl) tstr = self.pstr(iiif.__dict__) print " <tr>\n <td>" + tstr + "</td>\n <td>" + turl + "</td>\n </tr>" self.assertEqual(tstr, pstr) print
def check_encoding(self, data, api_version): """Encoding. Checks that every for each test in the dict data, the data values (first element) encode to the URL given (second element). """ for tname in sorted(data.keys()): tdata = data[tname] iiif = IIIFRequest(api_version=api_version, **data[tname][0]) self.assertEqual(iiif.url(), data[tname][1])
def test20_bad_response_codes(self): """Response codes.""" for (path, code) in [("id/b", 400), ("id/b/c", 400), ("id/b/c/d", 400), ("id/full/full/0/default.jpg/extra", 400)]: got_code = None try: IIIFRequest(api_version='2.0').split_url(path) except IIIFError as e: got_code = e.code self.assertEqual( got_code, code, "Bad code %s, expected %d, for path %s" % (str(got_code), code, path))
def test08_do_format(self): m = IIIFManipulator() m.request = IIIFRequest() m.request.format = None m.srcfile = 'abc' m.do_format() self.assertEqual(m.outfile, m.srcfile) # failure to copy if srcfile and outfile specified same m.outfile = m.srcfile self.assertRaises(IIIFError, m.do_format) # any format specified -> raise m.request.format = 'something' self.assertRaises(IIIFError, m.do_format)
def test05_do_size(self): m = IIIFManipulator() m.request = IIIFRequest() m.request.size_pct = 100 m.request.size = '100' m.do_size() m.request.size_pct = None m.request.size = 'full' m.do_size() # and raise for not 100 or full m.request.size_pct = None m.request.size = '1,1' self.assertRaises(IIIFError, m.do_size)
def test03_parse_size(self): """Parse size.""" r = IIIFRequest(api_version='2.1') r.parse_size('pct:100') self.assertEqual(r.size_pct, 100.0) self.assertFalse(r.size_bang) r.parse_size('1,2') self.assertFalse(r.size_pct) self.assertFalse(r.size_bang) self.assertEqual(r.size_wh, (1, 2)) r.parse_size('3,') self.assertFalse(r.size_pct) self.assertFalse(r.size_bang) self.assertEqual(r.size_wh, (3, None)) r.parse_size(',4') self.assertFalse(r.size_pct) self.assertFalse(r.size_bang) self.assertEqual(r.size_wh, (None, 4)) r.parse_size('!5,6') self.assertFalse(r.size_pct) self.assertTrue(r.size_bang) self.assertEqual(r.size_wh, (5, 6)) # 'full' r = IIIFRequest(api_version='2.1') r.parse_size('full') self.assertTrue(r.size_full) self.assertFalse(r.size_max) self.assertFalse(r.size_pct) self.assertFalse(r.size_bang) self.assertEqual(r.size_wh, (None, None)) # 'max' is new in 2.1 r = IIIFRequest(api_version='2.1') r.parse_size('max') self.assertFalse(r.size_full) self.assertTrue(r.size_max) self.assertFalse(r.size_pct) self.assertFalse(r.size_bang) self.assertEqual(r.size_wh, (None, None))