gendesign/tradein-mvp/backend/tests/scrapers/test_admin_avito_kit_parity.py
bot-backend a9b87aa311
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
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 1m36s
chore(tradein/scraper-kit): удалить 5 orphaned legacy-модулей (#2277 финальный шаг, частичный)
Удалены (0 runtime importers в app/, scripts/, packages/; проверено grep'ом,
включая intra-legacy импорты в оставшихся 21 legacy-модуле scrapers/):
- backend/app/services/scrapers/avito_imv.py
- backend/app/services/scrapers/domclick_detail.py
- backend/app/services/scrapers/ekb_geoportal_client.py
- backend/app/services/scrapers/yandex_detail.py
- backend/app/services/scrapers/yandex_valuation.py

Тесты — удалены (pure legacy-vs-kit parity, kit-only coverage уже есть в другом
месте):
- tests/scrapers/test_ekb_geoportal_client_kit_parity.py
- tests/scrapers/test_domclick_detail_kit_parity.py

Тесты — конвертированы в kit-only (импорт легаси заменён на scraper_kit.*,
покрытие сохранено без потерь):
- tests/scrapers/test_avito_imv_kit_parity.py (parity-тесты убраны, config-footgun
  regression на kit-стороне оставлен)
- tests/scrapers/test_avito_imv_browser_transport.py
- tests/scrapers/test_yandex_valuation_kit_migration.py (parity убрана, footgun-
  регрессия mandatory config/delay_provider оставлена)
- tests/scrapers/test_domclick_detail.py (+ exceptions переведены на
  scraper_kit.domclick_exceptions, т.к. kit parse_detail_html поднимает их)
- tests/test_avito_imv_parse.py
- tests/test_ekb_geoportal_ingest.py (client-часть; ingest/geocoder-часть не
  трогали — не зависят от удалённого модуля)
- tests/test_yandex_detail.py
- tests/test_yandex_detail_structural.py
- tests/test_yandex_valuation.py (YandexValuationScraper() → config=_KIT_CONFIG,
  kit конструктор требует обязательный config)
- tests/test_yandex_valuation_save.py
- tests/test_extval_house_id_write_path.py (только yandex_valuation-часть;
  cian_valuation остался нетронутым — живой легаси-модуль)
- tests/test_yandex_history_area_filter.py

Тесты — частично отредактированы (убраны только части про удалённые модули,
живые легаси-модули/их parity не тронуты):
- tests/scrapers/test_admin_domclick_ingest_kit_parity.py (base.py/ScrapedLot
  parity остался)
- tests/scrapers/test_admin_yandex_kit_parity.py (yandex_realty parity остался)
- tests/scrapers/test_admin_avito_kit_parity.py (avito.py/avito_houses.py parity
  остался; _parse_price parity убран)
- tests/scrapers/test_avito_unix_date_tz_consistency.py (IMV-ветка переведена на
  kit avito.imv, легаси avito/avito_houses/avito_shared/avito_detail не тронуты)
- tests/tasks/test_yandex_detail_backfill.py (subject — kit-задача, уже вызывает
  scraper_kit.providers.yandex.detail; save_detail_enrichment coverage-тесты
  внизу файла переведены на kit)
- tests/test_scraper_kit_yandex_golden_parity.py (detail/valuation parity убраны;
  serp/newbuilding/house_type_normalizer/build_url для yandex_realty/
  yandex_newbuilding не тронуты)
- tests/test_scraper_proxy.py (YandexValuation proxy-тесты переведены на kit
  config= DI; test_avito_imv_own_session_receives_proxies удалён — дублирует
  test_avito_imv_kit_parity.py footgun-тесты)
- tests/test_yandex_scrapers_delay_wiring.py (yandex_detail/yandex_valuation →
  kit delay_provider=; yandex_realty/yandex_newbuilding не тронуты)
- tests/test_scraper_kit_group_c_backfill_kit_parity.py (docstring уточнение,
  без функциональных изменений)

Полный backend-suite зелёный (3253 passed, 6 skipped) кроме известного
pre-existing flake test_search_api.py::test_search_cache_hit (#2208, не
регрессия этого PR). ruff check + ruff format — чисто на всех изменённых файлах.
2026-07-04 10:41:46 +03:00

112 lines
5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Parity-proof: admin.py Avito debug-роуты (#2305, Group A) — legacy vs scraper_kit.
`app/api/v1/admin.py::scrape_avito_house` теперь зовёт `scraper_kit.providers.avito.houses`
вместо `app.services.scrapers.avito_houses` (тот же `/scrape` root-роут —
`scraper_kit.providers.avito.serp.AvitoScraper`). Каждая пара функций ниже — чистое,
offline-тестируемое parsing-ядро, которое реально используется соответствующим
debug-эндпоинтом (не сам HTTP-fetch — см. `tests/support/README.md`: "Live network/DB
в parity-тестах избегайте").
- `_parse_house_page` — `scrape_avito_house` → `fetch_house_catalog` парсит виджет
`housePage` этой функцией.
- `_extract_rooms_from_title` / `_extract_area_from_title` — использует
`AvitoScraper` (SERP-парсинг `/scrape` root-роута) для title-fallback полей.
Легаси `app.services.scrapers.avito_imv` (`scrape_avito_imv` → `evaluate_via_imv` →
`_parse_price`) удалён (#2277 финальный шаг scraper_kit-миграции, 0 runtime
importers) — parity-проверка `_parse_price` убрана вместе с ним; kit-сторона
`_parse_price` покрыта отдельно (`tests/scrapers/test_avito_imv_kit_parity.py` /
`tests/test_avito_imv_parse.py`).
"""
from __future__ import annotations
import dataclasses
import os
# Соседние модули app.services.scrapers.* импортируют app.core.config при импорте
# пакета — фиктивный DSN мостит офлайн-запуск (mirror test_avito_detail_kit_parity.py).
os.environ.setdefault("DATABASE_URL", "postgresql+psycopg://test:test@localhost/test_db")
from scraper_kit.providers.avito.houses import _parse_house_page as kit_parse_house_page
from scraper_kit.providers.avito.serp import (
_extract_area_from_title as kit_extract_area_from_title,
)
from scraper_kit.providers.avito.serp import (
_extract_rooms_from_title as kit_extract_rooms_from_title,
)
from app.services.scrapers.avito import _extract_area_from_title as legacy_extract_area_from_title
from app.services.scrapers.avito import (
_extract_rooms_from_title as legacy_extract_rooms_from_title,
)
from app.services.scrapers.avito_houses import _parse_house_page as legacy_parse_house_page
from tests.support.parity import assert_parity
_HOUSE_WIDGET = {
"props": {
"developmentData": {
"avitoId": 3171365,
"id": "abc123hash",
"title": "ЖК Тестовый",
"address": "ул. Тестовая, 1",
"fullAddress": "Екатеринбург, ул. Тестовая, 1",
"coords": {"lat": 56.8, "lng": 60.6},
"aboutDevelopment": {
"expandParams": {
"items": [
{
"params": [
{"type": "Год постройки", "value": "2020"},
{"type": "Этажей", "value": "16"},
{"type": "Пассажирский лифт", "value": "2"},
]
}
]
}
},
"ratingBadge": {"info": {"score": 4.5, "scoreString": "4.5"}},
"ratingSummaryStat": {"reviewCount": 10, "ratingStat": []},
"mapPreview": {"objects": "школа рядом", "distance": "5 мин", "pins": []},
"developer": {"name": "ООО Застройщик", "key": "dev1"},
}
}
}
def test_avito_house_page_parse_are_class_distinct() -> None:
"""Sanity: legacy/kit HouseInfo — разные классы, обычный `==` даёт False."""
legacy_result = legacy_parse_house_page(_HOUSE_WIDGET)
kit_result = kit_parse_house_page(_HOUSE_WIDGET)
assert type(legacy_result) is not type(kit_result)
assert legacy_result != kit_result
assert dataclasses.asdict(legacy_result) == dataclasses.asdict(kit_result)
def test_parity_avito_house_page() -> None:
"""`scrape_avito_house` (admin.py) → fetch_house_catalog → _parse_house_page."""
assert_parity(
legacy_fn=legacy_parse_house_page,
kit_fn=kit_parse_house_page,
fixtures=[(_HOUSE_WIDGET,)],
)
def test_parity_avito_serp_title_extract() -> None:
"""`/scrape` root-роут (admin.py) → AvitoScraper SERP title-fallback fields."""
titles = [
"2-к. квартира, 54.3 м², 3/9 эт.",
"Студия, 25 м², 1/5 эт.",
"3-к. кв., 75,5 м², 12/16 эт.",
]
assert_parity(
legacy_fn=legacy_extract_rooms_from_title,
kit_fn=kit_extract_rooms_from_title,
fixtures=titles,
)
assert_parity(
legacy_fn=legacy_extract_area_from_title,
kit_fn=kit_extract_area_from_title,
fixtures=titles,
)