26

这是我的文件夹结构:

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 测试包布局中询问过,但作为Python 单元测试在哪里的副本而被关闭?. 非常感谢对我当前测试包布局的评论!


那么下面的答案在我的情况下不起作用:

模块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()。

4

2 回答 2

29

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

不是文件系统操作(“一个目录向上,文件bass”)而是模块名称操作。它的意思是“一个包升级,模块低音”。bosh不是从它的包中导入的,而是单独导入的。因此,不可能增加一个包裹 - 你最终会得到包裹'',这是无效的。

让我们看看当你这样做时会发生什么

import bash.bosh

反而。首先,导入包。 bash然后,作为该包bosh的模块导入- 它在全球范围内被称为,即使您使用.bash.boshfrom bash import bosh

什么bosh时候

from .. import bass

那个现在有效:从上一级可以bash.bosh让你到bash. 从那里bass导入为bash.bass.

于 2016-10-13T13:38:51.477 回答
0

无需破解或研究同级模块的导入。只需转到您的项目目录并导入模块。如果项目目录不是包,添加init .py 使其成为项目目录。

# File name ProjectDir/sibling1/main.py
import ProjectDir.sibling2

if __name__=='__main__':
    md = sibling2.module()
于 2021-04-18T18:19:09.897 回答