Reputation: 2525
This is mostly a general python question, I am working in a distributed environment so my workers write their stdout and stderr to files on a shared filesystem (I can't change this). I want my launcher script to read one of those files and print it out realtime to roughly track the progress of the workers, each of which outputs progress bars using tqdm. I was happy to see that running tail -f
of the files correctly outputs the progress bars e.g. the bars update on a single line just like they would if I was running tqdm locally. However when I try to wrap that with python, using the following function:
def follow(job : submitit.Job) -> Iterator[str]:
with open(job.paths.stdout) as fo:
with open(job.paths.stderr) as fe:
while True:
lo = fo.readline()
if lo:
yield lo
le = fe.readline()
if le:
yield le
if job.state != 'RUNNING' and not (le or lo):
break
else:
time.sleep(1)
loglines = follow(job)
for line in loglines:
print(line, end='', flush=True)
it doesn't do this, e.g. I get a newline and the progress bar updates by printing new lines, it doesn't seem to handle the \x1b[A
character that tqdm is writing.
Is there a way to do this purely in python?
Upvotes: 0
Views: 758
Reputation: 2525
I was able to solve this by using read binary mode, using read
to read to the end of the file, then decoding the resulting bytes as ascii
instead of the python 3 default of UTF-8. The updated working follow function is as follows:
def follow(job : Job) -> Iterator[str]:
with open(job.paths.stdout, 'rb') as fo:
with open(job.paths.stderr, 'rb') as fe:
while True:
lo = fo.read().decode('ascii')
if lo:
yield lo
le = fe.read().decode('ascii')
if le:
yield le
if job.state != 'RUNNING' and not le and not lo:
break
else:
time.sleep(0.1)
Upvotes: 1