【问题标题】:how to add a package to sys path for testing如何将包添加到 sys 路径以进行测试
【发布时间】:2016-08-24 23:58:30
【问题描述】:

这个问题是由python guide 中关于将项目添加到 sys 路径以在测试中使用的说明引起的,除非我误解了说明,否则这似乎不起作用

我有一个这样的 python 项目的目录结构

sample/a.py
sample/b.py
sample/c.py
sample/__init__.py
test/context.py
test/test_something.py
test/__init__.py
docs

根据the python guide,我应该创建一个test/context.py文件并添加这个

import os
import sys
sys.path.insert(0, os.path.abspath('..'))

import sample

然后,在我的test/test_something.py 文件中,它说我可以这样做

from .context import sample

指南说“这将始终按预期工作”。

但是,当我 cd 进入测试并运行时

python -m unittest test_something

我收到一个错误

ValueError: Attempted relative import in non-package

而错误信息具体指的是这个:from .context import sample

问题:如何正确地将示例包添加到 sys 路径?

在回答时,您能否澄清一下解决方案是否会处理示例包中的绝对导入。例如,我的 sample.a 导入 sample.b 等。当我以不同的方式构建测试时,我对 sample.a 进行了绝对导入,但由于它的相对导入为 from .b import Boo,因此产生了类似的错误

更新

