test_manifest.py•12.4 kB
import unittest
import os
from typing import Any, Dict, List, Optional
import appbuilder
from appbuilder import Manifest
from appbuilder import manifest, manifest_parameter
@unittest.skipUnless(os.getenv("TEST_CASE", "UNKNOWN") == "CPU_SERIAL", "")
class TestManifest(unittest.TestCase):
def setUp(self):
"""
设置环境变量。
Args:
无参数,默认值为空。
Returns:
无返回值,方法中执行了环境变量的赋值操作。
"""
os.environ["APPBUILDER_TOKEN"] = (
"your api key"
)
self.app_id = "7cc4c21f-0e25-4a76-baf7-01a2b923a1a7"
def test_google_style(self):
# Generated by vscode plugin
# https://marketplace.visualstudio.com/items?itemName=njpwerner.autodocstring
def google_style(
name: str,
val: str = None,
val_obj: Optional[Any] = None,
val_list: List[str] = None,
data: Dict[str, int] = None,
) -> str:
"""Google style docstring.
Args:
name (str): Name of object.
val (str, optional): Value of obj. Defaults to None.
val_obj (Optional[Any], optional): Real object reference. Defaults to None.
val_list (List[str], optional): List of items with object. Defaults to None.
data (Dict[str, int], optional): Data along with object. Defaults to None.
Returns:
str: Styled string.
"""
return ""
manifest_from_function = appbuilder.Manifest.from_function(google_style)
# 断言顶层的结构
assert manifest_from_function.type == "function", "Type does not match 'function'"
assert (
manifest_from_function.function["name"] == "google_style"
), "Function name does not match 'google_style'"
assert (
manifest_from_function.function["description"]
== """Google style docstring.
Args:
name (str): Name of object.
val (str, optional): Value of obj. Defaults to None.
val_obj (Optional[Any], optional): Real object reference. Defaults to None.
val_list (List[str], optional): List of items with object. Defaults to None.
data (Dict[str, int], optional): Data along with object. Defaults to None.
Returns:
str: Styled string.
"""
), "Description does not match"
# 断言参数结构
parameters = manifest_from_function.function["parameters"]
assert parameters["type"] == "object", "Parameters type does not match 'object'"
assert "properties" in parameters, "Properties not found in parameters"
# 断言各个参数的类型和描述
properties = parameters["properties"]
# name 参数
assert "name" in properties, "'name' parameter missing"
# 添加类型检查时的调试信息
try:
assert (
properties["name"]["type"] == "str"
), f"'name' type does not match 'str'. Actual type: {properties['name']['type']}"
except AssertionError as e:
print(f"Debug Info: Actual 'name' type is {properties['name']['type']}")
raise e # 重新抛出异常
# val 参数
assert "val" in properties, "'val' parameter missing"
assert properties["val"]["type"] == "str", "'val' type does not match 'str'"
# val_obj 参数
assert "val_obj" in properties, "'val_obj' parameter missing"
assert (
properties["val_obj"]["type"] == "Optional[Any]"
), "'val_obj' type does not match 'object'"
# val_list 参数
assert "val_list" in properties, "'val_list' parameter missing"
assert (
properties["val_list"]["type"] == "List[str]"
), "'val_list' type does not match 'array'"
# data 参数
assert "data" in properties, "'data' parameter missing"
assert (
properties["data"]["type"] == "Dict[str, int]"
), "'data' type does not match 'object'"
# 断言必需参数
assert "required" in parameters, "'required' field missing in parameters"
assert parameters["required"] == ["name"], "'required' does not match ['name']"
def test_google_style_bad_args_return_dict(self):
def func(
bad_param: str,
bad_generic_param: List[str],
bad_format: int,
val: str = None,
) -> Dict[str, str]:
"""Google style docstring.
Args:
bad param (str): Bad parameter, name contains whitespace.
bad_generic_param (List<str>): Bad generic parameter, use <> instead of []
bad_format (int) Bad arg doc format, lost :.
val (str , optional): Value of obj. Defaults to None.
Returns:
Dict[str, str]: Returns a dict.
"""
return ""
manifest_from_function = appbuilder.Manifest.from_function(func)
# 断言顶层的结构
assert manifest_from_function.type == "function", "Type does not match 'function'"
assert (
manifest_from_function.function["name"] == "func"
), "Function name does not match 'func'"
assert (
manifest_from_function.function["description"]
== """Google style docstring.
Args:
bad param (str): Bad parameter, name contains whitespace.
bad_generic_param (List<str>): Bad generic parameter, use <> instead of []
bad_format (int) Bad arg doc format, lost :.
val (str , optional): Value of obj. Defaults to None.
Returns:
Dict[str, str]: Returns a dict.
"""
), "Description does not match"
# 断言参数结构
parameters = manifest_from_function.function["parameters"]
assert parameters["type"] == "object", "Parameters type does not match 'object'"
assert "properties" in parameters, "Properties not found in parameters"
# 断言各个参数的类型和描述
properties = parameters["properties"]
# bad_param 参数
assert "bad_param" in properties, "'bad_param' parameter missing"
assert (
properties["bad_param"]["type"] == "str"
), "'bad_param' type does not match 'str'"
# bad_format 参数
assert "bad_format" in properties, "'bad_format' parameter missing"
assert (
properties["bad_format"]["type"] == "int"
), "'bad_format' type does not match 'int'"
# val 参数
assert "val" in properties, "'val' parameter missing"
assert properties["val"]["type"] == "str", "'val' type does not match 'str'"
# 断言必需参数
assert "required" in parameters, "'required' field missing in parameters"
assert parameters["required"] == [
"bad_param",
"bad_generic_param",
"bad_format",
], "'required' does not match expected required parameters"
# 断言没有多余参数
assert len(properties) == 4, "Unexpected number of parameters in properties"
def test_google_style_no_return(self):
def func(
name: str,
):
"""Google style docstring.
Args:
name (str): Name of object.
"""
return ""
manifest_from_function = appbuilder.Manifest.from_function(func)
# 断言顶层的结构
assert manifest_from_function.type == "function", "Type does not match 'function'"
assert (
manifest_from_function.function["name"] == "func"
), "Function name does not match 'func'"
assert (
manifest_from_function.function["description"]
== """Google style docstring.
Args:
name (str): Name of object.
"""
), "Description does not match"
# 断言参数结构
parameters = manifest_from_function.function["parameters"]
assert parameters["type"] == "object", "Parameters type does not match 'object'"
assert "properties" in parameters, "Properties not found in parameters"
# 断言参数类型和描述
properties = parameters["properties"]
# name 参数
assert "name" in properties, "'name' parameter missing"
assert properties["name"]["type"] == "str", "'name' type does not match 'str'"
# 断言必需参数
assert "required" in parameters, "'required' field missing in parameters"
assert parameters["required"] == ["name"], "'required' does not match ['name']"
# 断言没有["parameters"][1]的参数了
assert not (
"parameters" in manifest_from_function.function
and len(manifest_from_function.function["parameters"]) == 1
)
def test_no_doc(self):
def func(
name: str,
/,
*args,
val: str = None,
val_obj: Optional[Any] = None,
data: Dict[str, int] = None,
**kwargs,
) -> str:
return ""
# 断言这里会抛出缺少文档字符串的 ValueError 异常
try:
manifest_from_function = appbuilder.Manifest.from_function(func)
except ValueError as e:
assert (
str(e) == "函数 func 缺少文档字符串"
), "未抛出预期的 ValueError 或信息不匹配"
def test_decorator_google_style_basic(self):
@manifest(description="Function with required parameter.")
def func(
name: str,
) -> str:
"""Function with required parameter.
Args:
name (str): Name of object.
Returns:
str: Styled string.
"""
return ""
# 获取装饰器生成的 Manifest
manifest_from_function = func.__ab_manifest__
# 断言顶层的结构
assert manifest_from_function.type == "function", "Type does not match 'function'"
assert (
manifest_from_function.function["name"] == "func"
), "Function name does not match 'func'"
assert (
manifest_from_function.function["description"]
== "Function with required parameter."
), "Description does not match"
# 断言参数结构
parameters = manifest_from_function.function["parameters"]
assert parameters["type"] == "object", "Parameters type does not match 'object'"
assert "properties" in parameters, "Properties not found in parameters"
# 断言各个参数的类型和描述
properties = parameters["properties"]
# name 参数
assert "name" in properties, "'name' parameter missing"
assert properties["name"]["type"] == "str", "'name' type does not match 'str'"
assert (
properties["name"]["description"] == None
), "'name' description does not match"
# 断言必需参数
assert "required" in parameters, "'required' field missing in parameters"
assert parameters["required"] == ["name"], "'required' does not match ['name']"
def test_manifest_decorator(self):
@appbuilder.manifest(
description="获取指定中国城市的当前天气信息。仅支持中国城市的天气查询。参数 `location` 为中国城市名称,其他国家城市不支持天气查询。"
)
@appbuilder.manifest_parameter(
name="location", description="城市名,例如:北京。"
)
@appbuilder.manifest_parameter(
name="unit", description="温度单位,支持 'celsius' 或 'fahrenheit'"
)
# 定义示例函数
def get_current_weather(location: str, unit) -> str:
return "北京今天25度"
manifest_from_function = appbuilder.Manifest.from_function(get_current_weather)
assert manifest_from_function.function.get("description") is not None
if __name__ == "__main__":
unittest.main()