技術ドキュメント: add_docstring.py

プログラムの動作

add_docstring.py は、PythonソースファイルにSphinx形式のDocstringを自動的に追加するためのツールです。このプログラムは、大規模言語モデル(LLM)の能力を活用し、指定されたPythonコードの内容に基づいて適切なDocstringを生成します。生成されたDocstringは、元のコードに組み込まれて新しいファイルとして出力されます。

このツールの主な機能は以下の通りです。

  • Docstringの自動生成: 入力されたPythonコードの各関数、クラス、およびファイル全体に対して、LLMが内容を理解し、Sphinx形式のDocstringを生成します。

  • 柔軟なファイル指定: ワイルドカードパターンを使用して複数のPythonファイルを一度に処理できます。

  • 出力管理: 単一ファイルの場合は特定の出力ファイル名を指定でき、複数ファイルの場合は元ファイル名に _docstring.py を付加した名前で出力されます。

  • AIモデルの選択: OpenAI(GPT-4, GPT-5相当)またはGoogle Geminiといった複数のAIモデルAPIから使用するものを選択できます。

  • 設定ファイルの利用: INI形式の設定ファイルを通じて、AIへのプロンプト内容やシステムロールをカスタマイズできます。

  • 更新・上書き制御: 既存の出力ファイルが存在する場合、入力ファイルとの更新日時を比較して処理をスキップする「更新モード」や、既存ファイルを強制的に上書きする「上書きモード」を提供します。

  • 一時停止オプション: 全ての処理完了後にユーザーの入力を待つオプションがあり、実行結果を確認しやすくなっています。

このプログラムは、手作業でのDocstring記述の手間を大幅に削減し、Pythonプロジェクトのドキュメント作成プロセスを効率化することで、コードの可読性とメンテナンス性を向上させることを目的としています。

原理

