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:
2026-09-09 13:12:55 +03:00
parent 98e8e58023
commit f20080305d
2069 changed files with 803865 additions and 97 deletions
@@ -0,0 +1,189 @@
"""Pydantic-specific errors."""
from __future__ import annotations as _annotations
import re
from typing import Any, ClassVar, Literal
from typing_extensions import Self
from typing_inspection.introspection import Qualifier
from pydantic._internal import _repr
from ._migration import getattr_migration
from .version import version_short
__all__ = (
'PydanticUserError',
'PydanticUndefinedAnnotation',
'PydanticImportError',
'PydanticSchemaGenerationError',
'PydanticInvalidForJsonSchema',
'PydanticForbiddenQualifier',
'PydanticErrorCodes',
)
# We use this URL to allow for future flexibility about how we host the docs, while allowing for Pydantic
# code in the while with "old" URLs to still work.
# 'u' refers to "user errors" - e.g. errors caused by developers using pydantic, as opposed to validation errors.
DEV_ERROR_DOCS_URL = f'https://errors.pydantic.dev/{version_short()}/u/'
PydanticErrorCodes = Literal[
'class-not-fully-defined',
'custom-json-schema',
'decorator-invalid-fields',
'decorator-missing-arguments',
'decorator-missing-field',
'discriminator-no-field',
'discriminator-alias-type',
'discriminator-needs-literal',
'discriminator-alias',
'discriminator-validator',
'callable-discriminator-no-tag',
'typed-dict-version',
'model-field-overridden',
'model-field-missing-annotation',
'config-both',
'removed-kwargs',
'circular-reference-schema',
'invalid-for-json-schema',
'json-schema-already-used',
'base-model-instantiated',
'undefined-annotation',
'schema-for-unknown-type',
'import-error',
'create-model-field-definitions',
'validator-instance-method',
'validator-input-type',
'root-validator-pre-skip',
'model-serializer-instance-method',
'validator-field-config-info',
'validator-v1-signature',
'validator-signature',
'field-serializer-signature',
'model-serializer-signature',
'multiple-field-serializers',
'invalid-annotated-type',
'type-adapter-config-unused',
'root-model-extra',
'unevaluable-type-annotation',
'dataclass-init-false-extra-allow',
'clashing-init-and-init-var',
'model-config-invalid-field-name',
'with-config-on-model',
'dataclass-on-model',
'validate-call-type',
'unpack-typed-dict',
'overlapping-unpack-typed-dict',
'invalid-self-type',
'validate-by-alias-and-name-false',
]
class PydanticErrorMixin:
"""A mixin class for common functionality shared by all Pydantic-specific errors.
Attributes:
message: A message describing the error.
code: An optional error code from PydanticErrorCodes enum.
"""
def __init__(self, message: str, *, code: PydanticErrorCodes | None) -> None:
self.message = message
self.code = code
def __str__(self) -> str:
if self.code is None:
return self.message
else:
return f'{self.message}\n\nFor further information visit {DEV_ERROR_DOCS_URL}{self.code}'
class PydanticUserError(PydanticErrorMixin, RuntimeError):
"""An error raised due to incorrect use of Pydantic."""
class PydanticUndefinedAnnotation(PydanticErrorMixin, NameError):
"""A subclass of `NameError` raised when handling undefined annotations during `CoreSchema` generation.
Attributes:
name: Name of the error.
message: Description of the error.
"""
def __init__(self, name: str, message: str) -> None:
self.name = name
super().__init__(message=message, code='undefined-annotation')
@classmethod
def from_name_error(cls, name_error: NameError) -> Self:
"""Convert a `NameError` to a `PydanticUndefinedAnnotation` error.
Args:
name_error: `NameError` to be converted.
Returns:
Converted `PydanticUndefinedAnnotation` error.
"""
try:
name = name_error.name # type: ignore # python > 3.10
except AttributeError:
name = re.search(r".*'(.+?)'", str(name_error)).group(1) # type: ignore[union-attr]
return cls(name=name, message=str(name_error))
class PydanticImportError(PydanticErrorMixin, ImportError):
"""An error raised when an import fails due to module changes between V1 and V2.
Attributes:
message: Description of the error.
"""
def __init__(self, message: str) -> None:
super().__init__(message, code='import-error')
class PydanticSchemaGenerationError(PydanticUserError):
"""An error raised during failures to generate a `CoreSchema` for some type.
Attributes:
message: Description of the error.
"""
def __init__(self, message: str) -> None:
super().__init__(message, code='schema-for-unknown-type')
class PydanticInvalidForJsonSchema(PydanticUserError):
"""An error raised during failures to generate a JSON schema for some `CoreSchema`.
Attributes:
message: Description of the error.
"""
def __init__(self, message: str) -> None:
super().__init__(message, code='invalid-for-json-schema')
class PydanticForbiddenQualifier(PydanticUserError):
"""An error raised if a forbidden type qualifier is found in a type annotation."""
_qualifier_repr_map: ClassVar[dict[Qualifier, str]] = {
'required': 'typing.Required',
'not_required': 'typing.NotRequired',
'read_only': 'typing.ReadOnly',
'class_var': 'typing.ClassVar',
'init_var': 'dataclasses.InitVar',
'final': 'typing.Final',
}
def __init__(self, qualifier: Qualifier, annotation: Any) -> None:
super().__init__(
message=(
f'The annotation {_repr.display_as_type(annotation)!r} contains the {self._qualifier_repr_map[qualifier]!r} '
f'type qualifier, which is invalid in the context it is defined.'
),
code=None,
)
__getattr__ = getattr_migration(__name__)