ckanext-iiif


Nameckanext-iiif JSON
Version 3.0.9 PyPI version JSON
download
home_page
SummaryIIIF for CKAN
upload_time2023-07-17 08:20:21
maintainer
docs_urlNone
author
requires_python>=3.6
licenseGPL-3.0-or-later
keywords ckan data iiif
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage
            <!--header-start-->
<img src="https://data.nhm.ac.uk/images/nhm_logo.svg" align="left" width="150px" height="100px" hspace="40"/>

# ckanext-iiif

[![Tests](https://img.shields.io/github/actions/workflow/status/NaturalHistoryMuseum/ckanext-iiif/main.yml?style=flat-square)](https://github.com/NaturalHistoryMuseum/ckanext-iiif/actions/workflows/main.yml)
[![Coveralls](https://img.shields.io/coveralls/github/NaturalHistoryMuseum/ckanext-iiif/main?style=flat-square)](https://coveralls.io/github/NaturalHistoryMuseum/ckanext-iiif)
[![CKAN](https://img.shields.io/badge/ckan-2.9.7-orange.svg?style=flat-square)](https://github.com/ckan/ckan)
[![Python](https://img.shields.io/badge/python-3.6%20%7C%203.7%20%7C%203.8-blue.svg?style=flat-square)](https://www.python.org/)
[![Docs](https://img.shields.io/readthedocs/ckanext-iiif?style=flat-square)](https://ckanext-iiif.readthedocs.io)

_IIIF for CKAN_

<!--header-end-->

# Overview

<!--overview-start-->
This extension enables IIIF functionality for CKAN by implementing the Presentation API.
Currently, this includes a single manifest builder for records, but through the `IIIIF`
interface you can extend the builders to include other IIIF resources.

<!--overview-end-->

# Installation

<!--installation-start-->
Path variables used below:
- `$INSTALL_FOLDER` (i.e. where CKAN is installed), e.g. `/usr/lib/ckan/default`
- `$CONFIG_FILE`, e.g. `/etc/ckan/default/development.ini`

## Installing from PyPI

```shell
pip install ckanext-iiif
```

## Installing from source

1. Clone the repository into the `src` folder:
   ```shell
   cd $INSTALL_FOLDER/src
   git clone https://github.com/NaturalHistoryMuseum/ckanext-iiif.git
   ```

2. Activate the virtual env:
   ```shell
   . $INSTALL_FOLDER/bin/activate
   ```

3. Install via pip:
   ```shell
   pip install $INSTALL_FOLDER/src/ckanext-iiif
   ```

### Installing in editable mode

Installing from a `pyproject.toml` in editable mode (i.e. `pip install -e`) requires `setuptools>=64`; however, CKAN 2.9 requires `setuptools==44.1.0`. See [our CKAN fork](https://github.com/NaturalHistoryMuseum/ckan) for a version of v2.9 that uses an updated setuptools if this functionality is something you need.

## Post-install setup

1. Add 'iiif' to the list of plugins in your `$CONFIG_FILE`:
   ```ini
   ckan.plugins = ... iiif
   ```

<!--installation-end-->

# Configuration

<!--configuration-start-->
There are no configuration options for this extension.

<!--configuration-end-->

# Usage

<!--usage-start-->
This extension's main function is provide a standard endpoint and action to create IIIF
resources.
These IIIF resources could be based on whatever you like - a record, a resource, a whole
dataset etc.

Presentation API IIIF resources can be accessed via either the `/iiif/<identifier>`
endpoint or the `build_iiif_resource` action where the identifier is passed in the data
dict in the key `"identifier"`.
When this occurs the identifier is matched against any of the registered IIIF resource
builders and if a match is found, the resource is returned.
Identifiers can be built if the builder ID is known along with the necessary parameters
by using the `build_iiif_identifier` action.

## Record Manifest Builder

By default, the only IIIF resource this extension can build is record manifests.
This requires the `record_show` action to be available from the `ckanext-nhm` extension
(there is
an [open issue](https://github.com/NaturalHistoryMuseum/ckanext-nhm/issues/602) to move
this action to a different extension, most likely
[ckanext-versioned-datastore](https://github.com/NaturalHistoryMuseum/ckanext-versioned-datastore))
.

To build a record manifest you must provide the appropriate identifier, which must be of
the format `resource/<resource_id>/record/<record_id>`, for example:
`resource/afea211d-1b3d-49ad-9d15-17f0de368967/record/429`.
This example identifies the record with ID `429` from the resource with ID
`afea211d-1b3d-49ad-9d15-17f0de368967`.
If the record and the resource can be found, and images can be found on the record, then
a manifest is returned.
If any of these conditions fail, the action returns `None` and the endpoint returns 404.

The images are detected in the record by looking for the `_image_field` extra on the
resource.
This should define the field name in the record where images can be found.
The value associated with this image field in the record can be:

- a string (should be a URL)
- a list of strings (each element should be a URL)
- a string containing several URLs separated by a delimiter (this should be defined on
  the resource using the `_image_delimiter` extra)
- a list of dicts (the URL is extracted by looking for an `identifier` field within
  each dict)

To fill out the values in the manifest, the builder pulls out fields as specified by
more resource level extras or by falling back to a default value.
These are:

- `"label"` - attempts to use `_title_field` extra but falls back to record ID
- `"rights"` - attempts to use `_image_licence` extra but falls back
  to [cc-by](https://creativecommons.org/licenses/by/4.0/)

The `"metadata"` field in the manifest is populated using the fields and values in the
record data itself.

## Adding a Custom Builder

To add a custom builder all you have to do is implement the `IIIIF` interface in your
extension plugin.
For example:

```python
import ckan.plugins as plugins
from typing import Optional, Callable
from typing import OrderedDict

from ckanext.iiif.builders.abc import IIIFResourceBuilder
from ckanext.iiif.interfaces import IIIIF


class MyBuilder(IIIFResourceBuilder):

    def match_and_build(self, identifier: str) -> Optional[dict]:
        ...

    def build_identifier(self, *args, **kwargs) -> str:
        ...


class MyExtension(plugins.SingletonPlugin):
    plugins.implements(IIIIF)

    def register_iiif_builders(self, builders: OrderedDict[str, IIIFResourceBuilder]):
        builders["my_builder"]: MyBuilder()
```

When a request is made to build a IIIF resource, each of the registered builders is
called in turn with the identifier.
This means that the builders need to both match the identifier to confirm it matches its
pattern or meets its criteria, and generate the manifest.

The builders should:

- Return `None` if the identifier doesn't match the builders requirements. When this
  happens, the logic continues and tries the next registered builder function.
- Raise a `ckanext.iiif.builders.utils.IIIFBuildError` if the identifier matched but the
  manifest couldn't be generated for any reason. This will stop the logic from checking
  any other builders for matches and return `None` to the caller.
- Raise any other type of `Exception` if an unexpected error occurred during matching or
  processing. This will be propagated to the caller.

<!--usage-end-->

# Testing

<!--testing-start-->
There is a Docker compose configuration available in this repository to make it easier to run tests. The ckan image uses the Dockerfile in the `docker/` folder.

To run the tests against ckan 2.9.x on Python3:

1. Build the required images:
   ```shell
   docker-compose build
   ```

2. Then run the tests.
   The root of the repository is mounted into the ckan container as a volume by the Docker compose
   configuration, so you should only need to rebuild the ckan image if you change the extension's
   dependencies.
   ```shell
   docker-compose run ckan
   ```

<!--testing-end-->

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "ckanext-iiif",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.6",
    "maintainer_email": "",
    "keywords": "CKAN,data,iiif",
    "author": "",
    "author_email": "Natural History Museum <data@nhm.ac.uk>",
    "download_url": "https://files.pythonhosted.org/packages/38/ac/bcc97fcd217abc8b7842f3c98cae9654d6e02cf2008abc2109c6499bf38a/ckanext-iiif-3.0.9.tar.gz",
    "platform": null,
    "description": "<!--header-start-->\n<img src=\"https://data.nhm.ac.uk/images/nhm_logo.svg\" align=\"left\" width=\"150px\" height=\"100px\" hspace=\"40\"/>\n\n# ckanext-iiif\n\n[![Tests](https://img.shields.io/github/actions/workflow/status/NaturalHistoryMuseum/ckanext-iiif/main.yml?style=flat-square)](https://github.com/NaturalHistoryMuseum/ckanext-iiif/actions/workflows/main.yml)\n[![Coveralls](https://img.shields.io/coveralls/github/NaturalHistoryMuseum/ckanext-iiif/main?style=flat-square)](https://coveralls.io/github/NaturalHistoryMuseum/ckanext-iiif)\n[![CKAN](https://img.shields.io/badge/ckan-2.9.7-orange.svg?style=flat-square)](https://github.com/ckan/ckan)\n[![Python](https://img.shields.io/badge/python-3.6%20%7C%203.7%20%7C%203.8-blue.svg?style=flat-square)](https://www.python.org/)\n[![Docs](https://img.shields.io/readthedocs/ckanext-iiif?style=flat-square)](https://ckanext-iiif.readthedocs.io)\n\n_IIIF for CKAN_\n\n<!--header-end-->\n\n# Overview\n\n<!--overview-start-->\nThis extension enables IIIF functionality for CKAN by implementing the Presentation API.\nCurrently, this includes a single manifest builder for records, but through the `IIIIF`\ninterface you can extend the builders to include other IIIF resources.\n\n<!--overview-end-->\n\n# Installation\n\n<!--installation-start-->\nPath variables used below:\n- `$INSTALL_FOLDER` (i.e. where CKAN is installed), e.g. `/usr/lib/ckan/default`\n- `$CONFIG_FILE`, e.g. `/etc/ckan/default/development.ini`\n\n## Installing from PyPI\n\n```shell\npip install ckanext-iiif\n```\n\n## Installing from source\n\n1. Clone the repository into the `src` folder:\n   ```shell\n   cd $INSTALL_FOLDER/src\n   git clone https://github.com/NaturalHistoryMuseum/ckanext-iiif.git\n   ```\n\n2. Activate the virtual env:\n   ```shell\n   . $INSTALL_FOLDER/bin/activate\n   ```\n\n3. Install via pip:\n   ```shell\n   pip install $INSTALL_FOLDER/src/ckanext-iiif\n   ```\n\n### Installing in editable mode\n\nInstalling from a `pyproject.toml` in editable mode (i.e. `pip install -e`) requires `setuptools>=64`; however, CKAN 2.9 requires `setuptools==44.1.0`. See [our CKAN fork](https://github.com/NaturalHistoryMuseum/ckan) for a version of v2.9 that uses an updated setuptools if this functionality is something you need.\n\n## Post-install setup\n\n1. Add 'iiif' to the list of plugins in your `$CONFIG_FILE`:\n   ```ini\n   ckan.plugins = ... iiif\n   ```\n\n<!--installation-end-->\n\n# Configuration\n\n<!--configuration-start-->\nThere are no configuration options for this extension.\n\n<!--configuration-end-->\n\n# Usage\n\n<!--usage-start-->\nThis extension's main function is provide a standard endpoint and action to create IIIF\nresources.\nThese IIIF resources could be based on whatever you like - a record, a resource, a whole\ndataset etc.\n\nPresentation API IIIF resources can be accessed via either the `/iiif/<identifier>`\nendpoint or the `build_iiif_resource` action where the identifier is passed in the data\ndict in the key `\"identifier\"`.\nWhen this occurs the identifier is matched against any of the registered IIIF resource\nbuilders and if a match is found, the resource is returned.\nIdentifiers can be built if the builder ID is known along with the necessary parameters\nby using the `build_iiif_identifier` action.\n\n## Record Manifest Builder\n\nBy default, the only IIIF resource this extension can build is record manifests.\nThis requires the `record_show` action to be available from the `ckanext-nhm` extension\n(there is\nan [open issue](https://github.com/NaturalHistoryMuseum/ckanext-nhm/issues/602) to move\nthis action to a different extension, most likely\n[ckanext-versioned-datastore](https://github.com/NaturalHistoryMuseum/ckanext-versioned-datastore))\n.\n\nTo build a record manifest you must provide the appropriate identifier, which must be of\nthe format `resource/<resource_id>/record/<record_id>`, for example:\n`resource/afea211d-1b3d-49ad-9d15-17f0de368967/record/429`.\nThis example identifies the record with ID `429` from the resource with ID\n`afea211d-1b3d-49ad-9d15-17f0de368967`.\nIf the record and the resource can be found, and images can be found on the record, then\na manifest is returned.\nIf any of these conditions fail, the action returns `None` and the endpoint returns 404.\n\nThe images are detected in the record by looking for the `_image_field` extra on the\nresource.\nThis should define the field name in the record where images can be found.\nThe value associated with this image field in the record can be:\n\n- a string (should be a URL)\n- a list of strings (each element should be a URL)\n- a string containing several URLs separated by a delimiter (this should be defined on\n  the resource using the `_image_delimiter` extra)\n- a list of dicts (the URL is extracted by looking for an `identifier` field within\n  each dict)\n\nTo fill out the values in the manifest, the builder pulls out fields as specified by\nmore resource level extras or by falling back to a default value.\nThese are:\n\n- `\"label\"` - attempts to use `_title_field` extra but falls back to record ID\n- `\"rights\"` - attempts to use `_image_licence` extra but falls back\n  to [cc-by](https://creativecommons.org/licenses/by/4.0/)\n\nThe `\"metadata\"` field in the manifest is populated using the fields and values in the\nrecord data itself.\n\n## Adding a Custom Builder\n\nTo add a custom builder all you have to do is implement the `IIIIF` interface in your\nextension plugin.\nFor example:\n\n```python\nimport ckan.plugins as plugins\nfrom typing import Optional, Callable\nfrom typing import OrderedDict\n\nfrom ckanext.iiif.builders.abc import IIIFResourceBuilder\nfrom ckanext.iiif.interfaces import IIIIF\n\n\nclass MyBuilder(IIIFResourceBuilder):\n\n    def match_and_build(self, identifier: str) -> Optional[dict]:\n        ...\n\n    def build_identifier(self, *args, **kwargs) -> str:\n        ...\n\n\nclass MyExtension(plugins.SingletonPlugin):\n    plugins.implements(IIIIF)\n\n    def register_iiif_builders(self, builders: OrderedDict[str, IIIFResourceBuilder]):\n        builders[\"my_builder\"]: MyBuilder()\n```\n\nWhen a request is made to build a IIIF resource, each of the registered builders is\ncalled in turn with the identifier.\nThis means that the builders need to both match the identifier to confirm it matches its\npattern or meets its criteria, and generate the manifest.\n\nThe builders should:\n\n- Return `None` if the identifier doesn't match the builders requirements. When this\n  happens, the logic continues and tries the next registered builder function.\n- Raise a `ckanext.iiif.builders.utils.IIIFBuildError` if the identifier matched but the\n  manifest couldn't be generated for any reason. This will stop the logic from checking\n  any other builders for matches and return `None` to the caller.\n- Raise any other type of `Exception` if an unexpected error occurred during matching or\n  processing. This will be propagated to the caller.\n\n<!--usage-end-->\n\n# Testing\n\n<!--testing-start-->\nThere is a Docker compose configuration available in this repository to make it easier to run tests. The ckan image uses the Dockerfile in the `docker/` folder.\n\nTo run the tests against ckan 2.9.x on Python3:\n\n1. Build the required images:\n   ```shell\n   docker-compose build\n   ```\n\n2. Then run the tests.\n   The root of the repository is mounted into the ckan container as a volume by the Docker compose\n   configuration, so you should only need to rebuild the ckan image if you change the extension's\n   dependencies.\n   ```shell\n   docker-compose run ckan\n   ```\n\n<!--testing-end-->\n",
    "bugtrack_url": null,
    "license": "GPL-3.0-or-later",
    "summary": "IIIF for CKAN",
    "version": "3.0.9",
    "project_urls": {
        "changelog": "https://github.com/NaturalHistoryMuseum/ckanext-iiif/blob/main/CHANGELOG.md",
        "repository": "https://github.com/NaturalHistoryMuseum/ckanext-iiif"
    },
    "split_keywords": [
        "ckan",
        "data",
        "iiif"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "72d2b363ead7d3e604cdf693324318e8854edecff58422b8b656a6604b49aa51",
                "md5": "fd1c245c788601af4e74bcb641527263",
                "sha256": "6ab70e6e2343c6788036a388d4809747b8c0d43ac878d057273aca688e041c02"
            },
            "downloads": -1,
            "filename": "ckanext_iiif-3.0.9-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "fd1c245c788601af4e74bcb641527263",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.6",
            "size": 35529,
            "upload_time": "2023-07-17T08:20:19",
            "upload_time_iso_8601": "2023-07-17T08:20:19.222138Z",
            "url": "https://files.pythonhosted.org/packages/72/d2/b363ead7d3e604cdf693324318e8854edecff58422b8b656a6604b49aa51/ckanext_iiif-3.0.9-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "38acbcc97fcd217abc8b7842f3c98cae9654d6e02cf2008abc2109c6499bf38a",
                "md5": "9d08f14484374d068861e1c818937aec",
                "sha256": "41731e3912c745a25727e8f720cd45c57efaf0f2f3768c1d8b4b40eaa4a0b1b8"
            },
            "downloads": -1,
            "filename": "ckanext-iiif-3.0.9.tar.gz",
            "has_sig": false,
            "md5_digest": "9d08f14484374d068861e1c818937aec",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.6",
            "size": 32024,
            "upload_time": "2023-07-17T08:20:21",
            "upload_time_iso_8601": "2023-07-17T08:20:21.036335Z",
            "url": "https://files.pythonhosted.org/packages/38/ac/bcc97fcd217abc8b7842f3c98cae9654d6e02cf2008abc2109c6499bf38a/ckanext-iiif-3.0.9.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-07-17 08:20:21",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "NaturalHistoryMuseum",
    "github_project": "ckanext-iiif",
    "travis_ci": false,
    "coveralls": true,
    "github_actions": true,
    "lcname": "ckanext-iiif"
}
        
Elapsed time: 0.09197s