Python 尝试在顶级包之外进行相对导入

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40022220/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 23:05:29  来源:igfitidea点击:

Attempted relative import beyond toplevel package

pythonpython-2.7python-importpython-unittestrelative-import

提问by Mr_and_Mrs_D

Here is my folder structure:

这是我的文件夹结构:

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

In test_bash\__init__.pyI have:

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

while in test_bsa_files.py:

而在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()

Now when I issue:

现在当我发出:

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

I get:

我得到:

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

Since 'Mopy" is in the sys.path and bosh\__init__.pyis correctly resolved why it complains about relative import above the top level package ? Which is the top level package?

由于“Mopy”在 sys.path 中并且bosh\__init__.py已正确解决,为什么它会抱怨顶级包上方的相对导入?哪个是顶级包

Incidentally this is my attempt to add tests to a legacy project - had asked in Python test package layoutbut was closed as a duplicate of Where do the Python unit tests go?. Comments on my current test package layout are much appreciated !

顺便说一句,这是我尝试向遗留项目添加测试 - 曾在Python 测试包布局中询问过,但作为Python 单元测试去哪里的副本而关闭. 非常感谢对我当前测试包布局的评论!



Well the answer belowdoes not work in my case:

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

The modulebash.py is the entry point to the application containing:

模块bash.py是入口点到包含应用:

if __name__ == '__main__':
    main()

When I use import bash.boshor from bash import boshI get:

当我使用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

This usage message is from the main() in bash.

此用法消息来自 bash 中的 main()。

回答by MisterMiyagi

TLDR: Do

TLDR:做

import bash.bosh

or

或者

from bash import bosh

If you also just happen to have a construct like bash.bash, you have to make sure your package takes precedence over its contents. Instead of appending, add it to the front of the search order:

如果您碰巧也有类似 的构造bash.bash,则必须确保您的包优先于其内容。而不是追加,将其添加到搜索顺序的前面:

# test_bash\__init__.py
sys.path.insert(0, mopy)


When you do

当你做

import bosh

it will import the modulebosh. This means Mopy/bashis in your sys.path, python finds the file boshthere, and imports it. The module is now globally known by the name bosh. Whether boshis itself a module or package doesn't matter for this, it only changes whether bosh.pyor bosh/__init__.pyis used.

它将导入模块bosh。这意味着Mopy/bash在您的sys.path, python 中找到该文件bosh,然后将其导入。该模块现在以名称而闻名bosh。无论bosh是本身就是一个模块或包不要紧此,它只会改变是否bosh.pybosh/__init__.py使用。

Now, when boshtries to do

现在,当bosh试图做

from .. import bass

this is nota file system operation ("one directory up, file bass") but a module name operation. It means "one package level up, module bass". boshwasn't imported from its package, but on its own, though. So going up one package is not possible - you end up at the package '', which is not valid.

不是一个文件系统操作(“一个目录,文件bass”)而是一个模块名称操作。它的意思是“一包升级,模块低音”。bosh不是从它的包中导入的,而是它自己导入的。所以上升一个包裹是不可能的——你最终''得到的是无效的包裹。

Let's look at what happens when you do

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

import bash.bosh

instead. First, the packagebashis imported. Then, boshis imported as a module of that package- it is globally know as bash.bosh, even if you used from bash import bosh.

反而。首先,导入bash。然后,bosh作为该包的模块导入-bash.bosh即使您使用from bash import bosh.

When boshdoes

什么bosh时候

from .. import bass

that one works now: going one level up from bash.boshgets you to bash. From there, bassis imported as bash.bass.

那个现在有效:从上一层开始bash.bosh让你到bash. 从那里,bass作为bash.bass.

See also this related answerfor executing a module from within a package without modifying sys.path.

另请参阅此相关答案以从包内执行模块而不修改sys.path