add_docstring.py の動作は、主に以下のステップとアルゴリズムに基づいています。

  1. コマンドライン引数の解析: argparse モジュールを使用して、入力ファイルパターン、出力ファイル名、INI設定ファイルパス、使用するAIモデルAPI、更新・上書きモード、処理後の一時停止オプションなどのコマンドライン引数を解析します。

  2. INI設定ファイルの読み込み:

    • search_file 関数は、指定されたINIファイルを現在の作業ディレクトリ、またはスクリプトが配置されているディレクトリから検索します。

    • read_ini 関数は、見つかったINIファイルを読み込み、設定を辞書形式で返します。この関数は、コメント行(# または ; で始まる行)、複数行の値(「3重引用符」で囲まれたもの)、および $VARNAME 形式の変数展開をサポートします。特にAIに送るプロンプトのテンプレート (PROMPT_MAIN) やシステムロール (SYSTEM_ROLE) がここで読み込まれます。

  3. 対象ファイルの展開と出力パスの決定:

    • glob モジュールを使用して、コマンドラインで指定されたワイルドカードパターン(例: '*.py')に合致するすべてのPythonファイルをリストアップします。

    • 出力ファイル名は、単一ファイルの場合はコマンドライン引数で指定された名前を、複数ファイルの場合は元のファイル名に _docstring.py を付加した名前(例: example.pyexample_docstring.py)を使用します。

  4. Docstring生成処理ループ: 各入力Pythonファイルに対し、以下の処理を繰り返します。

    • 更新・上書きチェック:

      • 出力ファイルが既に存在し、上書き (-w 1) が指定されていない場合、処理をスキップするかどうかの判断を行います。

      • 更新モード (-u 1) が有効な場合、出力ファイルの最終更新日時が入力ファイルの最終更新日時と同じかそれより新しい場合に処理をスキップします。これは、最新のDocstringが既に存在すると判断するためです。

    • ソースコードの読み込み: 対象のPythonソースファイルをUTF-8エンコーディングで読み込みます。失敗した場合はShift-JISエンコーディングで再試行します。

    • プロンプトの構築: INIファイルから読み込んだ PROMPT_MAIN テンプレートに、読み込んだソースコード ({{code}}) とファイル名 ({{script_name}}) を埋め込み、AIに送信する最終的なプロンプトを作成します。

    • AIモデルへの問い合わせ:

      • tkai_lib ライブラリを介して、指定されたAIモデル(OpenAIのGPT-4/GPT-5相当、Google Geminiなど)に構築したプロンプトを送信します。

      • read_ai_config("ai.env") を呼び出し、ai.env ファイルからAPIキーなどのAI設定を環境変数として読み込みます。

    • AI応答からのDocstring抽出: AIからの応答テキストから、Markdownのコードブロックを示すバッククォート(「```」)を除去し、純粋なDocstringテキストを抽出します。

    • 出力ファイルへの書き込み: 抽出されたDocstringテキストを、決定された出力ファイル名で新しいPythonファイルとしてUTF-8エンコーディングで保存します。

  5. レートリミット対策: 各AI API呼び出しの間に1秒間の time.sleep(1) を挿入し、APIのレートリミット超過を防ぎます。

これらのステップを通じて、プログラムは既存のPythonコードからDocstringの欠落や古さを検出し、LLMの理解力と生成能力を用いて適切で最新のDocstringを自動的に追加します。

必要な非標準ライブラリとインストール方法

add_docstring.py は、AIサービスとの連携のために tkai_lib というライブラリを利用しています。

  • tkai_lib:

    • このライブラリは、Pythonの標準的なパッケージ管理システム pip で直接インストールできる公開パッケージではありません。

    • 通常は、add_docstring.py と同じディレクトリ、またはPythonのモジュール検索パスに含まれるカスタムライブラリです。

    • したがって、ユーザーはこの tkai_lib.py ファイルを別途入手し、スクリプトが動作する環境に配置する必要があります。

Pythonの標準ライブラリ(os, sys, argparse, glob, time, re, traceback, pathlib)は追加のインストールは不要です。

AIサービス利用のための準備:

  • APIキーの取得と設定:

    • OpenAIまたはGoogle Gemini APIを利用するためには、それぞれのサービスでAPIキーを取得する必要があります。

    • 取得したAPIキーは、プログラムが読み込む .env 形式のファイル(例: ai.env)に環境変数として記述するか、システム環境変数として設定する必要があります。

    例: ai.env ファイルの内容

    OPENAI_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    openai_model="gpt-4o-mini"
    openai_model5="gpt-4o"
    GEMINI_API_KEY="AIzaSyXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    gemini_model="gemini-pro"
    

    openai_modelopenai_model5 は、それぞれ --api openai--api openai5 オプションで使用するモデル名を指定します。gemini_model--api google (Gemini APIを指す) オプションで使用するモデル名を指定します。

必要な入力ファイル

add_docstring.py の実行には、以下のファイルが必要です。

  1. Pythonソースファイル:

    • 形式: .py 拡張子のPythonソースコードファイル。

    • データ構造: Docstringを追加したい関数、クラス、モジュールなどが含まれる任意のPythonプログラム。

    • 説明: コマンドライン引数の <pattern> で指定されます(例: my_script.py, '*.py', src/*.py)。

  2. INI設定ファイル:

    • 形式: .ini 拡張子のテキストファイル。

    • ファイル名: コマンドライン引数 --inifile で指定します。指定がない場合、スクリプト名と同じ名前(例: add_docstring.ini)がデフォルトとして使用されます。このファイルは、add_docstring.py と同じディレクトリ、またはカレントディレクトリに配置されている必要があります。

    • 内容: AIへのプロンプトテンプレートとシステムロールを定義します。

      • PROMPT_MAIN: AIにDocstring生成を依頼する際のプロンプトのテンプレートです。このテンプレートには、プレースホルダー {{script_name}}(入力ファイル名に置換)と {{code}}(入力Pythonコードに置換)を含める必要があります。

      • SYSTEM_ROLE: AIの応答スタイルや役割を定義するシステムメッセージです。

    • : add_docstring.ini

      # プロンプト設定
      [PROMPTS]
      PROMPT_MAIN = あなたはPythonコードの専門家です。以下のPythonスクリプトについて、Sphinx形式のDocstringを生成してください。\n\nスクリプト名: {{script_name}}\n\nコード:\n```python\n{{code}}\n```\n\nDocstringはファイル冒頭の3重引用符内と、各関数・クラスの定義直後に挿入してください。例:\n\n「3重引用符」\nファイル概要...\n「3重引用符」\n\ndef my_func(arg):\n    「3重引用符」\n    関数の説明。\n\n    :param arg: 引数の説明。\n    :returns: 戻り値の説明。\n    「3重引用符」
      SYSTEM_ROLE = You are a helpful assistant that generates Sphinx-style docstrings for Python code.
      

      : 上記の例では、PythonのDocstringを示す「3重引用符」が、指示に従い「3重引用符」というテキストに置き換えられています。

  3. AI設定ファイル(例: ai.env:

    • 形式: .env 形式のテキストファイル。

    • ファイル名: プログラム内部で read_ai_config("ai.env") により ai.env という名前が想定されています。このファイルは、add_docstring.py と同じディレクトリ、またはカレントディレクトリに配置されている必要があります。

    • 内容: 各AIサービスへのアクセスに必要なAPIキーや、使用するAIモデル名を定義します。

    • : ai.env

      OPENAI_API_KEY="sk-your-openai-api-key"
      openai_model="gpt-4o-mini"
      openai_model5="gpt-4o"
      GEMINI_API_KEY="AIzaSy_your-gemini-api-key"
      gemini_model="gemini-pro"
      

生成される出力ファイル

add_docstring.py は、入力されたPythonソースファイルに基づいて、以下の形式で新しいPythonソースファイルを生成します。

  • ファイル名:

    • 単一の入力ファイルを処理する場合: コマンドライン引数の output で指定されたファイル名が使用されます。

    • 複数の入力ファイルを処理する場合: 各入力ファイルのベース名に _docstring.py という接尾辞が付加されます。

      • 例: my_script.py が入力された場合、デフォルトの出力は my_script_docstring.py となります。

  • 内容:

    • 元のPythonソースコードに、AIが生成したSphinx形式のDocstringが追加された完全なPythonスクリプトです。

    • Docstringは以下の位置に挿入されます。

      • ファイルの冒頭(モジュールDocstring)。

      • 各クラス定義の直後(クラスDocstring)。

      • 各関数/メソッド定義の直後(関数/メソッドDocstring)。

    • 生成されるDocstringは、Pythonの「3重引用符」で囲まれ、SphinxのreStructuredText形式(:param:, :returns: など)に従います。

生成される出力ファイルの例:

元のファイル (my_script.py):

def calculate_area(radius):
    return 3.14159 * radius * radius

class Circle:
    def __init__(self, radius):
        self.radius = radius

    def get_circumference(self):
        return 2 * 3.14159 * self.radius

add_docstring.py 実行後 (my_script_docstring.py):

"""
このモジュールは円に関連する計算機能を提供します。

円の面積や円周を計算するための関数とクラスを含んでいます。
"""

def calculate_area(radius):
    """
    指定された半径を持つ円の面積を計算します。

    :param radius: 円の半径 (float)。
    :returns: 円の面積 (float)。
    """
    return 3.14159 * radius * radius

class Circle:
    """
    円のプロパティと操作を表すクラス。

    :ivar radius: 円の半径。
    """
    def __init__(self, radius):
        """
        Circleオブジェクトの新しいインスタンスを初期化します。

        :param radius: 円の半径 (float)。
        """
        self.radius = radius

    def get_circumference(self):
        """
        円の円周を計算して返します。

        :returns: 円の円周 (float)。
        """
        return 2 * 3.14159 * self.radius

コマンドラインでの使用例 (Usage)

add_docstring.py はコマンドラインツールであり、以下の形式で実行します。

python add_docstring.py <pattern> [output] [--inifile INIFILE] [--api {openai,openai5,google,gemini}] [-u {0,1}] [-w {0,1}] [-p {0,1}]

引数の説明:

  • <pattern> (必須):

    • Docstringを追加する対象となるPythonファイルのワイルドカードパターン。

    • 例: '*.py', my_script.py, 'src/*.py'

  • [output] (オプション):

    • 出力ファイル名。この引数は、<pattern> が単一のファイルにマッチする場合のみ有効です。

    • 省略した場合、出力ファイル名は元のファイル名に _docstring.py が付加されます。

  • --inifile INIFILE (オプション):

    • AIへのプロンプト設定を含むINIファイルのパス。

    • デフォルトは add_docstring.ini です。

  • --api {openai,openai5,google,gemini} (オプション):

    • 使用するAIモデルのAPIを選択します。

      • openai: openai_model 環境変数で指定されたOpenAIモデル(例: gpt-4o-mini)を使用します。

      • openai5: openai_model5 環境変数で指定されたOpenAIモデル(例: gpt-4o)を使用します。

      • google または gemini: gemini_model 環境変数で指定されたGoogle Geminiモデル(例: gemini-pro)を使用します。

    • デフォルトは google です。

  • -u {0,1}, --update {0,1} (オプション):

    • 更新モードを制御します。1 を指定すると、出力ファイルが入力ファイルよりも新しい場合に処理をスキップします。

    • デフォルトは 0 (無効) です。

  • -w {0,1}, --overwrite {0,1} (オプション):

    • 上書きモードを制御します。1 を指定すると、既存の出力ファイルを無条件に上書きします。

    • デフォルトは 0 (無効) です。

  • -p {0,1}, --pause {0,1} (オプション):

    • 処理完了後に一時停止するかどうかを制御します。1 を指定すると、処理完了後にEnterキーが押されるまでプログラムが終了しません。

    • デフォルトは 1 (有効) です。

コマンドラインでの具体的な使用例

ここでは、add_docstring.py の具体的な使用例をいくつか示します。実行には、前述の「必要な入力ファイル」セクションで説明されている add_docstring.ini および ai.env ファイルが適切に設定されていることを前提とします。

例1: 単一のPythonファイルにDocstringを追加し、別のファイル名で出力する

my_module.py というファイルにDocstringを追加し、my_module_final.py という名前で保存します。Google Gemini APIを使用します。

python add_docstring.py my_module.py my_module_final.py --api google --pause 0
  • my_module.py (入力ファイル):

    def greeting(name):
        return f"Hello, {name}!"
    
  • 実行結果の説明: my_module_final.py が生成され、greeting 関数にDocstringが追加されたPythonコードが含まれます。処理完了後に一時停止しません。

    # my_module_final.py の内容例
    """
    このモジュールはシンプルな挨拶機能を提供します。
    """
    
    def greeting(name):
        """
        指定された名前に対して挨拶メッセージを生成します。
    
        :param name: 挨拶する対象の名前 (str)。
        :returns: 生成された挨拶メッセージ (str)。
        """
        return f"Hello, {name}!"
    

例2: 複数のPythonファイルにDocstringを追加し、上書きモードとOpenAI API (GPT-4o-mini) を使用する

src/ ディレクトリ内のすべてのPythonファイルにDocstringを追加します。既存の出力ファイルを上書きし、処理後に一時停止しません。

python add_docstring.py "src/*.py" --api openai --overwrite 1 --pause 0
  • src/file1.py, src/file2.py (入力ファイル):

    # src/file1.py
    def add(a, b):
        return a + b
    
    # src/file2.py
    class Calculator:
        def multiply(self, a, b):
            return a * b
    
  • 実行結果の説明: src/file1_docstring.pysrc/file2_docstring.py が生成または上書きされます。各ファイルには元のコードにAIが生成したDocstringが追加されます。

    # src/file1_docstring.py の内容例
    """
    このモジュールは基本的な算術関数を提供します。
    """
    
    def add(a, b):
        """
        二つの数値を加算します。
    
        :param a: 最初の数値 (int or float)。
        :param b: 二番目の数値 (int or float)。
        :returns: 二つの数値の合計 (int or float)。
        """
        return a + b
    

例3: 更新モードを使用して、既に最新の出力ファイルをスキップする

script.py と、既にDocstringが追加されており script_docstring.py として保存されたファイルがあるとします。script_docstring.py の方が script.py より新しい場合、処理をスキップします。

python add_docstring.py script.py --update 1
  • script.py (入力ファイル):

    def hello():
        print("Hello")
    
  • script_docstring.py (既存の出力ファイル):

    # script.py の Docstring 付きバージョンで、script.py よりも新しいタイムスタンプを持つ
    """
    シンプルな挨拶機能を持つモジュール。
    """
    
    def hello():
        """
        コンソールに「Hello」と出力します。
        """
        print("Hello")
    
  • 実行結果の説明: コンソールに以下のようなメッセージが表示され、script_docstring.py は再生成されません。

    Args:
      args.pattern='script.py'
      args.output=None
      args.inifile='add_docstring.ini'
      args.api='google'
      args.update=1
      args.overwrite=0
      args.pause=1
    Loaded INI: /path/to/add_docstring.ini
    Skip: script_docstring.py
    
    Press ENTER to terminate>>