test(read): v4 Live read cassettes + fix unbounded v4 retry-loop#457
Conversation
…454) The 7 v4 Live read commands could not be recorded into VCR cassettes — `pytest --record-mode=rewrite` "hung indefinitely". Root cause was NOT a vcrpy×v4 incompatibility (vcrpy records v4 through the same requests/urllib3 transport as v5; it had recorded v4 cassettes before in 547e837). The real cause: `V4LiveClientAdapter.retry_request` retried request-limit errors (code 54/55) in an UNBOUNDED loop — `time.sleep(10); return True` with no `repeat_number` guard. When the sandbox account lacked v4 rights it returned code 54 ("Not enough rights", which v4 overloads with the rate-limit code), so the adapter looped forever. Changes: - direct_cli/_vendor/tapi_yandex_direct/v4/adapter.py: bound the 54/55 retry branch with the same attempt budget as the server-error branch. Also fixes a real production hang for any caller hitting a persistent code 54/55. NOTE: vendored file — this fix must also land upstream in axisrow/tapi-yandex-direct or it will be lost on the next update_vendor.sh. - tests/test_read_cassettes.py: +6 v4 success cases in READ_CASES (v4goals/v4tags/v4forecast/v4wordstat/v4events/v4finance get-clients-units) +1 dedicated check-payment case asserting the deterministic error_code=370 (non-zero exit). Docstring corrected to drop the false "vcrpy cannot intercept v4" claim. - tests/conftest.py: scrub the login from the v4 request body too (GetClientsUnits echoes the account login as a Logins param). - 7 new cassettes recorded against --sandbox, all secrets/PII redacted (token in body, login in request param + response Login field, auth headers). Offline replay verified (39 passed, no token/network). Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
@claude review. Focus on critical issues: bugs, security vulnerabilities, logical errors, data loss risks, performance problems. Do NOT nitpick style, naming conventions, minor formatting, or subjective preferences — only flag issues that could break functionality or cause real harm in production. |
|
@claude review. The previous review run errored out before posting (empty ANTHROPIC_API_KEY + an internal action error), so this is a re-request. Focus on critical issues: bugs, security vulnerabilities, logical errors, data loss risks, performance problems. Do NOT nitpick style, naming, or formatting. |
|
Claude finished @axisrow's task in 2m 8s —— View job Review: PR #457 — v4 Live read cassettes + bounded retry-loop
Verdict: LGTM. No bugs, security issues, or data-loss risks found. The diagnosis (unbounded retry, not a vcrpy×v4 incompatibility) is correct and the fix is minimal and well-targeted. Correctness — retry fix (
|

Что и зачем
Завершает offline-покрытие read-команд: 7 v4 Live read-команд теперь записаны в
VCR-кассеты и реплеятся в CI без токена и сети — так же, как 32 v5-кассеты из #455.
Корень «зависания» (опровержение гипотезы #454)
Issue #454 предполагал, что vcrpy не умеет перехватывать v4 Live HTTP-клиент.
Это неверно:
547e837) тем же@pytest.mark.vcr. Транспорт v4 = транспорт v5 (requests/urllib3).V4LiveClientAdapter.retry_request: ретрай ошибокrequest-limit (код 54/55) был без ограничения числа попыток
(
time.sleep(10); return Trueбез проверкиrepeat_number) → бесконечный цикл.этот код и для rate-limit), из-за чего адаптер вис навсегда. Recording-аккаунт
(профиль) v4-права имеет — на нём все 7 команд отвечают за пару секунд.
Подтверждено faulthandler-трейсом: до фикса
v4goals get-stat-goalsпротив аккаунтабез прав виснет на
adapter.py:180; после фикса — 5 ограниченных ретраев и аккуратнаяошибка (exit 1). Это чинит и реальный production-зависон для любого вызывающего.
Изменения
direct_cli/_vendor/tapi_yandex_direct/v4/adapter.py— ограничил ветку 54/55 тем жебюджетом попыток, что и серверную.
в форк
axisrow/tapi-yandex-direct, иначе он потеряется при следующемupdate_vendor.sh.tests/test_read_cassettes.py— +6 success-кейсов v4 вREAD_CASES(
v4goals get-stat-goals,v4tags get-campaigns,v4forecast list,v4wordstat list-reports,v4events get-events-log,v4finance get-clients-units)check-payment, проверяющий детерминированную ошибкуerror_code=370(exit≠0). Docstring исправлен — убрано неверное утверждение про vcrpy×v4.
tests/conftest.py— скраб логина и из тела запроса v4(
GetClientsUnitsшлёт логин аккаунта вLogins).--sandbox, все секреты/PII вычищены: токен в теле,логин в request-param и в response-поле
Login, auth-заголовки.Проверка
pytest tests/test_read_cassettes.py→ 39 passed (32 v5 + 7 v4) офлайн, без сети.pytest -m "not integration"→ 1963 passed, 46 skipped (вендор-фикс ничего не сломал).ruff/black→ clean._vendor/исключён из CI mypy.\uXXXX-escaped) → ALL CLEAN.Follow-up
axisrow/tapi-yandex-direct(чтобы пережил ре-вендоринг).Closes #454
🤖 Generated with Claude Code