Coverage for fastblocks/decorators.py: 100%

26 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2025-09-21 04:50 -0700

1import functools 

2import typing as t 

3from collections.abc import Sequence 

4 

5from starlette.types import ASGIApp 

6 

7from .caching import CacheDirectives, Rule 

8from .middleware import CacheControlMiddleware, CacheMiddleware 

9 

10_P = t.ParamSpec("_P") 

11_T = t.TypeVar("_T", bound=ASGIApp) 

12 

13 

14class _MiddlewareFactory(t.Protocol[_P]): 

15 def __call__( 

16 self, 

17 app: ASGIApp, 

18 *args: _P.args, 

19 **kwargs: _P.kwargs, 

20 ) -> ASGIApp: ... 

21 

22 

23def _wrap_in_middleware[T: ASGIApp](app: T, middleware: ASGIApp) -> T: 

24 return t.cast("T", functools.wraps(app, updated=())(middleware)) 

25 

26 

27class _CacheMiddlewareDecorator: 

28 def __call__( 

29 self, 

30 *, 

31 cache: t.Any, 

32 rules: Sequence[Rule] | None = None, 

33 ) -> t.Callable[[_T], _T]: 

34 def wrap(app: _T) -> _T: 

35 middleware = CacheMiddleware(app, cache=cache, rules=rules) 

36 return _wrap_in_middleware(app, middleware) 

37 

38 return wrap 

39 

40 

41class _CacheControlMiddlewareDecorator: 

42 def __call__(self, **kwargs: t.Unpack[CacheDirectives]) -> t.Callable[[_T], _T]: 

43 def wrap(app: _T) -> _T: 

44 middleware = CacheControlMiddleware(app, **kwargs) 

45 return _wrap_in_middleware(app, middleware) 

46 

47 return wrap 

48 

49 

50cached = _CacheMiddlewareDecorator() 

51cache_control = _CacheControlMiddlewareDecorator() 

52__all__ = ["_MiddlewareFactory", "cache_control", "cached"]