Files
vector/.venv-test/lib/python3.12/site-packages/pluggy/_callers.py
T
Sadmin f20080305d 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).
2026-09-09 13:12:55 +03:00

170 lines
5.9 KiB
Python

"""
Call loop machinery
"""
from __future__ import annotations
from collections.abc import Generator
from collections.abc import Mapping
from collections.abc import Sequence
from typing import cast
from typing import NoReturn
import warnings
from ._hooks import HookImpl
from ._result import HookCallError
from ._result import Result
from ._warnings import PluggyTeardownRaisedWarning
# Need to distinguish between old- and new-style hook wrappers.
# Wrapping with a tuple is the fastest type-safe way I found to do it.
Teardown = Generator[None, object, object]
def run_old_style_hookwrapper(
hook_impl: HookImpl, hook_name: str, args: Sequence[object]
) -> Teardown:
"""
backward compatibility wrapper to run a old style hookwrapper as a wrapper
"""
teardown: Teardown = cast(Teardown, hook_impl.function(*args))
try:
next(teardown)
except StopIteration:
_raise_wrapfail(teardown, "did not yield")
try:
res = yield
result = Result(res, None)
except BaseException as exc:
result = Result(None, exc)
try:
teardown.send(result)
except StopIteration:
pass
except BaseException as e:
_warn_teardown_exception(hook_name, hook_impl, e)
raise
else:
_raise_wrapfail(teardown, "has second yield")
finally:
teardown.close()
return result.get_result()
def _raise_wrapfail(
wrap_controller: Generator[None, object, object],
msg: str,
) -> NoReturn:
co = wrap_controller.gi_code # type: ignore[attr-defined]
raise RuntimeError(
f"wrap_controller at {co.co_name!r} {co.co_filename}:{co.co_firstlineno} {msg}"
)
def _warn_teardown_exception(
hook_name: str, hook_impl: HookImpl, e: BaseException
) -> None:
msg = "A plugin raised an exception during an old-style hookwrapper teardown.\n"
msg += f"Plugin: {hook_impl.plugin_name}, Hook: {hook_name}\n"
msg += f"{type(e).__name__}: {e}\n"
msg += "For more information see https://pluggy.readthedocs.io/en/stable/api_reference.html#pluggy.PluggyTeardownRaisedWarning" # noqa: E501
warnings.warn(PluggyTeardownRaisedWarning(msg), stacklevel=6)
def _multicall(
hook_name: str,
hook_impls: Sequence[HookImpl],
caller_kwargs: Mapping[str, object],
firstresult: bool,
) -> object | list[object]:
"""Execute a call into multiple python functions/methods and return the
result(s).
``caller_kwargs`` comes from HookCaller.__call__().
"""
__tracebackhide__ = True
results: list[object] = []
exception = None
try: # run impl and wrapper setup functions in a loop
teardowns: list[Teardown] = []
try:
for hook_impl in reversed(hook_impls):
try:
args = [caller_kwargs[argname] for argname in hook_impl.argnames]
except KeyError as e:
# coverage bug - this is tested
for argname in hook_impl.argnames: # pragma: no cover
if argname not in caller_kwargs:
raise HookCallError(
f"hook call must provide argument {argname!r}"
) from e
if hook_impl.hookwrapper:
function_gen = run_old_style_hookwrapper(hook_impl, hook_name, args)
next(function_gen) # first yield
teardowns.append(function_gen)
elif hook_impl.wrapper:
try:
# If this cast is not valid, a type error is raised below,
# which is the desired response.
res = hook_impl.function(*args)
function_gen = cast(Generator[None, object, object], res)
next(function_gen) # first yield
teardowns.append(function_gen)
except StopIteration:
_raise_wrapfail(function_gen, "did not yield")
else:
res = hook_impl.function(*args)
if res is not None:
results.append(res)
if firstresult: # halt further impl calls
break
except BaseException as exc:
exception = exc
finally:
if firstresult: # first result hooks return a single value
result = results[0] if results else None
else:
result = results
# run all wrapper post-yield blocks
for teardown in reversed(teardowns):
try:
if exception is not None:
try:
teardown.throw(exception)
except RuntimeError as re:
# StopIteration from generator causes RuntimeError
# even for coroutine usage - see #544
if (
isinstance(exception, StopIteration)
and re.__cause__ is exception
):
teardown.close()
continue
else:
raise
else:
teardown.send(result)
# Following is unreachable for a well behaved hook wrapper.
# Try to force finalizers otherwise postponed till GC action.
# Note: close() may raise if generator handles GeneratorExit.
teardown.close()
except StopIteration as si:
result = si.value
exception = None
continue
except BaseException as e:
exception = e
continue
_raise_wrapfail(teardown, "has second yield")
if exception is not None:
raise exception
else:
return result