使用 argparse 获取选定的子命令

发布于 2024-10-10 06:47:51 字数 535 浏览 0 评论 0原文

当我将子命令与 python argparse 一起使用时,我可以获得所选的参数。

parser = argparse.ArgumentParser()
parser.add_argument('-g', '--global')
subparsers = parser.add_subparsers()   
foo_parser = subparsers.add_parser('foo')
foo_parser.add_argument('-c', '--count')
bar_parser = subparsers.add_parser('bar')
args = parser.parse_args(['-g', 'xyz', 'foo', '--count', '42'])
# args => Namespace(global='xyz', count='42')

因此 args 不包含 'foo'。由于可能存在全局参数,仅编写 sys.argv[1] 是行不通的。我怎样才能获得子命令本身?

When I use subcommands with python argparse, I can get the selected arguments.

parser = argparse.ArgumentParser()
parser.add_argument('-g', '--global')
subparsers = parser.add_subparsers()   
foo_parser = subparsers.add_parser('foo')
foo_parser.add_argument('-c', '--count')
bar_parser = subparsers.add_parser('bar')
args = parser.parse_args(['-g', 'xyz', 'foo', '--count', '42'])
# args => Namespace(global='xyz', count='42')

So args doesn't contain 'foo'. Simply writing sys.argv[1] doesn't work because of the possible global args. How can I get the subcommand itself?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

黯然 2024-10-17 06:47:51

关于 argparse 子命令的 Python 文档 的最底部解释了如何执行此操作:

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('-g', '--global')
>>> subparsers = parser.add_subparsers(dest="subparser_name") # this line changed
>>> foo_parser = subparsers.add_parser('foo')
>>> foo_parser.add_argument('-c', '--count')
>>> bar_parser = subparsers.add_parser('bar')
>>> args = parser.parse_args(['-g', 'xyz', 'foo', '--count', '42'])
>>> args
Namespace(count='42', global='xyz', subparser_name='foo')

您还可以使用我找到的示例上方引用的 set_defaults() 方法。

The very bottom of the Python docs on argparse sub-commands explains how to do this:

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('-g', '--global')
>>> subparsers = parser.add_subparsers(dest="subparser_name") # this line changed
>>> foo_parser = subparsers.add_parser('foo')
>>> foo_parser.add_argument('-c', '--count')
>>> bar_parser = subparsers.add_parser('bar')
>>> args = parser.parse_args(['-g', 'xyz', 'foo', '--count', '42'])
>>> args
Namespace(count='42', global='xyz', subparser_name='foo')

You can also use the set_defaults() method referenced just above the example I found.

匿名的好友 2024-10-17 06:47:51

ArgumentParser.add_subparsersdest 形式参数描述为:

dest - 将存储子命令名称的属性名称;默认情况下None并且不存储任何值

在下面使用子解析器的简单任务函数布局的示例中,选定的子解析器位于parser.parse_args().subparser中。

import argparse


def task_a(alpha):
    print('task a', alpha)


def task_b(beta, gamma):
    print('task b', beta, gamma)


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    subparsers = parser.add_subparsers(dest='subparser')

    parser_a = subparsers.add_parser('task_a')
    parser_a.add_argument(
        '-a', '--alpha', dest='alpha', help='Alpha description')

    parser_b = subparsers.add_parser('task_b')
    parser_b.add_argument(
        '-b', '--beta', dest='beta', help='Beta description')
    parser_b.add_argument(
        '-g', '--gamma', dest='gamma', default=42, help='Gamma description')

    kwargs = vars(parser.parse_args())
    globals()[kwargs.pop('subparser')](**kwargs)

ArgumentParser.add_subparsers has dest formal argument described as:

dest - name of the attribute under which sub-command name will be stored; by default None and no value is stored

In the example below of a simple task function layout using subparsers, the selected subparser is in parser.parse_args().subparser.

import argparse


def task_a(alpha):
    print('task a', alpha)


def task_b(beta, gamma):
    print('task b', beta, gamma)


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    subparsers = parser.add_subparsers(dest='subparser')

    parser_a = subparsers.add_parser('task_a')
    parser_a.add_argument(
        '-a', '--alpha', dest='alpha', help='Alpha description')

    parser_b = subparsers.add_parser('task_b')
    parser_b.add_argument(
        '-b', '--beta', dest='beta', help='Beta description')
    parser_b.add_argument(
        '-g', '--gamma', dest='gamma', default=42, help='Gamma description')

    kwargs = vars(parser.parse_args())
    globals()[kwargs.pop('subparser')](**kwargs)
