Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #48826

Re: New line conversion with Popen attached to a pty

Path csiph.com!newsfeed.hal-mli.net!feeder3.hal-mli.net!newsfeed.hal-mli.net!feeder2.hal-mli.net!newsfeed.xs4all.nl!newsfeed4.news.xs4all.nl!xs4all!newsgate.cistron.nl!newsgate.news.xs4all.nl!post.news.xs4all.nl!not-for-mail
Return-Path <python-python-list@m.gmane.org>
X-Original-To python-list@python.org
Delivered-To python-list@mail.python.org
X-Spam-Status OK 0.000
X-Spam-Evidence '*H*': 1.00; '*S*': 0.00; 'output': 0.05; 'explicit': 0.07; 'intermediate': 0.07; 'odd': 0.07; 'problem:': 0.07; '"__main__":': 0.09; '[],': 0.09; '__name__': 0.09; 'data:': 0.09; 'executes': 0.09; 'interpreted': 0.09; 'newline': 0.09; 'pointers': 0.09; 'received:80.91': 0.09; 'received:80.91.229': 0.09; 'received:gmane.org': 0.09; 'received:list': 0.09; 'seemed': 0.09; 'sys,': 0.09; 'try:': 0.09; 'python': 0.11; 'def': 0.12; 'translation': 0.12; 'wrote': 0.14; '%r"': 0.16; '0.1)': 0.16; '2.6.4': 0.16; 'attaching': 0.16; 'attrs': 0.16; 'fcntl': 0.16; 'fiddle': 0.16; 'googling': 0.16; 'newlines': 0.16; 'os;': 0.16; 'pty': 0.16; 'received:80.91.229.3': 0.16; 'received:dip0.t-ipconnect.de': 0.16; 'received:plane.gmane.org': 0.16; 'received:t-ipconnect.de': 0.16; 'simplest': 0.16; 'stdout': 0.16; 'true:': 0.16; 'followed': 0.16; 'fix': 0.17; 'wrote:': 0.18; 'bit': 0.19; 'seems': 0.21; 'appears': 0.22; 'select': 0.22; 'import': 0.22; 'print': 0.22; 'header:User-Agent:1': 0.23; 'earlier': 0.24; 'looks': 0.24; 'environment': 0.24; "i've": 0.25; 'this:': 0.26; 'gets': 0.27; 'header:X-Complaints-To:1': 0.27; 'testing': 0.29; 'correct': 0.29; 'external': 0.29; 'dos': 0.30; 'mode': 0.30; 'specified': 0.30; '(which': 0.31; 'getting': 0.31; 'bunch': 0.31; 'controlled': 0.31; 'enabled': 0.31; 'anyone': 0.31; 'class': 0.32; 'cases': 0.33; 'mac': 0.33; 'skip:# 10': 0.33; 'noticed': 0.34; 'skip:_ 10': 0.34; "i'd": 0.34; 'could': 0.34; 'subject:with': 0.35; 'except': 0.35; 'skip:u 20': 0.35; '(2)': 0.35; 'test': 0.35; 'add': 0.35; 'done': 0.36; 'hi,': 0.36; 'should': 0.36; 'subject:New': 0.37; 'wrong': 0.37; 'two': 0.37; 'list': 0.37; 'level': 0.37; 'step': 0.37; 'skip:o 20': 0.38; 'needed': 0.38; 'skip:[ 10': 0.38; 'to:addr:python-list': 0.38; 'fact': 0.38; 'does': 0.39; 'environment.': 0.39; 'to:addr:python.org': 0.39; 'mailing': 0.39; 'received:org': 0.40; 'even': 0.60; 'skip:u 10': 0.60; 'disclaimer:': 0.60; 'black': 0.61; 'break': 0.61; 'conversion': 0.61; 'new': 0.61; 'simple': 0.61; 'email addr:gmail.com': 0.63; 'kept': 0.65; 'hours': 0.66; 'approaches': 0.68; 'message).': 0.84; 'skip:| 10': 0.84; 'whereas': 0.91
X-Injected-Via-Gmane http://gmane.org/
To python-list@python.org
From Peter Otten <__peter__@web.de>
Subject Re: New line conversion with Popen attached to a pty
Date Fri, 21 Jun 2013 00:04:39 +0200
Organization None
References <c280b727-f979-4107-89e8-a4a54be2fbfa@googlegroups.com>
Mime-Version 1.0
Content-Type text/plain; charset="ISO-8859-1"
Content-Transfer-Encoding 7Bit
X-Gmane-NNTP-Posting-Host p50848af3.dip0.t-ipconnect.de
User-Agent KNode/4.7.3
X-BeenThere python-list@python.org
X-Mailman-Version 2.1.15
Precedence list
List-Id General discussion list for the Python programming language <python-list.python.org>
List-Unsubscribe <http://mail.python.org/mailman/options/python-list>, <mailto:python-list-request@python.org?subject=unsubscribe>
List-Archive <http://mail.python.org/pipermail/python-list/>
List-Post <mailto:python-list@python.org>
List-Help <mailto:python-list-request@python.org?subject=help>
List-Subscribe <http://mail.python.org/mailman/listinfo/python-list>, <mailto:python-list-request@python.org?subject=subscribe>
Newsgroups comp.lang.python
Message-ID <mailman.3640.1371765829.3114.python-list@python.org> (permalink)
Lines 137
NNTP-Posting-Host 2001:888:2000:d::a6
X-Trace 1371765829 news.xs4all.nl 15951 [2001:888:2000:d::a6]:44075
X-Complaints-To abuse@xs4all.nl
Xref csiph.com comp.lang.python:48826

