Несовместимые аргументы, передаваемые в функцию представления пирамиды в зависимости от сигнатуры оболочки - PullRequest
2 голосов
/ 26 февраля 2020

Я пытаюсь понять аргументы, которые передаются в функцию представления пирамиды.

В следующем примере демонстрируется функция, обернутая двумя разными обертками. Единственная разница между двумя обертками - это подпись. В первой оболочке первый позиционный аргумент (obj) является явным. Во втором случае он включен в *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'}

. Я ожидаю, что оба метода wrapepd будут вести себя одинаково.

В decorator_1 я ожидаю, что obj будет объект запроса, и это действительно так.

В decorator_2 я бы ожидал, что args[0] будет тем же объектом запроса, но это не так. Похоже, перед первым объектом запроса передается дополнительный первый позиционный аргумент.

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")

Вывод:

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>)
{}

Следовательно, func_2 аварийно завершает работу, поскольку он получает объект DefaultRootFactory, который он выполняет. не ожидаю.

Я бы хотел понять это несоответствие. Почему подпись оболочки изменяет то, что пирамида передает обернутой функции?

На карту поставлен механизм, которого я не понимаю, и я подозреваю, что он может быть в логике пирамиды c.

1 Ответ

2 голосов
/ 27 февраля 2020

Я поделился своими выводами в проблеме webargs, где это возникло , но на всякий случай, если кто-нибудь сталкивался с этим здесь:

Пирамида позволяет вам написать функцию представления с любой из этих подписей

def view(request):
    ...
def view(context, request):
    ...

Второе соглашение о вызовах является исходным, а первое - более новым. Таким образом, хотя это и называется «альтернативой» в документах по пирамиде , это значение по умолчанию.

Они используют inspect.getfullargspec, чтобы увидеть, принимает ли представление один позиционный параметр, и если Итак, заверните его в соответствии со вторым соглашением. Если представление не соответствует первому соглашению, предполагается, что оно соответствует второму соглашению (что в данном случае неверно).

...