text: '''
  This bottle-sqlalchemy plugin integrates SQLAlchemy with your Bottle
  application. It connects to a database at the beginning of a request,
  passes the database handle to the route callback and closes the connection
  afterwards.
  
  The plugin inject an argument to all route callbacks that require a `db`
  keyword.
  
  Usage Example::
  
      import bottle
      from bottle import HTTPError
      from bottle.ext import sqlalchemy
      from sqlalchemy import create_engine, Column, Integer, Sequence, String
      from sqlalchemy.ext.declarative import declarative_base
  
      Base = declarative_base()
      engine = create_engine('sqlite:///:memory:', echo=True)
  
      app = bottle.Bottle()
      plugin = sqlalchemy.Plugin(engine, Base.metadata, create=True)
      app.install(plugin)
  
      class Entity(Base):
          __tablename__ = 'entity'
          id = Column(Integer, Sequence('id_seq'), primary_key=True)
          name = Column(String(50))
  
          def __init__(self, name):
              self.name = name
  
          def __repr__(self):
              return "<Entity('%d', '%s')>" % (self.id, self.name)
  
  
      @app.get('/:name')
      def show(name, db):
          entity = db.query(Entity).filter_by(name=name).first()
          if entity:
              return {'id': entity.id, 'name': entity.name}
          return HTTPError(404, 'Entity not found.')
  
      @app.put('/:name')
      def put_name(name, db):
          entity = Entity(name)
          db.add(entity)
  
  
  It is up to you create engine and metadata, because SQLAlchemy has
  a lot of options to do it. The plugin just handles the SQLAlchemy
  session.
  
  Copyright (c) 2011-2012, Iuri de Silvio
  License: MIT (see LICENSE for details)
  '''
  
  import inspect
  
  import bottle
  from sqlalchemy.exc import SQLAlchemyError
  from sqlalchemy.orm import sessionmaker
  from sqlalchemy.orm.scoping import ScopedSession
  
  # PluginError is defined to bottle >= 0.10
  if not hasattr(bottle, 'PluginError'):
      class PluginError(bottle.BottleException):
          pass
      bottle.PluginError = PluginError
  
  
  class SQLAlchemyPlugin(object):
  
      name = 'sqlalchemy'
      api = 2
  
      def __init__(self, engine, metadata=None,
                   keyword='db', commit=True, create=False, use_kwargs=False, create_session=None):
          '''
          :param engine: SQLAlchemy engine created with `create_engine` function
          :param metadata: SQLAlchemy metadata. It is required only if `create=True`
          :param keyword: Keyword used to inject session database in a route
          :param create: If it is true, execute `metadata.create_all(engine)`
                 when plugin is applied
          :param commit: If it is true, commit changes after route is executed.
          :param use_kwargs: plugin inject session database even if it is not
                 explicitly defined, using **kwargs argument if defined.
          :param create_session: SQLAlchemy session maker created with the 
                  'sessionmaker' function. Will create its own if undefined.
          '''
          self.engine = engine
          if create_session is None:
              create_session = sessionmaker()
          self.create_session = create_session
          self.metadata = metadata
          self.keyword = keyword
          self.create = create
          self.commit = commit
          self.use_kwargs = use_kwargs
  
      def setup(self, app):
          ''' 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, SQLAlchemyPlugin):
                  continue
              if other.keyword == self.keyword:
                  raise bottle.PluginError("Found another SQLAlchemy plugin with "\
                                    "conflicting settings (non-unique keyword).")
              elif other.name == self.name:
                  self.name += '_%s' % self.keyword
          if self.create and not self.metadata:
              raise bottle.PluginError('Define metadata value to create database.')
      
      def apply(self, callback, route):
          # hack to support bottle v0.9.x
          if bottle.__version__.startswith('0.9'):
              config = route['config']
              _callback = route['callback']
          else:
              config = route.config
              _callback = route.callback
  
          if "sqlalchemy" in config:  # support for configuration before `ConfigDict` namespaces
              g = lambda key, default: config.get('sqlalchemy', {}).get(key, default)
          else:
              g = lambda key, default: config.get('sqlalchemy.' + key, default)
  
          keyword = g('keyword', self.keyword)
          create = g('create', self.create)
          commit = g('commit', self.commit)
          use_kwargs = g('use_kwargs', self.use_kwargs)
  
          try:
              # check if inspect.signature exists
              inspect.signature
          except AttributeError:
              argspec = inspect.getargspec(_callback)
              parameters = argspec.args
              accept_kwargs = argspec.keywords
          else:
              parameters = inspect.signature(_callback).parameters
              accept_kwargs = any(p.kind == inspect.Parameter.VAR_KEYWORD
                                  for p in parameters.values())
  
          if not ((use_kwargs and accept_kwargs) or keyword in parameters):
              return callback
  
          if create:
              self.metadata.create_all(self.engine)
  
          def wrapper(*args, **kwargs):
              kwargs[keyword] = session = self.create_session(bind=self.engine)
              try:
                  rv = callback(*args, **kwargs)
                  if commit:
                      session.commit()
              except (SQLAlchemyError, bottle.HTTPError):
                  session.rollback()
                  raise
              except bottle.HTTPResponse:
                  if commit:
                      session.commit()
                  raise
              finally:
                  if isinstance(self.create_session, ScopedSession):
                      self.create_session.remove()
                  else:
                      session.close()
              return rv
  
          return wrapper
  
  
  Plugin = SQLAlchemyPlugin