python argparse - 在没有命令行的情况下传递值

Posted

技术标签:

【中文标题】python argparse - 在没有命令行的情况下传递值【英文标题】:python argparse - pass values WITHOUT command line 【发布时间】:2015-09-14 10:17:31 【问题描述】:

我想我对 python 的 argparse 的一些基本知识不了解。

我正在尝试将 Google YouTube API 用于 python 脚本,但我不明白如何在不使用命令行的情况下将值传递给脚本。

例如,here 是 API 的示例。 github 和其他地方的示例显示此示例是从命令行调用的,调用脚本时从命令行传递 argparse 值。

我不想使用命令行。我正在构建一个应用程序,它使用装饰器获取用户的登录凭据,当该用户想要上传到他们的 YouTube 帐户时,他们提交一个表单,然后调用这个脚本并将 argparse 值传递给它。

如何将值从另一个 python 脚本传递给 argparser(请参阅下面的 YouTube 上传 API 脚本中的部分代码)?

if __name__ == '__main__':
    argparser.add_argument("--file", required=True, help="Video file to upload")
    argparser.add_argument("--title", help="Video title", default="Test Title")
    argparser.add_argument("--description", help="Video description",
        default="Test Description")
    argparser.add_argument("--category", default="22",
        help="Numeric video category. " +
            "See https://developers.google.com/youtube/v3/docs/videoCategories/list")
    argparser.add_argument("--keywords", help="Video keywords, comma separated",
        default="")
    argparser.add_argument("--privacyStatus", choices=VALID_PRIVACY_STATUSES,
        default=VALID_PRIVACY_STATUSES[0], help="Video privacy status.")
    args = argparser.parse_args()

    if not os.path.exists(args.file):
        exit("Please specify a valid file using the --file= parameter.")

    youtube = get_authenticated_service(args)
    try:
        initialize_upload(youtube, args)
    except HttpError, e:
        print "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content)

编辑:根据请求,这是我使用标准方法初始化字典或使用 argparse 创建字典时遇到的 400 错误的回溯。我以为我得到这个是因为参数格式错误,但也许不是:

Traceback (most recent call last):
  File "C:\Program Files (x86)\Google\google_appengine\lib\webapp2-2.5.2\webapp2.py", line 1535, in __call__
    rv = self.handle_exception(request, response, e)
  File "C:\Program Files (x86)\Google\google_appengine\lib\webapp2-2.5.2\webapp2.py", line 1529, in __call__
    rv = self.router.dispatch(request, response)
  File "C:\Program Files (x86)\Google\google_appengine\lib\webapp2-2.5.2\webapp2.py", line 1278, in default_dispatcher
    return route.handler_adapter(request, response)
  File "C:\Program Files (x86)\Google\google_appengine\lib\webapp2-2.5.2\webapp2.py", line 1102, in __call__
    return handler.dispatch()
  File "C:\Program Files (x86)\Google\google_appengine\lib\webapp2-2.5.2\webapp2.py", line 572, in dispatch
    return self.handle_exception(e, self.app.debug)
  File "C:\Program Files (x86)\Google\google_appengine\lib\webapp2-2.5.2\webapp2.py", line 570, in dispatch
    return method(*args, **kwargs)
  File "C:\Users\...\testapp\oauth2client\appengine.py", line 796, in setup_oauth
    resp = method(request_handler, *args, **kwargs)
  File "C:\Users\...\testapp\testapp.py", line 116, in get
    resumable_upload(insert_request)
  File "C:\Users\...\testapp\testapp.py", line 183, in resumable_upload
    status, response = insert_request.next_chunk()
  File "C:\Users\...\testapp\oauth2client\util.py", line 129, in positional_wrapper
    return wrapped(*args, **kwargs)
  File "C:\Users\...\testapp\apiclient\http.py", line 874, in next_chunk
    return self._process_response(resp, content)
  File "C:\Users\...\testapp\apiclient\http.py", line 901, in _process_response
    raise HttpError(resp, content, uri=self.uri)
