将py.test与已编译的库代码一起使用

时间:2016-05-18 18:20:16

标签: python build pytest

我有一个包含以下存储库结构的python库:

repobase
 |- mylibrary
 |  |- __init__.py
 |- tests
    |- test_mylibrary.py

到目前为止,可以通过调用repobase目录中的py.test来完成测试。然后 test_mylibrary.py 中的import mylibrary使用 repobase / mylibrary 中的本地代码。

现在,我已经扩展了库以使用编译代码。因此, repobase / mylibrary 的源代码本身不起作用。我必须做setup.py build。这将创建 repobase / build / lib.linux-x86_64-2.7 / mylibrary

有没有合理的方法让py.test使用这个目录导入mylibrary?鉴于这些限制:

  1. 我不想在 test_mylibrary.py 中包含任何sys.path /导入魔法,因为这可能会破坏其他环境中的测试。

  2. 我不想放弃从 repobase 运行py.test的可能性。因此,修改PYTHONPATH无济于事,因为.仍然是sys.path中的第一个。因此 repobase / mylibrary repobase / build / lib.linux-x86_64-2.7 / mylibrary 更受青睐。

  3. 如果没有,那么需要构建的python库的标准方法是什么?

2 个答案:

答案 0 :(得分:6)

我认为你的问题只是py.test没有将构建的共享对象复制到存储库的根目录。

我刚尝试使用py.test在测试C扩展的Python wiki上直接运行UT,如下所示:

python setup.py build
py.test test/examp_unittest.py

AssertionError: No module named examp失败了。

然而,当我按照wiki跟着这个字母(而不是运行python setup.py test)时,我注意到它将.so复制到根目录(注意它开始运行测试之前的最后一行) ):

running test
running egg_info
writing examp.egg-info/PKG-INFO
writing top-level names to examp.egg-info/top_level.txt
writing dependency_links to examp.egg-info/dependency_links.txt
reading manifest file 'examp.egg-info/SOURCES.txt'
writing manifest file 'examp.egg-info/SOURCES.txt'
running build_ext
copying build/lib.linux-x86_64-2.6/examp.so ->
runTest (test.examp_unittest.DeviceTest) ... ok

----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

在我的系统上运行它之后,我现在可以在相同的代码库上非常愉快地运行py.test - 如下所示。

============================= test session starts ==============================
platform linux2 -- Python 2.7.3, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
rootdir: /tmp/sotest, inifile: 
collected 1 items 

test/examp_unittest.py .

=========================== 1 passed in 0.01 seconds ===========================

因此,解决方案是将共享对象复制到存储库的根目录。

为了确保我从头开始运行整个事情,只需构建扩展,复制共享对象然后运行py.test。这一切都按预期工作。

答案 1 :(得分:3)

从聊天讨论中,听起来好像C实现只提供了Python实现功能的一个子集。

一种常见的解决方案是拆分模块,使得需要优化实现的部件存在于单独的模块中。

考虑一个需要在不同图像格式之间转换的库的更具体的例子。

我们假设你的布局看起来像这样......

<body>
  <div class="nav">
    <div class="links">
      <div class="link">
        Servers
      </div>
    </div>
  </div>
</body>

...您的repobase |- image | |- __init__.py | |- pyJPEG.py |- build | |- lib.linux-x86_64-2.7 | |- cJPEG.so |- tests |- test_image.py 包括PYTHONPATH/path/to/repobase:/path/to/repobase/build/lib.linux-x86_64-2.7导出符号cJPEG.sojpeg_decompress,您的文件看起来像这样......

图片/ __初始化__。PY

jpeg_compress

图片/ pyJPEG.py

# Load the C implementation if we have it, otherwise fall back to
# a pure Python implementation
try:
    from cJPEG import jpeg_decompress, jpeg_compress
except ImportError:
    from pyJPEG import jpeg_decompress, jpeg_compress

def load_image(filename):
    data = open(filename, 'rb').read()
    if filename.endswidth('.jpg'):
        return jpeg_decompress(data)
    else:
        raise NotImplementedError

def save_image(data, filename, filetype='JPEG'):
    if filetype == 'JPEG':
        data = jpeg_compress(data)
    else:
        raise NotImplementedError
    open(filename, 'wb').write(data)

通过这种布局,测试套件无需关心是否构建了库 - 您可以在两种情况下使用相同的套件,def jpeg_decompress(data): # A pure Python implementation of a JPEG decoder def jpeg_compress(data): # A pure Python implementation of a JPEG encoder 的存在(或不存在)将决定哪个版本经过测试。