Skip to content

Commit

Permalink
Merge pull request #83 from iiif-prezi/pr-updates
Browse files Browse the repository at this point in the history
Outstanding PR fixes
  • Loading branch information
digitaldogsbody authored Oct 6, 2022
2 parents 7c61ce7 + c57a983 commit 70138dd
Show file tree
Hide file tree
Showing 15 changed files with 188 additions and 23 deletions.
10 changes: 6 additions & 4 deletions iiif_prezi3/helpers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
from .annotation_helpers import AnnotationHelpers # noqa: F401
from .add_item import AddItem, AddItemByReference # noqa: F401
from .add_label import AddLabel # noqa: F401
from .add_metadata import AddMetadata # noqa: F401
from .add_range import AddRange # noqa: F401
from .annotation_helpers import AnnotationHelpers # noqa: F401
from .auto_fields import * # noqa: F401,F403
from .canvas_helpers import AddImageToCanvas # noqa: F401
from .canvas_sizes import MaxHelper, MinHelper # noqa: F401
from .make_collection import MakeCollection # noqa: F401
from .make_manifest import MakeManifest # noqa: F401
from .add_range import AddRange # noqa: F401
from .make_collection import MakeCollection # noqa: F401
from .make_manifest import MakeManifest # noqa: F401
from .set_hwd import SetHwd # noqa: F401
from .set_hwd_from_file import SetHeightWidthDurationFileHelper # noqa: F401
from .set_hwd_from_iiif import SetHwdFromIIIF # noqa: F401
from .to_reference import ToReference # noqa: F401
5 changes: 3 additions & 2 deletions iiif_prezi3/helpers/add_metadata.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from ..skeleton import Canvas, Collection, KeyValueString, LngString, Manifest, Range
from ..loader import monkeypatch_schema
from ..skeleton import (Canvas, Collection, KeyValueString, LngString,
Manifest, Range)


class AddMetadata:

