From 635381f7b8e671fc7e066f0f5c18371a8b1b6140 Mon Sep 17 00:00:00 2001 From: bot-backend Date: Thu, 17 Sep 2026 14:45:54 +0500 Subject: [PATCH] =?UTF-8?q?fix(tests):=20=D0=BA=D1=80=D0=B0=D1=81=D0=BD?= =?UTF-8?q?=D1=8B=D0=B9=20main=20=E2=80=94=20=D1=82=D0=B5=D1=81=D1=82?= =?UTF-8?q?=D1=8B=20#3466=20=D1=87=D0=B8=D1=82=D0=B0=D0=BB=D0=B8=20=D0=BD?= =?UTF-8?q?=D0=B0=D1=81=D1=82=D1=80=D0=BE=D0=B9=D0=BA=D0=B8,=20=D0=BA?= =?UTF-8?q?=D0=BE=D1=82=D0=BE=D1=80=D1=8B=D0=B5=20#3556=20=D0=BF=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=D0=B2=D1=91=D0=BB=20=D0=B2=20=D0=BA=D0=BE=D0=BD?= =?UTF-8?q?=D1=81=D1=82=D0=B0=D0=BD=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Семантический конфликт двух PR, смерженных 17.09 подряд. Текстового конфликта не было, CI каждого PR был зелёным на своей голове, а объединённое дерево падало: test_3466_corridor_tier_a.py (2), test_estimator_radius_floor.py (2) AttributeError: 'Settings' object has no attribute 'estimate_corridor_clamp_slack' TypeError: _run_estimate() got an unexpected keyword argument 'radius_floor_factor' #3554 (Tier A и advisory_only) писал тесты против settings.estimate_corridor_clamp_*, а #3556 (#2380) убрал эти поля из Settings в константы CORRIDOR_CLAMP_SLACK (estimator) и CORRIDOR_CLAMP_MIN_N (app.core.config) и снял параметр radius_floor_factor у хелпера. Продуктовый код не затронут: в app/ старые имена остались только в комментарии, на проде AttributeError не было. Но красный test блокировал деплой МЕРЫ: на проде до сих пор образ до второй пачки мержей. Тесты переведены на константы, значения прежние (0.40, 10, 0.8). pytest tests/ — 6374 passed, 44 skipped, rc=0; ruff check/format — rc=0. Co-Authored-By: Claude Opus 5 --- .../tests/test_3466_corridor_tier_a.py | 3 +-- .../tests/test_estimator_radius_floor.py | 20 +++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/tradein-mvp/backend/tests/test_3466_corridor_tier_a.py b/tradein-mvp/backend/tests/test_3466_corridor_tier_a.py index 4350f621..72542446 100644 --- a/tradein-mvp/backend/tests/test_3466_corridor_tier_a.py +++ b/tradein-mvp/backend/tests/test_3466_corridor_tier_a.py @@ -26,7 +26,6 @@ from unittest.mock import MagicMock, patch os.environ.setdefault("DATABASE_URL", "postgresql+psycopg://test:test@localhost:5432/test") -from app.core.config import settings from app.services import estimator from app.services.geocoder import GeocodeResult @@ -45,7 +44,7 @@ _ANCHOR_PPM2 = (190_000, 195_000, 200_000, 205_000, 210_000) def _cap() -> float: - return _CORRIDOR["high_ppm2"] * (1.0 + settings.estimate_corridor_clamp_slack) + return _CORRIDOR["high_ppm2"] * (1.0 + estimator.CORRIDOR_CLAMP_SLACK) def _call( diff --git a/tradein-mvp/backend/tests/test_estimator_radius_floor.py b/tradein-mvp/backend/tests/test_estimator_radius_floor.py index c532ed95..0f3e8485 100644 --- a/tradein-mvp/backend/tests/test_estimator_radius_floor.py +++ b/tradein-mvp/backend/tests/test_estimator_radius_floor.py @@ -8,8 +8,8 @@ - radius median выше dkp_low × factor → no-op (медиана не изменена) - dkp_raw is None → no-op (нет базы для floor) - anchor-путь (anchor_tier != None) → не затронут floor'ом -- коридор ниже estimate_corridor_clamp_min_n → floor не применяется (#3466) -- коридор ровно estimate_corridor_clamp_min_n → floor применяется (#3466) +- коридор ниже CORRIDOR_CLAMP_MIN_N → floor не применяется (#3466) +- коридор ровно CORRIDOR_CLAMP_MIN_N → floor применяется (#3466) """ from __future__ import annotations @@ -194,23 +194,23 @@ def test_no_dkp_raw_no_floor() -> None: def test_floor_not_applied_below_clamp_min_n() -> None: - """n = estimate_corridor_clamp_min_n − 1: тот же floor, что в тесте 1, но выключен. + """n = CORRIDOR_CLAMP_MIN_N − 1: тот же floor, что в тесте 1, но выключен. `DkpCorridor.advisory_only` (#3452) обосновывает себя общим порогом у клампа headline И у radius-floor. Половина про кламп стережётся test_3452_*, эта — здесь: без гейта по count медиана 80k поднялась бы до 120k. """ - from app.core.config import settings + from app.core.config import CORRIDOR_CLAMP_MIN_N analogs = _six(80_000.0) dkp_raw = { - "count": settings.estimate_corridor_clamp_min_n - 1, + "count": CORRIDOR_CLAMP_MIN_N - 1, "low_ppm2": 150_000, "median_ppm2": 180_000, "high_ppm2": 220_000, "period_months": 12, } - est = _run_estimate(analogs, dkp_raw, radius_floor_factor=0.8) + est = _run_estimate(analogs, dkp_raw) assert est.median_price_per_m2 < 100_000, ( f"median_ppm2={est.median_price_per_m2}: коридор из " @@ -222,18 +222,18 @@ def test_floor_not_applied_below_clamp_min_n() -> None: def test_floor_applied_at_exactly_clamp_min_n() -> None: - """n = estimate_corridor_clamp_min_n: advisory_only=False → floor обязан поднять. + """n = CORRIDOR_CLAMP_MIN_N: advisory_only=False → floor обязан поднять. Тест 4 стережёт «ниже порога — нет», тест 1 — «15 сделок — да». Граница между ними (`>=` против `>`) не стереглась: при n == min_n витрина не пишет подпись «справочно», значит коридор обязан войти в цену. """ - from app.core.config import settings + from app.core.config import CORRIDOR_CLAMP_MIN_N from app.schemas.trade_in import DkpCorridor analogs = _six(80_000.0) dkp_raw = { - "count": settings.estimate_corridor_clamp_min_n, + "count": CORRIDOR_CLAMP_MIN_N, "low_ppm2": 150_000, "median_ppm2": 180_000, "high_ppm2": 220_000, @@ -242,7 +242,7 @@ def test_floor_applied_at_exactly_clamp_min_n() -> None: # Та же граница с другой стороны: на ней коридор уже не справочный. assert DkpCorridor(**dkp_raw).advisory_only is False - est = _run_estimate(analogs, dkp_raw, radius_floor_factor=0.8) + est = _run_estimate(analogs, dkp_raw) assert est.median_price_per_m2 == 150_000 * 0.8, ( f"median_ppm2={est.median_price_per_m2}: коридор из {dkp_raw['count']} сделок " -- 2.45.3