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