2015-04-22 49 views
2

我的virtualenv一個Foo項目創建和我有一些問題,在test_file.py蟒蛇 - 進口父目錄發出

導入文件模塊。這是我的項目目錄

Foo/ 
├── app 
│   ├── __init__.py 
│   ├── testfile.py 
│   ├── tests 
│   │   ├── __init__.py 
│   │   └── test_gram.py 
│   ├── util 
│   │   ├── File.py 
│   │   ├── Gram.py 
│   │   ├── __init__.py 
└── NOTES 

test_gram.py :

from app.util.File import loadDataFromPickle 

listofdict = loadDataFromPickle(".....") 
i = 0 
for item in listofdict[:50]: 
    print(item) 

如果我跑test_gram,我得到一個導入錯誤:

Traceback (most recent call last): 
    File "test_gram.py", line 1, in <module> 
    from app.util.File import loadDataFromPickle 
ImportError: No module named 'app 

我在做什麼錯?我是否需要將virtualenv路徑更改爲Foo/app而不是Foo?

+1

默認情況下Python導入是絕對的,你的app目錄不在'sys.path'中。試試'from ..app.util.File import loadDataFromPickle' – dhke

+0

我認爲你應該將'test_gram.py'移動到Foo /(不太確定) – Ronnie

+0

如果我把test_gram.py放在app中,並且我從util.File import ...............它可以工作,但將測試放在測試目錄中會更乾淨。 – Eric

回答

3

如果test_gram.py是在測試文件夾,然後導入行應該是:

from ..util.File import loadDataFromPickle$ 

另一種選擇是使用imp模塊,這通常是建議而不是附加的SYS。路徑(source here,包括Python 3版)

import imp 

foo = imp.load_source('module.name', '/path/to/file.py') 
foo.MyClass() 
0

您在test_gram.py這在app子文件夾。因此,當您嘗試導入app,它看起來apptests,它是不是有:

import sys 
sys.path.append('/Foo/app/util') 

from File import loadDataFromPickle 
+0

比追加sys.path更好的是使用'imp'模塊 - 參見[here](http://stackoverflow.com/a/ 67692/2327328) – philshem

2
from app.util.File import loadDataFromPickle 

絕對進口,這意味着

  1. sys.path
  2. 來自列出的任何路徑
  3. 找到fir st一個有app模塊。
  4. 然後從app模塊導入util模塊。
  5. ...

棘手位是sys.path,這是documented作爲

As initialized upon program startup, the first item of this list, path[0], is the directory containing the script that was used to invoke the Python interpreter. If the script directory is not available (e.g. if the interpreter is invoked interactively or if the script is read from standard input), path[0] is the empty string, which directs Python to search modules in the current directory first. Notice that the script directory is inserted before the entries inserted as a result of PYTHONPATH.

所以,如果你運行Foo/app/tests/test_gram.pysys.path開始與.../Foo/app/tests/。在該目錄下的任何地方都沒有app模塊,因此您不能使用絕對導入導入app(除非在某些sys.path的某個位置有app)。

作爲評價和其他答案建議,它是使用在這樣的情況下,相對進口好的做法:

from ..util.File import loadDataFromPickle 

相對進口relative to the current package/module,而不是目錄中sys.path

編輯:

不過,相對於進口量將不會直接在命令行運行腳本時工作,因爲Python會抱怨''模塊尚未導入(Parent module '' not loaded, cannot perform relative importSystemError: Parent module '')。那是因爲在直接運行腳本時導入父模塊(tests'')並且導入器正確地假定它們應該是。

一個竅門是run the test script as a module

python -m app.tests.test_gram.py 

這很可能會需要一些修改測試腳本,至少有

if __name__ == '__main__': 
    [...] 

在腳本中。有關更多詳細信息,另請參閱Relative imports in Python 3

作爲一個建議,無論如何,您可能希望將測試腳本轉換爲使用​​。

+0

感謝您的信息。將app dir附加到由a.j建議的sys.path中的解決方案在這個特定的工作中起作用,但是如果有很多測試文件,它似乎沒有用處。所以我試圖用@dhke建議的相對路徑導入模塊。但我得到以下錯誤:SystemError:父模塊''未加載,無法執行相對importSystemError:父模塊''未加載,無法執行相對導入 我只是試驗尋找一個有用的層次結構 – Eric

+1

請參閱http:// stackoverflow.com/questions/16981921/relative-imports-in-python-3 – dhke

+1

比追加sys.path更好的是使用'imp'模塊 - 請參閱[這裏](http://stackoverflow.com/a/67692/2327328) – philshem

0

在這種情況下,我只需要從頂級目錄運行測試(Foo/app/tests/test_gram.py),而不是像我一樣從測試目錄運行。