live output from subprocess command

后端 未结 16 1384
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-11-22 08:16

I\'m using a python script as a driver for a hydrodynamics code. When it comes time to run the simulation, I use subprocess.Popen to run the code, collect the

16条回答
  •  不要未来只要你来
    2020-11-22 09:07

    Here is a class which I'm using in one of my projects. It redirects output of a subprocess to the log. At first I tried simply overwriting the write-method but that doesn't work as the subprocess will never call it (redirection happens on filedescriptor level). So I'm using my own pipe, similar to how it's done in the subprocess-module. This has the advantage of encapsulating all logging/printing logic in the adapter and you can simply pass instances of the logger to Popen: subprocess.Popen("/path/to/binary", stderr = LogAdapter("foo"))

    class LogAdapter(threading.Thread):
    
        def __init__(self, logname, level = logging.INFO):
            super().__init__()
            self.log = logging.getLogger(logname)
            self.readpipe, self.writepipe = os.pipe()
    
            logFunctions = {
                logging.DEBUG: self.log.debug,
                logging.INFO: self.log.info,
                logging.WARN: self.log.warn,
                logging.ERROR: self.log.warn,
            }
    
            try:
                self.logFunction = logFunctions[level]
            except KeyError:
                self.logFunction = self.log.info
    
        def fileno(self):
            #when fileno is called this indicates the subprocess is about to fork => start thread
            self.start()
            return self.writepipe
    
        def finished(self):
           """If the write-filedescriptor is not closed this thread will
           prevent the whole program from exiting. You can use this method
           to clean up after the subprocess has terminated."""
           os.close(self.writepipe)
    
        def run(self):
            inputFile = os.fdopen(self.readpipe)
    
            while True:
                line = inputFile.readline()
    
                if len(line) == 0:
                    #no new data was added
                    break
    
                self.logFunction(line.strip())
    

    If you don't need logging but simply want to use print() you can obviously remove large portions of the code and keep the class shorter. You could also expand it by an __enter__ and __exit__ method and call finished in __exit__ so that you could easily use it as context.

提交回复
热议问题