feat: ж/д слой + cant_swim в скоринг + профили вне модели
Определение специфических рекомендаций (матрица профилей §8):
1. Ж/д слой (закрыт мёртвый railway ×2.5 у РАС):
- /api/v1/water/{case_id} отдаёт railway=rail как LineString
(без service/industrial/military веток), кэш общий v2;
- railway_warning «перекрыть/проверить немедленно» по профилям;
- SearchMap: Polyline слой ж/д (тёмно-красный), счётчики 💧/🚂.
2. cant_swim → профиль не_умеет_плавать (water ×3.0, без изменения
радиуса, critical_warning «обследовать водоёмы НЕМЕДЛЕННО»):
- раньше чекбокс влиял только на текст, в скоринге был пробел;
- derive в analyze._derive_profiles — работает и для closed_cases.
3. unmodeled_profiles: ДЦП/слабое зрение/слух — честная пометка
«вне поведенческой модели» с пояснением (vector_tasks B12:
профили без аналога не выдавать за учтённые); блок на фронте
в карточке здоровья.
Площадь воды: сферический эксцесс, проверен на квадрате 53° (744017 м²
vs 743272 точного). Тесты: 202 passed (новый test_cant_swim_profile).
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
# cyextension/resultproxy.pyx
|
||||
# Copyright (C) 2005-2024 the SQLAlchemy authors and contributors
|
||||
# <see AUTHORS file>
|
||||
#
|
||||
# This module is part of SQLAlchemy and is released under
|
||||
# the MIT License: https://www.opensource.org/licenses/mit-license.php
|
||||
import operator
|
||||
|
||||
cdef class BaseRow:
|
||||
cdef readonly object _parent
|
||||
cdef readonly dict _key_to_index
|
||||
cdef readonly tuple _data
|
||||
|
||||
def __init__(self, object parent, object processors, dict key_to_index, object data):
|
||||
"""Row objects are constructed by CursorResult objects."""
|
||||
|
||||
self._parent = parent
|
||||
|
||||
self._key_to_index = key_to_index
|
||||
|
||||
if processors:
|
||||
self._data = _apply_processors(processors, data)
|
||||
else:
|
||||
self._data = tuple(data)
|
||||
|
||||
def __reduce__(self):
|
||||
return (
|
||||
rowproxy_reconstructor,
|
||||
(self.__class__, self.__getstate__()),
|
||||
)
|
||||
|
||||
def __getstate__(self):
|
||||
return {"_parent": self._parent, "_data": self._data}
|
||||
|
||||
def __setstate__(self, dict state):
|
||||
parent = state["_parent"]
|
||||
self._parent = parent
|
||||
self._data = state["_data"]
|
||||
self._key_to_index = parent._key_to_index
|
||||
|
||||
def _values_impl(self):
|
||||
return list(self)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._data)
|
||||
|
||||
def __len__(self):
|
||||
return len(self._data)
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self._data)
|
||||
|
||||
def __getitem__(self, index):
|
||||
return self._data[index]
|
||||
|
||||
def _get_by_key_impl_mapping(self, key):
|
||||
return self._get_by_key_impl(key, 0)
|
||||
|
||||
cdef _get_by_key_impl(self, object key, int attr_err):
|
||||
index = self._key_to_index.get(key)
|
||||
if index is not None:
|
||||
return self._data[<int>index]
|
||||
self._parent._key_not_found(key, attr_err != 0)
|
||||
|
||||
def __getattr__(self, name):
|
||||
return self._get_by_key_impl(name, 1)
|
||||
|
||||
def _to_tuple_instance(self):
|
||||
return self._data
|
||||
|
||||
|
||||
cdef tuple _apply_processors(proc, data):
|
||||
res = []
|
||||
for i in range(len(proc)):
|
||||
p = proc[i]
|
||||
if p is None:
|
||||
res.append(data[i])
|
||||
else:
|
||||
res.append(p(data[i]))
|
||||
return tuple(res)
|
||||
|
||||
|
||||
def rowproxy_reconstructor(cls, state):
|
||||
obj = cls.__new__(cls)
|
||||
obj.__setstate__(state)
|
||||
return obj
|
||||
|
||||
|
||||
cdef int is_contiguous(tuple indexes):
|
||||
cdef int i
|
||||
for i in range(1, len(indexes)):
|
||||
if indexes[i-1] != indexes[i] -1:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
def tuplegetter(*indexes):
|
||||
if len(indexes) == 1 or is_contiguous(indexes) != 0:
|
||||
# slice form is faster but returns a list if input is list
|
||||
return operator.itemgetter(slice(indexes[0], indexes[-1] + 1))
|
||||
else:
|
||||
return operator.itemgetter(*indexes)
|
||||
Reference in New Issue
Block a user