Hello,
Some time ago, I set up some logging using stdout in a program with the `stdout_redirected()` context manager, which had to close and reopen stdout to work.
Unsurprisingly, the StreamHandler didn't take it well.

So I made a Handler class which is able to reload the stream (AKA get the new sys.stdout) whenever the old one wasn't writable. But there might be some more legit use cases for stubborn StreamHandlers like that (that are not ugly-looking, hopefully temporary patches).

The way I see it for now is a StreamHandler subclass which, instead of having a `stream` argument, would have |`getStream`|,|`reloadStream`| and |`location`|, and would be used this way: On initialisation, it would load the stream object, then act as a regular StreamHandler, but checking that the stream is writable at each `handler.emit()` call. If it is not, then reload it.

If given, the |`getStream`| (a callable object which returns a ready-to-use stream) argument is used to load/reload the underlying stream, else it would be fetched at the location described by `location`, and, if it is still not writable, call |`reloadStream()` |(which should put a usable stream object at |`location`|) then try to fetch it again.

Here is the current implementation I have:

|||```|
from .config import _resolve as resolve  # will (uglily) be used later

|class ReloadingHandler(StreamHandler):|
|    """|
|    A stream handler which reloads the stream object from one place if an error occurs|
|    """|
|    def __init__(self, getStream=None, reloadStream=None, location=None):|
|        """|
|        Initialize the handler.|
||
|        If stream is not specified, sys.stderr is used.|
|        """

        self.getStream = getStream
        self.stream = None  # to be overwritten later
        if getStream is None:|
||            if location is None:
                self.location = 'sys.stderr'  # note the lack of 'ext://'
                self.reloadStream = None
            else:
|                self.reloadStream = reloadStream
                self.location = location

        stream = self.reload()  # gets the stream
        StreamHandler.__init__(self, stream||)
||||
    def reload(self):
        if self.getStream is not None:
            stream = self.getStream()
        else:
            try:
                stream = resolve(self.location)
                exc = None
            except Exception as err:
                exc = err  # is this really needed?
                stream = None  # just retry for now
            if stream is None or not stream.writable():
                if self.reloadStream is None:
                    if exc:
                        raise exc
                    else:
                        raise ValueError("ReloadingHandler couldn't reload a valid stream")

                stream = resolve(self.location)  # if it fails this time, do not catch exception here

        return stream
|||
|    def emit(self, record):|
|        """|
|        Emit a record.|
||
|        If a formatter is specified, it is used to format the record.|
|        The record is then written to the stream with a trailing newline.  If|
|        exception information is present, it is formatted using|
|        traceback.print_exception and appended to the stream.  If the stream|
|        has an 'encoding' attribute, it is used to determine how to do the|
|        output to the stream.|
|        """|
|        if not self.stream.writable():|
|            self.reload()|
|        StreamHandler.emit(self, record)|
|||```
|
What do you think? (about the idea, the implementation, and the way I wrote this email)|
|


---
L'absence de virus dans ce courrier électronique a été vérifiée par le logiciel 
antivirus Avast.
https://www.avast.com/antivirus
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to