Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
Download standalone_cli/tests/test_cli.py from huggingface/paperswithcode-mcp: direct link, hf CLI and curl.
- Browser
- Download file 106 kB
-
https://huggingface.co/spaces/huggingface/paperswithcode-mcp/resolve/main/standalone_cli/tests/test_cli.py
- Command line
-
hf download hf://spaces/huggingface/paperswithcode-mcp/standalone_cli/tests/test_cli.py
-
curl -L -o test_cli.py https://huggingface.co/spaces/huggingface/paperswithcode-mcp/resolve/main/standalone_cli/tests/test_cli.py
106 kB
| from __future__ import annotations | |
| import argparse | |
| import importlib.util | |
| import io | |
| import json | |
| import sys | |
| import urllib.error | |
| import urllib.request | |
| from contextlib import redirect_stderr, redirect_stdout | |
| from pathlib import Path | |
| import pytest | |
| ROOT = Path(__file__).resolve().parents[1] | |
| sys.path.insert(0, str(ROOT / "src")) | |
| from pwc_cli.cli import UsageError, build_parser, main # noqa: E402 | |
| from pwc_cli.skills import build_skill_md # noqa: E402 | |
| from pwc_cli.transport import ( # noqa: E402 | |
| Client, | |
| HTTPStatusError, | |
| Response, | |
| ResponseError, | |
| ) | |
| INSTALLER_SPEC = importlib.util.spec_from_file_location( | |
| "pwc_cli_installer", ROOT / "install.py" | |
| ) | |
| assert INSTALLER_SPEC and INSTALLER_SPEC.loader | |
| installer = importlib.util.module_from_spec(INSTALLER_SPEC) | |
| INSTALLER_SPEC.loader.exec_module(installer) | |
| def test_complete_parser_omits_administrative_commands(): | |
| help_text = build_parser().format_help() | |
| assert ( | |
| "{search,paper,task,method,conference,organization,framework,benchmark,skills,version,auth}" | |
| in help_text | |
| ) | |
| for command in ("add-external", "cron", "embedding", "github-issue"): | |
| assert command not in help_text | |
| assert build_parser().parse_args(["paper", "lineage", "list", "2501.1"]).paper | |
| assert ( | |
| build_parser() | |
| .parse_args(["paper", "info", "2501.1", "--include-evals"]) | |
| .include_evals | |
| ) | |
| paper_filters = build_parser().parse_args( | |
| [ | |
| "paper", | |
| "list", | |
| "--task", | |
| "Image Classification", | |
| "--method", | |
| "Vision Transformer", | |
| "--conference", | |
| "CVPR 2026", | |
| "--framework", | |
| "vLLM", | |
| "--organization", | |
| "Qwen", | |
| ] | |
| ) | |
| assert paper_filters.task == "Image Classification" | |
| assert paper_filters.method == "Vision Transformer" | |
| assert paper_filters.conference == "CVPR 2026" | |
| assert paper_filters.framework == "vLLM" | |
| assert paper_filters.organization == "Qwen" | |
| assert ( | |
| build_parser().parse_args(["task", "--name", "scene-text-recognition"]).name | |
| == "scene-text-recognition" | |
| ) | |
| assert build_parser().parse_args(["task", "list", "--area", "Vision"]).area | |
| assert build_parser().parse_args(["task", "list", "--group-by-area"]).group_by_area | |
| assert build_parser().parse_args(["method", "list", "--area", "Audio"]).area | |
| assert build_parser().parse_args(["method", "--name", "Transformer"]).name | |
| assert build_parser().parse_args(["conference", "list", "--year", "2025"]).year | |
| assert build_parser().parse_args(["conference", "--name", "CVPR 2025"]).name | |
| assert build_parser().parse_args(["organization", "--name", "NVIDIA"]).name | |
| assert ( | |
| build_parser() | |
| .parse_args(["organization", "list", "--featured-only"]) | |
| .featured_only | |
| ) | |
| assert build_parser().parse_args(["framework", "--name", "vLLM"]).name | |
| assert ( | |
| build_parser().parse_args(["framework", "list", "--platform", "gpu"]).platform | |
| == "gpu" | |
| ) | |
| def test_generated_skill_matches_installed_cli_version_and_commands(): | |
| skill = build_skill_md() | |
| assert "name: pwc-cli" in skill | |
| assert "Generated with `pwc v0.4.6`" in skill | |
| assert "`pwc search QUERY" in skill | |
| assert "--include-evals" in skill | |
| assert "[--organization ORGANIZATION]" in skill | |
| assert "[--author AUTHOR]" in skill | |
| assert "When the user identifies an author" in skill | |
| assert "`pwc organization [--name NAME] [--json]`" in skill | |
| assert "`pwc framework list [--domain DOMAIN]" in skill | |
| assert "`pwc benchmark --name NAME" in skill | |
| assert "[--max-parameters SIZE]" in skill | |
| assert "`pwc skills add" in skill | |
| assert "Publication date ranges are inclusive" in skill | |
| assert "must not be later than `--end-date`" in skill | |
| def test_published_skill_documents_x_thread_edits(): | |
| skill = (ROOT / "SKILL.md").read_text(encoding="utf-8") | |
| assert "x_threads/x_threads" in skill | |
| assert "authors or their organization" in skill | |
| def test_published_skill_advertises_inclusive_date_ranges(): | |
| skill = (ROOT / "SKILL.md").read_text(encoding="utf-8") | |
| assert "--start-date YYYY-MM-DD --end-date YYYY-MM-DD" in skill | |
| assert "--published-after" not in skill | |
| assert "--time today|week|month|all_time" not in skill | |
| assert "--max-parameters SIZE" in skill | |
| assert "inclusive parameter" in skill | |
| def test_skills_add_installs_project_skill(monkeypatch, tmp_path, capsys): | |
| monkeypatch.chdir(tmp_path) | |
| assert main(["skills", "add"]) == 0 | |
| skill_file = tmp_path / ".agents" / "skills" / "pwc-cli" / "SKILL.md" | |
| assert skill_file.read_text() == build_skill_md() | |
| assert str(skill_file.parent) in capsys.readouterr().out | |
| def test_skills_add_global_and_claude_uses_user_directories( | |
| monkeypatch, tmp_path, capsys | |
| ): | |
| monkeypatch.setenv("HOME", str(tmp_path)) | |
| assert main(["skills", "add", "--global", "--claude"]) == 0 | |
| central = tmp_path / ".agents" / "skills" / "pwc-cli" | |
| claude = tmp_path / ".claude" / "skills" / "pwc-cli" | |
| assert (central / "SKILL.md").is_file() | |
| assert claude.is_symlink() | |
| assert claude.resolve() == central | |
| output = capsys.readouterr().out | |
| assert str(central) in output | |
| assert str(claude) in output | |
| def test_skills_add_protects_existing_install_and_force_replaces_it( | |
| monkeypatch, tmp_path, capsys | |
| ): | |
| monkeypatch.chdir(tmp_path) | |
| existing = tmp_path / ".agents" / "skills" / "pwc-cli" | |
| existing.mkdir(parents=True) | |
| (existing / "old.txt").write_text("keep unless forced") | |
| assert main(["skills", "add"]) == 2 | |
| assert (existing / "old.txt").is_file() | |
| assert "rerun with --force" in capsys.readouterr().err | |
| assert main(["skills", "add", "--force"]) == 0 | |
| assert not (existing / "old.txt").exists() | |
| assert (existing / "SKILL.md").is_file() | |
| def test_skills_add_supports_custom_harness_directory_and_rejects_mixed_scope( | |
| tmp_path, capsys | |
| ): | |
| custom = tmp_path / "agent-skills" | |
| assert main(["skills", "add", "--dest", str(custom)]) == 0 | |
| assert (custom / "pwc-cli" / "SKILL.md").is_file() | |
| assert main(["skills", "add", "--dest", str(custom), "--global"]) == 2 | |
| assert "--dest cannot be combined" in capsys.readouterr().err | |
| def test_installer_downloads_from_this_repository_release_origin(): | |
| source = (ROOT / "install.py").read_text() | |
| assert "github.com/huggingface/pwc-cli/releases/download" in source | |
| assert "github.com/paperswithcode/paperswithcode.co" not in source | |
| def test_installer_version_pin_is_optional_and_explicit_pin_skips_lookup(monkeypatch): | |
| assert installer.parse_args([]).version is None | |
| monkeypatch.setattr( | |
| installer, "_open", lambda _url: (_ for _ in ()).throw(AssertionError()) | |
| ) | |
| assert installer.resolve_version("1.2.3", "unused") == "1.2.3" | |
| def test_installer_resolves_valid_latest_release_tag(monkeypatch): | |
| class Response(io.BytesIO): | |
| def __enter__(self): | |
| return self | |
| def __exit__(self, *_args): | |
| self.close() | |
| monkeypatch.setattr( | |
| installer, | |
| "_open", | |
| lambda _url: Response(b'{"tag_name": "pwc-cli-1.2.3"}'), | |
| ) | |
| assert installer.resolve_version(None, "https://example.test/latest") == "1.2.3" | |
| def test_installer_release_lookup_network_error_is_one_line_exit_3(monkeypatch, capsys): | |
| monkeypatch.setattr( | |
| installer.urllib.request, | |
| "urlopen", | |
| lambda *_args, **_kwargs: (_ for _ in ()).throw( | |
| urllib.error.URLError("offline\nnow") | |
| ), | |
| ) | |
| assert installer.main([]) == 3 | |
| assert capsys.readouterr().err == "pwc installer: network error: offline now\n" | |
| def test_installer_artifact_and_checksum_network_errors_exit_3( | |
| monkeypatch, tmp_path, capsys | |
| ): | |
| monkeypatch.setattr(installer.platform, "system", lambda: "Linux") | |
| monkeypatch.setattr(installer.platform, "machine", lambda: "x86_64") | |
| monkeypatch.setattr( | |
| installer, | |
| "_download", | |
| lambda *_args: (_ for _ in ()).throw(installer.NetworkError("artifact")), | |
| ) | |
| assert installer.main(["--version", "1.2.3", "--prefix", str(tmp_path)]) == 3 | |
| assert capsys.readouterr().err == "pwc installer: network error: artifact\n" | |
| monkeypatch.setattr( | |
| installer, "_download", lambda _url, destination: destination.write_bytes(b"x") | |
| ) | |
| monkeypatch.setattr( | |
| installer, | |
| "_read_checksum", | |
| lambda *_args: (_ for _ in ()).throw(installer.NetworkError("checksum")), | |
| ) | |
| assert installer.main(["--version", "1.2.3", "--prefix", str(tmp_path)]) == 3 | |
| assert capsys.readouterr().err == "pwc installer: network error: checksum\n" | |
| def test_installer_reports_path_and_persistent_instruction(tmp_path, capsys): | |
| bin_directory = tmp_path / ".local" / "bin" | |
| installer.report_path(bin_directory, f"/usr/bin:{bin_directory}") | |
| captured = capsys.readouterr() | |
| assert captured.out == f"{bin_directory} is on PATH\n" | |
| assert captured.err == "" | |
| installer.report_path(bin_directory, "/usr/bin") | |
| captured = capsys.readouterr() | |
| assert captured.out == "" | |
| assert captured.err == ( | |
| f"warning: {bin_directory} is not on PATH\n" | |
| f'Add this to ~/.profile: export PATH={bin_directory}:"$PATH"\n' | |
| ) | |
| def test_installer_default_path_instruction_uses_expandable_home(capsys): | |
| installer.report_path(Path.home() / ".local" / "bin", "/usr/bin") | |
| assert capsys.readouterr().err == ( | |
| "warning: ~/.local/bin is not on PATH\n" | |
| 'Add this to ~/.profile: export PATH="$HOME/.local/bin:$PATH"\n' | |
| ) | |
| def test_installer_replaces_binary_atomically(tmp_path): | |
| artifact = tmp_path / "artifact" | |
| artifact.write_bytes(b"new executable") | |
| destination = tmp_path / "bin" / "pwc" | |
| destination.parent.mkdir() | |
| destination.write_bytes(b"old executable") | |
| installer._install_atomically(artifact, destination) | |
| assert destination.read_bytes() == b"new executable" | |
| assert destination.stat().st_mode & 0o111 | |
| assert list(destination.parent.iterdir()) == [destination] | |
| def test_benchmark_limit_alias_preserves_page_size_destination(): | |
| parser = build_parser() | |
| assert parser.parse_args(["benchmark", "list", "--limit", "7"]).page_size == 7 | |
| assert parser.parse_args(["benchmark", "list", "--page-size", "8"]).page_size == 8 | |
| def test_paper_list_forwards_composable_catalog_filters(monkeypatch): | |
| calls = [] | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| calls.append((path, params)) | |
| return Response( | |
| b'{"count":0,"results":[],"applied_filters":' | |
| b'{"task":"Image Classification","method":"Vision Transformer",' | |
| b'"conference":"CVPR 2026","framework":"vLLM",' | |
| b'"organization":"Qwen","authors":[' | |
| b'{"id":"264","name":"Kaiming He","hf_username":null},' | |
| b'{"id":"26405","name":"Yilun Du","hf_username":"yilundu"}]}}', | |
| {}, | |
| ) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| assert ( | |
| main( | |
| [ | |
| "paper", | |
| "list", | |
| "--task", | |
| "Image Classification", | |
| "--method", | |
| "Vision Transformer", | |
| "--conference", | |
| "CVPR 2026", | |
| "--framework", | |
| "vLLM", | |
| "--organization", | |
| "Qwen", | |
| "--author", | |
| "Kaiming He", | |
| "--author", | |
| "@yilundu", | |
| ] | |
| ) | |
| == 0 | |
| ) | |
| assert calls == [ | |
| ( | |
| "papers/", | |
| { | |
| "page": 1, | |
| "page_size": 20, | |
| "search": None, | |
| "start_date": None, | |
| "end_date": None, | |
| "task": "Image Classification", | |
| "method": "Vision Transformer", | |
| "conference": "CVPR 2026", | |
| "framework": "vLLM", | |
| "organization": "Qwen", | |
| "author": ["Kaiming He", "@yilundu"], | |
| "latest_only": True, | |
| "order_by": "trending", | |
| "order_dir": "desc", | |
| "include_resources": False, | |
| }, | |
| ) | |
| ] | |
| def test_paper_list_rejects_more_than_ten_authors_before_request(monkeypatch, capsys): | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| raise AssertionError("author limit must be checked before the request") | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| arguments = ["paper", "list"] | |
| for author_id in range(1, 12): | |
| arguments.extend(("--author", str(author_id))) | |
| assert main(arguments) == 2 | |
| assert "at most 10 author filters" in capsys.readouterr().err.lower() | |
| def test_search_and_paper_list_forward_inclusive_date_ranges(monkeypatch): | |
| calls = [] | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| calls.append((path, params)) | |
| return Response( | |
| b'{"count":0,"results":[],"applied_filters":' | |
| b'{"start_date":"2026-08-01","end_date":"2026-08-21"}}', | |
| {}, | |
| ) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| assert ( | |
| main( | |
| [ | |
| "search", | |
| "date filtering", | |
| "--start-date", | |
| "2026-08-01", | |
| "--end-date", | |
| "2026-08-21", | |
| ] | |
| ) | |
| == 0 | |
| ) | |
| assert ( | |
| main( | |
| [ | |
| "paper", | |
| "list", | |
| "--start-date", | |
| "2026-08-01", | |
| "--end-date", | |
| "2026-08-21", | |
| ] | |
| ) | |
| == 0 | |
| ) | |
| assert calls[0][1]["start_date"].isoformat() == "2026-08-01" | |
| assert calls[0][1]["end_date"].isoformat() == "2026-08-21" | |
| assert calls[1][1]["start_date"].isoformat() == "2026-08-01" | |
| assert calls[1][1]["end_date"].isoformat() == "2026-08-21" | |
| def test_date_range_rejects_an_end_before_its_start(capsys): | |
| assert ( | |
| main( | |
| [ | |
| "search", | |
| "date filtering", | |
| "--start-date", | |
| "2026-08-21", | |
| "--end-date", | |
| "2026-08-01", | |
| ] | |
| ) | |
| == 2 | |
| ) | |
| assert "start date must be on or before end date" in capsys.readouterr().err | |
| def test_paper_list_rejects_server_that_does_not_confirm_filters(monkeypatch, capsys): | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| return Response(b'{"count":20,"results":[]}', {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| assert main(["paper", "list", "--organization", "Qwen"]) == 4 | |
| assert "server must be upgraded" in capsys.readouterr().err | |
| def test_paper_list_rejects_server_that_does_not_confirm_authors(monkeypatch, capsys): | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| return Response(b'{"count":20,"results":[],"applied_filters":{}}', {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| assert main(["paper", "list", "--author", "Kaiming He"]) == 4 | |
| assert "did not confirm" in capsys.readouterr().err | |
| def test_paper_list_rejects_partial_author_confirmation(monkeypatch, capsys): | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| return Response( | |
| b'{"count":0,"results":[],"applied_filters":{"authors":[' | |
| b'{"id":"264","name":"Kaiming He","hf_username":null}]}}', | |
| {}, | |
| ) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| assert ( | |
| main( | |
| [ | |
| "paper", | |
| "list", | |
| "--author", | |
| "Kaiming He", | |
| "--author", | |
| "@yilundu", | |
| ] | |
| ) | |
| == 4 | |
| ) | |
| assert "did not confirm" in capsys.readouterr().err | |
| def test_paper_list_accepts_canonical_confirmation_for_zero_padded_id( | |
| monkeypatch, capsys | |
| ): | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| return Response( | |
| b'{"count":0,"results":[],"applied_filters":{"authors":[' | |
| b'{"id":"264","name":"Kaiming He","hf_username":null}]}}', | |
| {}, | |
| ) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| assert main(["paper", "list", "--author", "000264"]) == 0 | |
| assert capsys.readouterr().err == "" | |
| def test_paper_list_reports_ambiguous_author_as_usage_error(monkeypatch, capsys): | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| raise HTTPStatusError( | |
| 409, | |
| json.dumps( | |
| { | |
| "detail": { | |
| "code": "ambiguous_author", | |
| "reference": "Alex Kim", | |
| "candidates": [ | |
| { | |
| "id": "41", | |
| "name": "Alex Kim", | |
| "hf_username": "alex-one", | |
| }, | |
| { | |
| "id": "72", | |
| "name": "Alex Kim", | |
| "hf_username": None, | |
| }, | |
| ], | |
| } | |
| } | |
| ), | |
| ) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| assert main(["paper", "list", "--author", "Alex Kim"]) == 2 | |
| error = capsys.readouterr().err | |
| assert "Alex Kim is ambiguous" in error | |
| assert "--author 41" in error | |
| assert "@alex-one" in error | |
| assert "--author 72" in error | |
| def test_benchmark_detail_parser_matches_requested_command_shape(): | |
| args = build_parser().parse_args( | |
| [ | |
| "benchmark", | |
| "--name", | |
| "SWE-Bench Pro", | |
| "--limit", | |
| "5", | |
| "--require-metrics", | |
| "Resolved,Latency", | |
| "--min", | |
| "Resolved=50", | |
| "--max", | |
| "Latency=2.5", | |
| "--sort", | |
| "Resolved:desc", | |
| "--pareto", | |
| "Resolved:higher,Latency:lower", | |
| "--max-parameters", | |
| "3B", | |
| ] | |
| ) | |
| assert args.name == "SWE-Bench Pro" | |
| assert args.limit == 5 | |
| assert args.require_metrics == ("Resolved", "Latency") | |
| assert args.minimum_metrics == [("Resolved", 50)] | |
| assert args.maximum_metrics == [("Latency", 2.5)] | |
| assert args.sort_metric == ("Resolved", "desc") | |
| assert args.pareto == (("Resolved", "higher"), ("Latency", "lower")) | |
| assert args.max_parameters == 3_000_000_000 | |
| def test_benchmark_detail_parser_accepts_human_parameter_sizes(): | |
| parser = build_parser() | |
| assert ( | |
| parser.parse_args( | |
| ["benchmark", "--name", "LM", "--max-parameters", "500m"] | |
| ).max_parameters | |
| == 500_000_000 | |
| ) | |
| assert ( | |
| parser.parse_args( | |
| ["benchmark", "--name", "LM", "--max-parameters", "1.5B"] | |
| ).max_parameters | |
| == 1_500_000_000 | |
| ) | |
| assert ( | |
| parser.parse_args( | |
| ["benchmark", "--name", "LM", "--max-parameters", "3_000_000_000"] | |
| ).max_parameters | |
| == 3_000_000_000 | |
| ) | |
| for invalid in ( | |
| "0", | |
| "-1", | |
| "1.5", | |
| "3K", | |
| "3B parameters", | |
| "_3B", | |
| "3_B", | |
| "3B_", | |
| "1__000", | |
| "1_.5B", | |
| ): | |
| errors = io.StringIO() | |
| with redirect_stderr(errors): | |
| try: | |
| parser.parse_args( | |
| ["benchmark", "--name", "LM", "--max-parameters", invalid] | |
| ) | |
| except SystemExit as error: | |
| assert error.code == 2 | |
| else: | |
| raise AssertionError(f"accepted invalid parameter size: {invalid}") | |
| assert "--max-parameters" in errors.getvalue() | |
| def test_benchmark_list_rejects_parent_parameter_filter(monkeypatch, capsys): | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, _path, _params=None): | |
| return Response(b'{"count":0,"results":[]}', {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| assert main(["benchmark", "--max-parameters", "3B", "list"]) == 2 | |
| assert capsys.readouterr().err == ( | |
| "pwc: --max-parameters is only valid with benchmark --name\n" | |
| ) | |
| def test_task_benchmark_list_uses_frontend_ranking_and_aligned_output(monkeypatch): | |
| calls = [] | |
| payload = { | |
| "task_id": "18", | |
| "task_slug": "ocr", | |
| "recent_days": 90, | |
| "results": [ | |
| { | |
| "id": "2", | |
| "slug": "recent-ocr", | |
| "name": "Recent OCR", | |
| "description": "Recent OCR benchmark.", | |
| "hf_url": "https://huggingface.co/datasets/example/recent-ocr", | |
| "recent_paper_count": 4, | |
| "all_time_paper_count": 5, | |
| "trend_score": 1.3333, | |
| "support_weighted_score": 3.8627, | |
| "best_model_name": "Reader 2", | |
| "best_paper_title": "Recent OCR Paper", | |
| "best_code_url": "https://github.com/example/reader-2", | |
| }, | |
| { | |
| "id": "1", | |
| "slug": "classic-ocr", | |
| "name": "Classic OCR", | |
| "description": None, | |
| "hf_url": None, | |
| "recent_paper_count": 1, | |
| "all_time_paper_count": 20, | |
| "trend_score": 0.3333, | |
| "support_weighted_score": 0.5941, | |
| "best_model_name": "Reader 1", | |
| "best_paper_title": "Classic OCR Paper", | |
| "best_code_url": None, | |
| }, | |
| ], | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params): | |
| calls.append((path, params)) | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output = io.StringIO() | |
| with redirect_stdout(output): | |
| assert main(["benchmark", "list", "--task", "OCR"]) == 0 | |
| assert calls[0][0] == "tasks/OCR/trending-benchmarks" | |
| assert calls[0][1]["min_recent_papers"] == 0 | |
| rows = output.getvalue().splitlines() | |
| assert rows[0].split() == [ | |
| "id", | |
| "slug", | |
| "name", | |
| "description", | |
| "hf_url", | |
| "recent_papers", | |
| "ranking_score", | |
| "best_model", | |
| "paper_title", | |
| "code", | |
| ] | |
| assert "Recent OCR benchmark." in rows[1] | |
| assert "https://huggingface.co/datasets/example/recent-ocr" in rows[1] | |
| assert "Classic OCR" in rows[2] | |
| def test_task_filter_takes_precedence_over_grouped_benchmark_display( | |
| monkeypatch, capsys | |
| ): | |
| payload = { | |
| "count": 1, | |
| "results": [ | |
| { | |
| "id": "2", | |
| "slug": "recent-ocr", | |
| "name": "Recent OCR", | |
| "recent_paper_count": 4, | |
| "trend_score": 1.3333, | |
| "best_model_name": "Reader 2", | |
| "best_paper_title": "Recent OCR Paper", | |
| } | |
| ], | |
| } | |
| calls = [] | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params): | |
| calls.append((path, params)) | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| assert main(["benchmark", "list", "--task", "OCR", "--group-by-area"]) == 0 | |
| captured = capsys.readouterr() | |
| assert calls[0][0] == "tasks/OCR/trending-benchmarks" | |
| assert captured.out.startswith("id slug name") | |
| assert captured.err == ( | |
| "# filters select task-scoped flat output; --group-by-area ignored\n" | |
| ) | |
| def test_flat_benchmark_list_aligns_captured_column_widths(monkeypatch, capsys): | |
| payload = { | |
| "count": 2, | |
| "results": [ | |
| { | |
| "id": "2", | |
| "name": "Short", | |
| "description": "Short description", | |
| "hf_url": None, | |
| "full_name": "S", | |
| "paper_count": 3, | |
| }, | |
| { | |
| "id": "10", | |
| "name": "Longer Name", | |
| "description": "Longer benchmark description", | |
| "hf_url": "https://huggingface.co/datasets/example/longer", | |
| "full_name": "Full benchmark name", | |
| "paper_count": 12, | |
| }, | |
| ], | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, _path, _params): | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| assert main(["benchmark", "list", "--flat"]) == 0 | |
| rows = capsys.readouterr().out.splitlines() | |
| assert rows[0].split() == [ | |
| "id", | |
| "name", | |
| "description", | |
| "hf_url", | |
| "full_name", | |
| "evals", | |
| ] | |
| assert "Short description" in rows[1] | |
| assert "Longer benchmark description" in rows[2] | |
| assert "https://huggingface.co/datasets/example/longer" in rows[2] | |
| def test_benchmark_list_groups_top_benchmarks_as_markdown(monkeypatch): | |
| calls = [] | |
| payload = { | |
| "results": [ | |
| { | |
| "id": "1", | |
| "name": "Vision", | |
| "tasks": [ | |
| { | |
| "id": "10", | |
| "name": "Image Classification", | |
| "slug": "image-classification", | |
| "paper_count": 100, | |
| "benchmarks": [ | |
| { | |
| "id": "20", | |
| "name": "ImageNet [1K]", | |
| "slug": "imagenet", | |
| "full_name": "ImageNet Large Scale Visual Recognition", | |
| "description": "Image classification benchmark.", | |
| "hf_url": "https://huggingface.co/datasets/imagenet-1k", | |
| "evaluation_count": 1234, | |
| "featured_rank": 1, | |
| } | |
| ], | |
| } | |
| ], | |
| } | |
| ] | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params): | |
| calls.append((path, params)) | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output = io.StringIO() | |
| with redirect_stdout(output): | |
| assert ( | |
| main( | |
| [ | |
| "benchmark", | |
| "list", | |
| "--group-by-area", | |
| "--area", | |
| "Vision", | |
| "--benchmarks-per-task", | |
| "5", | |
| ] | |
| ) | |
| == 0 | |
| ) | |
| assert calls == [ | |
| ( | |
| "areas/with-task-benchmarks/", | |
| {"benchmarks_per_task": 5, "min_eval_count": 2}, | |
| ) | |
| ] | |
| assert output.getvalue() == ( | |
| "# Area: Vision\n" | |
| "\n" | |
| "Inspect a benchmark with `pwc benchmark --name SLUG`.\n" | |
| "\n" | |
| "## Image Classification (`image-classification`)\n" | |
| "\n" | |
| "- ImageNet [1K] — description: Image classification benchmark.; HF: " | |
| "https://huggingface.co/datasets/imagenet-1k; full name: ImageNet Large Scale Visual Recognition; " | |
| "slug: `imagenet`; ID: `20`; 1,234 evaluations\n" | |
| ) | |
| def test_task_list_resolves_area_name_and_renders_compact_output(monkeypatch): | |
| calls = [] | |
| areas = { | |
| "count": 2, | |
| "results": [{"id": "1", "name": "Vision"}, {"id": "6", "name": "Audio"}], | |
| } | |
| tasks = { | |
| "count": 1, | |
| "results": [ | |
| { | |
| "id": "10", | |
| "slug": "image-classification", | |
| "name": "Image Classification", | |
| "area_id": "1", | |
| "level": 0, | |
| "paper_count": 123, | |
| "benchmark_count": 4, | |
| "evaluation_count": 567, | |
| } | |
| ], | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| calls.append((path, params)) | |
| payload = areas if path == "areas/" else tasks | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output = io.StringIO() | |
| with redirect_stdout(output): | |
| assert ( | |
| main( | |
| [ | |
| "task", | |
| "list", | |
| "--area", | |
| "vision", | |
| "--search", | |
| "image", | |
| "--page-size", | |
| "1", | |
| "--order-by", | |
| "paper_count", | |
| "--order-dir", | |
| "desc", | |
| ] | |
| ) | |
| == 0 | |
| ) | |
| assert calls == [ | |
| ("areas/", {"page": 1, "page_size": 500, "ordering": "name"}), | |
| ( | |
| "tasks/", | |
| { | |
| "page": 1, | |
| "page_size": 1, | |
| "q": "image", | |
| "area_id": "1", | |
| "level": None, | |
| "visible_only": False, | |
| "ordering": "-paper_count", | |
| }, | |
| ), | |
| ] | |
| assert output.getvalue() == ( | |
| "id\tslug\tname\tarea\tlevel\tpapers\tbenchmarks\tevals\n" | |
| "10\timage-classification\tImage Classification\tVision\t0\t123\t4\t567\n" | |
| ) | |
| def test_task_list_groups_complete_taxonomy_in_interactive_terminal(monkeypatch): | |
| payload = { | |
| "results": [ | |
| { | |
| "id": "6", | |
| "name": "Audio", | |
| "tasks": [ | |
| { | |
| "id": "259", | |
| "slug": "audio-classification", | |
| "name": "Audio Classification", | |
| "paper_count": 63, | |
| "benchmark_count": 1, | |
| "evaluation_count": 8, | |
| } | |
| ], | |
| }, | |
| { | |
| "id": "1", | |
| "name": "Vision", | |
| "tasks": [ | |
| { | |
| "id": "13", | |
| "slug": "3d-generation", | |
| "name": "3D generation", | |
| "paper_count": 2389, | |
| "benchmark_count": 12, | |
| "evaluation_count": 345, | |
| }, | |
| { | |
| "id": "1", | |
| "slug": "image-classification", | |
| "name": "Image Classification", | |
| "paper_count": 1, | |
| "benchmark_count": 1, | |
| "evaluation_count": 1, | |
| }, | |
| ], | |
| }, | |
| ] | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| assert (path, params) == ("areas/with-tasks/", None) | |
| return Response(json.dumps(payload).encode(), {}) | |
| class TerminalOutput(io.StringIO): | |
| def isatty(self): | |
| return True | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output = TerminalOutput() | |
| with redirect_stdout(output): | |
| assert main(["task", "list"]) == 0 | |
| assert output.getvalue() == ( | |
| "# Area: Audio\n" | |
| "- **Audio Classification** (`audio-classification`) — " | |
| "63 papers · 1 benchmark · 8 evals\n" | |
| "\n" | |
| "# Area: Vision\n" | |
| "- **3D generation** (`3d-generation`) — " | |
| "2,389 papers · 12 benchmarks · 345 evals\n" | |
| "- **Image Classification** (`image-classification`) — " | |
| "1 paper · 1 benchmark · 1 eval\n" | |
| ) | |
| assert "(`13`)" not in output.getvalue() | |
| def test_task_list_can_force_grouped_area_output_when_captured(monkeypatch): | |
| payload = { | |
| "results": [ | |
| {"id": "6", "name": "Audio", "tasks": []}, | |
| { | |
| "id": "1", | |
| "name": "Vision", | |
| "tasks": [ | |
| { | |
| "id": "13", | |
| "slug": "3d-generation", | |
| "name": "3D generation", | |
| "paper_count": 2389, | |
| "benchmark_count": 12, | |
| "evaluation_count": 345, | |
| } | |
| ], | |
| }, | |
| ] | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| assert (path, params) == ("areas/with-tasks/", None) | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output = io.StringIO() | |
| with redirect_stdout(output): | |
| assert main(["task", "list", "--group-by-area", "--area", "vision"]) == 0 | |
| assert output.getvalue() == ( | |
| "# Area: Vision\n- **3D generation** (`3d-generation`) — " | |
| "2,389 papers · 12 benchmarks · 345 evals\n" | |
| ) | |
| def test_task_detail_renders_task_page_sections(monkeypatch): | |
| calls = [] | |
| search = { | |
| "count": 1, | |
| "results": [ | |
| { | |
| "id": "17", | |
| "slug": "scene-text-recognition", | |
| "name": "Scene Text Recognition", | |
| "area_id": "1", | |
| "level": 1, | |
| "paper_count": 204, | |
| "benchmark_count": 21, | |
| "evaluation_count": 401, | |
| } | |
| ], | |
| } | |
| page = { | |
| "task": { | |
| "id": "17", | |
| "slug": "scene-text-recognition", | |
| "name": "Scene Text Recognition", | |
| "description": "Recognizing text in natural images.", | |
| "research_trends": ["Vision-language pretraining"], | |
| "area_id": "1", | |
| "level": 1, | |
| "paper_count": 204, | |
| }, | |
| "parents": [{"id": "2", "slug": "ocr", "name": "OCR"}], | |
| "sisters": [{"id": "18", "slug": "text-detection", "name": "Text Detection"}], | |
| "recommended_frameworks": [ | |
| { | |
| "id": "44", | |
| "url": "https://github.com/huggingface/transformers", | |
| "owner": "huggingface", | |
| "name": "transformers", | |
| "num_stars": 150000, | |
| } | |
| ], | |
| "children": [{"id": "19", "slug": "handwritten-text", "name": "Handwriting"}], | |
| "benchmarks": [ | |
| { | |
| "id": "30", | |
| "slug": "iiit5k", | |
| "name": "IIIT5K", | |
| "paper_count": 12, | |
| "best_model_name": "Model A", | |
| }, | |
| { | |
| "id": "32", | |
| "slug": "svt", | |
| "name": "SVT", | |
| "paper_count": 4, | |
| "best_model_name": "Model B", | |
| }, | |
| ], | |
| "subtask_benchmarks": [ | |
| { | |
| "subtask_id": "19", | |
| "benchmarks": [{"id": "31", "slug": "iam", "name": "IAM"}], | |
| } | |
| ], | |
| } | |
| papers = { | |
| "count": 204, | |
| "results": [ | |
| { | |
| "id": "100", | |
| "arxiv_id": "2501.00001", | |
| "title": "A Better Text Recognizer", | |
| "published": "2025-01-01", | |
| "citation_count": 10, | |
| "methods": [{"id": "7", "slug": "transformer", "name": "Transformer"}], | |
| } | |
| ], | |
| } | |
| benchmark_trends = { | |
| "support_prior_papers": 2.0, | |
| "results": [ | |
| { | |
| "id": "32", | |
| "slug": "svt", | |
| "name": "SVT", | |
| "support_weighted_score": 2.5, | |
| }, | |
| { | |
| "id": "30", | |
| "slug": "iiit5k", | |
| "name": "IIIT5K", | |
| "support_weighted_score": 1.25, | |
| }, | |
| ], | |
| } | |
| areas = {"count": 1, "results": [{"id": "1", "name": "Vision"}]} | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| calls.append((path, params)) | |
| payloads = { | |
| "tasks/": search, | |
| "tasks/17/page": page, | |
| "tasks/17/trending-benchmarks": benchmark_trends, | |
| "tasks/17/papers": papers, | |
| "areas/": areas, | |
| } | |
| return Response(json.dumps(payloads[path]).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output = io.StringIO() | |
| with redirect_stdout(output): | |
| assert main(["task", "--name", "scene-text-recognition"]) == 0 | |
| rendered = output.getvalue() | |
| assert "# Scene Text Recognition" in rendered | |
| assert ( | |
| "Area: Vision · Level: 1 · 204 papers · 21 benchmarks · 401 evaluations" | |
| in rendered | |
| ) | |
| assert "## Recommended frameworks" in rendered | |
| assert ( | |
| "[huggingface/transformers](https://github.com/huggingface/transformers)" | |
| in rendered | |
| ) | |
| assert "## Sister tasks" in rendered | |
| assert "## Common methods (from 1 sampled papers)" in rendered | |
| assert "## Benchmarks by subtask" in rendered | |
| assert "## Trending papers (top 1 of 204)" in rendered | |
| assert rendered.index("SVT") < rendered.index("IIIT5K") | |
| assert "trend score: 2.50" in rendered | |
| assert calls == [ | |
| ("tasks/", {"q": "scene-text-recognition", "page": 1, "page_size": 100}), | |
| ("tasks/17/page", None), | |
| ( | |
| "tasks/17/trending-benchmarks", | |
| {"limit": 100, "min_recent_papers": 0}, | |
| ), | |
| ( | |
| "tasks/17/papers", | |
| { | |
| "page": 1, | |
| "page_size": 100, | |
| "order_by": "trending", | |
| "order_dir": "desc", | |
| "include_resources": True, | |
| }, | |
| ), | |
| ("areas/", {"page": 1, "page_size": 500, "ordering": "name"}), | |
| ] | |
| def test_task_detail_json_has_stable_composed_payload(monkeypatch, capsys): | |
| payloads = { | |
| "tasks/": { | |
| "count": 1, | |
| "results": [ | |
| { | |
| "id": "17", | |
| "slug": "scene-text-recognition", | |
| "name": "Scene Text Recognition", | |
| "area_id": "1", | |
| } | |
| ], | |
| }, | |
| "tasks/17/page": { | |
| "task": {"id": "17", "name": "Scene Text Recognition"}, | |
| "recommended_frameworks": [], | |
| "benchmarks": [], | |
| }, | |
| "tasks/17/trending-benchmarks": {"results": []}, | |
| "tasks/17/papers": {"count": 0, "results": []}, | |
| "tasks/17": { | |
| "id": "17", | |
| "slug": "scene-text-recognition", | |
| "name": "Scene Text Recognition", | |
| "area_id": "1", | |
| }, | |
| "areas/": {"count": 1, "results": [{"id": "1", "name": "Vision"}]}, | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| return Response(json.dumps(payloads[path]).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| assert main(["task", "--name", "Scene Text Recognition", "--json"]) == 0 | |
| result = json.loads(capsys.readouterr().out) | |
| assert result["schema_version"] == "v1" | |
| assert result["data"]["task"]["id"] == "17" | |
| assert result["data"]["area"]["name"] == "Vision" | |
| assert result["data"]["paper_sample_size"] == 0 | |
| assert main(["task", "--name", "17", "--json"]) == 0 | |
| result = json.loads(capsys.readouterr().out) | |
| assert result["data"]["task"]["id"] == "17" | |
| def test_method_list_accepts_area_id_and_year_filter(monkeypatch): | |
| calls = [] | |
| areas = { | |
| "count": 1, | |
| "results": [{"id": "6", "name": "Audio"}], | |
| } | |
| methods = { | |
| "count": 1, | |
| "results": [ | |
| { | |
| "id": "20", | |
| "slug": "wav2vec-2", | |
| "name": "wav2vec 2.0", | |
| "full_name": "wav2vec 2.0", | |
| "area_id": "6", | |
| "introduced_year": 2020, | |
| "paper_count": 45, | |
| } | |
| ], | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| calls.append((path, params)) | |
| payload = areas if path == "areas/" else methods | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output = io.StringIO() | |
| with redirect_stdout(output): | |
| assert ( | |
| main( | |
| [ | |
| "method", | |
| "list", | |
| "--area", | |
| "6", | |
| "--search", | |
| "wav2vec", | |
| "--introduced-year", | |
| "2020", | |
| ] | |
| ) | |
| == 0 | |
| ) | |
| assert calls[1] == ( | |
| "methods/", | |
| { | |
| "page": 1, | |
| "page_size": 50, | |
| "q": "wav2vec", | |
| "area_id": "6", | |
| "introduced_year": 2020, | |
| "ordering": "name", | |
| }, | |
| ) | |
| assert output.getvalue() == ( | |
| "id\tslug\tname\tfull_name\tarea\tintroduced\tpapers\n" | |
| "20\twav2vec-2\twav2vec 2.0\twav2vec 2.0\tAudio\t2020\t45\n" | |
| ) | |
| def test_method_detail_resolves_exact_name_and_renders_source(monkeypatch): | |
| calls = [] | |
| payloads = { | |
| "methods/": { | |
| "count": 1, | |
| "results": [ | |
| { | |
| "id": "2", | |
| "slug": "transformer", | |
| "name": "Transformer", | |
| "full_name": "Transformer", | |
| } | |
| ], | |
| }, | |
| "methods/2": { | |
| "id": "2", | |
| "slug": "transformer", | |
| "name": "Transformer", | |
| "description": "Attention-only architecture.", | |
| "area_id": "3", | |
| "introduced_year": 2017, | |
| "paper_count": 13086, | |
| "source_url": "/paper/1706.03762", | |
| "source_title": "Attention Is All You Need", | |
| }, | |
| "areas/": {"count": 1, "results": [{"id": "3", "name": "General"}]}, | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| calls.append((path, params)) | |
| return Response(json.dumps(payloads[path]).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output = io.StringIO() | |
| with redirect_stdout(output): | |
| assert main(["method", "--name", "Transformer"]) == 0 | |
| rendered = output.getvalue() | |
| assert "# Transformer" in rendered | |
| assert "Area: General · Introduced: 2017 · 13,086 papers" in rendered | |
| assert ( | |
| "[Attention Is All You Need](https://paperswithcode.co/paper/1706.03762)" | |
| in rendered | |
| ) | |
| assert calls[0] == ( | |
| "methods/", | |
| {"q": "Transformer", "page": 1, "page_size": 100}, | |
| ) | |
| calls.clear() | |
| with redirect_stdout(io.StringIO()): | |
| assert main(["method", "--name", "2"]) == 0 | |
| assert calls == [ | |
| ("methods/2", None), | |
| ("areas/", {"page": 1, "page_size": 500, "ordering": "name"}), | |
| ] | |
| def _keyword_method_client(monkeypatch, catalog): | |
| calls = [] | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| calls.append((path, params)) | |
| if path == "methods/" and params.get("q"): | |
| payload = {"count": 0, "results": []} | |
| elif path == "methods/": | |
| payload = {"count": len(catalog), "results": catalog} | |
| elif path == "areas/": | |
| payload = {"count": 0, "results": []} | |
| else: | |
| method_id = path.split("/")[1] | |
| payload = next(m for m in catalog if m["id"] == method_id) | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| return calls | |
| def test_method_detail_resolves_keyword_alias(monkeypatch): | |
| catalog = [ | |
| { | |
| "id": "1205", | |
| "slug": "gbdt", | |
| "name": "Gradient Boosted Decision Trees", | |
| "full_name": "Gradient Boosted Decision Trees (GBDT)", | |
| "keywords": "GBDT, GBDTs, GDBT, gradient boosting machine", | |
| }, | |
| { | |
| "id": "9", | |
| "slug": "pi0", | |
| "name": "pi0", | |
| "full_name": "pi0", | |
| "keywords": "pi-0, pi zero", | |
| }, | |
| ] | |
| calls = _keyword_method_client(monkeypatch, catalog) | |
| for alias, slug in (("gdbt", "gbdt"), ("GDBT", "gbdt"), ("pi 0", "pi0")): | |
| output = io.StringIO() | |
| with redirect_stdout(output): | |
| assert main(["method", "--name", alias, "--json"]) == 0 | |
| assert json.loads(output.getvalue())["data"]["method"]["slug"] == slug | |
| assert ("methods/", {"page": 1, "page_size": 500}) in calls | |
| def test_method_detail_keyword_alias_must_be_unique(monkeypatch, capsys): | |
| catalog = [ | |
| {"id": "1", "slug": "a", "name": "Alpha", "keywords": "shared, one"}, | |
| {"id": "2", "slug": "b", "name": "Beta", "keywords": "Shared"}, | |
| ] | |
| _keyword_method_client(monkeypatch, catalog) | |
| assert main(["method", "--name", "shared"]) != 0 | |
| assert "Method not found: shared" in capsys.readouterr().err | |
| def test_conference_list_filters_complete_response_by_year(monkeypatch): | |
| payload = { | |
| "count": 2, | |
| "results": [ | |
| { | |
| "slug": "cvpr-2025", | |
| "name": "CVPR 2025", | |
| "year": 2025, | |
| "paper_count": 1834, | |
| "location": "Nashville, USA", | |
| }, | |
| { | |
| "slug": "cvpr-2026", | |
| "name": "CVPR 2026", | |
| "year": 2026, | |
| "paper_count": 2200, | |
| "location": "Denver, USA", | |
| }, | |
| ], | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| assert (path, params) == ("conferences/", None) | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output = io.StringIO() | |
| with redirect_stdout(output): | |
| assert main(["conference", "list", "--year", "2025"]) == 0 | |
| assert output.getvalue() == ( | |
| "slug\tname\tyear\tpapers\tlocation\n" | |
| "cvpr-2025\tCVPR 2025\t2025\t1834\tNashville, USA\n" | |
| ) | |
| def test_conference_detail_accepts_name_slug_or_id(monkeypatch, capsys): | |
| listing = { | |
| "count": 1, | |
| "results": [ | |
| {"id": "7", "slug": "cvpr-2026", "name": "CVPR 2026", "year": 2026} | |
| ], | |
| } | |
| detail = { | |
| "id": "7", | |
| "slug": "cvpr-2026", | |
| "name": "CVPR 2026", | |
| "year": 2026, | |
| "paper_count": 2677, | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| payload = listing if path == "conferences/" else detail | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| for reference in ("CVPR 2026", "cvpr-2026", "7"): | |
| assert main(["conference", "--name", reference, "--json"]) == 0 | |
| result = json.loads(capsys.readouterr().out) | |
| assert result["data"]["slug"] == "cvpr-2026" | |
| def test_conference_list_aligns_columns_in_interactive_terminal(monkeypatch): | |
| payload = { | |
| "count": 2, | |
| "results": [ | |
| { | |
| "slug": "cvpr-2025", | |
| "name": "CVPR 2025", | |
| "year": 2025, | |
| "paper_count": 1834, | |
| "location": "Nashville, USA", | |
| }, | |
| { | |
| "slug": "neurips-2025", | |
| "name": "NeurIPS 2025", | |
| "year": 2025, | |
| "paper_count": 2763, | |
| "location": "San Diego, USA", | |
| }, | |
| ], | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| assert (path, params) == ("conferences/", None) | |
| return Response(json.dumps(payload).encode(), {}) | |
| class TerminalOutput(io.StringIO): | |
| def isatty(self): | |
| return True | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output = TerminalOutput() | |
| with redirect_stdout(output): | |
| assert main(["conference", "list"]) == 0 | |
| assert output.getvalue() == ( | |
| "slug name year papers location\n" | |
| "cvpr-2025 CVPR 2025 2025 1834 Nashville, USA\n" | |
| "neurips-2025 NeurIPS 2025 2025 2763 San Diego, USA\n" | |
| ) | |
| def test_organization_detail_and_featured_list(monkeypatch, capsys): | |
| listing = { | |
| "count": 1, | |
| "results": [ | |
| { | |
| "id": "1", | |
| "slug": "nvidia", | |
| "name": "NVIDIA", | |
| "paper_count": 158, | |
| "is_featured": True, | |
| "trending_rank": 1, | |
| } | |
| ], | |
| } | |
| detail = { | |
| **listing["results"][0], | |
| "hf_url": "https://huggingface.co/nvidia", | |
| "website_url": "https://www.nvidia.com/", | |
| } | |
| calls = [] | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| calls.append((path, params)) | |
| payload = detail if path == "organizations/nvidia" else listing | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| assert main(["organization", "--name", "NVIDIA", "--json"]) == 0 | |
| result = json.loads(capsys.readouterr().out) | |
| assert result["data"]["slug"] == "nvidia" | |
| assert main(["organization", "list", "--featured-only"]) == 0 | |
| assert "1\tnvidia\tNVIDIA\t158\tyes\t1" in capsys.readouterr().out | |
| assert calls == [ | |
| ("organizations/", {"featured_only": False}), | |
| ("organizations/nvidia", None), | |
| ("organizations/", {"featured_only": True}), | |
| ] | |
| def test_framework_detail_and_filtered_list_flatten_catalog(monkeypatch, capsys): | |
| catalog = { | |
| "domains": [ | |
| { | |
| "slug": "llm", | |
| "name": "Large Language Models", | |
| "categories": [ | |
| { | |
| "slug": "inference", | |
| "name": "Inference & Serving", | |
| "frameworks": [ | |
| { | |
| "id": "11", | |
| "slug": "vllm", | |
| "name": "vLLM", | |
| "description": "High-throughput serving.", | |
| "platforms": ["gpu"], | |
| "paper_count": 73, | |
| }, | |
| { | |
| "id": "9", | |
| "slug": "llama-cpp", | |
| "name": "llama.cpp", | |
| "description": "Portable inference.", | |
| "platforms": ["cpu", "apple"], | |
| "paper_count": 2, | |
| }, | |
| ], | |
| } | |
| ], | |
| } | |
| ] | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| assert (path, params) == ("frameworks/", None) | |
| return Response(json.dumps(catalog).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| assert main(["framework", "--name", "11", "--json"]) == 0 | |
| result = json.loads(capsys.readouterr().out) | |
| assert result["data"]["slug"] == "vllm" | |
| assert result["data"]["domain_slug"] == "llm" | |
| assert main(["framework", "list", "--platform", "apple"]) == 0 | |
| output = capsys.readouterr().out | |
| assert "llama-cpp" in output | |
| assert "vllm" not in output | |
| def test_unknown_area_lists_valid_choices(monkeypatch): | |
| areas = { | |
| "count": 2, | |
| "results": [{"id": "1", "name": "Vision"}, {"id": "6", "name": "Audio"}], | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| assert path == "areas/" | |
| return Response(json.dumps(areas).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| errors = io.StringIO() | |
| with redirect_stderr(errors): | |
| assert main(["task", "list", "--area", "Robotics"]) == 4 | |
| assert errors.getvalue() == ( | |
| "pwc: Area not found: Robotics; available areas: Audio, Vision\n" | |
| ) | |
| def test_benchmark_detail_renders_merged_markdown_leaderboard(monkeypatch): | |
| calls = [] | |
| benchmark_payload = { | |
| "count": 1, | |
| "results": [ | |
| { | |
| "id": "42", | |
| "name": "SWE-Bench Pro", | |
| "slug": "swe-bench-pro", | |
| "description": "A coding-agent benchmark.", | |
| } | |
| ], | |
| } | |
| evaluations_payload = { | |
| "count": 3, | |
| "results": [ | |
| { | |
| "id": "1", | |
| "paper_id": "9", | |
| "task_id": "3", | |
| "dataset_id": "42", | |
| "model_name": "Agent | One", | |
| "metrics": {"Resolved": 55.5}, | |
| "best_metric": "Resolved", | |
| "best_rank": 1, | |
| "num_parameters": 10_000_000_000, | |
| "paper_title": "An Agent Paper", | |
| "paper_arxiv_id": "2601.12345", | |
| "paper_published_date": "2026-01-20", | |
| "task_name": "Coding Agents", | |
| "is_open": False, | |
| }, | |
| { | |
| "id": "2", | |
| "paper_id": "9", | |
| "task_id": "3", | |
| "dataset_id": "42", | |
| "model_name": "Agent | One", | |
| "metrics": {"Pass@1": 50}, | |
| "best_metric": "Pass@1", | |
| "best_rank": 2, | |
| "num_parameters": 10_000_000_000, | |
| "paper_title": "An Agent Paper", | |
| "paper_arxiv_id": "2601.12345", | |
| "paper_published_date": "2026-01-20", | |
| "task_name": "Coding Agents", | |
| "is_open": False, | |
| }, | |
| { | |
| "id": "3", | |
| "paper_id": "9", | |
| "task_id": "8", | |
| "dataset_id": "42", | |
| "model_name": "Agent | One", | |
| "metrics": {"Resolved": 55.5}, | |
| "best_metric": "Resolved", | |
| "best_rank": 4, | |
| "num_parameters": 10_000_000_000, | |
| "paper_title": "An Agent Paper", | |
| "paper_arxiv_id": "2601.12345", | |
| "paper_published_date": "2026-01-20", | |
| "task_name": "Software Engineering", | |
| "task_slug": "software-engineering", | |
| "is_open": False, | |
| }, | |
| ], | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params): | |
| calls.append((path, params)) | |
| payload = benchmark_payload if path == "datasets/" else evaluations_payload | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output = io.StringIO() | |
| with redirect_stdout(output): | |
| assert main(["benchmark", "--name", "SWE-Bench Pro"]) == 0 | |
| rendered = output.getvalue() | |
| assert "# SWE-Bench Pro" in rendered | |
| assert "Agent \\| One" in rendered | |
| assert "| 1 | Agent \\| One | 10B |" in rendered | |
| assert "Resolved: 55.5, Pass@1: 50" in rendered | |
| assert "[An Agent Paper](https://paperswithcode.co/paper/2601.12345)" in rendered | |
| assert "2026-01-20" in rendered | |
| assert calls[1] == ( | |
| "datasets/42/evaluations/", | |
| { | |
| "page": 1, | |
| "page_size": 20, | |
| "ordering": "best_rank", | |
| "is_open": None, | |
| }, | |
| ) | |
| json_output = io.StringIO() | |
| with redirect_stdout(json_output): | |
| assert main(["benchmark", "--name", "SWE-Bench Pro", "--json"]) == 0 | |
| rows = json.loads(json_output.getvalue())["data"]["results"] | |
| assert len(rows) == 1 | |
| assert rows[0]["rank_scopes"] == [ | |
| { | |
| "task_id": "3", | |
| "task_name": "Coding Agents", | |
| "task_slug": None, | |
| "rank": 1, | |
| }, | |
| { | |
| "task_id": "8", | |
| "task_name": "Software Engineering", | |
| "task_slug": "software-engineering", | |
| "rank": 4, | |
| }, | |
| ] | |
| def test_benchmark_detail_renders_aligned_table_in_terminal(monkeypatch): | |
| benchmark_payload = { | |
| "count": 1, | |
| "results": [ | |
| { | |
| "id": "42", | |
| "name": "SWE-Bench Pro", | |
| "slug": "swe-bench-pro", | |
| "description": "A coding-agent benchmark.", | |
| } | |
| ], | |
| } | |
| evaluations_payload = { | |
| "count": 1, | |
| "results": [ | |
| { | |
| "id": "1", | |
| "paper_id": "9", | |
| "task_id": "3", | |
| "dataset_id": "42", | |
| "model_name": "Agent One", | |
| "metrics": {"Resolved": 55.5}, | |
| "best_metric": "Resolved", | |
| "best_rank": 1, | |
| "paper_title": "An Agent Paper", | |
| "paper_arxiv_id": "2601.12345", | |
| "paper_published_date": "2026-01-20", | |
| "task_name": "Coding Agents", | |
| "is_open": False, | |
| } | |
| ], | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params): | |
| payload = benchmark_payload if path == "datasets/" else evaluations_payload | |
| return Response(json.dumps(payload).encode(), {}) | |
| class TerminalBuffer(io.StringIO): | |
| def isatty(self): | |
| return True | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output = TerminalBuffer() | |
| with redirect_stdout(output): | |
| assert main(["benchmark", "--name", "SWE-Bench Pro"]) == 0 | |
| rendered = output.getvalue() | |
| assert rendered.startswith("SWE-Bench Pro\n\nA coding-agent benchmark.\n") | |
| assert ( | |
| "View benchmark: https://paperswithcode.co/benchmark/swe-bench-pro" in rendered | |
| ) | |
| assert "Rank Model Parameters Scores Task" in rendered | |
| assert " 1 Agent One — Resolved: 55.5 Coding Agents" in rendered | |
| assert "An Agent Paper [2601.12345]" in rendered | |
| assert "| ---:" not in rendered | |
| def _parameter_filter_client(monkeypatch, evaluations_payload): | |
| benchmark_payload = { | |
| "count": 1, | |
| "results": [{"id": "42", "name": "Language Model Benchmark", "slug": "lmb"}], | |
| } | |
| calls = [] | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params): | |
| calls.append((path, params)) | |
| payload = benchmark_payload if path == "datasets/" else evaluations_payload | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| return calls | |
| def test_benchmark_detail_filters_by_inclusive_max_parameters(monkeypatch, capsys): | |
| evaluations_payload = { | |
| "count": 1, | |
| "next_page": None, | |
| "previous_page": None, | |
| "parameter_coverage_known": 1, | |
| "parameter_coverage_total": 2, | |
| "results": [ | |
| { | |
| "id": "1", | |
| "paper_id": "9", | |
| "task_id": "3", | |
| "dataset_id": "42", | |
| "model_name": "Edge 3B", | |
| "metrics": {"Perplexity": 12.5}, | |
| "best_metric": "Perplexity", | |
| "best_rank": 4, | |
| "num_parameters": 3_000_000_000, | |
| "is_open": True, | |
| } | |
| ], | |
| } | |
| calls = _parameter_filter_client(monkeypatch, evaluations_payload) | |
| assert ( | |
| main( | |
| [ | |
| "benchmark", | |
| "--name", | |
| "Language Model Benchmark", | |
| "--is-open", | |
| "true", | |
| "--max-parameters", | |
| "3B", | |
| "--json", | |
| ] | |
| ) | |
| == 0 | |
| ) | |
| assert calls[1] == ( | |
| "evaluations/", | |
| { | |
| "page": 1, | |
| "page_size": 20, | |
| "dataset_id": "42", | |
| "ordering": "best_rank", | |
| "is_open": "true", | |
| "max_parameters_exclusive": 3_000_000_001, | |
| }, | |
| ) | |
| result = json.loads(capsys.readouterr().out) | |
| assert result["data"]["matched_count"] == 1 | |
| assert result["data"]["results"][0]["model_name"] == "Edge 3B" | |
| assert result["data"]["results"][0]["num_parameters"] == 3_000_000_000 | |
| assert ( | |
| main( | |
| [ | |
| "benchmark", | |
| "--name", | |
| "Language Model Benchmark", | |
| "--max-parameters", | |
| "3B", | |
| ] | |
| ) | |
| == 0 | |
| ) | |
| rendered = capsys.readouterr().out | |
| assert "| Rank | Model | Parameters | Scores |" in rendered | |
| assert "| 4 | Edge 3B | 3B | Perplexity: 12.5 |" in rendered | |
| def test_benchmark_detail_parameter_filter_fails_closed_without_api_support( | |
| monkeypatch, capsys | |
| ): | |
| unsupported_payload = {"count": 0, "results": []} | |
| _parameter_filter_client(monkeypatch, unsupported_payload) | |
| assert ( | |
| main( | |
| [ | |
| "benchmark", | |
| "--name", | |
| "Language Model Benchmark", | |
| "--max-parameters", | |
| "3B", | |
| ] | |
| ) | |
| == 4 | |
| ) | |
| assert capsys.readouterr().err == ( | |
| "pwc: parameter filtering requires a compatible API; server must be upgraded\n" | |
| ) | |
| def test_benchmark_detail_parameter_filter_rejects_out_of_bound_response( | |
| monkeypatch, capsys | |
| ): | |
| invalid_payload = { | |
| "count": 1, | |
| "parameter_coverage_known": 1, | |
| "parameter_coverage_total": 1, | |
| "results": [ | |
| { | |
| "paper_id": "9", | |
| "task_id": "3", | |
| "dataset_id": "42", | |
| "model_name": "Too Large", | |
| "metrics": {"Perplexity": 10}, | |
| "num_parameters": 3_000_000_001, | |
| } | |
| ], | |
| } | |
| _parameter_filter_client(monkeypatch, invalid_payload) | |
| assert ( | |
| main( | |
| [ | |
| "benchmark", | |
| "--name", | |
| "Language Model Benchmark", | |
| "--max-parameters", | |
| "3B", | |
| ] | |
| ) | |
| == 4 | |
| ) | |
| assert capsys.readouterr().err == ( | |
| "pwc: API returned a model outside the requested parameter limit\n" | |
| ) | |
| def test_benchmark_detail_parameter_filter_rejects_conflicting_sibling_counts( | |
| monkeypatch, capsys | |
| ): | |
| invalid_payload = { | |
| "count": 1, | |
| "parameter_coverage_known": 1, | |
| "parameter_coverage_total": 1, | |
| "results": [ | |
| { | |
| "paper_id": "9", | |
| "task_id": "3", | |
| "dataset_id": "42", | |
| "model_name": "Conflicting", | |
| "metrics": {"Perplexity": 10}, | |
| "num_parameters": 2_000_000_000, | |
| }, | |
| { | |
| "paper_id": "9", | |
| "task_id": "3", | |
| "dataset_id": "42", | |
| "model_name": "Conflicting", | |
| "metrics": {"Accuracy": 90}, | |
| "num_parameters": 2_500_000_000, | |
| }, | |
| ], | |
| } | |
| _parameter_filter_client(monkeypatch, invalid_payload) | |
| assert ( | |
| main( | |
| [ | |
| "benchmark", | |
| "--name", | |
| "Language Model Benchmark", | |
| "--max-parameters", | |
| "3B", | |
| ] | |
| ) | |
| == 4 | |
| ) | |
| assert capsys.readouterr().err == ( | |
| "pwc: API returned a model outside the requested parameter limit\n" | |
| ) | |
| def test_benchmark_detail_parameter_filter_rejects_incomplete_sibling_counts( | |
| monkeypatch, capsys | |
| ): | |
| invalid_payload = { | |
| "count": 1, | |
| "parameter_coverage_known": 1, | |
| "parameter_coverage_total": 1, | |
| "results": [ | |
| { | |
| "paper_id": "9", | |
| "task_id": "3", | |
| "dataset_id": "42", | |
| "model_name": "Incomplete", | |
| "metrics": {"Perplexity": 10}, | |
| "num_parameters": 2_000_000_000, | |
| }, | |
| { | |
| "paper_id": "9", | |
| "task_id": "3", | |
| "dataset_id": "42", | |
| "model_name": "Incomplete", | |
| "metrics": {"Accuracy": 90}, | |
| "num_parameters": None, | |
| }, | |
| ], | |
| } | |
| _parameter_filter_client(monkeypatch, invalid_payload) | |
| assert ( | |
| main( | |
| [ | |
| "benchmark", | |
| "--name", | |
| "Language Model Benchmark", | |
| "--max-parameters", | |
| "3B", | |
| ] | |
| ) | |
| == 4 | |
| ) | |
| assert capsys.readouterr().err == ( | |
| "pwc: API returned a model outside the requested parameter limit\n" | |
| ) | |
| def test_benchmark_detail_parameter_filter_composes_with_metric_pagination( | |
| monkeypatch, capsys | |
| ): | |
| benchmark_payload = { | |
| "count": 1, | |
| "results": [{"id": "42", "name": "Language Model Benchmark"}], | |
| } | |
| pages = { | |
| 1: { | |
| "count": 2, | |
| "next_page": 2, | |
| "parameter_coverage_known": 2, | |
| "parameter_coverage_total": 3, | |
| "results": [ | |
| { | |
| "paper_id": "1", | |
| "task_id": "3", | |
| "dataset_id": "42", | |
| "model_name": "Model A", | |
| "metrics": {"Accuracy": 80}, | |
| "num_parameters": 1_000_000_000, | |
| }, | |
| { | |
| "paper_id": "1", | |
| "task_id": "3", | |
| "dataset_id": "42", | |
| "model_name": "Model A", | |
| "metrics": {"Latency": 5}, | |
| "num_parameters": 1_000_000_000, | |
| }, | |
| ], | |
| }, | |
| 2: { | |
| "count": 2, | |
| "next_page": None, | |
| "parameter_coverage_known": 2, | |
| "parameter_coverage_total": 3, | |
| "results": [ | |
| { | |
| "paper_id": "2", | |
| "task_id": "3", | |
| "dataset_id": "42", | |
| "model_name": "Model B", | |
| "metrics": {"Accuracy": 90, "Latency": 7}, | |
| "num_parameters": 2_000_000_000, | |
| } | |
| ], | |
| }, | |
| } | |
| evaluation_calls = [] | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params): | |
| if path == "datasets/": | |
| return Response(json.dumps(benchmark_payload).encode(), {}) | |
| evaluation_calls.append(params) | |
| return Response(json.dumps(pages[params["page"]]).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| assert ( | |
| main( | |
| [ | |
| "benchmark", | |
| "--name", | |
| "Language Model Benchmark", | |
| "--max-parameters", | |
| "2B", | |
| "--require-metrics", | |
| "Accuracy,Latency", | |
| "--sort", | |
| "Accuracy:desc", | |
| "--json", | |
| ] | |
| ) | |
| == 0 | |
| ) | |
| result = json.loads(capsys.readouterr().out) | |
| assert [row["model_name"] for row in result["data"]["results"]] == [ | |
| "Model B", | |
| "Model A", | |
| ] | |
| assert [call["page"] for call in evaluation_calls] == [1, 2] | |
| def test_benchmark_detail_filters_sorts_and_computes_pareto_frontier( | |
| monkeypatch, capsys | |
| ): | |
| benchmark_payload = { | |
| "count": 1, | |
| "results": [{"id": "6", "name": "COCO", "slug": "coco"}], | |
| } | |
| evaluation_pages = { | |
| 1: { | |
| "count": 3, | |
| "results": [ | |
| { | |
| "id": "1", | |
| "paper_id": "1", | |
| "task_id": "3", | |
| "dataset_id": "6", | |
| "model_name": "Accurate", | |
| "metrics": {"mAP": 60, "FPS": 30}, | |
| "best_rank": 1, | |
| }, | |
| { | |
| "id": "2", | |
| "paper_id": "2", | |
| "task_id": "3", | |
| "dataset_id": "6", | |
| "model_name": "Fast", | |
| "metrics": {"mAP": "58", "FPS": "100"}, | |
| "best_rank": 2, | |
| }, | |
| ], | |
| }, | |
| 2: { | |
| "count": 3, | |
| "results": [ | |
| { | |
| "id": "3", | |
| "paper_id": "3", | |
| "task_id": "3", | |
| "dataset_id": "6", | |
| "model_name": "Dominated", | |
| "metrics": {"mAP": 57, "FPS": 50}, | |
| "best_rank": 3, | |
| } | |
| ], | |
| }, | |
| } | |
| calls = [] | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params): | |
| calls.append((path, params)) | |
| if path == "datasets/": | |
| return Response(json.dumps(benchmark_payload).encode(), {}) | |
| return Response(json.dumps(evaluation_pages[params["page"]]).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| assert ( | |
| main( | |
| [ | |
| "benchmark", | |
| "--name", | |
| "COCO", | |
| "--pareto", | |
| "mAP:higher,FPS:higher", | |
| "--sort", | |
| "FPS:desc", | |
| ] | |
| ) | |
| == 0 | |
| ) | |
| captured = capsys.readouterr() | |
| assert captured.err == "" | |
| assert ( | |
| "Showing 2 of 2 matching merged rows from 3 stored evaluation rows." | |
| in captured.out | |
| ) | |
| assert captured.out.index("Fast") < captured.out.index("Accurate") | |
| assert "Dominated" not in captured.out | |
| assert [params["page"] for path, params in calls if path != "datasets/"] == [1, 2] | |
| def test_benchmark_detail_metric_thresholds_and_unknown_metric(monkeypatch, capsys): | |
| benchmark_payload = { | |
| "count": 1, | |
| "results": [{"id": "6", "name": "COCO", "slug": "coco"}], | |
| } | |
| evaluations_payload = { | |
| "count": 2, | |
| "results": [ | |
| { | |
| "paper_id": "1", | |
| "task_id": "3", | |
| "dataset_id": "6", | |
| "model_name": "Fast", | |
| "metrics": {"mAP": 58, "FPS": 100}, | |
| }, | |
| { | |
| "paper_id": "2", | |
| "task_id": "3", | |
| "dataset_id": "6", | |
| "model_name": "Slow", | |
| "metrics": {"mAP": 62, "FPS": 20}, | |
| }, | |
| ], | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, _params): | |
| payload = benchmark_payload if path == "datasets/" else evaluations_payload | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| assert ( | |
| main( | |
| [ | |
| "benchmark", | |
| "--name", | |
| "COCO", | |
| "--require-metrics", | |
| "mAP,FPS", | |
| "--min", | |
| "FPS=60", | |
| "--max", | |
| "mAP=60", | |
| ] | |
| ) | |
| == 0 | |
| ) | |
| captured = capsys.readouterr() | |
| assert "Fast" in captured.out | |
| assert "Slow" not in captured.out | |
| assert main(["benchmark", "--name", "COCO", "--sort", "Latency"]) == 2 | |
| captured = capsys.readouterr() | |
| assert captured.out == "" | |
| assert "unknown metric(s): latency; available metrics: FPS, mAP" in captured.err | |
| def test_top_level_version_is_offline_and_stable(): | |
| output = io.StringIO() | |
| with redirect_stdout(output): | |
| try: | |
| build_parser().parse_args(["--version"]) | |
| except SystemExit as error: | |
| assert error.code == 0 | |
| assert output.getvalue() == "pwc 0.4.6\tapi v1\n" | |
| def test_search_default_output_is_compact_deterministic_tsv(monkeypatch): | |
| payload = { | |
| "count": 1, | |
| "results": [ | |
| { | |
| "arxiv_id": "2501.01234", | |
| "title": "Line one\nline two", | |
| "published": "2025-01-03", | |
| "citation_count": 42, | |
| "has_official_implementation": True, | |
| "code_repository_count": 3, | |
| } | |
| ], | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, _path, _params): | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output = io.StringIO() | |
| with redirect_stdout(output): | |
| assert main(["search", "vision"]) == 0 | |
| assert output.getvalue() == ( | |
| "id\ttitle\tyear\tcitations\n2501.01234\tLine one\\nline two\t2025\t42\n" | |
| ) | |
| output = io.StringIO() | |
| with redirect_stdout(output): | |
| assert main(["search", "vision", "--implementation-coverage"]) == 0 | |
| assert output.getvalue() == ( | |
| "id\ttitle\tyear\tcitations\tofficial_implementation\tcode_repositories\n" | |
| "2501.01234\tLine one\\nline two\t2025\t42\ttrue\t3\n" | |
| ) | |
| def test_search_official_implementation_filter_is_forwarded_and_fail_closed( | |
| monkeypatch, capsys | |
| ): | |
| calls = [] | |
| payloads = [ | |
| {"results": [], "applied_filters": {}}, | |
| { | |
| "results": [], | |
| "applied_filters": {"has_official_implementation": "true"}, | |
| }, | |
| ] | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params): | |
| calls.append((path, params)) | |
| return Response(json.dumps(payloads.pop(0)).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| command = ["search", "vision", "--has-official-implementation"] | |
| assert main(command) == 4 | |
| assert "did not confirm has_official_implementation" in capsys.readouterr().err | |
| assert main(command) == 0 | |
| capsys.readouterr() | |
| assert calls[0][0] == "papers/search" | |
| assert calls[0][1]["has_official_implementation"] is True | |
| def test_paper_list_forwards_confirmed_official_implementation_filter(monkeypatch): | |
| calls = [] | |
| payload = { | |
| "results": [], | |
| "applied_filters": {"has_official_implementation": "true"}, | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params): | |
| calls.append((path, params)) | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| assert main(["paper", "list", "--has-official-implementation"]) == 0 | |
| assert calls[0][0] == "papers/" | |
| assert calls[0][1]["has_official_implementation"] is True | |
| def test_all_paper_commands_resolve_exact_titles(monkeypatch): | |
| title = "Transformers Are RNNs" | |
| resolved = "2006.16236" | |
| search_payload = { | |
| "count": 1, | |
| "results": [{"arxiv_id": resolved, "title": title}], | |
| } | |
| calls = [] | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| calls.append((path, params)) | |
| if path == "papers/search": | |
| return Response(json.dumps(search_payload).encode(), {}) | |
| if path == f"papers/{resolved}": | |
| return Response( | |
| json.dumps({"arxiv_id": resolved, "title": title}).encode(), {} | |
| ) | |
| if path == f"research/papers/{resolved}/read": | |
| return Response(b"# Paper", {}) | |
| if path == f"papers/{resolved}/related": | |
| return Response(b'{"count":0,"results":[]}', {}) | |
| if path == f"research/papers/{resolved}/lineage": | |
| return Response( | |
| json.dumps( | |
| { | |
| "paper": {"reference": resolved, "title": title}, | |
| "predecessors": [], | |
| "successors": [], | |
| } | |
| ).encode(), | |
| {}, | |
| ) | |
| raise AssertionError(path) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| commands = ( | |
| ( | |
| ["paper", "info", title.lower()], | |
| (f"papers/{resolved}", {"include_resources": False}), | |
| ), | |
| ( | |
| ["paper", "read", title.lower()], | |
| (f"research/papers/{resolved}/read", None), | |
| ), | |
| ( | |
| ["paper", "related", title.lower()], | |
| (f"papers/{resolved}/related", {"limit": 4}), | |
| ), | |
| ( | |
| ["paper", "lineage", "list", title.lower()], | |
| (f"research/papers/{resolved}/lineage", None), | |
| ), | |
| ) | |
| for argv, expected_request in commands: | |
| calls.clear() | |
| with redirect_stdout(io.StringIO()): | |
| assert main(argv) == 0 | |
| assert calls == [ | |
| ( | |
| "papers/search", | |
| { | |
| "q": title.lower(), | |
| "page": 1, | |
| "page_size": 20, | |
| "mode": "keyword", | |
| }, | |
| ), | |
| expected_request, | |
| ] | |
| def test_ambiguous_paper_title_is_rejected_with_matches(monkeypatch): | |
| title = "A Shared Title" | |
| payload = { | |
| "count": 2, | |
| "results": [ | |
| {"arxiv_id": "2501.00001", "title": title}, | |
| {"arxiv_id": "2501.00002", "title": title}, | |
| ], | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| assert path == "papers/search" | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| errors = io.StringIO() | |
| with redirect_stderr(errors): | |
| assert main(["paper", "info", title]) == 4 | |
| assert errors.getvalue() == ( | |
| "pwc: Paper title is ambiguous: A Shared Title; " | |
| "A Shared Title (2501.00001); A Shared Title (2501.00002)\n" | |
| ) | |
| def test_paper_info_renders_metadata_and_abstract_sections(monkeypatch): | |
| payload = { | |
| "arxiv_id": "2501.01234", | |
| "title": "A Paper", | |
| "abstract": "First line.\nSecond line.", | |
| "published": "2025-01-03", | |
| "authors": ["Ada Researcher", "Grace Scientist"], | |
| "organizations": [{"id": "1", "name": "Example AI", "slug": "example"}], | |
| "citation_count": 42, | |
| "has_official_implementation": False, | |
| "code_repository_count": 2, | |
| "url_abs": "https://paperswithcode.co/paper/2501.01234", | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, _path, _params): | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output = io.StringIO() | |
| with redirect_stdout(output): | |
| assert main(["paper", "info", "2501.01234"]) == 0 | |
| assert output.getvalue() == ( | |
| "id: 2501.01234\n" | |
| "title: A Paper\n" | |
| "published: 2025-01-03\n" | |
| "authors: Ada Researcher, Grace Scientist\n" | |
| "organizations: Example AI\n" | |
| "citations: 42\n" | |
| "official_implementation: false\n" | |
| "code_repositories: 2\n" | |
| "url: https://paperswithcode.co/paper/2501.01234\n" | |
| "\n" | |
| "## Abstract\n" | |
| "\n" | |
| "First line.\n" | |
| "Second line.\n" | |
| "\n" | |
| "## Paper lineage\n" | |
| "\n" | |
| "### Predecessors\n" | |
| "\n" | |
| "- None\n" | |
| "\n" | |
| "### Successors\n" | |
| "\n" | |
| "- None\n" | |
| ) | |
| def test_paper_info_renders_linked_lineage_sections(monkeypatch): | |
| payload = { | |
| "arxiv_id": "2501.01234", | |
| "title": "A Paper", | |
| "predecessor_papers": [ | |
| { | |
| "title": "Earlier [Paper]", | |
| "route_identifier": "2401.00001", | |
| "published": "2024-01-02", | |
| } | |
| ], | |
| "successor_papers": [ | |
| { | |
| "title": "Later Paper", | |
| "route_identifier": "2601.00001", | |
| "published": None, | |
| } | |
| ], | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, _path, _params): | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output = io.StringIO() | |
| with redirect_stdout(output): | |
| assert main(["paper", "info", "2501.01234"]) == 0 | |
| assert output.getvalue().endswith( | |
| "\n## Paper lineage\n\n" | |
| "### Predecessors\n\n" | |
| "- [Earlier \\[Paper\\]](https://paperswithcode.co/paper/2401.00001)" | |
| " (2024-01-02)\n\n" | |
| "### Successors\n\n" | |
| "- [Later Paper](https://paperswithcode.co/paper/2601.00001)\n" | |
| ) | |
| def test_paper_info_renders_linked_resources_when_requested(monkeypatch): | |
| calls = [] | |
| payload = { | |
| "arxiv_id": "2501.01234", | |
| "title": "A Paper", | |
| "has_official_implementation": True, | |
| "code_repository_count": 2, | |
| "repositories": [ | |
| {"url": "https://github.com/example/implementation", "is_official": False}, | |
| {"url": "https://github.com/example/official", "is_official": True}, | |
| ], | |
| "project_pages": [ | |
| {"url": "https://example.org/community", "is_official": False}, | |
| {"url": "https://example.org/project", "is_official": True}, | |
| ], | |
| "hf_models": ["https://huggingface.co/example/model"], | |
| "hf_datasets": ["https://huggingface.co/datasets/example/data"], | |
| "hf_spaces": ["https://huggingface.co/spaces/example/demo"], | |
| "x_threads": [ | |
| { | |
| "url": "https://x.com/author/status/123", | |
| "author_name": "Ada Author", | |
| "author_handle": "author", | |
| } | |
| ], | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params): | |
| calls.append((path, params)) | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output = io.StringIO() | |
| with redirect_stdout(output): | |
| assert main(["paper", "info", "2501.01234", "--include-resources"]) == 0 | |
| assert calls == [ | |
| ("papers/2501.01234", {"include_resources": True}), | |
| ] | |
| assert output.getvalue() == ( | |
| "id: 2501.01234\n" | |
| "title: A Paper\n" | |
| "official_implementation: true\n" | |
| "code_repositories: 2\n" | |
| "\n" | |
| "## Paper lineage\n" | |
| "\n" | |
| "### Predecessors\n" | |
| "\n" | |
| "- None\n" | |
| "\n" | |
| "### Successors\n" | |
| "\n" | |
| "- None\n" | |
| "\n" | |
| "## Repositories\n" | |
| "\n" | |
| "- **Official:** https://github.com/example/official\n" | |
| "- https://github.com/example/implementation\n" | |
| "\n" | |
| "## Project pages\n" | |
| "\n" | |
| "- **Official:** https://example.org/project\n" | |
| "- https://example.org/community\n" | |
| "\n" | |
| "## Hugging Face artifacts\n" | |
| "\n" | |
| "- **Model:** https://huggingface.co/example/model\n" | |
| "- **Dataset:** https://huggingface.co/datasets/example/data\n" | |
| "- **Space:** https://huggingface.co/spaces/example/demo\n" | |
| "\n" | |
| "## X threads\n" | |
| "\n" | |
| "- **Ada Author (@author):** https://x.com/author/status/123\n" | |
| ) | |
| def test_paper_info_include_evals_renders_paginated_markdown_table(monkeypatch): | |
| calls = [] | |
| paper_payload = { | |
| "id": "9", | |
| "arxiv_id": "2607.24653", | |
| "title": "An Evaluated Paper", | |
| } | |
| evaluation_rows = [ | |
| { | |
| "id": "1", | |
| "paper_id": "9", | |
| "model_name": "Agent | One", | |
| "metrics": {"Resolved": 55.5}, | |
| "best_metric": "Resolved", | |
| "best_rank": 1, | |
| "task_name": "Coding Agents", | |
| "dataset_name": "SWE-Bench Pro", | |
| "is_open": True, | |
| "result_url": "https://example.test/result-one", | |
| }, | |
| { | |
| "id": "2", | |
| "paper_id": "9", | |
| "model_name": "Agent Two", | |
| "harness": "verified", | |
| "metrics": {"Accuracy": 50}, | |
| "best_metric": "Accuracy", | |
| "best_rank": None, | |
| "task_name": "Agents", | |
| "dataset_name": "Toolathlon", | |
| "is_open": False, | |
| "source_url": "https://example.test/result-two", | |
| }, | |
| ] | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params): | |
| calls.append((path, params)) | |
| if path.startswith("papers/"): | |
| payload = paper_payload | |
| else: | |
| payload = { | |
| "count": 2, | |
| "results": [evaluation_rows[params["page"] - 1]], | |
| } | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output = io.StringIO() | |
| with redirect_stdout(output): | |
| assert main(["paper", "info", "2607.24653", "--include-evals"]) == 0 | |
| assert calls == [ | |
| ("papers/2607.24653", {"include_resources": False}), | |
| ( | |
| "evaluations/", | |
| { | |
| "page": 1, | |
| "page_size": 100, | |
| "paper_id": "9", | |
| "ordering": "-benchmark_popularity", | |
| }, | |
| ), | |
| ( | |
| "evaluations/", | |
| { | |
| "page": 2, | |
| "page_size": 100, | |
| "paper_id": "9", | |
| "ordering": "-benchmark_popularity", | |
| }, | |
| ), | |
| ] | |
| rendered = output.getvalue() | |
| assert "\n## Evaluations\n" in rendered | |
| assert "| Benchmark | Model | Scores | Rank | Task | Open | Source |" in rendered | |
| assert "Agent \\| One" in rendered | |
| assert "Resolved: 55.5" in rendered | |
| assert "Agent Two (verified)" in rendered | |
| assert ( | |
| "| — | Agents | no | [source](<https://example.test/result-two>) |" in rendered | |
| ) | |
| def test_paper_info_include_evals_adds_structured_json(monkeypatch): | |
| calls = [] | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params): | |
| calls.append((path, params)) | |
| payload = ( | |
| {"id": "9", "arxiv_id": "2607.24653", "title": "Paper"} | |
| if path.startswith("papers/") | |
| else {"count": 0, "results": []} | |
| ) | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output = io.StringIO() | |
| with redirect_stdout(output): | |
| assert main(["paper", "info", "2607.24653", "--include-evals", "--json"]) == 0 | |
| data = json.loads(output.getvalue())["data"] | |
| assert data["evaluations"] == {"count": 0, "results": []} | |
| assert calls[-1][0] == "evaluations/" | |
| def test_paper_lineage_renders_linked_markdown_sections(monkeypatch): | |
| payload = { | |
| "paper": { | |
| "reference": "2307.09288", | |
| "title": "Llama 2: Open Foundation and Fine-Tuned Chat Models", | |
| }, | |
| "predecessors": [ | |
| { | |
| "reference": "2302.13971", | |
| "title": "LLaMA: Open and Efficient Foundation Language Models", | |
| } | |
| ], | |
| "successors": [], | |
| } | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path): | |
| assert path == "research/papers/2307.09288/lineage" | |
| return Response(json.dumps(payload).encode(), {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output = io.StringIO() | |
| with redirect_stdout(output): | |
| assert main(["paper", "lineage", "list", "2307.09288"]) == 0 | |
| assert output.getvalue() == ( | |
| "# Paper lineage\n" | |
| "\n" | |
| "## Paper\n" | |
| "\n" | |
| "- [Llama 2: Open Foundation and Fine-Tuned Chat Models]" | |
| "(https://paperswithcode.co/paper/2307.09288) (`2307.09288`)\n" | |
| "\n" | |
| "## Predecessors\n" | |
| "\n" | |
| "- [LLaMA: Open and Efficient Foundation Language Models]" | |
| "(https://paperswithcode.co/paper/2302.13971) (`2302.13971`)\n" | |
| "\n" | |
| "## Successors\n" | |
| "\n" | |
| "- None\n" | |
| ) | |
| def test_json_schema_and_errors_use_stable_streams(monkeypatch): | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, _path, _params): | |
| return Response(b'{"count":0,"results":[]}', {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output = io.StringIO() | |
| errors = io.StringIO() | |
| with redirect_stdout(output), redirect_stderr(errors): | |
| assert main(["search", "none", "--json"]) == 0 | |
| assert json.loads(output.getvalue())["schema_version"] == "v1" | |
| assert errors.getvalue() == "" | |
| def test_paper_read_supports_markdown_and_versioned_json(monkeypatch): | |
| paths = [] | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| paths.append((path, params)) | |
| return Response(b"# Paper\n\nBody", {}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output = io.StringIO() | |
| with redirect_stdout(output): | |
| assert main(["paper", "read", "2501.01234"]) == 0 | |
| assert output.getvalue() == "# Paper\n\nBody\n" | |
| output = io.StringIO() | |
| with redirect_stdout(output): | |
| assert main(["paper", "read", "2501.01234", "--json"]) == 0 | |
| payload = json.loads(output.getvalue()) | |
| assert payload == { | |
| "schema_version": "v1", | |
| "data": {"paper": "2501.01234", "markdown": "# Paper\n\nBody"}, | |
| } | |
| assert paths == [ | |
| ("research/papers/2501.01234/read", None), | |
| ("research/papers/2501.01234/read", None), | |
| ] | |
| def test_transport_is_anonymous_by_default(monkeypatch): | |
| requests = [] | |
| class HTTPResponse(io.BytesIO): | |
| headers = {} | |
| def __enter__(self): | |
| return self | |
| def __exit__(self, *_args): | |
| self.close() | |
| def fake_urlopen(request, *, timeout): | |
| requests.append(request) | |
| assert timeout == 30 | |
| return HTTPResponse(b"# Public paper\n") | |
| monkeypatch.delenv("PWC_API_URL", raising=False) | |
| monkeypatch.setattr(urllib.request, "urlopen", fake_urlopen) | |
| response = Client("https://example.test/api/v1").get( | |
| "research/papers/2501.01234/read" | |
| ) | |
| assert response.body == b"# Public paper\n" | |
| assert requests[0].full_url.endswith("/api/v1/research/papers/2501.01234/read") | |
| assert requests[0].get_header("Authorization") is None | |
| def test_transport_timeout_is_configurable_without_changing_the_default(monkeypatch): | |
| observed = [] | |
| class HTTPResponse(io.BytesIO): | |
| headers = {} | |
| def __enter__(self): | |
| return self | |
| def __exit__(self, *_args): | |
| self.close() | |
| def fake_urlopen(_request, *, timeout): | |
| observed.append(timeout) | |
| return HTTPResponse(b"{}") | |
| monkeypatch.setattr(urllib.request, "urlopen", fake_urlopen) | |
| Client("https://example.test/api/v1", timeout=25).get("health") | |
| Client("https://example.test/api/v1").get("health") | |
| assert observed == [25, 30] | |
| def test_transport_encodes_repeated_query_parameters(monkeypatch): | |
| requests = [] | |
| class HTTPResponse(io.BytesIO): | |
| headers = {} | |
| def __enter__(self): | |
| return self | |
| def __exit__(self, *_args): | |
| self.close() | |
| def fake_urlopen(request, *, timeout): | |
| requests.append(request) | |
| return HTTPResponse(b'{"count":0,"results":[]}') | |
| monkeypatch.setattr(urllib.request, "urlopen", fake_urlopen) | |
| Client("https://example.test/api/v1").get( | |
| "papers/", {"author": ["Kaiming He", "@yilundu"]} | |
| ) | |
| assert requests[0].full_url.endswith( | |
| "/api/v1/papers/?author=Kaiming+He&author=%40yilundu" | |
| ) | |
| def test_transport_reports_read_timeouts_and_socket_errors_as_transport_errors( | |
| monkeypatch, | |
| ): | |
| from pwc_cli.transport import TransportError | |
| failures = iter([TimeoutError("The read operation timed out"), ConnectionResetError(104, "reset")]) | |
| def fake_urlopen(_request, *, timeout): | |
| raise next(failures) | |
| monkeypatch.setattr(urllib.request, "urlopen", fake_urlopen) | |
| client = Client("https://example.test/api/v1") | |
| with pytest.raises(TransportError, match="timed out"): | |
| client.get("health") | |
| with pytest.raises(TransportError, match="API request failed"): | |
| client.get("health") | |
| def test_closest_results_rank_by_shared_words_not_search_order(): | |
| from pwc_cli.cli import _closest_names, _exact_entity_match | |
| candidates = [ | |
| {"name": "Spoken Language Identification"}, | |
| {"name": "Face Recognition"}, | |
| {"name": "Person Re-Identification (Video)"}, | |
| {"name": "Unsupervised Person Re-Identification"}, | |
| {"name": "Image Classification"}, | |
| ] | |
| assert _closest_names("person re-identification", candidates) == ( | |
| "Person Re-Identification (Video), Unsupervised Person Re-Identification" | |
| ) | |
| with pytest.raises(ResponseError, match="closest results: Person Re-Identification"): | |
| _exact_entity_match("person re-identification", candidates, label="Task") | |
| def test_closest_results_omit_unrelated_candidates(): | |
| from pwc_cli.cli import _closest_names, _exact_entity_match | |
| # Production chat: "FaceNet" suggested WaveNet, and "person | |
| # re-identification" suggested Spoken Language Identification. | |
| assert _closest_names("FaceNet", [{"name": "WaveNet"}, {"name": "ResNet"}]) == "" | |
| assert ( | |
| _closest_names( | |
| "person re-identification", | |
| [{"name": "Spoken Language Identification"}, {"name": "Face Recognition"}], | |
| ) | |
| == "" | |
| ) | |
| with pytest.raises(ResponseError) as error: | |
| _exact_entity_match("FaceNet", [{"name": "WaveNet"}], label="Method") | |
| assert str(error.value) == "Method not found: FaceNet" | |
| # Near spellings and containment still produce a hint. | |
| assert _closest_names("Transfomer", [{"name": "Transformer"}]) == "Transformer" | |
| assert _closest_names("ViT", [{"name": "ViTDet"}]) == "" | |
| assert _closest_names("Swin", [{"name": "Swin Transformer"}]) == "Swin Transformer" | |
| def test_metric_requests_resolve_through_case_and_common_aliases(): | |
| from pwc_cli.cli import _resolve_metric_name, _select_metric_rows | |
| available = {"map": "mAP", "fps": "FPS", "top 1 accuracy": "Top 1 Accuracy"} | |
| assert _resolve_metric_name("AP", available) == "mAP" | |
| assert _resolve_metric_name("box ap", available) == "mAP" | |
| assert _resolve_metric_name("top1", available) == "Top 1 Accuracy" | |
| assert _resolve_metric_name("Top-1 Accuracy", available) == "Top 1 Accuracy" | |
| assert _resolve_metric_name("fps", available) == "FPS" | |
| assert _resolve_metric_name("latency", available) is None | |
| rows = [ | |
| {"model_name": "Fast", "metrics": {"mAP": 58, "FPS": 100}}, | |
| {"model_name": "Slow", "metrics": {"mAP": 62, "FPS": 20}}, | |
| ] | |
| args = argparse.Namespace( | |
| require_metrics=["ap"], | |
| minimum_metrics=[("AP", 60)], | |
| maximum_metrics=[], | |
| sort_metric=("ap", "desc"), | |
| pareto=[], | |
| ) | |
| assert [row["model_name"] for row in _select_metric_rows(rows, args)] == ["Slow"] | |
| assert args.sort_metric == ("mAP", "desc") | |
| assert args.minimum_metrics == [("mAP", 60)] | |
| unknown = argparse.Namespace( | |
| require_metrics=[], | |
| minimum_metrics=[], | |
| maximum_metrics=[], | |
| sort_metric=("latency", "desc"), | |
| pareto=[], | |
| ) | |
| with pytest.raises(UsageError, match="unknown metric\\(s\\): latency; available metrics: FPS, mAP"): | |
| _select_metric_rows(rows, unknown) | |
| def test_metric_requests_resolve_by_containment_and_alias_containment(): | |
| from pwc_cli.cli import _resolve_metric_name | |
| # Requests seen from chat agents against production leaderboards. | |
| assert ( | |
| _resolve_metric_name("D4RL Normalized Score", {"normalized score": "Normalized Score"}) | |
| == "Normalized Score" | |
| ) | |
| assert _resolve_metric_name("Overall", {"geneval score": "GenEval Score"}) == "GenEval Score" | |
| assert _resolve_metric_name("Score", {"dpg-bench score": "DPG-Bench Score"}) == "DPG-Bench Score" | |
| assert _resolve_metric_name("Pass@1", {"accuracy": "Accuracy"}) == "Accuracy" | |
| assert _resolve_metric_name("Pass Rate", {"success rate": "Success Rate"}) == "Success Rate" | |
| mvtec = { | |
| "detection auroc": "Detection AUROC", | |
| "segmentation auroc": "Segmentation AUROC", | |
| "detection ap": "Detection AP", | |
| } | |
| assert _resolve_metric_name("image-level AUROC", mvtec) == "Detection AUROC" | |
| assert _resolve_metric_name("pixel-level AUROC", mvtec) == "Segmentation AUROC" | |
| # Ambiguous or unrelated requests still surface the leaderboard's names. | |
| assert _resolve_metric_name("AUROC", mvtec) is None | |
| assert ( | |
| _resolve_metric_name( | |
| "F-score", | |
| {"mean f1 (advanced)": "Mean F1 (Advanced)", "mean f1 (intermediate)": "Mean F1 (Intermediate)"}, | |
| ) | |
| is None | |
| ) | |
| assert _resolve_metric_name("latency", {"map": "mAP"}) is None | |
| def test_entity_names_match_ignoring_punctuation_and_trailing_acronyms(): | |
| from pwc_cli.cli import _exact_entity_match, _task_match, _without_abbreviation | |
| methods = [ | |
| {"name": "Mixture-of-Experts (MoE)", "slug": "moe"}, | |
| {"name": "Vision Transformer (ViT)", "slug": "vit"}, | |
| ] | |
| assert _exact_entity_match("mixture of experts", methods, label="Method")["slug"] == "moe" | |
| assert _exact_entity_match("vision transformer", methods, label="Method")["slug"] == "vit" | |
| with pytest.raises(ResponseError, match="Method not found: experts"): | |
| _exact_entity_match("experts", methods, label="Method") | |
| tasks = [ | |
| {"name": "Time Series Forecasting", "slug": "time-series-forecasting"}, | |
| {"name": "Person Re-Identification (Video)", "slug": "person-re-identification-video"}, | |
| {"name": "Unsupervised Person Re-Identification", "slug": "unsupervised-person-re-identification"}, | |
| ] | |
| assert _task_match("time-series forecasting", tasks)["slug"] == "time-series-forecasting" | |
| # "(Video)" qualifies the task instead of abbreviating it, so the bare name | |
| # must not silently pick the video variant. | |
| assert _task_match("person re-identification", tasks) is None | |
| # Two candidates that normalize alike stay unresolved. | |
| assert ( | |
| _task_match( | |
| "image-classification", | |
| [{"name": "Image Classification"}, {"name": "Image, Classification"}], | |
| ) | |
| is None | |
| ) | |
| assert ( | |
| _without_abbreviation("Physics-Informed Neural Networks (PINNs)") | |
| == "Physics-Informed Neural Networks" | |
| ) | |
| assert _without_abbreviation("Aspect-Based Sentiment Analysis (ABSA)") == "Aspect-Based Sentiment Analysis" | |
| assert _without_abbreviation("Person Re-Identification (Video)") is None | |
| assert _without_abbreviation("MVTec AD (Unified Multi-Class)") is None | |
| assert _without_abbreviation("Knowledge Distillation") is None | |
| PUBLIC_METADATA = { | |
| "in_catalog": False, | |
| "catalog_id": None, | |
| "catalog_url": None, | |
| "metadata_source": "huggingface", | |
| "note": "Not indexed on Papers With Code.", | |
| "id": "2610.18869", | |
| "arxiv_id": "2610.18869", | |
| "doi": None, | |
| "title": "A Paper Outside The Catalog", | |
| "authors": ["Ada Lovelace", "Alan Turing"], | |
| "abstract": "An abstract.", | |
| "published": "2026-10-12", | |
| "url": "https://arxiv.org/abs/2610.18869", | |
| "pdf_url": "https://arxiv.org/pdf/2610.18869", | |
| "hf_url": "https://huggingface.co/papers/2610.18869", | |
| "repositories": [], | |
| "project_pages": [], | |
| "available_at": [ | |
| {"label": "arXiv", "url": "https://arxiv.org/abs/2610.18869", "kind": "abstract"}, | |
| {"label": "Hugging Face Papers", "url": "https://huggingface.co/papers/2610.18869", "kind": "huggingface"}, | |
| ], | |
| } | |
| def _outside_catalog_client(public): | |
| paths = [] | |
| class Client: | |
| def __init__(self): | |
| pass | |
| def get(self, path, params=None): | |
| paths.append(path) | |
| if path.endswith("/public-metadata"): | |
| if path in public: | |
| return Response(json.dumps(public[path]).encode(), {}) | |
| raise HTTPStatusError(404, '{"detail":"Paper not found"}') | |
| if path in {"papers/1706.03762", "research/papers/1706.03762/read"}: | |
| if path.endswith("/read"): | |
| return Response(b"# Attention\n", {}) | |
| return Response( | |
| json.dumps({"id": "755", "title": "Attention Is All You Need"}).encode(), | |
| {}, | |
| ) | |
| if path == "papers/search": | |
| return Response(json.dumps({"results": []}).encode(), {}) | |
| raise HTTPStatusError(404, '{"detail":"Paper not found"}') | |
| return Client, paths | |
| def test_paper_outside_the_catalog_shows_where_it_is_available( | |
| monkeypatch, command, json_flag | |
| ): | |
| Client, paths = _outside_catalog_client( | |
| {"papers/2610.18869/public-metadata": PUBLIC_METADATA} | |
| ) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output, errors = io.StringIO(), io.StringIO() | |
| with redirect_stdout(output), redirect_stderr(errors): | |
| # The exit status and stdout of a miss are unchanged for scripts. | |
| assert main(["paper", command, "2610.18869", *json_flag]) == 3 | |
| assert output.getvalue() == "" | |
| assert errors.getvalue() == ( | |
| "Not indexed on Papers With Code — available at:\n" | |
| "- arXiv: https://arxiv.org/abs/2610.18869\n" | |
| "- Hugging Face Papers: https://huggingface.co/papers/2610.18869\n" | |
| "\n" | |
| "title: A Paper Outside The Catalog\n" | |
| "published: 2026-10-12\n" | |
| "authors: Ada Lovelace, Alan Turing\n" | |
| "metadata_source: huggingface\n" | |
| "\n" | |
| "## Abstract\n" | |
| "\n" | |
| "An abstract.\n" | |
| "\n" | |
| 'pwc: API request failed (404): {"detail":"Paper not found"}\n' | |
| ) | |
| assert paths[-1] == "papers/2610.18869/public-metadata" | |
| def test_paper_title_outside_the_catalog_keeps_its_exit_status(monkeypatch): | |
| path = "papers/Some%20Unindexed%20Title/public-metadata" | |
| Client, _paths = _outside_catalog_client({path: PUBLIC_METADATA}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| errors = io.StringIO() | |
| with redirect_stdout(io.StringIO()), redirect_stderr(errors): | |
| assert main(["paper", "info", "Some Unindexed Title"]) == 4 | |
| assert errors.getvalue().startswith("Not indexed on Papers With Code — available at:\n") | |
| assert errors.getvalue().endswith( | |
| "pwc: Paper title not found: Some Unindexed Title\n" | |
| ) | |
| def test_paper_unknown_everywhere_keeps_the_plain_error(monkeypatch): | |
| Client, paths = _outside_catalog_client({}) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| errors = io.StringIO() | |
| with redirect_stdout(io.StringIO()), redirect_stderr(errors): | |
| assert main(["paper", "info", "2610.99999"]) == 3 | |
| assert errors.getvalue() == ( | |
| 'pwc: API request failed (404): {"detail":"Paper not found"}\n' | |
| ) | |
| assert paths == ["papers/2610.99999", "papers/2610.99999/public-metadata"] | |
| def test_paper_reference_the_api_finds_in_the_catalog_is_retried( | |
| monkeypatch, command, expected | |
| ): | |
| # The CLI resolves only IDs and titles; the API also maps arXiv URLs. | |
| url = "https://arxiv.org/abs/1706.03762v7" | |
| record = {**PUBLIC_METADATA, "in_catalog": True, "catalog_id": "755", | |
| "arxiv_id": "1706.03762"} | |
| Client, _paths = _outside_catalog_client( | |
| {f"papers/{url}/public-metadata": record} | |
| ) | |
| monkeypatch.setattr("pwc_cli.cli.Client", Client) | |
| output, errors = io.StringIO(), io.StringIO() | |
| with redirect_stdout(output), redirect_stderr(errors): | |
| assert main(["paper", command, url]) == 0 | |
| assert expected in output.getvalue() | |
| assert errors.getvalue() == "" | |
| def test_embedded_paper_queries_do_not_call_the_public_metadata_api(): | |
| from pwc_cli.queries import query | |
| Client, paths = _outside_catalog_client( | |
| {"papers/2610.18869/public-metadata": PUBLIC_METADATA} | |
| ) | |
| with pytest.raises(HTTPStatusError): | |
| query(("paper", "info"), {"paper": "2610.18869"}, Client()) | |
| assert not any(path.endswith("/public-metadata") for path in paths) | |