All checks were successful
CI Trade-In / changes (pull_request) Successful in 10s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 14s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 2m31s
CI / backend-tests (pull_request) Successful in 6m44s
Регекс номера требовал суффикс областных актов (-ПП/-ПА/-РП/-ПГ/-ГП/-МО), а у постановлений Администрации Екатеринбурга его нет: на проде act_number пуст у всех 27 строк (17.09.2026). - izyatie_ocr: номер берётся у того же акта, чью дату выбирает _extract_act_date (вплотную после «от DD.MM.YYYY», иначе перед ней). Первое «№» в теле — «Решение Думы № 60/1» или «Приказ № 746-П». - page_reservation_parser: суффикс необязателен; номер с суффиксом не из списка («218-ФЗ», «746-П», «60/1») отбрасывается целиком, а не обрезается. - izyatie_ocr_ingest: перед записью удаляется прежний разбор того же участка из того же документа с другим номером. act_number в ключе конфликта, без этого прогон положил бы 27 строк с номером рядом с 27 строками без номера. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
103 lines
6.4 KiB
Python
103 lines
6.4 KiB
Python
"""act_number извлекается у постановлений Администрации Екатеринбурга (#2982).
|
||
|
||
Регекс номера требовал суффикс областных актов (`-ПП/-ПА/-РП/-ПГ/-ГП/-МО`). У
|
||
постановлений Администрации города его нет, поэтому на проде `act_number` пуст у
|
||
всех 27 строк `land_reservation` (замер 17.09.2026: 27 строк, заполнено 0).
|
||
|
||
Фрагменты — дословный OCR пяти прод-документов из test_2464_act_date_citation
|
||
(распознаны `ocr_pdf_text` в прод-контейнере). Ожидаемые номера — из самих PDF:
|
||
1413, 259, 2687, 863, 1504. Помехи в тех же текстах — «Решение Думы № 60/1»
|
||
(Генплан) и «Приказ Министерства № 746-П»: их номер браться не должен.
|
||
|
||
Тест зовёт `extract_izyatie_records` — путь загрузчика — и краснеет на origin/main
|
||
неверным значением (None вместо номера), а не ошибкой сигнатуры.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import pytest
|
||
|
||
from app.services.scrapers.izyatie_ocr import extract_izyatie_records
|
||
from app.services.scrapers.page_reservation_parser import extract_reservations
|
||
from tests.services.scrapers.test_2464_act_date_citation import (
|
||
ДОК_ПЕРЕМЕШАННЫЙ,
|
||
ДОК_ПЕРЕМЕШАННЫЙ_2,
|
||
ДОК_ПРЯМОЙ,
|
||
ДОК_РАЗВЯЗКА,
|
||
ДОК_ЭНЕРГОСТРОИТЕЛЕЙ,
|
||
ЗАГОЛОВОК,
|
||
КАД,
|
||
)
|
||
|
||
ПЯТЬ_ДОКУМЕНТОВ = [
|
||
pytest.param(ДОК_РАЗВЯЗКА, "1413", "2022-05-27", id="развязка"),
|
||
pytest.param(ДОК_ЭНЕРГОСТРОИТЕЛЕЙ, "259", "2020-02-12", id="энергостроителей"),
|
||
pytest.param(ДОК_ПЕРЕМЕШАННЫЙ, "2687", "2015-09-29", id="павлодарская"),
|
||
pytest.param(ДОК_ПЕРЕМЕШАННЫЙ_2, "863", "2019-04-19", id="иркутская"),
|
||
pytest.param(ДОК_ПРЯМОЙ, "1504", "2019-06-24", id="татищева"),
|
||
]
|
||
|
||
|
||
def _запись(текст: str) -> dict:
|
||
записи = extract_izyatie_records(f"{текст}\n{КАД}", ЗАГОЛОВОК, "http://x/y")
|
||
assert записи, "кад-номер не разобран — тест смотрел бы не туда"
|
||
return записи[0]
|
||
|
||
|
||
@pytest.mark.parametrize(("текст", "номер", "дата"), ПЯТЬ_ДОКУМЕНТОВ)
|
||
def test_act_number_of_ekb_administration_resolution(текст: str, номер: str, дата: str) -> None:
|
||
"""Головной: номер постановления без суффикса извлекается, и это номер того же акта,
|
||
чья дата стоит в act_date, — а не Решения Думы или приказа Министерства."""
|
||
запись = _запись(текст)
|
||
assert запись["act_number"] == номер
|
||
assert запись["act_date"] == дата
|
||
|
||
|
||
@pytest.mark.parametrize(("текст", "номер", "_дата"), ПЯТЬ_ДОКУМЕНТОВ)
|
||
def test_page_parser_takes_the_same_numbers(текст: str, номер: str, _дата: str) -> None:
|
||
"""Второе место того же дефекта — page_reservation_parser (pravo.gov66).
|
||
|
||
Там номер — первое «№» в тексте. В двух документах первыми идут «№ 60/1» и
|
||
«№ 746-П»: их нельзя ни взять, ни обрезать до «60»/«746».
|
||
"""
|
||
assert extract_reservations(f"{текст}\n{КАД}")[0].act_number == номер
|
||
|
||
|
||
def test_citations_alone_give_no_number() -> None:
|
||
"""Контроль: без постановления — None, а не номер Генплана или приказа."""
|
||
текст = (
|
||
"Решение Екатеринбургской городской Думы от 06.07.2004 № 60/1 «Об утверждении»;\n"
|
||
"Приказ Министерства строительства и развития инфраструктуры Свердловской "
|
||
"области от 30.12.2021 № 746-П"
|
||
)
|
||
assert _запись(текст)["act_number"] is None
|
||
assert extract_reservations(f"{текст}\n{КАД}")[0].act_number is None
|
||
|
||
|
||
def test_number_belongs_to_the_act_whose_date_is_taken() -> None:
|
||
"""Контроль связки: номер берётся у того же акта, что и дата, а не первое «№».
|
||
|
||
Тот же документ «развязка», но у приказа Министерства номер без суффикса.
|
||
Первое подходящее «№» в тексте — «746», дата при этом у постановления № 1413:
|
||
в строке оказалась бы пара реквизитов от двух разных документов.
|
||
"""
|
||
текст = ДОК_РАЗВЯЗКА.replace("№ 746-П", "№ 746")
|
||
запись = _запись(текст)
|
||
assert (запись["act_date"], запись["act_number"]) == ("2022-05-27", "1413")
|
||
|
||
|
||
def test_page_parser_prefers_own_number_over_cited_regional_act() -> None:
|
||
"""Контроль порядка: собственный номер в шапке без суффикса не пропускается ради
|
||
следующего «№ …-ПП» — номера цитируемого постановления Правительства."""
|
||
текст = (
|
||
"ПРИКАЗ\nот 12.03.2024 № 1234\nОб изъятии земельных участков\n"
|
||
"В соответствии с постановлением Правительства Свердловской области "
|
||
f"от 26.02.2020 № 100-ПП\n{КАД}"
|
||
)
|
||
assert extract_reservations(текст)[0].act_number == "1234"
|
||
|
||
|
||
def test_regional_suffix_still_extracted() -> None:
|
||
"""Контроль от переусердствования: областной номер с суффиксом не потерян."""
|
||
assert _запись("Постановление № 509-ПП от 12.03.2024")["act_number"] == "509-ПП"
|
||
assert _запись("Постановление Правительства от 12.03.2024 № 509-ПП")["act_number"] == "509-ПП"
|