mxivideo/python_core/utils/commander/parser.py

104 lines
3.7 KiB
Python

#!/usr/bin/env python3
"""
参数解析器
"""
import sys
from typing import List, Dict, Any, Tuple
from .types import CommandConfig
from ..logger import logger
class ArgumentParser:
"""命令行参数解析器"""
def __init__(self, commands: Dict[str, CommandConfig]):
self.commands = commands
def parse_arguments(self, args: List[str]) -> Tuple[str, Dict[str, Any]]:
"""
解析命令行参数
Args:
args: 命令行参数列表
Returns:
(command, parsed_args) 元组
"""
if len(args) < 1:
raise ValueError("No command provided")
command = args[0]
if command not in self.commands:
raise ValueError(f"Unknown command: {command}")
command_config = self.commands[command]
# 解析参数
parsed_args = {}
remaining_args = args[1:]
# 处理必需参数
if len(remaining_args) < len(command_config.required_args):
missing_args = command_config.required_args[len(remaining_args):]
raise ValueError(f"Missing required arguments: {missing_args}")
# 设置必需参数
for i, arg_name in enumerate(command_config.required_args):
parsed_args[arg_name] = remaining_args[i]
# 处理可选参数
optional_start = len(command_config.required_args)
i = optional_start
while i < len(remaining_args):
arg = remaining_args[i]
if arg.startswith('--'):
arg_name = arg[2:]
if arg_name in command_config.optional_args:
arg_config = command_config.optional_args[arg_name]
# 检查是否需要值
if arg_config.get('type') == bool:
parsed_args[arg_name] = True
i += 1
elif i + 1 < len(remaining_args) and not remaining_args[i + 1].startswith('--'):
value_str = remaining_args[i + 1]
# 类型转换
try:
arg_type = arg_config.get('type', str)
if arg_type == bool:
value = value_str.lower() in ('true', '1', 'yes', 'on')
else:
value = arg_type(value_str)
# 检查选择范围
choices = arg_config.get('choices')
if choices and value not in choices:
raise ValueError(f"Invalid value for {arg_name}: {value}. Choices: {choices}")
parsed_args[arg_name] = value
i += 2
except (ValueError, TypeError) as e:
raise ValueError(f"Invalid value for {arg_name}: {value_str}. {e}")
else:
raise ValueError(f"Missing value for argument: {arg_name}")
else:
logger.warning(f"Unknown optional argument: {arg_name}")
i += 1
else:
i += 1
# 设置默认值
for arg_name, arg_config in command_config.optional_args.items():
if arg_name not in parsed_args:
default_value = arg_config.get('default')
if default_value is not None:
parsed_args[arg_name] = default_value
return command, parsed_args