Show key headers only | View raw


jfharden@gmail.com wrote:

> Hi,
> 
> Sorry if this appears twice, I sent it to the mailing list earlier and the
> mail seems to have been swallowed by the black hole of email vagaries.
> 
> We have a class which executes external processes in a controlled
> environment and does "things" specified by the client program with each
> line of output. To do this we have been attaching stdout from the
> subprocess.Popen to a pseudo terminal (pty) made with pty.openempty and
> opened with os.fdopen. I noticed that we kept getting a bunch of extra new
> line characters.

Mixing subprocess and explicit select() looks a bit odd to me. Perhaps you 
should do it completely without subprocess. Did you consider pexpect?

> This is all using python 2.6.4 in a centos6 environment.
> 
> After some investigation I realised we needed to use universal_newline
> support so I enabled it for the Popen and specified the mode in the fdopen
> to be rU. Things still seemed to be coming out wrong so I wrote up a test
> program boiling it down to the simplest cases (which is at the end of this
> message). The output I was testing was this:
> 
> Fake\r\nData\r\n
> as seen through hexdump -C:
> 
>> hexdump -C output.txt
> 00000000  46 61 6b 65 0d 0a 44 61  74 61 0d 0a              |Fake..Data..|
> 0000000c
> 
> Now if I do a simple subprocess.Popen and set the stdout to
> subprocess.PIPE, then do p.stdout.read() I get the correct output of
> 
> Fake\nData\n
> 
> When do the Popen attached to a pty I end up with
> 
> Fake\n\nData\n\n
> 
> Does anyone know why the newline conversion would be incorrect, and what I
> could do to fix it? In fact if anyone even has any pointers to where this
> might be going wrong I'd be very helpful, I've done hours of fiddling with
> this and googling to no avail.
> 
> One liner to generate the test data:
> 
> python -c 'f = open("output.txt", "w"); f.write("Fake\r\nData\r\n");
> f.close()'
> 
> Test script:
> 
> #!/usr/bin/env python2.6.4
> import os
> import pty
> import subprocess
> import select
> import fcntl
> 
> class TestRead(object):
> 
>     def __init__(self):
>         super(TestRead, self).__init__()
>         self.outputPipe()
>         self.outputPty()
> 
>     def outputPipe(self):
>         p1 = subprocess.Popen(
>             ("/bin/cat", "output.txt"),
>             stdout=subprocess.PIPE,
>             universal_newlines=True
>         )
>         print "1: %r" % p1.stdout.read()
> 
>     def outputPty(self):
>         outMaster, outSlave = pty.openpty()
>         fcntl.fcntl(outMaster, fcntl.F_SETFL, os.O_NONBLOCK)
> 
>         p2 = subprocess.Popen(
>             ("/bin/cat", "output.txt"),
>             stdout=outSlave,
>             universal_newlines=True
>         )
> 
>         with os.fdopen(outMaster, 'rU') as pty_stdout:
>             while True:
>                 try:
>                     rfds, _, _ = select.select([pty_stdout], [], [], 0.1)
>                     break
>                 except select.error:
>                     continue
> 
>             for fd in rfds:
>                 buf = pty_stdout.read()
>                 print "2: %r" % buf
> 
> if __name__ == "__main__":
>     t = TestRead()

The "universal newlines" translation happens on the python level whereas the 
subprocesses communicate via OS means (pipes). Your pty gets "\r\n", leaves 
"\r" as is and replaces "\n" with "\r\n". You end up with "\r\r\n" which is 
interpreted by "universal newlines" mode as a Mac newline followed by a DOS 
newline. 

I see two approaches to fix the problem:

(1) Add an intermediate step to change newlines explicitly:

    p = subprocess.Popen(
        ["/bin/cat", "output.txt"],
        stdout=subprocess.PIPE
    )
    q = subprocess.Popen(
#        ["dos2unix"],
        ["python", "-c", "import sys, os; 
sys.stdout.writelines(os.fdopen(sys.stdin.fileno(), 'rU'))"],
        stdin=p.stdout,
        stdout=outSlave)

(2) Fiddle with terminal options, e. g.

    attrs = termios.tcgetattr(outSlave)
    attrs[1]  =  attrs[1] & (~termios.ONLCR) | termios.ONLRET
    termios.tcsetattr(outSlave, termios.TCSANOW, attrs)

    p = subprocess.Popen(
        ("/bin/cat", "output.txt"),
        stdout=outSlave,
    )


Disclaimer: I found this by try-and-error, so it may not be the "proper" 
way.

Back to comp.lang.python | Previous | NextPrevious in thread | Next in thread | Find similar | Unroll thread


Thread

New line conversion with Popen attached to a pty jfharden@gmail.com - 2013-06-20 06:28 -0700
  Re: New line conversion with Popen attached to a pty Peter Otten <__peter__@web.de> - 2013-06-21 00:04 +0200
    Re: New line conversion with Popen attached to a pty jfharden@gmail.com - 2013-06-21 04:12 -0700

csiph-web