¿Qué más puedo hacer para solucionar problemas de un paquete que no se está importando en Python pero que se importa en ipython mientras que en un virtualenv?

Soy un entusiasta de Python que decidió tomarme en serio la creación de algunos de mis propios paquetes reutilizables.

Sinopsis de mi problema:

  1. Al llamar a python test_dummy.py no se puede importar un paquete eforest . Se lanza un ImportError.
  2. import eforest en el intérprete de python y en el intérprete de ipython no arrojan excepciones.
  3. Al llamar a run test_dummy.py dentro del intérprete de ipython no se produce ninguna excepción.
  4. Todos los casos se ejecutan dentro de un virtualenv.

virtualenv no tiene nada que ver con mi problema. He publicado una nueva pregunta: el script que agrega paquetes a sys.path se importa como se espera cuando se ejecuta desde ipython, pero lanza una excepción cuando el script se ejecuta desde python

Una pregunta similar está en No se puede importar el paquete desde virtualenv

Leí la documentación en virtualenv y virtualenvwrapper y los instalé en un sistema Ubuntu 14.04.1 LTS con Python 2.7.6.

He creado un virtualenv:

 mkvirtualenv module_troubleshooting -a . -r requirements.txt 

Mi archivo Requirements.txt contenía:

 Django==1.6.6 EasyProcess==0.1.6 PyVirtualDisplay==0.1.5 South==1.0 argparse==1.2.1 ipython==2.2.0 lxml==3.3.5 selenium==2.42.1 wsgiref==0.1.2 

workon module_troubleshooting mi virtualenv con workon module_troubleshooting

Mi virtualenv estaba activo: (module_troubleshooting)dmmmd@ubuntuG5:

Entendí de la documentación de virtualenvwrapper que podía agregar paquetes a sys.path mediante el comando add2virtualenv .

Usando add2virtualenv agregué mis paquetes muy simples que había creado. Verifiqué que, efectivamente, el archivo pth contenía esos paquetes.

 /home/dmmmd/development/python/singleton /home/dmmmd/development/python/display /home/dmmmd/development/python/browser /home/dmmmd/development/python/eforest /home/dmmmd/development/python/dummy 

Corrí ipython para ver si podía importar esos paquetes. Yo podría. Sin errores. El examen de sys.path en ipython reveló que las rutas anteriores estaban presentes.

Para mi propia edificación hice el siguiente módulo llamado test_dummy.py:

 import browser import display import singleton import eforest 

Ejecuté el siguiente comando en ipython : run test_dummy.py .

No hay excepciones en ipython .

Luego salí de ipython y ejecuté el siguiente comando para asegurarme de que NO se estaba llamando a python global y para ver si python ejecutaría el script: /home/dmmmd/.virtualenvs/module_troubleshooting/bin/python test_dummy.py

 Traceback (most recent call last): File "tests/test_dummy.py", line 4, in  import eforest ImportError: No module named eforest 

Otros tres paquetes, el navegador, la pantalla y el singleton se importaron como se esperaba y la excepción se lanzó al importar bosque

