这是我的文件夹结构:
Mopy/ # no init.py !
bash/
__init__.py
bash.py # <--- Edit: yep there is such a module too
bass.py
bosh/
__init__.py # contains from .. import bass
bsa_files.py
...
test_bash\
__init__.py # code below
test_bosh\
__init__.py
test_bsa_files.py
在test_bash\__init__.py
我有:
import sys
from os.path import dirname, abspath, join, sep
mopy = dirname(dirname(abspath(__file__)))
assert mopy.split(sep)[-1].lower() == 'mopy'
sys.path.append(mopy)
print 'Mopy folder appended to path: ', mopy
在test_bsa_files.py
中:
import unittest
from unittest import TestCase
import bosh
class TestBSAHeader(TestCase):
def test_read_header(self):
bosh.bsa_files.Header.read_header()
if __name__ == '__main__':
unittest.main()
现在我发出:
python.exe "C:\_\JetBrains\PyCharm 2016.2.2\helpers\pycharm\utrunner.py" C:\path\to\Mopy\test_bash\test_bosh\test_bsa_files.py true
我明白了:
Traceback (most recent call last):
File "C:\_\JetBrains\PyCharm 2016.2.2\helpers\pycharm\utrunner.py", line 124, in <module>
modules = [loadSource(a[0])]
File "C:\_\JetBrains\PyCharm 2016.2.2\helpers\pycharm\utrunner.py", line 43, in loadSource
module = imp.load_source(moduleName, fileName)
File "C:\Dropbox\eclipse_workspaces\python\wrye-bash\Mopy\test_bash\test_bosh\test_bsa_files.py", line 4, in <module>
import bosh
File "C:\Dropbox\eclipse_workspaces\python\wrye-bash\Mopy\bash\bosh\__init__.py", line 50, in <module>
from .. import bass
ValueError: Attempted relative import beyond toplevel package
由于'Mopy'在sys.path中并且bosh\__init__.py
已正确解析,为什么它会抱怨顶级包之上的相对导入?哪个是顶级包?
顺便提一下,这是我尝试将测试添加到旧项目中 - 曾在Python test package layout中询问,但已作为Where do the Python unit tests go?的副本关闭。对我目前的测试包布局的评论非常感谢!
answer below在我的情况下不起作用:
模块 bash.py是包含以下内容的应用程序的入口点:
if __name__ == '__main__':
main()
当我使用import bash.bosh
或from bash import bosh
时,我得到:
C:\_\Python27\python.exe "C:\_\JetBrains\PyCharm 2016.2.2\helpers\pycharm\utrunner.py" C:\Dropbox\eclipse_workspaces\python\wrye-bash\Mopy\test_bash\test_bosh\test_bsa_files.py true
Testing started at 3:45 PM ...
usage: utrunner.py [-h] [-o OBLIVIONPATH] [-p PERSONALPATH] [-u USERPATH]
[-l LOCALAPPDATAPATH] [-b] [-r] [-f FILENAME] [-q] [-i]
[-I] [-g GAMENAME] [-d] [-C] [-P] [--no-uac] [--uac]
[--bashmon] [-L LANGUAGE]
utrunner.py: error: unrecognized arguments: C:\Dropbox\eclipse_workspaces\python\wrye-bash\Mopy\test_bash\test_bosh\test_bsa_files.py true
Process finished with exit code 2
此用法消息来自bash中的main()。
答案 0 :(得分:26)
TLDR:做
import bash.bosh
或
from bash import bosh
如果您恰好也有bash.bash
之类的构造,则必须确保您的包优先于其内容。而不是追加,将其添加到搜索顺序的前面:
# test_bash\__init__.py
sys.path.insert(0, mopy)
当你这样做时
import bosh
它将导入模块 bosh
。这意味着Mopy/bash
位于您的sys.path
中,python在那里找到文件bosh
并导入它。该模块现在以名称bosh
全球知晓。 bosh
本身是模块还是包对此无关紧要,它只会更改是否使用bosh.py
或bosh/__init__.py
。
现在,当bosh
尝试
from .. import bass
这是不文件系统操作(“一个目录向上,文件低音”),而是模块名称操作。这意味着“一个包装升级,模块低音”。 bosh
并未从其包中导入,而是单独导入。因此无法上传一个软件包 - 您最终会收到''
个软件包,这个软件包无效。
让我们看看你做什么时会发生什么
import bash.bosh
代替。首先,导入包 bash
。然后,bosh
作为该软件包的模块导入 - 即使您使用bash.bosh
,它也会全局知道为from bash import bosh
。
当bosh
执行
from .. import bass
现在可以使用:从bash.bosh
向上一级可以转到bash
。从那里,bass
导入为bash.bass
。
另请参阅this related answer,以便在不修改sys.path
的情况下从包中执行模块。
答案 1 :(得分:0)
无需破解或研究兄弟模块的导入。 只需转到您的项目目录并导入模块。如果项目目录不是包,添加 init.py 使其成为项目目录。
# File name ProjectDir/sibling1/main.py
import ProjectDir.sibling2
if __name__=='__main__':
md = sibling2.module()