【问题标题】:How to specify argparse options from an external file?如何从外部文件中指定 argparse 选项?
【发布时间】:2021-10-18 15:12:18
【问题描述】:

我正在使用 argparse 指定一些参数,如下所示:

my_parser = argparse.ArgumentParser()
my_parser.add_argument("--script_path", nargs='?', type=str, const='', default='', help="Path of the script to pull.")
my_parser.add_argument("--script", nargs='?', type=str, const='', default='', help="Name of the script to get pulled, without script extension.")
my_parser.add_argument("--project", nargs='?', type=str, const='', default='', help="Project.")
my_args = my_parser.parse_args()
my_script_path = my_args.script_path
my_script = my_args.script
my_project = my_args.project

现在我正在尝试做同样的事情,而是通过我将加载的 .json 文件定义上述参数。我选择 .json 是因为它看起来不错,请随时提出更好的建议。

我尝试过的是有一个这样的 .json 文件:

[
{
    "name_or_flags": ["-sp", "--script_path"],
    "nargs": "?",
    "const": "",
    "default": "",
    "type": "str",
    "help": "The absolute path of the script to run."
},
...
]

加载文件后,我在下面尝试并失败了:

my_parser.add_argument(<combination of all keys, values from .json as a dictionary>)

my_parser.add_argument(<*unnamed_tup, **named_dict>) 
    #unnamed tuple since name_or_flags isn't supposed to be used
    #unnamed tuple is only made from name_or_flags

不管我做什么都行不通。

有没有人做过类似的事情?

我不希望通过外部文件添加值,例如:Using Argparse and Json together

只是为了定义参数。

谢谢!

【问题讨论】:

  • 由于您只为您的 add_argument 代码提供了伪代码,因此您需要指定您收到的错误消息,可能会出现很多错误

标签: python json python-3.x argparse


【解决方案1】:

这是从文件中执行此操作的方式:

import argparse

jdata = [
    {
        "args": ["--script_path"],
        "kwargs": {
            "nargs": "?",
            "const": "",
            "default": "",
            "type": "str",
            "help": "The absolute path of the script to run.",
        },
    } ]

my_parser = argparse.ArgumentParser()

for i in jdata:
    i["kwargs"]["type"] = eval(i["kwargs"]["type"])
    my_parser.add_argument(*tuple(i["args"]), **i["kwargs"])

my_args = my_parser.parse_args() my_script_path = my_args.script_path

print(my_script_path)

注意:来自 JSON 文件的某些数据需要转换,例如类型需要转换为 Python 类型,然后才能传递给方法。

【讨论】:

【解决方案2】:

您需要pop("name_or_flags"),注意始终提供一个列表;此外,您需要排除type,因为它会引发错误(作为字符串而不是类或函数)。

import argparse
import json

args = json.loads("""
[{
    "name_or_flags": "-sp", "--script_path"],
    "nargs": "?",
    "const": "",
    "default": "",
    "type": "str",
    "help": "The absolute path of the script to run."
}]
""")
parser = argparse.ArgumentParser()

for arg in args:
    arg.pop("type", None)  # will raise ValueError: 'str' is not callable
    parser.add_argument(*arg.pop("name_or_flags"), **arg)

# If the type is important to keep, you can always create a dictionary to map a string to a value, that is a builtin class.
mapping = dict(str=str, bool=bool, int=int)  # this will map strings to classes
for arg in args:
    thetype_str = arg.pop("type", "str")
    arg["type"] = mapping.get(thetype_str, str)  # if missing or wrong, will give plain string
    parser.add_argument(*arg.pop("name_or_flags"), **arg)

【讨论】:

  • 删除类型会导致 arg 解析器验证的那部分不起作用。
  • 为什么它不应该工作?您始终可以通过eval("str") 获得str 类,但这是一个非常糟糕的主意 - 默认情况下,argparse 仅使用字符串作为解析的参数。
  • 因为如果他有 "type": "bool" 而你忽略它,它会错误地将其转换为字符串,所以仅仅忽略类型可能不是他想要的。
  • 你说得对,我已经添加了一个安全的方法来做到这一点。
【解决方案3】:

希望这会有所帮助(您应该从我的 cmets 中找到自己的方法)。

import argparse
import json
from pydoc import locate

# Load the json
f = open("args.json")
args = json.load(f)
# Pre-processing that converts "str" -> <class "str">, "int" -> <class "int">, etc.
for arg in args:
    if "type" in arg.keys():
        arg["type"] = locate(arg["type"])

my_parser = argparse.ArgumentParser()

# Normal method of arg-parse for comparision
my_parser.add_argument(
    "-sp-normal",
    "--script-path-normal",
    nargs="?",
    const="",
    default="",
    type=str,
    help="The absolute path of the script to run.",
)
# Loading from the JSON
for arg in args:
    my_parser.add_argument(*arg.pop("name_or_flags"), **arg)

# Load the args
my_args = my_parser.parse_args()

# Check
script_path = my_args.script_path
script_path_1 = my_args.script_path_1
script_path_normal = my_args.script_path_normal
print(script_path, script_path_1, script_path_normal)

我使用的 JSON:

[
  {
    "name_or_flags": [
      "-sp",
      "--script-path"
    ],
    "nargs": "?",
    "const": "",
    "default": "",
    "type": "str",
    "help": "The absolute path of the script to run."
  },
  {
    "name_or_flags": [
      "-sp-1",
      "--script-path-1"
    ],
    "nargs": "?",
    "const": "",
    "default": "",
    "type": "str",
    "help": "The absolute path of the script to run."
  }
]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多