10

这里是我的文件夹结构:尝试相对进口超出顶层包

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 

由于“多份原件打印”是在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()。

+0

在''bash.py'中使用'sys.argv'或'argparse'有没有任何无人值守的代码? 'if __name__ =='__main __':'不会在'import bash'或其任何变体上触发。 – MisterMiyagi

+0

@MisterMiyagi:是的,你知道了 - 这里的这一行解析cli:https://github.com/wrye-bash/wrye-bash/blob/f739aba0aa09e4c1e12141bd9fcd268f760121c9/Mopy/bash/bash.py –

+0

你应该把它移到'if __name__ ...',尽管它不能解决问题。我已经更新了答案,使得该软件包的优先级高于其模块。 – MisterMiyagi

回答

15

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,并导入它。该模块现在全称为boshbosh本身是模块还是封装对此无关紧要,它只会改变是否使用bosh.pybosh/__init__.py

现在,当bosh试图做

from .. import bass 

这是不是文件系统操作(“一级目录,文件低音”),但模块名称操作。它意味着“一个包装级别,模块低音”。虽然没有从包装中导入bosh,但它自己。因此,无法上传一个包裹 - 最终出现在包裹'',这是无效的。

让我们看一下,当你做

import bash.bosh 

,而不是发生了什么。首先,导入bash。然后,bosh作为该包的模块导入 - 即使您使用的是from bash import bosh,它在全球范围内也已知为bash.bosh

bosh确实

from .. import bass 

一个现在工作:从bash.bosh去一个级别得到你bash。从那里,bass被导入为bash.bass

另请参阅this related answer用于从包内执行模块而不修改sys.path

+0

哈哈 - 我有一个很好的你 - 看编辑;) –

+0

我曾试过顺便说一句,我已经得到的消息,但我没有提及(与无数其他这样的打击在黑暗中) –

+0

@Mr_and_Mrs_D你有重复的名称在你的文件层次结构中,认为这可能不值得一提? oO让我看看能不能找出那个...... – MisterMiyagi