0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Windows版のpythonで、cmd.exeの内容を完全に取得する事は「出来ませんでした」

Posted at

npmをインストールしている時のコンソールの出力を全て残そうと思ったけど出来なかった。
理由は、isTTYで出し分けをしており、pythonのttyモジュールはwindowsでは使えないから。

やりたかった事

↓コマンド実行中に表示されるプログレスバー。コマンド完了時には消えてる。
2020-08-09-00-52-47.gif

これを全てテキストファイルに保存したかった。

した事

以下のコードでnpm install typescriptコマンドを実行した。

commands=["npm","install","typescript"]
def gl():
    cp = subprocess.Popen(commands,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    with open("./stdout.txt","bw") as fh1,open("./stderr.txt","bw") as fh2:
        while True:
            if cp.stdout is None:
                print("stdout is none")
                break
            if cp.stderr is None:
                print("stderr is none")
                break
            line = cp.stdout.readline()
            if line:
                fh1.write(line)
                fh1.flush()
                yield line
            if not line and cp.poll() is not None:
                break
            line = cp.stderr.readline()
            if line:
                fh2.write(line)
                fh2.flush()
                yield line
            if not line and cp.poll() is not None:
                break

for line in gt():
    sys.stdout.write(line.decode("utf-8").strip()+"\n")

実行結果のファイルは以下の通り

stdout.txt
+ typescript@3.9.7
updated 1 package and audited 1 package in 7.016s
found 0 vulnerabilities
stderr.txt
npm WARN saveError ENOENT: no such file or directory, open 'D:\tmp_20200809Sun004215 \package.json'
npm WARN enoent ENOENT: no such file or directory, open 'D:\tmp_20200809Sun004215 \package.json'
npm WARN tmp_20200809Sun004215  No description
npm WARN tmp_20200809Sun004215  No repository field.
npm WARN tmp_20200809Sun004215  No README data
npm WARN tmp_20200809Sun004215 No license field.

原因

プログレスバーが表示されない

コンソールで出すには標準出力か、標準エラーのどちらか経由しか無いはず。という事は、npm側で出し分けをしている?
と思ってコードを追いかけてみたら、以下の箇所でした。
https://github.com/npm/cli/blob/ad8fe71a4f8c6d717375a6c699aaa00f11521adf/lib/npm.js#L349


if (config.get('progress') && process.stderr.isTTY && process.env['TERM'] !== 'dumb') {
  log.enableProgress()
} else {
  log.disableProgress()
}

python経由で実行した時はprocess.stderr.isTTYの値がundefinedになっていた。cmd.exe経由ではtrue

ちなみに、無理やりprocess.stderr.isTTY=trueとしたり、ifの判定を飛ばして実行してみたらターミナルが無反応になったので注意。ctrl+c すら吸い込まれた。おそらく、どこかの処理で別の事をしているのだろう。

isTTY をtrueにするには

pythonならやり方あるだろう。と思って調べたら以下の記事を発見
Filter out command that needs a terminal in Python subprocess module - Stack Overflow

回答の中に、疑似tty? を作る方法が書かれていた
https://stackoverflow.com/a/43012216/4314961 より転載

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import sys
import select
import termios
import tty
import pty
from subprocess import Popen

command = 'vim'

# save original tty setting then set it to raw mode
old_tty = termios.tcgetattr(sys.stdin)
tty.setraw(sys.stdin.fileno())

# open pseudo-terminal to interact with subprocess
master_fd, slave_fd = pty.openpty()

# use os.setsid() process the leader of a new session, or bash job control will not be enabled
p = Popen(command,
          preexec_fn=os.setsid,
          stdin=slave_fd,
          stdout=slave_fd,
          stderr=slave_fd,
          universal_newlines=True)

while p.poll() is None:
    r, w, e = select.select([sys.stdin, master_fd], [], [])
    if sys.stdin in r:
        d = os.read(sys.stdin.fileno(), 10240)
        os.write(master_fd, d)
    elif master_fd in r:
        o = os.read(master_fd, 10240)
        if o:
            os.write(sys.stdout.fileno(), o)

# restore tty settings back
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)

tty.setrawとか、いかにもこれだよこれ。と思って実行してみたら、ダメ。
調べると、依存しているttyモジュールがunix限定。

Because it requires the termios module, it will work only on Unix.
https://docs.python.org/3/library/tty.html

まさかここでwindowsの2級市民っぷりを再認識する羽目になるとは。

どうすれば?

npmにプルリク出して、isTTYをオーバーライドする設定を追加してもらうとか。

pythonではどうしようもない感じなので、nodejsを使う。pty.js というライブラリがあるが
chjj/pty.js: Bindings to forkpty(3) for node.js.

最終更新が2016年の上、win10で動かないというissueも上がっていて微妙。
`npm install pty.js` failed on Windows 10 · Issue #151 · chjj/pty.js

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?