Paquete Cython con init.pyx: Posible?


¿Es posible crear un paquete Python 2.7 usando __init__.pyx (compilado a __init__.so)? Si es así, ¿cómo? No he tenido suerte de hacerlo funcionar.

Esto es lo que he intentado:

  • setup.py:

    #!/usr/bin/env python
    
    from distutils.core import setup
    from distutils.extension import Extension
    from Cython.Distutils import build_ext
    
    foo = Extension(name='foo.__init__', sources=['foo/__init__.pyx'])
    bar = Extension(name='foo.bar', sources=['foo/bar.pyx'])
    
    setup(name='foo',
          packages = ['foo'],
          cmdclass={'build_ext':build_ext},
          ext_modules = [foo, bar])
    
  • foo/__init__.pyx:

    import foo.bar
    
    cpdef hello_world():
        print "hello world"
        foo.bar.blah()
    
  • foo/bar.pyx:

    cpdef blah():
        print "blah"
    

Lo anterior tiene el siguiente comportamiento:

$ python -c 'import foo; foo.hello_world()'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: No module named foo

Vi el problema de Python #15576que fue corregido por este commit de Hg. Mirando a la equivalente Git commiten el Git mirror del repositorio Python Hg, veo que el commit es accesible desde la etiqueta Python v2.7.5 (así como todos los v2.7 posteriores.x versiones). Hubo una regresión?

Author: Richard Hansen, 2015-02-01

2 answers

De acuerdo con este post de lista de correo realmente antiguo funciona si también tiene un archivo __init__.py (el archivo __init__.py no se usa, pero parece ser necesario para que el directorio se trate como un módulo, y por lo tanto el archivo __init__.so se cargue).

Si añado __init__.py:

# an exception just to confirm that the .so file is loaded instead of the .py file
raise ImportError("__init__.py loaded when __init__.so should have been loaded")

Entonces su ejemplo funciona en Linux Python 2.7.3:

$ python -c 'import foo; foo.hello_world()'
hello world
blah

Esto tiene todos los signos de una caja de esquina con errores, por lo que probablemente no se recomienda. Tenga en cuenta que en Windows esto no parece funcionar para mí dando

ImportError: DLL load failed: %1 is not a valid Win32 application.

Addendum (para un poco más de contexto):

Este comportamiento no parece estar explícitamente documentado. En la descripción original de los paquetes de alrededor de la era Python 1.5 dicen:

Sin el __init__.py, un directorio no se reconoce como un paquete

Y

Consejo: el orden de búsqueda está determinado por la lista de sufijos devueltos por la función imp.get_suffixes(). Generalmente los sufijos son buscado en el siguiente orden:". so", "module.so",". py",".pyc". Los directorios no aparecen explícitamente en esta lista, pero preceden a todas las entradas en ella.

El comportamiento observado es ciertamente consistente con esto - __init__.py necesario para tratar un directorio como un paquete, pero el archivo .so se carga con preferencia al archivo .py - pero no es inequívoco.

Desde el punto de vista de Cython, este comportamiento parece haber sido utilizado para compilar la biblioteca estándar (en cuyo caso __init__.py siempre han estado presentes), o en los casos de prueba dados https://github.com/cython/cython/blob/master/tests/build/package_compilation.srctree (y algunos otros ejemplos también). En estos, el archivo" srctree " parece expandirse en una variedad de carpetas que contienen __init__.py (y otros archivos) luego compilados. Es posible que solo tener __init__.so simplemente nunca fue probado.

 14
Author: DavidW,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-19 07:58:11

Intente usar una importación relativa.

En __init__:

from . import bar

También podría ser from . import foo. No he usado Python 2 Cython en un tiempo.

 -3
Author: Berserker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-14 23:24:14