2011-03-04 16 views
8

Tengo algunos problemas para estructurar mi proyecto python. Actualmente es un grupo de archivos en la misma carpeta. He tratado de estructurarlo comoPruebas y estructura de paquete python

proj/ 
    __init__.py 
    foo.py 
    ... 
    bar/ 
    __init__.py 
    foobar.py 
    ... 
    tests/ 
    foo_test.py 
    foobar_test.py 
    ... 

El problema es que no soy capaz, desde los directorios internos, para importar los módulos de los directorios exteriores. Esto es particularmente molesto con las pruebas.

He leído PEP 328 sobre importaciones relativas y PEP 366 sobre importaciones relativas desde el módulo principal. Pero ambos métodos requieren que el paquete base esté en mi PYTHONPATH. De hecho obtengo el siguiente error

ValueError: Attempted relative import in non-package.

por lo que añade el siguiente código repetitivo en la parte superior de los archivos de prueba

import os, sys 
sys.path.append(os.path.join(os.getcwd(), os.path.pardir)) 

Todavía me sale el mismo error. ¿Cuál es la forma correcta de

  • estructura de un paquete, con pruebas, y
  • añadir el directorio base a la ruta para permitir la importación?

EDITAR a lo solicitado en el comentario, añado una importación ejemplo que falla (en el archivo de foo_test.py)

import os, sys 
sys.path.append(os.path.join(os.getcwd(), os.path.pardir)) 
from ..foo import Foo 
+0

¿Puedes mostrar un ejemplo de importación que falla? –

+0

Además, incluya el valor de su 'PYTHONPATH' –

+0

' echo $ PYTHONPATH' solo está vacío en este momento. – Andrea

Respuesta

12

Cuando utiliza el modificador -m para ejecutar código, el directorio actual se agrega al sys.path. Así que la forma más fácil de ejecutar las pruebas es del directorio padre de proj, usando el comando:

python -m proj.tests.foo_test 

Para hacer que el trabajo, tendrá que incluir un archivo __init__.py en el directorio de pruebas para que las pruebas son correctamente reconocido como parte del paquete.

+0

¡Gracias! Entonces, lo que me faltaba era que 'tests 'en sí misma debería ser un paquete. Fue un error bastante estúpido, pero no pude entenderlo. – Andrea

5

me gusta para importar módulos utilizando el paquete proj.NAME prefijo completo siempre que sea posible. Este es el enfoque que recomienda el Google Python styleguide.

Una opción que le permite mantener su estructura de paquetes, utilice las rutas de paquetes completos, y aún así seguir adelante con el desarrollo sería utilizar un virtualenv y poner su proyecto en modo de desarrollarse. El proyecto setup.py deberá usar setuptools en lugar de distutils, para obtener el comando develop.

Esto le permitirá evitar la sys.path.append cosas arriba:

% virtualenv ~/virt 
% . ~/virt/bin/activate 
(virt)~% cd ~/myproject 
(virt)~/myproject% python setup.py develop 
(virt)~/myproject% python tests/foo_test.py 

Dónde foo_test.py utiliza:

from proj.foo import Foo 

Ahora cuando se ejecuta python desde dentro de su virtualenv su PYTHONPATH apuntará a todos los paquetes en tu proyecto Puede crear un alias de shell más corto para ingresar su virtualenv sin tener que escribir . ~/virt/bin/activate cada vez.

+0

Parece interesante. Tendré que investigar esta herramienta virtualenv. ¿Me permite trabajar en un entorno virtual en el que puedo tener acceso al directorio actual como un paquete? ¿O es simplemente una herramienta con una distribución de Python aislada, más parecida a un chroot, donde tengo que instalar mi paquete cada vez que lo uso? – Andrea

+0

Es una forma rápida de crear un entorno de Python aislado que puede volar y recrear rápidamente. Bueno para probar módulos usando pip/easy_install sin contaminar su sistema Python. El script virtualenv 'activate' inserta el directorio' ~/virt/bin' al frente de su 'PATH' para que' ~/virt/bin/python' se encuentre antes del sistema python. El comando 'develop' vincula los paquetes de su proyecto en' ~/virt/lib/pythonx.x/site-packages' utilizando un archivo '.pth'. También modifica el mensaje 'PS1' para que sepas que estás" dentro "del virtualenv. – samplebias

+0

Un buen consejo, aunque en estos días es posible que desee elegir 'distribute' como una alternativa mantenida de forma más activa a' setuptools'. – ncoghlan

Cuestiones relacionadas