user10146018
user10146018

Reputation:

prevent conversion of carriage return "\r" to "\n"

I have following code in t.py:-

import time

for i in range(1,100):
    print(f"{i}% \r",end='')
    time.sleep(0.05)

it count 1 to 99 in single line like this:-

enter image description here

So when I execute following code, I expect the same

import subprocess as sb
import sys

lol = sb.Popen('python t.py',stdout=sb.PIPE,shell=True,text=True)

while True:

    l = lol.stdout.read(1)
    if not l and lol.poll() is not None:
        break
    if(l == '\n'): # for checking
        print(" it should've been \\r") # this should not happen

    sys.stdout.write(l)
    sys.stdout.flush()

print("done")

But this code prints 1% to 99% in all separate line. like this:-

1%  it should've been \r

2%  it should've been \r

3%  it should've been \r

4%  it should've been \r

..... i have skipped this part .....

99%  it should've been \r

done

So i added a little if statement

    if(l == '\n'):
        print(" it should've been \\r")

the above if statement shows that somehow '\r' might be converted into '\n' which I don't want.

Upvotes: 1

Views: 474

Answers (1)

Roy2012
Roy2012

Reputation: 12503

Well, it's in the documentation: (https://docs.python.org/3.8/library/subprocess.html#frequently-used-arguments):

"If encoding or errors are specified, or text (also known as universal_newlines) is true, the file objects stdin, stdout and stderr will be opened in text mode using the encoding and errors specified in the call or the defaults for io.TextIOWrapper."

"For stdout and stderr, all line endings in the output will be converted to '\n'. For more information see the documentation of the io.TextIOWrapper class when the newline argument to its constructor is None."

Remove the text=True flag to avoid this behavior. When you do that, note that the stuff you read from stdout is now bytearrays and not strings, and you'll have to deal with them accordingly.

The following implementation of t.py and the main script achieves what you want.

t.py:

import time
import sys

for i in range(1,100):
    print(f'{i} \r', end='')
    sys.stdout.flush()
    time.sleep(0.2)

Main script:

import subprocess as sb
import sys

lol = sb.Popen('python3 t.py',stdout=sb.PIPE,shell=True)

while True:


    l = lol.stdout.read(1)

    if not l and lol.poll() is not None:
        break

    print(l.decode("utf-8"), end="")

print("done")

Upvotes: 2

Related Questions