有没有办法指示argparse(Python 2.7)从sys.argv中删除找到的参数?

时间:2016-03-01 20:53:09

标签: python python-2.7 argparse

我完全处于开发过程的中游,因为它正在变成一个相当重要的Python 2.7项目。现在,我将所有unittest个类集中在他们自己的模块tests.py中,它们大约有3300行。这是疯狂的大,不可能导航,所有围绕不良做法,等等。

所以,我目前的任务是将其重构为子模块。作为这种重构的一部分,我希望能够轻松地从命令行运行一部分测试。例如:

$ python tests.py --all                         <--- runs *all* tests
$ python tests.py --utils_base                  <--- runs all tests on .utils
$ python tests.py --utils_vector                <--- runs all tests on .utils.vector
$ python tests.py --utils_base --utils_vector   <--- runs all tests on .utils.vector & .utils

所以,我开始使用argparse设置内容。我有一个基本的ArgumentParser设置没有问题,帮助信息显示正常:

$ python tests.py -h
usage: tests.py [-h] [--all] [--utils_base]

optional arguments:
  -h, --help    show this help message and exit

Global Options:
  --all         Run all tests (overrides any other selections)

opan.base.utils Tests:
  --utils_base  Run all .utils tests

然而,当我去进行一些测试时,它被一个未被识别的&#39;参数崩溃了。错误:

$ python tests.py --all
option --all not recognized
Usage: tests.py [options] [test] [...]

Options:
  -h, --help       Show this message
  -v, --verbose    Verbose output
  -q, --quiet      Minimal output
  -f, --failfast   Stop on first failure
  -c, --catch      Catch control-C and display results
  -b, --buffer     Buffer stdout and stderr during test runs

Examples:
  tests.py                               - run default set of tests
  tests.py MyTestSuite                   - run suite 'MyTestSuite'
  tests.py MyTestCase.testSomething      - run MyTestCase.testSomething
  tests.py MyTestCase                    - run all 'test*' test methods
                                               in MyTestCase

经过一些调试后,我终于意识到我在tests.py内解析的命令行参数被保留在sys.argv中并传递给unittest.main。 (回想起来,仔细阅读错误消息的Examples:部分应该会让我早点了解。)

因此,为了解决这个问题,我在下面添加了标记的代码,以便在将控制权转移到sys.argv之前从unittest.main中清除我的自定义参数:

# Arguments for selecting test suites
ALL = 'all'
UTILS_BASE = 'utils_base'

# Collecting the args together for iteration later
test_args = [ALL, UTILS_BASE]

...

# Strip from sys.argv any test arguments that are present
for a in test_args:                 <---  
    str_arg = '--{0}'.format(a)     <--- ADDING THESE MAKES UNITTEST HAPPY
    if str_arg in sys.argv:         <---
        sys.argv.remove(str_arg)    <---

有没有办法告诉argparse .remove来自sys.argv的{​​{1}}个参数,也许是ArgumentParser的构建?我已经浏览了argparse个doc页面,但是对于我来说,找不到可以选择的选项。

1 个答案:

答案 0 :(得分:4)

您需要parse_known_args()

<?xml version="1.0" encoding="windows-1250" standalone="yes" ?>
<document>
 <ID>100</ID>
 <DOCUMENT_DATA>
  <OWNER>SOME OWNER</OWNER>
  <CODING>WINDOWS-1250</CODING>
  <MAIN_DATA>
   <NAME>JOHN</NAME>
   <SURNAME>DOE</SURNAME>
   <SYSTEM_ID>000</SYSTEM_ID>
   <COUNTRY>GB</COUNTRY>
  </MAIN_DATA>
  <SUB_DATA>
   <STREET>SOME STREET</STREET>
   <BUILDING_NO>120</BUILDING_NO>
   <FLAT_NO>200</FLAT_NO>
   <CITY>LONDON</CITY>
  </SUB_DATA>
  <DESCRIPTION>
   <HAIR>BLACK</HAIR>
   <EYES>BROWN</EYES>
   <BODY>SLIM</BODY>
   <HEIGHT>176</HEIGHT>
   <STATUS>
    <STATUS_NAME>SINGLE</STATUS_NAME>
   </STATUS>
   <SEX>MALE</SEX>
   <TATOO>NO</TATOO>
   <PIERCING>NO</PIERCING>
  </DESCRIPTION>
  <INTEREST>
   <GENERAL>
    <SPORT>
     <MAIN>SURFING</MAIN>
     <TRAINING>EVERY DAY</TRAINING>
    </SPORT>
    <CARS>CLASSIC</CARS>
    <OTHER>MUSIC</OTHER>
   </GENERAL>
   <BOOKS>CRIMINALS</BOOKS>
   <MOVIES>THRILLER</MOVIES>
  </INTEREST>
 </DOCUMENT_DATA>
</document>

虽然,我必须问。你为什么要写自己的测试跑步者? unittest模块允许您从cli运行特定的测试集:

from __future__ import print_function
import argparse
import sys

def main():
    print(sys.argv)


if __name__ == "__main__":
    parser = argparse.ArgumentParser()

    parser.add_argument('--all', action='store_true')
    parser.add_argument('--utils_base', action='store_true')

    args, left = parser.parse_known_args()

    sys.argv = sys.argv[:1]+left

    main()

如果您在分组和运行测试时需要更大的灵活性,我建议您查看nosetest