refactor(tradein/scraper-kit): avito providers on shared _base.py (#2361) #2375

Merged
lekss361 merged 1 commit from feat/tradein-scraper-kit-f4a-avito into main 2026-07-04 06:35:00 +00:00
Owner

Что мигрировано

avito/{serp,detail}.py -> build_browser_fetcher() / build_document_session() из scraper_kit.providers._base (Foundation #2358):

  • serp.py: BrowserFetcher(source="avito", endpoint=...) в __aenter__ -> build_browser_fetcher(config, "avito"); _build_cffi_session() (25s timeout, document headers, scraper_proxy_url) -> build_document_session().
  • detail.py: _build_detail_session() (тот же document-headers dict, 25s timeout) -> build_document_session(proxy_url=..., timeout=25).

Kwarg-by-kwarg diff подтверждает идентичное поведение (proxy resolution, timeout=25, impersonate=chrome120, DOCUMENT_HEADERS verbatim).

Caveat: use_pool (проверено explicit)

serp.py.__aenter__ раньше конструировал BrowserFetcher без proxy_provider/use_pool (implicit None/False). После миграции use_pool читает config.use_proxy_pool_browser вместо hardcoded False — НО proxy_provider остаётся None (default build_browser_fetcher), а BrowserFetcher._use_pool гейтится and self._proxy_provider is not None (browser_fetcher.py:215). При proxy_provider=None эффективный use_pool всегда False независимо от конфига. Verified: behavior-preserving, не тихая смена прод-поведения. (config.use_proxy_pool_browser default — тоже False.)

imv.py: НЕ мигрирован (единственное отклонение от issue-скоупа)

Own-session curl_cffi construction (headers=_DOC_HEADERS, тот же дублированный dict) технически подходит под миграцию, но build_document_session() резолвит AsyncSession через module-level импорт в _base.py (bind один раз при первом импорте), а tests/scrapers/test_avito_imv_kit_parity.py (#2334) патчит curl_cffi.requests.AsyncSession через unittest.mock — это работает только с локальным call-time импортом внутри функции (как было). Миграция роняет 2 реальных зелёных теста (test_kit_evaluate_via_imv_{with,without}_config_uses_proxy) — не шум. Прод-поведение идентично в обоих вариантах, но задача явно запрещает weaken/skip parity-тесты — оставлено как есть + inline-комментарий с находкой.

Follow-up для F4b-d (cian/yandex/domclick): тот же паттерн теста (unittest.mock.patch("curl_cffi.requests.AsyncSession") на module-level импорт) сломает миграцию любого provider'а с аналогичным test-mock таргетом. Стоит завести lightweight follow-up issue против _base.py's AsyncSession import style или против теста.

Code review (verdict: approve)

Ревьюер сам перепроверил все 6 пунктов (kwarg-diff, use_pool investigation, scope git show --stat, targeted parity tests 45/45 + -k avito 450/450, full suite, ruff). Minor findings (не блокирующие):

  • imv.py non-migration — обоснованно, follow-up issue предложен выше.
  • serp.py ruff-format drift (4 hunks) — pre-existing на main до этого PR, не тронуто.
  • test_search_api.py::test_search_cache_hit (401 vs 200) — pre-existing флейк #2208, не связан с этим диффом.

Tests

  • -k avito: 450/450 passed (после rebase на актуальный main — перепроверено)
  • Targeted kit_parity/golden_parity/pipeline_parity/providers_base: 45/45 passed
  • Full backend suite: 3278 passed, 6 skipped, 1 pre-existing flake (не связан)
  • ruff check clean на всех 3 файлах; ruff format --check drift на serp.py подтверждён pre-existing (идентичен на unmodified main)

Closes #2361

## Что мигрировано `avito/{serp,detail}.py` -> `build_browser_fetcher()` / `build_document_session()` из `scraper_kit.providers._base` (Foundation #2358): - `serp.py`: `BrowserFetcher(source="avito", endpoint=...)` в `__aenter__` -> `build_browser_fetcher(config, "avito")`; `_build_cffi_session()` (25s timeout, document headers, scraper_proxy_url) -> `build_document_session()`. - `detail.py`: `_build_detail_session()` (тот же document-headers dict, 25s timeout) -> `build_document_session(proxy_url=..., timeout=25)`. Kwarg-by-kwarg diff подтверждает идентичное поведение (proxy resolution, timeout=25, impersonate=chrome120, DOCUMENT_HEADERS verbatim). ## Caveat: use_pool (проверено explicit) `serp.py.__aenter__` раньше конструировал `BrowserFetcher` без `proxy_provider`/`use_pool` (implicit `None`/`False`). После миграции `use_pool` читает `config.use_proxy_pool_browser` вместо hardcoded `False` — НО `proxy_provider` остаётся `None` (default `build_browser_fetcher`), а `BrowserFetcher._use_pool` гейтится `and self._proxy_provider is not None` (`browser_fetcher.py:215`). При `proxy_provider=None` эффективный `use_pool` всегда `False` независимо от конфига. Verified: behavior-preserving, не тихая смена прод-поведения. (`config.use_proxy_pool_browser` default — тоже `False`.) ## imv.py: НЕ мигрирован (единственное отклонение от issue-скоупа) Own-session curl_cffi construction (`headers=_DOC_HEADERS`, тот же дублированный dict) технически подходит под миграцию, но `build_document_session()` резолвит `AsyncSession` через module-level импорт в `_base.py` (bind один раз при первом импорте), а `tests/scrapers/test_avito_imv_kit_parity.py` (#2334) патчит `curl_cffi.requests.AsyncSession` через `unittest.mock` — это работает только с локальным call-time импортом внутри функции (как было). Миграция роняет 2 реальных зелёных теста (`test_kit_evaluate_via_imv_{with,without}_config_uses_proxy`) — не шум. Прод-поведение идентично в обоих вариантах, но задача явно запрещает weaken/skip parity-тесты — оставлено как есть + inline-комментарий с находкой. **Follow-up для F4b-d (cian/yandex/domclick):** тот же паттерн теста (`unittest.mock.patch("curl_cffi.requests.AsyncSession")` на module-level импорт) сломает миграцию любого provider'а с аналогичным test-mock таргетом. Стоит завести lightweight follow-up issue против `_base.py`'s `AsyncSession` import style или против теста. ## Code review (verdict: approve) Ревьюер сам перепроверил все 6 пунктов (kwarg-diff, use_pool investigation, scope `git show --stat`, targeted parity tests 45/45 + `-k avito` 450/450, full suite, ruff). Minor findings (не блокирующие): - imv.py non-migration — обоснованно, follow-up issue предложен выше. - `serp.py` ruff-format drift (4 hunks) — pre-existing на `main` до этого PR, не тронуто. - `test_search_api.py::test_search_cache_hit` (401 vs 200) — pre-existing флейк #2208, не связан с этим диффом. ## Tests - `-k avito`: 450/450 passed (после rebase на актуальный main — перепроверено) - Targeted kit_parity/golden_parity/pipeline_parity/providers_base: 45/45 passed - Full backend suite: 3278 passed, 6 skipped, 1 pre-existing flake (не связан) - `ruff check` clean на всех 3 файлах; `ruff format --check` drift на `serp.py` подтверждён pre-existing (идентичен на unmodified main) Closes #2361
lekss361 added 1 commit 2026-07-04 06:32:30 +00:00
refactor(tradein/scraper-kit): avito providers on shared _base.py (#2361)
All checks were successful
CI / changes (pull_request) Successful in 10s
CI / backend-tests (pull_request) Has been skipped
CI Trade-In / changes (pull_request) Successful in 11s
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 1m44s
b445c34863
Мигрирует avito/{serp,detail}.py на build_browser_fetcher()/
build_document_session() из scraper_kit.providers._base (Foundation #2358):

- serp.py: BrowserFetcher(source="avito", endpoint=...) в __aenter__ ->
  build_browser_fetcher(config, "avito"); _build_cffi_session() (25s
  timeout, document headers, scraper_proxy_url) -> build_document_session().
- detail.py: _build_detail_session() (тот же document-headers dict,
  25s timeout) -> build_document_session(proxy_url=..., timeout=25).

Caveat (#2361, проверено explicit): serp.py __aenter__ раньше конструировал
BrowserFetcher БЕЗ proxy_provider/use_pool (implicit None/False). После
миграции use_pool читает config.use_proxy_pool_browser вместо hardcoded
False - НО proxy_provider остаётся None (build_browser_fetcher default), а
BrowserFetcher._use_pool гейтится `and self._proxy_provider is not None`
(browser_fetcher.py:215) - при proxy_provider=None use_pool всегда
эффективно False независимо от config. Verified: behavior-preserving,
не тихая смена прод-поведения.

imv.py: НЕ мигрирован (единственное отклонение от issue). Own-session
curl_cffi construction (headers=_DOC_HEADERS - тот же дублированный dict)
технически подходит под миграцию, но build_document_session() резолвит
AsyncSession через module-level импорт _base.py (biндится один раз при
первом импорте _base), а tests/scrapers/test_avito_imv_kit_parity.py
(#2334) патчит curl_cffi.requests.AsyncSession через unittest.mock -
это работает только с локальным call-time импортом (как было). Миграция
роняет 2 реальных теста (test_kit_evaluate_via_imv_{with,without}_config_
uses_proxy) - не шум, зелёные на main. Прод-поведение идентично в обоих
вариантах, но задача явно запрещает weaken/skip parity-тесты - оставлено
как есть + inline-комментарий с находкой. Follow-up для будущих групп
(cian/yandex/domclick F4b-d): тот же паттерн теста сломает миграцию любого
provider с аналогичным unittest.mock.patch("curl_cffi.requests.AsyncSession").

Tests: full backend suite 3278 passed, 1 known pre-existing flake
(test_search_api.py::test_search_cache_hit, #2208), 6 skipped. Все avito
kit_parity/golden_parity тесты + test_scraper_kit_pipeline_parity2.py
(cross-provider) зелёные.
lekss361 merged commit 758a4b06d4 into main 2026-07-04 06:35:00 +00:00
lekss361 deleted branch feat/tradein-scraper-kit-f4a-avito 2026-07-04 06:35:00 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#2375
No description provided.