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

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

本文介绍了尝试在顶级包之外进行相对导入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的文件夹结构:

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 已正确解决,为什么它会抱怨顶级包上方的相对导入?哪个是顶级包 ?

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

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

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

好吧,下面的答案在我的情况下不起作用:

Well the answer below does not work in my case:

模块 bash.py 是应用程序的入口点,包含:

The module bash.py is the entry point to the application containing:

if __name__ == '__main__':
    main()

当我使用 import bash.boshfrom bash import bosh 时,我得到:

When I use import bash.bosh or from bash import bosh I get:

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

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

推荐答案

TLDR: Do

import bash.bosh

from bash import bosh

避免修改sys.path,因为这会重复模块.

Avoid modifying sys.path, as this duplicates modules.

当你这样做

import bosh

它将导入模块 bosh.这意味着 Mopy/bash 在您的 sys.path 中,python 在那里找到文件 bosh 并将其导入.该模块现在以 bosh 的名称全球知名.bosh 本身是模块还是包并不重要,它只改变 bosh.pybosh/__init__.py 是用过.

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

现在,当 bosh 尝试做

from .. import bass

不是一个文件系统操作(一个目录,文件bass"),而是一个模块名称操作.它的意思是一个包升级,模块低音".bosh 不是从它的包中导入的,而是它自己导入的.因此,不可能上升一个包裹 - 您最终会到达包裹 '',这是无效的.

this is not a file system operation ("one directory up, file bass") but a module name operation. It means "one package level up, module bass". bosh wasn'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.

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

Let's look at what happens when you do

import bash.bosh

相反.首先,导入package bash.然后,bosh 被导入为该包的一个模块 - 它被全局称为 bash.bosh,即使您使用了 frombash 导入 bosh.

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

bosh 出现时

from .. import bass

现在可以使用了:从 bash.bosh 上一级可以让您进入 bash.从那里,bass 被导入为 bash.bass.

that one works now: going one level up from bash.bosh gets you to bash. From there, bass is imported as bash.bass.

这篇关于尝试在顶级包之外进行相对导入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-24 18:08