【问题标题】:argparse subparser implied by other parameters其他参数隐含的 argparse 子解析器
【发布时间】:2023-10-13 03:15:01
【问题描述】:

定义子解析器的通常方法是做

master_parser = argparse.ArgumentParser()
subparsers = master_parser.add_subparsers()
parser = subparsers.add_parser('sub')
parser.add_argument('--subopt')

子解析器会被调用

command sub --subopt

我正在实现一个调用多个转换器的包。如果我使用通常的子解析器方法,我将不得不这样做

convert ext1_to_ext2 file.ext1 file.ext2 --args

这既重复又容易出错,因为用户可能会调用

convert ext1_to_ext3 file.ext1 file.ext2 --args

我更希望从主解析器自动确定子解析器,以便用户可以使用命令

convert file.ext1 file.ext2  EXTRA

argparse 将从file.ext1file.ext2 中确定子解析器ext1_to_ext2,并调用子解析器ext1_to_ext2 来解析EXTRA。当然EXTRA 这里是子解析器特定的。

我尝试为每个转换器 (add_argument_group) 使用参数组,但参数组中的参数不能重叠,并且我得到了来自所有解析器的组合参数的混乱列表,因此使用子解析器似乎是要走的路。

我尝试将parse_known_args 与两个位置参数一起使用,确定并使用适当的子解析器来解析剩余的参数,但很难从帮助消息中为用户提供转换器列表及其参数。

有没有办法做到这一点?

【问题讨论】:

  • 你能用parse_known_args吗?这将让您解析参数的第一部分,自己评估正确的子解析器,然后将剩余的参数传递给正确的子解析器。
  • 这是我现在正在采取的方法,但我正在努力为用户提供帮助信息。看来我需要劫持convert file.ext1 file.ext2 -h 以打印来自另一个解析器的帮助消息,但我仍然无法列出来自convert -h 的所有可用转换器(也许epilog 可以工作)。
  • 你要求的那种逻辑对于argparse来说是不合理的。要么直接解析sys.argv,要么通过argparse获取简单字符串的值,然后推断你应该采取什么行动。

标签: python argparse subparsers


【解决方案1】:

推断要使用的子解析器很棘手,因为当您检查以下每个参数时,它需要重新实现argparse 本身使用的许多逻辑。

一个更简单的方法是使用 subparser 命令,它随后允许您“类型检查”以下参数以确保它们使用正确的参数。例如

# This allows a file name ending with any of the given extensions,
# or allows "file.1" in place of "file.1.jpg"
def jpeg_file(s):
    for ext in ("jpg", "jpeg"):
        if s.endswith(ext) or os.path.exists("%s.%s" % (s, ext)):
            return s
    raise argparse.ArgumentTypeError()

def tiff_file(s):
    # similar to jpeg_file

master_parser = argparse.ArgumentParser()
subparsers = master_parser.add_subparsers()
jpg_to_tiff_parser = subparsers.add_parser('sub')
jpg_to_tiff_parser = parse.add_argument('jpg', type=jpg_file)
jpg_to_tiff_parser = parse.add_argument('tiff', type=tiff_file)

【讨论】:

  • 但是命令行仍然是convert sub file.jpg file.tiff。我刚刚有了一个绝妙的(?)想法,劫持sys.argv 怎么样?我可以检查sys.argv[1]sys.argv[2],在sys.argv[1] 之前插入适当的子解析器名称,然后使用所有子解析器调用master_parser。不过,-h 消息会有点偏离。
  • 虽然前两个位置参数不一定是 sys.argv[1]sys.argv[2]
【解决方案2】:

在我看来,这可以让您获得更多控制权。它一直在朝着你的要求前进。只需根据您的需要添加文件扩展名检查。

#prog.py
topParser=argparse.ArgumentParser()

subParsers = topParser.add_subparsers(
    title='SubCommands', 
    description='Use "prog.py <subCommand> (-h | --help)" to learn more about each subcommand', 
    help='I can do stuff')

subParser1 = subParsers.add_parser('use1', help="Use1 does one thing")
subParser2 = subParsers.add_parser('use2', help='Use2 does another thing')

subParser1.add_argument(
    '-f','--first-arg-for-use1',
    help="A text file",
    required=True
    )

subParser1.add_argument(
    '-s','--second-arg-for-use1',
    help="An encoding",
    required=True
    )

subParser2.add_argument(
    '-f','--first-arg-for-use2',
    help="An image format",
    required=True
    )

args = topParser.parse_args()
print(args)

如果没有别的,它显示了如何处理不同层的帮助文本。

【讨论】: