Chris
Chris

Reputation: 31216

Import Cython class in Python file Pycharm

How does one import a compiled cython file in a pycharm python file?

Here is my setup.

From my project root directory, the cython class is "/classes/knn.cpython-35m-x86_64-linux-gnu.so." My python file is "/classes/testing_cython_knn.py."

I have an "__init __.py" file in "/classes/"...


However, Pycharm does not recognize the ".so" file as a file which I can import. What do I need to do in order to make this file available to import, so I can test it?


Currently, I have successfully compiled and imported a "helloworld.so" file in regular, terminal-based python...however, the function I defined was a pythonic function...no C-stuff.

My Cythonic file is:

import numpy as np
cimport numpy as np


from scipy.stats import mode
from scipy.spatial.distance import cdist
from threading import Thread



cdef class KNN:
    cdef public int k
    cdef public str metric
    cdef public np.ndarray trainingX
    cdef public np.ndarray trainingY
    cdef public np.ndarray predict(self,np.ndarray X):
        cdef np.ndarray distances,predicted_classes,sorted_distance_indices

        distances = cdist(X,self.trainingX,metric=self.metric)
        predicted_classes = np.zeros(X.shape[0],dtype=np.float64)
        sorted_distance_indices = np.argpartition(distances,self.k,axis=1)[:,:self.k]
        predicted_classes,_ = mode(self.trainingY[sorted_distance_indices])
        return predicted_classes

And setup.py:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
import numpy


extensions = [
    Extension("knn",["cKNN.pyx"]),
    Extension("*",["*.pyx"],include_dirs=[numpy.get_include()])]

setup(ext_modules = cythonize(extensions),include_dirs=[numpy.get_include()])

Currently, this fails on import to python running on the terminal with an Import Error:

Dynamic module does not define module export function (PyInit_knn)

Upvotes: 1

Views: 3191

Answers (1)

bio_c
bio_c

Reputation: 321

The first thing I notice is that you are renaming your extension. For Cython, the name of the extension must correspond with the name of the file to compile. That should fix the

Dynamic module does not define module export function (PyInit_knn)

Second, you are declaring two extensions, but you have only one file (wich needs Numpy) so you should either remove the first extension completely (the * will take care of all the .pyx files in the folder) or remove the second and integrate the 'include_dirs' directive to the first extension, so you should change your extensions list to:

extensions = [
    Extension("cKNN",["cKNN.pyx"],include_dirs=[numpy.get_include()])]

If you use --inplace or if you move the .so file to the right place, it will be imported. Pycharm has nothing to do there, it is all up to Cpython, but, in your setup.py, you have to be careful about setting the paths properly. If your project's folder structure is like:

- knnProject (this opens in Pycharm) 
- - knnextension
- - - classes
- - - - __init__.py
- - - - cKNN.pyx
- - - __init__.py (this is required to do module import from /classes)
- - setup.py
- - test.py

Your extension should say:

extensions = [
        Extension("knnextension/classes/cKNN",["knnextension/classes/cKNN.pyx"],include_dirs=[numpy.get_include()])]

The shared library file (.so or .pyd) will show up (by using --inplace) inside /classes. In the classes/__init__.py file you can import the class with:

from .cKNN import KNN

and then from test.py:

from knnextension.classes import KNN

Check other working cython extensions, like my own, to see how the structure might be (that one uses Numpy too).

Upvotes: 3

Related Questions