2015-04-22 54 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),而不是像我一样从测试目录运行。