Skip to content

Commit 840142f

Browse files
committed
Update test_doc.py
1 parent b16eb4e commit 840142f

File tree

1 file changed

+71
-46
lines changed

1 file changed

+71
-46
lines changed

tests/test_doc.py

Lines changed: 71 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
"X-DashScope-SSE": "enable",
1616
}
1717

18-
# --- [NEW] MODEL MAPPING ---
19-
# 定义模型名称到 URL 路径的精确映射
18+
# --- MODEL MAPPING ---
19+
# Exact mapping from model name to URL path
2020
MODEL_PATH_MAP = {
2121
"deepseek-v3": "deepseek-ai/DeepSeek-V3",
2222
"deepseek-v3.1": "deepseek-ai/DeepSeek-V3.1",
@@ -28,7 +28,7 @@
2828
"pre-siliconflow/deepseek-r1": "deepseek-ai/DeepSeek-R1",
2929
}
3030

31-
# --- EXPECTED ERROR MESSAGES (COPIED FROM TABLE) ---
31+
# --- EXPECTED ERROR MESSAGES ---
3232
ERR_MSG_TOP_P_TYPE = "<400> InternalError.Algo.InvalidParameter: Input should be a valid number, unable to parse string as a number: parameters.top_p"
3333
ERR_MSG_TOP_P_RANGE = (
3434
"<400> InternalError.Algo.InvalidParameter: Range of top_p should be (0.0, 1.0]"
@@ -42,6 +42,7 @@
4242

4343
# --- HELPERS ---
4444

45+
4546
def make_request(payload: Dict[str, Any], stream: bool = True) -> requests.Response:
4647
"""
4748
Helper to send POST request using the Dynamic Path URL structure.
@@ -57,17 +58,17 @@ def make_request(payload: Dict[str, Any], stream: bool = True) -> requests.Respo
5758
model_path = MODEL_PATH_MAP[raw_model_name]
5859
url = f"{BASE_URL_PREFIX}/{model_path}"
5960

60-
# 处理 Headers
61+
# Handle Headers
6162
current_headers = HEADERS.copy()
6263
if not stream:
6364
current_headers["Accept"] = "application/json"
64-
# 移除 SSE 标记
65+
# Remove SSE flag
6566
if "X-DashScope-SSE" in current_headers:
6667
del current_headers["X-DashScope-SSE"]
6768

68-
# 注意:requests.post stream 参数控制是否立即下载响应体,
69-
# 但业务层面的流式由 headers 和 json body 决定,这里保持 requests 的 stream=True
70-
# 只是为了方便拿到原始响应,或者统一设为 stream 变量也可以。
69+
# Note: requests.post 'stream' parameter controls whether to immediately download
70+
# the response body. We keep it True here to access raw response/iter_lines conveniently,
71+
# regardless of the business logic stream setting.
7172
return requests.post(url, headers=current_headers, json=payload, stream=True)
7273

7374

@@ -131,7 +132,9 @@ def test_conflict_prefix_and_thinking(self):
131132
"parameters": {"enable_thinking": True},
132133
}
133134
response = make_request(payload)
134-
assert_exact_error(response, "InvalidParameter", ERR_MSG_PARTIAL_THINKING_CONFLICT)
135+
assert_exact_error(
136+
response, "InvalidParameter", ERR_MSG_PARTIAL_THINKING_CONFLICT
137+
)
135138

136139
def test_r1_enable_thinking_unsupported(self):
137140
payload = {
@@ -159,13 +162,24 @@ def test_r1_usage_structure_no_text_tokens(self):
159162
def test_tool_choice_invalid_error_mapping(self):
160163
payload = {
161164
"model": "pre-siliconflow/deepseek-r1",
162-
"input": {
163-
"messages": [{"role": "user", "content": "Weather?"}]
164-
},
165+
"input": {"messages": [{"role": "user", "content": "Weather?"}]},
165166
"parameters": {
166167
"result_format": "message",
167168
"tool_choice": {"type": "get_current_weather"},
168-
"tools": [{"type": "function", "function": {"name": "get_current_weather", "description": "Get weather", "parameters": {"type": "object", "properties": {"location": {"type": "string"}}, "required": ["location"]}}}],
169+
"tools": [
170+
{
171+
"type": "function",
172+
"function": {
173+
"name": "get_current_weather",
174+
"description": "Get weather",
175+
"parameters": {
176+
"type": "object",
177+
"properties": {"location": {"type": "string"}},
178+
"required": ["location"],
179+
},
180+
},
181+
}
182+
],
169183
},
170184
}
171185
response = make_request(payload)
@@ -178,7 +192,16 @@ def test_history_tool_call_fix(self):
178192
"messages": [
179193
{"role": "system", "content": "sys"},
180194
{"role": "user", "content": "user"},
181-
{"role": "assistant", "tool_calls": [{"function": {"arguments": "{}", "name": "fn"}, "id": "call_1", "type": "function"}]},
195+
{
196+
"role": "assistant",
197+
"tool_calls": [
198+
{
199+
"function": {"arguments": "{}", "name": "fn"},
200+
"id": "call_1",
201+
"type": "function",
202+
}
203+
],
204+
},
182205
{"role": "tool", "content": "res", "tool_call_id": "call_1"},
183206
]
184207
},
@@ -212,49 +235,47 @@ def test_stop_parameter_invalid_type(self):
212235

213236
def test_non_streaming_request(self):
214237
"""
215-
[Row 16] 验证非流式返回 (incremental_output=false)
216-
使用优化后的 make_request,代码更干净
238+
Verify non-streaming response (incremental_output=false).
217239
"""
218240
payload = {
219241
"model": "pre-siliconflow/deepseek-v3.2",
220242
"input": {"messages": [{"role": "user", "content": "Say hi"}]},
221-
"parameters": {"incremental_output": False}, # 显式设置参数
243+
"parameters": {"incremental_output": False}, # Explicitly set parameter
222244
}
223245

224-
# 调用优化后的 helper,传入 stream=False
225246
response = make_request(payload, stream=False)
226247

227-
assert response.status_code == 200, f"Non-streaming request failed: {response.text}"
248+
assert (
249+
response.status_code == 200
250+
), f"Non-streaming request failed: {response.text}"
228251
data = response.json()
229-
# 非流式应该直接返回 output 字段,而不是 SSE 的 delta
252+
# Non-streaming should return 'output' field directly, not SSE delta
230253
assert "output" in data, "Non-streaming response missing 'output' field"
231254

232255
def test_stop_behavior_in_reasoning(self):
233256
"""
234-
[Updated] 验证 Stop 参数在 Reasoning 模型中的行为:
235-
1. 确认 reasoning_content 能够正常返回 (不被误截断)。
236-
2. 确认 stop 参数作用于正文 (content),并正确截断。
257+
Verify Stop parameter behavior in Reasoning models:
258+
1. Ensure reasoning_content is returned (not truncated).
259+
2. Ensure stop parameter applies to content and truncates correctly.
237260
"""
238-
# 设置一个具体的 Stop 词,诱导模型在正文中输出它
239261
target_stop_word = "Banana"
240262
payload = {
241263
"model": "pre-siliconflow/deepseek-r1",
242264
"input": {
243-
"messages": [{
244-
"role": "user",
245-
"content": f"Please think about the color of the sun, and then simply output the phrase: 'The sun is like a {target_stop_word}'"
246-
}]
265+
"messages": [
266+
{
267+
"role": "user",
268+
"content": f"Please think about the color of the sun, and then simply output the phrase: 'The sun is like a {target_stop_word}'",
269+
}
270+
]
247271
},
248-
"parameters": {
249-
"stop": [target_stop_word],
250-
"incremental_output": True # 开启增量输出,避免内容重复
251-
}
272+
"parameters": {"stop": [target_stop_word], "incremental_output": True},
252273
}
253274

254275
response = make_request(payload)
255276
assert response.status_code == 200
256277

257-
# --- SSE 解析逻辑 ---
278+
# --- SSE Parsing Logic ---
258279
collected_reasoning = ""
259280
collected_content = ""
260281
final_finish_reason = None
@@ -263,8 +284,7 @@ def test_stop_behavior_in_reasoning(self):
263284
if not line:
264285
continue
265286

266-
# 解码 line
267-
line_text = line.decode('utf-8')
287+
line_text = line.decode("utf-8")
268288

269289
if line_text.startswith("data:"):
270290
json_str = line_text[5:].strip()
@@ -274,15 +294,14 @@ def test_stop_behavior_in_reasoning(self):
274294
try:
275295
chunk = json.loads(json_str)
276296

277-
# --- [修复 1] 适配 DashScope 结构:先取 output ---
297+
# Adapt to DashScope structure: get output first
278298
output = chunk.get("output", {})
279299
choices = output.get("choices", [])
280300

281301
if not choices:
282302
continue
283303

284-
# --- [修复 2] 适配 DashScope 结构:取 message 而非 delta ---
285-
# DashScope 在流式传输中也使用 message 字段
304+
# Adapt to DashScope structure: use 'message' instead of 'delta'
286305
message = choices[0].get("message", {})
287306

288307
if "reasoning_content" in message:
@@ -297,20 +316,26 @@ def test_stop_behavior_in_reasoning(self):
297316
except json.JSONDecodeError:
298317
continue
299318

300-
# --- 断言验证 ---
319+
# --- Assertions ---
301320
print(f"\n[DEBUG] Collected Reasoning Length: {len(collected_reasoning)}")
302321
print(f"[DEBUG] Collected Content: '{collected_content}'")
303322
print(f"[DEBUG] Finish Reason: {final_finish_reason}")
304323

305-
# 1. 验证 reasoning 内容回来了 (Think 过程不应为空)
306-
assert len(collected_reasoning) > 10, f"Expected significant reasoning content from R1 model. {collected_reasoning}"
324+
# 1. Verify reasoning content is present (Think process should not be empty)
325+
assert (
326+
len(collected_reasoning) > 10
327+
), f"Expected significant reasoning content from R1 model. {collected_reasoning}"
307328

308-
# 2. 验证 Stop 生效 (Content 应该包含 'The sun is like a ' 但不包含 'Banana')
329+
# 2. Verify Stop worked (Content should include prefix but stop before target word)
309330
assert "The sun" in collected_content
310-
assert target_stop_word not in collected_content, f"Content should stop before '{target_stop_word}'"
311-
312-
# 3. 验证 finish_reason 是 stop
313-
assert final_finish_reason == "stop", f"Expected finish_reason to be 'stop', but got '{final_finish_reason}'"
331+
assert (
332+
target_stop_word not in collected_content
333+
), f"Content should stop before '{target_stop_word}'"
334+
335+
# 3. Verify finish_reason is stop
336+
assert (
337+
final_finish_reason == "stop"
338+
), f"Expected finish_reason to be 'stop', but got '{final_finish_reason}'"
314339

315340
def test_thinking_budget_behavior(self):
316341
payload = {

0 commit comments

Comments
 (0)