从单元测试调用时 argparse 失败 [英] argparse fails when called from unittest test

查看:32
本文介绍了从单元测试调用时 argparse 失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在一个文件中(比如 parser.py)我有:

In a file (say parser.py) I have:

import argparse

def parse_cmdline(cmdline=None):
    parser = argparse.ArgumentParser()
    parser.add_argument('--first-param',help="Does foo.")
    parser.add_argument('--second-param',help="Does bar.")

    if cmdline is not None:
        args = parser.parse_args(cmdline)
    else:
        args = parser.parse_args()

    return vars(args)

if __name__=='__main__':
    print parse_cmdline()

果然,当从命令行调用时,它可以正常工作,并且几乎可以满足我的期望:

Sure enough, when called from the command line it works and give me pretty much what I expect:

$ ./parser.py --first-param 123 --second-param 456
{'first_param': '123', 'second_param': '456'}

但是我想unittest它,因此我写了一个test_parser.py文件:

But then I want to unittest it, thus I write a test_parser.py file:

import unittest
from parser import parse_cmdline

class TestParser(unittest.TestCase):
    def test_parse_cmdline(self):
        parsed = parse_cmdline("--first-param 123 --second-param 456")

        self.assertEqual(parsed['first_param'],'123')
        self.assertEqual(parsed['second_param'],'456')

if __name__ == '__main__':
    unittest.main()

然后我收到以下错误:

usage: test_parser.py [-h] [--first-param FIRST_PARAM]
                      [--second-param SECOND_PARAM]
test_parser.py: error: unrecognized arguments: - - f i r s t - p a r a m   1 2 3   - - s e c o n d - p a r a m   4 5 6
E
======================================================================
ERROR: test_parse_cmdline (__main__.TestParser)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "./test_parser.py", line 8, in test_parse_cmdline
    parsed = parse_cmdline("--first-param 123 --second-param 456")
  File "/home/renan/test_argparse/parser.py", line 12, in parse_cmdline
    args = parser.parse_args(cmdline)
  File "/usr/lib/python2.7/argparse.py", line 1691, in parse_args
    self.error(msg % ' '.join(argv))
  File "/usr/lib/python2.7/argparse.py", line 2361, in error
    self.exit(2, _('%s: error: %s\n') % (self.prog, message))
  File "/usr/lib/python2.7/argparse.py", line 2349, in exit
    _sys.exit(status)
SystemExit: 2

----------------------------------------------------------------------
Ran 1 test in 0.004s

FAILED (errors=1)

可以看出,我指定的命令行(--first-param 123 --second-param 456)变成了- - f i r s t - p a r a m 1 2 3 - - s e c o n d - p a r a m 4 5 6(每个字符用空格隔开).

As can be seen, the command line I specified (--first-param 123 --second-param 456) became - - f i r s t - p a r a m 1 2 3 - - s e c o n d - p a r a m 4 5 6 (each character is separated by a space).

我不明白为什么:我做错了什么?

I don't understand why: what am I doing wrong?

推荐答案

argparse 需要一个参数向量"——即一个单独参数的列表——而不是命令行"字符串.

argparse wants an "argument vector"—that is, a list of separate arguments—not a "command line" string.

而仅仅调用 split 并不能解决问题.例如,这个来自 shell 的命令行:

And just calling split won't solve things. For example, this command line from the shell:

python script.py --first-param '123 456' --second-param 789

... 会正确地给你 123 456789,但是这行代码:

… will correctly give you 123 456 and 789, but this line of code:

parse_cmdline("--first-param '123 456' --second-param 789")

不会;它会给你 '123789,还有一个它不知道如何处理的额外的 456'.

will not; it will give you '123 and 789, with an extra 456' that it doesn't know how to deal with.

事实上,即使这样也是错误的:

In fact, even this is wrong:

parse_cmdline("--first-param '123' --second-param 789")

... 因为你会得到 '123' 而不是 123.

… because you'll get '123' instead of 123.

有两种方法可以解决这个问题.

There are two ways to deal with this.

首先,如果您知道要传递的内容,则可以首先将其作为列表而不是字符串传递,而且您无需担心繁琐的引用和拆分细节:

First, if you know what you're trying to pass, you can just pass it as a list instead of a string in the first place, and you don't need to worry about fiddly quoting and splitting details:

parse_cmdline(["--first-param", "123 456", "--second-param", "789"])

或者,如果您不确切知道要传递什么,只知道它在 shell 上的样子,则可以使用 shlex:

Alternatively, if you don't know exactly what you're trying to pass, you just know what it looks like on the shell, you can use shlex:

if cmdline is not None:
    args = parser.parse_args(shlex.split(cmdline))

... 现在 Python 会以与标准 Unix shell 相同的方式拆分您的命令行,将 123 456 作为单个参数.

… and now Python will split your command line the same way as a standard Unix shell, getting the 123 456 as a single parameter.

这篇关于从单元测试调用时 argparse 失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