这是我的文件夹结构:

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.boshfrom 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()。

最佳答案

TLDR:做

import bash.bosh
或者
from bash import bosh
避免修改sys.path,因为这会重复模块。

当你做
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 boshbosh何时执行
from .. import bass
现在可以正常工作:从bash.bosh上一层将您带到bash。从那里,bass被导入为bash.bass

09-17 12:52