Fix parameterized type bug & better error message (#273)
## PR Description ### 1. Bug Fix A bug was observed where tools that were using [parameterized generics](https://docs.python.org/3/library/stdtypes.html#types-genericalias) (e.g., `dict[str, Any]`) for their input parameters or output, then this would cause the Worker to fail on startup with the error `issubclass() arg 1 must be a class` for Python3.13+. This error would not occur for Python versions less than 3.13. In Python <3.13, parameterized generics would implicitly be treated as their underlying type (its origin), so it was possible to treat `dict[str, Any]` as a class and pass it to `issubclass`. This is not the case for Python 3.13, so we need to explicitly strip the GenericAlias (e.g., `dict[str, Any]`) down to its origin (e.g., `dict`), before checking if it is a subclass of `Enum`. ### 2. Better Error Message When a tool used an unsupported parameter/output type, then Arcade would display the following message: ``` Failed to start Arcade Worker: Type error encountered while adding tool get_website_map from arcade_web.tools.firecrawl. Reason: issubclass() arg 1 must be a class ``` But now it displays ``` Failed to start Arcade Worker: Error encountered while adding tool get_website_map from arcade_web.tools.firecrawl. Reason: Unsupported type: tuple[str, str] ```
This commit is contained in:
parent
fb69e9ef77
commit
4608cce862
1 changed files with 11 additions and 4 deletions
|
|
@ -253,6 +253,10 @@ class ToolCatalog(BaseModel):
|
|||
raise ToolDefinitionError(
|
||||
f"Type error encountered while adding tool {tool_name} from {module_name}. Reason: {e}"
|
||||
)
|
||||
except Exception as e:
|
||||
raise ToolDefinitionError(
|
||||
f"Error encountered while adding tool {tool_name} from {module_name}. Reason: {e}"
|
||||
)
|
||||
|
||||
def __getitem__(self, name: FullyQualifiedName) -> MaterializedTool:
|
||||
return self.get_tool(name)
|
||||
|
|
@ -623,15 +627,18 @@ def get_wire_type_info(_type: type) -> WireTypeInfo:
|
|||
|
||||
type_to_check = inner_type if is_list else _type
|
||||
|
||||
# Strip generic parameters if type_to_check is a parameterized generic
|
||||
actual_type = get_origin(type_to_check) or type_to_check
|
||||
|
||||
# Special case: Literal["string1", "string2"] can be enumerated on the wire
|
||||
if is_string_literal(type_to_check):
|
||||
is_enum = True
|
||||
enum_values = [str(e) for e in get_args(type_to_check)]
|
||||
|
||||
# Special case: Enum can be enumerated on the wire
|
||||
elif issubclass(type_to_check, Enum):
|
||||
elif issubclass(actual_type, Enum):
|
||||
is_enum = True
|
||||
enum_values = [e.value for e in type_to_check] # type: ignore[union-attr]
|
||||
enum_values = [e.value for e in actual_type] # type: ignore[union-attr]
|
||||
|
||||
return WireTypeInfo(wire_type, inner_wire_type, enum_values if is_enum else None)
|
||||
|
||||
|
|
@ -732,10 +739,10 @@ def get_wire_type(
|
|||
if wire_type:
|
||||
return wire_type
|
||||
|
||||
if issubclass(_type, Enum):
|
||||
if isinstance(_type, type) and issubclass(_type, Enum):
|
||||
return "string"
|
||||
|
||||
if issubclass(_type, BaseModel):
|
||||
if isinstance(_type, type) and issubclass(_type, BaseModel):
|
||||
return "json"
|
||||
|
||||
raise ToolDefinitionError(f"Unsupported parameter type: {_type}")
|
||||
|
|
|
|||
Loading…
Reference in a new issue