Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/claude_code_sdk/_internal/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,21 @@ async def process_query(

finally:
await transport.disconnect()

async def process_query_raw(
self, prompt: str | AsyncIterable[dict[str, Any]], options: ClaudeCodeOptions
) -> AsyncIterator[dict[str, Any]]:
"""Process a query and return raw JSON data without parsing."""

transport = SubprocessCLITransport(
prompt=prompt, options=options, close_stdin_after_prompt=True
)

try:
await transport.connect()

async for data in transport.receive_messages():
yield data

finally:
await transport.disconnect()
12 changes: 8 additions & 4 deletions src/claude_code_sdk/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import os
from collections.abc import AsyncIterable, AsyncIterator
from typing import Any
from typing import Any, Union

from ._internal.client import InternalClient
from .types import ClaudeCodeOptions, Message
Expand All @@ -12,7 +12,7 @@ async def query(
*,
prompt: str | AsyncIterable[dict[str, Any]],
options: ClaudeCodeOptions | None = None,
) -> AsyncIterator[Message]:
) -> AsyncIterator[Union[Message, dict[str, Any]]]:
"""
Query Claude Code for one-shot or unidirectional streaming interactions.

Expand Down Expand Up @@ -98,5 +98,9 @@ async def prompts():

client = InternalClient()

async for message in client.process_query(prompt=prompt, options=options):
yield message
if options.return_raw_json:
async for raw_data in client.process_query_raw(prompt=prompt, options=options):
yield raw_data
else:
async for message in client.process_query(prompt=prompt, options=options):
yield message
1 change: 1 addition & 0 deletions src/claude_code_sdk/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,4 @@ class ClaudeCodeOptions:
extra_args: dict[str, str | None] = field(
default_factory=dict
) # Pass arbitrary CLI flags
return_raw_json: bool = False # Return raw JSON data instead of parsed messages
1 change: 1 addition & 0 deletions test_env/bin/python
1 change: 1 addition & 0 deletions test_env/bin/python3
1 change: 1 addition & 0 deletions test_env/bin/python3.12
1 change: 1 addition & 0 deletions test_env/lib64
5 changes: 5 additions & 0 deletions test_env/pyvenv.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
home = /usr/bin
include-system-site-packages = false
version = 3.12.3
executable = /usr/bin/python3.12
command = /usr/bin/python3 -m venv /root/repo/test_env
88 changes: 88 additions & 0 deletions test_raw_json.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/usr/bin/env python3
"""测试新功能的简单脚本"""

import asyncio
import sys
import os

# 添加src到Python路径
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))

from claude_code_sdk.query import query
from claude_code_sdk.types import ClaudeCodeOptions

async def test_raw_json_feature():
"""测试返回原始JSON的功能"""
print("测试返回原始JSON功能...")

# 创建选项,启用返回原始JSON
options = ClaudeCodeOptions(return_raw_json=True)

try:
# 执行查询
message_count = 0
async for message in query(prompt="你好,请简单回答", options=options):
message_count += 1
print(f"消息 {message_count}: {type(message)}")
if isinstance(message, dict):
print(f" - 原始JSON: {message}")
else:
print(f" - 解析后的消息: {message}")

# 限制消息数量以避免过长输出
if message_count >= 3:
break

print("✅ 原始JSON功能测试通过")

except Exception as e:
print(f"❌ 测试失败: {e}")
return False

return True

async def test_normal_mode():
"""测试正常模式(解析消息)"""
print("\n测试正常模式...")

# 创建选项,禁用返回原始JSON
options = ClaudeCodeOptions(return_raw_json=False)

try:
# 执行查询
message_count = 0
async for message in query(prompt="你好,请简单回答", options=options):
message_count += 1
print(f"消息 {message_count}: {type(message)}")
print(f" - 解析后的消息: {message}")

# 限制消息数量以避免过长输出
if message_count >= 3:
break

print("✅ 正常模式测试通过")

except Exception as e:
print(f"❌ 测试失败: {e}")
return False

return True

async def main():
"""主函数"""
print("开始测试新功能...")

# 测试原始JSON功能
raw_test_passed = await test_raw_json_feature()

# 测试正常模式
normal_test_passed = await test_normal_mode()

if raw_test_passed and normal_test_passed:
print("\n🎉 所有测试通过!")
else:
print("\n❌ 部分测试失败")
sys.exit(1)

if __name__ == "__main__":
asyncio.run(main())
84 changes: 84 additions & 0 deletions validate_code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#!/usr/bin/env python3
"""简单的代码验证脚本"""

import sys
import os

# 添加src到Python路径
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))

def test_import():
"""测试导入"""
try:
from claude_code_sdk.types import ClaudeCodeOptions
print("✅ 成功导入 ClaudeCodeOptions")

# 测试新的选项
options = ClaudeCodeOptions(return_raw_json=True)
print(f"✅ return_raw_json 选项: {options.return_raw_json}")

options2 = ClaudeCodeOptions(return_raw_json=False)
print(f"✅ return_raw_json 选项: {options2.return_raw_json}")

# 测试默认值
options3 = ClaudeCodeOptions()
print(f"✅ 默认 return_raw_json: {options3.return_raw_json}")

return True
except Exception as e:
print(f"❌ 导入失败: {e}")
return False

def test_types():
"""测试类型定义"""
try:
from claude_code_sdk.types import ClaudeCodeOptions
import inspect

# 检查类定义
sig = inspect.signature(ClaudeCodeOptions.__init__)
params = list(sig.parameters.keys())

if 'return_raw_json' in params:
print("✅ return_raw_json 参数已添加到 ClaudeCodeOptions")
else:
print("❌ return_raw_json 参数未找到")
return False

return True
except Exception as e:
print(f"❌ 类型测试失败: {e}")
return False

def main():
"""主函数"""
print("开始验证代码...")

# 测试导入
import_test = test_import()

# 测试类型
types_test = test_types()

if import_test and types_test:
print("\n🎉 代码验证通过!")
print("\n使用方法:")
print("```python")
print("from claude_code_sdk import query, ClaudeCodeOptions")
print("")
print("# 启用返回原始JSON")
print("options = ClaudeCodeOptions(return_raw_json=True)")
print("async for message in query(prompt='你好', options=options):")
print(" print(message) # 这将是原始的dict数据")
print("")
print("# 正常模式(默认)")
print("options = ClaudeCodeOptions(return_raw_json=False)")
print("async for message in query(prompt='你好', options=options):")
print(" print(message) # 这将是解析后的Message对象")
print("```")
else:
print("\n❌ 代码验证失败")
sys.exit(1)

if __name__ == "__main__":
main()
138 changes: 138 additions & 0 deletions validate_implementation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
#!/usr/bin/env python3
"""简单的语法和结构验证"""

import ast
import os

def validate_syntax(file_path):
"""验证Python文件的语法"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()

