@@ -149,6 +149,12 @@ class Message_Handler:
149149 :attribute brief: When true displays as much context as possible
150150 :type: Boolean
151151
152+ :attribute out: Output stream (stdout if None)
153+ :type: file or None
154+
155+ :attribute strip_prefix: Prefix stripped from file paths in messages
156+ :type: str or None
157+
152158 :attribute warnings: Number of system or user warnings raised
153159 :type: int
154160
@@ -158,16 +164,44 @@ class Message_Handler:
158164 :attribute supressed: Number of messages supressed by policy
159165 :type: int
160166
167+ Can be used as a context manager (``with Message_Handler(...) as
168+ mh:``), which will automatically close any file opened via
169+ ``out_path``.
170+
161171 """
162- def __init__ (self , brief = False , detailed_info = True ):
172+ def __init__ (self , brief = False , detailed_info = True ,
173+ out = None , strip_prefix = None , out_path = None ):
163174 assert isinstance (brief , bool )
175+ assert isinstance (strip_prefix , str ) or strip_prefix is None
176+ assert isinstance (out_path , str ) or out_path is None
164177 self .brief = brief
165178 self .show_details = detailed_info
166179 self .warnings = 0
167180 self .errors = 0
168181 self .suppressed = 0
169182 self .sm = None
170183 self .suppress_kind = set ()
184+ self .strip_prefix = strip_prefix
185+ if out_path is not None :
186+ self ._owned_file = open (out_path , "w" , encoding = "UTF-8" ) # pylint: disable=consider-using-with
187+ self .out = self ._owned_file
188+ else :
189+ self ._owned_file = None
190+ self .out = out
191+
192+ def close (self ):
193+ if self ._owned_file is not None :
194+ self ._owned_file .close ()
195+ self ._owned_file = None
196+
197+ def __enter__ (self ):
198+ return self
199+
200+ def __exit__ (self , * _ ):
201+ self .close ()
202+
203+ def __del__ (self ):
204+ self .close ()
171205
172206 def suppress (self , kind ):
173207 assert isinstance (kind , Kind )
@@ -178,8 +212,7 @@ def cross_file_reference(self, location):
178212
179213 if self .sm is None :
180214 return location .to_string (include_column = False )
181- else :
182- return self .sm .cross_file_reference (location )
215+ return self .sm .cross_file_reference (location )
183216
184217 def emit (self ,
185218 location ,
@@ -195,15 +228,21 @@ def emit(self,
195228 assert isinstance (extrainfo , str ) or extrainfo is None
196229 assert isinstance (category , str ) or category is None
197230
231+ def _loc_str (include_column = True ):
232+ loc = location .to_string (include_column )
233+ if self .strip_prefix and loc .startswith (self .strip_prefix ):
234+ loc = loc [len (self .strip_prefix ):]
235+ return loc
236+
198237 if self .brief :
199238 context = None
200- msg = "%s: trlc %s: %s" % (location . to_string (),
239+ msg = "%s: trlc %s: %s" % (_loc_str (),
201240 str (kind ),
202241 message )
203242
204243 else :
205244 context = location .context_lines ()
206- msg = "%s: %s: %s" % (location . to_string (len (context ) == 0 ),
245+ msg = "%s: %s: %s" % (_loc_str (len (context ) == 0 ),
207246 str (kind ),
208247 message )
209248
@@ -216,10 +255,10 @@ def emit(self,
216255 else :
217256 if context :
218257 assert len (context ) == 2
219- print (context [0 ].replace ("\t " , " " ))
220- print (context [1 ].replace ("\t " , " " ), msg )
258+ print (context [0 ].replace ("\t " , " " ), file = self . out )
259+ print (context [1 ].replace ("\t " , " " ), msg , file = self . out )
221260 else :
222- print (msg )
261+ print (msg , file = self . out )
223262
224263 if not self .brief \
225264 and self .show_details \
@@ -230,7 +269,7 @@ def emit(self,
230269 indent = 0
231270 for line in extrainfo .splitlines ():
232271 print ("%s| %s" % (" " * indent ,
233- line .rstrip ()))
272+ line .rstrip ()), file = self . out )
234273
235274 if fatal :
236275 raise TRLC_Error (location , kind , message )
0 commit comments