【问题标题】:How to make python -m unittest discover handle PEP 420 namespace packages?如何让 python -m unittest discover 处理 PEP 420 命名空间包?
【发布时间】:2020-03-22 02:28:22
【问题描述】:

假设项目的顶层是一个没有 __init__.py 的 PEP 420 命名空间包,如下所示:

src
└── toplevel
    └── secondlevel
        ├── __init__.py
        └── tests
            ├── __init__.py
            └── test_something.py

可以正常导入测试文件:

$ python3.8 -m venv v
$ ln -s $PWD/src/toplevel v/lib/python3.8/site-packages/
$ v/bin/python -m toplevel.secondlevel.tests.test_something
Hi from test_something.py

但是,如果我将 unittest 指向这个结构,它会失败:

$ v/bin/python -m unittest discover toplevel.secondlevel
Traceback (most recent call last):
  File "/usr/lib/python3.8/runpy.py", line 192, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.8/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/usr/lib/python3.8/unittest/__main__.py", line 18, in <module>
    main(module=None)
  File "/usr/lib/python3.8/unittest/main.py", line 100, in __init__
    self.parseArgs(argv)
  File "/usr/lib/python3.8/unittest/main.py", line 124, in parseArgs
    self._do_discovery(argv[2:])
  File "/usr/lib/python3.8/unittest/main.py", line 244, in _do_discovery
    self.createTests(from_discovery=True, Loader=Loader)
  File "/usr/lib/python3.8/unittest/main.py", line 154, in createTests
    self.test = loader.discover(self.start, self.pattern, self.top)
  File "/usr/lib/python3.8/unittest/loader.py", line 340, in discover
    self._get_directory_containing_module(top_part)
  File "/usr/lib/python3.8/unittest/loader.py", line 354, in _get_directory_containing_module
    full_path = os.path.abspath(module.__file__)
  File "/usr/lib/python3.8/posixpath.py", line 374, in abspath
    path = os.fspath(path)
TypeError: expected str, bytes or os.PathLike object, not NoneType

NoneType 显然来自 toplevel.__file__, 对于 PEP 420 命名空间包来说是 None 。 unittest.loader.TestLoader.discover 似乎包含一些用于命名空间包的机制,但在这种情况下它不起作用。

如果我添加 __init__.py 文件,一切正常:

$ touch src/toplevel/__init__.py
$ v/bin/python -m unittest discover toplevel.secondlevel
Hi from test_something.py

----------------------------------------------------------------------
Ran 0 tests in 0.000s

OK

如何使 unittest 与 __init__-less 包一起正常工作?

【问题讨论】:

标签: python-3.x python-unittest python-packaging


【解决方案1】:

您不应在常规包中省略 __init__.py

命名空间包不是常规包。在常规包中省略 __init__.py 是滥用 PEP 420。unittest 和其他工具不支持这种滥用。

也见https://dev.to/methane/don-t-omit-init-py-3hga

【讨论】:

  • 这是否意味着使用 PEP 420 的 所有 包都是一种滥用,并且 没有一个 可以使用 unittest 进行测试?
  • 不,当包作者真正需要namespace包时,并不是滥用PEP 420。但是99%的人不需要namespace包。
  • 值得注意的是这个答案作者是 CPython 贡献者。否则,这将被视为主观意见。
猜你喜欢
  • 1970-01-01
  • 2013-06-04
  • 2011-09-05
  • 2021-08-02
  • 1970-01-01
  • 1970-01-01
  • 2018-08-29
  • 1970-01-01
  • 2017-06-01
相关资源
最近更新 更多