侧边栏壁纸
  • 累计撰写 218 篇文章
  • 累计创建 59 个标签
  • 累计收到 5 条评论

一个带子解析器和多个action的参数解析器

barwe
2022-07-15 / 0 评论 / 0 点赞 / 564 阅读 / 2,930 字
温馨提示:
本文最后更新于 2022-07-15,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

类似于下面这样一行命令:

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)
0

评论区