Skip to content

Fix: Replace inspect.getargspec with inspect.signature for Python 3.1… #31

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 59 additions & 34 deletions bottle_sqlite.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'''
"""
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
Expand All @@ -24,11 +24,13 @@ def show(item, db):
if row:
return template('showitem', page=row)
return HTTPError(404, "Page not found")
'''
"""

__author__ = "Marcel Hellkamp"
__version__ = '0.2.0'
__license__ = 'MIT'
__version__ = (
"0.2.0" # Note: This version might not reflect the actual latest official release.
)
__license__ = "MIT"

### CUT HERE (see setup.py)

Expand All @@ -37,30 +39,41 @@ def show(item, db):
import bottle

# PluginError is defined to bottle >= 0.10
if not hasattr(bottle, 'PluginError'):
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
"""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. '''
settings on a per-route basis."""

name = 'sqlite'
name = "sqlite"
api = 2

''' python3 moves unicode to str '''
""" 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):
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
Expand All @@ -72,47 +85,58 @@ def __init__(self, dbfile=':memory:', autocommit=True, dictrows=True,
self.extensions = extensions or ()

def setup(self, app):
''' Make sure that other installed plugins don't affect the same
keyword argument.'''
"""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).")
raise PluginError(
"Found another sqlite plugin with "
"conflicting settings (non-unique keyword)."
)
elif other.name == self.name:
self.name += '_%s' % self.keyword
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']
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)
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)
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:
# UPDATED: Use inspect.signature for Python 3.11+ compatibility
try:
# For Python 3.0-3.10
argspec = inspect.getargspec(_callback)
has_keyword_arg = keyword in argspec.args
except AttributeError:
# For Python 3.11+
signature = inspect.signature(_callback)
has_keyword_arg = keyword in signature.parameters

if not has_keyword_arg:
return callback

def wrapper(*args, **kwargs):
Expand Down Expand Up @@ -157,4 +181,5 @@ def wrapper(*args, **kwargs):
# Replace the route callback with the wrapped one.
return wrapper


Plugin = SQLitePlugin