From ff9b87d5a986196395eb95a1396869f9e51a9d46 Mon Sep 17 00:00:00 2001 From: Tim Sherratt Date: Mon, 4 Apr 2022 13:23:29 +1000 Subject: [PATCH] Better handling of errors --- api.ipynb | 155 ++++++++++++++++++++++---------------- docs/api.html | 103 ++++++++++++------------- omeka_s_tools/__init__.py | 2 +- omeka_s_tools/api.py | 51 +++++++++---- settings.ini | 2 +- 5 files changed, 181 insertions(+), 132 deletions(-) diff --git a/api.ipynb b/api.ipynb index 959cf1d..74a9d3f 100644 --- a/api.ipynb +++ b/api.ipynb @@ -29,6 +29,7 @@ "import random\n", "import os\n", "from copy import deepcopy\n", + "import pytest\n", "%load_ext dotenv\n", "%dotenv" ] @@ -68,6 +69,22 @@ " def clear_cache():\n", " self.s.cache.clear()\n", " \n", + " def process_response(self, response):\n", + " '''\n", + " Handle Omeka responses, raising exceptions on errors.\n", + " '''\n", + " # Raise exception on HTTP error\n", + " response.raise_for_status()\n", + " # Try extracting JSON data\n", + " try:\n", + " data = response.json()\n", + " # If there's no JSON, display the raw response text and raise exception\n", + " except (json.decoder.JSONDecodeError, ValueError):\n", + " print(f'Bad JSON: {response.text}')\n", + " raise\n", + " else:\n", + " return data\n", + " \n", " def format_resource_id(self, resource_id, resource_type):\n", " '''\n", " Generate a formatted id for the resource with the specified Omeka id number and resource type.\n", @@ -100,8 +117,8 @@ " * `results` - a list of dicts, each containing a JSON-LD formatted representation of a resource\n", " '''\n", " response = self.s.get(f'{self.api_url}/{resource_type}/', params=kwargs)\n", - " results = response.json()\n", - " return {'total_results': int(response.headers['Omeka-S-Total-Results']), 'results': results}\n", + " data = self.process_response(response)\n", + " return {'total_results': int(response.headers['Omeka-S-Total-Results']), 'results': data}\n", " \n", " def get_resource(self, resource_type, **kwargs):\n", " '''\n", @@ -135,8 +152,8 @@ " * a dict containing a JSON-LD formatted representation of the resource\n", " '''\n", " response = self.s.get(f'{self.api_url}/{resource_type}/{resource_id}')\n", - " if response.status_code != 404:\n", - " return response.json()\n", + " data = self.process_response(response)\n", + " return data\n", "\n", " def get_template_by_label(self, label):\n", " '''\n", @@ -229,8 +246,8 @@ " }\n", " params = self.filter_items(params, **extra_filters)\n", " # print(params)\n", - " data = self.get_resources('items', **params)\n", - " return data\n", + " results = self.get_resources('items', **params)\n", + " return results\n", " \n", " def search_items(self, query, search_type='fulltext_search', page=1, **extra_filters):\n", " '''\n", @@ -257,7 +274,8 @@ " params = {'page': page}\n", " params[search_type] = query\n", " params = self.filter_items(params, **extra_filters)\n", - " return self.get_resources('items', **params)\n", + " results = self.get_resources('items', **params)\n", + " return results\n", "\n", " def get_template_properties(self, template_id):\n", " '''\n", @@ -279,7 +297,7 @@ " prop_url = prop['o:property']['@id']\n", " # The resource template doesn't include property terms, so we have to go to the property data\n", " response = self.s.get(prop_url)\n", - " data = response.json()\n", + " data = self.process_response(response)\n", " # Use default data types if they're not defined in the resource template\n", " data_type = ['literal', 'uri', 'resource:item'] if prop['o:data_type'] == [] else prop['o:data_type']\n", " properties[data['o:term']] = {'property_id': data['o:id'], 'type': data_type}\n", @@ -354,7 +372,8 @@ " else:\n", " response = self.s.post(f'{self.api_url}/items', json=payload, params=self.params)\n", " #print(response.text)\n", - " return response.json()\n", + " data = self.process_response(response)\n", + " return data\n", " \n", " def prepare_item_payload(self, terms):\n", " '''\n", @@ -472,7 +491,8 @@ " * dict with JSON-LD representation of the deleted resource\n", " '''\n", " response = self.s.delete(f'{self.api_url}/{resource_type}/{resource_id}', params=self.params)\n", - " return response.json()\n", + " data = self.process_response(response)\n", + " return data\n", " \n", " def update_resource(self, payload, resource_type='items'):\n", " '''\n", @@ -486,7 +506,8 @@ " make your desired changes to it, then submit the updated resource as your payload.\n", " '''\n", " response = self.s.put(f'{self.api_url}/{resource_type}/{payload[\"o:id\"]}', json=payload, params=self.params)\n", - " return response.json()\n", + " data = self.process_response(response)\n", + " return data\n", " \n", " def add_media_to_item(self, item_id, media_file, payload={}, template_id=None, class_id=None):\n", " '''\n", @@ -530,7 +551,8 @@ " files[f'file[0]'] = path.read_bytes()\n", " files['data'] = (None, json.dumps(payload), 'application/json')\n", " response = self.s.post(f'{self.api_url}/media', files=files, params=self.params)\n", - " return response.json()\n", + " data = self.process_response(response)\n", + " return data\n", " \n", " # MANAGING TEMPLATES\n", " \n", @@ -665,7 +687,8 @@ " '''\n", " # Upload the template payload\n", " response = self.s.post(f'{self.api_url}/resource_templates/', params=self.params, json=template_payload)\n", - " return response.json()\n", + " data = self.process_response(response)\n", + " return data\n", " \n", " # MODULE RELATED METHODS\n", "\n", @@ -707,7 +730,8 @@ " if media_id:\n", " marker_payload['o:media'] = {'o:id': media_id}\n", " response = self.s.post(f'{self.api_url}/mapping_markers/', json=marker_payload, params=self.params)\n", - " return response.json()\n" + " data = self.process_response(response)\n", + " return data\n" ] }, { @@ -763,7 +787,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.get_resources[source]

\n", + "

OmekaAPIClient.get_resources[source]

\n", "\n", "> OmekaAPIClient.get_resources(**`resource_type`**, **\\*\\*`kwargs`**)\n", "\n", @@ -799,7 +823,7 @@ { "data": { "text/plain": [ - "101" + "120" ] }, "execution_count": null, @@ -841,7 +865,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.get_resource_by_id[source]

\n", + "

OmekaAPIClient.get_resource_by_id[source]

\n", "\n", "> OmekaAPIClient.get_resource_by_id(**`resource_id`**, **`resource_type`**=*`'items'`*)\n", "\n", @@ -899,7 +923,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.get_template_by_label[source]

\n", + "

OmekaAPIClient.get_template_by_label[source]

\n", "\n", "> OmekaAPIClient.get_template_by_label(**`label`**)\n", "\n", @@ -960,7 +984,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.get_resource_by_term[source]

\n", + "

OmekaAPIClient.get_resource_by_term[source]

\n", "\n", "> OmekaAPIClient.get_resource_by_term(**`term`**, **`resource_type`**=*`'properties'`*)\n", "\n", @@ -1032,7 +1056,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.get_resource_from_vocab[source]

\n", + "

OmekaAPIClient.get_resource_from_vocab[source]

\n", "\n", "> OmekaAPIClient.get_resource_from_vocab(**`local_name`**, **`vocabulary_namespace_uri`**=*`'http://schema.org/'`*, **`resource_type`**=*`'properties'`*)\n", "\n", @@ -1111,7 +1135,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.get_property_id[source]

\n", + "

OmekaAPIClient.get_property_id[source]

\n", "\n", "> OmekaAPIClient.get_property_id(**`term`**)\n", "\n", @@ -1176,7 +1200,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.filter_items_by_property[source]

\n", + "

OmekaAPIClient.filter_items_by_property[source]

\n", "\n", "> OmekaAPIClient.filter_items_by_property(**`filter_property`**=*`'schema:name'`*, **`filter_value`**=*`''`*, **`filter_type`**=*`'eq'`*, **`page`**=*`1`*, **\\*\\*`extra_filters`**)\n", "\n", @@ -1231,7 +1255,7 @@ { "data": { "text/plain": [ - "'Clement Wragge at Home. - UPDATED!'" + "'Clement Wragge at Home. - UPDATED! - UPDATED!'" ] }, "execution_count": null, @@ -1251,7 +1275,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.search_items[source]

\n", + "

OmekaAPIClient.search_items[source]

\n", "\n", "> OmekaAPIClient.search_items(**`query`**, **`search_type`**=*`'fulltext_search'`*, **`page`**=*`1`*, **\\*\\*`extra_filters`**)\n", "\n", @@ -1295,7 +1319,7 @@ { "data": { "text/plain": [ - "21" + "23" ] }, "execution_count": null, @@ -1359,7 +1383,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.prepare_item_payload[source]

\n", + "

OmekaAPIClient.prepare_item_payload[source]

\n", "\n", "> OmekaAPIClient.prepare_item_payload(**`terms`**)\n", "\n", @@ -1456,7 +1480,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.prepare_item_payload_using_template[source]

\n", + "

OmekaAPIClient.prepare_item_payload_using_template[source]

\n", "\n", "> OmekaAPIClient.prepare_item_payload_using_template(**`terms`**, **`template_id`**)\n", "\n", @@ -1548,7 +1572,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.add_media_to_payload[source]

\n", + "

OmekaAPIClient.add_media_to_payload[source]

\n", "\n", "> OmekaAPIClient.add_media_to_payload(**`payload`**, **`media_files`**)\n", "\n", @@ -1612,7 +1636,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.add_item[source]

\n", + "

OmekaAPIClient.add_item[source]

\n", "\n", "> OmekaAPIClient.add_item(**`payload`**, **`media_files`**=*`None`*, **`template_id`**=*`None`*, **`class_id`**=*`None`*, **`item_set_id`**=*`None`*)\n", "\n", @@ -1656,9 +1680,9 @@ "data": { "text/plain": [ "{'@context': 'https://timsherratt.org/collections/api-context',\n", - " '@id': 'https://timsherratt.org/collections/api/items/992',\n", + " '@id': 'https://timsherratt.org/collections/api/items/1038',\n", " '@type': 'o:Item',\n", - " 'o:id': 992,\n", + " 'o:id': 1038,\n", " 'o:is_public': True,\n", " 'o:owner': {'@id': 'https://timsherratt.org/collections/api/users/1',\n", " 'o:id': 1},\n", @@ -1667,9 +1691,9 @@ " 'o:thumbnail': None,\n", " 'o:title': 'My first resource!',\n", " 'thumbnail_display_urls': {'large': None, 'medium': None, 'square': None},\n", - " 'o:created': {'@value': '2022-04-03T06:43:24+00:00',\n", + " 'o:created': {'@value': '2022-04-04T00:47:02+00:00',\n", " '@type': 'http://www.w3.org/2001/XMLSchema#dateTime'},\n", - " 'o:modified': {'@value': '2022-04-03T06:43:24+00:00',\n", + " 'o:modified': {'@value': '2022-04-04T00:47:02+00:00',\n", " '@type': 'http://www.w3.org/2001/XMLSchema#dateTime'},\n", " 'o:media': [],\n", " 'o:item_set': [],\n", @@ -1740,7 +1764,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.delete_resource[source]

\n", + "

OmekaAPIClient.delete_resource[source]

\n", "\n", "> OmekaAPIClient.delete_resource(**`resource_id`**, **`resource_type`**)\n", "\n", @@ -1783,8 +1807,9 @@ "# The titles of the random and deleted items should be the same\n", "assert deleted_resource['o:title'] == random_item['o:title']\n", "\n", - "# Trying to get the random item should now return None\n", - "assert omeka_auth.get_resource_by_id(random_item['o:id'], 'items') is None" + "# Trying to get the random item should now raise an HTTP 404 error\n", + "with pytest.raises(requests.exceptions.HTTPError):\n", + " omeka_auth.get_resource_by_id(random_item['o:id'], 'items')" ] }, { @@ -1795,7 +1820,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.update_resource[source]

\n", + "

OmekaAPIClient.update_resource[source]

\n", "\n", "> OmekaAPIClient.update_resource(**`payload`**, **`resource_type`**=*`'items'`*)\n", "\n", @@ -1829,7 +1854,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "The Courier-Mail (Brisbane, Qld. : 1933 - 1954) - UPDATED!\n" + "Wellington Times (NSW : 1899 - 1954) - UPDATED! - UPDATED! - UPDATED!\n" ] } ], @@ -1866,7 +1891,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.add_media_to_item[source]

\n", + "

OmekaAPIClient.add_media_to_item[source]

\n", "\n", "> OmekaAPIClient.add_media_to_item(**`item_id`**, **`media_file`**, **`payload`**=*`{}`*, **`template_id`**=*`None`*, **`class_id`**=*`None`*)\n", "\n", @@ -2018,7 +2043,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.add_marker_to_item[source]

\n", + "

OmekaAPIClient.add_marker_to_item[source]

\n", "\n", "> OmekaAPIClient.add_marker_to_item(**`item_id`**, **`coords`**=*`None`*, **`terms`**=*`None`*, **`label`**=*`None`*, **`media_id`**=*`None`*)\n", "\n", @@ -2156,7 +2181,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.prepare_template_payload[source]

\n", + "

OmekaAPIClient.prepare_template_payload[source]

\n", "\n", "> OmekaAPIClient.prepare_template_payload(**`template_file`**)\n", "\n", @@ -2217,7 +2242,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.upload_template[source]

\n", + "

OmekaAPIClient.upload_template[source]

\n", "\n", "> OmekaAPIClient.upload_template(**`template_payload`**)\n", "\n", @@ -2277,7 +2302,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.localise_custom_vocabs[source]

\n", + "

OmekaAPIClient.localise_custom_vocabs[source]

\n", "\n", "> OmekaAPIClient.localise_custom_vocabs(**`data_types`**)\n", "\n", @@ -2339,7 +2364,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.get_template_class_id[source]

\n", + "

OmekaAPIClient.get_template_class_id[source]

\n", "\n", "> OmekaAPIClient.get_template_class_id(**`template`**)\n", "\n", @@ -2388,7 +2413,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.get_template_property_id[source]

\n", + "

OmekaAPIClient.get_template_property_id[source]

\n", "\n", "> OmekaAPIClient.get_template_property_id(**`template`**, **`term`**)\n", "\n", @@ -2447,7 +2472,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.format_resource_id[source]

\n", + "

OmekaAPIClient.format_resource_id[source]

\n", "\n", "> OmekaAPIClient.format_resource_id(**`resource_id`**, **`resource_type`**)\n", "\n", @@ -2494,7 +2519,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.prepare_property_value[source]

\n", + "

OmekaAPIClient.prepare_property_value[source]

\n", "\n", "> OmekaAPIClient.prepare_property_value(**`value`**, **`property_id`**)\n", "\n", @@ -2565,7 +2590,7 @@ { "data": { "text/markdown": [ - "

OmekaAPIClient.get_template_properties[source]

\n", + "

OmekaAPIClient.get_template_properties[source]

\n", "\n", "> OmekaAPIClient.get_template_properties(**`template_id`**)\n", "\n", @@ -2859,9 +2884,9 @@ "data": { "text/plain": [ "{'@context': 'http://timsherratt.org/collections/api-context',\n", - " '@id': 'http://timsherratt.org/collections/api/items/999',\n", + " '@id': 'http://timsherratt.org/collections/api/items/1045',\n", " '@type': ['o:Item', 'schema:Newspaper'],\n", - " 'o:id': 999,\n", + " 'o:id': 1045,\n", " 'o:is_public': True,\n", " 'o:owner': {'@id': 'http://timsherratt.org/collections/api/users/1',\n", " 'o:id': 1},\n", @@ -2872,9 +2897,9 @@ " 'o:thumbnail': None,\n", " 'o:title': 'The Bendigo Independent (Vic. : 1891 - 1918)',\n", " 'thumbnail_display_urls': {'large': None, 'medium': None, 'square': None},\n", - " 'o:created': {'@value': '2022-04-03T06:44:57+00:00',\n", + " 'o:created': {'@value': '2022-04-04T00:48:33+00:00',\n", " '@type': 'http://www.w3.org/2001/XMLSchema#dateTime'},\n", - " 'o:modified': {'@value': '2022-04-03T06:44:57+00:00',\n", + " 'o:modified': {'@value': '2022-04-04T00:48:33+00:00',\n", " '@type': 'http://www.w3.org/2001/XMLSchema#dateTime'},\n", " 'o:media': [],\n", " 'o:item_set': [],\n", @@ -3085,8 +3110,8 @@ " '@value': \"MR WRAGGE'S PREDICTION. RENEWAL OF CYCLONE FORETOLD.\"}],\n", " 'schema:isPartOf': [{'property_id': 736,\n", " 'type': 'resource:item',\n", - " '@id': 'http://timsherratt.org/collections/api/items/999',\n", - " 'value_resource_id': 999,\n", + " '@id': 'http://timsherratt.org/collections/api/items/1045',\n", + " 'value_resource_id': 1045,\n", " 'value_resource_name': 'items'}],\n", " 'schema:datePublished': [{'property_id': 928,\n", " 'type': 'numeric:timestamp',\n", @@ -3142,9 +3167,9 @@ "data": { "text/plain": [ "{'@context': 'http://timsherratt.org/collections/api-context',\n", - " '@id': 'http://timsherratt.org/collections/api/items/1000',\n", + " '@id': 'http://timsherratt.org/collections/api/items/1046',\n", " '@type': ['o:Item', 'schema:NewsArticle'],\n", - " 'o:id': 1000,\n", + " 'o:id': 1046,\n", " 'o:is_public': True,\n", " 'o:owner': {'@id': 'http://timsherratt.org/collections/api/users/1',\n", " 'o:id': 1},\n", @@ -3154,15 +3179,15 @@ " 'o:id': 4},\n", " 'o:thumbnail': None,\n", " 'o:title': \"MR WRAGGE'S PREDICTION. RENEWAL OF CYCLONE FORETOLD.\",\n", - " 'thumbnail_display_urls': {'large': 'http://timsherratt.org/collections/files/large/4ad01b874e1d7f94c659638f681b93287b231263.jpg',\n", - " 'medium': 'http://timsherratt.org/collections/files/medium/4ad01b874e1d7f94c659638f681b93287b231263.jpg',\n", - " 'square': 'http://timsherratt.org/collections/files/square/4ad01b874e1d7f94c659638f681b93287b231263.jpg'},\n", - " 'o:created': {'@value': '2022-04-03T06:45:04+00:00',\n", + " 'thumbnail_display_urls': {'large': 'http://timsherratt.org/collections/files/large/c60918ee88cb729ae8803742bbbb185460700903.jpg',\n", + " 'medium': 'http://timsherratt.org/collections/files/medium/c60918ee88cb729ae8803742bbbb185460700903.jpg',\n", + " 'square': 'http://timsherratt.org/collections/files/square/c60918ee88cb729ae8803742bbbb185460700903.jpg'},\n", + " 'o:created': {'@value': '2022-04-04T00:48:40+00:00',\n", " '@type': 'http://www.w3.org/2001/XMLSchema#dateTime'},\n", - " 'o:modified': {'@value': '2022-04-03T06:45:04+00:00',\n", + " 'o:modified': {'@value': '2022-04-04T00:48:40+00:00',\n", " '@type': 'http://www.w3.org/2001/XMLSchema#dateTime'},\n", - " 'o:media': [{'@id': 'http://timsherratt.org/collections/api/media/1001',\n", - " 'o:id': 1001}],\n", + " 'o:media': [{'@id': 'http://timsherratt.org/collections/api/media/1047',\n", + " 'o:id': 1047}],\n", " 'o:item_set': [],\n", " 'o:site': [],\n", " 'schema:name': [{'type': 'literal',\n", @@ -3180,8 +3205,8 @@ " 'property_id': 736,\n", " 'property_label': 'isPartOf',\n", " 'is_public': True,\n", - " '@id': 'http://timsherratt.org/collections/api/items/999',\n", - " 'value_resource_id': 999,\n", + " '@id': 'http://timsherratt.org/collections/api/items/1045',\n", + " 'value_resource_id': 1045,\n", " 'value_resource_name': 'items',\n", " 'url': None,\n", " 'display_title': 'The Bendigo Independent (Vic. : 1891 - 1918)'}],\n", diff --git a/docs/api.html b/docs/api.html index 0b5cefd..2bddd8c 100644 --- a/docs/api.html +++ b/docs/api.html @@ -119,7 +119,7 @@

Getting resources -

OmekaAPIClient.get_resources[source]

OmekaAPIClient.get_resources(resource_type, **kwargs)

+

OmekaAPIClient.get_resources[source]

OmekaAPIClient.get_resources(resource_type, **kwargs)

Get a list of resources matching the supplied parameters. This will return the first page of matching results. To retrieve additional pages, @@ -168,7 +168,7 @@

OmekaAPIClient.ge
-
101
+
120
@@ -226,7 +226,7 @@

OmekaAPIClient.ge
-

OmekaAPIClient.get_resource_by_id[source]

OmekaAPIClient.get_resource_by_id(resource_id, resource_type='items')

+

OmekaAPIClient.get_resource_by_id[source]

OmekaAPIClient.get_resource_by_id(resource_id, resource_type='items')

Get a resource from its Omeka id.

Parameters:

@@ -292,7 +292,7 @@

OmekaAPIClie
-

OmekaAPIClient.get_template_by_label[source]

OmekaAPIClient.get_template_by_label(label)

+

OmekaAPIClient.get_template_by_label[source]

OmekaAPIClient.get_template_by_label(label)

Get a resource template from its Omeka label.

Parameters:

@@ -369,7 +369,7 @@

OmekaAPIC
-

OmekaAPIClient.get_resource_by_term[source]

OmekaAPIClient.get_resource_by_term(term, resource_type='properties')

+

OmekaAPIClient.get_resource_by_term[source]

OmekaAPIClient.get_resource_by_term(term, resource_type='properties')

Get the resource (property or class) associated with the suppied term.

Parameters:

@@ -463,7 +463,7 @@

OmekaAPICl
-

OmekaAPIClient.get_resource_from_vocab[source]

OmekaAPIClient.get_resource_from_vocab(local_name, vocabulary_namespace_uri='http://schema.org/', resource_type='properties')

+

OmekaAPIClient.get_resource_from_vocab[source]

OmekaAPIClient.get_resource_from_vocab(local_name, vocabulary_namespace_uri='http://schema.org/', resource_type='properties')

Get the resource (property or class) associated with the suppied vocabulary and label.

Parameters:

@@ -564,7 +564,7 @@

OmekaAP
-

OmekaAPIClient.get_property_id[source]

OmekaAPIClient.get_property_id(term)

+

OmekaAPIClient.get_property_id[source]

OmekaAPIClient.get_property_id(term)

Get the numeric identifier associated with the supplied property term.

Parameters:

@@ -651,7 +651,7 @@

OmekaAPIClient.
-

OmekaAPIClient.filter_items_by_property[source]

OmekaAPIClient.filter_items_by_property(filter_property='schema:name', filter_value='', filter_type='eq', page=1, **extra_filters)

+

OmekaAPIClient.filter_items_by_property[source]

OmekaAPIClient.filter_items_by_property(filter_property='schema:name', filter_value='', filter_type='eq', page=1, **extra_filters)

Filter the list of items by searching for a value in a particular property. Additional filters can also limit to items associated with particular templates, classes, or item sets.

@@ -727,7 +727,7 @@

OmekaA
-
'Clement Wragge at Home. - UPDATED!'
+
'Clement Wragge at Home. - UPDATED! - UPDATED!'

@@ -749,7 +749,7 @@

OmekaA
-

OmekaAPIClient.search_items[source]

OmekaAPIClient.search_items(query, search_type='fulltext_search', page=1, **extra_filters)

+

OmekaAPIClient.search_items[source]

OmekaAPIClient.search_items(query, search_type='fulltext_search', page=1, **extra_filters)

Search for matching items. Two search types are available:

@@ -809,7 +809,7 @@

OmekaAPIClient.sea
-
21
+
23

@@ -887,7 +887,7 @@

Prepare an item payload -

OmekaAPIClient.prepare_item_payload[source]

OmekaAPIClient.prepare_item_payload(terms)

+

OmekaAPIClient.prepare_item_payload[source]

OmekaAPIClient.prepare_item_payload(terms)

Prepare an item payload, ready for upload.

Parameters:

@@ -1014,7 +1014,7 @@

OmekaAPICl
-

OmekaAPIClient.prepare_item_payload_using_template[source]

OmekaAPIClient.prepare_item_payload_using_template(terms, template_id)

+

OmekaAPIClient.prepare_item_payload_using_template[source]

OmekaAPIClient.prepare_item_payload_using_template(terms, template_id)

Prepare an item payload, checking the supplied terms and values against the specified template. Note:

@@ -1138,7 +1138,7 @@

<
-

OmekaAPIClient.add_media_to_payload[source]

OmekaAPIClient.add_media_to_payload(payload, media_files)

+

OmekaAPIClient.add_media_to_payload[source]

OmekaAPIClient.add_media_to_payload(payload, media_files)

Add media files to the item payload.

Parameters:

@@ -1218,7 +1218,7 @@

Upload the payload to
-

OmekaAPIClient.add_item[source]

OmekaAPIClient.add_item(payload, media_files=None, template_id=None, class_id=None, item_set_id=None)

+

OmekaAPIClient.add_item[source]

OmekaAPIClient.add_item(payload, media_files=None, template_id=None, class_id=None, item_set_id=None)

Create a new item from the supplied payload, optionally uploading attached media files.

Parameters:

@@ -1274,9 +1274,9 @@

Add a simple item
{'@context': 'https://timsherratt.org/collections/api-context',
- '@id': 'https://timsherratt.org/collections/api/items/992',
+ '@id': 'https://timsherratt.org/collections/api/items/1038',
  '@type': 'o:Item',
- 'o:id': 992,
+ 'o:id': 1038,
  'o:is_public': True,
  'o:owner': {'@id': 'https://timsherratt.org/collections/api/users/1',
   'o:id': 1},
@@ -1285,9 +1285,9 @@ 

Add a simple itemUpdating resources -

OmekaAPIClient.delete_resource[source]

OmekaAPIClient.delete_resource(resource_id, resource_type)

+

OmekaAPIClient.delete_resource[source]

OmekaAPIClient.delete_resource(resource_id, resource_type)

Deletes a resource. No confirmation is requested, so use carefully.

Parameters:

@@ -1414,8 +1414,9 @@

OmekaAPIClient. # The titles of the random and deleted items should be the same assert deleted_resource['o:title'] == random_item['o:title'] -# Trying to get the random item should now return None -assert omeka_auth.get_resource_by_id(random_item['o:id'], 'items') is None +# Trying to get the random item should now raise an HTTP 404 error +with pytest.raises(requests.exceptions.HTTPError): + omeka_auth.get_resource_by_id(random_item['o:id'], 'items')

@@ -1436,7 +1437,7 @@

OmekaAPIClient.
-

OmekaAPIClient.update_resource[source]

OmekaAPIClient.update_resource(payload, resource_type='items')

+

OmekaAPIClient.update_resource[source]

OmekaAPIClient.update_resource(payload, resource_type='items')

Update an existing resource.

Parameters:

@@ -1497,7 +1498,7 @@

OmekaAPIClient.
-
The Courier-Mail (Brisbane, Qld. : 1933 - 1954) - UPDATED!
+
Wellington Times (NSW : 1899 - 1954) - UPDATED! - UPDATED! - UPDATED!
 
@@ -1519,7 +1520,7 @@

OmekaAPIClient.
-

OmekaAPIClient.add_media_to_item[source]

OmekaAPIClient.add_media_to_item(item_id, media_file, payload={}, template_id=None, class_id=None)

+

OmekaAPIClient.add_media_to_item[source]

OmekaAPIClient.add_media_to_item(item_id, media_file, payload={}, template_id=None, class_id=None)

Upload a media file and associate it with an existing item.

Parameters:

@@ -1708,7 +1709,7 @@

OmekaAPIClien
-

OmekaAPIClient.add_marker_to_item[source]

OmekaAPIClient.add_marker_to_item(item_id, coords=None, terms=None, label=None, media_id=None)

+

OmekaAPIClient.add_marker_to_item[source]

OmekaAPIClient.add_marker_to_item(item_id, coords=None, terms=None, label=None, media_id=None)

Add a map marker to an item. Requires the mapping module to be installed.

@@ -1866,7 +1867,7 @@

Managing templates -

OmekaAPIClient.prepare_template_payload[source]

OmekaAPIClient.prepare_template_payload(template_file)

+

OmekaAPIClient.prepare_template_payload[source]

OmekaAPIClient.prepare_template_payload(template_file)

Insert local property, class, and vocab identifiers into a resource template exported from Omeka so that it can be uploaded to the local instance.

@@ -1944,7 +1945,7 @@

OmekaA
-

OmekaAPIClient.upload_template[source]

OmekaAPIClient.upload_template(template_payload)

+

OmekaAPIClient.upload_template[source]

OmekaAPIClient.upload_template(template_payload)

Upload a template exported from an instance of Omeka to the current local instance.

Parameters:

@@ -2012,7 +2013,7 @@

OmekaAPIClient.
-

OmekaAPIClient.localise_custom_vocabs[source]

OmekaAPIClient.localise_custom_vocabs(data_types)

+

OmekaAPIClient.localise_custom_vocabs[source]

OmekaAPIClient.localise_custom_vocabs(data_types)

Check a list of data types for references to custom vocabs. If found, look for the local identifier of the custom vocab, @@ -2088,7 +2089,7 @@

OmekaAPI
-

OmekaAPIClient.get_template_class_id[source]

OmekaAPIClient.get_template_class_id(template)

+

OmekaAPIClient.get_template_class_id[source]

OmekaAPIClient.get_template_class_id(template)

Get the local id of the resource class associated with the supplied template.

Parameters:

@@ -2145,7 +2146,7 @@

OmekaAPIC
-

OmekaAPIClient.get_template_property_id[source]

OmekaAPIClient.get_template_property_id(template, term)

+

OmekaAPIClient.get_template_property_id[source]

OmekaAPIClient.get_template_property_id(template, term)

Get the local id of the property associated with the supplied template.

Parameters:

@@ -2211,7 +2212,7 @@

Utilities

-

OmekaAPIClient.format_resource_id[source]

OmekaAPIClient.format_resource_id(resource_id, resource_type)

+

OmekaAPIClient.format_resource_id[source]

OmekaAPIClient.format_resource_id(resource_id, resource_type)

Generate a formatted id for the resource with the specified Omeka id number and resource type.

Parameters:

@@ -2267,7 +2268,7 @@

OmekaAPIClie
-

OmekaAPIClient.prepare_property_value[source]

OmekaAPIClient.prepare_property_value(value, property_id)

+

OmekaAPIClient.prepare_property_value[source]

OmekaAPIClient.prepare_property_value(value, property_id)

Formats a property value according to its datatype as expected by Omeka. The formatted value can be used in a payload to create a new item.

@@ -2359,7 +2360,7 @@

OmekaAPI
-

OmekaAPIClient.get_template_properties[source]

OmekaAPIClient.get_template_properties(template_id)

+

OmekaAPIClient.get_template_properties[source]

OmekaAPIClient.get_template_properties(template_id)

List properties used by the specified template.

The resource template objects returned by the API don't include property terms. @@ -2753,9 +2754,9 @@

Example: adding a newspa
{'@context': 'http://timsherratt.org/collections/api-context',
- '@id': 'http://timsherratt.org/collections/api/items/999',
+ '@id': 'http://timsherratt.org/collections/api/items/1045',
  '@type': ['o:Item', 'schema:Newspaper'],
- 'o:id': 999,
+ 'o:id': 1045,
  'o:is_public': True,
  'o:owner': {'@id': 'http://timsherratt.org/collections/api/users/1',
   'o:id': 1},
@@ -2766,9 +2767,9 @@ 

Example: adding a newspa 'o:thumbnail': None, 'o:title': 'The Bendigo Independent (Vic. : 1891 - 1918)', 'thumbnail_display_urls': {'large': None, 'medium': None, 'square': None}, - 'o:created': {'@value': '2022-04-03T06:44:57+00:00', + 'o:created': {'@value': '2022-04-04T00:48:33+00:00', '@type': 'http://www.w3.org/2001/XMLSchema#dateTime'}, - 'o:modified': {'@value': '2022-04-03T06:44:57+00:00', + 'o:modified': {'@value': '2022-04-04T00:48:33+00:00', '@type': 'http://www.w3.org/2001/XMLSchema#dateTime'}, 'o:media': [], 'o:item_set': [], @@ -3034,8 +3035,8 @@

Example: adding a newspa '@value': "MR WRAGGE'S PREDICTION. RENEWAL OF CYCLONE FORETOLD."}], 'schema:isPartOf': [{'property_id': 736, 'type': 'resource:item', - '@id': 'http://timsherratt.org/collections/api/items/999', - 'value_resource_id': 999, + '@id': 'http://timsherratt.org/collections/api/items/1045', + 'value_resource_id': 1045, 'value_resource_name': 'items'}], 'schema:datePublished': [{'property_id': 928, 'type': 'numeric:timestamp', @@ -3111,9 +3112,9 @@

Example: adding a newspa
{'@context': 'http://timsherratt.org/collections/api-context',
- '@id': 'http://timsherratt.org/collections/api/items/1000',
+ '@id': 'http://timsherratt.org/collections/api/items/1046',
  '@type': ['o:Item', 'schema:NewsArticle'],
- 'o:id': 1000,
+ 'o:id': 1046,
  'o:is_public': True,
  'o:owner': {'@id': 'http://timsherratt.org/collections/api/users/1',
   'o:id': 1},
@@ -3123,15 +3124,15 @@ 

Example: adding a newspa 'o:id': 4}, 'o:thumbnail': None, 'o:title': "MR WRAGGE'S PREDICTION. RENEWAL OF CYCLONE FORETOLD.", - 'thumbnail_display_urls': {'large': 'http://timsherratt.org/collections/files/large/4ad01b874e1d7f94c659638f681b93287b231263.jpg', - 'medium': 'http://timsherratt.org/collections/files/medium/4ad01b874e1d7f94c659638f681b93287b231263.jpg', - 'square': 'http://timsherratt.org/collections/files/square/4ad01b874e1d7f94c659638f681b93287b231263.jpg'}, - 'o:created': {'@value': '2022-04-03T06:45:04+00:00', + 'thumbnail_display_urls': {'large': 'http://timsherratt.org/collections/files/large/c60918ee88cb729ae8803742bbbb185460700903.jpg', + 'medium': 'http://timsherratt.org/collections/files/medium/c60918ee88cb729ae8803742bbbb185460700903.jpg', + 'square': 'http://timsherratt.org/collections/files/square/c60918ee88cb729ae8803742bbbb185460700903.jpg'}, + 'o:created': {'@value': '2022-04-04T00:48:40+00:00', '@type': 'http://www.w3.org/2001/XMLSchema#dateTime'}, - 'o:modified': {'@value': '2022-04-03T06:45:04+00:00', + 'o:modified': {'@value': '2022-04-04T00:48:40+00:00', '@type': 'http://www.w3.org/2001/XMLSchema#dateTime'}, - 'o:media': [{'@id': 'http://timsherratt.org/collections/api/media/1001', - 'o:id': 1001}], + 'o:media': [{'@id': 'http://timsherratt.org/collections/api/media/1047', + 'o:id': 1047}], 'o:item_set': [], 'o:site': [], 'schema:name': [{'type': 'literal', @@ -3149,8 +3150,8 @@

Example: adding a newspa 'property_id': 736, 'property_label': 'isPartOf', 'is_public': True, - '@id': 'http://timsherratt.org/collections/api/items/999', - 'value_resource_id': 999, + '@id': 'http://timsherratt.org/collections/api/items/1045', + 'value_resource_id': 1045, 'value_resource_name': 'items', 'url': None, 'display_title': 'The Bendigo Independent (Vic. : 1891 - 1918)'}], diff --git a/omeka_s_tools/__init__.py b/omeka_s_tools/__init__.py index d3ec452..493f741 100644 --- a/omeka_s_tools/__init__.py +++ b/omeka_s_tools/__init__.py @@ -1 +1 @@ -__version__ = "0.2.0" +__version__ = "0.3.0" diff --git a/omeka_s_tools/api.py b/omeka_s_tools/api.py index a3fd9ad..bb56cbe 100644 --- a/omeka_s_tools/api.py +++ b/omeka_s_tools/api.py @@ -31,6 +31,22 @@ def __init__(self, api_url, key_identity=None, key_credential=None, use_cache=Tr def clear_cache(): self.s.cache.clear() + def process_response(self, response): + ''' + Handle Omeka responses, raising exceptions on errors. + ''' + # Raise exception on HTTP error + response.raise_for_status() + # Try extracting JSON data + try: + data = response.json() + # If there's no JSON, display the raw response text and raise exception + except (json.decoder.JSONDecodeError, ValueError): + print(f'Bad JSON: {response.text}') + raise + else: + return data + def format_resource_id(self, resource_id, resource_type): ''' Generate a formatted id for the resource with the specified Omeka id number and resource type. @@ -63,8 +79,8 @@ def get_resources(self, resource_type, **kwargs): * `results` - a list of dicts, each containing a JSON-LD formatted representation of a resource ''' response = self.s.get(f'{self.api_url}/{resource_type}/', params=kwargs) - results = response.json() - return {'total_results': int(response.headers['Omeka-S-Total-Results']), 'results': results} + data = self.process_response(response) + return {'total_results': int(response.headers['Omeka-S-Total-Results']), 'results': data} def get_resource(self, resource_type, **kwargs): ''' @@ -98,8 +114,8 @@ def get_resource_by_id(self, resource_id, resource_type='items'): * a dict containing a JSON-LD formatted representation of the resource ''' response = self.s.get(f'{self.api_url}/{resource_type}/{resource_id}') - if response.status_code != 404: - return response.json() + data = self.process_response(response) + return data def get_template_by_label(self, label): ''' @@ -192,8 +208,8 @@ def filter_items_by_property(self, filter_property='schema:name', filter_value=' } params = self.filter_items(params, **extra_filters) # print(params) - data = self.get_resources('items', **params) - return data + results = self.get_resources('items', **params) + return results def search_items(self, query, search_type='fulltext_search', page=1, **extra_filters): ''' @@ -220,7 +236,8 @@ def search_items(self, query, search_type='fulltext_search', page=1, **extra_fil params = {'page': page} params[search_type] = query params = self.filter_items(params, **extra_filters) - return self.get_resources('items', **params) + results = self.get_resources('items', **params) + return results def get_template_properties(self, template_id): ''' @@ -242,7 +259,7 @@ def get_template_properties(self, template_id): prop_url = prop['o:property']['@id'] # The resource template doesn't include property terms, so we have to go to the property data response = self.s.get(prop_url) - data = response.json() + data = self.process_response(response) # Use default data types if they're not defined in the resource template data_type = ['literal', 'uri', 'resource:item'] if prop['o:data_type'] == [] else prop['o:data_type'] properties[data['o:term']] = {'property_id': data['o:id'], 'type': data_type} @@ -317,7 +334,8 @@ def add_item(self, payload, media_files=None, template_id=None, class_id=None, i else: response = self.s.post(f'{self.api_url}/items', json=payload, params=self.params) #print(response.text) - return response.json() + data = self.process_response(response) + return data def prepare_item_payload(self, terms): ''' @@ -435,7 +453,8 @@ def delete_resource(self, resource_id, resource_type): * dict with JSON-LD representation of the deleted resource ''' response = self.s.delete(f'{self.api_url}/{resource_type}/{resource_id}', params=self.params) - return response.json() + data = self.process_response(response) + return data def update_resource(self, payload, resource_type='items'): ''' @@ -449,7 +468,8 @@ def update_resource(self, payload, resource_type='items'): make your desired changes to it, then submit the updated resource as your payload. ''' response = self.s.put(f'{self.api_url}/{resource_type}/{payload["o:id"]}', json=payload, params=self.params) - return response.json() + data = self.process_response(response) + return data def add_media_to_item(self, item_id, media_file, payload={}, template_id=None, class_id=None): ''' @@ -493,7 +513,8 @@ def add_media_to_item(self, item_id, media_file, payload={}, template_id=None, c files[f'file[0]'] = path.read_bytes() files['data'] = (None, json.dumps(payload), 'application/json') response = self.s.post(f'{self.api_url}/media', files=files, params=self.params) - return response.json() + data = self.process_response(response) + return data # MANAGING TEMPLATES @@ -628,7 +649,8 @@ def upload_template(self, template_payload): ''' # Upload the template payload response = self.s.post(f'{self.api_url}/resource_templates/', params=self.params, json=template_payload) - return response.json() + data = self.process_response(response) + return data # MODULE RELATED METHODS @@ -670,4 +692,5 @@ def add_marker_to_item(self, item_id, coords=None, terms=None, label=None, media if media_id: marker_payload['o:media'] = {'o:id': media_id} response = self.s.post(f'{self.api_url}/mapping_markers/', json=marker_payload, params=self.params) - return response.json() + data = self.process_response(response) + return data diff --git a/settings.ini b/settings.ini index 6de5123..7a18190 100644 --- a/settings.ini +++ b/settings.ini @@ -13,7 +13,7 @@ author = Tim Sherratt author_email = tim@timsherratt.org copyright = Tim Sherratt branch = master -version = 0.2.0 +version = 0.3.0 min_python = 3.8 audience = Developers language = English