Skip to content

遅延インポートによるヘルプ表示の高速化#1545

Open
yuji38kwmt wants to merge 1 commit intomainfrom
feature/lazy-import-for-help
Open

遅延インポートによるヘルプ表示の高速化#1545
yuji38kwmt wants to merge 1 commit intomainfrom
feature/lazy-import-for-help

Conversation

@yuji38kwmt
Copy link
Copy Markdown
Collaborator

概要

ヘルプ表示を高速化するため、サブコマンドのインポートを遅延させる実装を追加しました。

変更内容

  • サブコマンドのインポートを遅延させることで、ヘルプ表示時は必要最小限のモジュールのみロード
  • サブコマンド実行時のみ、該当するモジュールをインポート
  • 後方互換性のためcreate_parser()関数は維持(テストコードで使用されている可能性があるため)

パフォーマンス改善結果

バージョン 平均実行時間 改善率
元のバージョン 1036ms -
遅延インポート版 556ms 約46%高速化

動作確認

  • annofabcli --helpの表示が正常に動作することを確認
  • サブコマンドのヘルプ表示(annofabcli task --helpなど)が正常に動作することを確認
  • 既存のテストが正常にパスすることを確認
  • Lintエラーがないことを確認

影響範囲

  • ヘルプ表示が約50%高速化されるため、補完ツールでの使用が実用的な速度になります
  • 既存の機能に影響はありません
  • 後方互換性は維持されています

AI(GitHub Copilot)が生成したPRです。

- サブコマンドのインポートを遅延させることで、ヘルプ表示を約50%高速化(1秒→0.5秒)
- ヘルプ表示時は必要最小限のモジュールのみロード
- サブコマンド実行時のみ、該当するモジュールをインポート
- 後方互換性のためcreate_parser()関数は維持

パフォーマンス改善:
- 元のバージョン: 平均1036ms
- 遅延インポート版: 平均556ms
- 改善率: 約46%

これにより補完ツールでの使用も実用的な速度になりました。

AI(GitHub Copilot)が生成したコミットです。
Copilot AI review requested due to automatic review settings January 26, 2026 02:30
@kci-pr-agent
Copy link
Copy Markdown
Contributor

kci-pr-agent bot commented Jan 26, 2026

Title

遅延インポートによるヘルプ表示の高速化


Description

  • ヘルプ表示でサブコマンドを遅延ロード

  • SUBCOMMANDS 辞書でサブコマンド定義集約

  • create_parser_lazyload_subcommand_parser 追加

  • main 関数の引数解析を遅延対応


Changes walkthrough 📝

Relevant files
Enhancement
__main__.py
遅延インポート対応と main 処理改修                                                                         

