Skip to content
Snippets Groups Projects
Commit 6ab0e3d7 authored by Erwan Rouchet's avatar Erwan Rouchet Committed by Bastien Abadie
Browse files

First version

parent 559584aa
No related branches found
No related tags found
No related merge requests found
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
dist/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# Pytest
.pytest_cache/
# Editors
.vscode/
[._]*.s[a-v][a-z]
[._]*.sw[a-p]
[._]s[a-rt-v][a-z]
[._]ss[a-gi-z]
[._]sw[a-p]
Session.vim
.netrwhist
*~
tags
[._]*.un~
stages:
- test
client-tests:
stage: test
image: python:3.5-alpine
script:
- pip install .[test]
- pytest
- flake8
0.1.0
"""
Arkindex API Client
"""
import requests
from urllib.parse import urljoin
class ArkindexAPI(object):
DEFAULT_BASE_URL = 'https://arkindex.teklia.com/api/v1/'
def __init__(self, token=None, base_url=DEFAULT_BASE_URL):
self.auth = ArkindexTokenAuth(token) if token else None
self.base_url = str(base_url)
if not self.base_url.endswith('/'):
self.base_url += '/'
def get(self, endpoint, params={}, requires_auth=False):
response = requests.get(
urljoin(self.base_url, endpoint),
params=params,
auth=self._get_auth(requires_auth),
)
response.raise_for_status()
return response.json()
def post(self, endpoint, params={}, json=None, requires_auth=False):
response = requests.post(
urljoin(self.base_url, endpoint),
params=params,
json=json,
auth=self._get_auth(requires_auth),
)
response.raise_for_status()
return response.json()
def get_elements(self, type='volume'):
return ResponsePaginator(self, 'elements', params={'type': type})
def get_related(self, id, type='page'):
return ResponsePaginator(self, 'elements/{}'.format(id), params={'type': type})
def get_pages(self, id):
return ResponsePaginator(self, 'elements/{}/pages'.format(id))
def create_element(self, **kwargs):
self.post('element', json=kwargs, requires_auth=True)
def _get_auth(self, requires_auth):
if not requires_auth:
return
if not self.auth:
raise ArkindexAPIError(
'This endpoint requires authentication, but no credentials have been provided')
return self.auth
class ResponsePaginator(object):
def __init__(self, client, *request_args, **request_kwargs):
assert isinstance(client, ArkindexAPI)
self.client = client
self.data = {}
self.results = []
self.request_args = request_args
self.request_kwargs = request_kwargs
if "params" not in self.request_kwargs:
self.request_kwargs['params'] = {}
self.current_page = 0
def _fetch_page(self, page):
self.request_kwargs['params']['page'] = page
self.data = self.client.get(*self.request_args, **self.request_kwargs)
self.results = self.data.get('results', [])
self.current_page = page
def __iter__(self):
return self
def __next__(self):
if len(self.results) < 1:
if self.data and self.data.get('next') is None:
raise StopIteration
self._fetch_page(self.current_page + 1)
return self.results.pop(0)
def __len__(self):
# Handle calls to len when no requests have been made yet
if not self.data and self.current_page < 1:
self._fetch_page(1)
return self.data['count']
class ArkindexTokenAuth(requests.auth.AuthBase):
"""
HTTP Authentication using a token
"""
def __init__(self, token):
self.token = token
def __call__(self, request):
request.headers['Authorization'] = "Token {}".format(self.token)
return request
class ArkindexAPIError(Exception):
"""
Describes any error from the Arkindex API.
"""
import pytest
from arkindex.client import ArkindexAPI
@pytest.fixture
def client():
return ArkindexAPI(
token='12345',
base_url='https://arkindex.test/api/v1')
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": "d82a00e7-9d21-451b-9958-b657a9af48c3",
"type": "volume",
"name": "JJ007",
"viewer_url": "https://mirador.test?manifest=http://arkindex.test/api/v1/manifest/d82a00e7-9d21-451b-9958-b657a9af48c3/pages"
},
{
"id": "51576b4b-29b6-416d-9ebd-706685c9438c",
"type": "volume",
"name": "JJ008",
"viewer_url": "https://mirador.test?manifest=http://arkindex.test/api/v1/manifest/51576b4b-29b6-416d-9ebd-706685c9438c/pages"
}
]
}
{
"count": 3,
"next": null,
"previous": null,
"results": [
{
"id": "b27ce670-e8dd-4b46-8b67-783bab844696",
"page_type": "page",
"nb": 1,
"direction": "recto",
"display_name": "Page no. 1, recto",
"image": {
"id": "583e7c72-8bdb-4caa-94ed-b767a78014f4",
"path": "Paris/FRCHANJJ_JJ007/jp2/FRCHANJJ_JJ007_0001R_A",
"width": 2559,
"height": 3447,
"url": "http://iiif.irht.cnrs.fr/iiif/Paris/FRCHANJJ_JJ007/jp2/FRCHANJJ_JJ007_0001R_A"
}
},
{
"id": "b4a74b13-80e1-4ff1-a83a-8daa64da8699",
"page_type": "page",
"nb": 1,
"direction": "verso",
"display_name": "Page no. 1, verso",
"image": {
"id": "b496af33-0fd8-4925-aa73-b53d7cc5ac3a",
"path": "Paris/FRCHANJJ_JJ007/jp2/FRCHANJJ_JJ007_0001V_A",
"width": 2459,
"height": 3399,
"url": "http://iiif.irht.cnrs.fr/iiif/Paris/FRCHANJJ_JJ007/jp2/FRCHANJJ_JJ007_0001V_A"
}
},
{
"id": "1a6ae8dd-b557-47f1-8729-b295c4bc9dea",
"page_type": "page",
"nb": 2,
"direction": "recto",
"display_name": "Page no. 2, recto",
"image": {
"id": "5f751939-751a-4606-a414-d27a2a9f4f60",
"path": "Paris/FRCHANJJ_JJ007/jp2/FRCHANJJ_JJ007_0002R_A",
"width": 2492,
"height": 3374,
"url": "http://iiif.irht.cnrs.fr/iiif/Paris/FRCHANJJ_JJ007/jp2/FRCHANJJ_JJ007_0002R_A"
}
}
]
}
{
"count": 3,
"next": null,
"previous": null,
"results": [
{
"id": "b27ce670-e8dd-4b46-8b67-783bab844696",
"type": "page",
"name": "Page 001r du volume JJ007",
"viewer_url": "https://mirador.test?manifest=http://arkindex.test/api/v1/manifest/b27ce670-e8dd-4b46-8b67-783bab844696/pages"
},
{
"id": "b4a74b13-80e1-4ff1-a83a-8daa64da8699",
"type": "page",
"name": "Page 001v du volume JJ007",
"viewer_url": "https://mirador.test?manifest=http://arkindex.test/api/v1/manifest/b4a74b13-80e1-4ff1-a83a-8daa64da8699/pages"
},
{
"id": "1a6ae8dd-b557-47f1-8729-b295c4bc9dea",
"type": "page",
"name": "Page 002r du volume JJ007",
"viewer_url": "https://mirador.test?manifest=http://arkindex.test/api/v1/manifest/1a6ae8dd-b557-47f1-8729-b295c4bc9dea/pages"
}
]
}
import responses
import os
import json
from arkindex.client import ResponsePaginator
FIXTURES = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
'fixtures',
)
@responses.activate
def test_get_elements(client):
responses.add(
responses.GET,
'https://arkindex.test/api/v1/elements',
json=json.load(open(os.path.join(FIXTURES, 'elements.json'))),
status=200,
)
response = client.get_elements()
assert isinstance(response, ResponsePaginator)
assert len(responses.calls) == 0
assert len(response) == 2
assert len(responses.calls) == 1
results = list(response)
assert len(responses.calls) == 1
assert all(isinstance(result, dict) for result in results)
assert all(result.keys() == {'id', 'type', 'name', 'viewer_url'} for result in results)
@responses.activate
def test_get_related(client):
responses.add(
responses.GET,
'https://arkindex.test/api/v1/elements/d82a00e7-9d21-451b-9958-b657a9af48c3',
json=json.load(open(os.path.join(FIXTURES, 'related.json'))),
status=200,
)
response = client.get_related('d82a00e7-9d21-451b-9958-b657a9af48c3', type="page")
assert isinstance(response, ResponsePaginator)
results = list(response)
assert len(results) == 3
assert all(isinstance(result, dict) for result in results)
assert all(result.keys() == {'id', 'type', 'name', 'viewer_url'} for result in results)
@responses.activate
def test_get_pages(client):
responses.add(
responses.GET,
'https://arkindex.test/api/v1/elements/d82a00e7-9d21-451b-9958-b657a9af48c3/pages',
json=json.load(open(os.path.join(FIXTURES, 'pages.json'))),
status=200,
)
response = client.get_pages('d82a00e7-9d21-451b-9958-b657a9af48c3')
assert isinstance(response, ResponsePaginator)
results = list(response)
assert len(results) == 3
for result in results:
assert isinstance(result, dict)
assert result.keys() == {
'id', 'page_type', 'nb', 'direction', 'display_name', 'image'
}
assert isinstance(result['image'], dict)
assert result['image'].keys() == {'id', 'path', 'width', 'height', 'url'}
@responses.activate
def test_create_element(client):
responses.add_callback(
responses.POST,
'https://arkindex.test/api/v1/element',
callback=lambda request: (201, {}, request.body),
content_type='application/json',
)
client.create_element(
type='transcription',
element='d82a00e7-9d21-451b-9958-b657a9af48c3',
text='Something',
polygon=[[0, 0], [0, 100], [100, 100], [100, 0], [0, 0]],
score=0.74,
)
assert len(responses.calls) == 1
assert responses.calls[0].request.headers['Authorization'] == 'Token 12345'
assert json.loads(responses.calls[0].request.body.decode()).keys() == \
{'type', 'element', 'text', 'polygon', 'score'}
requests>=2.16.0
[flake8]
max-line-length = 120
exclude=build,.eggs,.git
setup.py 0 → 100644
from setuptools import setup, find_packages
def read_requirements(filename):
return [req.strip() for req in open(filename)]
setup(
name='arkindex-client',
version=open('VERSION').read().strip(),
author='Teklia <contact@teklia.com>',
packages=find_packages(
exclude=["*.tests", "*.tests.*", "tests.*", "tests"]),
package_data={
'': ['*.md', 'LICENSE', 'README'],
},
install_requires=read_requirements('requirements.txt'),
extras_require={
'test': read_requirements('tests-requirements.txt'),
},
license='MIT',
description="API client for the Arkindex project",
long_description=open('README.md').read(),
keywords="api client arkindex",
url="https://gitlab.com/arkindex/api-client",
classifiers=[
"License :: OSI Approved :: MIT License",
"Natural Language :: English",
"Intended Audience :: Science/Research",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Scientific/Engineering :: Image Recognition",
"Topic :: Text Processing :: Indexing",
"Topic :: Text Processing :: Linguistic",
],
)
pytest>=3.6.2
responses>=0.9.0
flake8>=3.5.0
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment