S-JIS[2025-12-21/2026-02-22]

pyo3 例外

Rustpyo3で例外クラスを作成する方法のメモ。


概要

PyO3では、Pythonの例外クラス(Rustの構造体)はcreate_exception!マクロで作成できる。

例外の基底クラス(継承元クラス)としてPyException等の構造体(Pythonのクラス)が用意されている。

use pyo3::{create_exception, exceptions::PyException};

create_exception!(モジュール名, 例外名, 継承元クラス名);
create_exception!(モジュール名, 例外名, 継承元クラス名, 説明文);

モジュール名.例外名」の例外クラス(Rustの構造体)が定義される。

説明文を付けておくと、「例外クラス.__doc__」でその説明文が取得できる。(説明文を指定しなかった場合はNoneが返る)
help(例外クラス)」でも表示される。


例外のインスタンスは「例外クラス::new_err(メッセージ)」で生成する。
これはPyErr型であり、戻り型がPyResultである関数からErrで返すと、Python側では例外が送出される。


例外を送出するだけなら例外クラス(構造体)を定義しておくだけでいいが、それをPython側で使いたい場合(try〜exceptに記述する場合等)は、例外クラス(構造体)をエクスポート(pymodule_export)する必要がある。


example-pyo3/src/error.rs

use pyo3::{create_exception, exceptions::PyException};

create_exception!(example_pyo3, MyError, PyException);
create_exception!(example_pyo3, MyError2, PyException);
create_exception!(example_pyo3, MyError3, MyError);

example-pyo3/src/lib.rs:

use pyo3::prelude::*;

mod error;

#[pymodule]
mod example_pyo3 {
    use pyo3::prelude::*;

    #[pymodule_export]
    use crate::error::{MyError, MyError2, MyError3};

    #[pyfunction]
    fn throw_exception(n: i32) -> PyResult<()> {
        match n {
            2 => Err(MyError2::new_err("error message2")),
            3 => Err(MyError3::new_err("error message3")),
            _ => Err(MyError::new_err("error message1")),
        }
    }
}

pymodule_exportで例外クラスをエクスポートする(Python側から使えるようにする)。
(pymodule_exportでは*を使えない。すなわち「use create::error::*;」と書くことは出来ない)

呼び出すPython側

call-pyo3/main.py:

import example_pyo3

def main():
    try:
        example_pyo3.throw_exception(3)
    except example_pyo3.MyError as e:
        print(f"1: {e}")
    except example_pyo3.MyError2 as e:
        print(f"2: {e}")

if __name__ == "__main__":
    main()

> uv run main.py
1: error message3

この例では、throw_exception(3)はMyError3が発生するが、MyError3はMyErrorを継承しているので、MyErrorとして捕捉される。


型スタブファイルの生成

pyo3-stub-genで例外クラスは型スタブファイルの生成対象外になると思っていたので、例外クラスのpyiファイルを生成するスクリプトを作ってみた。 (正確には、ChatGPTに作らせたものを手直しした)[2026-02-22]

実際には、pyo3-stub-genが提供しているcreate_exception!マクロを使うだけで良かったのだが、
せっかくなので、作ったスクリプトも残しておく。

PyO3プロジェクトにtoolsというディレクトリーを作り、そこに置く想定。


使い方は以下の通り。

cd hidden-example
uv run tools/gen_exception_pyi.py -m hidden_example.error -o python/hidden_example/error/__init__.pyi

-mで例外クラスが入っているモジュールを指定する。(必須)

-oで出力先ファイル名を指定する。指定しない場合は標準出力に出力する。


pyo3へ戻る / Rustへ戻る / 技術メモへ戻る
メールの送信先:ひしだま