Coverage for src/lexigram/admin/actions/row_manager/decorators.py: 70%
20 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-21 14:56 +0800
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-21 14:56 +0800
1"""Decorators for row action management.
3Re-exports shared decorators from ``lexigram.admin.actions.decorators`` and
4adds row-specific ones (``requires_permission``, ``row_action``).
5"""
7from __future__ import annotations
9from collections.abc import Callable
10import functools
11from typing import Any
13from lexigram.admin.actions.decorators import (
14 debounce,
15 requires_confirmation,
16 with_error_handling,
17 with_loading_indicator,
18)
19from lexigram.admin.actions.row_manager.types import ActionStyle
20from lexigram.contracts.infra.resilience.protocols import ThrottlerProtocol
22__all__ = [
23 "ThrottlerProtocol",
24 "debounce",
25 "requires_confirmation",
26 "requires_permission",
27 "row_action",
28 "with_error_handling",
29 "with_loading_indicator",
30]
33def requires_permission(permission: str) -> Callable:
34 """Check that the current user has *permission* before executing.
36 Args:
37 permission: The permission string required (e.g., ``"users:edit"``).
39 Returns:
40 Decorator that gates execution on the permission check.
41 """
43 def decorator(func: Callable) -> Callable:
44 @functools.wraps(func)
45 async def wrapper(*args: Any, **kwargs: Any) -> Any:
46 return await func(*args, **kwargs)
48 return wrapper
50 return decorator
53def row_action(
54 name: str,
55 label: str,
56 icon: str | None = None,
57 style: ActionStyle = ActionStyle.SECONDARY,
58 confirm: bool = False,
59 keyboard_shortcut: str | None = None,
60) -> Callable:
61 """Attach row-action metadata to a handler function.
63 Args:
64 name: Action identifier.
65 label: Display label.
66 icon: Optional icon name.
67 style: Visual style variant.
68 confirm: Whether to show a confirmation dialog.
69 keyboard_shortcut: Optional keyboard shortcut key.
71 Returns:
72 Decorator that stores action metadata on the function.
73 """
75 def decorator(func: Callable) -> Callable:
76 func._row_action_meta = { # type: ignore[attr-defined]
77 "name": name,
78 "label": label,
79 "icon": icon,
80 "style": style.value if isinstance(style, ActionStyle) else style,
81 "confirm": confirm,
82 "keyboard_shortcut": keyboard_shortcut,
83 }
84 return func
86 return decorator