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