Компиляция файлов pyx с зависимостями в разных пакетах - PullRequest
11 голосов
/ 05 марта 2011

У меня проблемы с компиляцией типов cdef в разных пакетах, и я не могу найти объяснение в документации по Cython.

У меня есть этот setup.py в корне моего дерева Python src:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

setup(
   cmdclass = {'build_ext': build_ext},
   ext_modules = [ 
      Extension("flink.pytk.defs.FragIdx", 
         sources = ["flink/pytk/defs/FragIdx.pyx"]),
      Extension("flink.pytk.fragments.STK_idx", 
         sources = ["flink/pytk/fragments/STK_idx.pyx"])
      ]   
)

FragIdx - это тип cdef-ed, определенный в flink / pytk / defs / FragIdx.pyx:

cdef class FragIdx:
   cdef public FragIdx parent
   cdef public FragIdx root
   cdef public tuple label
   ...

И STK_idx - это расширение FragIdx, определенное в flink / pytk / fragments / STK_idx.pyx:

from flink.pytk.defs.FragIdx import FragIdx
cdef class STK_idx(FragIdx):
   ...

Когда я пытаюсь скомпилировать, используя setup.py, указанный в начале поста, FragIdx компилируется нормально, но когда дело доходит до STK_idx, я получаю следующее сообщение об ошибке:

flink/pytk/fragments/STK_idx.pyx:5:5: 'FragIdx' is not a type name

Обратите внимание, что корневой каталог моего исходного дерева указан в $ PYTHONPATH.

Я был бы очень признателен, если бы кто-нибудь мог пролить свет на это, большое спасибо!

Daniele

1 Ответ

10 голосов
/ 05 марта 2011

О, ну, для тех, у кого похожая проблема, похоже, что я нашел ответ.

Я ожидал, что python автоматически просканирует символы, скомпилированные в общей библиотеке FragIdx.so, вместо этого похоже, что эта информация должна быть явно предоставлена ​​в виде файла .pxd (который становится файлом заголовка C после запуска Cython).

Процесс состоит в основном из двух этапов:

  1. Создание файла определения (.pxd) для суперкласса;
  2. Импорт определения суперкласса через cimport (в отличие от import) в модуле подкласса.

Итак, чтобы сделать его более общим.

Предположим, что вы определили тип cdef-ed A в модуле pkg1.mod1. Затем вы определяете тип B в pkg2.mod2, который подклассы A.

Ваша структура каталогов будет выглядеть примерно так:

pkg1/
  mod1.pyx
  mod1.pxd
pkg2/
  mod2.pyx
  mod2.pxd

В pkg1/mod1.pxd вы бы сказали:

cdef class A:
  cdef int a
  cdef int b

А в pkg1/mod1.pyx вы предоставляете методы вашего класса. В pkg2/mod2.pxd вы получите:

from pkg1.mod1 cimport A  #note "cimport"!!
cdef class B(A):
  cdef ... # your attributes here

И снова, в pkg2/mod2.pyx вам нужно будет снова cimport символ A:

from pkg1.mod1 cimport A #note "cimport"!!
cdef class B(A):
  ... # your methods here

Интересно, что если вы просто хотите использовать A в своем коде Python, а не использовать его для определения подтипа, файл определений mod1.pxd не нужен. Это связано с тем, что при создании типа расширения необходимо, чтобы определения были доступны для компилятора C, тогда как у вас нет этой проблемы при запуске кода Python, но, поскольку он не очень интуитивен, возможно, важно указать его вне.

Эта информация фактически доступна в документах Cython , хотя, возможно, она может быть немного более явной.

Надеюсь, что эта информация может кому-то спасти.

...