#!/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())