class PresentationManifestTester(unittest.TestCase): def __init__(self, *args, **kwargs): super(PresentationManifestTester, self).__init__(*args, **kwargs) self.book_pages = [ ("agrtfhs:2279", 1), ("agrtfhs:2278", 2), ("agrtfhs:2291", 3), ("agrtfhs:2290", 4), ("agrtfhs:2289", 5), ("agrtfhs:2288", 6), ("agrtfhs:2287", 7), ("agrtfhs:2286", 8), ("agrtfhs:2285", 9), ("agrtfhs:2284", 10), ("agrtfhs:2283", 11), ("agrtfhs:2282", 12), ("agrtfhs:2281", 13), ("agrtfhs:2280", 14), ("agrtfhs:2277", 15), ("agrtfhs:2276", 16), ] self.metadata = MODSScraper( "agrtfhs:2275").build_iiif_descriptive_metadata_v2() self.collection = "collections:agrtfhs" self.validator = IIIFValidator(debug=True, collect_warnings=False) def test_presentation_manifest(self): manifest = Manifest(self.metadata, self.book_pages, self.collection) self.validator.validate(manifest.manifest_json) self.assertTrue(self.validator.is_valid)
def get_archivelab_org_validator(): class PatchedManifestValidator(ManifestValidator): # Replace the image API with the presentation API at manifest level. def context_field(self, value): if value == 'http://iiif.io/api/image/2/context.json': self.log_warning("@context", "Applied library specific corrections. " "Replaced image context with presentation context.") return self.PRESENTATION_API_URI return value class PatchedSequenceValidator(SequenceValidator): @SequenceValidator.errors_to_warnings def context_field(self, value): return super().context_field(value) class PatchedAnnotationValidator(AnnotationValidator): REQUIRED_FIELDS = AnnotationValidator.REQUIRED_FIELDS - {"on", "@type"} def setup(self): self.ImageSchema['type'] = self.type_field iv = IIIFValidator() iv.ManifestValidator = PatchedManifestValidator iv.AnnotationValidator = PatchedAnnotationValidator iv.SequenceValidator = PatchedSequenceValidator return iv
def test_iiif_manifest_schema(running_app, es_clear, client_with_login, headers, minimal_record): client = client_with_login file_id = "test_image.png" recid = publish_record_with_images(client, file_id, minimal_record, headers) response = client.get(f"/iiif/record:{recid}/manifest") manifest = response.json validator = IIIFValidator(fail_fast=False) validator.validate(manifest) assert not validator.errors
def get_vatlib_it_validator(): class PatchedAnnotationValidator(AnnotationValidator): def setup(self): self.REQUIRED_FIELDS = AnnotationValidator.REQUIRED_FIELDS - {"on"} self.RECOMMENDED_FIELDS = AnnotationValidator.RECOMMENDED_FIELDS & {"on"} class PatchedCanvasValidator(CanvasValidator): def viewing_hint_field(self, value): val, errs = self.mute_errors(super().viewing_hint_field, value) if errs: if val == "paged": self.log_warning("viewingHint", "Applied library specific corrections. Allowd value 'paged'.") iv = IIIFValidator() iv.AnnotationValidator = PatchedAnnotationValidator iv.CanvasValidator = PatchedCanvasValidator return iv
def get_harvard_edu_validator(): def str_to_int(self, field, value): """Coerce strings to ints.""" if isinstance(value, int): return value try: val = int(value) self.log_warning(field, "Coerced to int.") return val except ValueError: self.log_error(field, "Could not coerce to int.") return value BaseValidator.width_field = lambda self, value: str_to_int(self, "width", value) BaseValidator.height_field = lambda self, value: str_to_int(self, "height", value) class PatchedImageContentValidator(ImageContentValidator): def service_field(self, value): """Add a context to the service if none exists.""" val, errs = self.mute_errors(super().service_field, value) if not val.get('@context'): val['@context'] = 'http://library.stanford.edu/iiif/image-api/1.1/context.json' self.log_warning("@context", "Applied library specific corrections. Added @context to images.") return val class PatchedManifestValidator(ManifestValidator): @ManifestValidator.errors_to_warnings def context_field(self, value): """Allow the unknown top level context (since it doesn't seem to break things)""" return super().context_field(value) @ManifestValidator.errors_to_warnings def license_field(self, value): """Allow non uri in license field.""" return super().license_field(value) iv = IIIFValidator() iv.ManifestValidator = PatchedManifestValidator iv.ImageContentValidator = PatchedImageContentValidator return iv
def get_gallica_bnf_fr_validator(): class PatchedManifestValidator(ManifestValidator): # Squash the lang-val pairs down to one value, separated by semicolon. def metadata_field(self, value): """Correct any metadata entries missing a language key in lang-val pairs.""" values, errs = self.mute_errors(super().metadata_field, value) if not errs: return values for value in values: v = value.get('value') if isinstance(v, list) and not all(vsub.get("@language") for vsub in v): value['value'] = "; ".join((vsub.get("@value", "") for vsub in v)) self.log_warning("metadata", "Applied library specific corrections: " "metadata field bad formatting ignored.") return values iv = IIIFValidator() iv.ManifestValidator = PatchedManifestValidator return iv