別の変換プログラムを呼んだ後は、処理を起動できたことと、成功して終わったことを分けます。起動時にエラーが出なくても、呼び出した先が途中で失敗することがあります。
Pythonのsubprocess.runを使うと、終了コード、標準出力、標準エラー出力を受け取れます。非0の終了と待ち時間の超過を別に扱うと、次に確認する場所も分けられます。
子Pythonで三つの結果を試す
次は別の業務プログラムではなく、ローカルのPythonを子プロセスとして呼ぶ架空の例です。同じPythonの実行先をsys.executableで指定し、UTF-8の出力へそろえます。
import subprocess
import sys
def run_python(code, timeout=3):
return subprocess.run(
[sys.executable, "-X", "utf8", "-c", code],
check=True,
capture_output=True,
text=True,
encoding="utf-8",
timeout=timeout,
)
success = run_python("print('ready')")
print("成功:", success.stdout.strip())
assert success.returncode == 0
try:
run_python("raise SystemExit(3)")
except subprocess.CalledProcessError as error:
print("失敗時の終了コード:", error.returncode)
assert error.returncode == 3
else:
raise AssertionError("失敗を検出できません")
try:
run_python("import time; time.sleep(5)", timeout=0.2)
except subprocess.TimeoutExpired:
print("待ち時間を超過")
else:
raise AssertionError("時間超過を検出できません")
成功、終了コード3、待ち時間超過の三つが表示されます。Windows・Python 3.12.10で、この三経路を実行しました。実際の帳票変換や外部サービスへ接続した結果ではありません。
引数はリストで渡す
コードは実行ファイルと各引数を別の要素にしています。空白を含むパスなどを一つのシェル文字列へ組み立てる方法とは違います。必要のない場面でshell=Trueを加えない形です。
実際のツールを呼ぶ場合も、実行ファイルの場所、作業フォルダー、入力ファイルのパスを明確にします。親の実行場所が変わるだけで入力先が変わらないか、確認してください。
失敗した出力を成功結果へ流さない
CalledProcessErrorには終了コードなどの情報があります。診断を読む場合は、入力全文や秘密が出力に含まれないかも確認してからログへ残します。
capture_outputは出力をメモリーへ受け取る指定です。大量のログを出すプログラムなら、ファイルへ渡すなど別の受け取り方も検討します。成功時でも、必要な結果ファイルや値があるかを読み戻す確認は残ります。
timeoutの範囲を理解する
runのtimeoutは、指定時間後に必ず親処理が戻るという保証ではありません。環境によってはプロセス作成自体を中断できず、その時間が必要になることがあります。
また、この例の子は一つのPythonです。子がさらに別の処理を起動する構成で、その全体が同じように停止することを検証したわけではありません。実際に使う変換ツールで、時間超過後に処理や一時出力が残らないかを確認します。
例外の扱いはPythonの例外処理、ファイル位置の整理はpathlib入門で補えます。
参考資料
Python subprocess公式資料を2026年11月1日に確認しました。
