adapters.py
280 lines
| 6.4 KiB
| text/x-python
|
PythonLexer
r5040 | ||||
r3912 | """ | |||
Adapters | ||||
-------- | ||||
.. contents:: | ||||
:backlinks: none | ||||
The :func:`authomatic.login` function needs access to functionality like | ||||
getting the **URL** of the handler where it is being called, getting the | ||||
**request params** and **cookies** and **writing the body**, **headers** | ||||
and **status** to the response. | ||||
Since implementation of these features varies across Python web frameworks, | ||||
the Authomatic library uses **adapters** to unify these differences into a | ||||
single interface. | ||||
Available Adapters | ||||
^^^^^^^^^^^^^^^^^^ | ||||
If you are missing an adapter for the framework of your choice, please | ||||
open an `enhancement issue <https://github.com/authomatic/authomatic/issues>`_ | ||||
or consider a contribution to this module by | ||||
:ref:`implementing <implement_adapters>` one by yourself. | ||||
Its very easy and shouldn't take you more than a few minutes. | ||||
.. autoclass:: DjangoAdapter | ||||
:members: | ||||
.. autoclass:: Webapp2Adapter | ||||
:members: | ||||
.. autoclass:: WebObAdapter | ||||
:members: | ||||
.. autoclass:: WerkzeugAdapter | ||||
:members: | ||||
.. _implement_adapters: | ||||
Implementing an Adapter | ||||
^^^^^^^^^^^^^^^^^^^^^^^ | ||||
Implementing an adapter for a Python web framework is pretty easy. | ||||
Do it by subclassing the :class:`.BaseAdapter` abstract class. | ||||
There are only **six** members that you need to implement. | ||||
Moreover if your framework is based on the |webob|_ or |werkzeug|_ package | ||||
you can subclass the :class:`.WebObAdapter` or :class:`.WerkzeugAdapter` | ||||
respectively. | ||||
.. autoclass:: BaseAdapter | ||||
:members: | ||||
""" | ||||
import abc | ||||
from authomatic.core import Response | ||||
r4973 | class BaseAdapter(object, metaclass=abc.ABCMeta): | |||
r3912 | """ | |||
Base class for platform adapters. | ||||
Defines common interface for WSGI framework specific functionality. | ||||
""" | ||||
@abc.abstractproperty | ||||
def params(self): | ||||
""" | ||||
Must return a :class:`dict` of all request parameters of any HTTP | ||||
method. | ||||
:returns: | ||||
:class:`dict` | ||||
""" | ||||
@abc.abstractproperty | ||||
def url(self): | ||||
""" | ||||
Must return the url of the actual request including path but without | ||||
query and fragment. | ||||
:returns: | ||||
:class:`str` | ||||
""" | ||||
@abc.abstractproperty | ||||
def cookies(self): | ||||
""" | ||||
Must return cookies as a :class:`dict`. | ||||
:returns: | ||||
:class:`dict` | ||||
""" | ||||
@abc.abstractmethod | ||||
def write(self, value): | ||||
""" | ||||
Must write specified value to response. | ||||
:param str value: | ||||
String to be written to response. | ||||
""" | ||||
@abc.abstractmethod | ||||
def set_header(self, key, value): | ||||
""" | ||||
Must set response headers to ``Key: value``. | ||||
:param str key: | ||||
Header name. | ||||
:param str value: | ||||
Header value. | ||||
""" | ||||
@abc.abstractmethod | ||||
def set_status(self, status): | ||||
""" | ||||
Must set the response status e.g. ``'302 Found'``. | ||||
:param str status: | ||||
The HTTP response status. | ||||
""" | ||||
class DjangoAdapter(BaseAdapter): | ||||
""" | ||||
Adapter for the |django|_ framework. | ||||
""" | ||||
def __init__(self, request, response): | ||||
""" | ||||
:param request: | ||||
An instance of the :class:`django.http.HttpRequest` class. | ||||
:param response: | ||||
An instance of the :class:`django.http.HttpResponse` class. | ||||
""" | ||||
self.request = request | ||||
self.response = response | ||||
@property | ||||
def params(self): | ||||
params = {} | ||||
params.update(self.request.GET.dict()) | ||||
params.update(self.request.POST.dict()) | ||||
return params | ||||
@property | ||||
def url(self): | ||||
return self.request.build_absolute_uri(self.request.path) | ||||
@property | ||||
def cookies(self): | ||||
return dict(self.request.COOKIES) | ||||
def write(self, value): | ||||
self.response.write(value) | ||||
def set_header(self, key, value): | ||||
self.response[key] = value | ||||
def set_status(self, status): | ||||
status_code, reason = status.split(' ', 1) | ||||
self.response.status_code = int(status_code) | ||||
class WebObAdapter(BaseAdapter): | ||||
""" | ||||
Adapter for the |webob|_ package. | ||||
""" | ||||
def __init__(self, request, response): | ||||
""" | ||||
:param request: | ||||
A |webob|_ :class:`Request` instance. | ||||
:param response: | ||||
A |webob|_ :class:`Response` instance. | ||||
""" | ||||
self.request = request | ||||
self.response = response | ||||
# ========================================================================= | ||||
# Request | ||||
# ========================================================================= | ||||
@property | ||||
def url(self): | ||||
return self.request.path_url | ||||
@property | ||||
def params(self): | ||||
return dict(self.request.params) | ||||
@property | ||||
def cookies(self): | ||||
return dict(self.request.cookies) | ||||
# ========================================================================= | ||||
# Response | ||||
# ========================================================================= | ||||
def write(self, value): | ||||
self.response.write(value) | ||||
def set_header(self, key, value): | ||||
self.response.headers[key] = str(value) | ||||
def set_status(self, status): | ||||
self.response.status = status | ||||
class Webapp2Adapter(WebObAdapter): | ||||
""" | ||||
Adapter for the |webapp2|_ framework. | ||||
Inherits from the :class:`.WebObAdapter`. | ||||
""" | ||||
def __init__(self, handler): | ||||
""" | ||||
:param handler: | ||||
A :class:`webapp2.RequestHandler` instance. | ||||
""" | ||||
self.request = handler.request | ||||
self.response = handler.response | ||||
class WerkzeugAdapter(BaseAdapter): | ||||
""" | ||||
Adapter for |flask|_ and other |werkzeug|_ based frameworks. | ||||
Thanks to `Mark Steve Samson <http://marksteve.com>`_. | ||||
""" | ||||
@property | ||||
def params(self): | ||||
return self.request.args | ||||
@property | ||||
def url(self): | ||||
return self.request.base_url | ||||
@property | ||||
def cookies(self): | ||||
return self.request.cookies | ||||
def __init__(self, request, response): | ||||
""" | ||||
:param request: | ||||
Instance of the :class:`werkzeug.wrappers.Request` class. | ||||
:param response: | ||||
Instance of the :class:`werkzeug.wrappers.Response` class. | ||||
""" | ||||
self.request = request | ||||
self.response = response | ||||
def write(self, value): | ||||
r5114 | self.response.data = self.response.data.decode('utf-8') + value | |||
r3912 | ||||
def set_header(self, key, value): | ||||
self.response.headers[key] = value | ||||
def set_status(self, status): | ||||
self.response.status = status | ||||