annofabcli/main.py

  • トップレベルのサブコマンドimportを削除
  • SUBCOMMANDS 辞書でモジュール・ヘルプ定義
  • create_parser_lazy で遅延ヘルプサポート追加
  • main 処理を遅延ロード対応に改修
  • +208/-37

    Need help?
  • Type /help how to ... in the comments thread for any questions about PR-Agent usage.
  • Check out the documentation for more information.
  • @kci-pr-agent
    Copy link
    Copy Markdown
    Contributor

    kci-pr-agent bot commented Jan 26, 2026

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    ⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
    🧪 No relevant tests
    🔒 No security concerns identified
    ⚡ Recommended focus areas for review

    Importエラー時の処理

    モジュールの遅延読み込み時にimportlib.import_moduleでエラーが発生した場合、ユーザーにわかりやすいエラーメッセージを出力して正常終了するか検討してください

    def load_subcommand_parser(module_path: str) -> argparse.ArgumentParser:
        """
        指定されたサブコマンドのパーサーを遅延ロードする。
        """
        import importlib  # noqa: PLC0415
    
        # モジュールをインポート
        module = importlib.import_module(module_path)
    サブコマンドヘルプ動作

    create_parser_lazyでadd_help=Falseを指定したサブコマンドが-h/--helpで期待どおりヘルプを表示するか動作確認を行ってください

    # サブコマンドの簡易登録(遅延ロード用)
    for cmd_name, cmd_info in SUBCOMMANDS.items():
        subparser = subparsers.add_parser(cmd_name, help=cmd_info["help"], add_help=False)
        # 実際のサブコマンドは実行時にロードする
        subparser.set_defaults(_lazy_module=cmd_info["module"], _lazy_command=cmd_name)

    Comment thread annofabcli/__main__.py
    Comment on lines +149 to +152
    # サブコマンドの簡易登録(遅延ロード用)
    for cmd_name, cmd_info in SUBCOMMANDS.items():
    subparser = subparsers.add_parser(cmd_name, help=cmd_info["help"], add_help=False)
    # 実際のサブコマンドは実行時にロードする
    Copy link
    Copy Markdown
    Contributor

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    Suggestion: 遅延ロード用サブコマンドにヘルプオプションがないため、-h/--helpでサブコマンド固有のヘルプが表示できません。add_help=Falseを削除するか、サブパーサーに明示的に-h/--help引数を追加してヘルプを有効化してください。 [general, importance: 5]

    Suggested change
    # サブコマンドの簡易登録(遅延ロード用)
    for cmd_name, cmd_info in SUBCOMMANDS.items():
    subparser = subparsers.add_parser(cmd_name, help=cmd_info["help"], add_help=False)
    # 実際のサブコマンドは実行時にロードする
    for cmd_name, cmd_info in SUBCOMMANDS.items():
    subparser = subparsers.add_parser(cmd_name, help=cmd_info["help"]) # add_help=False を削除
    subparser.add_argument("-h", "--help", action="help", help="サブコマンドのヘルプを表示します。")
    subparser.set_defaults(_lazy_module=cmd_info["module"], _lazy_command=cmd_name)

    Comment thread annofabcli/__main__.py
    Comment on lines 238 to +240
    else:
    # 未知のサブコマンドの場合はヘルプを表示
    args.command_help()
    # サブコマンドが見つからない場合
    parser_lazy.print_help()
    Copy link
    Copy Markdown
    Contributor

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    Suggestion: 未知のサブコマンド実行時にヘルプを表示したまま正常終了してしまうため、エラーコードを返すようにしてください。sys.exit(1)を追加することで呼び出し元に失敗を伝えられます。 [general, importance: 7]

    Suggested change
    else:
    # 未知のサブコマンドの場合はヘルプを表示
    args.command_help()
    # サブコマンドが見つからない場合
    parser_lazy.print_help()
    else:
    # サブコマンドが見つからない場合
    parser_lazy.print_help()
    sys.exit(1)

    Copy link
    Copy Markdown
    Contributor

    Copilot AI left a comment

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    Pull request overview

    ヘルプ表示の高速化のために、サブコマンドのインポートを遅延させる仕組みを annofabcli のエントリポイントに導入するPRです。

    Changes:

    • サブコマンド一覧を静的定義し、--help 時はサブコマンド実装を import しない構成に変更
    • 実行時に選択されたサブコマンドだけを importlib でロードしてパースするフローを追加
    • 後方互換のため、従来の create_parser() を維持(全サブコマンドをロード)

    Comment thread annofabcli/__main__.py
    Comment on lines +199 to +205
    # ヘルプ表示のみの場合は遅延パーサーを使う
    if len(argv) == 0 or argv[0] in ["-h", "--help"]:
    parser = create_parser_lazy()
    args = parser.parse_args(argv)
    if hasattr(args, "command_help"):
    args.command_help()
    return
    Copy link

    Copilot AI Jan 26, 2026

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    ヘルプ表示/バージョン表示の分岐と遅延ロードの新しい制御フローが入っているため、最低限 tests/test____main__.py などで main([]) / main(["--help"]) / main(["task","--help"]) のようなケースが期待どおりに動く(SystemExit の有無や終了コードなど)ことをテストで担保したいです。現状この経路を直接検証するテストが見当たりません。

    Copilot uses AI. Check for mistakes.
    Comment thread annofabcli/__main__.py
    Comment on lines +170 to +173
    parser = argparse.ArgumentParser(description="Command Line Interface for Annofab", formatter_class=annofabcli.common.cli.PrettyHelpFormatter)
    parser.add_argument("--version", action="version", version=f"annofabcli {annofabcli.__version__}")
    parser.set_defaults(command_help=parser.print_help)

    Copy link

    Copilot AI Jan 26, 2026

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    create_parser_lazy()load_subcommand_parser()create_parser() で、トップレベルの ArgumentParser 生成(description/formatter/--version/defaults)が重複しています。将来どれか一方だけが更新されると挙動差分が出やすいので、共通のヘルパー(例: create_base_parser())に切り出して重複をなくすのが安全です。

    Copilot uses AI. Check for mistakes.
    Comment thread annofabcli/__main__.py
    # バージョン表示
    if argv[0] in ["--version"]:
    parser = create_parser_lazy()
    args = parser.parse_args(argv)
    Copy link

    Copilot AI Jan 26, 2026

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    --version 処理の分岐で args = parser.parse_args(argv) を代入していますが、その後 args を参照していないため Ruff の F841 (local variable 'args' is assigned to but never used) でlintエラーになります。代入せずに parser.parse_args(argv) を呼ぶか、未使用であることが明確な変数名(例: _args)にしてください。

    Suggested change
    args = parser.parse_args(argv)
    parser.parse_args(argv)

    Copilot uses AI. Check for mistakes.
    Comment thread annofabcli/__main__.py
    # 未知のサブコマンドの場合はヘルプを表示
    args.command_help()
    # サブコマンドが見つからない場合
    parser_lazy.print_help()
    Copy link

    Copilot AI Jan 26, 2026

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    parse_known_args() の結果でサブコマンドが判定できなかった場合に無条件で print_help() してしまうため、例えば annofabcli --unknown-option のような入力でもエラー終了せずヘルプ表示(終了コード0)になってしまいます(以前は argparse の unrecognized arguments で終了コード2)。_remaining に未知の引数が残っている場合は parser_lazy.parse_args(argv) でエラーにする、もしくは parser_lazy.error(...) を呼ぶなどして従来どおりエラー扱いにしてください。

    Suggested change
    parser_lazy.print_help()
    if len(_remaining) != 0:
    # 未知の引数が残っている場合は、従来どおりエラー扱いにする
    parser_lazy.parse_args(argv)
    else:
    parser_lazy.print_help()

    Copilot uses AI. Check for mistakes.
    Comment thread annofabcli/__main__.py

    if hasattr(args_lazy, "_lazy_module"):
    # 実際のサブコマンドパーサーをロード
    parser = load_subcommand_parser(args_lazy._lazy_module) # noqa: SLF001
    Copy link

    Copilot AI Jan 26, 2026

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    args_lazy._lazy_module のように先頭が _ の属性名を使っているため、アクセス側で # noqa: SLF001 が必要になっています。CLI内部用の値であれば lazy_module のような名前に変更して noqa を不要にすると、意図が明確になり lint抑止も減らせます。

    Suggested change
    parser = load_subcommand_parser(args_lazy._lazy_module) # noqa: SLF001
    lazy_module = getattr(args_lazy, "_lazy_module")
    parser = load_subcommand_parser(lazy_module)

    Copilot uses AI. Check for mistakes.
    Comment thread annofabcli/__main__.py
    args.subcommand_func(args)
    except Exception as e:
    logger.exception(e) # noqa: TRY401
    raise e # noqa: TRY201
    Copy link

    Copilot AI Jan 26, 2026

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    例外捕捉後に raise e で再送出すると traceback が書き換わり、元の例外発生箇所が追いづらくなります。ここは bare raise で再送出してください(ログ出力は現状のままでOKです)。

    Suggested change
    raise e # noqa: TRY201
    raise

    Copilot uses AI. Check for mistakes.
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Labels

    None yet

    Projects

    None yet

    Development

    Successfully merging this pull request may close these issues.

    2 participants