Al principio, teoricé que eforest podría contener alguna excepción. Así que ejecuté /home/dmmmd/.virtualenvs/module_troubleshooting/bin/python y tuve un mensaje esperado y no hubo errores de importación al importar el bosque:

 Python 2.7.6 (default, Mar 22 2014, 22:57:26) [GCC 4.8.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import eforest >>> print eforest  >>> 

Entonces teoricé que el sys.path para ipython y python podría ser diferente. Guardé el archivo sys.path para python en un archivo y lo sys.path a lo siguiente para que la lista de sys.path pudiera importarse:

 /home/dmmmd/.virtualenvs/module_troubleshooting/bin/python -c "import sys; print sys.path" > path.py 

Edité path.py para que from path import path sea ​​la lista sys.path desde que se llame a /home/dmmmd/.virtualenvs/module_troubleshooting/bin/python .

Luego ejecuté ipython y escribí los siguientes comandos:

 In [1]: from path import path In [2]: path # this is the sys.path from calling /home/dmmmd/.virtualenvs/module_troubleshooting/bin/python Out[2]: ['', '/home/dmmmd/development/python/singleton', '/home/dmmmd/development/python/eforest', '/home/dmmmd/development/python/dummy', '/home/dmmmd/development/python/display', '/home/dmmmd/development/python/browser', '/home/dmmmd/.virtualenvs/module_troubleshooting/lib/python2.7', '/home/dmmmd/.virtualenvs/module_troubleshooting/lib/python2.7/plat-powerpc-linux-gnu', '/home/dmmmd/.virtualenvs/module_troubleshooting/lib/python2.7/lib-tk', '/home/dmmmd/.virtualenvs/module_troubleshooting/lib/python2.7/lib-old', '/home/dmmmd/.virtualenvs/module_troubleshooting/lib/python2.7/lib-dynload', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-powerpc-linux-gnu', '/usr/lib/python2.7/lib-tk', '/home/dmmmd/.virtualenvs/module_troubleshooting/local/lib/python2.7/site-packages', '/home/dmmmd/.virtualenvs/module_troubleshooting/lib/python2.7/site-packages'] 

Para ver si el sys.path de sys.path era diferente, sys.path :

 In [5]: import sys In [6]: len(sys.path) Out[6]: 19 In [7]: len(path) Out[7]: 16 In [8]: [item for item in sys.path if item not in path] Out[8]: ['/home/dmmmd/.virtualenvs/module_troubleshooting/bin', '/home/dmmmd/.virtualenvs/module_troubleshooting/local/lib/python2.7/site-packages/IPython/extensions', '/home/dmmmd/.ipython'] 

Los dos últimos elementos de sys.path de ipython están relacionados con ipython . El único elemento diferente es ‘/home/dmmmd/.virtualenvs/module_troubleshooting/bin’.

¿Alguien puede ofrecer algún otro consejo de resolución de problemas o explicarme cómo tener ‘/home/dmmmd/.virtualenvs/module_troubleshooting/bin’ en la ruta sys.path en ipython permite que eforest se importe como se espera en ipython cuando se run test_dummy.py ?

paquete de eforest:

 eforest/ ├── CustomElementFilters.py ├── CustomEtrees.py ├── CustomEtrees.pyc ├── __init__.py └── __init__.pyc 

Nuevamente, eforest importa como se esperaba en ipython y con el intérprete de python, pero no se importa cuando un script pasa como argumento a /home/dmmmd/.virtualenvs/module_troubleshooting/bin/python test_dummy.py .

La única excepción posible a eforest que me parece que es diferente de los otros paquetes es que importa lxml. ¿Podría lxml depender de alguna manera de tener ‘/home/dmmmd/.virtualenvs/module_troubleshooting/bin’ en el sys.path?

Cualquier sugerencia para la solución de problemas sería muy apreciada. Noté el problema por primera vez cuando estaba usando py.test. Pensé que tenía algo que ver con py.test, pero al final resultó que los scripts de prueba que estaba escribiendo tampoco se ejecutaban con python. Decidí detenerme allí y ver si podía obtener ayuda.

Descartado virtualenv como una fuente de problemas

python test_dummy.py el siguiente script con python test_dummy.py con virtuenv desactivado .

 import sys import os HOME = os.path.expanduser('~') PYTHON = os.path.join(HOME, 'development/my_python') PACKAGES = [ 'browser', 'display', 'singleton', 'eforest' ] for package in PACKAGES: package = os.path.join(PYTHON, package) if os.path.exists(package) is True: if package not in sys.path: print "loading package '{0}'".format(package) sys.path.append(package) else: print "package '{0}' already in sys.path".format(package) else: raise import browser import display import singleton import eforest 

Con el virtualenv desactivado, eforest es el único paquete que no se importa al ejecutar el comando python test_dummy.py .

Resultado:

 Traceback (most recent call last): File "my_django/automated_browsing/tests/test_dummy.py", line 16, in  import eforest ImportError: No module named eforest 

Encontré una solución, aunque la solución no resuelve el problema de por qué ciertas rutas de paquetes agregadas de manera ad hoc a sys.path no se importan cuando el script se ejecuta con python test_dummy.py .

Originalmente me encontré con este problema al intentar usar py.test. En la documentación de py.test, he visto esta sugerencia sobre “administrar su proyecto con virutalenv, pip y el modo editable”. Lo ignoré porque pensé que era demasiado avanzado para mi nivel de conocimiento de Python.

Decidí probar la sugerencia después de leer sobre ” crear tu propio proyecto en Python “.

En el pwd creé un archivo setup.py con el siguiente código:

 from setuptools import setup, find_packages setup(name='import_troubleshooting', version='1.0') packages = find_packages(exclude=[ 'my_django', 'fake*', 'tests*' ]) 

Luego ejecuté el siguiente código en la línea de comando:

 pip install -e . # the pip way (which just calls "setup.py develop") 

Luego ejecuté el siguiente código con los resultados esperados:

 $ python tests/test_dummy.py # output package '/home/dmmmd/development/my_python/browser' already in sys.path package '/home/dmmmd/development/my_python/display' already in sys.path package '/home/dmmmd/development/my_python/singleton' already in sys.path loading package '/home/dmmmd/development/my_python/test_a' loading package '/home/dmmmd/development/my_python/hello_world' loading 'browser' loading 'display' loading 'singleton' loading 'test_a' loading 'hello_world.hello' Hello, world! 

Nada de esto me explica por qué no pude agregar las rutas del paquete de manera ad hoc . Sin embargo, me complace haber aprendido algo sobre la instalación y el empaquetado de Python. La test_dummy.py comandos test_dummy.py ahora se ejecuta como se espera cuando se llama desde python tests/test_dummy.py .

Ahora estoy confundido sobre por qué tres de los paquetes ya están en sys.path cuando se test_dummy.py script test_dummy.py :

 package '/home/dmmmd/development/my_python/browser' already in sys.path package '/home/dmmmd/development/my_python/display' already in sys.path package '/home/dmmmd/development/my_python/singleton' already in sys.path 

No recuerdo haber hecho nada que los agregue a sys.path pero es posible ya que he estado haciendo varios tutoriales. No están en sys.path en ningún otro entorno donde no haya ejecutado el setup.py que creé.

Mi confusión es un síntoma de la complejidad de Python, ¡no una causa!

Gracias por el aporte de todos.

NB: Esta es la salida de python test_dummy.py después de un virtualenv nuevo:

 $ pip install -e . # install output unremarkable $ python tests/test_dummy.py # output loading package '/home/dmmmd/development/my_python/automated_browsing/browser' loading package '/home/dmmmd/development/my_python/automated_browsing/display' loading package '/home/dmmmd/development/my_python/automated_browsing/singleton' loading package '/home/dmmmd/development/my_python/automated_browsing/hello_world' loading package '/home/dmmmd/development/my_python/automated_browsing/test_a' loading 'browser' loading 'display' loading 'singleton' loading 'hello_world.hello' Hello, world! loading 'test_a'