Ver código fonte

refactor(workflow): introduce specific exceptions for code validation (#10218)

-LAN- 5 meses atrás
pai
commit
be96f6e62d

+ 26 - 20
api/core/workflow/nodes/code/code_node.py

@@ -12,6 +12,12 @@ from core.workflow.nodes.code.entities import CodeNodeData
 from core.workflow.nodes.enums import NodeType
 from models.workflow import WorkflowNodeExecutionStatus
 
+from .exc import (
+    CodeNodeError,
+    DepthLimitError,
+    OutputValidationError,
+)
+
 
 class CodeNode(BaseNode[CodeNodeData]):
     _node_data_cls = CodeNodeData
@@ -60,7 +66,7 @@ class CodeNode(BaseNode[CodeNodeData]):
 
             # Transform result
             result = self._transform_result(result, self.node_data.outputs)
-        except (CodeExecutionError, ValueError) as e:
+        except (CodeExecutionError, CodeNodeError) as e:
             return NodeRunResult(status=WorkflowNodeExecutionStatus.FAILED, inputs=variables, error=str(e))
 
         return NodeRunResult(status=WorkflowNodeExecutionStatus.SUCCEEDED, inputs=variables, outputs=result)
@@ -76,10 +82,10 @@ class CodeNode(BaseNode[CodeNodeData]):
             if value is None:
                 return None
             else:
-                raise ValueError(f"Output variable `{variable}` must be a string")
+                raise OutputValidationError(f"Output variable `{variable}` must be a string")
 
         if len(value) > dify_config.CODE_MAX_STRING_LENGTH:
-            raise ValueError(
+            raise OutputValidationError(
                 f"The length of output variable `{variable}` must be"
                 f" less than {dify_config.CODE_MAX_STRING_LENGTH} characters"
             )
@@ -97,10 +103,10 @@ class CodeNode(BaseNode[CodeNodeData]):
             if value is None:
                 return None
             else:
-                raise ValueError(f"Output variable `{variable}` must be a number")
+                raise OutputValidationError(f"Output variable `{variable}` must be a number")
 
         if value > dify_config.CODE_MAX_NUMBER or value < dify_config.CODE_MIN_NUMBER:
-            raise ValueError(
+            raise OutputValidationError(
                 f"Output variable `{variable}` is out of range,"
                 f" it must be between {dify_config.CODE_MIN_NUMBER} and {dify_config.CODE_MAX_NUMBER}."
             )
@@ -108,7 +114,7 @@ class CodeNode(BaseNode[CodeNodeData]):
         if isinstance(value, float):
             # raise error if precision is too high
             if len(str(value).split(".")[1]) > dify_config.CODE_MAX_PRECISION:
-                raise ValueError(
+                raise OutputValidationError(
                     f"Output variable `{variable}` has too high precision,"
                     f" it must be less than {dify_config.CODE_MAX_PRECISION} digits."
                 )
@@ -125,7 +131,7 @@ class CodeNode(BaseNode[CodeNodeData]):
         :return:
         """
         if depth > dify_config.CODE_MAX_DEPTH:
-            raise ValueError(f"Depth limit ${dify_config.CODE_MAX_DEPTH} reached, object too deep.")
+            raise DepthLimitError(f"Depth limit ${dify_config.CODE_MAX_DEPTH} reached, object too deep.")
 
         transformed_result = {}
         if output_schema is None:
@@ -177,14 +183,14 @@ class CodeNode(BaseNode[CodeNodeData]):
                                         depth=depth + 1,
                                     )
                         else:
-                            raise ValueError(
+                            raise OutputValidationError(
                                 f"Output {prefix}.{output_name} is not a valid array."
                                 f" make sure all elements are of the same type."
                             )
                 elif output_value is None:
                     pass
                 else:
-                    raise ValueError(f"Output {prefix}.{output_name} is not a valid type.")
+                    raise OutputValidationError(f"Output {prefix}.{output_name} is not a valid type.")
 
             return result
 
@@ -192,7 +198,7 @@ class CodeNode(BaseNode[CodeNodeData]):
         for output_name, output_config in output_schema.items():
             dot = "." if prefix else ""
             if output_name not in result:
-                raise ValueError(f"Output {prefix}{dot}{output_name} is missing.")
+                raise OutputValidationError(f"Output {prefix}{dot}{output_name} is missing.")
 
             if output_config.type == "object":
                 # check if output is object
@@ -200,7 +206,7 @@ class CodeNode(BaseNode[CodeNodeData]):
                     if isinstance(result.get(output_name), type(None)):
                         transformed_result[output_name] = None
                     else:
-                        raise ValueError(
+                        raise OutputValidationError(
                             f"Output {prefix}{dot}{output_name} is not an object,"
                             f" got {type(result.get(output_name))} instead."
                         )
@@ -228,13 +234,13 @@ class CodeNode(BaseNode[CodeNodeData]):
                     if isinstance(result[output_name], type(None)):
                         transformed_result[output_name] = None
                     else:
-                        raise ValueError(
+                        raise OutputValidationError(
                             f"Output {prefix}{dot}{output_name} is not an array,"
                             f" got {type(result.get(output_name))} instead."
                         )
                 else:
                     if len(result[output_name]) > dify_config.CODE_MAX_NUMBER_ARRAY_LENGTH:
-                        raise ValueError(
+                        raise OutputValidationError(
                             f"The length of output variable `{prefix}{dot}{output_name}` must be"
                             f" less than {dify_config.CODE_MAX_NUMBER_ARRAY_LENGTH} elements."
                         )
@@ -249,13 +255,13 @@ class CodeNode(BaseNode[CodeNodeData]):
                     if isinstance(result[output_name], type(None)):
                         transformed_result[output_name] = None
                     else:
-                        raise ValueError(
+                        raise OutputValidationError(
                             f"Output {prefix}{dot}{output_name} is not an array,"
                             f" got {type(result.get(output_name))} instead."
                         )
                 else:
                     if len(result[output_name]) > dify_config.CODE_MAX_STRING_ARRAY_LENGTH:
-                        raise ValueError(
+                        raise OutputValidationError(
                             f"The length of output variable `{prefix}{dot}{output_name}` must be"
                             f" less than {dify_config.CODE_MAX_STRING_ARRAY_LENGTH} elements."
                         )
@@ -270,13 +276,13 @@ class CodeNode(BaseNode[CodeNodeData]):
                     if isinstance(result[output_name], type(None)):
                         transformed_result[output_name] = None
                     else:
-                        raise ValueError(
+                        raise OutputValidationError(
                             f"Output {prefix}{dot}{output_name} is not an array,"
                             f" got {type(result.get(output_name))} instead."
                         )
                 else:
                     if len(result[output_name]) > dify_config.CODE_MAX_OBJECT_ARRAY_LENGTH:
-                        raise ValueError(
+                        raise OutputValidationError(
                             f"The length of output variable `{prefix}{dot}{output_name}` must be"
                             f" less than {dify_config.CODE_MAX_OBJECT_ARRAY_LENGTH} elements."
                         )
@@ -286,7 +292,7 @@ class CodeNode(BaseNode[CodeNodeData]):
                             if value is None:
                                 pass
                             else:
-                                raise ValueError(
+                                raise OutputValidationError(
                                     f"Output {prefix}{dot}{output_name}[{i}] is not an object,"
                                     f" got {type(value)} instead at index {i}."
                                 )
@@ -303,13 +309,13 @@ class CodeNode(BaseNode[CodeNodeData]):
                         for i, value in enumerate(result[output_name])
                     ]
             else:
-                raise ValueError(f"Output type {output_config.type} is not supported.")
+                raise OutputValidationError(f"Output type {output_config.type} is not supported.")
 
             parameters_validated[output_name] = True
 
         # check if all output parameters are validated
         if len(parameters_validated) != len(result):
-            raise ValueError("Not all output parameters are validated.")
+            raise CodeNodeError("Not all output parameters are validated.")
 
         return transformed_result
 

+ 16 - 0
api/core/workflow/nodes/code/exc.py

@@ -0,0 +1,16 @@
+class CodeNodeError(ValueError):
+    """Base class for code node errors."""
+
+    pass
+
+
+class OutputValidationError(CodeNodeError):
+    """Raised when there is an output validation error."""
+
+    pass
+
+
+class DepthLimitError(CodeNodeError):
+    """Raised when the depth limit is reached."""
+
+    pass