有没有办法让 Python 静态分析器(例如,在 PyCharm 中,其他 IDE 中)在 argparse.Namespace
对象上获取 Typehints?示例:
parser = argparse.ArgumentParser()
parser.add_argument('--somearg')
parsed = parser.parse_args(['--somearg','someval']) # type: argparse.Namespace
the_arg = parsed.somearg # <- Pycharm complains that parsed object has no attribute 'somearg'
如果我删除内联注释中的类型声明,PyCharm 不会提示,但它也不会拾取无效属性。例如:
parser = argparse.ArgumentParser()
parser.add_argument('--somearg')
parsed = parser.parse_args(['--somearg','someval']) # no typehint
the_arg = parsed.somaerg # <- typo in attribute, but no complaint in PyCharm. Raises AttributeError when executed.
有什么想法吗?
更新
灵感来自 Austin's answer下面,我能找到的最简单的解决方案是使用 namedtuples
:
from collections import namedtuple
ArgNamespace = namedtuple('ArgNamespace', ['some_arg', 'another_arg'])
parser = argparse.ArgumentParser()
parser.add_argument('--some-arg')
parser.add_argument('--another-arg')
parsed = parser.parse_args(['--some-arg', 'val1', '--another-arg', 'val2']) # type: ArgNamespace
x = parsed.some_arg # good...
y = parsed.another_arg # still good...
z = parsed.aint_no_arg # Flagged by PyCharm!
虽然这令人满意,但我仍然不喜欢重复参数名称。如果参数列表显着增长,更新两个位置将是乏味的。理想的方法是以某种方式从 parser
对象中提取参数,如下所示:
parser = argparse.ArgumentParser()
parser.add_argument('--some-arg')
parser.add_argument('--another-arg')
MagicNamespace = parser.magically_extract_namespace()
parsed = parser.parse_args(['--some-arg', 'val1', '--another-arg', 'val2']) # type: MagicNamespace
我在 argparse
模块中找不到任何可以实现这一点的东西,我仍然不确定 any 静态分析工具是否聪明足以获得这些值,而不会使 IDE 陷入停顿。
仍在搜索中...
更新 2
根据 hpaulj 的评论,我能找到的最接近上述方法的“神奇地”提取已解析对象的属性的方法是从每个解析器中提取 dest
属性_action
s.:
parser = argparse.ArgumentParser()
parser.add_argument('--some-arg')
parser.add_argument('--another-arg')
MagicNamespace = namedtuple('MagicNamespace', [act.dest for act in parser._actions])
parsed = parser.parse_args(['--some-arg', 'val1', '--another-arg', 'val2']) # type: MagicNamespace
但这仍然不会导致在静态分析中标记属性错误。如果我在 parser.parse_args
调用中传递 namespace=MagicNamespace
也是如此。
最佳答案
Typed argument parser正是为此目的而制作的。它包装了 argparse
。您的示例实现为:
from tap import Tap
class ArgumentParser(Tap):
somearg: str
parsed = ArgumentParser().parse_args(['--somearg', 'someval'])
the_arg = parsed.somearg
它在 PyPI 上,可以通过以下方式安装:pip install typed-argument-parser
完全披露:我是这个库的创建者之一。
关于Python:argparse.Namespace 对象的类型提示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42279063/