# 解析AST
tree = ast.parse(content)
print(f"✅ {file_path} 语法正确")
return True
except SyntaxError as e:
print(f"❌ {file_path} 语法错误: {e}")
return False
except Exception as e:
print(f"❌ {file_path} 验证失败: {e}")
return False

def check_return_raw_json_option(file_path):
"""检查是否添加了return_raw_json选项"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()

if 'return_raw_json' in content:
print(f"✅ {file_path} 包含 return_raw_json 选项")
return True
else:
print(f"❌ {file_path} 缺少 return_raw_json 选项")
return False
except Exception as e:
print(f"❌ 检查 {file_path} 失败: {e}")
return False

def check_query_function(file_path):
"""检查query函数的修改"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()

# 检查Union类型
if 'Union[Message, dict[str, Any]]' in content:
print(f"✅ {file_path} 包含正确的返回类型注解")
else:
print(f"❌ {file_path} 缺少正确的返回类型注解")
return False

# 检查条件逻辑
if 'if options.return_raw_json:' in content:
print(f"✅ {file_path} 包含条件逻辑")
else:
print(f"❌ {file_path} 缺少条件逻辑")
return False

return True
except Exception as e:
print(f"❌ 检查 {file_path} 失败: {e}")
return False

def check_client_methods(file_path):
"""检查client.py中的方法"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()

# 检查新方法
if 'process_query_raw' in content:
print(f"✅ {file_path} 包含 process_query_raw 方法")
else:
print(f"❌ {file_path} 缺少 process_query_raw 方法")
return False

return True
except Exception as e:
print(f"❌ 检查 {file_path} 失败: {e}")
return False

def main():
"""主函数"""
print("开始验证代码实现...")

files_to_check = [
'src/claude_code_sdk/types.py',
'src/claude_code_sdk/query.py',
'src/claude_code_sdk/_internal/client.py'
]

all_valid = True

# 验证语法
for file_path in files_to_check:
if not validate_syntax(file_path):
all_valid = False

# 检查具体实现
if not check_return_raw_json_option('src/claude_code_sdk/types.py'):
all_valid = False

if not check_query_function('src/claude_code_sdk/query.py'):
all_valid = False

if not check_client_methods('src/claude_code_sdk/_internal/client.py'):
all_valid = False

if all_valid:
print("\n🎉 代码实现验证通过!")
print("\n实现摘要:")
print("1. ✅ 在 ClaudeCodeOptions 中添加了 return_raw_json: bool = False")
print("2. ✅ 修改了 query() 函数返回类型为 Union[Message, dict[str, Any]]")
print("3. ✅ 添加了条件逻辑来决定返回原始JSON还是解析后的消息")
print("4. ✅ 在 InternalClient 中添加了 process_query_raw() 方法")
print("\n使用方法:")
print("```python")
print("from claude_code_sdk import query, ClaudeCodeOptions")
print("")
print("# 返回原始JSON")
print("options = ClaudeCodeOptions(return_raw_json=True)")
print("async for message in query(prompt='你好', options=options):")
print(" print(message) # dict[str, Any]")
print("")
print("# 返回解析后的消息(默认)")
print("options = ClaudeCodeOptions(return_raw_json=False)")
print("async for message in query(prompt='你好', options=options):")
print(" print(message) # Message")
print("```")
else:
print("\n❌ 代码实现验证失败")
return 1

return 0

if __name__ == "__main__":
exit(main())