def add_metadata(self, label, value):
#Validate incoming data
# Validate incoming data
criteria = [
label and value,
type(label) is type(value),
Expand Down
2 changes: 1 addition & 1 deletion iiif_prezi3/helpers/add_range.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from ..skeleton import Manifest, Range
from ..loader import monkeypatch_schema
from ..skeleton import Manifest


class AddRange:
Expand Down
6 changes: 3 additions & 3 deletions iiif_prezi3/helpers/make_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
class MakeCollection:

def make_collection(self, **kwargs):
"""
"""Create a Collection.
Creates a new collection, adds it to the calling Collection `items`
and returns the newly created object. Accepts keyword arguments to
and returns the newly created object. Accepts keyword arguments to
customize the resulting instance.
"""

child_collection = Collection(**kwargs)
self.add_item(child_collection)
return child_collection
Expand Down
6 changes: 3 additions & 3 deletions iiif_prezi3/helpers/make_manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
class MakeManifest:

def make_manifest(self, **kwargs):
"""
Creates a new Manifest, adds a Reference to it to the
"""Add a Manifest to a Collection.
Creates a new Manifest, adds a Reference to it to the
calling Collection items and returns the newly created Manifest.
Accepts keyword arguments to customize the resulting instance.
"""

manifest = Manifest(**kwargs)
self.add_item(manifest)
return manifest
Expand Down
32 changes: 32 additions & 0 deletions iiif_prezi3/helpers/set_hwd_from_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import mimetypes
import os

from PIL import Image

from ..loader import monkeypatch_schema
from ..skeleton import Canvas


class SetHeightWidthDurationFileHelper:
"""Introspect a file and set the height, width, and duration properties.
Args:
file_path_or_object (filepath or fileobject): the file path or file object to introspect
Returns:
None
"""

def set_hwd_from_file(self, file_path_or_object):
if isinstance(file_path_or_object, str) or isinstance(file_path_or_object, os.PathLike):
filetype, _ = mimetypes.guess_type(file_path_or_object)
if not filetype.startswith("image/"):
raise NotImplementedError

tmp_image = Image.open(file_path_or_object)
w, h = tmp_image.size
self.set_hwd(h, w, None)
tmp_image.close()


monkeypatch_schema(Canvas, SetHeightWidthDurationFileHelper)
35 changes: 35 additions & 0 deletions iiif_prezi3/helpers/set_hwd_from_iiif.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import requests

from ..loader import monkeypatch_schema
from ..skeleton import Canvas


class SetHwdFromIIIF:
# should probably be added to canvas helpers

def set_hwd_from_iiif(self, url):
"""Set height and width on a Canvas object.
Requests IIIF Image information remotely for an
image resource and sets resulting height and width.
Args:
url (str): An HTTP URL for the IIIF image endpoint.
"""
# resource url may or may not end with info.json;
# add if not present
if not url.endswith("info.json"):
url = f"{ url.rstrip('/') }/info.json"

response = requests.get(url)
# if response is not 200, raise exception
if response.status_code != requests.codes.ok:
response.raise_for_status()
# if response is not valid json, request will raise
# requests.exceptions.JSONDecodeError
# — handle or document and let calling code handle?
resource_info = response.json()
self.set_hwd(resource_info.get("height"), resource_info.get("width"))


monkeypatch_schema(Canvas, [SetHwdFromIIIF])
1 change: 1 addition & 0 deletions requirements.dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ flake8>=4.0.1,<5.0.0
flake8-docstrings>=1.6.0,<2.0.0
flake8-isort>=4.1.1,<5.0.0
tox>=3.25.0,<4.0.0
Pillow>=9.1.1
12 changes: 7 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
VERSION = "local_test_version"

REQUIREMENTS = [
"pydantic"
"pydantic",
"requests",
"Pillow"
]

DOCS_REQUIREMENTS = [
Expand All @@ -24,10 +26,10 @@

# Setting up
setup(
name='iiif-prezi3',
name="iiif-prezi3",
version=VERSION,
author='IIIF Prezi3 Team',
description='IIIF Presentation v3 API implementation',
author="IIIF Prezi3 Team",
description="IIIF Presentation v3 API implementation",
long_description=long_description,
long_description_content_type='text/markdown',
packages=['iiif_prezi3', 'iiif_prezi3.helpers', 'iiif_prezi3.extensions'],
Expand All @@ -52,7 +54,7 @@
url='https://github.com/iiif-prezi/iiif-prezi3',
license='Apache License, Version 2.0',
install_requires=REQUIREMENTS,
extras_require={
extras_require={
"docs": DOCS_REQUIREMENTS,
},
)
Binary file added tests/fixtures/resources/page1-full.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 5 additions & 5 deletions tests/test_add_metadata.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
import unittest

from iiif_prezi3 import Collection, Manifest, Canvas, Range, LngString
from iiif_prezi3 import Collection, LngString


class AddMetadataTest(unittest.TestCase):
def setUp(self):
self.collection = Collection();
self.collection = Collection()

def test_add_metadata_string(self):
self.collection.add_metadata("label", "value");
self.collection.add_metadata("label", "value")
assert isinstance(self.collection.metadata, list)
assert self.collection.metadata[-1].label == {'none': ['label']}
assert self.collection.metadata[-1].value == {'none': ['value']}

def test_add_metadata_dict(self):
label = {"en": ["label"]}
value = {"en": ["value"]}
self.collection.add_metadata(label, value);
self.collection.add_metadata(label, value)
assert isinstance(self.collection.metadata, list)
assert self.collection.metadata[-1].label == {'en': ['label']}
assert self.collection.metadata[-1].value == {'en': ['value']}

def test_add_metadata_lngstring(self):
label = LngString(__root__={'en': ['label']})
value = LngString(__root__={'en': ['value']})
self.collection.add_metadata(label, value);
self.collection.add_metadata(label, value)
assert isinstance(self.collection.metadata, list)
assert self.collection.metadata[-1].label == {'en': ['label']}
assert self.collection.metadata[-1].value == {'en': ['value']}
Expand Down
1 change: 1 addition & 0 deletions tests/test_add_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from iiif_prezi3 import Manifest, Range


class AddRangeTest(unittest.TestCase):
def setUp(self):
self.manifest = Manifest(label="manifest")
Expand Down
25 changes: 25 additions & 0 deletions tests/test_set_hwd_from_file_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import unittest

from iiif_prezi3 import Canvas


class SetHeightWidthDurationFileHelperTests(unittest.TestCase):
def setUp(self):
self.canvas = Canvas(id="http://iiif.example.org/prezi/Canvas/0")
self.test_image = "tests/fixtures/resources/page1-full.png"

def test_set_hwd_from_filepath_notimage(self):
self.assertRaises(NotImplementedError, self.canvas.set_hwd_from_file, "foo.mp3")

def test_set_hwd_from_filepath(self):
self.canvas.set_hwd_from_file(self.test_image)
self.assertEqual(self.canvas.width, 1200) # width
self.assertEqual(self.canvas.height, 1800) # height
self.assertEqual(self.canvas.duration, None) # duration

def test_set_hwd_from_fileobject(self):
with open(self.test_image, "rb") as image_file:
self.canvas.set_hwd_from_file(image_file)
self.assertEqual(self.canvas.width, 1200) # width
self.assertEqual(self.canvas.height, 1800) # height
self.assertEqual(self.canvas.duration, None) # duration
63 changes: 63 additions & 0 deletions tests/test_set_hwd_from_iiif.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import unittest
from unittest.mock import Mock, patch

import requests

from iiif_prezi3 import Canvas


class SetHwdFromIIIFTests(unittest.TestCase):

def setUp(self):
self.canvas = Canvas(id='http://iiif.example.org/prezi/Canvas/0')

@patch('iiif_prezi3.helpers.set_hwd_from_iiif.requests.get')
def test_set_hwd_from_iiif(self, mockrequest_get):
image_id = 'http://iiif.example.org/images/1234abcd'
image_info_url = f'{image_id}/info.json'
# image api url without info.json
self.canvas.set_hwd_from_iiif(image_id)
mockrequest_get.assert_called_with(image_info_url)

# image api url with info.json
mockrequest_get.reset_mock()
self.canvas.set_hwd_from_iiif(image_id)
mockrequest_get.assert_called_with(image_info_url)

# image url with trailing slash
mockrequest_get.reset_mock()
self.canvas.set_hwd_from_iiif(image_id + "/")
mockrequest_get.assert_called_with(image_info_url)

# non-200 response
mockresponse = Mock(status_code=404)
# This is necessary otherwise the mocked response correctly calls raise_for_status, but doesn't terminate the
# code flow like it would in normal usage (because there's not actually an exception) so it would try and call
# set_hwd with non-existent values and error out incorrectly.
mockresponse.raise_for_status.side_effect = requests.exceptions.HTTPError
mockrequest_get.return_value = mockresponse
with self.assertRaises(requests.exceptions.HTTPError):
self.canvas.set_hwd_from_iiif(image_id)
# non-200 should raise exception for status
mockresponse.raise_for_status.assert_called_once()

# 200 response but not valid json should raise exception
mockresponse.status_code = 200
mockresponse.json.side_effect = requests.exceptions.JSONDecodeError("", "", 0) # JSONDecodeError needs arguments
with self.assertRaises(requests.exceptions.JSONDecodeError):
self.canvas.set_hwd_from_iiif(image_id)

# successful response with dimensions
mockresponse.json.side_effect = None
# set mock to return minimal image api response
mockresponse.json.return_value = {
"@context": "http://iiif.io/api/image/2/context.json",
"@id": image_id,
"protocol": "http://iiif.io/api/image",
"width": 4821,
"height": 6608
}
# patch the method this helper calls so we can inspect
with patch.object(Canvas, 'set_hwd') as mock_set_hwd:
self.canvas.set_hwd_from_iiif(image_id)
mock_set_hwd.assert_called_with(6608, 4821)
3 changes: 3 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ python =
[testenv]
deps =
pydantic
Pillow
requests

skip_install = True
commands =
python -m unittest discover -s tests
Expand Down

0 comments on commit 70138dd

Please sign in to comment.