Add comprehensive documentation for Claude Agent SDK including usage patterns, test examples, and development guide. Includes: - CLAUDE.md with project structure and quick reference - SDK test examples for query, client, and hooks - Shared test utilities for auth and tmpdir management - Detailed SDK overview and capabilities documentation
76 lines
2.5 KiB
Python
76 lines
2.5 KiB
Python
"""Shared helpers for Claude Agent SDK tests.
|
|
|
|
Loads ANTHROPIC_BASE_URL / ANTHROPIC_AUTH_TOKEN from the project root .env
|
|
and injects them into the process environment and ClaudeAgentOptions.env.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import shutil
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
|
DOTENV_PATH = PROJECT_ROOT / ".env"
|
|
|
|
|
|
def load_dotenv(dotenv_path: Path = DOTENV_PATH) -> dict[str, str]:
|
|
"""Parse KEY=VALUE lines from a .env file (no third-party deps)."""
|
|
values: dict[str, str] = {}
|
|
if not dotenv_path.exists():
|
|
return values
|
|
for raw_line in dotenv_path.read_text(encoding="utf-8").splitlines():
|
|
line = raw_line.strip()
|
|
if not line or line.startswith("#") or "=" not in line:
|
|
continue
|
|
key, value = line.split("=", 1)
|
|
values[key.strip()] = value.strip().strip('"').strip("'")
|
|
return values
|
|
|
|
|
|
def setup_auth() -> tuple[bool, str]:
|
|
"""Inject .env auth vars into os.environ; clear ANTHROPIC_API_KEY to avoid conflicts."""
|
|
values = load_dotenv()
|
|
base_url = values.get("ANTHROPIC_BASE_URL")
|
|
auth_token = values.get("ANTHROPIC_AUTH_TOKEN")
|
|
oauth_token = values.get("CLAUDE_CODE_OAUTH_TOKEN")
|
|
|
|
if not base_url:
|
|
return False, "Missing ANTHROPIC_BASE_URL in .env"
|
|
if not auth_token and not oauth_token:
|
|
return False, "Missing ANTHROPIC_AUTH_TOKEN or CLAUDE_CODE_OAUTH_TOKEN in .env"
|
|
|
|
os.environ["ANTHROPIC_BASE_URL"] = base_url
|
|
if auth_token:
|
|
os.environ["ANTHROPIC_AUTH_TOKEN"] = auth_token
|
|
if oauth_token:
|
|
os.environ["CLAUDE_CODE_OAUTH_TOKEN"] = oauth_token
|
|
os.environ.pop("ANTHROPIC_API_KEY", None)
|
|
return True, f"Auth loaded from {DOTENV_PATH}"
|
|
|
|
|
|
def auth_env() -> dict[str, str]:
|
|
"""Return env dict suitable for ClaudeAgentOptions(env=...)."""
|
|
return {
|
|
"ANTHROPIC_BASE_URL": os.environ["ANTHROPIC_BASE_URL"],
|
|
"ANTHROPIC_AUTH_TOKEN": os.environ.get("ANTHROPIC_AUTH_TOKEN", ""),
|
|
"CLAUDE_CODE_OAUTH_TOKEN": os.environ.get("CLAUDE_CODE_OAUTH_TOKEN", ""),
|
|
}
|
|
|
|
|
|
def make_tmpdir(prefix: str = "sdk-test-") -> Path:
|
|
"""Create a temporary directory manually (caller is responsible for cleanup)."""
|
|
return Path(tempfile.mkdtemp(prefix=prefix))
|
|
|
|
|
|
def remove_tmpdir(path: Path) -> None:
|
|
"""Remove a temporary directory, retrying once on Windows lock errors."""
|
|
try:
|
|
shutil.rmtree(path)
|
|
except OSError:
|
|
import time
|
|
time.sleep(1)
|
|
shutil.rmtree(path, ignore_errors=True)
|