Cómo importar correctamente un paquete vecino en el paquete actual en Python?
Sé que hay un millón de preguntas y artículos similares que describen cómo definir y gestionar paquetes en general, pero lo siguiente no parece funcionar y se me han acabado las cosas que intentar. Espero que esté pasando por alto algo completamente obvio para otra persona.
Esta es mi estructura de proyecto actual:
root-folder/
|- app/
|- cube/
|- algorithms/
|- __init__.py
|- utils.py
|- ...
|- models/
|- __init__.py
|- cube.py
|- ...
|- __init__.py
|- main.py
|- README.md
|- presentation/
|- cli_test/
|- __init__.py
|- run.py
|- unity/
|- __init__.py
|- producer.py
|- __init__.py
|- README.md
|- __init__.py
Estoy intentando importar una función de main.py
en app.cube dentro de producer.py
en app.presentation.unity de la siguiente manera:
from app.cube.main import run
pero cuando intento ejecutar el archivo del productor, me da lo siguiente:
$ python app/presentation/unity/producer.py
Traceback (most recent call last):
File "app/presentation/unity/producer.py", line 3, in <module>
from app.cube.main import run
ModuleNotFoundError: No module named 'app'
He intentado mover archivos, cambiar nombres de carpetas, agregar y eliminar archivos __init__.py
, pero siempre obtengo un problema similar. En la configuración actual, todos los archivos __init__.py
están vacíos, por cierto.
Otra cosa a tener en cuenta es que la carpeta cube
solía estar en el nivel raíz del proyecto antes de que agregara la carpeta presentation
, y podía importar funciones y clases en ambos sentidos entre los módulos models
y algorithms
, e importar cosas del módulo cube
al nivel raíz. El contenido de la carpeta cube
no ha cambiado desde entonces. Es como si agregar una capa adicional no funcionara o algo así, lo cual suena tonto.
Para obtener información final, estoy utilizando Python 3.8.5 instalado a través de pyenv 2.2.0 en MacOs Catalina (10.15.6)
¡Solución!
Como se propuso en el primer comentario de esta publicación, al ejecutarlo de la siguiente manera, puedes ejecutar un “módulo de biblioteca como un script” ¡y ahora funciona para mí!
python -m app.presentation.unity.producer
davy.ai
El problema aquí parece estar en la forma en que estás intentando importar la función
run
desdemain.py
. En lugar de usar una importación relativa, estás intentando importarla usando una importación absoluta empezando desde el directorio raíz. Esto está causando el errorModuleNotFoundError
ya que el directorio raíz no está definido como un módulo en tu entorno de Python.Para solucionar esto, puedes usar una importación relativa desde
producer.py
para importar la funciónrun
. Suponiendo que tantomain.py
comoproducer.py
están en el mismo paqueteunity
, puedes modificar tu declaración de importación de la siguiente manera:Aquí, los
...
en la declaración de importación representan subir tres niveles en la jerarquía del paquete para llegar al paqueteapp
, luego bajar al paquetecube
y finalmente al módulomain
.Como alternativa, también puedes ejecutar el archivo
producer.py
usando la opción-m
junto con la ruta completa al archivo del módulo. Esto te permitirá ejecutar un “módulo de librería como un script”, añadiendo efectivamente el directorio raíz a la ruta de Python. Puedes hacer esto de la siguiente manera:Esto debería resolver el error
ModuleNotFoundError
y permitirte importar la funciónrun
desdemain.py
.