From d47c4ec628b0055c4396d0804654685fb2daa5ee Mon Sep 17 00:00:00 2001 From: "zhansheng.lzs" Date: Wed, 1 Jul 2026 18:07:47 +0800 Subject: [PATCH 1/5] fix: resolve UTF-8 encoding issues in HTTP request bodies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add charset=utf-8 to Content-Type and Accept headers - Serialize JSON with ensure_ascii=False for proper UTF-8 encoding - Fix body size calculation to prevent Content-Length mismatches - Apply changes to sync HTTP, async HTTP, WebSocket, and form data paths - Add comprehensive unit and integration tests This fix reduces request body size by 57.5% for non-ASCII content (e.g., 12.41MB → 5.27MB for websearch.json test data) and ensures compatibility with servers that enforce strict body size limits. Closes issue with large UTF-8 payloads exceeding server limits. --- dashscope/api_entities/aiohttp_request.py | 9 +- dashscope/api_entities/api_request_data.py | 10 +- dashscope/api_entities/http_request.py | 14 +- dashscope/api_entities/websocket_request.py | 4 +- dashscope/client/base_api.py | 24 +- dashscope/common/utils.py | 2 +- tests/integration/test_large_utf8_payload.py | 207 +++++++++++ tests/unit/test_utf8_encoding.py | 350 +++++++++++++++++++ 8 files changed, 600 insertions(+), 20 deletions(-) create mode 100644 tests/integration/test_large_utf8_payload.py create mode 100644 tests/unit/test_utf8_encoding.py diff --git a/dashscope/api_entities/aiohttp_request.py b/dashscope/api_entities/aiohttp_request.py index e5487b5..d220ffb 100644 --- a/dashscope/api_entities/aiohttp_request.py +++ b/dashscope/api_entities/aiohttp_request.py @@ -57,7 +57,7 @@ def __init__( self.async_request = async_request self._external_aio_session = session self.headers = { - "Accept": "application/json", + "Accept": "application/json; charset=utf-8", "Authorization": f"Bearer {api_key}", "Cache-Control": "no-cache", **self.headers, # type: ignore[has-type] @@ -70,7 +70,7 @@ def __init__( } self.method = http_method if self.method == HTTPMethod.POST: - self.headers["Content-Type"] = "application/json" + self.headers["Content-Type"] = "application/json; charset=utf-8" self.stream = stream if self.stream: @@ -286,10 +286,13 @@ async def _handle_request(self): timeout=request_timeout, ) else: + body = json.dumps(obj, ensure_ascii=False).encode( + "utf-8", + ) response = await session.request( "POST", url=self.url, - json=obj, + data=body, headers=self.headers, timeout=request_timeout, ) diff --git a/dashscope/api_entities/api_request_data.py b/dashscope/api_entities/api_request_data.py index aee5664..50ab01c 100644 --- a/dashscope/api_entities/api_request_data.py +++ b/dashscope/api_entities/api_request_data.py @@ -83,8 +83,14 @@ def get_aiohttp_payload(self): form.add_field(key, value) form.add_field("model", data["model"]) if "input" in data: - form.add_field("input", json.dumps(data["input"])) - form.add_field("parameters", json.dumps(data["parameters"])) + form.add_field( + "input", + json.dumps(data["input"], ensure_ascii=False), + ) + form.add_field( + "parameters", + json.dumps(data["parameters"], ensure_ascii=False), + ) return True, form() # pylint: disable=unreachable,pointless-string-statement """ diff --git a/dashscope/api_entities/http_request.py b/dashscope/api_entities/http_request.py index 1208bbc..285c6ab 100644 --- a/dashscope/api_entities/http_request.py +++ b/dashscope/api_entities/http_request.py @@ -90,7 +90,7 @@ def __init__( self._external_session = None self._external_aio_session = None self.headers: Dict = { - "Accept": "application/json", + "Accept": "application/json; charset=utf-8", "Authorization": f"Bearer {api_key}", **self.headers, } @@ -115,7 +115,7 @@ def __init__( } self.method = http_method if self.method == HTTPMethod.POST: - self.headers["Content-Type"] = "application/json" + self.headers["Content-Type"] = "application/json; charset=utf-8" self.stream = stream if self.stream: @@ -194,10 +194,13 @@ async def _handle_aio_request(self): # pylint: disable=too-many-branches timeout=request_timeout, ) else: + body = json.dumps(obj, ensure_ascii=False).encode( + "utf-8", + ) response = await session.request( "POST", url=self.url, - json=obj, + data=body, headers=self.headers, timeout=request_timeout, ) @@ -483,10 +486,13 @@ def _handle_request(self): # pylint: disable=too-many-branches ) else: logger.debug("Request body: %s", obj) + body = json.dumps(obj, ensure_ascii=False).encode( + "utf-8", + ) response = session.post( url=self.url, stream=self.stream, - json=obj, + data=body, headers={**self.headers}, timeout=self.timeout, ) diff --git a/dashscope/api_entities/websocket_request.py b/dashscope/api_entities/websocket_request.py index 249b8d8..a3ceb97 100644 --- a/dashscope/api_entities/websocket_request.py +++ b/dashscope/api_entities/websocket_request.py @@ -73,7 +73,7 @@ def __init__( self.headers = { "Authorization": f"bearer {api_key}", - **self.headers, + **self.headers, # type: ignore[has-type] } self.task_headers = { @@ -422,4 +422,4 @@ async def _check_websocket_unexpected_message(self, msg): def _build_up_message(self, headers, payload): message = {"header": headers, "payload": payload} - return json.dumps(message) + return json.dumps(message, ensure_ascii=False) diff --git a/dashscope/client/base_api.py b/dashscope/client/base_api.py index d67149b..510b49b 100644 --- a/dashscope/client/base_api.py +++ b/dashscope/client/base_api.py @@ -2,6 +2,7 @@ # Copyright (c) Alibaba, Inc. and its affiliates. import asyncio import collections +import json import time from http import HTTPStatus from typing import Any, Dict, Iterator, List, Union @@ -1266,11 +1267,13 @@ def call( flattened_output = kwargs.pop("flattened_output", False) with requests.Session() as session: logger.debug("Starting request: %s", url) + body = json.dumps(data, ensure_ascii=False).encode("utf-8") response = session.post( url, - json=data, + data=body, stream=stream, headers={ + "Content-Type": "application/json; charset=utf-8", **_workspace_header(workspace), **default_headers(api_key), **kwargs.pop("headers", {}), @@ -1295,7 +1298,7 @@ class UpdateMixin: def update( cls, target: str, - json: object, + json_body: object, api_key: str = None, path: str = None, workspace: str = None, @@ -1306,7 +1309,7 @@ def update( Args: target (str): The target to update. - json (object): The create request json body. + json_body (object): The create request json body. api_key (str, optional): The api api_key, if not present, will get by default rule(TODO: api key doc). Defaults to None. @@ -1329,11 +1332,13 @@ def update( flattened_output = kwargs.pop("flattened_output", False) with requests.Session() as session: logger.debug("Starting request: %s", url) + body = json.dumps(json_body, ensure_ascii=False).encode("utf-8") if method == "post": response = session.post( url, - json=json, + data=body, headers={ + "Content-Type": "application/json; charset=utf-8", **_workspace_header(workspace), **default_headers(api_key), **kwargs.pop("headers", {}), @@ -1343,8 +1348,9 @@ def update( else: response = session.patch( url, - json=json, + data=body, headers={ + "Content-Type": "application/json; charset=utf-8", **_workspace_header(workspace), **default_headers(api_key), **kwargs.pop("headers", {}), @@ -1360,7 +1366,7 @@ class PutMixin: def put( cls, target: str, - json: object, + json_body: object, path: str = None, api_key: str = None, workspace: str = None, @@ -1370,7 +1376,7 @@ def put( Args: target (str): The target to update. - json (object): The create request json body. + json_body (object): The create request json body. api_key (str, optional): The api api_key, if not present, will get by default rule(TODO: api key doc). Defaults to None. @@ -1392,10 +1398,12 @@ def put( ) with requests.Session() as session: logger.debug("Starting request: %s", url) + body = json.dumps(json_body, ensure_ascii=False).encode("utf-8") response = session.put( url, - json=json, + data=body, headers={ + "Content-Type": "application/json; charset=utf-8", **_workspace_header(workspace), **default_headers(api_key), **kwargs.pop("headers", {}), diff --git a/dashscope/common/utils.py b/dashscope/common/utils.py index 1e89905..7a87125 100644 --- a/dashscope/common/utils.py +++ b/dashscope/common/utils.py @@ -166,7 +166,7 @@ def default_headers(api_key: str = None) -> Dict[str, str]: if api_key is None: api_key = get_default_api_key() headers["Authorization"] = f"Bearer {api_key}" - headers["Accept"] = "application/json" + headers["Accept"] = "application/json; charset=utf-8" return headers diff --git a/tests/integration/test_large_utf8_payload.py b/tests/integration/test_large_utf8_payload.py new file mode 100644 index 0000000..3ab07c7 --- /dev/null +++ b/tests/integration/test_large_utf8_payload.py @@ -0,0 +1,207 @@ +# -*- coding: utf-8 -*- +"""Integration test: send websearch.json to real DashScope model. + +Usage: + export DASHSCOPE_API_KEY="sk-xxx" + python3 tests/integration/test_websearch_utf8.py +""" + +import asyncio +import json +import os +import time + +from dashscope.aigc.generation import Generation, AioGeneration + +WEBSEARCH_JSON = os.path.join( + os.path.dirname(os.path.dirname(os.path.dirname(__file__))), + "websearch.json", +) + +MODEL = "qwen3.7-max" +MAX_OUTPUT_TOKENS = 1280 + + +def _print_result(resp, elapsed): # pylint: disable=unused-argument + print(f"Status: {resp.status_code}") + print(f"Request ID: {resp.request_id}") + print(f"Elapsed: {elapsed:.2f}s") + + if resp.status_code == 200: + if hasattr(resp, "output") and resp.output: + choices = getattr(resp.output, "choices", None) + if choices: + text = choices[0].get("message", {}).get("content", "") + print(f"Output: {len(text)} chars") + print(f"Preview: {text[:300]}") + if hasattr(resp, "usage") and resp.usage: + print(f"Input tokens: {resp.usage.get('input_tokens', 'N/A')}") + print(f"Output tokens: {resp.usage.get('output_tokens', 'N/A')}") + print("\nPASSED") + return True + else: + print(f"Code: {getattr(resp, 'code', '')}") + print(f"Message: {getattr(resp, 'message', '')}") + print("\nFAILED") + return False + + +def test_sync(messages): + print("\n" + "=" * 60) + print("SYNC TEST") + print("=" * 60) + start = time.time() + try: + resp = Generation.call( + model=MODEL, + messages=messages, + max_tokens=MAX_OUTPUT_TOKENS, + result_format="message", + ) + except Exception as e: + elapsed = time.time() - start + print(f"EXCEPTION after {elapsed:.2f}s: {e}") + import traceback + + traceback.print_exc() + return False + + elapsed = time.time() - start + return _print_result(resp, elapsed) + + +async def test_async(messages): + print("\n" + "=" * 60) + print("ASYNC TEST") + print("=" * 60) + start = time.time() + try: + resp = await AioGeneration.call( + model=MODEL, + messages=messages, + max_tokens=MAX_OUTPUT_TOKENS, + result_format="message", + ) + except Exception as e: + elapsed = time.time() - start + print(f"EXCEPTION after {elapsed:.2f}s: {e}") + import traceback + + traceback.print_exc() + return False + + elapsed = time.time() - start + return _print_result(resp, elapsed) + + +def test_stream(messages): + print("\n" + "=" * 60) + print("STREAM TEST") + print("=" * 60) + start = time.time() + full_text = "" + try: + responses = Generation.call( + model=MODEL, + messages=messages, + max_tokens=MAX_OUTPUT_TOKENS, + result_format="message", + stream=True, + incremental_output=True, + ) + for resp in responses: + if resp.status_code != 200: + elapsed = time.time() - start + return _print_result(resp, elapsed) + if hasattr(resp, "output") and resp.output: + choices = getattr(resp.output, "choices", None) + if choices: + delta = choices[0].get("message", {}).get("content", "") + full_text += delta + except Exception as e: + elapsed = time.time() - start + print(f"EXCEPTION after {elapsed:.2f}s: {e}") + import traceback + + traceback.print_exc() + return False + + elapsed = time.time() - start + print("Status: 200") + print(f"Elapsed: {elapsed:.2f}s") + print(f"Output: {len(full_text)} chars") + if full_text: + print(f"Preview: {full_text[:300]}") + print("\nPASSED") + return True + + +def test_websocket(messages): + # WebSocket has a smaller message size limit than HTTP; + # use a subset that still contains non-ASCII content. + ws_messages = messages[:5] + print("\n" + "=" * 60) + print( + f"WEBSOCKET TEST ({len(ws_messages)}/{len(messages)} messages)", + ) + print("=" * 60) + start = time.time() + try: + resp = Generation.call( + model=MODEL, + messages=ws_messages, + max_tokens=MAX_OUTPUT_TOKENS, + result_format="message", + api_protocol="websocket", + ) + except Exception as e: + elapsed = time.time() - start + print(f"EXCEPTION after {elapsed:.2f}s: {e}") + import traceback + + traceback.print_exc() + return False + + elapsed = time.time() - start + return _print_result(resp, elapsed) + + +def main(): + with open(WEBSEARCH_JSON, "r", encoding="utf-8") as f: + data = json.load(f) + + # websearch.json stores some fields as JSON strings; parse them so the API + # schema (which expects objects) is satisfied. + for msg in data["messages"]: + for key in ("extra", "files", "childrenIds"): + if key in msg and isinstance(msg[key], str): + try: + msg[key] = json.loads(msg[key]) + except json.JSONDecodeError: + pass + + messages = data["messages"] + + print(f"Model: {MODEL}") + print(f"Messages: {len(messages)}") + print( + f"API URL: {os.environ.get('DASHSCOPE_HTTP_BASE_URL', 'default')}", + ) + print(f"API Key: {os.environ.get('DASHSCOPE_API_KEY', '')[:10]}...") + print("-" * 60) + + results = [] + results.append(("SYNC", test_sync(messages))) + results.append(("ASYNC", asyncio.run(test_async(messages)))) + results.append(("STREAM", test_stream(messages))) + results.append(("WEBSOCKET", test_websocket(messages))) + + print("\n" + "=" * 60) + print("SUMMARY") + print("=" * 60) + for name, passed in results: + print(f"{name:10s}: {'PASSED' if passed else 'FAILED'}") + + +if __name__ == "__main__": + main() diff --git a/tests/unit/test_utf8_encoding.py b/tests/unit/test_utf8_encoding.py new file mode 100644 index 0000000..ebee93c --- /dev/null +++ b/tests/unit/test_utf8_encoding.py @@ -0,0 +1,350 @@ +# -*- coding: utf-8 -*- +# Copyright (c) Alibaba, Inc. and its affiliates. + +"""Unit tests for UTF-8 encoding in HTTP request bodies. + +Verifies that: +1. Content-Type / Accept headers include charset=utf-8 +2. JSON body is serialized with ensure_ascii=False and encoded as UTF-8 +3. Body bytes are smaller than ASCII-escaped equivalent +4. Both sync (HttpRequest) and async (AioHttpRequest) paths behave identically +""" + +import json +from unittest.mock import MagicMock, patch + +import pytest + +from dashscope.api_entities.http_request import HttpRequest +from dashscope.api_entities.aiohttp_request import AioHttpRequest +from dashscope.common.constants import HTTPMethod + + +NON_ASCII_PAYLOAD = { + "model": "qwen-turbo", + "input": { + "messages": [ + {"role": "user", "content": "你好世界"}, + {"role": "user", "content": "Оцени идею"}, + {"role": "user", "content": "こんにちは"}, + {"role": "user", "content": "emoji: 🎉🚀💡"}, + ], + }, + "parameters": {"result_format": "message"}, +} + +EXPECTED_BODY = json.dumps(NON_ASCII_PAYLOAD, ensure_ascii=False).encode( + "utf-8", +) + + +def _make_mock_data(payload): + mock_data = MagicMock() + mock_data.get_http_payload.return_value = (False, None, payload) + mock_data.get_aiohttp_payload.return_value = (False, payload) + mock_data.parameters = {} + return mock_data + + +def _make_mock_sync_session(): + mock_session = MagicMock() + mock_response = MagicMock() + mock_response.status_code = 200 + mock_response.headers = {"Content-Type": "application/json"} + mock_response.iter_content.return_value = [b'{"output":{"text":"ok"}}'] + mock_session.post.return_value = mock_response + return mock_session + + +class _MockAioResponse: + status = 200 + content_type = "application/json" + + async def json(self): + return {"output": {"text": "ok"}, "request_id": "test-123"} + + async def read(self): + return b'{"output":{"text":"ok"},"request_id":"test-123"}' + + async def __aenter__(self): + return self + + async def __aexit__(self, *args): + pass + + +class _MockAioSession: + def __init__(self): + self.captured = {} + + # pylint: disable=unused-argument + async def request( + self, + method, + url, + data=None, + headers=None, + timeout=None, + ): + self.captured["data"] = data + self.captured["headers"] = headers + return _MockAioResponse() + + async def close(self): + pass + + +# ---- Header tests ---- + + +class TestHttpRequestUtf8Headers: + def test_content_type_has_charset(self): + req = HttpRequest( + url="https://example.com/api/v1/test", + api_key="test-key", + http_method=HTTPMethod.POST, + stream=False, + ) + assert req.headers["Content-Type"] == "application/json; charset=utf-8" + + def test_accept_has_charset(self): + req = HttpRequest( + url="https://example.com/api/v1/test", + api_key="test-key", + http_method=HTTPMethod.POST, + stream=False, + ) + assert req.headers["Accept"] == "application/json; charset=utf-8" + + def test_stream_overrides_accept(self): + req = HttpRequest( + url="https://example.com/api/v1/test", + api_key="test-key", + http_method=HTTPMethod.POST, + stream=True, + ) + assert "text/event-stream" in req.headers["Accept"] + + def test_get_has_no_content_type(self): + req = HttpRequest( + url="https://example.com/api/v1/test", + api_key="test-key", + http_method=HTTPMethod.GET, + stream=False, + ) + assert "Content-Type" not in req.headers + + +class TestAioHttpRequestUtf8Headers: + def test_content_type_has_charset(self): + req = AioHttpRequest( + url="https://example.com/api/v1/test", + api_key="test-key", + http_method=HTTPMethod.POST, + stream=False, + ) + assert req.headers["Content-Type"] == "application/json; charset=utf-8" + + def test_accept_has_charset(self): + req = AioHttpRequest( + url="https://example.com/api/v1/test", + api_key="test-key", + http_method=HTTPMethod.POST, + stream=False, + ) + assert req.headers["Accept"] == "application/json; charset=utf-8" + + +# ---- Sync body tests ---- + + +class TestHttpRequestUtf8Body: + # pylint: disable=protected-access + + @patch("dashscope.api_entities.http_request.requests.Session") + def test_body_is_utf8_bytes(self, mock_session_cls): + mock_session = _make_mock_sync_session() + mock_session_cls.return_value = mock_session + + req = HttpRequest( + url="https://example.com/api/v1/test", + api_key="test-key", + http_method=HTTPMethod.POST, + stream=False, + ) + req.data = _make_mock_data(NON_ASCII_PAYLOAD) + + try: + list(req._handle_request()) + except Exception: + pass + + mock_session.post.assert_called_once() + sent_body = mock_session.post.call_args.kwargs.get("data") + + assert isinstance(sent_body, bytes), "Body must be bytes, not str" + assert sent_body == EXPECTED_BODY + + @patch("dashscope.api_entities.http_request.requests.Session") + def test_no_unicode_escapes_in_body(self, mock_session_cls): + mock_session = _make_mock_sync_session() + mock_session_cls.return_value = mock_session + + req = HttpRequest( + url="https://example.com/api/v1/test", + api_key="test-key", + http_method=HTTPMethod.POST, + stream=False, + ) + req.data = _make_mock_data(NON_ASCII_PAYLOAD) + + try: + list(req._handle_request()) + except Exception: + pass + + sent_body = mock_session.post.call_args.kwargs.get("data") + body_str = sent_body.decode("utf-8") + + assert "\\u" not in body_str, "Body must not contain \\uXXXX escapes" + assert "你好世界" in body_str + assert "Оцени идею" in body_str + assert "こんにちは" in body_str + + @patch("dashscope.api_entities.http_request.requests.Session") + def test_body_is_smaller_than_ascii_escaped(self, mock_session_cls): + mock_session = _make_mock_sync_session() + mock_session_cls.return_value = mock_session + + req = HttpRequest( + url="https://example.com/api/v1/test", + api_key="test-key", + http_method=HTTPMethod.POST, + stream=False, + ) + req.data = _make_mock_data(NON_ASCII_PAYLOAD) + + try: + list(req._handle_request()) + except Exception: + pass + + sent_body = mock_session.post.call_args.kwargs.get("data") + ascii_escaped_size = len( + json.dumps(NON_ASCII_PAYLOAD, ensure_ascii=True).encode("utf-8"), + ) + assert len(sent_body) < ascii_escaped_size + + +# ---- Async body tests ---- + + +@pytest.mark.asyncio +class TestAioHttpRequestUtf8Body: + # pylint: disable=protected-access + + async def test_body_is_utf8_bytes(self): + session = _MockAioSession() + req = AioHttpRequest( + url="https://example.com/api/v1/test", + api_key="test-key", + http_method=HTTPMethod.POST, + stream=False, + session=session, + ) + req.data = _make_mock_data(NON_ASCII_PAYLOAD) + + async for _ in req._handle_request(): + pass + + sent_body = session.captured.get("data") + assert isinstance(sent_body, bytes), "Body must be bytes, not str" + assert sent_body == EXPECTED_BODY + + async def test_no_unicode_escapes_in_body(self): + session = _MockAioSession() + req = AioHttpRequest( + url="https://example.com/api/v1/test", + api_key="test-key", + http_method=HTTPMethod.POST, + stream=False, + session=session, + ) + req.data = _make_mock_data(NON_ASCII_PAYLOAD) + + async for _ in req._handle_request(): + pass + + sent_body = session.captured.get("data") + body_str = sent_body.decode("utf-8") + + assert "\\u" not in body_str, "Body must not contain \\uXXXX escapes" + assert "你好世界" in body_str + assert "Оцени идею" in body_str + + async def test_body_is_smaller_than_ascii_escaped(self): + session = _MockAioSession() + req = AioHttpRequest( + url="https://example.com/api/v1/test", + api_key="test-key", + http_method=HTTPMethod.POST, + stream=False, + session=session, + ) + req.data = _make_mock_data(NON_ASCII_PAYLOAD) + + async for _ in req._handle_request(): + pass + + sent_body = session.captured.get("data") + ascii_escaped_size = len( + json.dumps(NON_ASCII_PAYLOAD, ensure_ascii=True).encode("utf-8"), + ) + assert len(sent_body) < ascii_escaped_size + + +# ---- WebSocket tests ---- + + +class TestWebSocketRequestUtf8: + # pylint: disable=protected-access + + def test_build_up_message_no_unicode_escapes(self): + from dashscope.api_entities.websocket_request import WebSocketRequest + + req = WebSocketRequest( + url="wss://example.com/api-ws/v1/test", + api_key="test-key", + stream=False, + ) + headers = {"task_id": "test-123", "action": "start"} + payload = { + "input": {"messages": [{"role": "user", "content": "你好世界"}]}, + } + + message = req._build_up_message(headers, payload) + + assert isinstance(message, str), "Message must be str" + assert "\\u" not in message, "Message must not contain \\uXXXX escapes" + assert "你好世界" in message + + def test_build_up_message_smaller_than_ascii_escaped(self): + from dashscope.api_entities.websocket_request import WebSocketRequest + + req = WebSocketRequest( + url="wss://example.com/api-ws/v1/test", + api_key="test-key", + stream=False, + ) + headers = {"task_id": "test-123", "action": "start"} + payload = NON_ASCII_PAYLOAD + + message = req._build_up_message(headers, payload) + message_bytes = message.encode("utf-8") + + ascii_escaped = json.dumps( + {"header": headers, "payload": payload}, + ensure_ascii=True, + ).encode("utf-8") + + assert len(message_bytes) < len(ascii_escaped) From b198288689426546cf062827c1d0544d5349ca2f Mon Sep 17 00:00:00 2001 From: kevin Date: Wed, 1 Jul 2026 18:17:58 +0800 Subject: [PATCH 2/5] fix: resolve dict access errors and URL path issues in 5 CLI commands due to SDK dataclass return types --- .acli/config.toml | 4 +++ .acli/history | 19 +++++++++++ .acli/session.json | 1 + .idea/.gitignore | 3 ++ .idea/dashscope-sdk-python-cli.iml | 17 ++++++++++ .../inspectionProfiles/profiles_settings.xml | 6 ++++ .idea/misc.xml | 7 ++++ .idea/modules.xml | 8 +++++ .idea/vcs.xml | 6 ++++ dashscope/aigc/code_generation.py | 1 + dashscope/cli/agentic_rl.py | 2 +- dashscope/cli/deployments.py | 32 ++++++++----------- dashscope/cli/fine_tunes.py | 30 ++++++++--------- dashscope/nlp/understanding.py | 1 + tests/unit/test_cli_main.py | 18 +++++++++-- 15 files changed, 119 insertions(+), 36 deletions(-) create mode 100644 .acli/config.toml create mode 100644 .acli/history create mode 100644 .acli/session.json create mode 100644 .idea/.gitignore create mode 100644 .idea/dashscope-sdk-python-cli.iml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml diff --git a/.acli/config.toml b/.acli/config.toml new file mode 100644 index 0000000..1917f42 --- /dev/null +++ b/.acli/config.toml @@ -0,0 +1,4 @@ +user_name = "kevin" +model = "qwen3.7-max" +enabled_capabilities = "bailian.profile,bailian.mcp,bailian.cli" +memory_user_id = "acli-kevin" diff --git a/.acli/history b/.acli/history new file mode 100644 index 0000000..4a105da --- /dev/null +++ b/.acli/history @@ -0,0 +1,19 @@ + +# 2026-06-23 11:48:20.526657 ++/key ideatalk c3f124ab49b349c8c683ae429549bca3 + +# 2026-06-25 13:57:58.409997 ++/provider + +# 2026-06-25 13:58:04.636300 ++/key + +# 2026-06-25 13:58:30.078745 ++帮我跑一下整体项目的ut + +# 2026-06-25 13:59:54.531479 ++ ++可以 + +# 2026-06-25 14:16:53.652734 ++所以你是没跑成功吗 diff --git a/.acli/session.json b/.acli/session.json new file mode 100644 index 0000000..481c964 --- /dev/null +++ b/.acli/session.json @@ -0,0 +1 @@ +[{"role": "user", "content": "帮我跑一下整体项目的ut"}, {"role": "assistant", "content": "先看下项目结构,确定测试运行方式。\n\n", "tool_calls": [{"id": "call_206b259592f0435881f5e0a4", "type": "function", "function": {"name": "list_directory", "arguments": "{\"path\": \".\"}"}}]}, {"role": "tool", "content": "目录: . (24 项)\n [目录] .acli/\n [目录] .git/\n [目录] .github/\n [文件] .gitignore (3.3 KB)\n [目录] .idea/\n [目录] .mypy_cache/\n [文件] .pre-commit-config.yaml (4.0 KB)\n [目录] .pytest_cache/\n [文件] LICENSE (11.1 KB)\n [文件] MANIFEST.in (42 B)\n [文件] README.md (12.2 KB)\n [目录] dashscope/\n [目录] dashscope.egg-info/\n [文件] dev.md (1.1 KB)\n [目录] docs/\n [文件] pytest.ini (176 B)\n [文件] requirements-doc.txt (115 B)\n [文件] requirements-test.txt (192 B)\n [文件] requirements.txt (81 B)\n [目录] samples/\n [文件] setup.cfg (94 B)\n [文件] setup.py (2.0 KB)\n [目录] tests/\n [目录] venv/", "name": "list_directory", "tool_use_id": "call_206b259592f0435881f5e0a4", "tool_call_id": "call_206b259592f0435881f5e0a4"}, {"role": "assistant", "tool_calls": [{"id": "call_ce066e1be2bc436da5423300", "type": "function", "function": {"name": "read_file", "arguments": "{\"path\": \"pytest.ini\"}"}}, {"id": "call_057c77f230604cad96ad707b", "type": "function", "function": {"name": "read_file", "arguments": "{\"path\": \"requirements-test.txt\"}"}}]}, {"role": "tool", "content": " 1\t# pytest.ini or .pytest.ini\n 2\t[pytest]\n 3\tminversion = 7.0\n 4\t# addopts = -ra -q\n 5\tasyncio_mode = auto\n 6\tasyncio_default_fixture_loop_scope = function\n 7\tpythonpath = .\n 8\ttestpaths =\n 9\t tests", "name": "read_file", "tool_use_id": "call_ce066e1be2bc436da5423300", "tool_call_id": "call_ce066e1be2bc436da5423300"}, {"role": "tool", "content": " 1\tflake8\n 2\tisort>=4.3.21\n 3\tpre-commit\n 4\tpytest>=7\n 5\tpytest-aiohttp\n 6\tpytest-asyncio\n 7\tyapf==0.30.0 # use fix version to ensure consistent auto-styling\n 8\tcoverage\n 9\tpydantic>=2.0,<3.0\n 10\ttenacity\n 11\ttyping_extensions", "name": "read_file", "tool_use_id": "call_057c77f230604cad96ad707b", "tool_call_id": "call_057c77f230604cad96ad707b"}, {"role": "assistant", "tool_calls": [{"id": "call_2d5e710ec42543ffa856c10e", "type": "function", "function": {"name": "run_command", "arguments": "{\"command\": \"./venv/bin/pytest\"}"}}]}, {"role": "tool", "content": "错误: 命令超时 (30s)", "name": "run_command", "tool_use_id": "call_2d5e710ec42543ffa856c10e", "tool_call_id": "call_2d5e710ec42543ffa856c10e"}, {"role": "assistant", "content": "测试套件可能包含一些依赖网络或耗时较长的用例(比如调用 DashScope API 的集成测试),导致 30 秒内跑不完。\n\n我建议分步排查:\n\n1. **先看看有多少测试用例**\n2. **识别是否有网络依赖的用例**\n3. **选择跳过或延长超时**\n\n我先执行第一步,你看可以吗?\n\n1. 继续\n2. 跳过"}, {"role": "user", "content": "可以"}, {"role": "assistant", "tool_calls": [{"id": "call_c87fa28fe6e2431ebb7cc6f3", "type": "function", "function": {"name": "run_command", "arguments": "{\"command\": \"./venv/bin/pytest --collect-only -q 2>&1 | tail -50\"}"}}, {"id": "call_505e82d73051455d9330c225", "type": "function", "function": {"name": "list_directory", "arguments": "{\"path\": \"tests\"}"}}]}, {"role": "tool", "content": "tests/unit/test_sync_custom_session.py::TestSyncSessionWithCustomConfiguration::test_custom_session_with_proxies\ntests/unit/test_sync_custom_session.py::TestSyncSessionPriority::test_custom_session_has_priority\ntests/unit/test_sync_custom_session.py::TestSyncSessionWithDifferentMethods::test_custom_session_with_post_request\ntests/unit/test_sync_custom_session.py::TestSyncSessionWithDifferentMethods::test_custom_session_with_get_request\ntests/unit/test_sync_custom_session.py::TestSyncBackwardCompatibility::test_works_without_session_parameter\ntests/unit/test_sync_custom_session.py::TestSyncBackwardCompatibility::test_default_behavior_unchanged\ntests/unit/test_text_embedding.py::TestTextEmbeddingRequest::test_call_with_string\ntests/unit/test_text_embedding.py::TestTextEmbeddingRequest::test_call_with_list_str\ntests/unit/test_text_embedding.py::TestTextEmbeddingRequest::test_call_with_opened_file\ntests/unit/test_threads.py::TestThreads::test_create_with_no_messages\ntests/unit/test_threads.py::TestThreads::test_create_with_messages\ntests/unit/test_threads.py::TestThreads::test_retrieve\ntests/unit/test_threads.py::TestThreads::test_update\ntests/unit/test_threads.py::TestThreads::test_delete\ntests/unit/test_tokenization.py::TestTokenization::test_default_no_resources_request\ntests/unit/test_tokenizer.py::TestTokenization::test_encode_decode\ntests/unit/test_translation_recognizer.py::TestSynthesis::test_translate_from_file\ntests/unit/test_understanding.py::TestUnderstandingRequest::test_http_text_call\n\n=============================== warnings summary ===============================\ndashscope/finetune/reinforcement/component/data/base_data_model.py:53\n /Users/kevin/PycharmProjects/dashscope-sdk-python-cli/dashscope/finetune/reinforcement/component/data/base_data_model.py:53: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.13/migration/\n class BaseDataModel(BaseModel):\n\ndashscope/finetune/reinforcement/component/data/group_reward_input.py:27\n /Users/kevin/PycharmProjects/dashscope-sdk-python-cli/dashscope/finetune/reinforcement/component/data/group_reward_input.py:27: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.13/migration/\n class GroupRewardInput(BaseDataModel):\n\ndashscope/finetune/reinforcement/component/data/reward_output.py:41\n /Users/kevin/PycharmProjects/dashscope-sdk-python-cli/dashscope/finetune/reinforcement/component/data/reward_output.py:41: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.13/migration/\n class RewardOutput(BaseModel):\n\ndashscope/finetune/reinforcement/component/data/group_reward_output.py:38\n /Users/kevin/PycharmProjects/dashscope-sdk-python-cli/dashscope/finetune/reinforcement/component/data/group_reward_output.py:38: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.13/migration/\n class GroupRewardOutput(BaseModel):\n\ndashscope/finetune/reinforcement/component/data/reward_input.py:27\n /Users/kevin/PycharmProjects/dashscope-sdk-python-cli/dashscope/finetune/reinforcement/component/data/reward_input.py:27: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.13/migration/\n class RewardInput(BaseDataModel):\n\ndashscope/finetune/reinforcement/component/data/rollout_input.py:27\n /Users/kevin/PycharmProjects/dashscope-sdk-python-cli/dashscope/finetune/reinforcement/component/data/rollout_input.py:27: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.13/migration/\n class RolloutInput(BaseDataModel):\n\ndashscope/finetune/reinforcement/component/data/rollout_output.py:23\n /Users/kevin/PycharmProjects/dashscope-sdk-python-cli/dashscope/finetune/reinforcement/component/data/rollout_output.py:23: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.13/migration/\n class RolloutOutput(BaseModel):\n\n-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html\n429 tests collected in 0.35s\n[exit code: 0]", "name": "run_command", "tool_use_id": "call_c87fa28fe6e2431ebb7cc6f3", "tool_call_id": "call_c87fa28fe6e2431ebb7cc6f3"}, {"role": "tool", "content": "目录: tests (3 项)\n [目录] data/\n [目录] legacy/\n [目录] unit/", "name": "list_directory", "tool_use_id": "call_505e82d73051455d9330c225", "tool_call_id": "call_505e82d73051455d9330c225"}, {"role": "assistant", "content": "测试很多(429 个),30s 跑不完大概率是有用例在做真实网络请求或 sleep。我延长超时到 180s 先跑 `tests/unit`,如果还卡住再定位具体是哪个用例。\n\n", "tool_calls": [{"id": "call_811759963951466f94dea0b1", "type": "function", "function": {"name": "run_command", "arguments": "{\"command\": \"./venv/bin/pytest tests/unit -v --tb=short 2>&1 | tail -200\", \"timeout\": \"180\"}"}}]}, {"role": "tool", "content": "错误: 命令超时 (180s)", "name": "run_command", "tool_use_id": "call_811759963951466f94dea0b1", "tool_call_id": "call_811759963951466f94dea0b1"}, {"role": "assistant", "content": "180s 也超时了,说明有测试用例在做真实的网络请求或者长时间等待。我换个策略——先列出所有测试文件,然后分批执行,找出卡在哪里。\n\n", "tool_calls": [{"id": "call_52b132db93ef4b44a16bf083", "type": "function", "function": {"name": "run_command", "arguments": "{\"command\": \"find tests/unit -name 'test_*.py' -type f | sort\"}"}}]}, {"role": "tool", "content": "tests/unit/test_add_resources.py\ntests/unit/test_agentic_rl_components.py\ntests/unit/test_agentic_rl_model.py\ntests/unit/test_agentic_rl_submit_job.py\ntests/unit/test_agentic_rl_utils.py\ntests/unit/test_application.py\ntests/unit/test_asr_phrases.py\ntests/unit/test_assistant_files.py\ntests/unit/test_assistants.py\ntests/unit/test_async_custom_session.py\ntests/unit/test_cli_application.py\ntests/unit/test_cli_code_generation.py\ntests/unit/test_cli_embeddings.py\ntests/unit/test_cli_image_generation.py\ntests/unit/test_cli_image_synthesis.py\ntests/unit/test_cli_main.py\ntests/unit/test_cli_models.py\ntests/unit/test_cli_multimodal_conversation.py\ntests/unit/test_cli_multimodal_embedding.py\ntests/unit/test_cli_rerank.py\ntests/unit/test_cli_speech_synthesis.py\ntests/unit/test_cli_tokenization.py\ntests/unit/test_cli_transcription.py\ntests/unit/test_cli_understanding.py\ntests/unit/test_cli_video_synthesis.py\ntests/unit/test_code_generation.py\ntests/unit/test_conversation.py\ntests/unit/test_http_api.py\ntests/unit/test_http_deployments_api.py\ntests/unit/test_http_files_api.py\ntests/unit/test_http_fine_tunes_api.py\ntests/unit/test_http_models_api.py\ntests/unit/test_messages.py\ntests/unit/test_multimodal_dialog.py\ntests/unit/test_rerank.py\ntests/unit/test_runs.py\ntests/unit/test_sketch_image_synthesis.py\ntests/unit/test_speech_synthesis_v2.py\ntests/unit/test_sync_custom_session.py\ntests/unit/test_text_embedding.py\ntests/unit/test_threads.py\ntests/unit/test_tokenization.py\ntests/unit/test_tokenizer.py\ntests/unit/test_translation_recognizer.py\ntests/unit/test_understanding.py\n[exit code: 0]", "name": "run_command", "tool_use_id": "call_52b132db93ef4b44a16bf083", "tool_call_id": "call_52b132db93ef4b44a16bf083"}, {"role": "assistant", "content": "测试文件很多,我用 `--timeout=10` 来杀掉耗时超过 10 秒的用例,快速定位问题。\n\n", "tool_calls": [{"id": "call_b8b95f1611c24cdc816718d7", "type": "function", "function": {"name": "run_command", "arguments": "{\"command\": \"./venv/bin/pip install pytest-timeout -q 2>&1 | tail -3\"}"}}]}, {"role": "tool", "content": "[notice] A new release of pip is available: 23.2.1 -> 26.1.2\n[notice] To update, run: pip install --upgrade pip\n[exit code: 0]", "name": "run_command", "tool_use_id": "call_b8b95f1611c24cdc816718d7", "tool_call_id": "call_b8b95f1611c24cdc816718d7"}, {"role": "assistant", "tool_calls": [{"id": "call_dcf37264e0914b0785161a92", "type": "function", "function": {"name": "run_command", "arguments": "{\"command\": \"./venv/bin/pytest tests/unit --timeout=10 -v --tb=short 2>&1\", \"timeout\": \"300\"}"}}]}, {"role": "tool", "content": "============================= test session starts ==============================\nplatform darwin -- Python 3.11.15, pytest-9.1.1, pluggy-1.6.0 -- /Users/kevin/PycharmProjects/dashscope-sdk-python-cli/venv/bin/python\ncachedir: .pytest_cache\nrootdir: /Users/kevin/PycharmProjects/dashscope-sdk-python-cli\nconfigfile: pytest.ini\nplugins: mock-3.15.1, timeout-2.4.0, asyncio-1.4.0, aiohttp-1.1.1\ntimeout: 10.0s\ntimeout method: signal\ntimeout func_only: False\nasyncio: mode=Mode.AUTO, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function\ncollecting ... collected 333 items\n\ntests/unit/test_add_resources.py::TestAddResources::test_default_no_resources_request +++++++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++\n~~~~~~~~~~~~~~~~~~~ Stack of QueueFeederThread (6139817984) ~~~~~~~~~~~~~~~~~~~~\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1002, in _bootstrap\n self._bootstrap_inner()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1045, in _bootstrap_inner\n self.run()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 982, in run\n self._target(*self._args, **self._kwargs)\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/queues.py\", line 231, in _feed\n nwait()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 327, in wait\n waiter.acquire()\n+++++++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++\nFAILED [ 0%]\ntests/unit/test_add_resources.py::TestAddResources::test_default_with_resources_request +++++++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++\n~~~~~~~~~~~~~~~~~~~ Stack of QueueFeederThread (6139817984) ~~~~~~~~~~~~~~~~~~~~\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1002, in _bootstrap\n self._bootstrap_inner()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1045, in _bootstrap_inner\n self.run()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 982, in run\n self._target(*self._args, **self._kwargs)\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/queues.py\", line 231, in _feed\n nwait()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 327, in wait\n waiter.acquire()\n+++++++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++\nFAILED [ 0%]\ntests/unit/test_add_resources.py::TestAddResources::test_default_websocket_no_resources_request +++++++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++\n~~~~~~~~~~~~~~~~~~~~~~~ Stack of asyncio_0 (6325039104) ~~~~~~~~~~~~~~~~~~~~~~~~\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1002, in _bootstrap\n self._bootstrap_inner()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1045, in _bootstrap_inner\n self.run()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 982, in run\n self._target(*self._args, **self._kwargs)\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/concurrent/futures/thread.py\", line 81, in _worker\n work_item = work_queue.get(block=True)\n~~~~~~~~~~~~~~~~~~~ Stack of iter_async_thread (6157217792) ~~~~~~~~~~~~~~~~~~~~\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1002, in _bootstrap\n self._bootstrap_inner()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1045, in _bootstrap_inner\n self.run()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 982, in run\n self._target(*self._args, **self._kwargs)\n File \"/Users/kevin/PycharmProjects/dashscope-sdk-python-cli/dashscope/common/utils.py\", line 98, in iter_thread\n done, obj = loop.run_until_complete(get_next())\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py\", line 641, in run_until_complete\n self.run_forever()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py\", line 608, in run_forever\n self._run_once()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py\", line 1898, in _run_once\n event_list = self._selector.select(timeout)\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/selectors.py\", line 566, in select\n kev_list = self._selector.control(None, max_ev, timeout)\n~~~~~~~~~~~~~~~~~~~ Stack of QueueFeederThread (6139817984) ~~~~~~~~~~~~~~~~~~~~\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1002, in _bootstrap\n self._bootstrap_inner()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1045, in _bootstrap_inner\n self.run()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 982, in run\n self._target(*self._args, **self._kwargs)\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/queues.py\", line 231, in _feed\n nwait()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 327, in wait\n waiter.acquire()\n+++++++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++\nFAILED [ 0%]\ntests/unit/test_add_resources.py::TestAddResources::test_websocket_with_resources_request +++++++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++\n~~~~~~~~~~~~~~~~~~~~~~~ Stack of asyncio_0 (6358691840) ~~~~~~~~~~~~~~~~~~~~~~~~\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1002, in _bootstrap\n self._bootstrap_inner()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1045, in _bootstrap_inner\n self.run()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 982, in run\n self._target(*self._args, **self._kwargs)\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/concurrent/futures/thread.py\", line 81, in _worker\n work_item = work_queue.get(block=True)\n~~~~~~~~~~~~~~~~~~~ Stack of iter_async_thread (6341865472) ~~~~~~~~~~~~~~~~~~~~\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1002, in _bootstrap\n self._bootstrap_inner()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1045, in _bootstrap_inner\n self.run()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 982, in run\n self._target(*self._args, **self._kwargs)\n File \"/Users/kevin/PycharmProjects/dashscope-sdk-python-cli/dashscope/common/utils.py\", line 98, in iter_thread\n done, obj = loop.run_until_complete(get_next())\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py\", line 641, in run_until_complete\n self.run_forever()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py\", line 608, in run_forever\n self._run_once()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py\", line 1898, in _run_once\n event_list = self._selector.select(timeout)\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/selectors.py\", line 566, in select\n kev_list = self._selector.control(None, max_ev, timeout)\n~~~~~~~~~~~~~~~~~~~~~~~ Stack of asyncio_0 (6325039104) ~~~~~~~~~~~~~~~~~~~~~~~~\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1002, in _bootstrap\n self._bootstrap_inner()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1045, in _bootstrap_inner\n self.run()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 982, in run\n self._target(*self._args, **self._kwargs)\n File \"/opt/homebrew/Cellar/python@3.11/3.11.1\n\n... (输出被截断,总长度 318444 字节)\n[exit code: 1]", "name": "run_command", "tool_use_id": "call_dcf37264e0914b0785161a92", "tool_call_id": "call_dcf37264e0914b0785161a92"}, {"role": "assistant", "content": "输出太多了,我提取最后的汇总结果。\n\n", "tool_calls": [{"id": "call_f4a2c78e618148258f7c211d", "type": "function", "function": {"name": "run_command", "arguments": "{\"command\": \"./venv/bin/pytest tests/unit --timeout=10 --tb=no -q 2>&1 | tail -30\", \"timeout\": \"300\"}"}}]}, {"role": "tool", "content": "FAILED tests/unit/test_assistants.py::TestAssistants::test_list_assistant - r...\nFAILED tests/unit/test_assistants.py::TestAssistants::test_update_assistant\nFAILED tests/unit/test_assistants.py::TestAssistants::test_delete_assistant\nFAILED tests/unit/test_conversation.py::TestConversationRequest::test_message_request\nFAILED tests/unit/test_conversation.py::TestConversationRequest::test_conversation_with_history\nFAILED tests/unit/test_conversation.py::TestConversationRequest::test_conversation_with_message_and_prompt\nFAILED tests/unit/test_conversation.py::TestConversationRequest::test_conversation_with_messages\nFAILED tests/unit/test_conversation.py::TestConversationRequest::test_conversation_call_with_messages\nFAILED tests/unit/test_conversation.py::TestConversationRequest::test_not_qwen\nFAILED tests/unit/test_http_api.py::TestHttpRequest::test_independent_model_sync_stream_request\nFAILED tests/unit/test_http_fine_tunes_api.py::TestFineTuneRequest::test_create_fine_tune_job\nFAILED tests/unit/test_http_fine_tunes_api.py::TestFineTuneRequest::test_create_fine_tune_job_with_files\nFAILED tests/unit/test_http_fine_tunes_api.py::TestFineTuneRequest::test_list_fine_tune_job\nFAILED tests/unit/test_http_fine_tunes_api.py::TestFineTuneRequest::test_get_fine_tune_job\nFAILED tests/unit/test_http_fine_tunes_api.py::TestFineTuneRequest::test_delete_fine_tune_job\nFAILED tests/unit/test_http_fine_tunes_api.py::TestFineTuneRequest::test_cancel_fine_tune_job\nFAILED tests/unit/test_http_fine_tunes_api.py::TestFineTuneRequest::test_stream_event\nFAILED tests/unit/test_messages.py::TestMessages::test_update - KeyError: 'me...\nFAILED tests/unit/test_messages.py::TestMessages::test_retrieve - Failed: Tim...\nFAILED tests/unit/test_messages.py::TestMessages::test_list - Failed: Timeout...\nFAILED tests/unit/test_messages.py::TestMessages::test_list_message_files - F...\nFAILED tests/unit/test_messages.py::TestMessages::test_retrieve_message_file\nFAILED tests/unit/test_runs.py::TestRuns::test_retrieve - Failed: Timeout (>1...\nFAILED tests/unit/test_runs.py::TestRuns::test_list - Failed: Timeout (>10.0s...\nFAILED tests/unit/test_runs.py::TestRuns::test_submit_tool_outputs - Failed: ...\nFAILED tests/unit/test_runs.py::TestRuns::test_run_required_function_call - A...\nFAILED tests/unit/test_runs.py::TestRuns::test_list_run_steps - Failed: Timeo...\nFAILED tests/unit/test_runs.py::TestRuns::test_retrieve_run_steps - Failed: T...\nFAILED tests/unit/test_runs.py::TestRuns::test_cancel - Failed: Timeout (>10....\n44 failed, 283 passed, 6 skipped, 161 warnings in 267.14s (0:04:27)\n[exit code: 0]", "name": "run_command", "tool_use_id": "call_f4a2c78e618148258f7c211d", "tool_call_id": "call_f4a2c78e618148258f7c211d"}, {"role": "user", "content": "所以你是没跑成功吗"}] \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..359bb53 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml diff --git a/.idea/dashscope-sdk-python-cli.iml b/.idea/dashscope-sdk-python-cli.iml new file mode 100644 index 0000000..3effa6c --- /dev/null +++ b/.idea/dashscope-sdk-python-cli.iml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..0d8674f --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..ffd63ce --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/dashscope/aigc/code_generation.py b/dashscope/aigc/code_generation.py index a5f819f..4dbf422 100644 --- a/dashscope/aigc/code_generation.py +++ b/dashscope/aigc/code_generation.py @@ -152,6 +152,7 @@ def call( # type: ignore[override] api_key=api_key, input=input, workspace=workspace, + is_service=False, **parameters, ) diff --git a/dashscope/cli/agentic_rl.py b/dashscope/cli/agentic_rl.py index ece3953..34d5c1d 100644 --- a/dashscope/cli/agentic_rl.py +++ b/dashscope/cli/agentic_rl.py @@ -670,7 +670,7 @@ def logs( ) format_output( - {"job_id": job_id, "logs": result.output.get("logs", "")}, + {"job_id": job_id, "logs": getattr(result.output, "logs", "")}, fmt=output_format, ) except Exception as e: diff --git a/dashscope/cli/deployments.py b/dashscope/cli/deployments.py index d17bdd0..6664c73 100644 --- a/dashscope/cli/deployments.py +++ b/dashscope/cli/deployments.py @@ -43,7 +43,7 @@ def _wait_for_deployment(deployed_model: str): while True: rsp = dashscope.Deployments.get(deployed_model) output = ensure_ok(rsp) - status = output["status"] + status = output.status if status in ( DeploymentStatus.PENDING, @@ -67,18 +67,14 @@ def _wait_for_deployment(deployed_model: str): def _print_deployments(output): """Pretty-print a list of deployments from *output*.""" - if ( - output is None - or "deployments" not in output - or not output["deployments"] - ): + if output is None or not output.deployments: console.print("There is no deployed model!") return - for dep in output["deployments"]: + for dep in output.deployments: console.print( - f"Deployed_model: {dep['deployed_model']}, " - f"model: {dep['model_name']}, " - f"status: {dep['status']}", + f"Deployed_model: {dep.deployed_model}, " + f"model: {dep.model_name}, " + f"status: {dep.status}", ) @@ -111,7 +107,7 @@ def create( suffix=suffix, # type: ignore[arg-type] ) output = ensure_ok(rsp) - deployed_model = output["deployed_model"] + deployed_model = output.deployed_model success(f"Create model: {deployed_model} deployment") _wait_for_deployment(deployed_model) @@ -151,9 +147,9 @@ def get( rsp = dashscope.Deployments.get(deployed_model) output = ensure_ok(rsp) console.print( - f"Deployed model: {output['deployed_model']} " - f"capacity: {output['capacity']} " - f"status: {output['status']}", + f"Deployed model: {output.deployed_model} " + f"capacity: {output.capacity} " + f"status: {output.status}", ) @@ -166,7 +162,7 @@ def list_deployments( """List model deployments.""" rsp = dashscope.Deployments.list(page_no=page, page_size=size) output = ensure_ok(rsp) - if output is None or not output.get("deployments"): + if output is None or not output.deployments: console.print("There is no deployed model.") return _print_deployments(output) @@ -193,9 +189,9 @@ def scale( console.print("There is no deployed model.") return console.print( - f"Deployed_model: {output['deployed_model']}, " - f"model: {output['model_name']}, " - f"status: {output['status']}", + f"Deployed_model: {output.deployed_model}, " + f"model: {output.model_name}, " + f"status: {output.status}", ) diff --git a/dashscope/cli/fine_tunes.py b/dashscope/cli/fine_tunes.py index cdd44df..0a7f60d 100644 --- a/dashscope/cli/fine_tunes.py +++ b/dashscope/cli/fine_tunes.py @@ -45,7 +45,7 @@ def _wait_for_job(job_id: str): while True: rsp = dashscope.FineTunes.get(job_id) output = ensure_ok(rsp) - status = output["status"] + status = output.status if status == TaskStatus.FAILED: err_console.print("[red]Fine-tune FAILED![/red]") @@ -62,7 +62,7 @@ def _wait_for_job(job_id: str): if status == TaskStatus.SUCCEEDED: success( f"Fine-tune task success, fine-tuned model: " - f"{output['finetuned_output']}", + f"{output.finetuned_output}", ) return @@ -86,12 +86,12 @@ def _stream_events(job_id: str): print_failed_message(rsp) return - if rsp.output["status"] in ( + if rsp.output.status in ( TaskStatus.FAILED, TaskStatus.CANCELED, TaskStatus.SUCCEEDED, ): - console.print(f"Fine-tune job: {job_id} is {rsp.output['status']}") + console.print(f"Fine-tune job: {job_id} is {rsp.output.status}") _dump_logs(job_id) return @@ -120,9 +120,9 @@ def _dump_logs(job_id: str): line=LOG_PAGE_SIZE, ) output = ensure_ok(rsp) - for line in output["logs"]: + for line in output.logs: console.print(line, highlight=False) - if len(output["logs"]) < LOG_PAGE_SIZE: + if len(output.logs) < LOG_PAGE_SIZE: break offset += LOG_PAGE_SIZE @@ -202,7 +202,7 @@ def create( hyper_parameters=params if params else None, # type: ignore[arg-type] ) output = ensure_ok(rsp) - job_id = output["job_id"] + job_id = output.job_id success(f"Create fine-tune job success, job_id: {job_id}") _wait_for_job(job_id) @@ -280,14 +280,14 @@ def get( """Get fine-tune job status.""" rsp = dashscope.FineTunes.get(job_id) output = ensure_ok(rsp) - status = output["status"] + status = output.status if status == TaskStatus.FAILED: err_console.print("[red]Fine-tune failed![/red]") elif status == TaskStatus.CANCELED: console.print("Fine-tune task canceled") elif status == TaskStatus.SUCCEEDED: - model_name = output["finetuned_output"] + model_name = output.finetuned_output success(f"Fine-tune task success, fine-tuned model: {model_name}") else: console.print(f"The fine-tune task is: {status}") @@ -302,17 +302,17 @@ def list_jobs( """List fine-tune jobs.""" rsp = dashscope.FineTunes.list(page=page, page_size=size) output = ensure_ok(rsp) - if output is None or not output.get("jobs"): + if output is None or not output.jobs: console.print("There is no fine-tuned model.") return - for job in output["jobs"]: + for job in output.jobs: line = ( - f"job: {job['job_id']}, status: {job['status']}, " - f"base model: {job['model']}" + f"job: {job.job_id}, status: {job.status}, " + f"base model: {job.model}" ) - if job["status"] == TaskStatus.SUCCEEDED: - line += f", fine-tuned model: {job['finetuned_output']}" + if job.status == TaskStatus.SUCCEEDED: + line += f", fine-tuned model: {job.finetuned_output}" console.print(line) diff --git a/dashscope/nlp/understanding.py b/dashscope/nlp/understanding.py index 137f0a4..e6be294 100644 --- a/dashscope/nlp/understanding.py +++ b/dashscope/nlp/understanding.py @@ -66,6 +66,7 @@ def call( # type: ignore[override] function=function, api_key=api_key, input=input, + is_service=False, **parameters, ) diff --git a/tests/unit/test_cli_main.py b/tests/unit/test_cli_main.py index 6999fc3..d4c839c 100644 --- a/tests/unit/test_cli_main.py +++ b/tests/unit/test_cli_main.py @@ -403,11 +403,25 @@ def mock_files_list(**kwargs): def mock_fine_tunes_list(**kwargs): captured_requests["fine_tunes"] = kwargs - return SimpleNamespace(status_code=200, output={"jobs": []}) + from dashscope.finetune.customize_types import ( + FineTuneList, + FineTuneListOutput, + ) + + result = FineTuneList(status_code=200) + result.output = FineTuneListOutput(jobs=[]) + return result def mock_deployments_list(**kwargs): captured_requests["deployments"] = kwargs - return SimpleNamespace(status_code=200, output={"deployments": []}) + from dashscope.finetune.customize_types import ( + DeploymentList, + DeploymentListOutput, + ) + + result = DeploymentList(status_code=200) + result.output = DeploymentListOutput(deployments=[]) + return result monkeypatch.setattr( "dashscope.cli.files.dashscope.Files.list", From 68b3609f2f37fe59644b963551d2178c19ef59db Mon Sep 17 00:00:00 2001 From: "zhansheng.lzs" Date: Wed, 1 Jul 2026 18:22:35 +0800 Subject: [PATCH 3/5] fix: resolve parameter shadowing in base_api.py update/put methods The 'json' parameter in UpdateMixin.update() and PutMixin.put() shadowed the 'json' module, causing AttributeError when calling json.dumps(). Use local 'import json as _json' alias to avoid the conflict while keeping the public API parameter name unchanged. --- dashscope/client/base_api.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/dashscope/client/base_api.py b/dashscope/client/base_api.py index 510b49b..fc067fc 100644 --- a/dashscope/client/base_api.py +++ b/dashscope/client/base_api.py @@ -1298,7 +1298,7 @@ class UpdateMixin: def update( cls, target: str, - json_body: object, + json: object, # pylint: disable=redefined-outer-name api_key: str = None, path: str = None, workspace: str = None, @@ -1309,7 +1309,7 @@ def update( Args: target (str): The target to update. - json_body (object): The create request json body. + json (object): The create request json body. api_key (str, optional): The api api_key, if not present, will get by default rule(TODO: api key doc). Defaults to None. @@ -1330,9 +1330,11 @@ def update( DEFAULT_REQUEST_TIMEOUT_SECONDS, ) flattened_output = kwargs.pop("flattened_output", False) + import json as _json # pylint: disable=reimported + with requests.Session() as session: logger.debug("Starting request: %s", url) - body = json.dumps(json_body, ensure_ascii=False).encode("utf-8") + body = _json.dumps(json, ensure_ascii=False).encode("utf-8") if method == "post": response = session.post( url, @@ -1366,7 +1368,7 @@ class PutMixin: def put( cls, target: str, - json_body: object, + json: object, # pylint: disable=redefined-outer-name path: str = None, api_key: str = None, workspace: str = None, @@ -1376,7 +1378,7 @@ def put( Args: target (str): The target to update. - json_body (object): The create request json body. + json (object): The create request json body. api_key (str, optional): The api api_key, if not present, will get by default rule(TODO: api key doc). Defaults to None. @@ -1396,9 +1398,11 @@ def put( REQUEST_TIMEOUT_KEYWORD, DEFAULT_REQUEST_TIMEOUT_SECONDS, ) + import json as _json # pylint: disable=reimported + with requests.Session() as session: logger.debug("Starting request: %s", url) - body = json.dumps(json_body, ensure_ascii=False).encode("utf-8") + body = _json.dumps(json, ensure_ascii=False).encode("utf-8") response = session.put( url, data=body, From 8603389ac1b29cdb96454afab20fc6b50ade6593 Mon Sep 17 00:00:00 2001 From: "zhansheng.lzs" Date: Wed, 1 Jul 2026 18:32:32 +0800 Subject: [PATCH 4/5] chore: update .gitignore to exclude .acli and .idea Co-Authored-By: Claude Opus 4.7 --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 15425d1..9800941 100644 --- a/.gitignore +++ b/.gitignore @@ -171,4 +171,6 @@ cython_debug/ .pypirc # acli -.acli/ +.acli + +.idea From 4364783e4e804328988e0623e446bc082741e132 Mon Sep 17 00:00:00 2001 From: "zhansheng.lzs" Date: Wed, 1 Jul 2026 18:38:22 +0800 Subject: [PATCH 5/5] chore: remove .acli and .idea from repository These local config directories should not be tracked in git. They are now properly excluded via .gitignore. Co-Authored-By: Claude Opus 4.7 --- .acli/config.toml | 4 ---- .acli/history | 19 ------------------- .acli/session.json | 1 - .idea/.gitignore | 3 --- .idea/dashscope-sdk-python-cli.iml | 17 ----------------- .../inspectionProfiles/profiles_settings.xml | 6 ------ .idea/misc.xml | 7 ------- .idea/modules.xml | 8 -------- .idea/vcs.xml | 6 ------ 9 files changed, 71 deletions(-) delete mode 100644 .acli/config.toml delete mode 100644 .acli/history delete mode 100644 .acli/session.json delete mode 100644 .idea/.gitignore delete mode 100644 .idea/dashscope-sdk-python-cli.iml delete mode 100644 .idea/inspectionProfiles/profiles_settings.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml diff --git a/.acli/config.toml b/.acli/config.toml deleted file mode 100644 index 1917f42..0000000 --- a/.acli/config.toml +++ /dev/null @@ -1,4 +0,0 @@ -user_name = "kevin" -model = "qwen3.7-max" -enabled_capabilities = "bailian.profile,bailian.mcp,bailian.cli" -memory_user_id = "acli-kevin" diff --git a/.acli/history b/.acli/history deleted file mode 100644 index 4a105da..0000000 --- a/.acli/history +++ /dev/null @@ -1,19 +0,0 @@ - -# 2026-06-23 11:48:20.526657 -+/key ideatalk c3f124ab49b349c8c683ae429549bca3 - -# 2026-06-25 13:57:58.409997 -+/provider - -# 2026-06-25 13:58:04.636300 -+/key - -# 2026-06-25 13:58:30.078745 -+帮我跑一下整体项目的ut - -# 2026-06-25 13:59:54.531479 -+ -+可以 - -# 2026-06-25 14:16:53.652734 -+所以你是没跑成功吗 diff --git a/.acli/session.json b/.acli/session.json deleted file mode 100644 index 481c964..0000000 --- a/.acli/session.json +++ /dev/null @@ -1 +0,0 @@ -[{"role": "user", "content": "帮我跑一下整体项目的ut"}, {"role": "assistant", "content": "先看下项目结构,确定测试运行方式。\n\n", "tool_calls": [{"id": "call_206b259592f0435881f5e0a4", "type": "function", "function": {"name": "list_directory", "arguments": "{\"path\": \".\"}"}}]}, {"role": "tool", "content": "目录: . (24 项)\n [目录] .acli/\n [目录] .git/\n [目录] .github/\n [文件] .gitignore (3.3 KB)\n [目录] .idea/\n [目录] .mypy_cache/\n [文件] .pre-commit-config.yaml (4.0 KB)\n [目录] .pytest_cache/\n [文件] LICENSE (11.1 KB)\n [文件] MANIFEST.in (42 B)\n [文件] README.md (12.2 KB)\n [目录] dashscope/\n [目录] dashscope.egg-info/\n [文件] dev.md (1.1 KB)\n [目录] docs/\n [文件] pytest.ini (176 B)\n [文件] requirements-doc.txt (115 B)\n [文件] requirements-test.txt (192 B)\n [文件] requirements.txt (81 B)\n [目录] samples/\n [文件] setup.cfg (94 B)\n [文件] setup.py (2.0 KB)\n [目录] tests/\n [目录] venv/", "name": "list_directory", "tool_use_id": "call_206b259592f0435881f5e0a4", "tool_call_id": "call_206b259592f0435881f5e0a4"}, {"role": "assistant", "tool_calls": [{"id": "call_ce066e1be2bc436da5423300", "type": "function", "function": {"name": "read_file", "arguments": "{\"path\": \"pytest.ini\"}"}}, {"id": "call_057c77f230604cad96ad707b", "type": "function", "function": {"name": "read_file", "arguments": "{\"path\": \"requirements-test.txt\"}"}}]}, {"role": "tool", "content": " 1\t# pytest.ini or .pytest.ini\n 2\t[pytest]\n 3\tminversion = 7.0\n 4\t# addopts = -ra -q\n 5\tasyncio_mode = auto\n 6\tasyncio_default_fixture_loop_scope = function\n 7\tpythonpath = .\n 8\ttestpaths =\n 9\t tests", "name": "read_file", "tool_use_id": "call_ce066e1be2bc436da5423300", "tool_call_id": "call_ce066e1be2bc436da5423300"}, {"role": "tool", "content": " 1\tflake8\n 2\tisort>=4.3.21\n 3\tpre-commit\n 4\tpytest>=7\n 5\tpytest-aiohttp\n 6\tpytest-asyncio\n 7\tyapf==0.30.0 # use fix version to ensure consistent auto-styling\n 8\tcoverage\n 9\tpydantic>=2.0,<3.0\n 10\ttenacity\n 11\ttyping_extensions", "name": "read_file", "tool_use_id": "call_057c77f230604cad96ad707b", "tool_call_id": "call_057c77f230604cad96ad707b"}, {"role": "assistant", "tool_calls": [{"id": "call_2d5e710ec42543ffa856c10e", "type": "function", "function": {"name": "run_command", "arguments": "{\"command\": \"./venv/bin/pytest\"}"}}]}, {"role": "tool", "content": "错误: 命令超时 (30s)", "name": "run_command", "tool_use_id": "call_2d5e710ec42543ffa856c10e", "tool_call_id": "call_2d5e710ec42543ffa856c10e"}, {"role": "assistant", "content": "测试套件可能包含一些依赖网络或耗时较长的用例(比如调用 DashScope API 的集成测试),导致 30 秒内跑不完。\n\n我建议分步排查:\n\n1. **先看看有多少测试用例**\n2. **识别是否有网络依赖的用例**\n3. **选择跳过或延长超时**\n\n我先执行第一步,你看可以吗?\n\n1. 继续\n2. 跳过"}, {"role": "user", "content": "可以"}, {"role": "assistant", "tool_calls": [{"id": "call_c87fa28fe6e2431ebb7cc6f3", "type": "function", "function": {"name": "run_command", "arguments": "{\"command\": \"./venv/bin/pytest --collect-only -q 2>&1 | tail -50\"}"}}, {"id": "call_505e82d73051455d9330c225", "type": "function", "function": {"name": "list_directory", "arguments": "{\"path\": \"tests\"}"}}]}, {"role": "tool", "content": "tests/unit/test_sync_custom_session.py::TestSyncSessionWithCustomConfiguration::test_custom_session_with_proxies\ntests/unit/test_sync_custom_session.py::TestSyncSessionPriority::test_custom_session_has_priority\ntests/unit/test_sync_custom_session.py::TestSyncSessionWithDifferentMethods::test_custom_session_with_post_request\ntests/unit/test_sync_custom_session.py::TestSyncSessionWithDifferentMethods::test_custom_session_with_get_request\ntests/unit/test_sync_custom_session.py::TestSyncBackwardCompatibility::test_works_without_session_parameter\ntests/unit/test_sync_custom_session.py::TestSyncBackwardCompatibility::test_default_behavior_unchanged\ntests/unit/test_text_embedding.py::TestTextEmbeddingRequest::test_call_with_string\ntests/unit/test_text_embedding.py::TestTextEmbeddingRequest::test_call_with_list_str\ntests/unit/test_text_embedding.py::TestTextEmbeddingRequest::test_call_with_opened_file\ntests/unit/test_threads.py::TestThreads::test_create_with_no_messages\ntests/unit/test_threads.py::TestThreads::test_create_with_messages\ntests/unit/test_threads.py::TestThreads::test_retrieve\ntests/unit/test_threads.py::TestThreads::test_update\ntests/unit/test_threads.py::TestThreads::test_delete\ntests/unit/test_tokenization.py::TestTokenization::test_default_no_resources_request\ntests/unit/test_tokenizer.py::TestTokenization::test_encode_decode\ntests/unit/test_translation_recognizer.py::TestSynthesis::test_translate_from_file\ntests/unit/test_understanding.py::TestUnderstandingRequest::test_http_text_call\n\n=============================== warnings summary ===============================\ndashscope/finetune/reinforcement/component/data/base_data_model.py:53\n /Users/kevin/PycharmProjects/dashscope-sdk-python-cli/dashscope/finetune/reinforcement/component/data/base_data_model.py:53: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.13/migration/\n class BaseDataModel(BaseModel):\n\ndashscope/finetune/reinforcement/component/data/group_reward_input.py:27\n /Users/kevin/PycharmProjects/dashscope-sdk-python-cli/dashscope/finetune/reinforcement/component/data/group_reward_input.py:27: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.13/migration/\n class GroupRewardInput(BaseDataModel):\n\ndashscope/finetune/reinforcement/component/data/reward_output.py:41\n /Users/kevin/PycharmProjects/dashscope-sdk-python-cli/dashscope/finetune/reinforcement/component/data/reward_output.py:41: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.13/migration/\n class RewardOutput(BaseModel):\n\ndashscope/finetune/reinforcement/component/data/group_reward_output.py:38\n /Users/kevin/PycharmProjects/dashscope-sdk-python-cli/dashscope/finetune/reinforcement/component/data/group_reward_output.py:38: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.13/migration/\n class GroupRewardOutput(BaseModel):\n\ndashscope/finetune/reinforcement/component/data/reward_input.py:27\n /Users/kevin/PycharmProjects/dashscope-sdk-python-cli/dashscope/finetune/reinforcement/component/data/reward_input.py:27: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.13/migration/\n class RewardInput(BaseDataModel):\n\ndashscope/finetune/reinforcement/component/data/rollout_input.py:27\n /Users/kevin/PycharmProjects/dashscope-sdk-python-cli/dashscope/finetune/reinforcement/component/data/rollout_input.py:27: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.13/migration/\n class RolloutInput(BaseDataModel):\n\ndashscope/finetune/reinforcement/component/data/rollout_output.py:23\n /Users/kevin/PycharmProjects/dashscope-sdk-python-cli/dashscope/finetune/reinforcement/component/data/rollout_output.py:23: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.13/migration/\n class RolloutOutput(BaseModel):\n\n-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html\n429 tests collected in 0.35s\n[exit code: 0]", "name": "run_command", "tool_use_id": "call_c87fa28fe6e2431ebb7cc6f3", "tool_call_id": "call_c87fa28fe6e2431ebb7cc6f3"}, {"role": "tool", "content": "目录: tests (3 项)\n [目录] data/\n [目录] legacy/\n [目录] unit/", "name": "list_directory", "tool_use_id": "call_505e82d73051455d9330c225", "tool_call_id": "call_505e82d73051455d9330c225"}, {"role": "assistant", "content": "测试很多(429 个),30s 跑不完大概率是有用例在做真实网络请求或 sleep。我延长超时到 180s 先跑 `tests/unit`,如果还卡住再定位具体是哪个用例。\n\n", "tool_calls": [{"id": "call_811759963951466f94dea0b1", "type": "function", "function": {"name": "run_command", "arguments": "{\"command\": \"./venv/bin/pytest tests/unit -v --tb=short 2>&1 | tail -200\", \"timeout\": \"180\"}"}}]}, {"role": "tool", "content": "错误: 命令超时 (180s)", "name": "run_command", "tool_use_id": "call_811759963951466f94dea0b1", "tool_call_id": "call_811759963951466f94dea0b1"}, {"role": "assistant", "content": "180s 也超时了,说明有测试用例在做真实的网络请求或者长时间等待。我换个策略——先列出所有测试文件,然后分批执行,找出卡在哪里。\n\n", "tool_calls": [{"id": "call_52b132db93ef4b44a16bf083", "type": "function", "function": {"name": "run_command", "arguments": "{\"command\": \"find tests/unit -name 'test_*.py' -type f | sort\"}"}}]}, {"role": "tool", "content": "tests/unit/test_add_resources.py\ntests/unit/test_agentic_rl_components.py\ntests/unit/test_agentic_rl_model.py\ntests/unit/test_agentic_rl_submit_job.py\ntests/unit/test_agentic_rl_utils.py\ntests/unit/test_application.py\ntests/unit/test_asr_phrases.py\ntests/unit/test_assistant_files.py\ntests/unit/test_assistants.py\ntests/unit/test_async_custom_session.py\ntests/unit/test_cli_application.py\ntests/unit/test_cli_code_generation.py\ntests/unit/test_cli_embeddings.py\ntests/unit/test_cli_image_generation.py\ntests/unit/test_cli_image_synthesis.py\ntests/unit/test_cli_main.py\ntests/unit/test_cli_models.py\ntests/unit/test_cli_multimodal_conversation.py\ntests/unit/test_cli_multimodal_embedding.py\ntests/unit/test_cli_rerank.py\ntests/unit/test_cli_speech_synthesis.py\ntests/unit/test_cli_tokenization.py\ntests/unit/test_cli_transcription.py\ntests/unit/test_cli_understanding.py\ntests/unit/test_cli_video_synthesis.py\ntests/unit/test_code_generation.py\ntests/unit/test_conversation.py\ntests/unit/test_http_api.py\ntests/unit/test_http_deployments_api.py\ntests/unit/test_http_files_api.py\ntests/unit/test_http_fine_tunes_api.py\ntests/unit/test_http_models_api.py\ntests/unit/test_messages.py\ntests/unit/test_multimodal_dialog.py\ntests/unit/test_rerank.py\ntests/unit/test_runs.py\ntests/unit/test_sketch_image_synthesis.py\ntests/unit/test_speech_synthesis_v2.py\ntests/unit/test_sync_custom_session.py\ntests/unit/test_text_embedding.py\ntests/unit/test_threads.py\ntests/unit/test_tokenization.py\ntests/unit/test_tokenizer.py\ntests/unit/test_translation_recognizer.py\ntests/unit/test_understanding.py\n[exit code: 0]", "name": "run_command", "tool_use_id": "call_52b132db93ef4b44a16bf083", "tool_call_id": "call_52b132db93ef4b44a16bf083"}, {"role": "assistant", "content": "测试文件很多,我用 `--timeout=10` 来杀掉耗时超过 10 秒的用例,快速定位问题。\n\n", "tool_calls": [{"id": "call_b8b95f1611c24cdc816718d7", "type": "function", "function": {"name": "run_command", "arguments": "{\"command\": \"./venv/bin/pip install pytest-timeout -q 2>&1 | tail -3\"}"}}]}, {"role": "tool", "content": "[notice] A new release of pip is available: 23.2.1 -> 26.1.2\n[notice] To update, run: pip install --upgrade pip\n[exit code: 0]", "name": "run_command", "tool_use_id": "call_b8b95f1611c24cdc816718d7", "tool_call_id": "call_b8b95f1611c24cdc816718d7"}, {"role": "assistant", "tool_calls": [{"id": "call_dcf37264e0914b0785161a92", "type": "function", "function": {"name": "run_command", "arguments": "{\"command\": \"./venv/bin/pytest tests/unit --timeout=10 -v --tb=short 2>&1\", \"timeout\": \"300\"}"}}]}, {"role": "tool", "content": "============================= test session starts ==============================\nplatform darwin -- Python 3.11.15, pytest-9.1.1, pluggy-1.6.0 -- /Users/kevin/PycharmProjects/dashscope-sdk-python-cli/venv/bin/python\ncachedir: .pytest_cache\nrootdir: /Users/kevin/PycharmProjects/dashscope-sdk-python-cli\nconfigfile: pytest.ini\nplugins: mock-3.15.1, timeout-2.4.0, asyncio-1.4.0, aiohttp-1.1.1\ntimeout: 10.0s\ntimeout method: signal\ntimeout func_only: False\nasyncio: mode=Mode.AUTO, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function\ncollecting ... collected 333 items\n\ntests/unit/test_add_resources.py::TestAddResources::test_default_no_resources_request +++++++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++\n~~~~~~~~~~~~~~~~~~~ Stack of QueueFeederThread (6139817984) ~~~~~~~~~~~~~~~~~~~~\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1002, in _bootstrap\n self._bootstrap_inner()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1045, in _bootstrap_inner\n self.run()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 982, in run\n self._target(*self._args, **self._kwargs)\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/queues.py\", line 231, in _feed\n nwait()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 327, in wait\n waiter.acquire()\n+++++++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++\nFAILED [ 0%]\ntests/unit/test_add_resources.py::TestAddResources::test_default_with_resources_request +++++++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++\n~~~~~~~~~~~~~~~~~~~ Stack of QueueFeederThread (6139817984) ~~~~~~~~~~~~~~~~~~~~\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1002, in _bootstrap\n self._bootstrap_inner()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1045, in _bootstrap_inner\n self.run()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 982, in run\n self._target(*self._args, **self._kwargs)\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/queues.py\", line 231, in _feed\n nwait()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 327, in wait\n waiter.acquire()\n+++++++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++\nFAILED [ 0%]\ntests/unit/test_add_resources.py::TestAddResources::test_default_websocket_no_resources_request +++++++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++\n~~~~~~~~~~~~~~~~~~~~~~~ Stack of asyncio_0 (6325039104) ~~~~~~~~~~~~~~~~~~~~~~~~\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1002, in _bootstrap\n self._bootstrap_inner()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1045, in _bootstrap_inner\n self.run()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 982, in run\n self._target(*self._args, **self._kwargs)\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/concurrent/futures/thread.py\", line 81, in _worker\n work_item = work_queue.get(block=True)\n~~~~~~~~~~~~~~~~~~~ Stack of iter_async_thread (6157217792) ~~~~~~~~~~~~~~~~~~~~\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1002, in _bootstrap\n self._bootstrap_inner()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1045, in _bootstrap_inner\n self.run()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 982, in run\n self._target(*self._args, **self._kwargs)\n File \"/Users/kevin/PycharmProjects/dashscope-sdk-python-cli/dashscope/common/utils.py\", line 98, in iter_thread\n done, obj = loop.run_until_complete(get_next())\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py\", line 641, in run_until_complete\n self.run_forever()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py\", line 608, in run_forever\n self._run_once()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py\", line 1898, in _run_once\n event_list = self._selector.select(timeout)\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/selectors.py\", line 566, in select\n kev_list = self._selector.control(None, max_ev, timeout)\n~~~~~~~~~~~~~~~~~~~ Stack of QueueFeederThread (6139817984) ~~~~~~~~~~~~~~~~~~~~\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1002, in _bootstrap\n self._bootstrap_inner()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1045, in _bootstrap_inner\n self.run()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 982, in run\n self._target(*self._args, **self._kwargs)\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/queues.py\", line 231, in _feed\n nwait()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 327, in wait\n waiter.acquire()\n+++++++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++\nFAILED [ 0%]\ntests/unit/test_add_resources.py::TestAddResources::test_websocket_with_resources_request +++++++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++\n~~~~~~~~~~~~~~~~~~~~~~~ Stack of asyncio_0 (6358691840) ~~~~~~~~~~~~~~~~~~~~~~~~\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1002, in _bootstrap\n self._bootstrap_inner()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1045, in _bootstrap_inner\n self.run()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 982, in run\n self._target(*self._args, **self._kwargs)\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/concurrent/futures/thread.py\", line 81, in _worker\n work_item = work_queue.get(block=True)\n~~~~~~~~~~~~~~~~~~~ Stack of iter_async_thread (6341865472) ~~~~~~~~~~~~~~~~~~~~\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1002, in _bootstrap\n self._bootstrap_inner()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1045, in _bootstrap_inner\n self.run()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 982, in run\n self._target(*self._args, **self._kwargs)\n File \"/Users/kevin/PycharmProjects/dashscope-sdk-python-cli/dashscope/common/utils.py\", line 98, in iter_thread\n done, obj = loop.run_until_complete(get_next())\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py\", line 641, in run_until_complete\n self.run_forever()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py\", line 608, in run_forever\n self._run_once()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py\", line 1898, in _run_once\n event_list = self._selector.select(timeout)\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/selectors.py\", line 566, in select\n kev_list = self._selector.control(None, max_ev, timeout)\n~~~~~~~~~~~~~~~~~~~~~~~ Stack of asyncio_0 (6325039104) ~~~~~~~~~~~~~~~~~~~~~~~~\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1002, in _bootstrap\n self._bootstrap_inner()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 1045, in _bootstrap_inner\n self.run()\n File \"/opt/homebrew/Cellar/python@3.11/3.11.15_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py\", line 982, in run\n self._target(*self._args, **self._kwargs)\n File \"/opt/homebrew/Cellar/python@3.11/3.11.1\n\n... (输出被截断,总长度 318444 字节)\n[exit code: 1]", "name": "run_command", "tool_use_id": "call_dcf37264e0914b0785161a92", "tool_call_id": "call_dcf37264e0914b0785161a92"}, {"role": "assistant", "content": "输出太多了,我提取最后的汇总结果。\n\n", "tool_calls": [{"id": "call_f4a2c78e618148258f7c211d", "type": "function", "function": {"name": "run_command", "arguments": "{\"command\": \"./venv/bin/pytest tests/unit --timeout=10 --tb=no -q 2>&1 | tail -30\", \"timeout\": \"300\"}"}}]}, {"role": "tool", "content": "FAILED tests/unit/test_assistants.py::TestAssistants::test_list_assistant - r...\nFAILED tests/unit/test_assistants.py::TestAssistants::test_update_assistant\nFAILED tests/unit/test_assistants.py::TestAssistants::test_delete_assistant\nFAILED tests/unit/test_conversation.py::TestConversationRequest::test_message_request\nFAILED tests/unit/test_conversation.py::TestConversationRequest::test_conversation_with_history\nFAILED tests/unit/test_conversation.py::TestConversationRequest::test_conversation_with_message_and_prompt\nFAILED tests/unit/test_conversation.py::TestConversationRequest::test_conversation_with_messages\nFAILED tests/unit/test_conversation.py::TestConversationRequest::test_conversation_call_with_messages\nFAILED tests/unit/test_conversation.py::TestConversationRequest::test_not_qwen\nFAILED tests/unit/test_http_api.py::TestHttpRequest::test_independent_model_sync_stream_request\nFAILED tests/unit/test_http_fine_tunes_api.py::TestFineTuneRequest::test_create_fine_tune_job\nFAILED tests/unit/test_http_fine_tunes_api.py::TestFineTuneRequest::test_create_fine_tune_job_with_files\nFAILED tests/unit/test_http_fine_tunes_api.py::TestFineTuneRequest::test_list_fine_tune_job\nFAILED tests/unit/test_http_fine_tunes_api.py::TestFineTuneRequest::test_get_fine_tune_job\nFAILED tests/unit/test_http_fine_tunes_api.py::TestFineTuneRequest::test_delete_fine_tune_job\nFAILED tests/unit/test_http_fine_tunes_api.py::TestFineTuneRequest::test_cancel_fine_tune_job\nFAILED tests/unit/test_http_fine_tunes_api.py::TestFineTuneRequest::test_stream_event\nFAILED tests/unit/test_messages.py::TestMessages::test_update - KeyError: 'me...\nFAILED tests/unit/test_messages.py::TestMessages::test_retrieve - Failed: Tim...\nFAILED tests/unit/test_messages.py::TestMessages::test_list - Failed: Timeout...\nFAILED tests/unit/test_messages.py::TestMessages::test_list_message_files - F...\nFAILED tests/unit/test_messages.py::TestMessages::test_retrieve_message_file\nFAILED tests/unit/test_runs.py::TestRuns::test_retrieve - Failed: Timeout (>1...\nFAILED tests/unit/test_runs.py::TestRuns::test_list - Failed: Timeout (>10.0s...\nFAILED tests/unit/test_runs.py::TestRuns::test_submit_tool_outputs - Failed: ...\nFAILED tests/unit/test_runs.py::TestRuns::test_run_required_function_call - A...\nFAILED tests/unit/test_runs.py::TestRuns::test_list_run_steps - Failed: Timeo...\nFAILED tests/unit/test_runs.py::TestRuns::test_retrieve_run_steps - Failed: T...\nFAILED tests/unit/test_runs.py::TestRuns::test_cancel - Failed: Timeout (>10....\n44 failed, 283 passed, 6 skipped, 161 warnings in 267.14s (0:04:27)\n[exit code: 0]", "name": "run_command", "tool_use_id": "call_f4a2c78e618148258f7c211d", "tool_call_id": "call_f4a2c78e618148258f7c211d"}, {"role": "user", "content": "所以你是没跑成功吗"}] \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 359bb53..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# 默认忽略的文件 -/shelf/ -/workspace.xml diff --git a/.idea/dashscope-sdk-python-cli.iml b/.idea/dashscope-sdk-python-cli.iml deleted file mode 100644 index 3effa6c..0000000 --- a/.idea/dashscope-sdk-python-cli.iml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2d..0000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 0d8674f..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index ffd63ce..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file