88from __future__ import annotations
99
1010import inspect
11+ import weakref
1112from typing import TYPE_CHECKING , Callable
1213
1314import rich .repr
3536if TYPE_CHECKING :
3637 from importlib .metadata import version
3738
39+ from textual .app import App
40+
3841 __version__ = version ("textual" )
3942 """The version of Textual."""
4043
@@ -62,10 +65,17 @@ def __init__(
6265 log_callable : LogCallable | None ,
6366 group : LogGroup = LogGroup .INFO ,
6467 verbosity : LogVerbosity = LogVerbosity .NORMAL ,
68+ app : App | None = None ,
6569 ) -> None :
6670 self ._log = log_callable
6771 self ._group = group
6872 self ._verbosity = verbosity
73+ self ._app = None if app is None else weakref .ref (app )
74+
75+ @property
76+ def app (self ) -> App | None :
77+ """The associated application, or `None` if there isn't one."""
78+ return None if self ._app is None else self ._app ()
6979
7080 def __rich_repr__ (self ) -> rich .repr .Result :
7181 yield self ._group , LogGroup .INFO
@@ -82,17 +92,20 @@ def __call__(self, *args: object, **kwargs) -> None:
8292
8393 with open (constants .LOG_FILE , "a" ) as log_file :
8494 print (output , file = log_file )
85- try :
86- app = active_app .get ()
87- except LookupError :
88- if constants .DEBUG :
89- print_args = (
90- * args ,
91- * [f"{ key } ={ value !r} " for key , value in kwargs .items ()],
92- )
93- print (* print_args )
94- return
95- if app .devtools is None or not app .devtools .is_connected :
95+
96+ app = self .app
97+ if app is None :
98+ try :
99+ app = active_app .get ()
100+ except LookupError :
101+ if constants .DEBUG :
102+ print_args = (
103+ * args ,
104+ * [f"{ key } ={ value !r} " for key , value in kwargs .items ()],
105+ )
106+ print (* print_args )
107+ return
108+ if not app ._is_devtools_connected :
96109 return
97110
98111 current_frame = inspect .currentframe ()
@@ -129,52 +142,52 @@ def verbosity(self, verbose: bool) -> Logger:
129142 New logger.
130143 """
131144 verbosity = LogVerbosity .HIGH if verbose else LogVerbosity .NORMAL
132- return Logger (self ._log , self ._group , verbosity )
145+ return Logger (self ._log , self ._group , verbosity , app = self . app )
133146
134147 @property
135148 def verbose (self ) -> Logger :
136149 """A verbose logger."""
137- return Logger (self ._log , self ._group , LogVerbosity .HIGH )
150+ return Logger (self ._log , self ._group , LogVerbosity .HIGH , app = self . app )
138151
139152 @property
140153 def event (self ) -> Logger :
141154 """Logs events."""
142- return Logger (self ._log , LogGroup .EVENT )
155+ return Logger (self ._log , LogGroup .EVENT , app = self . app )
143156
144157 @property
145158 def debug (self ) -> Logger :
146159 """Logs debug messages."""
147- return Logger (self ._log , LogGroup .DEBUG )
160+ return Logger (self ._log , LogGroup .DEBUG , app = self . app )
148161
149162 @property
150163 def info (self ) -> Logger :
151164 """Logs information."""
152- return Logger (self ._log , LogGroup .INFO )
165+ return Logger (self ._log , LogGroup .INFO , app = self . app )
153166
154167 @property
155168 def warning (self ) -> Logger :
156169 """Logs warnings."""
157- return Logger (self ._log , LogGroup .WARNING )
170+ return Logger (self ._log , LogGroup .WARNING , app = self . app )
158171
159172 @property
160173 def error (self ) -> Logger :
161174 """Logs errors."""
162- return Logger (self ._log , LogGroup .ERROR )
175+ return Logger (self ._log , LogGroup .ERROR , app = self . app )
163176
164177 @property
165178 def system (self ) -> Logger :
166179 """Logs system information."""
167- return Logger (self ._log , LogGroup .SYSTEM )
180+ return Logger (self ._log , LogGroup .SYSTEM , app = self . app )
168181
169182 @property
170183 def logging (self ) -> Logger :
171184 """Logs from stdlib logging module."""
172- return Logger (self ._log , LogGroup .LOGGING )
185+ return Logger (self ._log , LogGroup .LOGGING , app = self . app )
173186
174187 @property
175188 def worker (self ) -> Logger :
176189 """Logs worker information."""
177- return Logger (self ._log , LogGroup .WORKER )
190+ return Logger (self ._log , LogGroup .WORKER , app = self . app )
178191
179192
180193log = Logger (None )
@@ -185,4 +198,10 @@ def worker(self) -> Logger:
185198 from textual import log
186199 log(locals())
187200 ```
201+
202+ !!! note
203+ This logger will only work if there is an active app in the current thread.
204+ Use `app.log` to write logs from a thread without an active app.
205+
206+
188207"""
0 commit comments