Intento de importación relativa más allá del paquete de nivel superior

Aquí está mi estructura de carpetas:

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 

En test_bash\__init__.py tengo:

 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 

mientras que en 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() 

Ahora cuando emito:

 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 

Yo obtengo:

     Traceback (most recent call last): File "C:\_\JetBrains\PyCharm 2016.2.2\helpers\pycharm\utrunner.py", line 124, in  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  import bosh File "C:\Dropbox\eclipse_workspaces\python\wrye-bash\Mopy\bash\bosh\__init__.py", line 50, in  from .. import bass ValueError: Attempted relative import beyond toplevel package 

    Dado que ‘Mopy “está en sys.path y bosh\__init__.py se resuelve correctamente ¿por qué se queja sobre la importación relativa por encima del paquete de nivel superior? ¿Cuál es el paquete de nivel superior ?

    Por cierto, este es mi bash de agregar pruebas a un proyecto heredado: había preguntado en el diseño del paquete de prueba de Python, pero se cerró como duplicado de ¿Adónde van las pruebas de unidad de Python? . ¡Los comentarios sobre el diseño actual de mi paquete de prueba son muy apreciados!


    Bueno, la respuesta a continuación no funciona en mi caso:

    El módulo bash.py es el punto de entrada a la aplicación que contiene:

     if __name__ == '__main__': main() 

    Cuando uso import bash.bosh o from bash import bosh obtengo:

     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 

    Este mensaje de uso es de main () en bash.

    TLDR: hacer

     import bash.bosh 

    o

     from bash import bosh 

    Si también tiene una construcción como bash.bash , debe asegurarse de que su paquete tenga prioridad sobre su contenido. En lugar de agregar, agréguelo al frente del orden de búsqueda:

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

    Cuando tu lo hagas

     import bosh 

    Se importará el módulo bosh . Esto significa que Mopy/bash está en tu sys.path , python encuentra el archivo bosh allí, y lo importa. El módulo ahora es conocido globalmente por el nombre bosh . Si bosh es en sí mismo un módulo o paquete no importa para esto, solo cambia si se bosh.py o bosh/__init__.py .

    Ahora, cuando bosh trata de hacer

     from .. import bass 

    esto no es una operación del sistema de archivos (“un directorio arriba, archivo bajo”) sino una operación de nombre de módulo. Significa “un paquete de nivel, módulo bajo”. bosh embargo, bosh no se importó de su paquete, pero sí solo. Por lo tanto, no es posible subir un paquete: terminas en el paquete '' , que no es válido.

    Echemos un vistazo a lo que sucede cuando lo haces

     import bash.bosh 

    en lugar. Primero, se importa el paquete bash . Luego, bosh se importa como un módulo de ese paquete ; se conoce globalmente como bash.bosh , incluso si usó from bash import bosh .

    Cuando bosh hace

     from .. import bass 

    ese funciona ahora: subir un nivel desde bash.bosh te hace bash . A partir de ahí, el bass se importa como bash.bass .

    Consulte también esta respuesta relacionada para ejecutar un módulo desde un paquete sin modificar sys.path .