Coverage for fastblocks/initializers.py: 26%
74 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-21 04:50 -0700
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-21 04:50 -0700
1"""Application initialization components for FastBlocks.
3This module contains classes responsible for initializing various aspects
4of a FastBlocks application, separating concerns from the main application class.
5"""
7import logging
8import typing as t
10from acb import register_pkg
11from acb.adapters import get_installed_adapter
12from acb.config import AdapterBase, Config
13from acb.depends import depends
14from starception import install_error_handler
15from starlette.applications import Starlette
18class ApplicationInitializer:
19 def __init__(self, app: Starlette, **kwargs: t.Any) -> None:
20 self.app = app
21 self.kwargs = kwargs
22 self.config: t.Any | None = None
23 self.logger: t.Any | None = None
24 self.depends: t.Any | None = None
25 self._acb_modules: tuple[t.Any, ...] = ()
27 def initialize(self) -> None:
28 self._load_acb_modules()
29 self._setup_dependencies()
30 self._configure_error_handling()
31 self._configure_debug_mode()
32 self._initialize_starlette()
33 self._configure_exception_handlers()
34 self._setup_models()
35 self._configure_logging()
37 def _load_acb_modules(self) -> None:
38 try:
39 logger_class: type[t.Any] | None = depends.get("logger").__class__
40 from acb.logger import InterceptHandler
42 interceptor_class: type[t.Any] | None = InterceptHandler
43 except Exception:
44 logger_class = None
45 interceptor_class = None
46 self._acb_modules = (
47 register_pkg,
48 get_installed_adapter,
49 Config,
50 AdapterBase,
51 interceptor_class,
52 logger_class,
53 depends,
54 )
56 def _setup_dependencies(self) -> None:
57 self.config = (
58 self.kwargs.get("config")
59 if self.kwargs.get("config") is not None
60 else depends.get("config")
61 )
62 self.logger = (
63 self.kwargs.get("logger")
64 if self.kwargs.get("logger") is not None
65 else depends.get("logger")
66 )
67 self.depends = depends
69 def _configure_error_handling(self) -> None:
70 if not getattr(self.config, "deployed", False) or not getattr(
71 getattr(self.config, "debug", None),
72 "production",
73 False,
74 ):
75 install_error_handler()
77 def _configure_debug_mode(self) -> None:
78 debug_config = getattr(self.config, "debug", None)
79 self.app.debug = (
80 getattr(debug_config, "fastblocks", False) if debug_config else False
81 )
82 if self.logger:
83 self.logger.warning(f"Fastblocks debug: {self.app.debug}")
85 def _initialize_starlette(self) -> None:
86 Starlette.__init__(
87 self.app,
88 debug=self.app.debug,
89 routes=[],
90 middleware=self.kwargs.get("middleware")
91 if self.kwargs.get("middleware") is not None
92 else [],
93 lifespan=self.kwargs.get("lifespan"),
94 exception_handlers=self.kwargs.get("exception_handlers")
95 if self.kwargs.get("exception_handlers") is not None
96 else {},
97 )
98 middleware = self.kwargs.get("middleware")
99 self.app.user_middleware = list(middleware) if middleware is not None else []
101 def _configure_exception_handlers(self) -> None:
102 from .exceptions import handle_exception
104 exception_handlers = self.kwargs.get("exception_handlers")
105 if exception_handlers is None:
106 exception_handlers = {
107 404: handle_exception,
108 500: handle_exception,
109 }
110 object.__setattr__(self.app, "exception_handlers", exception_handlers)
112 def _setup_models(self) -> None:
113 try:
114 models = self.depends.get("models")
115 except Exception:
116 models = None
117 object.__setattr__(self.app, "models", models)
119 def _configure_logging(self) -> None:
120 if get_installed_adapter("logfire"):
121 from logfire import instrument_starlette # type: ignore[import-untyped]
123 instrument_starlette(self.app)
124 interceptor_class = self._acb_modules[4]
125 if interceptor_class:
126 for logger_name in (
127 "uvicorn",
128 "uvicorn.access",
129 "granian",
130 "granian.access",
131 ):
132 server_logger = logging.getLogger(logger_name)
133 server_logger.handlers.clear()
134 server_logger.addHandler(interceptor_class())
135 server_logger.setLevel(logging.DEBUG)
136 server_logger.propagate = False