调用ASK SDK for Python的修饰请求处理程序

2024-09-30 22:14:37 发布

您现在位置:Python中文网/ 问答频道 /正文

Python ask sdk for writing alexa skills提供了两种编写意图处理程序的方法。一种是从AbstractRequestHandler派生并实现两个函数can_handle()handle()。另一个使用函数修饰符(@SkillBuilder.request_handler())。你知道吗

使用decorator的第二种方法,我不能直接调用处理函数(在单元测试中)。试图访问函数时,解释器显示错误TypeError: 'NoneType' object is not callable。你知道吗

下面是intent处理程序和测试代码的最小示例(其工作方式类似于this github issue处的建议)。你知道吗

意图处理程序

sb = SkillBuilder()
# Built-in Intent Handlers
@sb.request_handler(can_handle_func=is_request_type("LaunchRequest"))
def test_intent_handler(handler_input):
    return "Hello, test handler"

测试功能

def test_intent():
    request = new_request('TestIntent', {})
    # THE FOLLOWING LINE THROWS THE ERROR
    response = test_intent_handler(request)

    expected_response = "Hello, test handler"
    assert response == expected_response

根据this question的答案,decorator函数必须返回一个函数,但是request_handler()的情况似乎已经是这样了,正如您在github上看到的那样

decorator函数确实返回包装器函数,因此test_intent_handler应该是函数类型。我错过了什么?你知道吗


编辑

对于这个问题,Adam Smith的答案是一个很好的解决方法。你知道吗

发生这种情况的原因是函数SkillBuilder.request_handler返回一个不返回任何内容的包装函数。此包装器函数用作处理程序函数的装饰器。由于decorator的结果被分配给test_intent_handler,并且decorator(包装器)不返回任何内容,因此结果是NoneType。 因此,在用@sb.request_handler装饰处理程序之后,原始函数就不能再访问了。你知道吗

为了解决这个问题,包装函数只需要返回传入的处理函数。根据adamsmith的建议,我创建了一个pull request来改变这一点,这样“Alexa Skills Kit SDK for Python”就可以变得更易于测试。你知道吗


Tags: 方法函数test处理程序forresponserequestdecorator
1条回答
网友
1楼 · 发布于 2024-09-30 22:14:37

decorator的目的是在适当的位置修改函数。装饰器不会(没有一些自定义逻辑)将对其底层函数的引用公开给调用者。但这很好,因为您要测试的不是请求处理程序,而是回调本身。你知道吗

ask-SDK不太可能有编写处理程序单元测试的框架,但如果没有,只需为自己保存回调的引用。你知道吗

# handler code

sb = SkillBuilder()

def _test_intent_handler(handler_input):
    return "Hello, test handler"

# Built-in Intent Handlers
@sb.request_handler(can_handle_func=is_request_type("LaunchRequest"))

test_intent_handler = sb.request_handler(
    can_handle_func=is_request_type("LaunchRequest"))(_test_intent_handler)
# test suite

def test_intent():
    request = new_request('TestIntent', {})
    response = _test_intent_handler(request)

    expected_response = "Hello, test handler"
    assert response == expected_response

如果这让你感到困扰(我不会责怪你,这很难看),你可以编写自己的装饰器,保持我上面提到的自定义逻辑。你知道吗

import functools

def meta_decorator(dec, *args, **kwargs):
    @functools.wraps(dec)
    def wrapper(f):
        @functools.wraps(f)
        def wrapped(*args, **kwargs):
            return f(*args, **kwargs)
        wrapped._original_function = f
        return dec(*args, **kwargs)(wrapped)
    return wrapper

sb = SkillBuilder()

@meta_decorator(sb.request_handler, can_handle_func=is_request_type("LaunchRequest"))
def test_intent_handler(handler_input):
    return "Hello, test handler"
# Test suite 2

def test_intent():
    request = new_request('Test Intent', {})
    response = test_intent_handler._original_function(request)
    expected_response = "Hello, test handler"
    assert response == expected_response

相关问题 更多 >