2017-04-03 17:29:29 +02:00
|
|
|
# coding: utf-8
|
|
|
|
"""
|
|
|
|
This module contains a Bottle plugin to pass the database argument to any route
|
|
|
|
which needs it.
|
2017-04-13 23:22:11 +02:00
|
|
|
|
|
|
|
This module is heavily based on code from
|
|
|
|
[Bottle-SQLAlchemy](https://github.com/iurisilvio/bottle-sqlalchemy) which is
|
|
|
|
licensed under MIT license.
|
2017-04-03 17:29:29 +02:00
|
|
|
"""
|
2021-01-26 14:39:52 +01:00
|
|
|
from __future__ import absolute_import, division, print_function, unicode_literals
|
2017-04-03 17:29:29 +02:00
|
|
|
|
|
|
|
import inspect
|
|
|
|
|
|
|
|
import bottle
|
|
|
|
|
|
|
|
|
|
|
|
class DatabasePlugin(object):
|
2017-04-13 23:22:11 +02:00
|
|
|
"""
|
|
|
|
A Bottle plugin to automatically pass an SQLAlchemy database session object
|
|
|
|
to the routes specifying they need it.
|
|
|
|
"""
|
2021-01-26 14:39:52 +01:00
|
|
|
|
|
|
|
name = "database"
|
2017-04-03 17:29:29 +02:00
|
|
|
api = 2
|
|
|
|
KEYWORD = "db"
|
|
|
|
|
|
|
|
def __init__(self, get_session):
|
|
|
|
"""
|
|
|
|
:param create_session: SQLAlchemy session maker created with the
|
|
|
|
'sessionmaker' function. Will create its own if undefined.
|
|
|
|
"""
|
|
|
|
self.get_session = get_session
|
|
|
|
|
2017-04-27 07:52:16 +02:00
|
|
|
def setup(self, app): # pylint: disable=locally-disabled,no-self-use
|
2017-04-03 17:29:29 +02:00
|
|
|
"""
|
|
|
|
Make sure that other installed plugins don't affect the same
|
|
|
|
keyword argument and check if metadata is available.
|
|
|
|
"""
|
|
|
|
for other in app.plugins:
|
|
|
|
if not isinstance(other, DatabasePlugin):
|
|
|
|
continue
|
|
|
|
else:
|
2021-01-26 14:39:52 +01:00
|
|
|
raise bottle.PluginError("Found another conflicting Database plugin.")
|
2017-04-03 17:29:29 +02:00
|
|
|
|
|
|
|
def apply(self, callback, route):
|
2017-04-13 23:22:11 +02:00
|
|
|
"""
|
|
|
|
Method called on route invocation. Should apply some transformations to
|
|
|
|
the route prior to returing it.
|
|
|
|
|
|
|
|
We check the presence of ``self.KEYWORD`` in the route signature and
|
|
|
|
replace the route callback by a partial invocation where we replaced
|
|
|
|
this argument by a valid SQLAlchemy session.
|
|
|
|
"""
|
|
|
|
# Check whether the route needs a valid db session or not.
|
2017-04-03 17:29:29 +02:00
|
|
|
try:
|
|
|
|
callback_args = inspect.signature(route.callback).parameters
|
|
|
|
except AttributeError:
|
|
|
|
# inspect.signature does not exist on older Python
|
|
|
|
callback_args = inspect.getargspec(route.callback).args
|
|
|
|
|
|
|
|
if self.KEYWORD not in callback_args:
|
2017-04-13 23:22:11 +02:00
|
|
|
# If no need for a db session, call the route callback
|
2017-04-03 17:29:29 +02:00
|
|
|
return callback
|
2021-01-26 14:39:52 +01:00
|
|
|
|
2017-04-27 16:37:39 +02:00
|
|
|
def wrapper(*args, **kwargs):
|
|
|
|
"""
|
|
|
|
Wrap the callback in a call to get_session.
|
|
|
|
"""
|
|
|
|
with self.get_session() as session:
|
|
|
|
# Get a db session and pass it to the callback
|
|
|
|
kwargs[self.KEYWORD] = session
|
|
|
|
return callback(*args, **kwargs)
|
2021-01-26 14:39:52 +01:00
|
|
|
|
2017-04-27 16:37:39 +02:00
|
|
|
return wrapper
|
2017-04-03 17:29:29 +02:00
|
|
|
|
|
|
|
|
|
|
|
Plugin = DatabasePlugin
|