-
Notifications
You must be signed in to change notification settings - Fork 0
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 #46 from odin-detector/async_adapter
Implement support for asynchronous adapters
- Loading branch information
Showing
44 changed files
with
4,677 additions
and
1,021 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
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,14 @@ | ||
[run] | ||
omit = | ||
*_version* | ||
src/odin/adapters/async_adapter.py | ||
|
||
[paths] | ||
source= | ||
src/ | ||
.tox/py*/lib/python*/site-packages/ | ||
|
||
[report] | ||
omit = | ||
*_version* | ||
*/async_*.py |
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 |
---|---|---|
|
@@ -3,7 +3,10 @@ language: python | |
sudo: false | ||
python: | ||
- 2.7 | ||
- 3.6 | ||
- 3.7 | ||
- 3.8 | ||
- 3.9 | ||
addons: | ||
apt: | ||
packages: | ||
|
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
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,123 @@ | ||
""" | ||
odin.adapters.adapter.py - base asynchronous API adapter implmentation for the ODIN server. | ||
Tim Nicholls, STFC Detector Systems Software Group | ||
""" | ||
|
||
import asyncio | ||
import logging | ||
import inspect | ||
|
||
from odin.adapters.adapter import ApiAdapter, ApiAdapterResponse | ||
|
||
|
||
class AsyncApiAdapter(ApiAdapter): | ||
""" | ||
Asynchronous API adapter base class. | ||
This class defines the basis for all async API adapters and provides default | ||
methods for the required HTTP verbs in case the derived classes fail to | ||
implement them, returning an error message and 400 code. | ||
""" | ||
|
||
is_async = True | ||
|
||
def __init__(self, **kwargs): | ||
"""Initialise the AsyncApiAdapter object. | ||
:param kwargs: keyword argument list that is copied into options dictionary | ||
""" | ||
super(AsyncApiAdapter, self).__init__(**kwargs) | ||
|
||
def __await__(self): | ||
"""Make AsyncApiAdapter objects awaitable. | ||
This magic method makes the instantiation of AsyncApiAdapter objects awaitable. This allows | ||
any underlying async and awaitable attributes, e.g. an AsyncParameterTree, to be correctly | ||
awaited when the adapter is loaded.""" | ||
async def closure(): | ||
"""Await all async attributes of the adapter.""" | ||
awaitable_attrs = [attr for attr in self.__dict__.values() if inspect.isawaitable(attr)] | ||
await asyncio.gather(*awaitable_attrs) | ||
return self | ||
|
||
return closure().__await__() | ||
|
||
async def initialize(self, adapters): | ||
"""Initialize the AsyncApiAdapter after it has been registered by the API Route. | ||
This is an abstract implementation of the initialize mechinism that allows | ||
an adapter to receive a list of loaded adapters, for Inter-adapter communication. | ||
:param adapters: a dictionary of the adapters loaded by the API route. | ||
""" | ||
|
||
pass | ||
|
||
async def cleanup(self): | ||
"""Clean up adapter state. | ||
This is an abstract implementation of the cleanup mechanism provided to allow adapters | ||
to clean up their state (e.g. disconnect cleanly from the device being controlled, set | ||
some status message). | ||
""" | ||
pass | ||
|
||
async def get(self, path, request): | ||
"""Handle an HTTP GET request. | ||
This method is an abstract implementation of the GET request handler for AsyncApiAdapter. | ||
:param path: URI path of resource | ||
:param request: HTTP request object passed from handler | ||
:return: ApiAdapterResponse container of data, content-type and status_code | ||
""" | ||
logging.debug('GET on path %s from %s: method not implemented by %s', | ||
path, request.remote_ip, self.name) | ||
await asyncio.sleep(0) | ||
response = "GET method not implemented by {}".format(self.name) | ||
return ApiAdapterResponse(response, status_code=400) | ||
|
||
async def post(self, path, request): | ||
"""Handle an HTTP POST request. | ||
This method is an abstract implementation of the POST request handler for AsyncApiAdapter. | ||
:param path: URI path of resource | ||
:param request: HTTP request object passed from handler | ||
:return: ApiAdapterResponse container of data, content-type and status_code | ||
""" | ||
logging.debug('POST on path %s from %s: method not implemented by %s', | ||
path, request.remote_ip, self.name) | ||
await asyncio.sleep(0) | ||
response = "POST method not implemented by {}".format(self.name) | ||
return ApiAdapterResponse(response, status_code=400) | ||
|
||
async def put(self, path, request): | ||
"""Handle an HTTP PUT request. | ||
This method is an abstract implementation of the PUT request handler for AsyncApiAdapter. | ||
:param path: URI path of resource | ||
:param request: HTTP request object passed from handler | ||
:return: ApiAdapterResponse container of data, content-type and status_code | ||
""" | ||
logging.debug('PUT on path %s from %s: method not implemented by %s', | ||
path, request.remote_ip, self.name) | ||
await asyncio.sleep(0) | ||
response = "PUT method not implemented by {}".format(self.name) | ||
return ApiAdapterResponse(response, status_code=400) | ||
|
||
async def delete(self, path, request): | ||
"""Handle an HTTP DELETE request. | ||
This method is an abstract implementation of the DELETE request handler for ApiAdapter. | ||
:param path: URI path of resource | ||
:param request: HTTP request object passed from handler | ||
:return: ApiAdapterResponse container of data, content-type and status_code | ||
""" | ||
logging.debug('DELETE on path %s from %s: method not implemented by %s', | ||
path, request.remote_ip, self.name) | ||
await asyncio.sleep(0) | ||
response = "DELETE method not implemented by {}".format(self.name) | ||
return ApiAdapterResponse(response, status_code=400) |
Oops, something went wrong.