类似于下面这样一行命令:
python main.py module list -l INFO
它包含了:
- 执行器:
python
- 执行程序:
main.py
- 一个隐形的根参数解析器
- 一个子参数解析器:
module
- 子解析器的一个位置参数:
action="list"
- 子解析器的一个可选参数:
log_level="INFO"
首先声明一个可以良好换行的参数帮助文档,默认的好像不支持:
from argparse import HelpFormatter
class SmartFormatter(HelpFormatter):
def _split_lines(self, text: str, width: int) -> list[str]:
return [s.strip(' \n') for s in text.strip(' \n').split('\n')]
然后扩展一下默认的解析器:
from argparse import ArgumentParser
from typing import Callable
class ExArgumentParser(ArgumentParser):
def __init__(self, formatter_class=SmartFormatter, **kwargs):
super().__init__(formatter_class=formatter_class, **kwargs)
self.__subparsers = None
@property
def subparsers(self):
if self._subparsers is None:
self._subparsers = self.add_subparsers()
return self._subparsers
def set_callback(self, callback: Callable):
"""Set callback function for self parser of its subparsers."""
levels = 'DEBUG|INFO|WARNING|ERROR|CRITICAL'
self.add_argument('-l', '--log-level', choices=levels.split('|'), default='INFO', metavar=levels, help="set logging level")
self.set_defaults(callback=callback)
def run(self):
"""Run callback function."""
args = self.parse_args()
log_level: str = args.log_level
callback: Callable = args.callback
logging.getLogger().setLevel(log_level)
callback(args)
def get_subparser(self, *args, **kwargs):
return self.subparsers.add_parser(*args, **kwargs)
这个 ExArgumentParser 新增了一下功能:
- 默认使用 SmartFormatter 格式化帮助文档,会被子解析器继承
- 添加了一个设置回调函数的方法
set_callback
,为子解析器设置回调函数的同时添加一个日志等级参数 - 添加了一个解析参数并执行回调函数的方法
run
- 添加了一个创建子解析器的方法
get_subparser
然后就可以进行参数解析了:
# 根解析器
parser = ExArgumentParser()
# 子解析器
pa = parser.get_subparser('module', ...)
# 子解析器的参数
pa.add_argument('action', choices=['list'], ...)
# 子解析器的回调
pa.set_callback(some_callback_fn)
# 运行解析,调用回调
parser.run()
如果一个子解析器有多个 action,可以将他们封装为类的静态方法:
# 根据 action 的值自动执行对应静态方法
class BaseHandler(object):
@classmethod
def run(cls, args):
getattr(cls, args.action)(args)
# 一个解析器 module 拥有多个 action:create update delete list
class ModuleHandler(BaseHandler):
@staticmethod
def create(args): ...
@staticmethod
def update(args): ...
@staticmethod
def delete(args): ...
@staticmethod
def list(args): ...
ExArgumentParser 的方法需要修改一下:
class ExArgumentParser(ArgumentParser):
def set_callback(self, callback: Callable = None, Callback: BaseHandler = None):
"""Set callback function for self parser of its subparsers."""
levels = 'DEBUG|INFO|WARNING|ERROR|CRITICAL'
self.add_argument('-l', '--log-level', choices=levels.split('|'), default='INFO', metavar=levels, help="set logging level")
if callback is not None:
self.set_defaults(callback=callback, Callback=None)
elif Callback is not None:
self.set_defaults(callback=None, Callback=Callback)
else:
raise Exception('`Callback` and `callback` cannot be both `None`.')
def run(self):
"""Run callback function."""
args = self.parse_args()
log_level: str = args.log_level
logging.getLogger().setLevel(log_level)
if args.callback is not None:
callback: Callable = args.callback
callback(args)
else:
Callback: BaseHandler = args.Callback
Callback.run(args)
评论区