【Python】subprocess.Popenのreturncodeが0(サブプロセスが終了せず)にならず、ハマった話をメモ

  • 2022年2月11日
  • 2023年5月18日
  • python

こんにちは。

野中やすおです。

タイトルにある通り、PythonのsubprocessモジュールのPopen(ぴーおーぷん、と読むらしいです)クラスがreturncodeがゼロ以外の場合に例外を発生させるエラーハンドリング処理を実装しようとしていたのですが、subprocess.Popenがどういったものか分からず、少し実装に時間がかかってしまったのでメモを残そうと思います。

subprocess.Popenとは?

subprocessモジュールあるいは、Popenクラスの詳細な話はまた別記事でしたいと思います。

公式HPは以下のリンクになります。

https://docs.python.org/ja/3/library/subprocess.html#popen-objects

Popen.returncodeが0にならなかった理由

Popenはサブプロセスが実行されている間は、Popen オブジェクトのreturncode属性はNoneを返します。以下のコード例を使って紹介したいと思います。

まずは、subprocess.Popenで「ls  -la」(ディレクトリ中にあるファイル詳細を全て表示させるコマンド) を実行します。

その返り値をpとし、単純にprintするとPopenオブジェクトが返ってきていることがわかります。Popenオブジェクトの説明がある公式HPは以下のURLから飛ぶことができますので、同時に参照お願いします。

https://docs.python.org/ja/3/library/subprocess.html#popen-objects

次に「”process id = %s” % p.pid」でPopenで実行しているプロセスidを確認します。例えばプロセスIDが14とします。次にp.returncodeをprintしてもNoneになります。つまりそのサブプロセスが終了していないことを示します。

なので、wait関数である「Popen.wait」を使って(その他poll関数などがあります)をサブプロセスが終わるまで待ちます。Popen.waitは、returncode属性を設定して返却します。ちなみにPopen.waitはPopen.wait(timeout=10)のように、引数としてtimeoutを設定することができ、プロセスが timeoutに設定した秒後に終了してない場合、TimeoutExpired 例外を発出します。TimeoutExpiredを使ったエラーハンドリングもできますね。

確認のために、Popen.waitの前後にrunを使って起動しているプロセスを確認します。そうするとwait実行前には、プロセスID 14のサブプロセスが実行されていること、wait実行後にはそのサブプロセスが終了し、printの結果から消えていることが確認できます。

最後にもう一度p.returncodeをprintするとコマンドの正常終了を表すが返ってきています。

今までおざなりになっていたsubprocessの使い方が実装にハマったことで理解が深まりました。

そして例えば以下のような形でPopenで実行したコマンドがうまくいかない場合には以下のようにエラーハンドリングをして、処理を中断させることができます。

もしこの記事が参考になった方がいらっしゃれば幸いです!