El código de Python se ejecuta desde IDE, pero no desde la terminal

Mis importaciones no funcionan cuando bash ejecutar el código desde el terminal de Linux. Específicamente, las importaciones desde otros paquetes en el mismo proyecto. Sé que esto es un problema de PYTHONPATH, pero no sé cómo diagnosticarlo más o resolverlo. El código corre bien dentro del IDE (eclipse).

Estoy interesado en una solución permanente, suponiendo que implicará editar .bashrc. Simplemente quiero invocar scripts desde la línea de comandos, como

python my_script.py 

os.environ["PYTHONPATH"] da un error clave en el terminal ipython.

Lo intenté

 print os.getcwd() print sys.path 

Dentro de IDE

 /home/myname/workspace/project2/main ['/home/myname/workspace/project2/main', '/home/myname/workspacep/problem2', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_6 4-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/p ython2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PILcompat', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/pytho n2.7/dist-packages/ubuntu-sso-client', '/usr/lib/pymodules/python2.7', '/usr/lib/python2.7/lib-old'] 

Terminal interior

 /home/myname/workspace/project2/main ['/home/myname/workspace/project2/main', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PILcompat', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/python2.7/dist-packages/ubuntu-sso-client'] 

Como se mencionó, para ilustrar la diferencia en las rutas utilizadas durante su ejecución de IDE y la ejecución de terminal, ejecute el siguiente script tanto en IDE como en la terminal:

 import os import sys print(os.getcwd()) for i in sys.path: print(i) 

Comparando sus resultados, al ejecutar desde el terminal, estas carpetas faltan en comparación con la ejecución en IDE:

 '/home/myname/workspacep/problem2' '/usr/lib/pymodules/python2.7' 

Una cosa a tener en cuenta es que el directorio de trabajo actual y sys.path s cambiarán en el terminal dependiendo de dónde lo ejecute y de dónde reside el archivo. Pero la clave es sys.path s porque le dicen a Python dónde buscar los módulos.

Estoy dispuesto a apostar que los módulos que está intentando importar provienen de una de estas carpetas, muy probablemente en /home/myname/workspacep/problem2 . Esto presenta problemas ya que sus módulos no se almacenan en una ubicación de acceso centralizada (por ejemplo, /usr/lib/python2.7/my_modules ) ni una subcarpeta en la estructura de su proyecto.

Para ilustrar, tengo una carpeta de proyecto simulada configurada de la siguiente manera:

 pi@box:~/project $ tree . ├── main.py ├── mod1.py └── subfolder ├── __init__.py ├── main.py └── mod2.py 

Es una buena idea tener un __init__.py vacío debajo de las subcarpetas, consulte aquí para obtener más detalles . Mi main.py ve así:

 import os import sys print(f'cwd = {os.getcwd()}') print(f'path0 = {sys.path[0]}') try: import mod1 mod1.hello() except Exception as e: print(f'import mod1 failed: {e}') try: from subfolder import mod2 mod2.hello() except Exception as e: print(f'from subfolder import mod2 failed: {e}') try: import mod2 as mod2copy mod2copy.hello() except Exception as e: print(f'import mod2copy failed: {e}') 

A continuación se muestran los resultados de mi ejecución al intentar ejecutar main.py en project y project/subfolder en terminal:

 pi@box:~/project $ python3 main.py cwd = /home/pi/project path0 = /home/pi/project Module 1 reporting in! Module 2 reporting in! import mod2copy failed: No module named 'mod2' pi@box:~/project $ python3 ./subfolder/main.py cwd = /home/pi/project path0 = /home/pi/project/subfolder import mod1 failed: No module named 'mod1' from subfolder import mod2 failed: No module named 'subfolder' Module 2 reporting in! pi@box:~/project $ cd subfolder pi@box:~/project/subfolder $ python3 main.py cwd = /home/pi/project/subfolder path0 = /home/pi/project/subfolder import mod1 failed: No module named 'mod1' from subfolder import mod2 failed: No module named 'subfolder' Module 2 reporting in! pi@box:~/project/subfolder $ python3 ../main.py cwd = /home/pi/project/subfolder path0 = /home/pi/project Module 1 reporting in! Module 2 reporting in! import mod2copy failed: No module named 'mod2' 

