【问题标题】:Python Packages?Python 包?
【发布时间】:2009-08-27 18:33:28
【问题描述】:

好的,我认为无论我做错了什么,它可能非常明显,但我无法弄清楚。我已经阅读并重新阅读了关于包的教程部分,我唯一能想到的是这不起作用,因为我直接执行它。这是目录设置:

eulerproject/
  __init__.py
  euler1.py
  euler2.py
  ...
  eulern.py
  tests/
    __init__.py
    testeulern.py

这里是 testeuler12.py(我写的第一个测试模块)的内容:

import unittest
from .. import euler12

class Euler12UnitTests(unittest.TestCase):


    def testtriangle(self):
        """
        Ensure that the triangle number generator returns the first 10
        triangle numbers.

        """
        self.seq = [1,3,6,10,15,21,28,36,45,55]
        self.generator = euler12.trianglegenerator()
        self.results = []
        while len(self.results) != 10:
            self.results.append(self.generator.next())
        self.assertEqual(self.seq, self.results)

    def testdivisors(self):
        """
        Ensure that the divisors function can properly factor the number 28.

        """
        self.number = 28
        self.answer = [1,2,4,7,14,28]
        self.assertEqual(self.answer, euler12.divisors(self.number))


if __name__ == '__main__':

    unittest.main()

现在,当我在目录中从 IDLE 和命令行执行此操作时,出现以下错误:

Traceback (most recent call last):
  File "C:\Documents and Settings\jbennet\My Documents\Python\eulerproject\tests\testeuler12.py", line 2, in <module>
    from .. import euler12
ValueError: Attempted relative import in non-package

我认为问题在于,由于我直接运行它,我无法进行相对导入(因为 __name__ 发生了变化,而且我对包描述的模糊理解是 __name__ 是它告诉的一部分它在什么包中),但在这种情况下,你们对如何导入存储在测试代码上一级的“生产”代码有什么建议?

【问题讨论】:

  • 只需选择它并单击代码示例按钮。或者将其包裹在 ``

标签: python unit-testing packages


【解决方案1】:

我遇到了同样的问题。我现在使用nose 运行我的测试,并且正确处理了相关导入。

是的,这整个相对导入的事情令人困惑。

【讨论】:

  • 我接受另一个答案只是因为它让我可以做我一直在尝试做的相对进口。但是,我也在下载鼻子作为我的测试工具,因为它看起来比我自己拼凑的任何东西都要强大。
【解决方案2】:

通常你会有一个目录,它的名字就是你的包名,在你的 PYTHONPATH 的某个地方。例如:

eulerproject/
    euler/
        __init__.py
        euler1.py
        ...
        tests/
            ...
    setup.py

然后,您可以在系统范围内安装此工具,或者确保在调用脚本时设置 PYTHONPATH=/path/to/eulerproject/:$PYTHONPATH

这样的绝对导入将起作用:

from euler import euler1

编辑

根据 Python 文档,“用作 Python 应用程序主模块的模块应始终使用绝对导入。” (Cite)

因此,另一个答案提到的像 nose 这样的测试工具之所以有效,是因为它导入包而不是从命令行运行它们。

如果你想手工做,你的可运行脚本需要在包层次结构之外,像这样:

eulerproject/
    runtests.py
    euler/
        __init__.py
        euler1.py
        ...
        tests/
            __init__.py
           testeulern.py

现在,runtests.py 可以做 from euler.tests.testeulern import TestCasetesteulern.py 可以做 from .. import euler1

【讨论】:

  • 是的,但是您的项目不再利用相对导入。相对导入的好处是它使你的包独立。它不依赖于它的主文件夹名称,并且它不能错误地从包的过时版本中导入一个单元,例如埋在 PYTHONPATH 中的某个位置。
  • 好的,那么在调用脚本之前如何设置 PYTHONPATH 呢?就像我希望能够从同一台计算机上的两个不同位置运行它一样? ps:我也在学习如何使用 mercurial 处理克隆/合并,这就是为什么它在两个地方。
  • 添加了一个注释,说明如果模块是从位于包层次结构之外的脚本导入的,则相对导入如何工作。否则使用测试工具。设置环境变量取决于您的工作。如果您使用的是 bash,只需执行 PYTHONPATH=foo python scriptname.py
  • 太棒了!这个答案在编辑后完全符合我的要求。我已经更改了层次结构,今晚我将在根目录中编写 euler.py 脚本,该脚本将接受 --test 以启用单元测试。这让我可以保留我的相对导入,使用包结构,并尝试自动测试我的构建。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-03
  • 2015-10-22
  • 1970-01-01
  • 2015-04-13
  • 2010-09-30
  • 1970-01-01
  • 2016-04-24
相关资源
最近更新 更多