HttpError: <HttpError 400 when requesting https://www.googleapis.com/upload/youtube/v3/videos?alt=json&part=status%2Csnippet&uploadType=resumable returned "Bad Request">

【问题讨论】:

最简单的方法是重构代码,这样sys.argv被显式传递给使用argparse的函数来处理生成的list我>;这也使测试变得更加简单。参见例如github.com/textbook/py_wlc/blob/develop/py_wlc/data/… 这里只有一个大问题,如果你不会使用命令行,为什么需要解析命令行参数?您只是从谷歌网站复制粘贴示例而不了解代码本身。 正如 JL Peyret 所展示的,argparse 可以在不使用命令行的情况下发挥作用。虽然我是 python 新手,但我试图理解代码,这就是为什么我尝试了不同的字典创建方法。我想两者都有效。我感谢人们尝试帮助我更好地理解 argparse 方法。因为我使用任何一种方法都会收到 400 错误,所以我显然需要了解更多关于该 API 的知识,所以你说得对,我没有完全理解代码。我希望我最终会做更多的工作。感谢您花时间光临,Reishin。 主要问题是args 是一个具有属性的对象,而不是字典。我找到了你需要调用的API代码。 是的,我的示例中的 vars(args) 只是一种快速显示 args 内容的方法。不打算在其他地方使用。我 【参考方案1】:

这是否是最好的方法真的需要你自己去弄清楚。但是在没有命令行的情况下使用 argparse 很容易。我一直这样做是因为我有可以从命令行运行的批处理。或者也可以由其他代码调用 - 如前所述,这非常适合单元测试。例如,argparse 特别擅长默认参数。

从您的示例开始。

import argparse

argparser = argparse.ArgumentParser()
argparser.add_argument("--file", required=True, help="Video file to upload")
argparser.add_argument("--title", help="Video title", default="Test Title")
argparser.add_argument("--description", help="Video description",
    default="Test Description")
argparser.add_argument("--category", default="22",
    help="Numeric video category. " +
        "See https://developers.google.com/youtube/v3/docs/videoCategories/list")
argparser.add_argument("--keywords", help="Video keywords, comma separated",
    default="")
VALID_PRIVACY_STATUSES = ("private","public")
argparser.add_argument("--privacyStatus", choices=VALID_PRIVACY_STATUSES,
    default=VALID_PRIVACY_STATUSES[0], help="Video privacy status.")

#pass in any positional or required variables.. as strings in a list
#which corresponds to sys.argv[1:].  Not a string => arcane errors.
args = argparser.parse_args(["--file", "myfile.avi"])

#you can populate other optional parameters, not just positionals/required
#args = argparser.parse_args(["--file", "myfile.avi", "--title", "my title"])


print vars(args)

#modify them as you see fit, but no more validation is taking place
#so best to use parse_args.
args.privacyStatus = "some status not in choices - already parsed"
args.category = 42

print vars(args)

#proceed as before, the system doesn't care if it came from the command line or not
# youtube = get_authenticated_service(args)    

输出:

'category': '22', 'description': 'Test Description', 'title': 'Test Title', 'privacyStatus': 'private', 'file': 'myfile.avi', 'keywords': ''
'category': 42, 'description': 'Test Description', 'title': 'Test Title', 'privacyStatus': 'some status not in choices - already parsed', 'file': 'myfile.avi', 'keywords': ''

【讨论】:

这正是我所需要的。谢谢!当我尝试上传视频时,我仍然收到 400 错误,但我认为这是一个不同的问题 - 您将值传递给 argparse 的方法有效。 答案是一个例子,什么人不应该做,太棒了! 附注FWIW,我最近开始使用click,我发现以编程方式使用它更容易一些,尽管您仍然必须自己编写命令行 - 内省和使用standalone_mode=False 调用目标函数更容易导致它抛出一个正常的异常而不是SystemExit【参考方案2】:

