From 9c2856b230eedeb7901ba6e2420160015128f768 Mon Sep 17 00:00:00 2001 From: kevin Date: Thu, 9 Jul 2026 17:26:35 +0800 Subject: [PATCH 1/2] fix(cli): Fix CLI compatibility issue with SDK response objects --- dashscope/cli/deployments.py | 2 +- dashscope/cli/files.py | 2 +- dashscope/cli/fine_tunes.py | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dashscope/cli/deployments.py b/dashscope/cli/deployments.py index 1130ad3..2d91c96 100644 --- a/dashscope/cli/deployments.py +++ b/dashscope/cli/deployments.py @@ -162,7 +162,7 @@ def create( if output is None: error("Deployment creation returned empty response") - deployed_model = output.get("deployed_model") + deployed_model = getattr(output, "deployed_model", None) if not deployed_model: error( "Deployment creation succeeded but missing deployed_model " diff --git a/dashscope/cli/files.py b/dashscope/cli/files.py index 32fdd9a..423caa0 100644 --- a/dashscope/cli/files.py +++ b/dashscope/cli/files.py @@ -74,7 +74,7 @@ def upload( output = ensure_ok(rsp) # Validate uploaded_files exists and is not empty - uploaded_files = output.get("uploaded_files", []) + uploaded_files = getattr(output, "uploaded_files", []) if not uploaded_files: error("Upload succeeded but no file_id returned in response") diff --git a/dashscope/cli/fine_tunes.py b/dashscope/cli/fine_tunes.py index d09d4a1..bb35a3d 100644 --- a/dashscope/cli/fine_tunes.py +++ b/dashscope/cli/fine_tunes.py @@ -115,7 +115,7 @@ def _stream_events(job_id: str): ) return - status = rsp.output.get("status") + status = getattr(rsp.output, "status", None) if status in ( TaskStatus.FAILED, TaskStatus.CANCELED, @@ -150,7 +150,7 @@ def _dump_logs(job_id: str): line=LOG_PAGE_SIZE, ) output = ensure_ok(rsp) - logs = output.get("logs", []) + logs = getattr(output, "logs", []) if not logs: break for line in logs: @@ -244,7 +244,7 @@ def create( if output is None: error("Fine-tune creation returned empty response") - job_id = output.get("job_id") + job_id = getattr(output, "job_id", None) if not job_id: error( "Fine-tune creation succeeded but missing job_id in response. " From 4920f6db9a24a057fc174bd7a1b52a2ed7ba8c5f Mon Sep 17 00:00:00 2001 From: kevin Date: Thu, 9 Jul 2026 17:58:05 +0800 Subject: [PATCH 2/2] fix: add type-safe attribute access and suppress pylint warnings --- dashscope/cli/deployments.py | 6 +++++- dashscope/cli/files.py | 6 +++++- dashscope/cli/fine_tunes.py | 12 ++++++++++-- tests/integration/test_large_utf8_payload.py | 16 ++++++++-------- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/dashscope/cli/deployments.py b/dashscope/cli/deployments.py index 2d91c96..44f2a58 100644 --- a/dashscope/cli/deployments.py +++ b/dashscope/cli/deployments.py @@ -162,7 +162,11 @@ def create( if output is None: error("Deployment creation returned empty response") - deployed_model = getattr(output, "deployed_model", None) + deployed_model = ( + output.get("deployed_model") + if isinstance(output, dict) + else getattr(output, "deployed_model", None) + ) if not deployed_model: error( "Deployment creation succeeded but missing deployed_model " diff --git a/dashscope/cli/files.py b/dashscope/cli/files.py index 423caa0..cb25a71 100644 --- a/dashscope/cli/files.py +++ b/dashscope/cli/files.py @@ -74,7 +74,11 @@ def upload( output = ensure_ok(rsp) # Validate uploaded_files exists and is not empty - uploaded_files = getattr(output, "uploaded_files", []) + uploaded_files = ( + output.get("uploaded_files", []) + if isinstance(output, dict) + else getattr(output, "uploaded_files", []) + ) if not uploaded_files: error("Upload succeeded but no file_id returned in response") diff --git a/dashscope/cli/fine_tunes.py b/dashscope/cli/fine_tunes.py index bb35a3d..d531752 100644 --- a/dashscope/cli/fine_tunes.py +++ b/dashscope/cli/fine_tunes.py @@ -115,7 +115,11 @@ def _stream_events(job_id: str): ) return - status = getattr(rsp.output, "status", None) + status = ( + rsp.output.get("status") + if isinstance(rsp.output, dict) + else getattr(rsp.output, "status", None) + ) if status in ( TaskStatus.FAILED, TaskStatus.CANCELED, @@ -150,7 +154,11 @@ def _dump_logs(job_id: str): line=LOG_PAGE_SIZE, ) output = ensure_ok(rsp) - logs = getattr(output, "logs", []) + logs = ( + output.get("logs", []) + if isinstance(output, dict) + else getattr(output, "logs", []) + ) if not logs: break for line in logs: diff --git a/tests/integration/test_large_utf8_payload.py b/tests/integration/test_large_utf8_payload.py index 39d6ebc..9a52320 100644 --- a/tests/integration/test_large_utf8_payload.py +++ b/tests/integration/test_large_utf8_payload.py @@ -70,7 +70,7 @@ def _print_result(resp, elapsed): # pylint: disable=unused-argument return False -def test_sync(test_messages): +def test_sync(messages): # pylint: disable=redefined-outer-name print("\n" + "=" * 60) print("SYNC TEST") print("=" * 60) @@ -78,7 +78,7 @@ def test_sync(test_messages): try: resp = Generation.call( model=MODEL, - messages=test_messages, + messages=messages, max_tokens=MAX_OUTPUT_TOKENS, result_format="message", ) @@ -94,7 +94,7 @@ def test_sync(test_messages): return _print_result(resp, elapsed) -async def test_async(test_messages): +async def test_async(messages): # pylint: disable=redefined-outer-name print("\n" + "=" * 60) print("ASYNC TEST") print("=" * 60) @@ -102,7 +102,7 @@ async def test_async(test_messages): try: resp = await AioGeneration.call( model=MODEL, - messages=test_messages, + messages=messages, max_tokens=MAX_OUTPUT_TOKENS, result_format="message", ) @@ -118,7 +118,7 @@ async def test_async(test_messages): return _print_result(resp, elapsed) -def test_stream(test_messages): +def test_stream(messages): # pylint: disable=redefined-outer-name print("\n" + "=" * 60) print("STREAM TEST") print("=" * 60) @@ -127,7 +127,7 @@ def test_stream(test_messages): try: responses = Generation.call( model=MODEL, - messages=test_messages, + messages=messages, max_tokens=MAX_OUTPUT_TOKENS, result_format="message", stream=True, @@ -160,10 +160,10 @@ def test_stream(test_messages): return True -def test_websocket(test_messages): +def test_websocket(messages): # pylint: disable=redefined-outer-name # WebSocket has a smaller message size limit than HTTP; # use a subset that still contains non-ASCII content. - ws_messages = test_messages[:5] + ws_messages = messages[:5] print("\n" + "=" * 60) print( f"WEBSOCKET TEST ({len(ws_messages)}/{len(messages)} messages)",