python build py.test

python - Usando py.test con código de biblioteca compilado



main python (2)

Creo que su problema es simplemente que py.test no está copiando el objeto compartido creado en la raíz de su repositorio.

Intenté ejecutar el UT directamente desde la wiki de Python al probar las extensiones C utilizando py.test de la siguiente manera:

python setup.py build py.test test/examp_unittest.py

Esto falló con AssertionError: No module named examp .

Sin embargo, cuando sigo la wiki a la letra (y python setup.py test lugar), observo que copia el .so al directorio raíz (tenga en cuenta la última línea antes de que comience a ejecutar la prueba):

running test running egg_info writing examp.egg-info/PKG-INFO writing top-level names to examp.egg-info/top_level.txt writing dependency_links to examp.egg-info/dependency_links.txt reading manifest file ''examp.egg-info/SOURCES.txt'' writing manifest file ''examp.egg-info/SOURCES.txt'' running build_ext copying build/lib.linux-x86_64-2.6/examp.so -> runTest (test.examp_unittest.DeviceTest) ... ok ---------------------------------------------------------------------- Ran 1 test in 0.001s OK

Habiendo ejecutado eso en mi sistema, ahora puedo ejecutar py.test con bastante satisfacción en la misma base de código, como se muestra a continuación.

============================= test session starts ============================== platform linux2 -- Python 2.7.3, pytest-2.9.2, py-1.4.31, pluggy-0.3.1 rootdir: /tmp/sotest, inifile: collected 1 items test/examp_unittest.py . =========================== 1 passed in 0.01 seconds ===========================

La solución es, por lo tanto, copiar su objeto compartido a la raíz de su repositorio.

Para asegurarme de haber ejecutado todo desde cero, simplemente construyendo la extensión, copiando el objeto compartido y luego ejecutando py.test. Todo esto funciona como se esperaba.

Tengo una biblioteca de Python con la siguiente estructura de repositorio:

repobase |- mylibrary | |- __init__.py |- tests |- test_mylibrary.py

Hasta ahora, ejecutar las pruebas simplemente podía hacerse llamando a py.test en el directorio repobase. La import mylibrary en test_mylibrary.py luego usó el código local en repobase / mylibrary .

Ahora, extendí la biblioteca para usar código compilado. Por lo tanto, el código fuente de repobase / mylibrary no funciona por sí solo. Tengo que hacer una setup.py build . Esto crea repobase / build / lib.linux-x86_64-2.7 / mylibrary .

¿Hay alguna manera razonable de hacer py.test use este directorio para importar mylibrary? Dadas estas limitaciones:

  1. No quiero incluir ninguna magia sys.path / import en test_mylibrary.py porque esto puede romper las pruebas en otros entornos.

  2. No quiero renunciar a la posibilidad de ejecutar py.test desde repobase . Por lo tanto, la modificación de PYTHONPATH no ayuda porque . seguirá siendo el primero en sys.path . Y, por lo tanto, se favorecería a repobase / mylibrary sobre repobase / build / lib.linux-x86_64-2.7 / mylibrary .

De lo contrario, ¿cuál es la forma estándar de probar las bibliotecas de Python, que necesitan ser compiladas?


A partir de la discusión en el chat, parece que la implementación de C solo proporciona un subconjunto de la funcionalidad de la implementación de Python.

Una solución común es dividir el módulo de modo que las partes que requieren implementaciones optimizadas existan en un módulo separado.

Considere un ejemplo más concreto de una biblioteca que necesita convertir entre diferentes formatos de imagen.

Supongamos que su diseño se ve así ...

repobase |- image | |- __init__.py | |- pyJPEG.py |- build | |- lib.linux-x86_64-2.7 | |- cJPEG.so |- tests |- test_image.py

... su PYTHONPATH incluye /path/to/repobase:/path/to/repobase/build/lib.linux-x86_64-2.7 , su cJPEG.so exporta símbolos jpeg_decompress y jpeg_compress , y sus archivos se ven así ...

image / __ init__.py

# Load the C implementation if we have it, otherwise fall back to # a pure Python implementation try: from cJPEG import jpeg_decompress, jpeg_compress except ImportError: from pyJPEG import jpeg_decompress, jpeg_compress def load_image(filename): data = open(filename, ''rb'').read() if filename.endswidth(''.jpg''): return jpeg_decompress(data) else: raise NotImplementedError def save_image(data, filename, filetype=''JPEG''): if filetype == ''JPEG'': data = jpeg_compress(data) else: raise NotImplementedError open(filename, ''wb'').write(data)

image / pyJPEG.py

def jpeg_decompress(data): # A pure Python implementation of a JPEG decoder def jpeg_compress(data): # A pure Python implementation of a JPEG encoder

Con este tipo de diseño, al conjunto de pruebas no le importa si la biblioteca está construida o no: puede usar el mismo paquete en ambos casos, y la presencia (o ausencia) de cJPEG.so determinará qué versión se prueba.