def test01_minmal(self): # Just do the trivial JSON test ir = IIIFInfo(identifier="i1",api_version='1.0') self.assertEqual( ir.as_json(validate=False), '{\n "identifier": "i1", \n "profile": "http://library.stanford.edu/iiif/image-api/compliance.html#level1"\n}' ) ir.width=100 ir.height=200 self.assertEqual( ir.as_json(), '{\n "height": 200, \n "identifier": "i1", \n "profile": "http://library.stanford.edu/iiif/image-api/compliance.html#level1", \n "width": 100\n}' )
def test10_read_example_from_spec(self): """Test reading of example from spec.""" i = IIIFInfo() fh = open("tests/testdata/info_json_2_0/info_from_spec.json") i.read(fh) self.assertEqual(i.context, "http://iiif.io/api/image/2/context.json") self.assertEqual(i.id, "http://www.example.org/image-service/abcd1234/1E34750D-38DB-4825-A38A-B60A345E591C") self.assertEqual(i.protocol, "http://iiif.io/api/image") self.assertEqual(i.width, 6000) self.assertEqual(i.height, 4000) self.assertEqual( i.sizes, [{"width": 150, "height": 100}, {"width": 600, "height": 400}, {"width": 3000, "height": 2000}] ) self.assertEqual( i.profile, [ "http://iiif.io/api/image/2/level2.json", { "formats": ["gif", "pdf"], "qualities": ["color", "gray"], "supports": [ "canonicalLinkHeader", "rotationArbitrary", "profileLinkHeader", "http://example.com/feature/", ], }, ], ) # extracted information self.assertEqual(i.compliance, "http://iiif.io/api/image/2/level2.json")
def test01_minmal(self): # Just do the trivial JSON test ir = IIIFInfo(server_and_prefix="http://example.com",identifier="i1",api_version='1.1') self.assertEqual( ir.as_json(validate=False), '{\n "@context": "http://library.stanford.edu/iiif/image-api/1.1/context.json", \n "@id": "http://example.com/i1", \n "profile": "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level1"\n}' ) ir.width=100 ir.height=200 self.assertEqual( ir.as_json(), '{\n "@context": "http://library.stanford.edu/iiif/image-api/1.1/context.json", \n "@id": "http://example.com/i1", \n "height": 200, \n "profile": "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level1", \n "width": 100\n}' )
def test20_write_example_in_spec(self): i = IIIFInfo( api_version='2.1', id="http://www.example.org/image-service/abcd1234/1E34750D-38DB-4825-A38A-B60A345E591C", #"protocol" : "http://iiif.io/api/image", width=6000, height=4000, sizes=[ {"width" : 150, "height" : 100}, {"width" : 600, "height" : 400}, {"width" : 3000, "height": 2000} ], tiles=[ {"width" : 512, "scaleFactors" : [1,2,4,8,16]} ], profile="http://iiif.io/api/image/2/level2.json", formats = [ "gif", "pdf" ], qualities = [ "color", "gray" ], supports = [ "canonicalLinkHeader", "rotationArbitrary", "profileLinkHeader", "http://example.com/feature/" ], service={ "@context": "http://iiif.io/api/annex/service/physdim/1/context.json", "profile": "http://iiif.io/api/annex/service/physdim", "physicalScale": 0.0025, "physicalUnits": "in" } ) reparsed_json = json.loads( i.as_json() ) example_json = json.load( open('test_info/2.1/info_from_spec.json') ) self.maxDiff = 4000 self.assertEqual( reparsed_json, example_json )
def test06_validate(self): i = IIIFInfo(api_version='1.1') self.assertRaises( Exception, i.validate, () ) i = IIIFInfo(identifier='a') self.assertRaises( Exception, i.validate, () ) i = IIIFInfo(identifier='a',width=1,height=2) self.assertTrue( i.validate() )
def do_GET_body(self): """Create body of GET.""" iiif = self.iiif if len(self.path) > 1024: raise IIIFError(code=414, text="URI Too Long: Max 1024 chars, got %d\n" % len(self.path)) try: # self.path has leading / then identifier/params... self.path = self.path.lstrip("/") sys.stderr.write("path = %s" % (self.path)) iiif.parse_url(self.path) except Exception as e: # Something completely unexpected => 500 raise IIIFError( code=500, text="Internal Server Error: unexpected exception parsing request (" + str(e) + ")" ) # Now we have a full iiif request if re.match("[\w\.\-]+$", iiif.identifier): file = os.path.join(TESTIMAGE_DIR, iiif.identifier) if not os.path.isfile(file): images_available = "" for image_file in os.listdir(TESTIMAGE_DIR): if os.path.isfile(os.path.join(TESTIMAGE_DIR, image_file)): images_available += " " + image_file + "\n" raise IIIFError( code=404, parameter="identifier", text="Image resource '" + iiif.identifier + "' not found. Local image files available:\n" + images_available, ) else: raise IIIFError( code=404, parameter="identifier", text="Image resource '" + iiif.identifier + "' not found. Only local test images and http: URIs for images are supported.\n", ) # Now know image is OK manipulator = IIIFRequestHandler.manipulator_class() # Stash manipulator object so we can cleanup after reading file self.manipulator = manipulator self.compliance_uri = manipulator.compliance_uri if iiif.info: # get size manipulator.srcfile = file manipulator.do_first() # most of info.json comes from config, a few things # specific to image i = IIIFInfo() i.identifier = self.iiif.identifier i.width = manipulator.width i.height = manipulator.height import io return (io.StringIO(i.as_json()), "application/json") else: (outfile, mime_type) = manipulator.derive(file, iiif) return (open(outfile, "r"), mime_type)
def test03_array_vals(self): """Test array values.""" i = IIIFInfo(api_version='1.1') i.scale_factors = [1, 2, 3] self.assertEqual(i.scale_factors, [1, 2, 3]) i._setattr('scale_factors', [4, 5, 6]) self.assertEqual(i.scale_factors, [4, 5, 6])
def test06_validate(self): """Test validate method.""" i = IIIFInfo() self.assertRaises(Exception, i.validate, ()) i = IIIFInfo(identifier="a") self.assertRaises(Exception, i.validate, ()) i = IIIFInfo(identifier="a", width=1, height=2) self.assertTrue(i.validate())
def test20_scale_factors(self): """Test getter/setter for scale_factors property.""" i = IIIFInfo(api_version="1.1") self.assertEqual(i.scale_factors, None) i.scale_factors = [1, 2] self.assertEqual(i.scale_factors, [1, 2]) i.scale_factors = [7, 8] self.assertEqual(i.scale_factors, [7, 8])
def test01_empty_auth_defined(self): """Test empty auth.""" info = IIIFInfo(identifier="http://example.com/i1", api_version='2.1') auth = IIIFAuth() auth.add_services(info) self.assertJSONEqual(info.as_json( validate=False), '{\n "@context": "http://iiif.io/api/image/2/context.json", \n "@id": "http://example.com/i1", \n "profile": [\n "http://iiif.io/api/image/2/level1.json"\n ], \n "protocol": "http://iiif.io/api/image"\n}') self.assertEqual(info.service, None)
def test01_minmal(self): # Just do the trivial JSON test # ?? should this empty case raise and error instead? ir = IIIFInfo(identifier="http://example.com/i1", api_version='2.1') self.assertEqual( ir.as_json(validate=False), '{\n "@context": "http://iiif.io/api/image/2/context.json", \n "@id": "http://example.com/i1", \n "profile": [\n "http://iiif.io/api/image/2/level1.json"\n ], \n "protocol": "http://iiif.io/api/image"\n}' ) ir.width=100 ir.height=200 self.assertEqual( ir.as_json(), '{\n "@context": "http://iiif.io/api/image/2/context.json", \n "@id": "http://example.com/i1", \n "height": 200, \n "profile": [\n "http://iiif.io/api/image/2/level1.json"\n ], \n "protocol": "http://iiif.io/api/image", \n "width": 100\n}' )
def test02_scale_factor(self): """Test scale factor.""" ir = IIIFInfo(width=1, height=2, scale_factors=[ 1, 2], api_version='1.1') # self.assertRegexpMatches( ir.as_json(validate=False), # r'"scale_factors": \[\s*1' ) #,\s*2\s*]' ) #no assertRegexpMatches in # 2.6 json = ir.as_json(validate=False) self.assertTrue(re.search(r'"scale_factors": \[\s*1', json))
def test05_level_and_profile(self): i = IIIFInfo(api_version='2.1') i.level = 0 self.assertEqual( i.level, 0 ) self.assertEqual( i.profile, "http://iiif.io/api/image/2/level0.json" ) i.level = 2 self.assertEqual( i.level, 2 ) self.assertEqual( i.profile, "http://iiif.io/api/image/2/level2.json" ) i.profile = "http://iiif.io/api/image/2/level1.json" self.assertEqual( i.level, 1 )
def test05_level_and_profile(self): i = IIIFInfo(api_version='1.1') i.level = 0 self.assertEqual( i.level, 0 ) self.assertEqual( i.profile, "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0" ) i.level = 2 self.assertEqual( i.level, 2 ) self.assertEqual( i.profile, "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level2" ) i.profile = "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level1" self.assertEqual( i.level, 1 )
def test11_read_example_with_explicit_version(self): i = IIIFInfo() #default not 1.1 fh = open('test_info/1.1/info_from_spec.json') i.read(fh) #will get 1.1 from @context self.assertEqual( i.api_version, '1.1' ) fh = open('test_info/1.1/info_from_spec.json') self.assertRaises( Exception, i.read, fh, '0.1' ) # 0.1 bad fh = open('test_info/1.1/info_from_spec.json') i.read(fh, '1.1') self.assertEqual( i.api_version, '1.1' )
def image_information_response(self): """Parse image information request and create response.""" dr = degraded_request(self.identifier) if (dr): self.logger.info("image_information: degraded %s -> %s" % (self.identifier,dr)) self.degraded = self.identifier self.identifier = dr else: self.logger.info("image_information: %s" % (self.identifier)) # get size self.manipulator.srcfile=self.file self.manipulator.do_first() # most of info.json comes from config, a few things specific to image info = { 'tile_height': self.config.tile_height, 'tile_width': self.config.tile_width, 'scale_factors' : self.config.scale_factors } i = IIIFInfo(conf=info,api_version=self.api_version) i.server_and_prefix = self.server_and_prefix i.identifier = self.iiif.identifier i.width = self.manipulator.width i.height = self.manipulator.height if (self.api_version>='2.0'): i.qualities = [ "default", "color", "gray" ] #FIXME - should come from manipulator else: i.qualities = [ "native", "color", "gray" ] #FIXME - should come from manipulator i.formats = [ "jpg", "png" ] #FIXME - should come from manipulator if (self.auth): self.auth.add_services(i) return self.make_response(i.as_json(),content_type=self.json_mime_type)
def test11_read_example_with_explicit_version(self): """Test reading without explicit version.""" i = IIIFInfo() # default not 1.1 fh = open('tests/testdata/info_json_1_1/info_from_spec.json') i.read(fh) # will get 1.1 from @context self.assertEqual(i.api_version, '1.1') fh = open('tests/testdata/info_json_1_1/info_from_spec.json') self.assertRaises(Exception, i.read, fh, '0.1') # 0.1 bad fh = open('tests/testdata/info_json_1_1/info_from_spec.json') i.read(fh, '1.1') self.assertEqual(i.api_version, '1.1')
def test05_level_and_profile(self): """Test level and profile.""" i = IIIFInfo() i.level = 0 self.assertEqual(i.level, 0) self.assertEqual(i.compliance, "http://iiif.io/api/image/2/level0.json") self.assertEqual(i.profile, ["http://iiif.io/api/image/2/level0.json"]) i.level = 2 self.assertEqual(i.level, 2) self.assertEqual(i.compliance, "http://iiif.io/api/image/2/level2.json") self.assertEqual(i.profile, ["http://iiif.io/api/image/2/level2.json"])
def test10_read_example_from_spec(self): i = IIIFInfo(api_version='2.1') fh = open('test_info/2.1/info_from_spec.json') i.read(fh) self.assertEqual( i.context, "http://iiif.io/api/image/2/context.json" ) self.assertEqual( i.id, "http://www.example.org/image-service/abcd1234/1E34750D-38DB-4825-A38A-B60A345E591C" ) self.assertEqual( i.protocol, "http://iiif.io/api/image" ) self.assertEqual( i.width, 6000 ) self.assertEqual( i.height, 4000 ) self.assertEqual( i.sizes, [ {"width" : 150, "height" : 100}, {"width" : 600, "height" : 400}, {"width" : 3000, "height": 2000} ] )
def test10_read_example_from_spec(self): i = IIIFInfo(api_version='1.0') fh = open('test_info/1.0/info_from_spec.json') i.read(fh) self.assertEqual( i.id, "1E34750D-38DB-4825-A38A-B60A345E591C" ) self.assertEqual( i.profile, "http://library.stanford.edu/iiif/image-api/compliance.html#level0" ) self.assertEqual( i.width, 6000 ) self.assertEqual( i.height, 4000 ) self.assertEqual( i.scale_factors, [1,2,4] ) self.assertEqual( i.tile_width, 1024 ) self.assertEqual( i.tile_height, 1024 ) self.assertEqual( i.formats, ['jpg','png'] ) self.assertEqual( i.qualities, ['native','grey'] )
def test11_read_example_with_extra(self): i = IIIFInfo(api_version='2.1') fh = open('test_info/2.1/info_with_extra.json') i.read(fh) self.assertEqual( i.context, "http://iiif.io/api/image/2/context.json" ) self.assertEqual( i.id, "http://www.example.org/image-service/abcd1234/1E34750D-38DB-4825-A38A-B60A345E591C" ) self.assertEqual( i.protocol, "http://iiif.io/api/image" ) self.assertEqual( i.width, 6000 ) self.assertEqual( i.height, 4000 ) self.assertEqual( i.tiles, [{"width" : 512, "scaleFactors" : [1,2,4,8,16]}] ) # and should have 1.1-like params too self.assertEqual( i.tile_width, 512 ) self.assertEqual( i.scale_factors, [1,2,4,8,16] ) self.assertEqual( i.profile, "http://iiif.io/api/image/2/level2.json" )
def generate(self, src=None, identifier=None): """Generate static files for one source image.""" self.src=src self.identifier=identifier # Get image details and calculate tiles im=IIIFManipulatorPIL() im.srcfile = self.src im.do_first() width = im.width height = im.height #print "w=%d h=%d ts=%d" % (im.width,im.height,tilesize) xtiles = int(width/self.tilesize) ytiles = int(height/self.tilesize) max_tiles = xtiles if (xtiles>ytiles) else ytiles scale_factors = [ 1 ] factor = 1 for n in range(10): if (factor >= max_tiles): break factor = factor+factor scale_factors.append(factor) # Setup destination and IIIF identifier self.setup_destination() # Write out images for (region,size) in static_partial_tile_sizes(width,height,self.tilesize,scale_factors): self.generate_tile(region,size) sizes = [] for (size) in static_full_sizes(width,height,self.tilesize): #FIXME - see https://github.com/zimeon/iiif/issues/9 #sizes.append({'width': size[0], 'height': size[1]}) self.generate_tile('full',size) # Write info.json qualities = ['default'] if (self.api_version>'1.1') else ['native'] info=IIIFInfo(level=0, server_and_prefix=self.prefix, identifier=self.identifier, width=width, height=height, scale_factors=scale_factors, tile_width=self.tilesize, tile_height=self.tilesize, formats=['jpg'], qualities=qualities, sizes=sizes, api_version=self.api_version) json_file = os.path.join(self.dst,self.identifier,'info.json') if (self.dryrun): print "dryrun mode, would write the following files:" print "%s / %s/%s" % (self.dst, self.identifier, 'info.json') self.logger.info(info.as_json()) else: with open(json_file,'w') as f: f.write(info.as_json()) f.close() self.logger.info("Written %s"%(json_file)) print
def test11_read_example_with_extra(self): """Test reading of example with extra data.""" i = IIIFInfo() fh = open("tests/testdata/info_json_2_0/info_with_extra.json") i.read(fh) self.assertEqual(i.context, "http://iiif.io/api/image/2/context.json") self.assertEqual(i.id, "http://www.example.org/image-service/abcd1234/1E34750D-38DB-4825-A38A-B60A345E591C") self.assertEqual(i.protocol, "http://iiif.io/api/image") self.assertEqual(i.width, 6000) self.assertEqual(i.height, 4000) self.assertEqual(i.tiles, [{"width": 512, "scaleFactors": [1, 2, 4, 8, 16]}]) # and should have 1.1-like params too self.assertEqual(i.tile_width, 512) self.assertEqual(i.scale_factors, [1, 2, 4, 8, 16]) self.assertEqual(i.compliance, "http://iiif.io/api/image/2/level2.json")
def test21_tile_width_tile_height(self): """Test getters/setters for tile_width and tile_height.""" i = IIIFInfo(api_version="1.1") self.assertEqual(i.tile_width, None) i.tile_width = 123 self.assertEqual(i.tile_width, 123) self.assertEqual(i.tile_height, 123) i.tile_width = 124 self.assertEqual(i.tile_width, 124) self.assertEqual(i.tile_height, 124) # once height it set, it won't inherit from future width setting i.tile_height = 255 self.assertEqual(i.tile_width, 124) self.assertEqual(i.tile_height, 255) i.tile_width = 345 self.assertEqual(i.tile_width, 345) self.assertEqual(i.tile_height, 255)
def test20_write_example_in_spec(self): """Create example info.json in spec.""" i = IIIFInfo( api_version='2.1', id="http://www.example.org/image-service/abcd1234/1E34750D-38DB-4825-A38A-B60A345E591C", # "protocol" : "http://iiif.io/api/image", width=6000, height=4000, sizes=[ {"width": 150, "height": 100}, {"width": 600, "height": 400}, {"width": 3000, "height": 2000}], tiles=[ {"width": 512, "scaleFactors": [1, 2, 4]}, {"width": 1024, "height": 2048, "scaleFactors": [8, 16]}], attribution=[ {"@value": "<span>Provided by Example Organization</span>", "@language": "en"}, {"@value": "<span>Darparwyd gan Enghraifft Sefydliad</span>", "@language": "cy"}], logo={"@id": "http://example.org/image-service/logo/full/200,/0/default.png", "service": {"@context": "http://iiif.io/api/image/2/context.json", "@id": "http://example.org/image-service/logo", "profile": "http://iiif.io/api/image/2/level2.json"}}, license=[ "http://example.org/rights/license1.html", "https://creativecommons.org/licenses/by/4.0/"], profile=["http://iiif.io/api/image/2/level2.json"], formats=["gif", "pdf"], qualities=["color", "gray"], supports=["canonicalLinkHeader", "rotationArbitrary", "profileLinkHeader", "http://example.com/feature/"], service=[ {"@context": "http://iiif.io/api/annex/service/physdim/1/context.json", "profile": "http://iiif.io/api/annex/service/physdim", "physicalScale": 0.0025, "physicalUnits": "in"}, {"@context": "http://geojson.org/contexts/geojson-base.jsonld", "@id": "http://www.example.org/geojson/paris.json"}] ) reparsed_json = json.loads(i.as_json()) example_json = json.load( open('tests/testdata/info_json_2_1/info_from_spec_section_5_6.json')) self.maxDiff = 4000 self.assertEqual(reparsed_json, example_json)
def test10_read_example_from_spec(self): """Test read of example from spec.""" i = IIIFInfo(api_version='1.1') fh = open('tests/testdata/info_json_1_1/info_from_spec.json') i.read(fh) self.assertEqual( i.context, "http://library.stanford.edu/iiif/image-api/1.1/context.json") self.assertEqual( i.id, "http://iiif.example.com/prefix/1E34750D-38DB-4825-A38A-B60A345E591C") self.assertEqual( i.profile, "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0") self.assertEqual(i.width, 6000) self.assertEqual(i.height, 4000) self.assertEqual(i.scale_factors, [1, 2, 4]) self.assertEqual(i.tile_width, 1024) self.assertEqual(i.tile_height, 1024) self.assertEqual(i.formats, ['jpg', 'png']) self.assertEqual(i.qualities, ['native', 'grey'])
def test05_set(self): """Test custom setter.""" i = IIIFInfo() i.array_params = set(["array"]) # array param i._setattr("array", "string") self.assertEqual(i.array, ["string"]) i._setattr("array", [1, 2, 3]) self.assertEqual(i.array, [1, 2, 3]) # other param (trivial) i._setattr("other", 1234) self.assertEqual(i.other, 1234)
def test05_set(self): """Test custom setter.""" i = IIIFInfo() i.array_params = set(['array']) # array param i._setattr('array', 'string') self.assertEqual(i.array, ['string']) i._setattr('array', [1, 2, 3]) self.assertEqual(i.array, [1, 2, 3]) # other param (trivial) i._setattr('other', 1234) self.assertEqual(i.other, 1234)
def test07_read(self): """Read test.""" i = IIIFInfo() fh = io.StringIO('{ "@id": "no_data" }') i.read(fh, api_version="2.0") self.assertEqual(i.api_version, "2.0") fh = io.StringIO('{ "@id": "no_data" }') self.assertRaises(IIIFInfoError, i.read, fh) # missing identifier cases fh = io.StringIO("{ }") self.assertRaises(IIIFInfoError, i.read, fh, api_version="1.0") fh = io.StringIO("{ }") self.assertRaises(IIIFInfoError, i.read, fh, api_version="2.0") # bad @context fh = io.StringIO('{ "@context": "oops" }') self.assertRaises(IIIFInfoError, i.read, fh) # fh = io.StringIO('{ "@context": "http://library.stanford.edu/' 'iiif/image-api/1.1/context.json", "@id": "a" }') i.read(fh) self.assertEqual(i.api_version, "1.1")
def test01_minmal(self): """Trivial JSON test.""" # ?? should this empty case raise and error instead? ir = IIIFInfo(identifier="http://example.com/i1", api_version='2.1') self.assertJSONEqual( ir.as_json(validate=False), '{\n "@context": "http://iiif.io/api/image/2/context.json", \n "@id": "http://example.com/i1", \n "profile": [\n "http://iiif.io/api/image/2/level1.json"\n ], \n "protocol": "http://iiif.io/api/image"\n}' ) ir.width = 100 ir.height = 200 self.assertJSONEqual( ir.as_json(), '{\n "@context": "http://iiif.io/api/image/2/context.json", \n "@id": "http://example.com/i1", \n "height": 200, \n "profile": [\n "http://iiif.io/api/image/2/level1.json"\n ], \n "protocol": "http://iiif.io/api/image", \n "width": 100\n}' )
def test04_conf(self): """Tile parameter configuration.""" conf = { 'tiles': [{ 'width': 999, 'scaleFactors': [9, 8, 7] }, { 'width': 500, 'height': 600, 'scaleFactors': [1, 2] }] } i = IIIFInfo(api_version='3.0', conf=conf) self.assertEqual(i.tiles[0]['width'], 999) self.assertEqual(i.tiles[0]['scaleFactors'], [9, 8, 7]) self.assertEqual(i.tiles[1]['width'], 500) self.assertEqual(i.tiles[1]['scaleFactors'], [1, 2]) # 1.1 style values look at only first entry self.assertEqual(i.tile_width, 999) self.assertEqual(i.scale_factors, [9, 8, 7])
def test01_minmal(self): # Just do the trivial JSON test ir = IIIFInfo(server_and_prefix="http://example.com", identifier="i1", api_version='1.1') self.assertEqual( ir.as_json(validate=False), '{\n "@context": "http://library.stanford.edu/iiif/image-api/1.1/context.json", \n "@id": "http://example.com/i1", \n "profile": "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level1"\n}' ) ir.width = 100 ir.height = 200 self.assertEqual( ir.as_json(), '{\n "@context": "http://library.stanford.edu/iiif/image-api/1.1/context.json", \n "@id": "http://example.com/i1", \n "height": 200, \n "profile": "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level1", \n "width": 100\n}' )
def do_GET_body(self): """Create body of GET.""" iiif = self.iiif if (len(self.path) > 1024): raise IIIFError(code=414, text="URI Too Long: Max 1024 chars, got %d\n" % len(self.path)) try: # self.path has leading / then identifier/params... self.path = self.path.lstrip('/') sys.stderr.write("path = %s" % (self.path)) iiif.parse_url(self.path) except Exception as e: # Something completely unexpected => 500 raise IIIFError(code=500, text="Internal Server Error: unexpected exception parsing request (" + str(e) + ")") # Now we have a full iiif request if (re.match('[\w\.\-]+$', iiif.identifier)): file = os.path.join(TESTIMAGE_DIR, iiif.identifier) if (not os.path.isfile(file)): images_available = "" for image_file in os.listdir(TESTIMAGE_DIR): if (os.path.isfile(os.path.join(TESTIMAGE_DIR, image_file))): images_available += " " + image_file + "\n" raise IIIFError(code=404, parameter="identifier", text="Image resource '" + iiif.identifier + "' not found. Local image files available:\n" + images_available) else: raise IIIFError(code=404, parameter="identifier", text="Image resource '" + iiif.identifier + "' not found. Only local test images and http: URIs for images are supported.\n") # Now know image is OK manipulator = IIIFRequestHandler.manipulator_class() # Stash manipulator object so we can cleanup after reading file self.manipulator = manipulator self.compliance_uri = manipulator.compliance_uri if (iiif.info): # get size manipulator.srcfile = file manipulator.do_first() # most of info.json comes from config, a few things # specific to image i = IIIFInfo() i.identifier = self.iiif.identifier i.width = manipulator.width i.height = manipulator.height import io return(io.StringIO(i.as_json()), "application/json") else: (outfile, mime_type) = manipulator.derive(file, iiif) return(open(outfile, 'r'), mime_type)
def test21_tile_width_tile_height(self): """Test getters/setters for tile_width and tile_height.""" i = IIIFInfo(api_version='1.1') self.assertEqual(i.tile_width, None) i.tile_width = 123 self.assertEqual(i.tile_width, 123) self.assertEqual(i.tile_height, 123) i.tile_width = 124 self.assertEqual(i.tile_width, 124) self.assertEqual(i.tile_height, 124) # once height it set, it won't inherit from future width setting i.tile_height = 255 self.assertEqual(i.tile_width, 124) self.assertEqual(i.tile_height, 255) i.tile_width = 345 self.assertEqual(i.tile_width, 345) self.assertEqual(i.tile_height, 255)
def test07_read(self): """Read test.""" i = IIIFInfo() fh = io.StringIO('{ "@id": "no_data" }') i.read(fh, api_version='2.0') self.assertEqual(i.api_version, '2.0') fh = io.StringIO('{ "@id": "no_data" }') self.assertRaises(IIIFInfoError, i.read, fh) # missing identifier cases fh = io.StringIO('{ }') self.assertRaises(IIIFInfoError, i.read, fh, api_version="1.0") fh = io.StringIO('{ }') self.assertRaises(IIIFInfoError, i.read, fh, api_version="2.0") # bad @context fh = io.StringIO('{ "@context": "oops" }') self.assertRaises(IIIFInfoError, i.read, fh) # minimal 1.1 -- @context and @id fh = io.StringIO( '{ "@context": "http://library.stanford.edu/iiif/image-api/1.1/context.json", "@id": "a" }') i.read(fh) self.assertEqual(i.api_version, '1.1')
def test02_id(self): """Test identifier handling.""" i = IIIFInfo() # setter i.id = '' self.assertEqual(i.server_and_prefix, '') self.assertEqual(i.identifier, '') i.id = 'a' self.assertEqual(i.server_and_prefix, '') self.assertEqual(i.identifier, 'a') i.id = 'a/b' self.assertEqual(i.server_and_prefix, 'a') self.assertEqual(i.identifier, 'b') i.id = 'a/b/c' self.assertEqual(i.server_and_prefix, 'a/b') self.assertEqual(i.identifier, 'c') i.id = 'a//b' self.assertEqual(i.server_and_prefix, 'a/') self.assertEqual(i.identifier, 'b') i.id = '/d' self.assertEqual(i.server_and_prefix, '') self.assertEqual(i.identifier, 'd') def xx(value): # FIXME - better way to test setter? i.id = value self.assertRaises(AttributeError, xx, None) self.assertRaises(AttributeError, xx, 123) # property i.server_and_prefix = '' i.identifier = '' self.assertEqual(i.id, '') i.identifier = 'abc' self.assertEqual(i.id, 'abc') i.server_and_prefix = 'def' self.assertEqual(i.id, 'def/abc') i.identifier = '' self.assertEqual(i.id, 'def/')
def test12_read_unknown_context(self): """Test read with bad/unknown @context.""" i = IIIFInfo() fh = open('tests/testdata/info_json_2_0/info_bad_context.json') self.assertRaises(IIIFInfoError, i.read, fh)
def test20_write_example_in_spec(self): """Create example info.json in spec.""" i = IIIFInfo( api_version='2.1', id= "http://www.example.org/image-service/abcd1234/1E34750D-38DB-4825-A38A-B60A345E591C", # "protocol" : "http://iiif.io/api/image", width=6000, height=4000, sizes=[{ "width": 150, "height": 100 }, { "width": 600, "height": 400 }, { "width": 3000, "height": 2000 }], tiles=[{ "width": 512, "scaleFactors": [1, 2, 4] }, { "width": 1024, "height": 2048, "scaleFactors": [8, 16] }], attribution=[{ "@value": "<span>Provided by Example Organization</span>", "@language": "en" }, { "@value": "<span>Darparwyd gan Enghraifft Sefydliad</span>", "@language": "cy" }], logo={ "@id": "http://example.org/image-service/logo/full/200,/0/default.png", "service": { "@context": "http://iiif.io/api/image/2/context.json", "@id": "http://example.org/image-service/logo", "profile": "http://iiif.io/api/image/2/level2.json" } }, license=[ "http://example.org/rights/license1.html", "https://creativecommons.org/licenses/by/4.0/" ], profile=["http://iiif.io/api/image/2/level2.json"], formats=["gif", "pdf"], qualities=["color", "gray"], supports=[ "canonicalLinkHeader", "rotationArbitrary", "profileLinkHeader", "http://example.com/feature/" ], service=[{ "@context": "http://iiif.io/api/annex/service/physdim/1/context.json", "profile": "http://iiif.io/api/annex/service/physdim", "physicalScale": 0.0025, "physicalUnits": "in" }, { "@context": "http://geojson.org/contexts/geojson-base.jsonld", "@id": "http://www.example.org/geojson/paris.json" }]) reparsed_json = json.loads(i.as_json()) example_json = json.load( open('tests/testdata/info_json_2_1/info_from_spec_section_5_6.json' )) self.maxDiff = 4000 self.assertEqual(reparsed_json, example_json)
def test10_read_examples_from_spec(self): """Test reading of examples from spec.""" # Section 5.2, full example i = IIIFInfo(api_version='2.1') fh = open('tests/testdata/info_json_2_1/info_from_spec_section_5_2.json') i.read(fh) self.assertEqual(i.context, "http://iiif.io/api/image/2/context.json") self.assertEqual(i.id, "http://www.example.org/image-service/abcd1234/1E34750D-38DB-4825-A38A-B60A345E591C") self.assertEqual(i.protocol, "http://iiif.io/api/image") self.assertEqual(i.width, 6000) self.assertEqual(i.height, 4000) self.assertEqual(i.sizes, [{"width": 150, "height": 100}, {"width": 600, "height": 400}, {"width": 3000, "height": 2000}]) self.assertEqual(i.tiles, [{"width": 512, "scaleFactors": [1, 2, 4, 8, 16]}]) self.assertEqual(i.profile, ["http://iiif.io/api/image/2/level2.json"]) # extracted information self.assertEqual(i.compliance, "http://iiif.io/api/image/2/level2.json") # and 1.1 style tile properties self.assertEqual(i.tile_width, 512) self.assertEqual(i.tile_height, 512) self.assertEqual(i.scale_factors, [1, 2, 4, 8, 16]) # Section 5.3, full example i = IIIFInfo(api_version='2.1') fh = open('tests/testdata/info_json_2_1/info_from_spec_section_5_3.json') i.read(fh) self.assertEqual(i.context, "http://iiif.io/api/image/2/context.json") self.assertEqual(i.id, "http://www.example.org/image-service/abcd1234/1E34750D-38DB-4825-A38A-B60A345E591C") self.assertEqual(i.protocol, "http://iiif.io/api/image") self.assertEqual(i.width, 4000) self.assertEqual(i.height, 3000) self.assertEqual( i.profile, ["http://iiif.io/api/image/2/level2.json", {"formats": ["gif", "pdf"], "maxWidth": 2000, "qualities": ["color", "gray"], "supports": ["canonicalLinkHeader", "rotationArbitrary", "profileLinkHeader", "http://example.com/feature/"]}]) # extracted information self.assertEqual(i.compliance, "http://iiif.io/api/image/2/level2.json") # Section 5.6, full example i = IIIFInfo(api_version='2.1') fh = open('tests/testdata/info_json_2_1/info_from_spec_section_5_6.json') i.read(fh) self.assertEqual(i.context, "http://iiif.io/api/image/2/context.json") self.assertEqual(i.id, "http://www.example.org/image-service/abcd1234/1E34750D-38DB-4825-A38A-B60A345E591C") self.assertEqual(i.protocol, "http://iiif.io/api/image") self.assertEqual(i.width, 6000) self.assertEqual(i.height, 4000) self.assertEqual(i.sizes, [{"width": 150, "height": 100}, {"width": 600, "height": 400}, {"width": 3000, "height": 2000}])
def test03_level(self): """Test level handling.""" i = IIIFInfo() i.compliance_prefix = 'prefix/' i.compliance_suffix = '/suffix' # and good i.compliance = 'prefix/2/suffix' self.assertEqual(i.level, 2) i.compliance = 'prefix/3/suffix' self.assertEqual(i.level, 3) # and bad i.compliance = '' # FIXME: how to avoid wrapping @property call in lamda? self.assertRaises(IIIFInfoError, lambda: i.level) i.compliance = 'prefix//suffix' self.assertRaises(IIIFInfoError, lambda: i.level) i.compliance = 'prefix/22/suffix' self.assertRaises(IIIFInfoError, lambda: i.level) i.compliance = 'prefix/junk/suffix' self.assertRaises(IIIFInfoError, lambda: i.level) i.compliance = 'extra/prefix/2/suffix' self.assertRaises(IIIFInfoError, lambda: i.level) i.compliance = '...2/suffix' self.assertRaises(IIIFInfoError, lambda: i.level) i.compliance = 'prefix/2...' self.assertRaises(IIIFInfoError, lambda: i.level) i.compliance = 'prefix/2/suffix/extra' self.assertRaises(IIIFInfoError, lambda: i.level)
def test03_set_version_info(self): """Test setting of version information.""" i = IIIFInfo() self.assertRaises(IIIFInfoError, i.set_version_info, api_version='9.9')
def test20_write_full_example_in_spec(self): """Create example info.json in spec.""" i = IIIFInfo( api_version='3.0', id= "https://example.org/image-service/abcd1234/1E34750D-38DB-4825-A38A-B60A345E591C", # "protocol" : "http://iiif.io/api/image", width=6000, height=4000, sizes=[{ "width": 150, "height": 100 }, { "width": 600, "height": 400 }, { "width": 3000, "height": 2000 }], tiles=[{ "width": 512, "scaleFactors": [1, 2, 4] }, { "width": 1024, "height": 2048, "scaleFactors": [8, 16] }], attribution=[{ "@value": "<span>Provided by Example Organization</span>", "@language": "en" }, { "@value": "<span>Darparwyd gan Enghraifft Sefydliad</span>", "@language": "cy" }], logo={ "id": "https://example.org/image-service/logo/square/200,200/0/default.png", "service": [{ "id": "https://example.org/image-service/logo", "profile": "level2", 'type': 'ImageService3' }] }, license=[ "https://example.org/rights/license1.html", "http://rightsstatements.org/vocab/InC-EDU/1.0/" ], profile="level1", extra_formats=["gif", "pdf"], extra_qualities=["color", "gray"], extra_features=[ "canonicalLinkHeader", "rotationArbitrary", "profileLinkHeader" ], service=[{ 'id': 'http://example.org/fix/me' }]) i.add_context("http://example.org/extension/context1.json") reparsed_json = json.loads(i.as_json()) example_json = json.load( self.open_testdata('info_from_spec_section_5_8.json')) self.maxDiff = 4000 self.assertEqual(reparsed_json, example_json)
def test10_read_examples_from_spec(self): """Test reading of examples from spec.""" # Section 5.2, max dimensions i = IIIFInfo(api_version='3.0') fh = self.open_testdata('info_from_spec_section_5_2.json') i.read(fh) self.assertEqual(i.context, "http://iiif.io/api/image/3/context.json") self.assertEqual( i.id, "https://example.org/image-service/abcd1234/1E34750D-38DB-4825-A38A-B60A345E591C" ) self.assertEqual(i.resource_type, "ImageService3") self.assertEqual(i.protocol, "http://iiif.io/api/image") self.assertEqual(i.width, 6000) self.assertEqual(i.height, 4000) # Section 5.3, sizes i = IIIFInfo(api_version='3.0') fh = self.open_testdata('info_from_spec_section_5_3.json') i.read(fh) self.assertEqual(i.context, "http://iiif.io/api/image/3/context.json") self.assertEqual( i.id, "https://example.org/image-service/abcd1234/1E34750D-38DB-4825-A38A-B60A345E591C" ) self.assertEqual(i.resource_type, "ImageService3") self.assertEqual(i.protocol, "http://iiif.io/api/image") self.assertEqual(i.width, 6000) self.assertEqual(i.height, 4000) self.assertEqual(i.sizes, [{ "width": 150, "height": 100 }, { "width": 600, "height": 400 }, { "width": 3000, "height": 2000 }]) self.assertEqual(i.profile, "level2") self.assertEqual(i.compliance, "level2") # Section 5.4, tiles i = IIIFInfo(api_version='3.0') fh = self.open_testdata('info_from_spec_section_5_4.json') i.read(fh) self.assertEqual(i.context, "http://iiif.io/api/image/3/context.json") self.assertEqual( i.id, "https://example.org/image-service/abcd1234/1E34750D-38DB-4825-A38A-B60A345E591C" ) self.assertEqual(i.resource_type, "ImageService3") self.assertEqual(i.protocol, "http://iiif.io/api/image") self.assertEqual(i.width, 6000) self.assertEqual(i.height, 4000) self.assertEqual(i.tiles, [{ "width": 512, "scaleFactors": [1, 2, 4, 8, 16] }]) self.assertEqual(i.profile, "level2") self.assertEqual(i.compliance, "level2") # and 1.1 style tile properties self.assertEqual(i.tile_width, 512) self.assertEqual(i.tile_height, 512) self.assertEqual(i.scale_factors, [1, 2, 4, 8, 16]) # Section 5.5, rights etc. i = IIIFInfo(api_version='3.0') fh = self.open_testdata('info_from_spec_section_5_5.json') i.read(fh) self.assertEqual(i.context, "http://iiif.io/api/image/3/context.json") self.assertEqual( i.id, "https://example.org/image-service/abcd1234/1E34750D-38DB-4825-A38A-B60A345E591C" ) self.assertEqual(i.protocol, "http://iiif.io/api/image") self.assertEqual(i.width, 6000) self.assertEqual(i.height, 4000) self.assertEqual(i.profile, "level2") self.assertEqual(i.attribution, "Provided by Example Organization") self.assertEqual(i.logo, "https://example.org/images/logo.png") self.assertEqual(i.license, "http://rightsstatements.org/vocab/InC-EDU/1.0/") # Section 5.7, simple service i = IIIFInfo(api_version='3.0') fh = self.open_testdata('info_from_spec_section_5_7.json') i.read(fh) self.assertEqual(i.context, "http://iiif.io/api/image/3/context.json") self.assertEqual( i.id, "https://example.org/image-service/abcd1234/1E34750D-38DB-4825-A38A-B60A345E591C" ) self.assertEqual(i.protocol, "http://iiif.io/api/image") self.assertEqual(i.width, 6000) self.assertEqual(i.height, 4000) self.assertEqual(i.profile, "level2") self.assertEqual(i.compliance, "level2") self.assertEqual(i.service, [{ "@id": "https://example.org/auth/login.html", "@type": "AuthCookieService1", "profile": "http://iiif.io/api/auth/1/login" }]) # Section 5.8, full example i = IIIFInfo(api_version='3.0') fh = self.open_testdata('info_from_spec_section_5_8.json') i.read(fh) self.assertEqual(i.context, "http://iiif.io/api/image/3/context.json") self.assertEqual( i.id, "https://example.org/image-service/abcd1234/1E34750D-38DB-4825-A38A-B60A345E591C" ) self.assertEqual(i.protocol, "http://iiif.io/api/image") self.assertEqual(i.width, 6000) self.assertEqual(i.height, 4000) self.assertEqual(i.sizes, [{ "width": 150, "height": 100 }, { "width": 600, "height": 400 }, { "width": 3000, "height": 2000 }])
def test20_read_unknown_contect(self): i = IIIFInfo() fh = open('test_info/1.1/info_bad_context.json') self.assertRaises(Exception, i.read, fh)
def test03_array_vals(self): i = IIIFInfo(api_version='1.1') i.scale_factors = [1, 2, 3] self.assertEqual(i.scale_factors, [1, 2, 3]) i.set('scale_factors', [4, 5, 6]) self.assertEqual(i.scale_factors, [4, 5, 6])
def test04_conf(self): conf = {'tile_width': 999, 'scale_factors': [9, 8, 7]} i = IIIFInfo(conf=conf, api_version='1.1') self.assertEqual(i.tile_width, 999) self.assertEqual(i.scale_factors, [9, 8, 7])
def test21_write_profile(self): """Test writing of profile information.""" i = IIIFInfo( api_version='2.1', id="http://example.org/svc/a", width=1, height=2, profile=['pfl'], formats=["fmt1", "fmt2"]) j = json.loads(i.as_json()) self.assertEqual(len(j['profile']), 2) self.assertEqual(j['profile'][0], 'pfl') self.assertEqual(j['profile'][1], {'formats': ['fmt1', 'fmt2']}) i = IIIFInfo( api_version='2.1', id="http://example.org/svc/a", width=1, height=2, profile=['pfl'], qualities=None) j = json.loads(i.as_json()) self.assertEqual(len(j['profile']), 1) self.assertEqual(j['profile'][0], 'pfl') i = IIIFInfo( api_version='2.1', id="http://example.org/svc/a", width=1, height=2, profile=['pfl'], qualities=['q1', 'q2', 'q0']) j = json.loads(i.as_json()) self.assertEqual(len(j['profile']), 2) self.assertEqual(j['profile'][0], 'pfl') self.assertEqual(j['profile'][1], {'qualities': ['q1', 'q2', 'q0']}) i = IIIFInfo( api_version='2.1', id="http://example.org/svc/a", width=1, height=2, profile=['pfl'], supports=['a', 'b']) j = json.loads(i.as_json()) self.assertEqual(len(j['profile']), 2) self.assertEqual(j['profile'][0], 'pfl') self.assertEqual(j['profile'][1], {'supports': ['a', 'b']}) i = IIIFInfo( api_version='2.1', id="http://example.org/svc/a", width=1, height=2, profile=['pfl'], formats=["fmt1", "fmt2"], qualities=['q1', 'q2', 'q0'], supports=['a', 'b']) j = json.loads(i.as_json()) self.assertEqual(len(j['profile']), 2) self.assertEqual(j['profile'][0], 'pfl') self.assertEqual(j['profile'][1]['formats'], ['fmt1', 'fmt2']) self.assertEqual(j['profile'][1]['qualities'], ['q1', 'q2', 'q0']) self.assertEqual(j['profile'][1]['supports'], ['a', 'b'])
def test04_conf(self): """Test configuration via conf parameter.""" conf = {'tile_width': 999, 'scale_factors': [9, 8, 7]} i = IIIFInfo(api_version='1.1', conf=conf) self.assertEqual(i.tile_width, 999) self.assertEqual(i.scale_factors, [9, 8, 7])
def test02_scale_factor(self): ir = IIIFInfo(width=199,height=299,tile_width=100,tile_height=100,scale_factors=[1,2]) #self.assertRegexpMatches( ir.as_json(validate=False), r'"scaleFactors": \[\s*1' ) #,\s*2\s*]' ) #no assertRegexpMatches in 2.6 json = ir.as_json(validate=False) self.assertTrue( re.search(r'"width": 100',json) ) self.assertTrue( re.search(r'"scaleFactors": \[\s*1',json) )
def test20_read_unknown_context(self): """Test attempt to read document with bad/unknown @context.""" i = IIIFInfo() fh = open('tests/testdata/info_json_1_0/info_bad_context.json') self.assertRaises(IIIFInfoError, i.read, fh)
def do_GET(self): """Implement the HTTP GET method The bulk of this code is wrapped in a big try block and anywhere within the code may raise an IIIFError which then results in an IIIF error response (section 5 of spec). """ self.compliance_level=None # We take prefix to see whe implementation to use, / is special info if (self.path == '/'): return self.send_top_level_index_page() # Test code... m = re.match(r'/response_test/(\d\d\d)$', self.path) if (m): status=int(m.group(1)) # WHAT DOES NULL info.json look like? # https://github.com/IIIF/auth/issues/2 self.api_version='2.0' i = IIIFInfo(api_version=self.api_version) i.identifier = 'abc' i.width = 0 i.height = 0 i.service = { '@context': 'http://example.org/auth_context.json', '@id': "http://example.com/authn_here", 'label': "Authenticate here" } return self.send_json_response(json=i.as_json(),status=status) # Is this a request for a prefix index page? m = re.match(r'/([\w\._]+)$', self.path) if (m and m.group(1) in IIIFRequestHandler.MANIPULATORS): return self.send_prefix_index_page(m.group(1)) # Is this a request for a test page? m = re.match(r'/([\w\._]+)$', self.path) if (m): page_path = os.path.join(IIIFRequestHandler.PAGES_DIR,m.group(1)) if (os.path.isfile(page_path)): return self.send_html_file(page_path) # Now assume we have an iiif request m = re.match(r'/([\w\._]+)/(.*)$', self.path) if (m): self.prefix = m.group(1) self.path = m.group(2) if (self.prefix in IIIFRequestHandler.MANIPULATORS): self.api_version = IIIFRequestHandler.MANIPULATORS[self.prefix]['api_version'] self.iiif = IIIFRequest(baseurl='/'+self.prefix+'/',api_version=self.api_version) self.manipulator = IIIFRequestHandler.MANIPULATORS[self.prefix]['klass'](api_version=self.api_version) self.auth_type = IIIFRequestHandler.MANIPULATORS[self.prefix]['auth_type'] else: # 404 - unrecognized prefix self.send_404_response("Not Found - prefix /%s/ is not known" % (self.prefix)) return else: # 404 - unrecognized path structure self.send_404_response("Not Found - path structure not recognized") return try: self.do_GET_body() except IIIFError as e: e.text += " Request parameters: "+str(self.iiif) self.write_error_response(e) except Exception as ue: # Anything else becomes a 500 Internal Server Error sys.stderr.write(str(ue)+"\n") self.write_error_response(IIIFError(code=500,text="Something went wrong... %s.\n"%(str(ue))))
def test02_id(self): """Test identifier handling.""" i = IIIFInfo() # setter i.id = '' self.assertEqual(i.server_and_prefix, '') self.assertEqual(i.identifier, '') i.id = 'a' self.assertEqual(i.server_and_prefix, '') self.assertEqual(i.identifier, 'a') i.id = 'a/b' self.assertEqual(i.server_and_prefix, 'a') self.assertEqual(i.identifier, 'b') i.id = 'a/b/c' self.assertEqual(i.server_and_prefix, 'a/b') self.assertEqual(i.identifier, 'c') i.id = 'a//b' self.assertEqual(i.server_and_prefix, 'a/') self.assertEqual(i.identifier, 'b') i.id = '/d' self.assertEqual(i.server_and_prefix, '') self.assertEqual(i.identifier, 'd') # id setter self.assertRaises(AttributeError, setattr, i, 'id', None) self.assertRaises(AttributeError, setattr, i, 'id', 123) # property i.server_and_prefix = '' i.identifier = '' self.assertEqual(i.id, '') i.identifier = 'abc' self.assertEqual(i.id, 'abc') i.server_and_prefix = 'def' self.assertEqual(i.id, 'def/abc') i.identifier = '' self.assertEqual(i.id, 'def/')
def do_GET_body(self): iiif=self.iiif if (len(self.path)>1024): raise IIIFError(code=414, text="URI Too Long: Max 1024 chars, got %d\n" % len(self.path)) #print "GET " + self.path try: iiif.parse_url(self.path) except IIIFRequestBaseURI as e: info_uri = self.server_and_prefix + '/' + urllib.quote(self.iiif.identifier) + '/info.json' raise IIIFError(code=303, headers={'Location': info_uri}) except IIIFError as e: # Pass through raise e except Exception as e: # Something completely unexpected => 500 raise IIIFError(code=500, text="Internal Server Error: unexpected exception parsing request (" + str(e) + ")") # URL path parsed OK, now determine how to handle request if (re.match('[\w\.\-]+$',iiif.identifier)): file = os.path.join(IIIFRequestHandler.IMAGE_DIR,iiif.identifier) if (not os.path.isfile(file)): images_available="" for image_file in os.listdir(IIIFRequestHandler.IMAGE_DIR): if (os.path.isfile(os.path.join(IIIFRequestHandler.IMAGE_DIR,image_file))): images_available += " "+image_file+"\n" raise IIIFError(code=404,parameter="identifier", text="Image resource '"+iiif.identifier+"' not found. Local image files available:\n" + images_available) else: raise IIIFError(code=404,parameter="identifier", text="Image resource '"+iiif.identifier+"' not found. Only local test images and http: URIs for images are supported.\n") # self.compliance_level=self.manipulator.complianceLevel # Do we have auth? if (self.auth_type == 'basic'): auth_map = parse_authorization_header(self.headers.get('Authorization','')) if (auth_map and auth_map['type']=='basic' and auth_map['username']+':'+auth_map['password']==IIIFRequestHandler.USER_PASS): # authz, continue pass else: # failed, send 401 with null image info, no service link for auth as # basic auth is all done via the WWW-Authenticate header i = IIIFInfo(api_version=self.api_version) i.identifier = 'null' i.width = 0 i.height = 0 return self.send_json_response(json=i.as_json(),status=401) if (self.iiif.info): # get size self.manipulator.srcfile=file self.manipulator.do_first() # most of info.json comes from config, a few things specific to image i = IIIFInfo(conf=IIIFRequestHandler.INFO,api_version=self.api_version) i.server_and_prefix = self.server_and_prefix i.identifier = self.iiif.identifier i.width = self.manipulator.width i.height = self.manipulator.height i.qualities = [ "native", "color" ] #FIXME - should come from manipulator i.formats = [ "jpg", "png" ] #FIXME - should come from manipulator return self.send_json_response(i.as_json(),200) else: if (self.api_version<'2.0' and self.iiif.format is None and 'Accept' in self.headers): # In 1.0 and 1.1 conneg was specified as an alternative to format, see: # http://iiif.io/api/image/1.0/#format # http://iiif.io/api/image/1.1/#parameters-format formats = { 'image/jpeg': 'jpg', 'image/tiff': 'tif', 'image/png': 'png', 'image/gif': 'gif', 'image/jp2': 'jps', 'application/pdf': 'pdf' } accept = do_conneg( self.headers['Accept'], formats.keys() ) # Ignore Accept header if not recognized, should this be an error instead? if (accept in formats): self.iiif.format = formats[accept] (outfile,mime_type)=self.manipulator.derive(file,iiif) return self.send_good_response(open(outfile,'r'),mime_type)
def test04_json_key(self): """Test json_key().""" i = IIIFInfo() self.assertEqual(i.json_key(None), None) self.assertEqual(i.json_key(''), '') self.assertEqual(i.json_key('abc'), 'abc') i.set_version_info('3.0') self.assertEqual(i.json_key(None), None) self.assertEqual(i.json_key(''), '') self.assertEqual(i.json_key('abc'), 'abc') self.assertEqual(i.json_key('resource_type'), 'type')
def test02_scale_factor(self): """Test scale factor.""" ir = IIIFInfo(width=1, height=2, scale_factors=[ 1, 2], api_version='1.0') json = ir.as_json(validate=False) self.assertRegexpMatches(json, r'"scale_factors": \[\s*1')
def test12_read_unknown_context(self): """Test bad/unknown context.""" i = IIIFInfo(api_version='2.1') fh = open('tests/testdata/info_json_2_1/info_bad_context.json') self.assertRaises(Exception, i.read, fh)
def test12_read_example_with_unknown_context(self): """Test read with unknown/bad context.""" i = IIIFInfo() fh = open('tests/testdata/info_json_1_1/info_bad_context.json') self.assertRaises(Exception, i.read, fh)