77 def lock(cls, logger):
79 Attach this singleton logger to the `sys.stderr` permanently. 81 global _stderr_singleton
82 global _stderr_default
83 global _stderr_default_class_type
87 if not sys.__stderr__:
88 sys.__stderr__ = sys.stderr
92 _stderr_default_class_type
96 _stderr_default = sys.stderr
98 _stderr_default_class_type = type( _stderr_default )
102 if not cls.is_active:
104 _stderr_write = _stderr_default.write
106 logger_call = logger._log_clean
107 clean_formatter = logger.clean_formatter
109 global _sys_stderr_write
110 global _sys_stderr_write_hidden
112 if sys.version_info <= (3,2):
114 def customEmit(self, record):
117 https://stackoverflow.com/questions/12699645/how-can-i-suppress-newline-in-python-logging-module 119 If a formatter is specified, it is used to format the record. 120 The record is then written to the stream with a trailing newline. If 121 exception information is present, it is formatted using 122 traceback.print_exception and appended to the stream. If the stream 123 has an 'encoding' attribute, it is used to determine how to do the 124 output to the stream. 127 msg = self.format(record)
131 stream.write(fs % (msg, self.terminator))
134 if (isinstance(msg, unicode)
and 135 getattr(stream,
'encoding',
None)):
138 stream.write(ufs % (msg, self.terminator))
139 except UnicodeEncodeError:
146 stream.write((ufs % (msg, self.terminator)).encode(stream.encoding))
148 stream.write(fs % (msg, self.terminator))
150 stream.write(fs % (msg.encode(
"UTF-8"), self.terminator))
152 except (KeyboardInterrupt, SystemExit):
155 self.handleError(record)
157 logging.StreamHandler.terminator =
'\n' 158 setattr(StreamHandler, StreamHandler.emit.__name__, customEmit)
161 def _sys_stderr_write_hidden(msg, *args, **kwargs):
163 Suppress newline in Python logging module 164 https://stackoverflow.com/questions/7168790/suppress-newline-in-python-logging-module 169 _stderr_write( msg, *args, **kwargs )
171 formatter = file.formatter
172 terminator = file.terminator
174 file.formatter = clean_formatter
177 kwargs[
'extra'] = {
'_duplicated_from_file':
True }
178 logger_call( msg, args, kwargs )
180 file.formatter = formatter
181 file.terminator = terminator
184 logger.exception(
"Could not write to the file: %s(%s)", file, logger )
193 def _sys_stderr_write(*args, **kwargs):
195 Hides the actual function pointer. This allow the external function pointer to 196 be cached while the internal written can be exchanged between the standard 197 `sys.stderr.write` and our custom wrapper around it. 199 _sys_stderr_write_hidden( *args, **kwargs )
212 class stderr_replament_hidden(_stderr_default_class_type):
214 Which special methods bypasses __getattribute__ in Python? 215 https://stackoverflow.com/questions/12872695/which-special-methods-bypasses-getattribute-in-python 218 if hasattr( _stderr_default,
"__abstractmethods__" ):
219 __abstractmethods__ = _stderr_default.__abstractmethods__
221 if hasattr( _stderr_default,
"__base__" ):
222 __base__ = _stderr_default.__base__
224 if hasattr( _stderr_default,
"__bases__" ):
225 __bases__ = _stderr_default.__bases__
227 if hasattr( _stderr_default,
"__basicsize__" ):
228 __basicsize__ = _stderr_default.__basicsize__
230 if hasattr( _stderr_default,
"__call__" ):
231 __call__ = _stderr_default.__call__
233 if hasattr( _stderr_default,
"__class__" ):
234 __class__ = _stderr_default.__class__
236 if hasattr( _stderr_default,
"__delattr__" ):
237 __delattr__ = _stderr_default.__delattr__
239 if hasattr( _stderr_default,
"__dict__" ):
240 __dict__ = _stderr_default.__dict__
242 if hasattr( _stderr_default,
"__dictoffset__" ):
243 __dictoffset__ = _stderr_default.__dictoffset__
245 if hasattr( _stderr_default,
"__dir__" ):
246 __dir__ = _stderr_default.__dir__
248 if hasattr( _stderr_default,
"__doc__" ):
249 __doc__ = _stderr_default.__doc__
251 if hasattr( _stderr_default,
"__eq__" ):
252 __eq__ = _stderr_default.__eq__
254 if hasattr( _stderr_default,
"__flags__" ):
255 __flags__ = _stderr_default.__flags__
257 if hasattr( _stderr_default,
"__format__" ):
258 __format__ = _stderr_default.__format__
260 if hasattr( _stderr_default,
"__ge__" ):
261 __ge__ = _stderr_default.__ge__
263 if hasattr( _stderr_default,
"__getattribute__" ):
264 __getattribute__ = _stderr_default.__getattribute__
266 if hasattr( _stderr_default,
"__gt__" ):
267 __gt__ = _stderr_default.__gt__
269 if hasattr( _stderr_default,
"__hash__" ):
270 __hash__ = _stderr_default.__hash__
272 if hasattr( _stderr_default,
"__init__" ):
273 __init__ = _stderr_default.__init__
275 if hasattr( _stderr_default,
"__init_subclass__" ):
276 __init_subclass__ = _stderr_default.__init_subclass__
278 if hasattr( _stderr_default,
"__instancecheck__" ):
279 __instancecheck__ = _stderr_default.__instancecheck__
281 if hasattr( _stderr_default,
"__itemsize__" ):
282 __itemsize__ = _stderr_default.__itemsize__
284 if hasattr( _stderr_default,
"__le__" ):
285 __le__ = _stderr_default.__le__
287 if hasattr( _stderr_default,
"__lt__" ):
288 __lt__ = _stderr_default.__lt__
290 if hasattr( _stderr_default,
"__module__" ):
291 __module__ = _stderr_default.__module__
293 if hasattr( _stderr_default,
"__mro__" ):
294 __mro__ = _stderr_default.__mro__
296 if hasattr( _stderr_default,
"__name__" ):
297 __name__ = _stderr_default.__name__
299 if hasattr( _stderr_default,
"__ne__" ):
300 __ne__ = _stderr_default.__ne__
302 if hasattr( _stderr_default,
"__new__" ):
303 __new__ = _stderr_default.__new__
305 if hasattr( _stderr_default,
"__prepare__" ):
306 __prepare__ = _stderr_default.__prepare__
308 if hasattr( _stderr_default,
"__qualname__" ):
309 __qualname__ = _stderr_default.__qualname__
311 if hasattr( _stderr_default,
"__reduce__" ):
312 __reduce__ = _stderr_default.__reduce__
314 if hasattr( _stderr_default,
"__reduce_ex__" ):
315 __reduce_ex__ = _stderr_default.__reduce_ex__
317 if hasattr( _stderr_default,
"__repr__" ):
318 __repr__ = _stderr_default.__repr__
320 if hasattr( _stderr_default,
"__setattr__" ):
321 __setattr__ = _stderr_default.__setattr__
323 if hasattr( _stderr_default,
"__sizeof__" ):
324 __sizeof__ = _stderr_default.__sizeof__
326 if hasattr( _stderr_default,
"__str__" ):
327 __str__ = _stderr_default.__str__
329 if hasattr( _stderr_default,
"__subclasscheck__" ):
330 __subclasscheck__ = _stderr_default.__subclasscheck__
332 if hasattr( _stderr_default,
"__subclasses__" ):
333 __subclasses__ = _stderr_default.__subclasses__
335 if hasattr( _stderr_default,
"__subclasshook__" ):
336 __subclasshook__ = _stderr_default.__subclasshook__
338 if hasattr( _stderr_default,
"__text_signature__" ):
339 __text_signature__ = _stderr_default.__text_signature__
341 if hasattr( _stderr_default,
"__weakrefoffset__" ):
342 __weakrefoffset__ = _stderr_default.__weakrefoffset__
344 if hasattr( _stderr_default,
"mro" ):
345 mro = _stderr_default.mro
349 Override any super class `type( _stderr_default )` constructor, so we can 350 instantiate any kind of `sys.stderr` replacement object, in case it was 351 already replaced by something else like on Sublime Text with `_LogWriter()`. 353 Assures all attributes were statically replaced just above. This should happen in case 354 some new attribute is added to the python language. 356 This also ignores the only two methods which are not equal, `__init__()` and `__getattribute__()`. 358 different_methods = (
"__init__",
"__class__",
"__getattribute__")
359 attributes_to_check = set( dir( object ) + dir( type ) )
361 for attribute
in attributes_to_check:
363 if attribute
not in different_methods \
364 and hasattr( _stderr_default, attribute ):
366 base_class_attribute = super( _stderr_default_class_type, self ).__getattribute__( attribute )
367 target_class_attribute = _stderr_default.__getattribute__( attribute )
369 if base_class_attribute != target_class_attribute:
370 sys.stderr.write(
" The base class attribute `%s` is different from the target class:\n%s\n%s\n\n" % ( attribute, base_class_attribute, target_class_attribute ) )
372 def __getattribute__(self, item):
376 return _sys_stderr_write
379 return _stderr_default.__getattribute__( item )
381 except AttributeError:
382 return super( _stderr_default_class_type, _stderr_default ).__getattribute__( item )
388 _stderr_singleton = stderr_replament_hidden()
392 sys.stderr = _stderr_singleton