Skip to content

Commit

Permalink
Merge pull request #740 from Bystroushaak/master
Browse files Browse the repository at this point in the history
.get_undecorated_callback() bugfix
  • Loading branch information
defnull committed Mar 24, 2015
2 parents 32a89fa + 5721333 commit dc0bbf4
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 1 deletion.
13 changes: 12 additions & 1 deletion bottle.py
Expand Up @@ -42,6 +42,7 @@
import base64, cgi, email.utils, functools, hmac, imp, itertools, mimetypes,\
os, re, sys, tempfile, threading, time, warnings

from types import FunctionType
from datetime import date as datedate, datetime, timedelta
from tempfile import TemporaryFile
from traceback import format_exc, print_exc
Expand Down Expand Up @@ -543,7 +544,17 @@ def get_undecorated_callback(self):
func = getattr(func, '__func__' if py3k else 'im_func', func)
closure_attr = '__closure__' if py3k else 'func_closure'
while hasattr(func, closure_attr) and getattr(func, closure_attr):
func = getattr(func, closure_attr)[0].cell_contents
attributes = getattr(func, closure_attr)
func = attributes[0].cell_contents

# in case of decorators with multiple arguments
if not isinstance(func, FunctionType) and func is not None:
# pick first FunctionType instance from multiple arguments
func = filter(
lambda x: isinstance(x, FunctionType),
map(lambda x: x.cell_contents, attributes)
)
func = list(func)[0] # py3 support
return func

def get_callback_args(self):
Expand Down
20 changes: 20 additions & 0 deletions test/test_route.py
Expand Up @@ -28,3 +28,23 @@ def w():
self.assertEqual(route.get_undecorated_callback(), x)
self.assertEqual(set(route.get_callback_args()), set(['a', 'b']))

def test_callback_inspection_multiple_args(self):
# decorator with argument, modifying kwargs
def d2(f="1"):
def d(fn):
def w(*args, **kwargs):
# modification of kwargs WITH the decorator argument
# is necessary requirement for the error
kwargs["a"] = f
return fn(*args, **kwargs)
return w
return d

@d2(f='foo')
def x(a, b):
return

route = bottle.Route(None, None, None, x)

# triggers the "TypeError: 'foo' is not a Python function"
self.assertEqual(set(route.get_callback_args()), set(['a', 'b']))

0 comments on commit dc0bbf4

Please sign in to comment.