##// END OF EJS Templates
merge: Resolved conflicts
merge: Resolved conflicts

File last commit:

r5114:6bd1539d default
r5471:df8a724f merge v5.1.0 stable
Show More
adapters.py
280 lines | 6.4 KiB | text/x-python | PythonLexer
"""
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
class BaseAdapter(object, metaclass=abc.ABCMeta):
"""
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):
self.response.data = self.response.data.decode('utf-8') + value
def set_header(self, key, value):
self.response.headers[key] = value
def set_status(self, status):
self.response.status = status