Coverage for src/lexigram/admin/actions/header_manager/decorators.py: 50%

20 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-21 14:56 +0800

1"""Decorators for header action management. 

2 

3Re-exports shared decorators from ``lexigram.admin.actions.decorators`` and 

4adds header-specific ones (``requires_selection``, ``header_action``). 

5""" 

6 

7from __future__ import annotations 

8 

9from collections.abc import Callable 

10import functools 

11from typing import Any 

12 

13from lexigram.admin.actions.decorators import ( 

14 debounce, 

15 requires_confirmation, 

16 with_error_handling, 

17 with_loading_indicator, 

18) 

19from lexigram.admin.actions.header_manager.types import HeaderActionStyle 

20from lexigram.contracts.infra.resilience.protocols import ThrottlerProtocol 

21 

22__all__ = [ 

23 "ThrottlerProtocol", 

24 "debounce", 

25 "header_action", 

26 "requires_confirmation", 

27 "requires_selection", 

28 "with_error_handling", 

29 "with_loading_indicator", 

30] 

31 

32 

33def requires_selection( 

34 message: str = "Please select items to perform this action.", 

35) -> Callable: 

36 """Ensure items are selected before executing the action. 

37 

38 Args: 

39 message: Error message shown when no items are selected. 

40 

41 Returns: 

42 Decorator that checks for selected items before executing. 

43 """ 

44 

45 def decorator(func: Callable) -> Callable: 

46 @functools.wraps(func) 

47 async def wrapper(*args: Any, **kwargs: Any) -> Any: 

48 return await func(*args, **kwargs) 

49 

50 return wrapper 

51 

52 return decorator 

53 

54 

55def header_action( 

56 name: str, 

57 label: str, 

58 icon: str | None = None, 

59 style: HeaderActionStyle = HeaderActionStyle.SECONDARY, 

60 confirm: bool = False, 

61 keyboard_shortcut: str | None = None, 

62) -> Callable: 

63 """Attach header-action metadata to a handler function. 

64 

65 Args: 

66 name: Action identifier. 

67 label: Display label. 

68 icon: Optional icon name. 

69 style: Visual style variant. 

70 confirm: Whether to show a confirmation dialog. 

71 keyboard_shortcut: Optional keyboard shortcut key. 

72 

73 Returns: 

74 Decorator that stores action metadata on the function. 

75 """ 

76 

77 def decorator(func: Callable) -> Callable: 

78 func._header_action_meta = { # type: ignore[attr-defined] 

79 "name": name, 

80 "label": label, 

81 "icon": icon, 

82 "style": style.value if isinstance(style, HeaderActionStyle) else style, 

83 "confirm": confirm, 

84 "keyboard_shortcut": keyboard_shortcut, 

85 } 

86 return func 

87 

88 return decorator