【问题标题】:A package which calls a C function from a subdirectory从子目录调用 C 函数的包
【发布时间】:2018-02-15 00:48:46
【问题描述】:

我在构建包含具有 C 函数的子包的包时遇到问题。我已经建立了一个测试用例来说明它。

目录树是:

README.rst
MANIFEST.in
setup.py
testcase/
  get_triple.py
  __init__.py
  spin/
    __init__.py
    setup.py
    spin.c
    spin.h

这是文件的内容。首先在testcase目录中。

get_triple.py:

import spin
print "here is the spin dir"
print dir(spin)

def get_triple(number):

    """ triple that number with a C func """

    new_number = spin.make_that_triple(number)

    return new_number

__init__.py:

from .get_triple import *

setup.py:

from setuptools import setup

def readme():
    with open('README.rst') as f:
        return f.read()

setup(name='testcase',
    version='0.1',
    description='test the C function called from a package',
    classifiers=[
        'Development Status :: 0 - Alpha',
        'License :: Friand_Dur',
        'Programming Language :: Python :: 2.7',
        'Topic :: Scientific/Engineering :: Bio-Informatics',
    ],
    author='test',
    author_email='test',
    license='test',
    package_dir = {
        'testcase': 'testcase',
        'testcase.spin': 'testcase/spin',
    },
    packages=['testcase', 'testcase.spin'],
    install_requires=[
        # nothing, it's a test
    ],
    zip_safe=False)

并且来自 spin 目录。

spin.c:

#include <stdio.h>
#include <stdlib.h>
#include <python2.7/Python.h>
#include <math.h>
#define PY_ARRAY_UNIQUE_SYMBOL get_spinangle_traj_ARRAY_API
/* This one makes the compilation crash if not commented, despite the warning message if it is */
//~ #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include "numpy/arrayobject.h"
/* Not typecasting anything */
#include "spin.h"

/* Docstring */
static char module_docstring[] =
    "triple using C";
static char make_that_triple_docstring[] =
    "triple using C";

static PyObject *make_that_triple(PyObject *self, PyObject *args){

    /* Just get a number */
    int number;
    double tripled_number = 0.0;

    /* Should get the python objects */
    if (!PyArg_ParseTuple(args,"i",&number)){
        PyErr_SetString(PyExc_ValueError,"Error while parsing the trajectory coordinates in get_spinangle_traj");
        return NULL;
    }

    /* Call the external C function to get the triple */
    tripled_number = tripleeee(number);

    PyObject *ret = Py_BuildValue("d", tripled_number);
    return ret;
}

double tripleeee(int number){

    return number * 3;

}

static PyMethodDef module_methods[] = {
    {"make_that_triple",make_that_triple,METH_VARARGS,make_that_triple_docstring},
    {NULL,NULL,0,NULL}
};

PyMODINIT_FUNC initspin(void)
{
    PyObject *m = Py_InitModule3("spin",module_methods,module_docstring);
    if (m == NULL)
        return;
    /* Load Numpy */
    import_array();
}

spin.h:

static PyObject *make_that_triple(PyObject *self, PyObject *args);
double tripleeee(int number);

setup.py:

from distutils.core import setup, Extension
import numpy.distutils.misc_util

setup(
    ext_modules=[Extension("spin", ["spin.c"])],
    include_dirs=numpy.distutils.misc_util.get_numpy_include_dirs(),
)

__init__.py 是空的。

我首先在spin子目录中使用python setup.py build_ext --inplace编译C包,然后使用sudo python setup.py install编译主包。

我还有一个测试脚本:

#!/usr/bin/python
# -*- coding: utf-8 -*-
import testcase
print "here is the testcase dir"
print dir(testcase)

# Let's multiply this by 3
number = 25

new_number = testcase.get_triple(number)

print new_number

哪个...不起作用:

here is the spin dir
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__']
here is the testcase dir
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', 'get_triple', 'spin']
Traceback (most recent call last):
  File "./spindihed_totable_pl60.py", line 17, in <module>
    new_number = testcase.get_triple(number)
  File "/usr/local/lib/python2.7/dist-packages/testcase-0.1-py2.7.egg/testcase/get_triple.py", line 9, in get_triple
    new_number = spin.make_that_triple(number)
AttributeError: 'module' object has no attribute 'make_that_triple'

它无法从testcase 包中访问spin 中的C 函数,即使其中的spin 确实存在,而且我已经在这一步卡住了一段时间。当我 cd 进入 spin 子目录时,我可以使用 C 函数,这似乎告诉我这不是 C 问题:

>>> import spin
>>> print spin.make_that_triple(3)
9.0

我错过了什么?我觉得我错过了一些非常基本的东西。 我还将所有内容都放在了 git 上,以使测试更容易:https://github.com/msidore/testcase

感谢您的帮助

【问题讨论】:

    标签: python python-2.7 python-c-extension python-packaging


    【解决方案1】:

    这里有一些问题。构建--inplace后,你在testcase/spin/spin.so中创建了一个扩展模块,所以对应的模块是testcase.spin.spin

    >>> import testcase.spin.spin
    >>> dir(testcase.spin.spin)
    ['__doc__', '__file__', '__name__', '__package__', 'make_that_triple']
    

    但是由于您的顶级setup.py 不知道扩展模块,因此如果您python setup.py install 将不会安装它。我建议重新安排这样的事情:

    setup.py
    testcase/get_triple.py
    testcase/__init__.py
    testcase/spin.c
    testcase/spin.h
    

    并修改您的顶级setup.py,使其了解扩展模块:

    from setuptools import setup, Extension
    import numpy.distutils.misc_util
    
    setup(name='testcase',
          packages=['testcase'],
          ext_modules=[Extension("testcase.spin", ["testcase/spin.c"])],
          include_dirs=numpy.distutils.misc_util.get_numpy_include_dirs(),
          zip_safe=False)
    

    有了这些变化,我可以:

    virtualenv .venv
    . .venv/bin/activate
    pip install numpy
    pip install .
    python testscript.py
    

    我从testscript.py 得到输出:

    here is the spin dir
    ['__doc__', '__file__', '__name__', '__package__', 'make_that_triple']
    here is the testcase dir
    ['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', 'get_triple', 'spin']
    75.0
    

    【讨论】:

    • 非常感谢,它成功了!我想我理解了我的问题(在此过程中也制造了一些奇怪的东西,我必须在让它工作之前手动将其删除)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-24
    • 1970-01-01
    • 1970-01-01
    • 2012-10-28
    • 1970-01-01
    相关资源
    最近更新 更多