From 0cf0ab3358828d9a1b3b16ae1a46dca402497aa1 Mon Sep 17 00:00:00 2001 From: lekss361 Date: Sat, 16 May 2026 08:55:53 +0300 Subject: [PATCH] fix(site-finder): narrow except clauses, fix quarter fallback WKT, add LIMIT to zouit query MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses review-bot blockers on PR #190 (4 reviews flagged same issues): 1. Narrow except in quarter_dump_lookup.py: - line 579/651: except Exception -> (OperationalError, ProgrammingError) для outer DB queries - line 598/668: except Exception -> (ValueError, json.JSONDecodeError) для json.loads fallback 2. _get_parcel_wkt fallback (line 506-521): cad_quarters_geom хранит 3-segment quarter keys, а cad_num передавался 4-segment -> fallback всегда возвращал NULL. Теперь derive_quarter_cad(cad_num). 3. _get_zouit_engineering_overlaps: добавлен LIMIT 100 для unbounded jsonb_array_elements fan-out (engineering_structures query уже имел LIMIT 50). --- .../services/site_finder/quarter_dump_lookup.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/backend/app/services/site_finder/quarter_dump_lookup.py b/backend/app/services/site_finder/quarter_dump_lookup.py index 69b731bb..ce5d9213 100644 --- a/backend/app/services/site_finder/quarter_dump_lookup.py +++ b/backend/app/services/site_finder/quarter_dump_lookup.py @@ -19,6 +19,7 @@ from datetime import UTC, datetime, timedelta from typing import Any from sqlalchemy import text +from sqlalchemy.exc import OperationalError, ProgrammingError from sqlalchemy.orm import Session logger = logging.getLogger(__name__) @@ -505,7 +506,9 @@ def _get_parcel_wkt(db: Session, cad_num: str) -> str | None: if row is not None and row[0] is not None: return str(row[0]) - # Fallback: кварталы (более крупный объект — менее точно, но лучше чем ничего) + # Fallback: кварталы (более крупный объект — менее точно, но лучше чем ничего). + # cad_quarters_geom хранит 3-сегментные ключи (66:41:0204016), не 4-сегментные. + quarter_key = derive_quarter_cad(cad_num) row = db.execute( text( """ @@ -515,7 +518,7 @@ def _get_parcel_wkt(db: Session, cad_num: str) -> str | None: LIMIT 1 """ ), - {"c": cad_num}, + {"c": quarter_key}, ).first() if row is not None and row[0] is not None: return str(row[0]) @@ -573,7 +576,7 @@ def _get_engineering_structures_by_boundary( ), {"q": quarter, "wkt": parcel_wkt, "radius_m": radius_m}, ).fetchall() - except Exception as e: + except (OperationalError, ProgrammingError) as e: logger.warning( "engineering_structures query failed for quarter=%s: %s", quarter, @@ -592,7 +595,7 @@ def _get_engineering_structures_by_boundary( if geom_raw: try: geom_dict = json.loads(geom_raw) - except Exception: + except (ValueError, json.JSONDecodeError): geom_dict = {} result.append( @@ -641,11 +644,12 @@ def _get_zouit_engineering_overlaps( ), ST_GeomFromText(:wkt, 4326) ) + LIMIT 100 """ ), {"q": quarter, "wkt": parcel_wkt}, ).fetchall() - except Exception as e: + except (OperationalError, ProgrammingError) as e: logger.warning( "zouit_engineering query failed for quarter=%s: %s", quarter, @@ -662,7 +666,7 @@ def _get_zouit_engineering_overlaps( if geom_raw: try: geom_dict = json.loads(geom_raw) - except Exception: + except (ValueError, json.JSONDecodeError): geom_dict = {} subcategory_raw = props.get("subcategory")