2

TL;博士

对于像这样的固定且不可更改的非包目录结构:

some_dir/
    mod.py
    test/
        test_mod.py
        example_data.txt

test_mod.py什么是启用从导入的非打包方式mod.py

在这种情况下,我仅限于使用 Python 2.7。

我想为mod.py. 我想创建一个新目录test,在它旁边mod.py和里面有一个测试文件test/test_mod.py,应该从中导入函数mod.py并测试它们。

由于依赖于基于包的命名的相对导入的众所周知的限制,您不能以直接的方式执行此操作。然而,关于该主题的所有建议都建议将脚本构建为一个包,然后使用相对导入,这对于我的用例来说是不可能的。

就我而言,它不允许mod.py作为一个包构建,我不能要求用户mod.py安装它。相反,他们可以自由地从版本控制中检出文件,然后按照他们的意愿开始使用它,我无法改变这种情况。

鉴于此,有什么方法可以提供简单、直接的test 目录

注意:不仅仅是一个测试文件mod.py,而是一个实际的测试目录,因为它会附带测试数据等其他资产,并且子目录组织至关重要。

如果这是重复的,我深表歉意,但是在发布之前我在研究中看到的这个问题的十几个排列中,我还没有看到一个解决如何做到这一点的问题。他们都说要使用包装,这对我来说是不允许的选择。

4

1 回答 1

1

根据@mgilson 的评论,我import_helper.py在测试目录中添加了一个文件。

some_dir/
    mod.py
    test/
        test_mod.py
        import_helper.py
        example_data.txt

以下是 的内容import_helper.py

import sys as _sys
import os.path as _ospath 
import inspect as _inspect
from contextlib import contextmanager as _contextmanager

@_contextmanager
def enable_parent_import():
    path_appended = False
    try:
        current_file      = _inspect.getfile(_inspect.currentframe())
        current_directory = _ospath.dirname(_ospath.abspath(current_file))
        parent_directory  = _ospath.dirname(current_directory)
        _sys.path.insert(0, parent_directory)
        path_appended = True
        yield
    finally:
        if path_appended:
            _sys.path.pop(0)

然后在导入部分test_mod.py,在尝试导入之前mod.py,我添加了:

import unittest
from import_helper import enable_parent_import

with enable_parent_import():
    from mod import some_mod_function_to_test

不幸的是需要手动修改 PYTHONPATH,但是将其编写为上下文管理器会有所帮助,并且可以恢复sys.path到父目录修改之前的原始状态。

为了使此解决方案能够跨此问题的多个实例进行扩展(比如明天我被要求widget.py为一些不相关的任务编写一个模块,并且它也不能作为一个包分发),我必须复制我的辅助函数并确保复制它与任何测试一起分发,或者我必须将该小实用程序编写为一个包,确保它在我的用户群中全局安装,然后继续维护它。

当您在公司内部管理大量 Python 代码时,通常会出现一种功能失调的代码分发模式,即“安装”一些 Python 代码相当于从版本控制中签出新版本。

由于代码通常非常本地化并且特定于较大团队的一小部分任务的一小部分任务,因此通过打包来维护共享代码的开销(即使它通常是一个更好的想法)根本不会发生。

因此,我觉得我上面描述的用例对于现实世界的 Python 来说非常普遍,如果一些导入工具添加了这个功能来修改 PYTHONPATH,那就太好了,一些明智的默认选择(比如添加父目录)非常简单的。

这样,您至少可以依赖它作为标准库的一部分,而无需滚动您自己的代码并确保它与您的测试一起提供或安装在您的用户群中。

于 2016-04-10T18:45:40.777 回答