python subprocess callback when updated output
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
To react to subprocess output in real time, open the process with subprocess.Popen, set stdout=subprocess.PIPE, and read lines in a loop. Each line can trigger a callback function for logging, progress tracking, or parsing. For asynchronous handling, use asyncio.create_subprocess_exec with process.stdout.readline() in an async loop. The key is avoiding communicate() or run() when you need incremental output — both buffer everything until the process exits.
Basic Real-Time Line Reading
The iter(readline, "") pattern reads lines until the pipe returns an empty string (process exits). Each line fires the callback immediately.
Callback with Progress Parsing
Handling Both stdout and stderr
Using threads prevents deadlock — if both stdout and stderr buffers fill up and you only read one, the process blocks waiting for the other to drain.
Async Subprocess with asyncio
Timeout with Real-Time Output
Buffering Fix for Child Processes
Common Pitfalls
- Using
process.communicate()for real-time output:communicate()waits for the process to finish and returns all output at once. It is designed for batch processing, not streaming. Usereadline()in a loop or async iteration for incremental output. - Deadlock when reading both stdout and stderr sequentially: If you read all of stdout first, stderr may fill its buffer, blocking the child process. The child never finishes writing to stdout because it is stuck on stderr. Use threads or
stderr=subprocess.STDOUTto merge both streams. - Child process buffering delays output: Many programs buffer stdout when it is a pipe (not a TTY). Python buffers by default. Use
python -u, setPYTHONUNBUFFERED=1, or usestdbuf -oLfor C programs. Without this, output arrives in large chunks instead of line by line. - Forgetting
bufsize=1on the parent side: Even if the child sends unbuffered output, the parentPopenmay buffer reads. Setbufsize=1(line-buffered) andtext=Trueto ensurereadline()returns as soon as a newline arrives. - Not closing the process on callback exceptions: If the callback raises an exception, the loop exits but the subprocess may keep running. Wrap the read loop in try/finally with
process.kill()andprocess.wait()to ensure cleanup on errors.
Summary
- Use
Popenwithstdout=PIPEanditer(stdout.readline, "")for real-time line-by-line output - Read stdout and stderr in separate threads to prevent deadlock
- Use
asyncio.create_subprocess_execfor async subprocess handling - Fix child buffering with
python -u,PYTHONUNBUFFERED=1, orstdbuf -oL - Always set
bufsize=1andtext=Trueon the parent for line-buffered reads
Related reading
- Python subprocess is not scalable by default, any simple solution you can recommend to make it scalable?
- Python subprocess/Popen with a modified environment
- python swapped tuple to dict
- Python synchronous pyaudio data in asynchronous code
- Python SyntaxError EOL while scanning string literal
- Python SyntaxError Non-ASCII character 'xe2' in file
- Python TensorFlow How to restart training with optimizer and import_meta_graph?
- Python tensorflow lite error:Cannot set tensor Got tensor of type 1 but expected type 3 for input 88
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.