-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #40 from jerive/feature/aio-support
Onfido client asyncio support
- Loading branch information
Showing
21 changed files
with
970 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
from .onfido import Api | ||
from .onfido import AsyncApi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
from aiohttp import BufferedReaderPayload, ClientSession, MultipartWriter, StringPayload | ||
from .exceptions import OnfidoRequestError | ||
from aiohttp.client_reqrep import ClientResponse | ||
from .onfido_download import OnfidoAioDownload | ||
from .exceptions import async_error_decorator, OnfidoUnknownError | ||
from .mimetype import mimetype_from_name | ||
from .utils import form_data_converter | ||
from typing import BinaryIO | ||
|
||
try: | ||
import importlib.metadata as importlib_metadata | ||
except ImportError: | ||
import importlib_metadata | ||
|
||
CURRENT_VERSION = importlib_metadata.version("onfido-python") | ||
|
||
|
||
class Resource: | ||
def __init__(self, api_token, region, aio_session: ClientSession, timeout): | ||
self._api_token = api_token | ||
self._region = region | ||
self._timeout = timeout | ||
self._aio_session = aio_session | ||
|
||
@property | ||
def _url(self): | ||
return getattr(self._region, "region_url", self._region) | ||
|
||
def _build_url(self, path): | ||
return self._url + path | ||
|
||
@property | ||
def _headers(self): | ||
return { | ||
"User-Agent": f"onfido-python/{CURRENT_VERSION}", | ||
"Authorization": f"Token token={self._api_token}", | ||
} | ||
|
||
async def _handle_response(self, response: ClientResponse): | ||
if response.status == 422: | ||
error = None | ||
if response.code == 422: | ||
content_type = response.headers.get("Content-Type", "") | ||
if "application/json" in content_type: | ||
resp_json = await response.json() | ||
error = resp_json.get("error") | ||
raise OnfidoRequestError(error) | ||
|
||
response.raise_for_status() | ||
if response.status == 204: | ||
return None | ||
|
||
try: | ||
return await response.json() | ||
except ValueError as e: | ||
raise OnfidoUnknownError("Onfido returned invalid JSON") from e | ||
|
||
@async_error_decorator | ||
async def _upload_request(self, path, file: BinaryIO, **request_body): | ||
import uuid | ||
|
||
boundary = uuid.uuid4().hex | ||
with MultipartWriter("form-data", boundary=boundary) as mpwriter: | ||
for k, v in form_data_converter(request_body).items(): | ||
part = mpwriter.append( | ||
StringPayload( | ||
v, headers={"Content-Disposition": f'form-data; name="{k}"'} | ||
) | ||
) | ||
|
||
file_part = mpwriter.append_payload( | ||
BufferedReaderPayload( | ||
file, | ||
content_type=mimetype_from_name(file.name), | ||
headers={ | ||
"Content-Disposition": f'form-data; name="file"; filename="{file.name}"' | ||
}, | ||
) | ||
) | ||
additional_headers = { | ||
"Content-Type": f"multipart/form-data;boundary={boundary}" | ||
} | ||
async with self._aio_session.post( | ||
self._build_url(path), | ||
data=mpwriter, | ||
headers=dict(self._headers, **additional_headers), | ||
timeout=self._timeout, | ||
) as response: | ||
return await self._handle_response(response) | ||
|
||
@async_error_decorator | ||
async def _post(self, path, **request_body): | ||
async with self._aio_session.post( | ||
self._build_url(path), | ||
json=request_body, | ||
headers=self._headers, | ||
timeout=self._timeout, | ||
) as response: | ||
return await self._handle_response(response) | ||
|
||
@async_error_decorator | ||
async def _put(self, path, data=None): | ||
async with self._aio_session.put( | ||
self._build_url(path), | ||
json=data, | ||
headers=self._headers, | ||
timeout=self._timeout, | ||
) as response: | ||
return await self._handle_response(response) | ||
|
||
@async_error_decorator | ||
async def _get(self, path, payload=None): | ||
async with self._aio_session.get( | ||
self._build_url(path), headers=self._headers, timeout=self._timeout | ||
) as response: | ||
return await self._handle_response(response) | ||
|
||
@async_error_decorator | ||
async def _download_request(self, path): | ||
async with self._aio_session.get( | ||
self._build_url(path), headers=self._headers, timeout=self._timeout | ||
) as response: | ||
response.raise_for_status() | ||
|
||
return OnfidoAioDownload(response) | ||
|
||
@async_error_decorator | ||
async def _delete_request(self, path): | ||
async with self._aio_session.delete( | ||
self._build_url(path), headers=self._headers, timeout=self._timeout | ||
) as response: | ||
return await self._handle_response(response) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,11 @@ | ||
from aiohttp.client_reqrep import ClientResponse | ||
|
||
class OnfidoDownload: | ||
def __init__(self, response): | ||
self.content = response.content | ||
self.content_type = response.headers['content-type'] | ||
|
||
class OnfidoAioDownload: | ||
def __init__(self, response: ClientResponse): | ||
self.content = response.content | ||
self.content_type = response.content_type |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from ..aio_resource import Resource | ||
|
||
|
||
class Addresses(Resource): | ||
def pick(self, postcode: str): | ||
return self._get(f"addresses/pick?postcode={postcode}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
from ..aio_resource import Resource | ||
|
||
|
||
class Applicants(Resource): | ||
def create(self, request_body: dict): | ||
return self._post("applicants/", **request_body) | ||
|
||
def update(self, applicant_id: str, request_body: dict): | ||
return self._put(f"applicants/{applicant_id}", request_body) | ||
|
||
def find(self, applicant_id: str): | ||
return self._get(f"applicants/{applicant_id}") | ||
|
||
def delete(self, applicant_id: str): | ||
return self._delete_request(f"applicants/{applicant_id}") | ||
|
||
def all(self, **user_payload: dict): | ||
payload = {"include_deleted": False, "per_page": 20, "page": 1} | ||
payload.update(user_payload) | ||
return self._get("applicants", payload=payload) | ||
|
||
def restore(self, applicant_id: str): | ||
return self._post(f"applicants/{applicant_id}/restore") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
from ..aio_resource import Resource | ||
|
||
|
||
class Checks(Resource): | ||
def create(self, request_body: dict): | ||
return self._post("checks/", **request_body) | ||
|
||
def find(self, check_id: str): | ||
return self._get(f"checks/{check_id}") | ||
|
||
def all(self, applicant_id: str): | ||
payload = {"applicant_id": applicant_id} | ||
return self._get("checks/", payload=payload) | ||
|
||
def resume(self, check_id: str): | ||
return self._post(f"checks/{check_id}/resume") | ||
|
||
def download(self, check_id: str): | ||
return self._download_request(f"checks/{check_id}/download") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
from ..aio_resource import Resource | ||
from typing import BinaryIO | ||
|
||
|
||
class Documents(Resource): | ||
def upload(self, sample_file: BinaryIO, request_body): | ||
return self._upload_request("documents/", sample_file, **request_body) | ||
|
||
def find(self, document_id: str): | ||
return self._get(f"documents/{document_id}") | ||
|
||
def all(self, applicant_id: str): | ||
return self._get(f"documents?applicant_id={applicant_id}") | ||
|
||
def download(self, document_id: str): | ||
return self._download_request(f"documents/{document_id}/download") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from ..aio_resource import Resource | ||
|
||
|
||
class Extraction(Resource): | ||
def perform(self, document_id: str): | ||
return self._post("extractions/", document_id=document_id) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
from ..aio_resource import Resource | ||
from typing import BinaryIO | ||
|
||
|
||
class LivePhotos(Resource): | ||
def upload(self, sample_file: BinaryIO, request_body): | ||
return self._upload_request("live_photos/", sample_file, **request_body) | ||
|
||
def find(self, live_photo_id: str): | ||
return self._get(f"live_photos/{live_photo_id}") | ||
|
||
def all(self, applicant_id: str): | ||
payload = {"applicant_id": applicant_id} | ||
return self._get("live_photos/", payload=payload) | ||
|
||
def download(self, live_photo_id: str): | ||
return self._download_request(f"live_photos/{live_photo_id}/download") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
from ..aio_resource import Resource | ||
|
||
|
||
class LiveVideos(Resource): | ||
def find(self, live_video_id: str): | ||
return self._get(f"live_videos/{live_video_id}") | ||
|
||
def all(self, applicant_id: str): | ||
payload = {"applicant_id": applicant_id} | ||
return self._get("live_videos/", payload=payload) | ||
|
||
def download(self, live_video_id: str): | ||
return self._download_request(f"live_videos/{live_video_id}/download") | ||
|
||
def download_frame(self, live_video_id: str): | ||
return self._download_request(f"live_videos/{live_video_id}/frame") |
Oops, something went wrong.