From 03489fdc5885cb7030f3773c9e68be2316b74977 Mon Sep 17 00:00:00 2001 From: Un7corn Date: Sat, 21 Mar 2026 16:17:18 +0800 Subject: [PATCH 1/2] Create batch.py --- httpie/cli/batch.py | 115 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 httpie/cli/batch.py diff --git a/httpie/cli/batch.py b/httpie/cli/batch.py new file mode 100644 index 0000000000..bc842d12f0 --- /dev/null +++ b/httpie/cli/batch.py @@ -0,0 +1,115 @@ +import json +from pathlib import Path +from dataclasses import dataclass, asdict +from typing import Any, Dict, List, Optional + +try: + import yaml +except ImportError: + yaml = None + + +@dataclass +class BatchRequestItem: + name: str + method: str + url: str + headers: Optional[Dict[str, str]] = None + params: Optional[Dict[str, Any]] = None + json_body: Optional[Any] = None + data: Optional[Any] = None + auth: Optional[Dict[str, Any]] = None + group: Optional[str] = None + + +@dataclass +class BatchExecutionResult: + name: str + method: str + url: str + success: bool + status_code: Optional[int] = None + error: Optional[str] = None + response_text: Optional[str] = None + + +class BatchExecutor: + def __init__( + self, + template_file: str, + exec_mode: str = "all", + preview: bool = False, + output_dir: str = "batch_results", + output_format: str = "json", + verbose: bool = False, + ) -> None: + self.template_file = Path(template_file) + self.exec_mode = exec_mode + self.preview = preview + self.output_dir = Path(output_dir) + self.output_format = output_format + self.verbose = verbose + self.requests: List[BatchRequestItem] = [] + + def load_templates(self) -> List[BatchRequestItem]: + if not self.template_file.exists(): + raise FileNotFoundError(f"Template file not found: {self.template_file}") + + suffix = self.template_file.suffix.lower() + content = self.template_file.read_text(encoding="utf-8") + + if suffix in [".yaml", ".yml"]: + if yaml is None: + raise RuntimeError("PyYAML is required for YAML batch templates") + raw = yaml.safe_load(content) + elif suffix == ".json": + raw = json.loads(content) + else: + raise ValueError(f"Unsupported template format: {suffix}") + + items = raw.get("requests", raw if isinstance(raw, list) else []) + self.requests = [BatchRequestItem(**item) for item in items] + return self.requests + + def preview_requests(self) -> None: + print("Batch request preview:") + for idx, req in enumerate(self.requests, start=1): + print(f"{idx}. [{req.method}] {req.name} -> {req.url}") + + def select_requests(self) -> List[BatchRequestItem]: + if self.exec_mode == "all": + return self.requests + + if self.exec_mode == "interactive": + print("Interactive mode is not fully verified yet.") + selected = [] + for req in self.requests: + answer = input(f"Execute '{req.name}'? [y/N]: ").strip().lower() + if answer == "y": + selected.append(req) + return selected + + if self.exec_mode == "preview": + return [] + + raise ValueError(f"Unsupported exec mode: {self.exec_mode}") + + def execute_one(self, req: BatchRequestItem) -> BatchExecutionResult: + """ + 这里暂时只放占位逻辑。 + 真正集成时,应接 HTTPie 现有请求执行流程,而不是自己重复造轮子。 + """ + try: + # TODO: 替换为 HTTPie 核心请求执行调用 + if self.verbose: + print(f"Executing: [{req.method}] {req.url}") + + return BatchExecutionResult( + name=req.name, + method=req.method, + url=req.url, + success=False, + error="Execution path not integrated with HTTPie core yet", + ) + except Exception as exc: + return BatchExec From b37fe030b8cf15d92c7686141e50cf810d862aed Mon Sep 17 00:00:00 2001 From: Un7corn Date: Sat, 21 Mar 2026 16:18:22 +0800 Subject: [PATCH 2/2] Update definition.py --- httpie/cli/definition.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/httpie/cli/definition.py b/httpie/cli/definition.py index 843b29c9cf..091a718f2d 100644 --- a/httpie/cli/definition.py +++ b/httpie/cli/definition.py @@ -954,3 +954,40 @@ def format_auth_help(auth_plugins_mapping, *, isolation_mode: bool = False): options.finalize() parser = to_argparse(options) +# 建议新增的参数定义,具体风格需对齐项目原有写法 + +BATCH_OPTIONS = [ + { + "names": ["--batch", "-B"], + "help": "Path to batch request template file (YAML or JSON).", + "metavar": "FILE", + }, + { + "names": ["--batch-exec"], + "help": "Batch execution mode: all, interactive, preview.", + "choices": ["all", "interactive", "preview"], + "default": "all", + }, + { + "names": ["--batch-output"], + "help": "Directory to write batch execution results.", + "default": "batch_results", + "metavar": "DIR", + }, + { + "names": ["--batch-format"], + "help": "Batch result export format.", + "choices": ["json", "md"], + "default": "json", + }, + { + "names": ["--batch-verbose"], + "help": "Enable verbose output for batch execution.", + "action": "store_true", + }, + { + "names": ["--batch-preview"], + "help": "Preview batch requests without executing them.", + "action": "store_true", + }, +]