#!/usr/bin/env python # -*- coding:utf-8 -*- r"""" コマンドラインプログラムの雛形 最小 各コマンドの実装はargparse.Actionの派生クラスで実装できるが コード量が多くなるのと単純なもの以外では面倒くさい感じなので ここでは使用しない。 """ # from typing import override from abc import ABC, abstractmethod from argparse import( ArgumentParser, _SubParsersAction, # type: ignore RawDescriptionHelpFormatter, Namespace, ) import locale import pathlib import sys from typing import Any, TypeAlias, TYPE_CHECKING __version__ = "0.0.1" if TYPE_CHECKING: SubParserType: TypeAlias = _SubParsersAction[ArgumentParser] else: SubParserType: TypeAlias = Any class AbstractSubCommand(ABC): r"""サブコマンドの抽象基底クラス""" @classmethod def set_argument(cls, parser_: SubParserType) -> None: r"""パーサーに登録""" parser = cls._set_argument_impl(parser_) parser.set_defaults(func=cls._run) @classmethod @abstractmethod def _set_argument_impl(cls, parser_: SubParserType) -> ArgumentParser: r"""パーサーに登録 実装""" raise NotImplementedError() @classmethod def _run(cls, args: Namespace) -> int: r"""処理内容""" return cls._run_impl(args) @classmethod @abstractmethod def _run_impl(cls, args: Namespace) -> int: r"""処理内容 実装""" raise NotImplementedError() class CatCommand(AbstractSubCommand): r"""サブコマンド cat """ # @override @classmethod def _set_argument_impl(cls, parser_: SubParserType) -> ArgumentParser: r"""パーサーに登録 実装""" parser = parser_.add_parser("cat", help="ファイルを出力する") parser.add_argument("inputfile", help="対象ファイル") parser.add_argument("--encoding", default="utf-8") return parser # @override @classmethod def _run_impl(cls, args: Namespace) -> int: r"""処理内容 実装""" path = pathlib.Path(args.inputfile) if not path.exists(): print(f"ファイルが存在しません。'{args.inputfile}'" , file=sys.stderr) return 1 if not path.is_file(): print(f"ファイルを指定して下さい。'{args.inputfile}'" , file=sys.stderr) return 1 text = path.read_text(encoding=args.encoding) print(text) return 0 def set_argsparse() -> ArgumentParser: r"""パーサーの起動とメインコマンドの登録""" description ="""説明 1行目 2行目 3行目""" argparser = ArgumentParser( prog="コマンドプログラムの雛形", description=description, formatter_class=RawDescriptionHelpFormatter, add_help=True, allow_abbrev=False) argparser.add_argument( "-v", "--version", action="version", version=f"%(prog)s {__version__}") argparser.add_argument( "--env", action="store_true", help="実行環境の情報を表示する") return argparser def set_subcommand(parser_: ArgumentParser): r"""サブコマンドを登録""" commands: list[type[AbstractSubCommand]] = [ CatCommand, ] subparser = parser_.add_subparsers(title="sub commands") for cmd in commands: cmd.set_argument(subparser) def main_command_env() -> int: r"""実行環境の出力""" print("{} {} {}.{}.{} {} {}".format( sys.platform, sys.implementation.cache_tag, *sys.implementation.version)) print(f" sys.getrecursionlimit(): {sys.getrecursionlimit()}") print(f" sys.stdout.encoding: {sys.stdout.encoding}") print(f" sys.getdefaultencoding(): {sys.getdefaultencoding()}") print(f" sys.getfilesystemencoding(): {sys.getfilesystemencoding()}") print(f" locale.getpreferredencoding(): {locale.getpreferredencoding()}") print(" sys.path: [\n {}]".format("\n ".join(sys.path))) return 0 def main_command(args: Namespace) -> tuple[int, bool]: r""" メインコマンドがあるならここに処理を書く """ ret: int = 0 is_continue: bool = True if args.env: ret = main_command_env() is_continue = False return (ret, is_continue) def main() -> int: r"""メイン処理""" argparser = set_argsparse() set_subcommand(argparser) try: args = argparser.parse_args() except SystemExit: return 1 ret, is_continue = main_command(args) if not is_continue: return ret if hasattr(args, 'func'): return args.func(args) argparser.print_help() return 0 if __name__ == "__main__": sys.exit(main())
[Python 3.10] コマンドライン サブコマンド 雛形
ラベル:
Python 3.10