This commit is contained in:
parent
1f036e94d1
commit
90c3e7e490
2 changed files with 82 additions and 32 deletions
|
|
@ -197,32 +197,74 @@ class TestParseBabushkinaBlock:
|
|||
assert site.krt_kind == "жилой застройки"
|
||||
|
||||
|
||||
class TestMultiSiteCountFromDump:
|
||||
"""Проверка количества площадок из реального дампа страницы."""
|
||||
# ── Многоблочная страница: два года, три площадки, повторяющийся номер ────────
|
||||
#
|
||||
# Здесь до #2778 стоял TestMultiSiteCountFromDump, читавший
|
||||
# `.playwright-mcp/ekb-docs/krt_page_raw.html`. Дампа нет ни в репозитории, ни у
|
||||
# кого-либо на диске, ни на проде: `ekb_krt_sites.raw_block` хранит не HTML, а
|
||||
# уже очищенный текст (`block_text[:4000]` в ekb_krt_registry.py:338), поэтому
|
||||
# восстановить вход парсера из БД нельзя. Оба теста не исполнялись НИГДЕ.
|
||||
#
|
||||
# Свойство, ради которого они писались, от дампа не зависит и выражается
|
||||
# страницей из блоков, которые уже лежат в этом файле:
|
||||
# • несколько <h2>-секций с годами разбираются в одном проходе;
|
||||
# • нумерация площадок на реальной странице НАЧИНАЕТСЯ ЗАНОВО В КАЖДОМ ГОДУ,
|
||||
# поэтому «2.» встречается дважды — и site_name всё равно обязан быть
|
||||
# уникальным (номер сам по себе ключом не является);
|
||||
# • блоки лежат внутри контейнера <div> — это ветка `_extract_krt_section`
|
||||
# через `find_parent`, которой одиночные блоки выше не касаются вовсе.
|
||||
#
|
||||
# ЧЕГО ЭТА ЗАМЕНА НЕ ПРОВЕРЯЕТ (осознанная потеря, зафиксирована в #2778):
|
||||
# «на живой странице ЕКБ ≥14 площадок». Это утверждение о полноте разбора
|
||||
# реального документа, синтетической страницей оно не заменяется. На проде
|
||||
# ekb_krt_sites = 15 строк, то есть по факту сейчас всё разбирается, но
|
||||
# автоматической проверки этого больше нет — она вернётся, когда в репозитории
|
||||
# появится образец страницы.
|
||||
_MULTISITE_PAGE = (
|
||||
"<div class='content'>"
|
||||
+ _BRUSNIKA_BLOCK
|
||||
+ _BABUSHKINA_BLOCK
|
||||
+ textwrap.dedent(
|
||||
"""\
|
||||
<p> <strong>2. КРТ нежилой застройки в районе ул. Краснофлотцев:</strong></p>
|
||||
<p>Площадь территории: 3,65 га;<br />\
|
||||
Градостроительный потенциал: 117 640 кв. м;<br />\
|
||||
Всего многоквартирных домов: 13.</p>
|
||||
"""
|
||||
)
|
||||
+ "</div>"
|
||||
)
|
||||
|
||||
|
||||
class TestMultiSitePage:
|
||||
"""Разбор страницы из нескольких блоков — без локального дампа."""
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def dump_html(self):
|
||||
"""Загружает локальный дамп страницы.
|
||||
def sites(self):
|
||||
return parse_krt_page(_MULTISITE_PAGE)
|
||||
|
||||
Тест пропускается если файл отсутствует (CI без дампа).
|
||||
"""
|
||||
import os
|
||||
def test_all_three_sites_parsed(self, sites):
|
||||
"""Три блока в двух годовых секциях → три площадки."""
|
||||
assert len(sites) == 3, f"Ожидалось 3 площадки, получено {len(sites)}: {sites}"
|
||||
|
||||
dump_path = os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"../../../../.playwright-mcp/ekb-docs/krt_page_raw.html",
|
||||
)
|
||||
if not os.path.exists(dump_path):
|
||||
pytest.skip("krt_page_raw.html dump not found — skip real-dump test")
|
||||
with open(dump_path, encoding="utf-8") as fh:
|
||||
return fh.read()
|
||||
|
||||
def test_site_count_from_dump(self, dump_html):
|
||||
"""Из дампа должно распарситься ≥ 14 площадок (реальных на странице 15)."""
|
||||
sites = parse_krt_page(dump_html)
|
||||
assert len(sites) >= 14, f"Expected ≥ 14 sites, got {len(sites)}"
|
||||
|
||||
def test_no_duplicate_site_names(self, dump_html):
|
||||
sites = parse_krt_page(dump_html)
|
||||
def test_no_duplicate_site_names(self, sites):
|
||||
"""Номер «2.» встречается дважды (2022 и 2024) — имена всё равно уникальны."""
|
||||
names = [s.site_name for s in sites]
|
||||
assert len(names) == len(set(names)), "Дубликаты site_name в результате"
|
||||
assert sum(n.startswith("2.") for n in names) == 2, names
|
||||
assert len(names) == len(set(names)), f"Дубликаты site_name: {names}"
|
||||
|
||||
def test_blocks_do_not_leak_into_each_other(self, sites):
|
||||
"""Границы блоков соблюдены: договор и застройщик остались у своей площадки.
|
||||
|
||||
Регресс, который этим ловится: если block_end съезжает, «Брусника» и
|
||||
договор 1-2/21.7-14 из первого блока прилипают ко второму и третьему.
|
||||
"""
|
||||
with_developer = [s for s in sites if s.developer_name]
|
||||
assert len(with_developer) == 1, [s.developer_name for s in sites]
|
||||
assert "Брусника" in with_developer[0].developer_name
|
||||
assert [s.contract_number for s in sites].count("1-2/21.7-14") == 1
|
||||
|
||||
def test_kinds_are_read_per_block(self, sites):
|
||||
"""Третий блок — «нежилой застройки», не должен унаследовать вид соседа."""
|
||||
kinds = sorted(s.krt_kind for s in sites if s.krt_kind)
|
||||
assert kinds == ["жилой застройки", "жилой застройки", "нежилой застройки"], kinds
|
||||
|
|
|
|||
|
|
@ -73,14 +73,22 @@ tests/scrapers/test_nspd_bulk_client.py::test_search_by_quarter_real_ekb
|
|||
tests/scrapers/test_nspd_bulk_client.py::test_wms_feature_info_real
|
||||
tests/scrapers/test_nspd_grid_walk.py::test_live_nspd_grid_walk_skipped
|
||||
|
||||
# ── Образцы, которых нет в git ────────────────────────────────────────────────
|
||||
# ДОЛГ, а не норма: парсеры проверяются на реальных дампах, которые лежат только
|
||||
# в untracked `.playwright-mcp/`. Пока файлы не в репозитории, эти 8 проверок не
|
||||
# исполняются нигде. Правильная починка — закоммитить образцы в tests/fixtures/
|
||||
# (как сделано в tradein-mvp/backend/tests/fixtures/*.html), после чего строки
|
||||
# отсюда убрать.
|
||||
tests/services/scrapers/test_ekb_krt_registry.py::TestMultiSiteCountFromDump::test_no_duplicate_site_names
|
||||
tests/services/scrapers/test_ekb_krt_registry.py::TestMultiSiteCountFromDump::test_site_count_from_dump
|
||||
# ── Образец, которого нет в git ───────────────────────────────────────────────
|
||||
# ДОЛГ, а не норма. Было 8 записей; 2 из них (test_ekb_krt_registry.py::
|
||||
# TestMultiSiteCountFromDump) сняты в #2778: дампа `krt_page_raw.html` не
|
||||
# оказалось НИГДЕ — ни в репозитории, ни на дисках, ни на проде (в БД лежит
|
||||
# `raw_block` = уже очищенный текст, вход парсера из него не восстановить), —
|
||||
# зато свойство, которое они проверяли (несколько блоков на странице, уникальные
|
||||
# site_name), выразимо без дампа и теперь проверяется на многоблочной странице,
|
||||
# собранной из блоков, уже лежащих в том же тест-файле.
|
||||
#
|
||||
# Оставшиеся 6 так не лечатся: они проверяют извлечение таблиц из НАСТОЯЩЕГО PDF
|
||||
# через pdfplumber, соседний класс TestParsePptTep уже мокает pdfplumber целиком.
|
||||
# Нужен файл `ppt2018_22823_poyasnit_PPT.pdf` (или рабочий URL на ГИСОГД ЕКБ) —
|
||||
# запрошен у Anton в #2778, там же список того, что оживёт. Причин не коммитить
|
||||
# нет: официальный градостроительный документ, без персональных данных.
|
||||
# После получения — положить в tests/fixtures/, поправить `_REAL_PDF_PATH`,
|
||||
# убрать эти шесть строк.
|
||||
tests/services/scrapers/test_ekb_ppt_tep_parser.py::TestParsePptTepRealPdf::test_phasing_has_area
|
||||
tests/services/scrapers/test_ekb_ppt_tep_parser.py::TestParsePptTepRealPdf::test_phasing_has_rows
|
||||
tests/services/scrapers/test_ekb_ppt_tep_parser.py::TestParsePptTepRealPdf::test_raw_tables_not_empty
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue