Coverage for src/lexigram/web/interceptors/builtin/transform.py: 47%

19 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-25 04:37 +0800

1"""Transform interceptor for response transformation. 

2 

3Allows transformation of handler responses before they're returned. 

4""" 

5 

6from __future__ import annotations 

7 

8from typing import TYPE_CHECKING, Any 

9 

10from lexigram.web.protocols import ( 

11 CallHandlerProtocol, 

12 ExecutionContextProtocol, 

13 WebInterceptorProtocol, 

14) 

15 

16if TYPE_CHECKING: 

17 from collections.abc import Callable 

18 

19 

20class TransformInterceptor(WebInterceptorProtocol): 

21 """Interceptor that transforms handler responses. 

22 

23 Can wrap, envelope, or restructure responses before they're returned. 

24 Useful for standardizing API response formats. 

25 

26 Example: 

27 ```python 

28 # Wrap all responses in a standard envelope 

29 class EnvelopeInterceptor(TransformInterceptor): 

30 def transform(self, data: Any) -> dict: 

31 return {"success": True, "data": data} 

32 

33 router.add_interceptor(EnvelopeInterceptor()) 

34 ``` 

35 """ 

36 

37 def __init__( 

38 self, 

39 transform: Callable[[Any], Any] | None = None, 

40 wrap_response: bool = False, 

41 ): 

42 """Initialize the transform interceptor. 

43 

44 Args: 

45 transform: Optional custom transform function. 

46 wrap_response: If True, wraps response in a standard format. 

47 """ 

48 self._transform = transform 

49 self._wrap_response = wrap_response 

50 

51 async def intercept( 

52 self, 

53 context: ExecutionContextProtocol, 

54 next_handler: CallHandlerProtocol, 

55 ) -> Any: 

56 """Intercept and transform the response. 

57 

58 Args: 

59 context: The execution context. 

60 next_handler: The next handler in the chain. 

61 

62 Returns: 

63 Transformed response. 

64 """ 

65 result = await next_handler.handle() 

66 

67 # Apply transformation 

68 if self._transform: 

69 return self._transform(result) 

70 

71 # Default wrap behavior 

72 if self._wrap_response: 

73 return self._wrap(result) 

74 

75 return result 

76 

77 def transform(self, data: Any) -> Any: 

78 """Transform the data. 

79 

80 Override this in subclasses to provide custom transformation. 

81 

82 Args: 

83 data: The data to transform. 

84 

85 Returns: 

86 Transformed data. 

87 """ 

88 return data 

89 

90 def _wrap(self, data: Any) -> dict[str, Any]: 

91 """Wrap data in standard response format. 

92 

93 Args: 

94 data: The data to wrap. 

95 

96 Returns: 

97 Wrapped response. 

98 """ 

99 return { 

100 "success": True, 

101 "data": data, 

102 } 

103 

104 

105__all__ = ["TransformInterceptor"]