`File "/usr/local/lib/python2.7/runpy.py", line 162 in _run_module_as_main "__main__", fname, loader, pkg_name)
File  "/usr/local/lib/python2.7/runpy.py", line 72, in _run_code exec code in run_globals
File  "/usr/local/lib/python2.7/unittest/__main__.py", line 12, in module main(module=None)
File  "/usr/local/lib/python2.7/unittest/main.py", line 94, in __init__ self.parseArgs(argv)
File  "/usr/local/lib/python2.7/unittest/main.py", line 149 in parseArgs self.createTests()
File  "/usr/local/lib/python2.7/unittest/main.py", line 158, in createTests self.module)
File  "/usr/local/lib/python2.7/unittest/loader.py", line 130, in loadTestsFromNames suites = [self.loadTestsFromName(name,module) for name in names]
File  "/usr/local/lib/python2.7/unittest/loader.py", line 91, in loadTestsFromName module = __import__('-'.join(parts_copy))
File "test_something.py", line 8, in module from .context import sample

更新

如果我从根目录运行以下命令

   python -m unittest test

它说,“在 0.000 秒内运行 0 次测试”

如果按照 @cuongnv 在 cmets 中的建议,我从根目录运行它

python -m unittest test/test_something.py

或者这个(没有文件扩展名)

python -m unittest test/test_something 

它说“不支持按文件名导入”

【问题讨论】:

  • 你用的是什么版本的python?可以肯定的是,python 3 对相关导入进行了重新设计
  • 呃,好的;那么,您可以发布完整的回溯吗?以及__init__.py 两个文件的内容?
  • 我添加了堆栈跟踪。谢谢你。另外,为了回答 @DarthVader 的问题,我使用的是 python 2,但也让应用程序在 python 3 上运行,所以我还在示例文件夹中每个文件的顶部使用 from __future__ import absolute_import
  • @Leahcim 如果您注释掉 __future__ 导入,它有效吗?
  • @cuongnv 我已经发布了 test_something.py 中的相关行,即from .context import sample,这是链接到 python 指南所说的内容,也是触发错误的原因。不幸的是,我删除了文件的其余部分,因为我找到了一种通过在测试目录之外使用 run_tests.py 文件(文件名显然无关紧要)来运行测试的方法。但是,我留下了这个问题,因为它显示的问题没有得到回答(并且指南说它应该可以工作)。但我认为 test_something.py 文件的其余部分只是一个基本的测试用例

标签: python


【解决方案1】:

问题:如何正确地将示例包添加到 sys 路径?

您的做法是正确的,但您错过了将您的文件夹声明为一个包。尝试Christian的解决方案,它应该可以工作。

您的路径存储在sys.path。通过这样做:

sys.path.insert(0, os.path.abspath('..'))

您是在告诉您的 python 将(当前文件的)上层文件夹添加到您的路径中。由于sys.path 是一个列表,您可以使用其他列表方法,如insertappend...

在您的情况下,您将上层目录插入到路径列表的顶部。

见:

In [1]: import sys

In [2]: sys.path
Out[2]: 
['',
 '/usr/local/bin',
 '/usr/lib/python3.4',
 '/usr/lib/python3.4/plat-x86_64-linux-gnu',
 '/usr/lib/python3.4/lib-dynload',
 '/usr/local/lib/python3.4/dist-packages',
 '/usr/lib/python3/dist-packages',
 '/usr/local/lib/python3.4/dist-packages/IPython/extensions',
 '/home/cuong/.ipython']

In [3]: sys.path.insert(0, '/tmp/foo')

In [4]: sys.path
Out[4]: 
['/tmp/foo', **<-- on top**
 '',
 '/usr/local/bin',
 '/usr/lib/python3.4',
 '/usr/lib/python3.4/plat-x86_64-linux-gnu',
 '/usr/lib/python3.4/lib-dynload',
 '/usr/local/lib/python3.4/dist-packages',
 '/usr/lib/python3/dist-packages',
 '/usr/local/lib/python3.4/dist-packages/IPython/extensions',
 '/home/cuong/.ipython']

所以,从这里开始,当你有

import sample

您的 python 将尝试在路径中查找是否有任何 sample 包。

很遗憾,它找不到sample,因为您在sample 文件夹中忘记了__init__.py,因此您没有将其打包成一个包。

希望我的解释能帮助您理解,并且您可以处理与此不同的其他情况。

【讨论】:

  • 感谢您的解释,但我在示例和测试文件夹中都有一个 init.py 文件,我只是忘记在 OP 中提及这一点。那么问题出在哪里呢?
  • 我想我明白了,你没有把你的test 作为一个包来调用。尝试执行此命令cd ..; python -m unittest test.test_something
  • 此评论应在实际答案中
【解决方案2】:

尝试在tests/ 中添加一个空的__init__.pytouch tests/__init__.py 应该可以。

【讨论】:

  • 实际上,我在test 文件夹和sample 文件夹中有一个init.py,但它不起作用。我刚刚忘记将其添加到 OP 中。现在更新了。问题是一样的。
【解决方案3】:

为了让我的测试目录结构能够在 IDE。请在下面找到我的解决方案。经测试 Windows 7 使用 python 3.6 和 Linux Mint 使用 python 3.4,运行代码 使用命令行:

python -m pytest test_compress_files.py

我写的要测试的文件在一个名为 compress_files.py 的目录中 \src。包含要使用 pytest 运行的测试的文件称为 test_compress_files.py 在子目录 \tests 中,所以完整的目录路径是 \src\测试。我需要将一个名为 context.py 的文件添加到 \src\tests 目录。此文件用于 test_compress_files.py 以启用对上述目录中的 compress_files.py 的访问。 _init_.py 文件是空的。

目录结构

\src
__init__.py
compress_files.py

\src\tests
__init__.py
context.py
test_compress_files.py  

compress_files.py 包含要测试的脚本。

context.py:

import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

import compress_files  

行:

sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

来自http://docs.python-guide.org/en/latest/writing/structure/ 的搭便车徒步旅行者指南中的建议。这会将 /src/tests 目录上方的目录路径添加到 sys.path,在本例中为 /src。

test_compress_files.py:

import os
import pytest
from .context import compress_files
from compress_files import *

# tests start here
...

【讨论】:

  • sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(file) GJ!!!
【解决方案4】:

我还不能发表评论,但我在 python 3.7 env 中尝试了 Oppy 的答案,但它失败了:

ImportError: cannot import name 'compress_files' from '__main__' (test_compress_files.py)

我使用修改后的 test_compress_files.py 解决了(注意删除的点):

import os
import pytest
from context import compress_files
from compress_files import *

# tests start here
...

【讨论】:

    猜你喜欢
    • 2019-11-22
    • 1970-01-01
    • 1970-01-01
    • 2013-12-19
    • 1970-01-01
    • 2021-10-30
    • 1970-01-01
    • 2010-11-22
    • 1970-01-01
    相关资源
    最近更新 更多