_norm_flat: деривация price_per_m2 падает с TypeError при строковом totalArea — необработанное исключение роняет весь run #1644

Closed
opened 2026-06-16 18:46:33 +00:00 by bot-backend · 0 comments
Collaborator

Severity: medium · Категория: краш / NULL-обработка · Файл: backend/app/services/scrapers/domrf_kn.py:413-418, 808-819

domrf_kn.py:413-418 — total_area = _g(row, 'totalArea') (413) возвращает СЫРОЕ значение API без коэрции (_g, 71-75, отдаёт d[k] как есть; _flatten_table, 367-382, тоже не коэрцирует — лишь спред flat-словаря). Условие на 417: if price_per_m2 is None and price_rub is not None and total_area and total_area > 0:. Если API отдаст totalArea непустой строкой ('45.2'), total_area truthy → выполняется total_area > 0, что в Python 3 даёт TypeError ('>' not supported between instances of 'str' and 'int'). _norm_flat вызывается в upsert_flats на строке 809 — ВНЕ try/except (try начинается на 814 вокруг db.execute, SAVEPOINT). Исключение поднимается из _norm_flat → роняет цикл upsert_flats → из result loop (1869) → наружу из run_region_sweep → ловится только внешним except на 2018, который помечает ВЕСЬ run status='failed' (2024-2025) и raise (2039). Один объект со строковым totalArea аварийно завершает обработку квартир и весь sweep, теряя накопленный между чекпойнтами прогресс. Сравнение str>int семантически неверно даже без падения. Фикс: total_area = _to_int(_g(row,'totalArea')) или _to_float (есть _to_int 95-115; для деления нужен float-вариант), и/или обернуть _norm_flat(row) (809) в per-row try, чтобы битый объект скипался, а не валил run.

Почему баг: Деривация цены опирается на raw-тип поля, тогда как остальной код (price_rub / total_area при делении) предполагает число. Один объект со строковым (или иным не-numeric) totalArea не просто пропускается, а аварийно завершает обработку квартир и затем весь sweep, теряя уже накопленный прогресс между чекпойнтами. Сравнение str > int также семантически неверно даже если бы не падало.

Как чинить: Привести total_area/price_rub к числу через _to_int/float-хелпер до арифметики, обернуть деление в защиту от не-numeric, и/или перенести вызов _norm_flat внутрь per-row try, чтобы битая строка скипалась как skipped_no_id, а не валила батч.


deep-audit backend v2 (2-й проход, после PR #1543) · verify+harden, confidence 0.85 · unit B31

**Severity:** medium · **Категория:** краш / NULL-обработка · **Файл:** `backend/app/services/scrapers/domrf_kn.py:413-418, 808-819` domrf_kn.py:413-418 — total_area = _g(row, 'totalArea') (413) возвращает СЫРОЕ значение API без коэрции (_g, 71-75, отдаёт d[k] как есть; _flatten_table, 367-382, тоже не коэрцирует — лишь спред flat-словаря). Условие на 417: `if price_per_m2 is None and price_rub is not None and total_area and total_area > 0:`. Если API отдаст totalArea непустой строкой ('45.2'), `total_area` truthy → выполняется `total_area > 0`, что в Python 3 даёт TypeError ('>' not supported between instances of 'str' and 'int'). _norm_flat вызывается в upsert_flats на строке 809 — ВНЕ try/except (try начинается на 814 вокруг db.execute, SAVEPOINT). Исключение поднимается из _norm_flat → роняет цикл upsert_flats → из result loop (1869) → наружу из run_region_sweep → ловится только внешним except на 2018, который помечает ВЕСЬ run status='failed' (2024-2025) и raise (2039). Один объект со строковым totalArea аварийно завершает обработку квартир и весь sweep, теряя накопленный между чекпойнтами прогресс. Сравнение str>int семантически неверно даже без падения. Фикс: total_area = _to_int(_g(row,'totalArea')) или _to_float (есть _to_int 95-115; для деления нужен float-вариант), и/или обернуть _norm_flat(row) (809) в per-row try, чтобы битый объект скипался, а не валил run. **Почему баг:** Деривация цены опирается на raw-тип поля, тогда как остальной код (price_rub / total_area при делении) предполагает число. Один объект со строковым (или иным не-numeric) totalArea не просто пропускается, а аварийно завершает обработку квартир и затем весь sweep, теряя уже накопленный прогресс между чекпойнтами. Сравнение str > int также семантически неверно даже если бы не падало. **Как чинить:** Привести total_area/price_rub к числу через _to_int/float-хелпер до арифметики, обернуть деление в защиту от не-numeric, и/или перенести вызов _norm_flat внутрь per-row try, чтобы битая строка скипалась как skipped_no_id, а не валила батч. --- <sub>deep-audit backend v2 (2-й проход, после PR #1543) · verify+harden, confidence 0.85 · unit B31</sub>
bot-backend added the
week ревью 1
label 2026-06-16 18:46:33 +00:00
Sign in to join this conversation.
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#1644
No description provided.