Puede ver que entre sys.path y sys.path , es sys.path que afecta directamente a mis import , lo que está determinado por el lugar donde se almacena main.py Al ejecutar main.py en la raíz del proyecto, pude importar tanto mod1 desde la raíz como mod2 desde la subcarpeta como se esperaba. Se supone que mod2copy falla porque no hay mod2 en la raíz. Sin embargo, al ejecutar main.py almacenado en la subcarpeta, mod1 no se pudo importar porque python no sabe dónde está almacenado mod1 , debido a la falta de sys.path . Sin embargo, si agregué esta línea siguiente antes de import :

 sys.path.append('/home/pi/project') 

El resultado de main.py en la subcarpeta será:

 pi@rpirpirpi:~/project/subfolder $ python3 main.py cwd = /home/pi/project/subfolder path0 = /home/pi/project/subfolder Module 1 reporting in! Module 2 reporting in! Module 2 reporting in! 

Notarás que las 3 importaciones son exitosas. Python puede localizar mod1 y /subfolder/mod2 porque la ruta raíz ahora se agrega a sys.path del sys.path . Y mod2copy sigue teniendo éxito porque la subfolder ya forma parte de la lista sys.path antes de la sys.path .

Dicho todo esto, se ensucia cuando tiene un módulo que hace referencia a otro módulo dentro de la subestructura. Digamos que /subfolder/module3 intenta import mod2 y está ejecutando desde /project/main.py , la línea import mod2 cuando su script se ejecuta from subfolder import mod3 devolverá un ModuleNotFoundError como antes porque sys.path no contiene /project/subfolder , por lo que necesitará cierta delicadeza en todas estas import entre módulos. Otra cosa a considerar es la ruta relativa: si comienza a mover archivos, se deberá mantener todos estos sys.path .

Para resumir: si espera importar módulos que no están en la biblioteca de Python ni están nesteds bajo la raíz de su proyecto, se encontrará con un mal momento.

Lo anterior fue un remedio fácil y rápido para pequeños proyectos ad-hoc, por ejemplo, para pruebas temporales antes de finalizar los módulos. Pero si su intención es reutilizar estos módulos para proyectos futuros, considere almacenarlos en una ruta centralizada y agregar a su PYTHONPATH. Este hilo tiene más información, por ejemplo, si desea almacenar sus módulos en /home/myname/modules :

agrega la línea de abajo a tu ~/.bashrc :

 export PYTHONPATH="${PYTHONPATH}:/home/myname/modules" 

… y luego agregue un archivo vacío llamado __init__.py en cada carpeta creada en modules (incluido los modules ) para evitar problemas de importación.

Si está listo para el trabajo adicional, como se mencionó, siempre puede convertir los módulos en un paquete e instalarlo a través de pip. De esta manera no tiene que preocuparse por el manejo de PATH en absoluto.

La diferencia entre ejecutar su script en Pycharm Eclipse frente a un shell bash es el valor de la variable de entorno $ PYTHONPATH.

En Pycharm, vaya a las preferencias, luego proyecte la configuración del intérprete y desplace el mouse sobre el paquete que no está encontrando en la terminal. La ruta donde se encuentra ese paquete debe presentarse. Eclipse, averigüe dónde se almacenan las variables de entorno de su proyecto, o encuentre la ruta de los módulos en cuestión.

Agregue ese camino a $ PYTHONPATH en su shell con

 PYTHONPATH=$PYTHONPATH:your/path/here 

Puede agregar esa línea a su archivo .bashrc o .bash_profile, puede agregarla a su script de bash, o simplemente puede escribirla cada vez.

Actualización en respuesta al comentario OP:

Use la ruta que apunta al directorio donde están instalados los módulos de Python que no está localizando.

Tratar

 python -v 

En tu consola IDE. Eso debería darle una lista de módulos y sus directorios.

Use el mismo comando en su shell y las diferencias le mostrarán qué falta en dónde.