diff --git a/README.md b/README.md index 65e48f2bc..75846c437 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ The main branch includes all four tracks below. Each track provides a runnable e | --- | --- | --- | --- | | Web Fetch | Retrieve the requested page content, records, resources or files | [LexBench Web Fetch](https://github.com/lexmount/lexbench-webfetch), [WebMainBench](https://github.com/opendatalab/WebMainBench), [WCXB](https://github.com/Murrough-Foley/web-content-extraction-benchmark) | [Local example](examples/web_fetch/README.md) · [Full guide](harness/web_fetch/README.md) | | Web Search (preview) | Compare search results, relevance, source retrieval, latency and billing | [LexBench Web Search](https://github.com/lexmount/lexbench-websearch): scenario queries and a SimpleQA Verified retrieval adaptation | [Local example](examples/web_search/README.md) · [Full guide](harness/web_search/README.md) | -| Browser Trajectory Replay | Complete the same recorded browser actions across implementations | [Repository-curated fixed-action suite](examples/trajectory_replay/tasks.v4.json), adapted from [Lexbench-Headless-Browser scenario designs](https://github.com/lexmount/Lexbench-Headless-Browser/tree/3f1580a20922fc3f339b5fc279d9bbdb06d5d194/tasks/scenarios); [qualified WebArena human recordings](evaluation/browser-use-public/webarena-human-suite.json), checked with the [WebArena-Verified evaluator](https://github.com/lexmount/webarena-verified/tree/lex-main) | [Curated suite](examples/trajectory_replay/README.md) · [WebArena replay](examples/trajectory_replay/public_webarena/README.md) | +| Browser Trajectory Replay | Complete the same recorded browser actions across implementations | [Repository-curated fixed-action suite](examples/trajectory_replay/README.md), adapted from [Lexbench-Headless-Browser scenario designs](https://github.com/lexmount/Lexbench-Headless-Browser/tree/3f1580a20922fc3f339b5fc279d9bbdb06d5d194/tasks/scenarios); [qualified WebArena human recordings](evaluation/browser-use-public/webarena-human-suite.json), checked with the [WebArena-Verified evaluator](https://github.com/lexmount/webarena-verified/tree/lex-main) | [Curated suite](examples/trajectory_replay/README.md) · [WebArena replay](examples/trajectory_replay/public_webarena/README.md) | | Browser Use | Let an Agent use different browsers to complete tasks | [WebArena-Verified](https://github.com/ServiceNow/webarena-verified), using the [pinned evaluator fork](https://github.com/lexmount/webarena-verified/tree/lex-main) and [declared task selection](evaluation/browser-use/webarena-verified-pilot.json) | [CowAgent + WebArena](examples/browser_use/README.md) | Web Fetch supports local browsers, hosted services and extraction tools. See [adapters](docs/provider-contract.md) for available methods and [dependencies](docs/dependencies.md) for installation requirements. Replay and Browser Use have separate runners and environments. @@ -63,9 +63,7 @@ To share a report online, publish its `report/` directory through [Artifact Site ## Versions -The current package version is `0.2.0`. Software tags use `vMAJOR.MINOR.PATCH`; benchmark editions and hosted report versions are independent. A report records all three identities so rebuilding a report does not relabel its tasks or saved calls. - -Use [the release guide](docs/releases.md) for compatibility rules, release checks and the scope of the first software release. Web Search is available as a preview; stable support is assessed through the release checks. A stable release commits to documented commands, input contracts and saved-evidence compatibility; it does not guarantee that every browser or live website passes every task. +Published versions, changes and dependency snapshots are listed in [GitHub Releases](https://github.com/lexmount/browser-eval/releases). See [version rules](docs/releases.md) for release policy and report provenance. ## Related repositories diff --git a/docs/README.zh-CN.md b/docs/README.zh-CN.md index 58a37bcf0..a72474c7d 100644 --- a/docs/README.zh-CN.md +++ b/docs/README.zh-CN.md @@ -22,7 +22,7 @@ Browser Eval 是面向浏览器和 Web Agent 的评测脚手架(evaluation har | --- | --- | --- | --- | | Web Fetch | 获取任务要求的网页正文、记录、资源或文件 | [LexBench Web Fetch](https://github.com/lexmount/lexbench-webfetch)、[WebMainBench](https://github.com/opendatalab/WebMainBench)、[WCXB](https://github.com/Murrough-Foley/web-content-extraction-benchmark) | [本地示例](../examples/web_fetch/README.md) · [完整指南](../harness/web_fetch/README.md) | | Web Search(预览) | 比较搜索结果、相关性、来源检索、延迟与计费 | [LexBench Web Search](https://github.com/lexmount/lexbench-websearch):场景问题,以及用于检索评测的 SimpleQA Verified 改编任务 | [本地示例](../examples/web_search/README.md) · [完整指南](../harness/web_search/README.md) | -| 轨迹重放 | 比较不同浏览器能否完成同一组录制动作 | [仓库自建固定动作任务集](../examples/trajectory_replay/tasks.v4.json),改编自 [Lexbench-Headless-Browser 场景设计](https://github.com/lexmount/Lexbench-Headless-Browser/tree/3f1580a20922fc3f339b5fc279d9bbdb06d5d194/tasks/scenarios);[经过资格验证的 WebArena 人工录制轨迹](../evaluation/browser-use-public/webarena-human-suite.json),由 [WebArena-Verified 评测器](https://github.com/lexmount/webarena-verified/tree/lex-main)验收 | [自建任务集](../examples/trajectory_replay/README.md) · [WebArena 重放](../examples/trajectory_replay/public_webarena/README.md) | +| 轨迹重放 | 比较不同浏览器能否完成同一组录制动作 | [仓库自建固定动作任务集](../examples/trajectory_replay/README.md),改编自 [Lexbench-Headless-Browser 场景设计](https://github.com/lexmount/Lexbench-Headless-Browser/tree/3f1580a20922fc3f339b5fc279d9bbdb06d5d194/tasks/scenarios);[经过资格验证的 WebArena 人工录制轨迹](../evaluation/browser-use-public/webarena-human-suite.json),由 [WebArena-Verified 评测器](https://github.com/lexmount/webarena-verified/tree/lex-main)验收 | [自建任务集](../examples/trajectory_replay/README.md) · [WebArena 重放](../examples/trajectory_replay/public_webarena/README.md) | | Browser Use | 让 Agent 使用不同浏览器完成任务 | [WebArena-Verified](https://github.com/ServiceNow/webarena-verified),使用[固定版本的评测器分支](https://github.com/lexmount/webarena-verified/tree/lex-main)和[明确选定的任务](../evaluation/browser-use/webarena-verified-pilot.json) | [CowAgent + WebArena](../examples/browser_use/README.md) | Web Fetch 支持本地浏览器、在线服务和提取工具。可用方法见[适配器说明](../docs/provider-contract.md),安装要求见[依赖说明](../docs/dependencies.md)。轨迹重放和 Browser Use 各有自己的运行入口与环境。 @@ -63,9 +63,7 @@ uv run --frozen browser-harness-eval report /absolute/path/to/run ## 版本 -当前软件包版本是 `0.2.0`。软件标签采用 `v主版本.次版本.补丁版本`,评测集和托管报告各有独立版本。报告记录这三种身份,因此重建报告不会改换题目版本或保存的调用。 - -兼容规则、发布检查和首个软件发行版的范围见[发布指南](../docs/releases.md)。Web Search 已提供预览功能,稳定版支持范围由发布检查确认。稳定版承诺的是文档中的命令、输入约定和历史证据兼容性;浏览器与在线网站的逐题表现仍由评测结果说明。 +已发布版本、变更和依赖见[发布记录](https://github.com/lexmount/browser-eval/releases)。升版规则与报告版本绑定见[版本说明](releases.md)。 ## 相关仓库 diff --git a/docs/benchmarks.md b/docs/benchmarks.md index d51044d02..0cc509f75 100644 --- a/docs/benchmarks.md +++ b/docs/benchmarks.md @@ -48,11 +48,11 @@ This uses the existing dataset interface. `uv sync --frozen` installs LexBench f The four initial LexBench suites preserve the original catalogs and source-input manifests. [The import binding](../evaluation/lexbench-webfetch.json) records the benchmark revision and exact hashes. The original catalogs, manifests and task-authoring contracts live only in LexBench, with their frozen bytes and relative paths preserved. Browser Eval resolves historical logical input paths through the installed package. Its experiment profiles and certificates retain their original bindings. -Change task requirements in LexBench, freeze a new dataset/catalog/manifest version there, and select that version in a new experiment profile. Fix execution defects in Browser Eval and scoring defects in LexBench; keep accepted/rejected scenario controls with their owner. Preserve prior measurements and apply corrections across the declared affected scope. +Change task requirements in LexBench, release the updated benchmark there, and select that version in a new experiment profile. Fix execution defects in Browser Eval and scoring defects in LexBench; keep accepted/rejected scenario controls with their owner. Preserve prior measurements and apply corrections across the declared affected scope. The retained `harness/lexbench/` module concerns historical headless-browser comparisons. It is unrelated to the `lexbench-webfetch` input package and remains an execution/report adapter. -The curated [Browser Trajectory Replay suite](../examples/trajectory_replay/tasks.v4.json) records [Lexbench-Headless-Browser scenario designs](https://github.com/lexmount/Lexbench-Headless-Browser/tree/3f1580a20922fc3f339b5fc279d9bbdb06d5d194/tasks/scenarios) in each applicable task's `source.design_basis`. It adapts those capabilities to public-page actions with its own exact expected outputs. This suite does not execute the complete upstream task population. The [public WebArena replay](../examples/trajectory_replay/public_webarena/README.md) instead uses qualified human recordings and the WebArena-Verified evaluator. +The curated [Browser Trajectory Replay suite](../examples/trajectory_replay/README.md) records [Lexbench-Headless-Browser scenario designs](https://github.com/lexmount/Lexbench-Headless-Browser/tree/3f1580a20922fc3f339b5fc279d9bbdb06d5d194/tasks/scenarios) in each applicable task's `source.design_basis`. It adapts those capabilities to public-page actions with its own exact expected outputs. This suite does not execute the complete upstream task population. The [public WebArena replay](../examples/trajectory_replay/public_webarena/README.md) instead uses qualified human recordings and the WebArena-Verified evaluator. ## Benchmark editions @@ -270,7 +270,7 @@ or renaming a participant requires data changes, without another renderer entry. LexBench Web Search is installed from the immutable commit in `pyproject.toml` and `uv.lock`. Its task files and scoring code have one owner in that repository. Browser Eval provides providers, model/human annotation collection, latency/billing collection, audits and report publication. Report-specific execution profiles and receipts live with external evidence, selected explicitly by the caller. No sibling checkout is required. -`uv run --frozen lexbench-websearch validate scenarios-v1` checks the installed definitions. The harness resolves explicit dataset/field/hash references before freezing a run. Resolving the split historical profiles reproduces the original profile bytes and hashes, so saved calls keep their original identity. Model judgment evidence and measured results stay outside both repositories. +The pinned benchmark's `version` command checks its catalog and scoring state. Select task suites through the installed registry's `current` mapping; the bench edition fixes their snapshots. The harness resolves explicit dataset/field/hash references before freezing a run. Resolving the split historical profiles reproduces the original profile bytes and hashes, so saved calls keep their original identity. Model judgment evidence and measured results stay outside both repositories. Change search queries, references or scoring in LexBench Web Search and pin the resulting commit here. Change provider behavior or report generation in Browser Eval. See the pinned benchmark's [data provenance](https://github.com/lexmount/lexbench-websearch/blob/a6d7b92987e32ef52563ee68bac4343db5686d95/docs/data.md) and [evaluation protocol](https://github.com/lexmount/lexbench-websearch/blob/a6d7b92987e32ef52563ee68bac4343db5686d95/docs/evaluation.md). diff --git a/docs/releases.md b/docs/releases.md index 16b04138b..d5ad10852 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -1,6 +1,6 @@ # Software releases -Browser Eval versions the execution and reporting software. The current package version is `0.3.0`; a version in source is not a published GitHub release. Software tags use `vMAJOR.MINOR.PATCH` and identify one tested commit. +Browser Eval versions the execution and reporting software. Software tags use `vMAJOR.MINOR.PATCH` and identify one tested commit. ## Version rules @@ -37,28 +37,60 @@ Web Fetch, Web Search / SERP, Browser Trajectory Replay and Browser Use have mai ## Release procedure 1. Select a clean commit on main and declare supported tracks, benchmark pins and migrations. Check that pending work is not described as included. -2. Align `pyproject.toml`, `harness/web_fetch/__init__.py` and `uv.lock`. Project citations stay version-neutral. Run `uv lock` when package metadata changes, retaining immutable dependency pins. The metadata tests check the lock, installed package, runtime version and bilingual citations. +2. Set the release version in `pyproject.toml` and refresh `uv.lock`. Runtime code reads installed package metadata automatically. Project citations stay version-neutral. Run `uv lock` when package metadata changes, retaining immutable dependency pins. The metadata tests check the lock, installed package, runtime version and bilingual citations. 3. Run `make setup-test` and `make ci` on that commit. The package gate checks installation outside the checkout. Follow each track's separate release gate when publishing benchmark reports; a software tag does not certify their measurements. 4. Prepare release notes with supported tracks and suites, installation commands, compatible interfaces, required external inputs and migrations. Check that the source archive and wheel contain the declared version. 5. After release approval, publish an annotated `vMAJOR.MINOR.PATCH` tag and GitHub release for that exact commit. Never move a published tag. Upload software distribution files; keep provider outputs and private report evidence outside the software release. Use a feature branch and PR for release preparation. Merging and publishing are separate maintainer actions. Record the exact commit in bug reports and experiment methods, including for unreleased branches. -## Release history and the next checkpoint +## Released versions -| Version | Scope | Source | +Each GitHub release is the version's changelog: why it was published, the +changes since its predecessor, exact source and benchmark pins, validation, +installation and comparison implications. The release page owns these details; +this table is the index. + +| Software release | Why it was published | LexBench dependencies | | --- | --- | --- | -| `0.1.0` | Original software checkpoint | `03c9a5e94619000480c92b8e517c16165dc2a7f4` | -| `0.2.0` | Shared report-build identity and reusable Web Fetch reports | `30645af1ba2520b4d089cbef32979e088cffe277` | -| `0.3.0` | Web Search integration, shared capture fixes and release metadata checks | This release preparation; tag the merged commit after validation | - -The first two versions were previously tagged. Restore deleted tags to their -original Git objects; never reuse their names for newer code. Restoration does -not rerun an experiment or alter its results. Use `0.3.1` for a compatible fix -after this release, `0.4.0` for another feature release or a breaking change -while developing, and `1.0.0` when the documented interfaces are ready for a -long-term compatibility promise. A stable Web Fetch workflow alone does not -make every track a stable API. +| [0.1.0](https://github.com/lexmount/browser-eval/releases/tag/v0.1.0) | Preserve the original installable Web Fetch, Replay and Browser Use checkpoint | Fetch scoring in this repository; no separate LexBench package | +| [0.2.0](https://github.com/lexmount/browser-eval/releases/tag/v0.2.0) | Extracted Fetch dependency and shared report-build identity | Fetch benchmark 2.0.1; no Search integration | +| [0.3.0](https://github.com/lexmount/browser-eval/releases/tag/v0.3.0) | Add Search/SERP and shared capture/source-validation fixes | Fetch benchmark 2.0.1; Search benchmark 1.0.0 | + +Historical 0.1.0 and 0.2.0 tags retain their original commits. A software release +can support several separately selected benchmarks; its version never chooses +a report's population or changes saved results. + +## Benchmark release index + +| Benchmark release | Scope and reason | +| --- | --- | +| [Fetch 1.0.0](https://github.com/lexmount/lexbench-webfetch/releases/tag/bench-v1.0.0) | Preserve the historical 430-task report contract and scorer | +| [Fetch 2.0.1](https://github.com/lexmount/lexbench-webfetch/releases/tag/bench-v2.0.1) | Expanded 550-entry catalog with complete compatibility fingerprints; separate population from 1.x | +| [Search 1.0.0](https://github.com/lexmount/lexbench-websearch/releases/tag/bench-v1.0.0) | First frozen Search catalog: scenario and factual task suites | +| [Search 1.1.0](https://github.com/lexmount/lexbench-websearch/releases/tag/bench-v1.1.0) | Correct numeric scoring and bind the catalog to its actual scorer; rescore saved cohorts before comparing | + +A benchmark release uses one tag for its tasks, reference answers, scoring rules +and evaluation code. Task suites use stable names rather than separate dataset +release numbers. Data unchanged with updated tooling can still warrant a bench +release: use a patch when measurement is unchanged, a minor for scoring +corrections, and a major for changed task scope. Python requires package version metadata for installation; this is +internal packaging information, not a separate public release line. + +## Version source and release cadence + +`pyproject.toml` is the software version source. Runtime `__version__` reads the +installed distribution metadata; do not duplicate its number in Python modules +or README files. `uv.lock` records the resolved package metadata. The software +tag must equal the package version at a formal release; commits between releases +retain their exact revision and source hashes without creating new tags. + +Release after a coherent set of changes is ready for users, or when a fix needs +an installable release. Do not release for each PR, dependency synchronization, +README edit or version-label correction. A benchmark edition changes only when +its measurement contract is deliberately released. Use GitHub Releases for +published versions and their dependency snapshots, rather than a changing +current-version paragraph in the README. ## Citations and experiment identity diff --git a/evaluation/lexbench-websearch.json b/evaluation/lexbench-websearch.json index dda6998b1..d30277234 100644 --- a/evaluation/lexbench-websearch.json +++ b/evaluation/lexbench-websearch.json @@ -2,7 +2,7 @@ "schema_version": 1, "kind": "external_benchmark_binding", "repository": "https://github.com/lexmount/lexbench-websearch", - "revision": "d312653cbdc0396ffefa49ced37f82f7ca764da2", + "revision": "f07a2e2ddf1c1c511cb3944659534301c86ff9c9", "datasets": { "scenarios-v1": { "path": "datasets/scenarios-v1.json", @@ -22,6 +22,6 @@ }, "definition_files": { "registry.json": "4b1a17f5a5b19c423aa450c9ce8dac97fb1cf32ce6df56c20e68058126debd8d", - "benchmark-release.json": "47fd3d011cdb486bc1257c55f8eb4ecf3c86f32f20052937854f1c818ad5a3b6" + "benchmark-release.json": "0d9d84ef66d1eab3c4907c639ba2174b769f430fbf8efd8b2cf924671081cf63" } } diff --git a/harness/web_fetch/__init__.py b/harness/web_fetch/__init__.py index 23c0218a5..43466db99 100644 --- a/harness/web_fetch/__init__.py +++ b/harness/web_fetch/__init__.py @@ -1,3 +1,5 @@ """Browser harness evaluation toolkit.""" -__version__ = "0.3.0" +from importlib.metadata import version as _installed_version + +__version__ = _installed_version("browser-harness-eval") diff --git a/pyproject.toml b/pyproject.toml index 7aff1c9a0..fadff409c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ license-files = ["LICENSE", "NOTICE", "THIRD_PARTY.md"] requires-python = ">=3.11" dependencies = [ "lexbench-webfetch @ git+https://github.com/lexmount/lexbench-webfetch.git@d0e78e71cf5145217cb1f2b71420a7c4194d80dd", - "lexbench-websearch @ git+https://github.com/lexmount/lexbench-websearch.git@d312653cbdc0396ffefa49ced37f82f7ca764da2", + "lexbench-websearch @ git+https://github.com/lexmount/lexbench-websearch.git@f07a2e2ddf1c1c511cb3944659534301c86ff9c9", "beautifulsoup4>=4.12,<5", "fastcdc==1.7.0", "python-dotenv==1.1.1", diff --git a/tests/test_lexbench_dependency_update.py b/tests/test_lexbench_dependency_update.py index b43b73c1c..3a78e0a01 100644 --- a/tests/test_lexbench_dependency_update.py +++ b/tests/test_lexbench_dependency_update.py @@ -36,16 +36,18 @@ def test_search_dependency_binds_project_lock_and_installed_datasets(tmp_path): assert len(revision) == 40 -@pytest.mark.parametrize("name", ["pyproject.toml", "uv.lock", "evaluation/lexbench-webfetch.json"]) -def test_mismatched_revision_rejected(tmp_path, name): +@pytest.mark.parametrize("benchmark", ["lexbench-webfetch", "lexbench-websearch"]) +@pytest.mark.parametrize("field", ["pyproject.toml", "uv.lock", "binding"]) +def test_mismatched_revision_rejected(tmp_path, benchmark, field): (tmp_path / "evaluation").mkdir() - for relative in ("pyproject.toml", "uv.lock", "evaluation/lexbench-webfetch.json"): + binding = "evaluation/" + benchmark + ".json" + for relative in ("pyproject.toml", "uv.lock", binding): shutil.copyfile(ROOT / relative, tmp_path / relative) - revision = validate_binding(tmp_path) - path = tmp_path / name + revision = validate_binding(tmp_path, benchmark) + path = tmp_path / (binding if field == "binding" else field) path.write_text(path.read_text().replace(revision, "a" * 40)) with pytest.raises(ValueError, match="make bump-lexbench"): - validate_binding(tmp_path) + validate_binding(tmp_path, benchmark) def test_refresh_captures_changed_tasks_and_hashes_without_mutating_input(tmp_path): diff --git a/tests/test_release_metadata.py b/tests/test_release_metadata.py index 6cc285bcb..1db292561 100644 --- a/tests/test_release_metadata.py +++ b/tests/test_release_metadata.py @@ -49,3 +49,44 @@ def test_release_tag_matches_installed_identity(): pytest.skip("Tag identity is checked on release-tag CI runs") tag = os.environ["GITHUB_REF_NAME"] assert tag == "v" + importlib.metadata.version("browser-harness-eval") + + +def test_declared_benchmark_pins_match_lock_and_installation(): + import json + + from harness.lexbench_pin import validate_binding + + project = source_project() + locked = tomllib.loads((ROOT / "uv.lock").read_text()) + for dependency in project["dependencies"]: + if not dependency.startswith("lexbench-"): + continue + name = dependency.split(" @ ")[0] + revision = validate_binding(ROOT, name) + package = next(p for p in locked["package"] if p["name"] == name) + installed = importlib.metadata.distribution(name) + assert installed.version == package["version"], name + origin = json.loads(installed.read_text("direct_url.json")) + assert origin["vcs_info"]["commit_id"] == revision, name + + +def test_installed_benchmarks_match_their_frozen_catalogs(): + from importlib import import_module + + source_project() + for module in ["lexbench_webfetch", "lexbench_websearch"]: + import_module(module + ".versions").catalog_release() + + +def test_runtime_version_reads_installation_metadata(): + import subprocess + import sys + + code = """ +from unittest.mock import patch +with patch('importlib.metadata.version', return_value='9.8.7') as installed: + import harness.web_fetch as package + assert package.__version__ == '9.8.7' + installed.assert_called_once_with('browser-harness-eval') +""" + subprocess.run([sys.executable, "-c", code], check=True) diff --git a/uv.lock b/uv.lock index 24b1918dd..bd810dd87 100644 --- a/uv.lock +++ b/uv.lock @@ -355,7 +355,7 @@ requires-dist = [ { name = "json-repair", marker = "extra == 'browser-use-eval'", specifier = ">=0.54,<1" }, { name = "langchain-community", marker = "extra == 'oss-eval'", specifier = "==0.3.30" }, { name = "lexbench-webfetch", git = "https://github.com/lexmount/lexbench-webfetch.git?rev=d0e78e71cf5145217cb1f2b71420a7c4194d80dd" }, - { name = "lexbench-websearch", git = "https://github.com/lexmount/lexbench-websearch.git?rev=d312653cbdc0396ffefa49ced37f82f7ca764da2" }, + { name = "lexbench-websearch", git = "https://github.com/lexmount/lexbench-websearch.git?rev=f07a2e2ddf1c1c511cb3944659534301c86ff9c9" }, { name = "markdown", marker = "extra == 'webmainbench-eval'", specifier = ">=3.7,<4" }, { name = "openai", marker = "extra == 'webmainbench-eval'", specifier = ">=2.8,<4" }, { name = "openpyxl", marker = "extra == 'oss-eval'", specifier = "==3.1.5" }, @@ -1941,8 +1941,8 @@ dependencies = [ [[package]] name = "lexbench-websearch" -version = "0.1.0" -source = { git = "https://github.com/lexmount/lexbench-websearch.git?rev=d312653cbdc0396ffefa49ced37f82f7ca764da2#d312653cbdc0396ffefa49ced37f82f7ca764da2" } +version = "0.1.1" +source = { git = "https://github.com/lexmount/lexbench-websearch.git?rev=f07a2e2ddf1c1c511cb3944659534301c86ff9c9#f07a2e2ddf1c1c511cb3944659534301c86ff9c9" } [[package]] name = "lxml"