Coverage for src/lexigram/web/integrations/cache.py: 40%

25 statements  

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

1"""Cache integration — attaches Redis client to ASGI app state for lifespan cleanup.""" 

2 

3from __future__ import annotations 

4 

5from typing import TYPE_CHECKING 

6 

7from lexigram.contracts.core.di import ContainerResolverProtocol 

8from lexigram.contracts.exceptions import UnresolvableDependencyError 

9from lexigram.contracts.infra.cache import CacheBackendProtocol 

10from lexigram.logging import get_logger 

11 

12if TYPE_CHECKING: 

13 from starlette.applications import Starlette 

14 

15logger = get_logger(__name__) 

16 

17 

18class CacheIntegration: 

19 """Resolves the cache backend and attaches Redis client to app.state. 

20 

21 Optional integration: silently skips if no cache module is registered 

22 or if the backend doesn't expose an underlying Redis client (e.g., memory backend). 

23 """ 

24 

25 @staticmethod 

26 async def configure( 

27 app: Starlette, 

28 container: ContainerResolverProtocol, 

29 ) -> None: 

30 """Attach the Redis client to app.state.redis_client. 

31 

32 Args: 

33 app: The ASGI application. 

34 container: The DI container resolver. 

35 

36 Note: 

37 This integration only attaches the client for Redis backends. 

38 Memory backends don't have an underlying client and are skipped. 

39 """ 

40 try: 

41 cache = await container.resolve(CacheBackendProtocol) 

42 except (LookupError, UnresolvableDependencyError, ValueError): 

43 logger.debug("No cache module registered; CacheIntegration skipped") 

44 return 

45 

46 if cache is None: 

47 logger.debug("No cache module registered; CacheIntegration skipped") 

48 return 

49 

50 if hasattr(cache, "get_underlying_client"): 

51 client = cache.get_underlying_client() 

52 if client is not None: 

53 app.state.redis_client = client 

54 logger.info("CacheIntegration: redis_client attached to app.state") 

55 else: 

56 logger.debug( 

57 "Cache backend has no underlying client (memory backend?); " 

58 "CacheIntegration skipped" 

59 ) 

60 else: 

61 logger.debug( 

62 "Cache backend doesn't expose get_underlying_client; " 

63 "CacheIntegration skipped" 

64 )