@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / e3e132d2dd
Fork 0

A high-throughput and memory-efficient inference and serving engine for LLMs

Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git

Synced Nov 2, 02:15 UTC

[Refactor] Suppress SyntaxWarning from ast.literal_eval in tool parsers (#44346)

Signed-off-by: sfeng33 <4florafeng@gmail.com>

Flora Feng committed Jun 3, 2026 at 10:42 UTC e3e132d2dd99af9d48f04c21e82c756211d730ae
7 files changed +20 -15
vllm/tool_parsers/glm4_moe_tool_parser.py
+2 -2
@@ -11,7 +11,6 @@ The fix streams string values incrementally as they arrive, providing a true
11 streaming experience for long content.
12 """
13
14 -import ast
14 import json
15 from collections.abc import Sequence
16 from typing import Any
@@ -42,6 +41,7 @@ from vllm.tool_parsers.utils import (
41 extract_types_from_schema,
42 find_tool_properties,
43 partial_tag_overlap,
44 + safe_literal_eval,
45 )
46
47 logger = init_logger(__name__)
@@ -110,7 +110,7 @@ class Glm4MoeModelToolParser(ToolParser):
110 pass
111
112 try:
113 - return ast.literal_eval(value)
113 + return safe_literal_eval(value)
114 except (ValueError, SyntaxError):
115 pass
116
vllm/tool_parsers/hy_v3_tool_parser.py
+3 -3
@@ -1,7 +1,6 @@
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 -import ast
4 import json
5 from collections.abc import Sequence
6 from typing import Any
@@ -27,6 +26,7 @@ from vllm.tool_parsers.abstract_tool_parser import (
26 Tool,
27 ToolParser,
28 )
29 +from vllm.tool_parsers.utils import safe_literal_eval
30
31 logger = init_logger(__name__)
32
@@ -183,13 +183,13 @@ class HYV3ToolParser(ToolParser):
183
184 @staticmethod
185 def _deserialize(value: str) -> Any:
186 - """Deserialize a string value using json.loads then ast.literal_eval."""
186 + """Deserialize a string value using json.loads then safe_literal_eval."""
187 try:
188 return json.loads(value)
189 except Exception:
190 pass
191 try:
192 - return ast.literal_eval(value)
192 + return safe_literal_eval(value)
193 except Exception:
194 pass
195 return value
vllm/tool_parsers/minicpm5xml_tool_parser.py
+2 -3
@@ -1,7 +1,6 @@
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 -import ast
4 import json
5 from collections.abc import Sequence
6 from typing import Any
@@ -28,7 +27,7 @@ from vllm.tool_parsers.abstract_tool_parser import (
27 Tool,
28 ToolParser,
29 )
31 -from vllm.tool_parsers.utils import partial_tag_overlap
30 +from vllm.tool_parsers.utils import partial_tag_overlap, safe_literal_eval
31 from vllm.utils import random_uuid
32
33 logger = init_logger(__name__)
@@ -116,7 +115,7 @@ def _parse_arguments(json_value: str) -> tuple[Any, bool]:
115 try:
116 parsed_value = json.loads(json_value)
117 except json.JSONDecodeError:
119 - parsed_value = ast.literal_eval(json_value)
118 + parsed_value = safe_literal_eval(json_value)
119 return parsed_value, True
120 except Exception:
121 return json_value, False
vllm/tool_parsers/poolside_v1_tool_parser.py
+2 -2
@@ -11,7 +11,6 @@ The fix streams string values incrementally as they arrive, providing a true
11 streaming experience for long content.
12 """
13
14 -import ast
14 import json
15 from collections.abc import Sequence
16 from typing import Any
@@ -41,6 +40,7 @@ from vllm.tool_parsers.abstract_tool_parser import (
40 Tool,
41 ToolParser,
42 )
43 +from vllm.tool_parsers.utils import safe_literal_eval
44
45 logger = init_logger(__name__)
46
@@ -106,7 +106,7 @@ class PoolsideV1ToolParser(ToolParser):
106 pass
107
108 try:
109 - return ast.literal_eval(value)
109 + return safe_literal_eval(value)
110 except (ValueError, SyntaxError):
111 pass
112
vllm/tool_parsers/qwen3xml_tool_parser.py
+2 -3
@@ -1,6 +1,5 @@
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 -import ast
3 import json
4 from collections.abc import Sequence
5 from typing import Any
@@ -26,7 +25,7 @@ from vllm.tool_parsers.abstract_tool_parser import (
25 Tool,
26 ToolParser,
27 )
29 -from vllm.tool_parsers.utils import find_tool_properties
28 +from vllm.tool_parsers.utils import find_tool_properties, safe_literal_eval
29
30 logger = init_logger(__name__)
31
@@ -824,7 +823,7 @@ class StreamingXMLToolCallParser:
823 try:
824 parsed_value = json.loads(raw_for_parse)
825 except json.JSONDecodeError:
827 - parsed_value = ast.literal_eval(raw_for_parse)
826 + parsed_value = safe_literal_eval(raw_for_parse)
827 output_arguments = json.dumps(parsed_value, ensure_ascii=False)
828 except Exception:
829 # Fallback: output as string as-is
vllm/tool_parsers/step3p5_tool_parser.py
+2 -2
@@ -1,6 +1,5 @@
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 -import ast
3 import json
4 from collections.abc import Sequence
5 from typing import Any
@@ -23,6 +22,7 @@ from vllm.entrypoints.openai.engine.protocol import (
22 from vllm.logger import init_logger
23 from vllm.tokenizers import TokenizerLike
24 from vllm.tool_parsers.abstract_tool_parser import Tool, ToolParser
25 +from vllm.tool_parsers.utils import safe_literal_eval
26
27 logger = init_logger(__name__)
28
@@ -1016,7 +1016,7 @@ class StreamingXMLToolCallParser:
1016 raw_for_parse = raw_text + "\n"
1017 else:
1018 raw_for_parse = raw_text
1019 - parsed_value = ast.literal_eval(raw_for_parse)
1019 + parsed_value = safe_literal_eval(raw_for_parse)
1020 output_arguments = json.dumps(parsed_value, ensure_ascii=False)
1021 except Exception:
1022 # Fallback: output as string as-is
vllm/tool_parsers/utils.py
+7
@@ -3,6 +3,7 @@
3
4 import ast
5 import json
6 +import warnings
7 from json import JSONDecodeError, JSONDecoder
8 from typing import Any, TypeAlias
9
@@ -31,6 +32,12 @@ Tool: TypeAlias = ChatCompletionToolsParam | ResponsesTool
32 logger = init_logger(__name__)
33
34
35 +def safe_literal_eval(text: str):
36 + with warnings.catch_warnings():
37 + warnings.simplefilter("ignore", SyntaxWarning)
38 + return ast.literal_eval(text)
39 +
40 +
41 def partial_tag_overlap(text: str, tag: str) -> int:
42 """Length of the longest prefix of *tag* that matches a suffix of *text*.
43