きっかけ
私は以前、Pythonの各ライブラリ型情報をまとめているtypeshed
に、ctypes
の内部実装_ctypes
に定義された_ctypes.COMError
の型情報を追加するPRをopenしてmergeされました。
このCOMError
は発生時スタックトレースに現れてキャッチされなければシステムを停止させる例外、つまり事実上パブリックな例外であるにも関わらず、どのような理由でエラーが起きるのか、エラーの各属性が何を意味するかなどはドキュメントで言及されておらず、仕様が不明瞭なものでした。
公式のドキュメントが存在しないことにより、この例外は私がメンテナンスしているcomtypes
のカスタム例外であると勘違いされることが多く、似通った内容のIssueがopenして質問と回答が繰り返され、メンテナーやコミュニティが疲弊する要素の一つとなっていました。
この状況を改善すべく、私はPythonのドキュメントに_ctypes.COMError
に関する記述を追加しようと考えました。
_ctypes.COMError
とは
COMError
は、Pythonのctypes
モジュールを使用してCOM (Component Object Model) オブジェクトと連携する際に発生するエラーです。
COMError
は、COM関連のエラー情報を保持するためのいくつかのフィールドを持っています。
-
hresult
: COMメソッドの実行結果を示す数値コードであるHRESULT
値を表します -
text
: エラーメッセージ -
details
: 長さ5で構成されるタプルです- インデックス0:
descr
。テキストによる説明 - インデックス1:
source
。エラーを発生させたクラスまたはアプリケーションの(言語依存の)ProgID
- インデックス2:
helpfile
。ヘルプファイルのパス - インデックス3:
helpcontext
。ヘルプコンテキストの識別子 - インデックス4:
progid
。エラーを定義したインターフェースのProgID
- インデックス0:
これらのフィールドを通じて、COMエラーの詳細な情報を取得し、エラーの原因を特定することができます。
OSError
との違い
COMメソッドの定義方法によっては、OSError
がCOMError
の代わりに投げられることがあります。
OSError
は、オペレーティングシステムに関連するエラー、例えばファイルが見つからない、ネットワークに接続できないなどの場合に発生します。
ctypes
でCOMオブジェクトのメソッドを呼び出す際、PYFUNCTYPE
を使って関数プロトタイプを作成し、そのプロトタイプからメソッド呼び出しを行うための関数を生成します。
プロトタイプから関数を生成する際にIID(COMインターフェースを一意に識別するためのGUID(Globally Unique Identifier))を指定しなければ、COMError
がOSError
の代わりに投げられます。
PR mergeまでの顛末
まず、私はPythonのIssueトラッカーにCOMError
に関するドキュメントを追加したい旨を報告しました。
しかし、Issueではあまり議論は起こりませんでした。そこで、私は反対意見がないものと判断し、プロダクションコードを変更することなくドキュメントだけを変更するPull Requestを送りました。
すると、PRを提出してから議論が始まりました。議論の中で他の開発者から「"プライベート"な要素に対してドキュメントを追加するだけでなく、COMError
をctypes
へインポートしてパブリックにした方がいい」という提案があり、私もその提案に賛同しました。
Pull Requestは、他の開発者によるレビューを経て、最終的にmergeされました。
現在の状況
現在では、ctypes.COMError
としてこのエラーはパブリックになり、Pythonのドキュメントにもctypes.COMError
に関する記述が追加されました。
-
PYFUNCTYPE
に関する記載
https://docs.python.org/ja/3.14/library/ctypes.html#ctypes.PYFUNCTYPE -
COMError
に関する記載
https://docs.python.org/ja/3.14/library/ctypes.html#ctypes.COMError
Python 3.14ベータ版も2025/4/7にリリースされたため、特に問題がなければファイナルリリースにも上記は含まれる予定です。
その後
この件を通じて、私はOSSへのコントリビューションの難しさ、そして楽しさを学びました。
当初はドキュメントの追加だけで良いと考えていましたが、他の開発者との議論を通じて、より良い解決策を見つけることができました。
また、Pull Requestを送る際には、コードの品質だけでなく、ドキュメントの整備やテストの追加なども行う必要があり、OSSへのコントリビューションは簡単なことでもありません。
しかし、自分の書いたコードがPythonのプロダクションコードとなり、多くのユーザーが利用するようになるのは、非常にやりがいのある経験でした。
この記事が、OSSへのコントリビューションに興味を持つ方にとって、少しでも参考になれば幸いです。