Soy un entusiasta de Python que decidió tomarme en serio la creación de algunos de mis propios paquetes reutilizables.
Sinopsis de mi problema:
python test_dummy.py
no se puede importar un paquete eforest
. Se lanza un ImportError. import eforest
en el intérprete de python y en el intérprete de ipython no arrojan excepciones. run test_dummy.py
dentro del intérprete de ipython no se produce ninguna excepción. 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.
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.
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'