0

What do I want to do: install a python/cython module exposing a c++ class and being able to cimport it in any .pyx files later.

What does not work: I cannot manage to cimport the file once the module is installed. The cython compilation is working as I can use the wrapped class in pure python.

File structure:

├── cytest
│   ├── cywrappers
│   │   ├── cynode.pxd
│   │   └── cynode.pyx
│   └── hpp
│       └── node.hpp
└── setup.py

node.hpp:

#ifndef graph_HPP
#define graph_HPP
class Node
{
public:
    int ID;
    double value;
    Node(){;};
    Node(int tid, double tvalue)
    {this->ID = tid; this->value = tvalue;}
    void multiplicate(double num){this->value = this->value * num;}
};
#endif

cynode.pxd

cdef extern from "node.hpp":
    cdef cppclass Node:
        Node()
        Node(int tid, double tvalue)
        int ID
        double value
        void multiplicate(double num)

cynode.pyx

cimport cynode
cdef class pynode:
    cdef cynode.Node c_node
    def __cinit__(self, int tid, double tval):
        self.c_node = cynode.Node(tid,tval)
    def print_val(self):
        print("ID: ", self.c_node.ID, "value: ", self.c_node.value)
    def multiplicate(self, mul):
        self.c_node.multiplicate(mul)

and the setup.py:

from setuptools import setup, find_packages, Extension
from Cython.Distutils import build_ext
import numpy as np
setup(
    name = "pycytest",
    packages=find_packages(include=['cytest', 'cytest.*']),
    package_data={'': ['*.pxd', '*.pyx', '*.hpp']},
    zip_safe=False,
    ext_modules=
        [Extension("cytest.cywrappers.cynode", 
         sources = ["cytest/cywrappers/cynode.pyx"], 
         language="c++", extra_compile_args=["-O3", "-std=c++11"],
         include_dirs=["./cytest/hpp/", np.get_include()])],
    cmdclass = {'build_ext': build_ext}
)

I install with pip install . and try to use it in a jupyter notebook (from another location).

import cytest.cywrappers.cynode as cynode
node = cynode.pynode(5, 7.6)
node.print_val()
node.multiplicate(67)
node.print_val()

outputs as it should:

('ID: ', 5, 'value: ', 7.6)
('ID: ', 5, 'value: ', 509.2)

However if I try any of the lines bellow:

%%cython --cplus

# from cytest cimport cywrappers
# cimport cytest
# cimport cynode

I always get a 'XXX.pxd' not found.

Anyone has a solution? I search for quite a long time and I am afraid I am not managing to find the right keywords.

boris
  • 378
  • 1
  • 4
  • 16
  • the name of the extension and of the pyx file should be the same, otherwise pxd cannot be found. – ead Jul 08 '21 at 12:53
  • If this is not a duplicate, edit your question with correct extension name (i.e. `cynode`) and I will reopen it. – ead Jul 08 '21 at 12:58
  • I edited, unfortunately it did not solve the problem – boris Jul 08 '21 at 13:02
  • True, there are more problems: the name of the extension should be `cytest.wrappers.cynode` and you are probably needing `__init__.py` or `__init__.pxd` in folders, otherwise they wont be detected as packages. – ead Jul 08 '21 at 13:10
  • I have to say I struggle a bit to find what to puts in my `__init__.pxd` files. I put an empty one in each folder and it can only `import cytest` now, but nothing else – boris Jul 08 '21 at 13:21
  • Right, I found a solution, writing it now – boris Jul 08 '21 at 14:10

1 Answers1

0

I managed to get it to work:

  • I renamed the extension names to fit the pyx
  • I made sure the pxd imported the hpp in relative import (cdef extern from "../hpp/node.hpp":)
  • Finally, in order to make the package_data to find and include all the files in the repository (needed to reuse the code in later pyx), I added an empty __init__.py in every directories.

Now I can cimport cytest.cywrappers.cynode as cynode.

I tried a lot of things, so all the edits are not relevant but here is a working setup.py:

from setuptools import setup, find_packages, Extension
from Cython.Distutils import build_ext
from Cython.Build import cythonize
import numpy as np

extension = cythonize( [Extension("cytest.cywrappers.cynode", 
         sources = ["cytest/cywrappers/cynode.pyx"], 
         language="c++", extra_compile_args=["-O3", "-std=c++11"],
         include_dirs=["./cytest/hpp/", np.get_include()])], compiler_directives = {"language_level": 3, "embedsignature": True})

setup(
    name = "pycytest",
    packages=find_packages(include=['cytest', 'cytest.cywrappers']),
    package_data={"cytest": ["./*/*.pyx", "./*/*.pxd", "./*/*.hpp" ]},
    zip_safe=False,
    ext_modules=extension
       ,
    cmdclass = {'build_ext': build_ext}

)
boris
  • 378
  • 1
  • 4
  • 16