Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/alucard1123_needle.json
T

1 line
11 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "alucard1123/needle", "files": {"README.md": {"ca3a44228a3d3827df185177a6356a72617a52a8": {"t": 1785674104.961423, "n": 7928, "h": "901d033883c5aa31", "c": "# needle\n\n[![PyPI](https://img.shields.io/pypi/v/needle.svg)](https://pypi.org/project/needle-fixer/)\n[![Python](https://img.shields.io/pypi/pyversions/needle.svg)](https://pypi.org/project/needle-fixer/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Tests](https://img.shields.io/badge/tests-pytest-blue.svg)](./tests)\n\n> 自动化测试异常自愈(Self-Healing)库。\n>\n> 当 Playwright / Selenium / 任意自动化脚本抛出异常时,`needle` 会按「责任链」模式自动寻找并执行可用的修复策略,把原本会失败的用例救回来。\n\n```python\nfrom needle import ExceptionHandler\nfrom needle.builtin import register_builtins\n\nregister_builtins() # 注册内置修复策略(可选)\n\ntry:\n page.get_by_role(\"button\", name=\"SEARCH\").click(timeout=5000)\nexcept Exception as e:\n ExceptionHandler(page=page).handle_exception(e)\n # 修复成功:正常返回;全部失败:抛出 RepairFailedException\n```\n\n---\n\n## 目录\n\n- [needle](#needle)\n - [目录](#目录)\n - [特性](#特性)\n - [安装](#安装)\n - [快速开始](#快速开始)\n - [1. 模块级便捷函数](#1-模块级便捷函数)\n - [2. 类级入口](#2-类级入口)\n - [3. 装饰器模式](#3-装饰器模式)\n - [核心概念](#核心概念)\n - [内置修复策略](#内置修复策略)\n - [自定义修复策略](#自定义修复策略)\n - [注入自定义后端](#注入自定义后端)\n - [默认后端的实例化](#默认后端的实例化)\n - [自定义 AI 客户端(ByPromptSolution 必须)](#自定义-ai-客户端bypromptsolution-必须)\n - [内置 Kimi / Moonshot 客户端](#内置-kimi--moonshot-客户端)\n - [装饰器模式](#装饰器模式)\n - [开发与测试](#开发与测试)\n - [许可证](#许可证)\n - [关于作者](#关于作者)\n\n---\n\n## 特性\n\n- **核心零依赖**:`handler` / `registry` / 基类 / 异常 / 装饰器 仅使用 Python 标准库。\n- **责任链调度**:按 `PRIORITY` 自动排序,逐个尝试 `can_fix → fix`,单个策略失败不会打断后续策略。\n- **Playwright 原生友好**:自动解析 `Locator` 超时异常,提取原始 locator、操作名与调用参数,修复后可保持参数一致重试。\n- **多种内置策略**:缓存、图像模板匹配、AI 提示词、环境型超时处理,按需安装依赖。\n- **可插拔后端**:重依赖(OpenCV、LLM 客户端)通过协议注入,可替换为项目自有实现。\n- **易于扩展**:继承 `NeedleSolution` 实现 `can_fix` / `fix`,注册即用。\n\n---\n\n## 安装\n\n```bash\n# 仅安装核心(零依赖)\npip install needle-fixer\n\n# 图像策略(OpenCV 模板匹配)\npip install \"needle-fixer[image]\"\n\n# AI 策略(内置 Kimi / Moonshot 客户端)\npip install \"needle-fixer[ai]\"\n\n# Playwright 运行时(如项目尚未安装)\npip install \"needle-fixer[playwright]\"\n\n# 全部可选依赖\npip install \"needle-fixer[all]\"\n\n# 开发依赖\npip install \"needle-fixer[dev]\"\n```\n\n> **注意**:缓存策略基于 JSON 文件,零依赖,已包含在核心包中。\n\n---\n\n## 快速开始\n\n### 1. 模块级便捷函数\n\n```python\nfrom needle import handle_exception\nfrom needle.builtin import register_builtins\n\nregister_builtins()\n\ntry:\n page.get_by_role(\"button\", name=\"SEARCH\").click(timeout=5000)\nexcept Exception as e:\n handle_exception(e, page=page)\n```\n\n### 2. 类级入口\n\n```python\nfrom needle import ExceptionHandler\nfrom needle.builtin import register_builtins\n\nregister_builtins()\n\nhandler = ExceptionHandler(page=page)\ntry:\n page.get_by_label(\"Name\").fill(\"needle\")\nexcept Exception as e:\n handler.handle_exception(e)\n```\n\n### 3. 装饰器模式\n\n```python\nfrom needle import with_recovery\n\n@with_recovery(\n context_extractor=lambda page, locator, **kw: {\n \"page\": page,\n \"locator\": locator,\n **kw,\n }\n)\ndef click_element(page, locator):\n page.locator(locator).click()\n\nclick_element(page, \"#submit\")\n```\n\n---\n\n## 核心概念\n\n```\nExceptionHandler.handle_exception(e)\n └─ ContextBuilder.build(e) # 异常 → 修复上下文 dict(可替换)\n └─ RepairFailedException.attempt_recovery()\n └─ SolutionRegistry.create_chain(ctx) # 按 PRIORITY 组装责任链\n └─ NeedleSolution.handle(ctx) # 逐个 can_fix → fix\n```\n\n| 组件 | 职责 |\n|------|------|\n| `ExceptionHandler` | 统一入口,负责构建上下文并触发修复。 |\n| `ContextBuilder` | 把原始异常翻译成修复策略可消费的 `dict`。内置 `PlaywrightContextBuilder` 与 `DefaultContextBuilder`。 |\n| `SolutionRegistry` | 策略注册中心,维护优先级排序,负责建链。 |\n| `NeedleSolution` | 修复策略基类,子类实现 `can_fix` / `fix`。 |\n| `RepairFailedException` | 修复失败时抛出,通过 `__cause__` 保留原始异常。 |\n\n---\n\n## 内置修复策略\n\n| 策略 | 优先级 | 说明 | 依赖 |\n|------|--------|------|------|\n| `ByCacheSolution` | 10 | 从 JSON 缓存读取备选 locator 逐个尝试。 | 无 |\n| `ByImageSolution` | 20 | OpenCV 模板匹配,按坐标定位元素。 | `opencv-python`, `numpy`, `Pillow` |\n| `ByPromptSolution` | 30 | 调用 AI 分析 DOM,给出新 locator。 | `httpx` |\n| `TimeoutSolution` | 50 | 处理环境型超时(如页面出现 waiting 提示)。 | 无 |\n\n使用全部内置策略:\n\n```python\nfrom needle.builtin import register_builtins\n\nregister_builtins()\n```\n\n或单独注册:\n\n```python\nfrom needle.core.registry import SolutionRegistry\nfrom needle.builtin import ByCacheSolution, ByImageSolution\n\nSolutionRegistry.register(ByCacheSolution)\nSolutionRegistry.register(ByImageSolution)\n```\n\n---\n\n## 自定义修复策略\n\n只需继承 `NeedleSolution` 并实现 `can_fix` / `fix`,然后注册:\n\n```python\nfrom needle import NeedleSolution, register_solution\n\n@register_solution\nclass MyRetrySolution(NeedleSolution):\n PRIORITY = 5 # 数字越小越先尝试\n\n def can_fix(self) -> bool:\n return \"locator\" in self.context\n\n def fix(self) -> bool:\n page, locator = self.context[\"page\"], self.context[\"locator\"]\n page.locator(locator).click()\n self.context[\"fixed_element\"] = locator # 可选:记录修复结果\n return True\n```\n\n---\n\n## 注入自定义后端\n\n内置策略的重依赖通过协议注入,可用宿主项目自己的实现替换默认实现:\n\n```python\nfrom needle.builtin import ByCacheSolution, ByImageSolution, ByPromptSolution\n\nByCacheSolution.configure(my_cache_backend) # CacheBackend\nByImageSolution.configure(my_image_matcher) # ImageMatcher\nByPromptSolution.configure(my_ai_client) # AIClient\n```\n\n### 默认后端的实例化\n\n```python\nfrom needle.builtin import (\n ByCacheSolution,\n ByImageSolution,\n ByPromptSolution,\n PickleDBCacheBackend,\n OpenCVImageMatcher,\n)\n\n# 1. 缓存后端:JSON 文件,key 为原 locator,value 为备选 locator 列表\nmy_cache_backend = PickleDBCacheBackend(db_path=\"needle_locator_cache.db\")\nByCacheSolution.configure(my_cache_backend)\n\n# 2. 图像匹配后端:OpenCV 模板匹配\nmy_image_matcher = OpenCVImageMatcher(\n image_dir=\"image_locator\", # 模板图片目录\n threshold=0.8, # 匹配阈值,范围 0~1\n)\nByImageSolution.configure(my_image_matcher)\n```\n\n### 自定义 AI 客户端(ByPromptSolution 必须)\n\n`needle` 没有内置通用 LLM 客户端,需要你自己实现 `AIClient` 协议:\n\n```python\nfrom typing import Optional\n\nclass MyAIClient:\n def analyze(self, html: str, description: str) -> Optional[str]:\n \"\"\"根据页面 HTML 和描述返回一个可用的 Playwright locator 表达式。\n\n 返回 None 表示无法给出建议;返回的字符串会被写入 context[\"fixed_element\"]。\n \"\"\"\n prompt = (\n f\"根据以下页面 HTML,给出一个能定位到「{description}」的 \"\n f\"Playwright locator 表达式。只返回表达式本身,不要任何解释。\\n\\n\"\n f\"{html[:8000]}\"\n )\n # 这里接入你实际使用的 LLM(OpenAI / Kimi / Claude / 自部署模型等)\n # response = call_your_llm(prompt)\n # return response.strip()\n raise NotImplementedError(\"请接入实际的 LLM API\")\n\n\nmy_ai_client = MyAIClient(api_key=\"sk-xxx\")\nByPromptSolution.configure(my_ai_client)\n```\n\n### 内置 Kimi / Moonshot 客户端\n\n`needle` 内置了一个基于 Moonshot AI(Kimi)的 `AIClient` 实现,安装 `ai` 依赖后即可使用:\n\n```bash\npip install \"needle[ai]\"\n```\n\n```python\nfrom needle.builtin import ByPromptSolution, KimiClient\n\nmy_ai_client = KimiClient(\n api_key=\"sk-xxxxxxxxxxxxxxxx\", # Moonshot API Key\n model=\"moonshot-v1-8k\", # 可选:moonshot-v1-32k / moonshot-v1-128k\n base_url=\"https://api.moonshot.cn/v1\",\n temperature=0.1,\n max_tokens=512,\n)\nByPromptSolution.configure(my_ai_client)\n```\n\n> **注意**:`ByPromptSolution` 在未配置 `AIClient` 时会直接跳过,因此如果只使用缓存/图像策略,可以不实现 AI 客户端。\n\n---\n\n## 装饰器模式\n\n`with_recovery` 可以把自动修复能力注入到任意函数:\n\n```python\nfrom needle import with_recovery\n\n@with_recovery(\n context_extractor=lambda page, locator, **kw: {\n \"page\": page,\n \"locator\": locator,\n **kw,\n }\n)\ndef click_element(page, locator):\n page.locator(locator).click()\n```\n\n- `context_extractor`:从被装饰函数参数中提取修复上下文,返回 `dict`。\n- `reraise_on_failure`:修复失败时是否重新抛出 `RepairFailedException`(默认 `True`)。\n\n---\n\n## 开发与测试\n\n```bash\n# 克隆仓库\ngit clone https://github.com/alucard1123/needle\ncd needle\n\n# 创建虚拟环境并安装开发依赖\npython -m venv .venv\nsource .venv/bin/activate\npip install -e \".[dev]\"\n\n# 运行测试\npytest\n\n# 运行测试并生成覆盖率报告\npytest --cov=needle --cov-report=term-missing\n```\n\n---\n\n## 许可证\n\n[MIT](./LICENSE)\n\n## 关于作者\n公众号: 中年老吴\n\n<img src=\"./gongzhonghaoQR.png\" width=\"300\" height=\"300\" alt=\"公众号二维码\">\n\n赏老吴杯咖啡:\n\n<img src=\"./payQR.JPG\" width=\"300\" height=\"400\" alt=\"赏老吴杯咖啡\">\n\n找老吴私聊:\n\n<img src=\"./weixinQR.JPG\" width=\"300\" height=\"400\" alt=\"找老吴私聊\">\n"}}}}