feat(tradein/scraper-kit): migrate cian/yandex price-history & session to kit (#2306) #2324

Merged
lekss361 merged 2 commits from feat/tradein-migrate-price-history-kit into main 2026-07-03 21:33:10 +00:00
Owner

Closes #2306 (Group B эпика #2277 — scraper_kit migration).

Что сделано

Три файла переведены на импорт из scraper_kit.* вместо legacy app/services/scrapers/*:

  • cian_price_history.pyfetch_detail/save_detail_enrichmentscraper_kit.providers.cian.detail
  • cian_session.pyextract_statescraper_kit.cian_state_parser (byte-identical, подтверждено diff'ом)
  • yandex_price_history.pyScrapedLotscraper_kit.base (byte-identical field/method surface, duck-typing без isinstance)

Публичный API всех трёх файлов не менялся — вызывающим (admin.py, product_handlers.py,
scheduler.py, cian_valuation.py) правки не понадобились (подтверждено grep'ом всех importers).

Kit-версия fetch_detail читает cian_proxy_url только если передан явный config=
(в отличие от legacy, который всегда читает settings.cian_proxy_url сам). Без этого
backfill тихо потерял бы прокси. Фикс: config=RealScraperConfig() на call site в
cian_price_history.py. Верифицировано ревьюером (трассировка через curl_proxy_url()
RealScraperConfig.cian_proxy_url → идентичное поведение legacy).

Hardening после review

Ревьюер нашёл: ни parity-тест, ни существующие test_backfill_wave2.py тесты не ловили бы
регрессию, если config=RealScraperConfig() случайно уберут из call site. Усилил все 3 теста
в test_backfill_wave2.pyisinstance(call_kwargs["config"], RealScraperConfig). Доказано
вручную: временно убрал fix → тесты упали → вернул → тесты прошли (реальная regression-catch
proof, не просто добавленный assert).

Проверено

  • tests/test_backfill_wave2.py + tests/test_scraper_kit_pricehistory_session_parity.py
    32/32 passed
  • Полный backend suite: 3175 passed / 6 skipped / 1 pre-existing unrelated failure
    (test_search_cache_hit, подтверждено — этот PR не трогает ту область кода)
  • ruff check + format — чисто
  • Code-review: ⚠️ MINOR → все замечания закрыты вторым коммитом
Closes #2306 (Group B эпика #2277 — scraper_kit migration). ## Что сделано Три файла переведены на импорт из `scraper_kit.*` вместо legacy `app/services/scrapers/*`: - `cian_price_history.py` — `fetch_detail`/`save_detail_enrichment` → `scraper_kit.providers.cian.detail` - `cian_session.py` — `extract_state` → `scraper_kit.cian_state_parser` (byte-identical, подтверждено diff'ом) - `yandex_price_history.py` — `ScrapedLot` → `scraper_kit.base` (byte-identical field/method surface, duck-typing без `isinstance`) Публичный API всех трёх файлов не менялся — вызывающим (`admin.py`, `product_handlers.py`, `scheduler.py`, `cian_valuation.py`) правки не понадобились (подтверждено grep'ом всех importers). ## Важная находка — proxy footgun (#806-related regression risk) Kit-версия `fetch_detail` читает `cian_proxy_url` только если передан явный `config=` (в отличие от legacy, который всегда читает `settings.cian_proxy_url` сам). Без этого backfill тихо потерял бы прокси. Фикс: `config=RealScraperConfig()` на call site в `cian_price_history.py`. Верифицировано ревьюером (трассировка через `curl_proxy_url()` → `RealScraperConfig.cian_proxy_url` → идентичное поведение legacy). ## Hardening после review Ревьюер нашёл: ни parity-тест, ни существующие `test_backfill_wave2.py` тесты не ловили бы регрессию, если `config=RealScraperConfig()` случайно уберут из call site. Усилил все 3 теста в `test_backfill_wave2.py` — `isinstance(call_kwargs["config"], RealScraperConfig)`. Доказано вручную: временно убрал fix → тесты упали → вернул → тесты прошли (реальная regression-catch proof, не просто добавленный assert). ## Проверено - `tests/test_backfill_wave2.py` + `tests/test_scraper_kit_pricehistory_session_parity.py` — 32/32 passed - Полный backend suite: 3175 passed / 6 skipped / 1 pre-existing unrelated failure (`test_search_cache_hit`, подтверждено — этот PR не трогает ту область кода) - ruff check + format — чисто - Code-review: ⚠️ MINOR → все замечания закрыты вторым коммитом
lekss361 added 2 commits 2026-07-03 21:28:59 +00:00
Group B of the scraper_kit migration epic (#2277): switch the three files'
internal dependency imports from legacy app/services/scrapers/* to their
byte/structurally-identical scraper_kit equivalents, proven via the new
parity harness (tests/support/parity.assert_parity, #2304). Public API of
all three files is unchanged, so no callers needed updating.

- cian_price_history.py: fetch_detail/save_detail_enrichment now from
  scraper_kit.providers.cian.detail. Wires config=RealScraperConfig() at
  the call site — kit's fetch_detail only reads cian_proxy_url when an
  explicit config is passed, unlike legacy's always-on settings read;
  without this the admin-triggered backfill would silently drop its
  datacenter-IP proxy (#806) after the import swap.
- cian_session.py: extract_state now from scraper_kit.cian_state_parser
  (byte-identical to legacy).
- yandex_price_history.py: ScrapedLot now from scraper_kit.base
  (byte-identical fields/methods; record_yandex_price_history only reads
  lot.* via duck-typing, no isinstance checks).

New tests/test_scraper_kit_pricehistory_session_parity.py proves the
migration delta specifically (extract_state, ScrapedLot.model_dump(),
fetch_detail+DetailEnrichment with config injection, and the own-session
proxy-kwarg wiring). Full backend suite passes (3145 passed, 6 skipped,
1 pre-existing unrelated failure confirmed on unmodified forgejo/main).
test(tradein): assert config kwarg on cian price-history fetch_detail call (#2306)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 7s
CI / changes (pull_request) Successful in 8s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 1m40s
88b93435fc
code-reviewer flagged that neither the new parity test nor
test_backfill_wave2.py's 3 cian_price_history tests would catch a
regression if config=RealScraperConfig() were accidentally dropped from
the fetch_detail call in cian_price_history.py (the proxy-footgun fix
from the #2306 migration) — mock_fetch.assert_called_once() doesn't
check kwargs.

Strengthens all 3 tests (saves_changes / skips_no_changes /
handles_fetch_none) to assert isinstance(call_kwargs["config"],
RealScraperConfig). Manually verified the guard actually catches the
regression: temporarily removed config= from cian_price_history.py:110,
confirmed all 3 tests fail, restored the fix, confirmed they pass again.
lekss361 merged commit 24b773efe3 into main 2026-07-03 21:33:10 +00:00
lekss361 deleted branch feat/tradein-migrate-price-history-kit 2026-07-03 21:33:11 +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#2324
No description provided.