gendesign/tradein-mvp/packages/scraper-kit/src/scraper_kit/ceiling_height.py
bot-backend 306fd82836
All checks were successful
Deploy Trade-In / changes (push) Successful in 11s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 3m5s
Deploy Trade-In / build-backend (push) Successful in 1m43s
Deploy Trade-In / deploy (push) Successful in 2m26s
fix(tradein): свести высоту потолков к одной колонке ceiling_height_m (#2779)
2026-08-07 09:18:48 +00:00

46 lines
2.8 KiB
Python
Raw Permalink 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.

"""Единый гейт правдоподобия для высоты потолков (#2699).
Канон — колонка ``listings.ceiling_height_m`` (метры). Единицы вынесены в имя,
как и во всём остальном коде проекта (``domrf_kn_flats.ceiling_height_m``,
``domrf_kn_objects.ceiling_height_m``, фронтовый ``ceiling_height_m``);
``listings.ceiling_height`` (миграция 019, numeric(3,2)) — единственное
исключение, помеченное DEPRECATED в миграции 238.
Гейт был только у yandex SERP (инлайн, #2007) — остальные писатели гнали в БД
что распарсили. Прод 2026-08-07: в ``ceiling_height_m`` 26 строк > 6 м (максимум
29.90) и 84 строки < 2 м (83 из них — ровно 0.00), все из avito detail. Теперь
гейт один на всех писателей.
Диапазон 2.06.0 м: снизу — ниже жилой потолок не бывает (СП 54.13330 требует
от 2.5 м; 2.0 оставлено с запасом на мис-парс округлений), сверху — сталинки и
лофты редко переваливают за 5 м, 6.0 покрывает двухуровневые карточки, где
продавец указывает высоту помещения целиком. Тот же диапазон уже год работает у
yandex SERP; прод-подтверждение: все 7 675 yandex-значений лежат в [2.00, 6.00].
Второй эффект гейта: ``ceiling_height`` — numeric(3,2), max 9.99, и запись
out-of-range роняла бы весь батч DataError'ом (per-lot SAVEPOINT ловит только
IntegrityError). Гейт снимает и этот класс отказа.
"""
from __future__ import annotations
CEILING_MIN_M = 2.0
CEILING_MAX_M = 6.0
def plausible_ceiling_m(value: float | int | str | None) -> float | None:
"""Вернуть высоту потолка в метрах, если она физически возможна, иначе None.
Нечисловой вход (``None``, пустая строка, мусор) → ``None`` без исключения:
вызывающие — парсеры чужого HTML/JSON, для них «не разобралось» это норма,
а не ошибка. Сырое значение остаётся в ``raw_payload`` карточки.
"""
if value is None:
return None
try:
height = float(value)
except (TypeError, ValueError):
return None
if CEILING_MIN_M <= height <= CEILING_MAX_M:
return height
return None