././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1601738733.1967854 bottle-sqlite-0.2.0/0000775000175000017500000000000000000000000014172 5ustar00marcmarc00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1601738733.1967854 bottle-sqlite-0.2.0/PKG-INFO0000664000175000017500000000334100000000000015270 0ustar00marcmarc00000000000000Metadata-Version: 1.1 Name: bottle-sqlite Version: 0.2.0 Summary: SQLite3 integration for Bottle. Home-page: https://github.com/bottlepy/bottle-sqlite Author: Marcel Hellkamp Author-email: marc@gsites.de License: MIT Description: Bottle-sqlite is a plugin that integrates SQLite3 with your Bottle application. It automatically connects to a database at the beginning of a request, passes the database handle to the route callback and closes the connection afterwards. To automatically detect routes that need a database connection, the plugin searches for route callbacks that require a `db` keyword argument (configurable) and skips routes that do not. This removes any overhead for routes that don't need a database connection. Usage Example:: import bottle from bottle.ext import sqlite app = bottle.Bottle() plugin = sqlite.Plugin(dbfile='/tmp/test.db') app.install(plugin) @app.route('/show/:item') def show(item, db): row = db.execute('SELECT * from items where name=?', item).fetchone() if row: return template('showitem', page=row) return HTTPError(404, "Page not found") Platform: any Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content Classifier: Topic :: Software Development :: Libraries :: Python Modules Requires: bottle (>=0.12) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1601738377.0 bottle-sqlite-0.2.0/README.rst0000664000175000017500000000756000000000000015671 0ustar00marcmarc00000000000000===================== Bottle-SQLite ===================== .. image:: https://travis-ci.org/bottlepy/bottle-sqlite.png?branch=master :target: https://travis-ci.org/bottlepy/bottle-sqlite :alt: Build Status - Travis CI SQLite is a self-contained SQL database engine that runs locally and does not require any additional server software or setup. The sqlite3 module is part of the Python standard library and already installed on most systems. It it very useful for prototyping database-driven applications that are later ported to larger databases such as PostgreSQL or MySQL. This plugin simplifies the use of sqlite databases in your Bottle applications. Once installed, all you have to do is to add a ``db`` keyword argument (configurable) to route callbacks that need a database connection. Installation =============== Install with one of the following commands:: $ pip install bottle-sqlite $ easy_install bottle-sqlite or download the latest version from github:: $ git clone git://github.com/bottlepy/bottle-sqlite.git $ cd bottle-sqlite $ python setup.py install Usage =============== Once installed to an application, the plugin passes an open :class:`sqlite3.Connection` instance to all routes that require a ``db`` keyword argument:: import bottle app = bottle.Bottle() plugin = bottle.ext.sqlite.Plugin(dbfile='/tmp/test.db') app.install(plugin) @app.route('/show/:item') def show(item, db): row = db.execute('SELECT * from items where name=?', item).fetchone() if row: return template('showitem', page=row) return HTTPError(404, "Page not found") Routes that do not expect a ``db`` keyword argument are not affected. The connection handle is configured so that :class:`sqlite3.Row` objects can be accessed both by index (like tuples) and case-insensitively by name. At the end of the request cycle, outstanding transactions are committed and the connection is closed automatically. If an error occurs, any changes to the database since the last commit are rolled back to keep the database in a consistent state. Configuration ============= The following configuration options exist for the plugin class: * **dbfile**: Database filename (default: in-memory database). * **keyword**: The keyword argument name that triggers the plugin (default: 'db'). * **autocommit**: Whether or not to commit outstanding transactions at the end of the request cycle (default: True). * **dictrows**: Whether or not to support dict-like access to row objects (default: True). * **text_factory**: The text_factory for the connection (default: unicode). * **functions**: Add user-defined functions for use in SQL, should be a dict like ``{'name': (num_params, func)}`` (default: None). * **aggregates**: Add user-defined aggregate functions, should be a dict like ``{'name': (num_params, aggregate_class)}`` (default: None). * **collations**: Add user-defined collations, should be a dict like ``{'name': callable}`` (default: None). * **extensions**: Load extensions on connect. Should be a list of extension names. (default: None). You can override each of these values on a per-route basis:: @app.route('/cache/:item', sqlite={'dbfile': ':memory:'}) def cache(item, db): ... or install two plugins with different ``keyword`` settings to the same application:: app = bottle.Bottle() test_db = bottle.ext.sqlite.Plugin(dbfile='/tmp/test.db') cache_db = bottle.ext.sqlite.Plugin(dbfile=':memory:', keyword='cache') app.install(test_db) app.install(cache_db) @app.route('/show/:item') def show(item, db): ... @app.route('/cache/:item') def cache(item, cache): ... Changelog ========= * **0.2** * Fixed `text_factory` parameter. * Added `functions`, `aggregates`, `collations` and `extensions` parameters. * Stopped testing for dead Python versions. ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1601738733.1967854 bottle-sqlite-0.2.0/bottle_sqlite.egg-info/0000775000175000017500000000000000000000000020536 5ustar00marcmarc00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1601738733.0 bottle-sqlite-0.2.0/bottle_sqlite.egg-info/PKG-INFO0000664000175000017500000000334100000000000021634 0ustar00marcmarc00000000000000Metadata-Version: 1.1 Name: bottle-sqlite Version: 0.2.0 Summary: SQLite3 integration for Bottle. Home-page: https://github.com/bottlepy/bottle-sqlite Author: Marcel Hellkamp Author-email: marc@gsites.de License: MIT Description: Bottle-sqlite is a plugin that integrates SQLite3 with your Bottle application. It automatically connects to a database at the beginning of a request, passes the database handle to the route callback and closes the connection afterwards. To automatically detect routes that need a database connection, the plugin searches for route callbacks that require a `db` keyword argument (configurable) and skips routes that do not. This removes any overhead for routes that don't need a database connection. Usage Example:: import bottle from bottle.ext import sqlite app = bottle.Bottle() plugin = sqlite.Plugin(dbfile='/tmp/test.db') app.install(plugin) @app.route('/show/:item') def show(item, db): row = db.execute('SELECT * from items where name=?', item).fetchone() if row: return template('showitem', page=row) return HTTPError(404, "Page not found") Platform: any Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content Classifier: Topic :: Software Development :: Libraries :: Python Modules Requires: bottle (>=0.12) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1601738733.0 bottle-sqlite-0.2.0/bottle_sqlite.egg-info/SOURCES.txt0000664000175000017500000000027000000000000022421 0ustar00marcmarc00000000000000README.rst bottle_sqlite.py setup.py bottle_sqlite.egg-info/PKG-INFO bottle_sqlite.egg-info/SOURCES.txt bottle_sqlite.egg-info/dependency_links.txt bottle_sqlite.egg-info/top_level.txt././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1601738733.0 bottle-sqlite-0.2.0/bottle_sqlite.egg-info/dependency_links.txt0000664000175000017500000000000100000000000024604 0ustar00marcmarc00000000000000 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1601738733.0 bottle-sqlite-0.2.0/bottle_sqlite.egg-info/top_level.txt0000664000175000017500000000001600000000000023265 0ustar00marcmarc00000000000000bottle_sqlite ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1601738377.0 bottle-sqlite-0.2.0/bottle_sqlite.py0000775000175000017500000001314700000000000017427 0ustar00marcmarc00000000000000''' Bottle-sqlite is a plugin that integrates SQLite3 with your Bottle application. It automatically connects to a database at the beginning of a request, passes the database handle to the route callback and closes the connection afterwards. To automatically detect routes that need a database connection, the plugin searches for route callbacks that require a `db` keyword argument (configurable) and skips routes that do not. This removes any overhead for routes that don't need a database connection. Usage Example:: import bottle from bottle.ext import sqlite app = bottle.Bottle() plugin = sqlite.Plugin(dbfile='/tmp/test.db') app.install(plugin) @app.route('/show/:item') def show(item, db): row = db.execute('SELECT * from items where name=?', item).fetchone() if row: return template('showitem', page=row) return HTTPError(404, "Page not found") ''' __author__ = "Marcel Hellkamp" __version__ = '0.2.0' __license__ = 'MIT' ### CUT HERE (see setup.py) import sqlite3 import inspect import bottle # PluginError is defined to bottle >= 0.10 if not hasattr(bottle, 'PluginError'): class PluginError(bottle.BottleException): pass bottle.PluginError = PluginError class SQLitePlugin(object): ''' This plugin passes an sqlite3 database handle to route callbacks that accept a `db` keyword argument. If a callback does not expect such a parameter, no connection is made. You can override the database settings on a per-route basis. ''' name = 'sqlite' api = 2 ''' python3 moves unicode to str ''' try: unicode except NameError: unicode = str def __init__(self, dbfile=':memory:', autocommit=True, dictrows=True, keyword='db', text_factory=unicode, functions=None, aggregates=None, collations=None, extensions=None): self.dbfile = dbfile self.autocommit = autocommit self.dictrows = dictrows self.keyword = keyword self.text_factory = text_factory self.functions = functions or {} self.aggregates = aggregates or {} self.collations = collations or {} self.extensions = extensions or () def setup(self, app): ''' Make sure that other installed plugins don't affect the same keyword argument.''' for other in app.plugins: if not isinstance(other, SQLitePlugin): continue if other.keyword == self.keyword: raise PluginError("Found another sqlite plugin with " "conflicting settings (non-unique keyword).") elif other.name == self.name: self.name += '_%s' % self.keyword 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 # Override global configuration with route-specific values. if "sqlite" in config: # support for configuration before `ConfigDict` namespaces g = lambda key, default: config.get('sqlite', {}).get(key, default) else: g = lambda key, default: config.get('sqlite.' + key, default) dbfile = g('dbfile', self.dbfile) autocommit = g('autocommit', self.autocommit) dictrows = g('dictrows', self.dictrows) keyword = g('keyword', self.keyword) text_factory = g('text_factory', self.text_factory) functions = g('functions', self.functions) aggregates = g('aggregates', self.aggregates) collations = g('collations', self.collations) extensions = g('extensions', self.extensions) # Test if the original callback accepts a 'db' keyword. # Ignore it if it does not need a database handle. argspec = inspect.getargspec(_callback) if keyword not in argspec.args: return callback def wrapper(*args, **kwargs): # Connect to the database db = sqlite3.connect(dbfile) # set text factory db.text_factory = text_factory # This enables column access by name: row['column_name'] if dictrows: db.row_factory = sqlite3.Row # Create user functions, aggregates and collations for name, value in functions.items(): db.create_function(name, *value) for name, value in aggregates.items(): db.create_aggregate(name, *value) for name, value in collations.items(): db.create_collation(name, value) for name in extensions: db.enable_load_extension(True) db.execute("SELECT load_extension(?)", (name,)) db.enable_load_extension(False) # Add the connection handle as a keyword argument. kwargs[keyword] = db try: rv = callback(*args, **kwargs) if autocommit: db.commit() except sqlite3.IntegrityError as e: db.rollback() raise bottle.HTTPError(500, "Database Error", e) except bottle.HTTPError as e: raise except bottle.HTTPResponse as e: if autocommit: db.commit() raise finally: db.close() return rv # Replace the route callback with the wrapped one. return wrapper Plugin = SQLitePlugin ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1601738733.1967854 bottle-sqlite-0.2.0/setup.cfg0000664000175000017500000000004600000000000016013 0ustar00marcmarc00000000000000[egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1601738377.0 bottle-sqlite-0.2.0/setup.py0000664000175000017500000000233200000000000015704 0ustar00marcmarc00000000000000#!/usr/bin/env python import sys import os from setuptools import setup # This ugly hack executes the first few lines of the module file to look up some # common variables. We cannot just import the module because it depends on other # modules that might not be installed yet. filename = os.path.join(os.path.dirname(__file__), 'bottle_sqlite.py') with open(filename) as fp: source = fp.read().split('### CUT HERE')[0] exec(source) setup( name = 'bottle-sqlite', version = __version__, url = 'https://github.com/bottlepy/bottle-sqlite', description = 'SQLite3 integration for Bottle.', long_description = __doc__, author = 'Marcel Hellkamp', author_email = 'marc@gsites.de', license = __license__, platforms = 'any', py_modules = [ 'bottle_sqlite' ], requires = [ 'bottle (>=0.12)' ], classifiers = [ 'Environment :: Web Environment', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 'Topic :: Software Development :: Libraries :: Python Modules' ] )