2009-08-27 145 views
9

好的,我認爲無論我做錯了什麼,它可能是非常明顯的,但我無法弄清楚。我已經閱讀並重新閱讀了關於包的教程部分,我唯一能想到的是這不會起作用,因爲我直接執行它。這裏的目錄設置:Python軟件包?

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__是它如何知道它在哪個軟件包中的一部分),但是在那種情況下,你們如何導入從測試代碼上級存儲的'生產'代碼?

+0

只需選擇它並點擊代碼示例按鈕。或者將它包裝在'' – 2009-08-27 18:52:04

回答

8

通常你會有一個目錄,其名稱是你的包名稱,在你的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

+2

是的,但是你的項目不再利用相對的進口。相對導入的好處在於它使您的軟件包自成一體。它不依賴於它的主文件夾名稱,也不能錯誤地導入某個單元,例如,被埋在PYTHONPATH某處的過時版本的軟件包。 – 2009-08-27 19:11:06

+0

好的,那麼在調用腳本之前我將如何設置PYTHONPATH?就像我希望能夠在同一臺計算機上的兩個不同位置運行一樣? ps:我也在學習如何處理與mercurial的克隆/合併,這就是爲什麼它在兩個地方。 – Jonathanb 2009-08-27 19:18:33

+0

如果從位於程序包層次結構之外的腳本導入模塊,則添加關於相對導入如何工作的註釋。否則,請使用測試工具。 設置環境變量取決於你在做什麼。如果你使用bash,只需做PYTHONPATH = foo python scriptname.py – 2009-08-27 19:23:02

10

我有同樣的問題。我現在使用nose來運行我的測試,並正確處理相對導入。

是的,這整個相對重要的東西是混亂。

+2

我正在接受其他答案,因爲它可以讓我執行我一直在嘗試使用相對導入的方法。然而,我也下載鼻子作爲我的測試用具,因爲它看起來比我可以自己拼湊起來的任何東西都強大得多。 – Jonathanb 2009-08-27 19:52:14

+0

正是我所尋找的,謝謝 – Copperfield 2017-02-27 19:16:29