Python 诅咒 Git 具有意外间距的子进程输出
Python Curses Git Subprocess Output with unexpected spacing
当我在 python-curses 屏幕中调用 git 时,我发现了一个奇怪的间距问题。我在下面的最小工作示例中做了什么导致间距半开而不与屏幕的侧面齐平?
最小工作示例:
import curses, subprocess
class MyApp(object):
def __init__(self, stdscreen):
self.screen = stdscreen
self.screen.addstr("Loading..." + '\n')
self.screen.refresh()
url = 'http://github.com/octocat/Hello-World/'
process = subprocess.Popen(['git', 'clone', url], stdout=subprocess.PIPE)
self.screen.addstr("Press any key to continue.")
self.screen.getch()
if __name__ == '__main__':
curses.wrapper(MyApp)
输出:
Loading...
Press any key to continue.Cloning into 'Hello-World'...
warning: redirecting to https://github.com/octocat/Hello-World/
remote: Enumerating objects: 13, done.
remote: Total 13 (delta 0), reused 0 (delta 0), pack-reused 13
Unpacking objects: 100% (13/13), done.3)
预期输出:
Loading...
Cloning into 'Hello-World'...
warning: redirecting to https://github.com/octocat/Hello-World/
remote: Enumerating objects: 13, done.
remote: Total 13 (delta 0), reused 0 (delta 0), pack-reused 13
Unpacking objects: 100% (13/13), done.3)
Press any key to continue.
git clone
将其信息性消息写入 stderr,而不是 stdout。
From the documentation(强调已加):
--verbose
Run verbosely. Does not affect the reporting of progress status to the standard error stream.
(以下代码来自Justapigeon)
考虑到这一点更新了 MWE:
import curses, subprocess
import os, re
class MyApp(object):
def __init__(self, stdscreen):
self.screen = stdscreen
self.screen.addstr("Loading..." + '\n')
self.screen.refresh()
url = 'http://github.com/octocat/Hello-World/'
#process = subprocess.Popen(['git', 'clone', url], stdout=subprocess.PIPE)
# additional code from:
dloutput = subprocess.Popen(['git', 'clone', '--progress', url], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
fd = dloutput.stderr.fileno()
gitmsg = []
while True:
lines = os.read(fd,1000).decode('utf-8')
lines = re.split('\n|\r', lines)
for l in lines:
self.screen.erase()
for g in gitmsg:
self.screen.addstr(g + '\n')
if l != '':
self.screen.addstr(str(l) + '\n')
self.screen.refresh()
if 'Cloning' in l:
gitmsg.append(l)
if 'done' in l:
gitmsg.append(l)
if len(lines) == 1:
break
self.screen.addstr("Press any key to continue.")
self.screen.getch()
if __name__ == '__main__':
curses.wrapper(MyApp)
当我在 python-curses 屏幕中调用 git 时,我发现了一个奇怪的间距问题。我在下面的最小工作示例中做了什么导致间距半开而不与屏幕的侧面齐平?
最小工作示例:
import curses, subprocess
class MyApp(object):
def __init__(self, stdscreen):
self.screen = stdscreen
self.screen.addstr("Loading..." + '\n')
self.screen.refresh()
url = 'http://github.com/octocat/Hello-World/'
process = subprocess.Popen(['git', 'clone', url], stdout=subprocess.PIPE)
self.screen.addstr("Press any key to continue.")
self.screen.getch()
if __name__ == '__main__':
curses.wrapper(MyApp)
输出:
Loading...
Press any key to continue.Cloning into 'Hello-World'...
warning: redirecting to https://github.com/octocat/Hello-World/
remote: Enumerating objects: 13, done.
remote: Total 13 (delta 0), reused 0 (delta 0), pack-reused 13
Unpacking objects: 100% (13/13), done.3)
预期输出:
Loading...
Cloning into 'Hello-World'...
warning: redirecting to https://github.com/octocat/Hello-World/
remote: Enumerating objects: 13, done.
remote: Total 13 (delta 0), reused 0 (delta 0), pack-reused 13
Unpacking objects: 100% (13/13), done.3)
Press any key to continue.
git clone
将其信息性消息写入 stderr,而不是 stdout。
From the documentation(强调已加):
--verbose
Run verbosely. Does not affect the reporting of progress status to the standard error stream.
(以下代码来自Justapigeon)
考虑到这一点更新了 MWE:
import curses, subprocess
import os, re
class MyApp(object):
def __init__(self, stdscreen):
self.screen = stdscreen
self.screen.addstr("Loading..." + '\n')
self.screen.refresh()
url = 'http://github.com/octocat/Hello-World/'
#process = subprocess.Popen(['git', 'clone', url], stdout=subprocess.PIPE)
# additional code from:
dloutput = subprocess.Popen(['git', 'clone', '--progress', url], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
fd = dloutput.stderr.fileno()
gitmsg = []
while True:
lines = os.read(fd,1000).decode('utf-8')
lines = re.split('\n|\r', lines)
for l in lines:
self.screen.erase()
for g in gitmsg:
self.screen.addstr(g + '\n')
if l != '':
self.screen.addstr(str(l) + '\n')
self.screen.refresh()
if 'Cloning' in l:
gitmsg.append(l)
if 'done' in l:
gitmsg.append(l)
if len(lines) == 1:
break
self.screen.addstr("Press any key to continue.")
self.screen.getch()
if __name__ == '__main__':
curses.wrapper(MyApp)