I'm trying to understand the arguments that are passed to a pyramid view function.
The following example demonstrates a function wrapped with two different wrapppers. The only difference between the two wrappers is the signature. In the first wrapper, the first positional argument (obj) is explicit. In the second, it is included in *args.
import functools
from pyramid.config import Configurator
import webtest
def decorator_1(func):
@functools.wraps(func)
def wrapper(obj, *args, **kwargs): # <- obj
print('decorator_1')
print(type(obj), obj)
print(args)
print(kwargs)
return func(obj, *args, **kwargs) # <- obj
wrapper.__wrapped__ = func
return wrapper
def decorator_2(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('decorator_2')
print(args)
print(kwargs)
return func(*args, **kwargs)
wrapper.__wrapped__ = func
return wrapper
@decorator_1
def func_1(request):
return {'func': 'func_1'}
@decorator_2
def func_2(request):
return {'func': 'func_2'}
I would expect both wrapepd method to behave the same.
In decorator_1, I expect obj to be a request object and indeed it is.
In decorator_2, I would expect args[0] to be the same request object but it is not. It appears an additional first positional argument is passed before the request object.
def add_route(config, route, view, renderer="json"):
"""Helper for adding a new route-view pair."""
route_name = view.__name__
config.add_route(route_name, route)
config.add_view(view, route_name=route_name, renderer=renderer)
config = Configurator()
add_route(config, "/func_1", func_1)
add_route(config, "/func_2", func_2)
app = config.make_wsgi_app()
testapp = webtest.TestApp(app)
testapp.get("/func_1")
testapp.get("/func_2")
Output:
decorator_1
<class 'pyramid.request.Request'> GET /func_1 HTTP/1.0
Host: localhost:80
()
{}
decorator_2
(<pyramid.traversal.DefaultRootFactory object at 0x7f981da2ee48>, <Request at 0x7f981da2ea20 GET http://localhost/func_2>)
{}
Consequently, func_2 crashes because it receives a DefaultRootFactory object it does not expect.
I'd like to understand this discrepancy. How come the signature of the wrapper changes what pyramid passes to the wrapped function?
There is a mechanism at stake I don't understand, and I suspect it might be in Pyramid's logic.