xticks xlabel python python-2.7 python-import python-unittest relative-import

xlabel - plot python



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

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 <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

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 intento 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 un constructo 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 ("one directory up, file bass") 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 lleva a 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 .