使用您自己的字符串列表调用parse_args 是一种常见的argparse 测试方法。如果你不给parse_args这个列表,它使用sys.argv[1:]——即shell给出的字符串。 sys.argv[0] 是片段名称。

args = argparser.parse_args(['--foo','foovalue','barvalue'])

构造args 对象也很容易。

args = argparse.Namespace(foo='foovalue', bar='barvalue')

事实上,如果您从parse_args 调用中打印args,它应该看起来像这样。如文档中所述,Namespace 是一个简单对象,其值是属性。所以很容易构建自己的namespace 类。所有args 需要是在用作时返回适当值的东西:

x = args.foo
b = args.bar

同样如文档中所述,vars(args) 将此命名空间转换为字典。有些代码喜欢使用字典,但显然这些 youtube 函数需要Namespace(或等效项)。

get_authenticated_service(args)
initialize_upload(youtube, args)

https://docs.python.org/3/library/argparse.html#beyond-sys-argv

https://docs.python.org/3/library/argparse.html#the-namespace-object


https://developers.google.com/youtube/v3/guides/uploading_a_video?hl=id-ID

get_authenticated_serviceinitialize_upload 代码

def initialize_upload(youtube, options):
  tags = None
  if options.keywords:
    tags = options.keywords.split(",")

  body=dict(
    snippet=dict(
      title=options.title,
      description=options.description,
      tags=tags,
      categoryId=options.category
    ),
    status=dict(
      privacyStatus=options.privacyStatus
    )
  )
 ....

解析器中的argsoptions,它用作options.categoryoptions.title 等。您可以替换具有相同行为和必要属性的任何其他对象。

【讨论】:

这真的很有帮助,hpaulj。我需要阅读有关命名空间的文档。这可能会解决我更大的问题。 相当棘手(将args 注入它自己的命名空间)。谢谢!【参考方案3】:

如果您不想使用命令行,为什么要使用 argparse? Argparse 是为解析命令行参数而创建的模块,没有其他用途。您不能以其他方式将值传递给 argparse。

我认为您想要的是一个显示 html 表单的 Web 应用程序,该应用程序向某些服务器处理程序发出 POST 请求,该服务器处理程序会将值从表单传递到 api 调用连接到 youtube 并执行您的 python 代码。根本不需要 Argparse。您可以从表单中获取值并将其传递给您的 api 调用。

【讨论】:

从技术上讲,您是正确的。还有其他传递值的方法,我一直在尝试其中一些选项,但遇到了错误。也许这些错误与我使用的参数格式无关。谢谢! “您不能以其他方式将值传递给 argparse。” 这显然是错误的,并且有许多理由以编程方式填充 argparse,如所述的单元测试。如果 youtube api 代码需要一个 argparse 参数,如果你想使用它,你还需要找到一种方法来提供它。 argparse 是否是最佳方法由 OP 决定,不是吗? @tjv09 您可以更新您试图以其他方式做事的问题发布回溯。我很确定您不需要 argparse,而且它对您的目的毫无用处 Pawel,我编辑了问题以包含回溯。我尝试使用标准方法将参数传递给上传方法以创建您提到的字典,但我仍然收到错误 - 如果我使用 JL Peyret 的方法使用 argparse 传递值,我会得到相同的错误。我认为这可能是一个不同的问题 - 与参数格式无关。

以上是关于python argparse - 在没有命令行的情况下传递值的主要内容,如果未能解决你的问题,请参考以下文章

Python 命令行工具 argparse 模块使用详解

python argparse详解

Python argparse 列出已定义解析器的所有可能命令

在没有任何参数的情况下调用脚本时使用 Python argparse 显示帮助消息

Python Argparse,如何正确组织 ArgParse 代码

python argparse 带多于的参数问题