bottlepy / bottle

bottle.py is a fast and simple micro-framework for python web-applications.
http://bottlepy.org/
MIT License
8.44k stars 1.46k forks source link

Multiple plugins can't inject parameters #295

Open hitezh opened 12 years ago

hitezh commented 12 years ago

Hi,

I am trying to write a plugin which injects some data into the the functions, but it failes if I already have another plugin (say sqlite).

A simple example is the code below:

from bottle import *
import bottle
from bottle.ext import sqlite

app = bottle.Bottle()
test_db = sqlite.Plugin(dbfile='test.db')
cache_db = sqlite.Plugin(dbfile=':memory:', keyword='cache')
app.install(test_db)
app.install(cache_db)

@app.route('/')
def show(db, cache):
    return "successfully loaded both plugins"

if __name__ == "__main__":
    run(app, reloader=True)

when run, it throws this error : TypeError: show() takes exactly 2 arguments (0 given)

hitezh commented 12 years ago

this looks similar to issue #207 and #231 There the view decorator is conflicting with the sqlite plugin, and in my case another plugin is conflicting.

Can I apply the same workaround here?

iurisilvio commented 12 years ago

No, that is not the case. I guess since v0.10, bottle doesn't allow two plugins with the same name.

It is an issue to me too.

thekad commented 12 years ago

Is not plugins with the same name, i have two completely different plugins (sqlalchemy and memcache) and I have the same issue, can't use both of them at the same time, don't matter if I use apply[db_plugin, mc_plugin]

thekad commented 12 years ago
from bottle import *
import bottle
from bottle.ext import sqlite
from bottle.ext import memcache

app = bottle.Bottle()
test_db = sqlite.Plugin(dbfile=':memory:', keyword='cache')
app.install(test_db)
test_mc = memcache.MemcachePlugin(servers=['localhost:11211'])
app.install(test_mc)

@app.route('/')
def show(db, mc):
    return "successfully loaded both plugins"

if __name__ == "__main__":
    run(app, reloader=True)

Will yield the following stack trace:

Traceback (most recent call last): File "/Users/kad/git/pasttle/env/lib/python2.7/site-packages/bottle.py", line 737, in _handle return route.call(_args) File "/Users/kad/git/pasttle/env/lib/python2.7/site-packages/bottle.py", line 1456, in wrapper rv = callback(_a, _ka) File "/Users/kad/git/pasttle/env/lib/python2.7/site-packages/bottle_memcache.py", line 39, in wrapper rv = callback(_args, **kwargs) TypeError: show() takes exactly 2 arguments (1 given)

Using the following versions:

bottle==0.10.9 bottle-memcache==0.1 bottle-sqlite==0.1.2

iurisilvio commented 12 years ago

https://github.com/iurisilvio/bottle-sqlalchemy/blob/master/bottle_sqlalchemy.py#L104

Looks like bottle-sqlalchemy has a bug. :/

It override the callback parameter with original callback (without plugins applied). Probably memcache plugin is applied first and sqlalchemy breaks that. I'll investigate this bug soon.

iurisilvio commented 12 years ago

Seriously, yesterday I read this thread thinking you are using bottle-sqlalchemy to test it. My last comment here makes no sense here. =/

thekad commented 12 years ago

Hah, yeah indeed makes no sense... this is an issue with any set of plugins, no clue what really is going on

iurisilvio commented 12 years ago

I checked your examples, they break here too.

When correcting this related issue in bottle-sqlalchemy, I added some tests to these cases and it works with all bottle versions: https://github.com/iurisilvio/bottle-sqlalchemy/blob/master/test.py#L147

Today I even tested use bottle-sqlalchemy with bottle-sqlite and bottle-sqlalchemy with bottle-memcache. Both works. I really didn't understand the difference between them to break.

iurisilvio commented 12 years ago

Wow, of course I know what is happening. Your first example use two plugins with the same name. I guess only bottle<0.10 allows it. Your second example use sqlite plugin with keyword='cache', but your route expect a 'db' parameter.

I don't like bottle rejecting two instances of the same plugin. :(

iurisilvio commented 12 years ago

If you really need two instances of sqlite (or any other plugin), you can do some workaround...

db1 = sqlite.Plugin(dbfile='test.db')
db2 = sqlite.Plugin(dbfile=':memory:', keyword='cache')
db2.name = 'other name'
app.install(db1)
app.install(db2)
benoitm974 commented 7 years ago

Trying to solve this for the sqlite plugin with 1st level recursion on wrapped function : bottlepy/bottle-sqlite#14