d87e7fe7e9
* fix(ci): stop redownloading the playwright browser on every run The cache key hashed uv.lock, but the browser revision is chosen by the installed playwright version, and pip resolved that version from pyproject.toml. Playwright sat in a PEP 735 [dependency-groups] table that pip cannot read, so `pip install -e ".[dev]" playwright` pulled an unpinned latest release whose revision was never in the restored cache. The prefix fallback then hid the miss instead of correcting it: uv.lock's hash never changed, so the exact key always hit, actions/cache skipped the post-step save, and restore-keys handed back a directory missing the current revision. The download repeated on every run, taking a median of 20 minutes. Pin playwright in [project.optional-dependencies] where pip can read it, hash that file for the cache key, and drop the fallback. Keep the PEP 735 group as an alias so `uv run` and pip resolve the same set. Split the install so system libraries land unconditionally and only the browser download is gated on the cache hit. * test: skip browser tests when chromium is missing, not just playwright The five gated files only checked whether the playwright package imports. That was enough while playwright lived in a group pip ignores, so the import itself was absent wherever the browser was. Now that it ships in [dev], the package installs in the test matrix while the browser does not, and 116 tests would hard-fail on a missing executable instead of skipping. Probe the chromium binary too, in one shared helper so all five files report the same reason. * fix(scripts): let the coverage gate import shared test helpers The gate loads tests/test_viewer_contracts.py through spec_from_file_location, which does not insert the repo root that pytest normally provides. A `from tests.conftest import ...` in that file therefore raised ModuleNotFoundError and killed the whole gate before it measured anything, even though two other test modules already import helpers that way. Put the repo root on sys.path before executing the module. * fix(test): run fake clients on the interpreter running the tests The fake client scripts carry `#!/usr/bin/env python3`, which resolves to whatever python3 is first on PATH. On macOS that is the system 3.9 from the Xcode toolchain, not the 3.13 venv running the suite, so any fake client importing a project dependency died on an unrelated interpreter: test_codex_zstd_request_body could not find backports.zstd, and test_kimi_code_client_reverse_proxy could not find tomllib. Rewrite the shebang to sys.executable in one helper and route all ten write sites through it. * fix(tests): skip browser tests when chromium is absent, not just playwright Moving playwright into the dev extra so pip can read its pin made the import succeed on runners that never download a browser. Guards that only caught ImportError -- and pytest.importorskip -- stopped skipping and started failing: the test matrix installs the package but not chromium, and reported "Executable doesn't exist at .../chromium_headless_shell-1208". Route every file that launches a browser through the shared playwright_skip_reason(), which probes the executable path rather than the import. With PLAYWRIGHT_BROWSERS_PATH pointed at an empty directory the suite goes from 3 failures to 1004 passed, 130 skipped. * test(ci): fail when a browser test file skips the chromium guard The previous fix touched six files found by hand. Discover them by call instead: matching launch/launch_persistent_context on a browser type finds every such file regardless of how it imports or aliases playwright, so a new one cannot quietly reintroduce an import-only guard. A second test asserts the discovery is not vacuous -- an empty match would make the first one pass while checking nothing. * fix(tests): run fake clients through a shell trampoline Embedding sys.executable in the shebang breaks when the checkout lives under a directory containing a space: the kernel does not split that line on quotes, so the path truncates at the space and every fake client becomes unexecutable. Re-exec through /bin/sh, which does parse quotes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
120 lines
3.4 KiB
TOML
120 lines
3.4 KiB
TOML
[project]
|
|
name = "claude-tap"
|
|
dynamic = ["version"]
|
|
description = "Trace AI CLI API requests via local reverse and forward proxies. Inspect system prompts, messages, tools, and token usage."
|
|
requires-python = ">=3.11"
|
|
license = "MIT"
|
|
authors = [{ name = "liaohch3" }]
|
|
readme = "README.md"
|
|
keywords = ["claude", "claude-code", "codex", "grok", "kimi", "cursor", "qoder", "trace", "proxy", "api", "llm", "context-engineering"]
|
|
classifiers = [
|
|
"Development Status :: 4 - Beta",
|
|
"Environment :: Console",
|
|
"Intended Audience :: Developers",
|
|
"Programming Language :: Python :: 3",
|
|
"Programming Language :: Python :: 3.11",
|
|
"Programming Language :: Python :: 3.12",
|
|
"Programming Language :: Python :: 3.13",
|
|
"Topic :: Software Development :: Debuggers",
|
|
"Topic :: Software Development :: Testing",
|
|
]
|
|
dependencies = [
|
|
"aiohttp==3.14.1",
|
|
"backports-zstd>=1.0; python_version < '3.14'",
|
|
"cryptography>=42.0",
|
|
]
|
|
|
|
[project.urls]
|
|
Homepage = "https://github.com/liaohch3/claude-tap"
|
|
Repository = "https://github.com/liaohch3/claude-tap"
|
|
Issues = "https://github.com/liaohch3/claude-tap/issues"
|
|
|
|
[project.scripts]
|
|
claude-tap = "claude_tap.cli:main_entry"
|
|
|
|
[build-system]
|
|
requires = ["setuptools>=68.0", "setuptools-scm[toml]>=8.0"]
|
|
build-backend = "setuptools.build_meta"
|
|
|
|
[tool.setuptools]
|
|
packages = ["claude_tap", "claude_tap.viewer_assets"]
|
|
|
|
[tool.setuptools_scm]
|
|
version_scheme = "guess-next-dev"
|
|
local_scheme = "no-local-version"
|
|
|
|
[tool.setuptools.package-data]
|
|
claude_tap = ["dashboard.html", "viewer.html", "viewer_i18n.json", "model_prices.json", "py.typed"]
|
|
"claude_tap.viewer_assets" = ["*.css", "*.js"]
|
|
|
|
[project.optional-dependencies]
|
|
dev = [
|
|
"pytest>=8.0",
|
|
"pytest-asyncio>=0.23",
|
|
"pytest-timeout>=2.3",
|
|
"pexpect>=4.9",
|
|
"coverage>=7.6",
|
|
"matplotlib==3.11.1",
|
|
"ruff>=0.11",
|
|
# Pinned exactly: CI caches ~/.cache/ms-playwright keyed on this file's hash,
|
|
# and each playwright release expects its own browser revision. A floating
|
|
# spec would install a version whose revision is absent from the cache,
|
|
# forcing a fresh browser download on every run.
|
|
"playwright==1.58.0",
|
|
]
|
|
|
|
[tool.ruff]
|
|
target-version = "py311"
|
|
line-length = 120
|
|
|
|
[tool.ruff.lint]
|
|
select = ["E", "F", "W", "I"]
|
|
ignore = ["E501"]
|
|
|
|
[tool.pytest.ini_options]
|
|
asyncio_mode = "auto"
|
|
testpaths = ["tests"]
|
|
python_files = ["test_*.py"]
|
|
python_functions = ["test_*"]
|
|
addopts = [
|
|
"-v",
|
|
"--tb=short",
|
|
"--strict-markers",
|
|
]
|
|
markers = [
|
|
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
|
|
"integration: marks tests as integration tests",
|
|
"asyncio: marks tests as async (run by pytest-asyncio)",
|
|
"real_e2e: marks tests as real E2E tests requiring claude CLI (use --run-real-e2e)",
|
|
]
|
|
timeout = 60
|
|
|
|
[tool.coverage.run]
|
|
source = ["claude_tap"]
|
|
branch = true
|
|
omit = ["tests/*"]
|
|
|
|
[tool.coverage.report]
|
|
exclude_lines = [
|
|
"pragma: no cover",
|
|
"if __name__ == .__main__.:",
|
|
"if TYPE_CHECKING:",
|
|
]
|
|
show_missing = true
|
|
|
|
[tool.claude_tap.coverage]
|
|
python_total_min = 65.0
|
|
python_diff_min = 80.0
|
|
viewer_js_function_min = 50.0
|
|
viewer_js_diff_min = 80.0
|
|
viewer_css_selector_min = 65.0
|
|
viewer_css_diff_min = 80.0
|
|
|
|
[dependency-groups]
|
|
# Kept as a thin alias so `uv run` (which auto-activates this group) and
|
|
# `pip install -e ".[dev]"` install the same set. Declare dev tooling in
|
|
# [project.optional-dependencies] only — pip cannot read PEP 735 groups.
|
|
dev = [
|
|
"claude-tap[dev]",
|
|
]
|