回眸一遍 2024-10-17 06:47:51

只是想发布这个答案,因为这在我最近的一些工作中非常方便。此方法使用装饰器(尽管不与传统的 @ 语法一起使用),并且如果推荐的 set_defaults 已与子解析器一起使用,则特别方便。

import argparse
from functools import wraps
import sys

def foo(subparser):
    subparser.error('err')

def bar(subparser):
    subparser.error('err')

def map_subparser_to_func(func, subparser):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return func(subparser, *args, **kwargs)
    return wrapper

parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()

foo_parser = subparsers.add_parser('foo')
foo_parser.set_defaults(func = map_subparser_to_func(foo, foo_parser))

bar_parser = subparsers.add_parser('bar')
bar_parser.set_defaults(func = map_subparser_to_func(bar, bar_parser))

args = parser.parse_args(sys.argv[1:])
args.func()

可以修改map_subparser_to_func函数,将子解析器设置为wrapper函数内部的某个类属性或全局变量,而不是直接传递它,也可以将其重新设计为传统的装饰器对于功能,尽管这需要添加另一层。

这样就可以直接引用该对象。

Just wanted to post this answer as this came in very handy in some of my recent work. This method makes use of decorators (although not used with conventional @ syntax) and comes in especially handy if the recommended set_defaults is already being used with subparsers.

import argparse
from functools import wraps
import sys

def foo(subparser):
    subparser.error('err')

def bar(subparser):
    subparser.error('err')

def map_subparser_to_func(func, subparser):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return func(subparser, *args, **kwargs)
    return wrapper

parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()

foo_parser = subparsers.add_parser('foo')
foo_parser.set_defaults(func = map_subparser_to_func(foo, foo_parser))

bar_parser = subparsers.add_parser('bar')
bar_parser.set_defaults(func = map_subparser_to_func(bar, bar_parser))

args = parser.parse_args(sys.argv[1:])
args.func()

The map_subparser_to_func function can be modified to set the subparser to some class attribute or global variable inside of the wrapper function instead of passing it directly and can also be reworked to a conventional decorator for the functions, although that would require adding another layer.

This way there is a direct reference to the object.

画骨成沙 2024-10-17 06:47:51

我有嵌套的子解析器并想要获得选定的
subparser 对象,以便我可以在特殊情况下 subparser.error(..)
其中 parse_known_args() 具有无效的未知参数。

我想出了这个递归来解决它。它可能只覆盖
我的子解析器与子解析器嵌套的具体情况
他们每个人都使用明确的dest。但它有一个优点
它不需要使用 set_defaults 并且它得到
实际的子解析器对象,而不仅仅是它的名称。

def get_selected_subparser(parser, args):
    for action in parser._actions:
        if not isinstance(action, argparse._SubParsersAction): continue
        choice = getattr(args, action.dest)
        if choice is None:
            return None
        else:
            subparser = action.choices[choice]
            return get_selected_subparser(subparser, args) or subparser
    else:
        return None

现在我可以这样做来打印所选子解析器的使用信息:

parser = argparse.ArgumentParser( ... )  
#  ... definition of parser goes here
args, remainder = parser.parse_known_args()
if remainder_is_invalid():
    subparser = get_selected_subparser(parser, args)
    subparser.error("unrecognized arguments: {}".format(" ".join(remainder)))

I have nested subparsers and wanted to get the selected
subparser object so I can subparser.error(..) on special cases
where parse_known_args() has invalid unknown args.

I came up with this recursion to solve it. It might only cover
my specific case of subparsers nested with subparsers with
each of them using an explicit dest. But it has the advantage
that it doesn't require using set_defaults and that it gets
the actual subparser object, not just the name of it.

def get_selected_subparser(parser, args):
    for action in parser._actions:
        if not isinstance(action, argparse._SubParsersAction): continue
        choice = getattr(args, action.dest)
        if choice is None:
            return None
        else:
            subparser = action.choices[choice]
            return get_selected_subparser(subparser, args) or subparser
    else:
        return None

Now I can do this to print the usage info of the selected subparser:

parser = argparse.ArgumentParser( ... )  
#  ... definition of parser goes here
args, remainder = parser.parse_known_args()
if remainder_is_invalid():
    subparser = get_selected_subparser(parser, args)
    subparser.error("unrecognized arguments: {}".format(" ".join(remainder)))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文