Изменен размер класса Cython cdef при переносе структуры - PullRequest
0 голосов
/ 28 июня 2019

У меня следующая структура каталогов:

testcython/
    setup.py
    testcython/
        __init__.py
        foo.pyx
        stuff.py
        bar/
            __init__.pxd
            __init__.py
            bar.pxd
            bar.pyx

где содержимое файла выглядит следующим образом:

bar.pxd

cdef struct constants:
    double a
    double b
    double c

cdef class Constants:
    cdef constants consts

bar.pyx

cdef class Constants:
    def __cinit__(self):
        self.consts.a = 1.0
        self.consts.b = 2.0
        self.consts.c = 3.0

    @property
    def a(self):
        return self.consts.a

    @property
    def b(self):
        return self.consts.b

    @b.setter
    def b(self, double value):
        self.consts.b = value
        self.consts.a = self.consts.c / (2.0 * value)

    @property
    def c(self):
        return self.consts.c

foo.pyx

from testcython.bar.bar cimport Constants, constants

cdef do_something_fast(constants* consts):
    return consts.a

cpdef do_something(Constants consts_cls):
    cdef:
        constants* consts = &consts_cls.consts

    return do_something_fast(consts)

stuff.py

from __future__ import print_function

from testcython.bar.bar import Constants
from testcython.foo import do_something

class Thing:
    def __init__(self):
        self.constants = Constants()

def do():
    thing = Thing()
    print(do_something(thing.constants))

setup.py

import os, sys

from Cython.Build import build_ext, cythonize
from setuptools import setup, Extension, find_packages

def ext_modules():
    import numpy as np

    include_dirs = ['.', np.get_include()]
    root_dir = os.path.abspath(os.path.dirname(__file__))
    bar_ext = Extension(
        "bar.bar",
        sources=[root_dir + "/testcython/bar/bar.pyx"],
        include_dirs=include_dirs,
    )
    foo_ext = Extension(
        "foo",
        sources=[root_dir + "/testcython/foo.pyx"],
        include_dirs=include_dirs
    )
    exts = [bar_ext, foo_ext]

    return cythonize(exts, language_level=3, annotate=True)

REQUIREMENTS = [
    "numpy",
    "cython"
]

setup(
    name="testcython",
    packages=find_packages(),
    ext_package="testcython",
    ext_modules=ext_modules(),
    cmdclass={"build_ext" : build_ext},
    zip_safe=False,
    package_data={
        "testcython" : ["bar/*.pxd",]
    },
    install_requires=REQUIREMENTS
)

testcython/__init__.py

from .stuff import do

Вопрос

Это все хорошо, проблема возникает при простом запуске:

import testcython

из среды Python. Это приводит к следующей ошибке:

>>> import testcython
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/path/to/testcython/testcython/__init__.py", line 1, in <module>
    from .stuff import do
  File "/path/to/testcython/testcython/stuff.py", line 6, in <module>
    from testcython.foo import do_something
  File "testcython/bar/bar.pxd", line 6, in init foo
    cdef class Constants:
ValueError: testcython.bar.bar.Constants size changed, may indicate binary incompatibility. Expected 40 from C header, got 16 from PyObject

Это проблема, связанная с попыткой обернуть структуру без указателя на C в классе Constants? Или что-то еще?

...