name: argparse-scaffolder description: 使用argparse生成基于Python的CLI应用程序,包含子解析器、类型转换器和标准库模式。创建轻量级Python CLI,无需外部依赖。 allowed-tools: Read, Write, Edit, Bash, Glob, Grep
Argparse 脚手架工具
使用Python标准库生成完整的argparse CLI应用程序,包含子解析器和最佳实践。
功能
- 生成基于Python的argparse CLI项目
- 为子命令创建子解析器层次结构
- 设置自定义类型转换器和操作
- 配置互斥参数组
- 为共享参数实现父解析器
- 设置标准的Python项目结构
使用场景
在以下情况下调用此技能:
- 仅使用Python标准库引导CLI
- 创建无需外部依赖的轻量级CLI
- 为命令层次结构设置子解析器
- 构建可在任何Python安装上运行的CLI
输入参数
| 参数 | 类型 | 必填 | 描述 |
|---|---|---|---|
| projectName | 字符串 | 是 | CLI项目名称(kebab-case格式) |
| description | 字符串 | 是 | CLI的简短描述 |
| commands | 数组 | 否 | 要搭建的命令列表 |
| pythonVersion | 字符串 | 否 | Python版本要求(默认:“>=3.8”) |
| useSubparsers | 布尔值 | 否 | 为命令使用子解析器(默认:true) |
命令结构
{
"commands": [
{
"name": "convert",
"description": "转换文件格式",
"arguments": [
{ "name": "input", "help": "输入文件路径" },
{ "name": "output", "help": "输出文件路径", "nargs": "?" }
],
"options": [
{ "flags": ["-f", "--format"], "choices": ["json", "yaml", "xml"] },
{ "flags": ["-v", "--verbose"], "action": "store_true" }
]
}
]
}
输出结构
<projectName>/
├── pyproject.toml
├── README.md
├── .gitignore
├── src/
│ └── <package_name>/
│ ├── __init__.py
│ ├── __main__.py # 入口点
│ ├── cli.py # Argparse设置
│ ├── commands/
│ │ ├── __init__.py
│ │ └── <command>.py # 命令处理器
│ ├── types/
│ │ ├── __init__.py
│ │ └── converters.py # 自定义类型转换器
│ └── utils/
│ ├── __init__.py
│ └── helpers.py # 辅助函数
└── tests/
├── __init__.py
└── test_<command>.py
生成的代码模式
主CLI入口(src/<package>/cli.py)
import argparse
import sys
from typing import Optional, Sequence
from .commands import convert, validate
def create_parser() -> argparse.ArgumentParser:
"""创建包含所有子命令的参数解析器。"""
parser = argparse.ArgumentParser(
prog='<projectName>',
description='<description>',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog='''
示例:
%(prog)s convert input.json output.yaml
%(prog)s validate config.yaml --strict
'''
)
parser.add_argument(
'-v', '--verbose',
action='store_true',
help='启用详细输出'
)
parser.add_argument(
'--version',
action='version',
version='%(prog)s 1.0.0'
)
# 创建子解析器
subparsers = parser.add_subparsers(
dest='command',
title='commands',
description='可用命令',
help='要运行的命令'
)
# 注册命令
convert.register_parser(subparsers)
validate.register_parser(subparsers)
return parser
def main(argv: Optional[Sequence[str]] = None) -> int:
"""主入口点。"""
parser = create_parser()
args = parser.parse_args(argv)
if args.command is None:
parser.print_help()
return 1
# 执行命令
return args.func(args)
if __name__ == '__main__':
sys.exit(main())
命令模板(src/<package>/commands/convert.py)
import argparse
from pathlib import Path
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from argparse import _SubParsersAction
def register_parser(subparsers: '_SubParsersAction[argparse.ArgumentParser]') -> None:
"""注册转换子解析器。"""
parser = subparsers.add_parser(
'convert',
help='转换文件格式',
description='在不同格式之间转换文件。',
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument(
'input',
type=Path,
help='输入文件路径'
)
parser.add_argument(
'output',
type=Path,
nargs='?',
help='输出文件路径(默认:标准输出)'
)
parser.add_argument(
'-f', '--format',
choices=['json', 'yaml', 'xml'],
default='json',
help='输出格式(默认:%(default)s)'
)
# 互斥参数组
group = parser.add_mutually_exclusive_group()
group.add_argument('--compact', action='store_true', help='紧凑输出')
group.add_argument('--pretty', action='store_true', help='美化打印')
parser.set_defaults(func=execute)
def execute(args: argparse.Namespace) -> int:
"""执行转换命令。"""
print(f"正在转换 {args.input} 到 {args.format}")
if args.output:
print(f"输出:{args.output}")
return 0
自定义类型转换器
import argparse
from pathlib import Path
def existing_file(value: str) -> Path:
"""现有文件路径的类型转换器。"""
path = Path(value)
if not path.exists():
raise argparse.ArgumentTypeError(f"文件未找到:{value}")
if not path.is_file():
raise argparse.ArgumentTypeError(f"不是文件:{value}")
return path
def port_number(value: str) -> int:
"""端口号的类型转换器。"""
try:
port = int(value)
except ValueError:
raise argparse.ArgumentTypeError(f"无效的端口号:{value}")
if not 1 <= port <= 65535:
raise argparse.ArgumentTypeError(f"端口必须在1-65535之间:{value}")
return port
依赖项
[project]
name = "<projectName>"
version = "1.0.0"
requires-python = ">=3.8"
dependencies = [] # 无外部依赖!
[project.optional-dependencies]
dev = [
"pytest>=7.0.0",
"pytest-cov>=4.0.0",
"mypy>=1.0.0",
]
[project.scripts]
<projectName> = "<package_name>.cli:main"
工作流程
- 验证输入 - 检查项目名称、命令结构
- 创建目录结构 - 设置Python项目布局
- 生成pyproject.toml - 配置项目元数据
- 创建CLI入口点 - 带有子解析器的Argparse设置
- 生成命令 - 单独的命令处理器
- 创建类型转换器 - 自定义参数类型
- 设置测试 - pytest测试结构
- 生成__main__.py - 包执行支持
应用的最佳实践
- 核心CLI零外部依赖
- 全程使用类型提示
- 使用自定义类型转换器进行验证
- 互斥参数组
- 共享参数的父解析器
- 适当的帮助文本和示例
参考资料
- argparse文档:https://docs.python.org/3/library/argparse.html
- argparse教程:https://docs.python.org/3/howto/argparse.html
- PEP 389 - argparse:https://peps.python.org/pep-0389/
目标流程
- cli-application-bootstrap
- argument-parser-setup
- cli-command-structure-design