So this is how I currently structure my files.
CPP Folder
Cython Folder
├── setup.py
└── Geometry
├── Circle
│ ├── __init__.py
│ ├── Circle.pyx
│ ├── Circle.pyi
│ └── Circle.pxd
└── Point
├── __init__.py
├── Point.pyx
├── Point.pyi
└── Point.pxd
And this is my setup.py file
from setuptools import setup, Extension, find_packages
from Cython.Build import cythonize
point_extension = Extension(
"Geometry.Point.Point",
[
"src/Geometry/Point/Point.pyx",
"../cpp/lib/src/Point.cpp"
],
include_dirs=[
"../cpp/lib/include"
],
libraries=["Some Library"],
library_dirs=[
"src/Geometry"
],
extra_compile_args=["-std=c++17", "-O3"],
language="c++"
)
circle_extension = Extension(
"Geometry.Circle.Circle",
[
"../cpp/lib/src/Circle.cpp",
"src/Geometry/Circle/Circle.pyx",
"../cpp/lib/src/Point.cpp"
],
include_dirs=[
"../cpp/lib/include"
],
libraries=["Some Library"],
library_dirs=[
"src/Geometry"
],
extra_compile_args=["-std=c++17", "-O3"],
language="c++"
)
setup(
name="Geometry",
version="0.1",
packages=find_packages(where="src"),
package_dir={"": "src"},
package_data={
"Geometry.Circle": ["*.so", "*.pyi"],
"Geometry.Point": ["*.so", "*.pyi"]
},
ext_modules=cythonize([point_extension, circle_extension],
compiler_directives={"language_level": 3},
include_path=[
"../../Expression/cython/src/Some Library",
"src/Geometry",
],
annotate=True),
zip_safe=False,
)
With this setup, when I want to import Circle or Point for testing, I have to do as below:
from Geometry.Point import Point
from Geometry.Circle import Circle
And my goal is to be able to import them in this way: from Geometry import Circle, Point
So I think I should structure my file as follows:
CPP Folder
Cython Folder
├── setup.py
└── Geometry
├── __init__.py
├── Geometry.pyx
├── Geometry.pyi
├── Geometry.pxd
├── Circle
│ ├── __init__.py
│ ├── Circle.pyx
│ ├── Circle.pyi
│ └── Circle.pxd
└── Point
├── __init__.py
├── Point.pyx
├── Point.pyi
└── Point.pxd
How should I rewrite my setup.py
and write my Geometry.pxd
, .pyx
and .pyi
?
FYI this is a sample of my Point.pxd
and Point.pyx
[Point.pxd]
from libcpp.memory cimport shared_ptr, weak_ptr, make_shared
from Bryan cimport _Bryan, Bryan
cdef extern from "Point.h":
cdef cppclass _Point:
_Point(shared_ptr[_Bryan] x, shared_ptr[_Bryan] y, shared_ptr[_Bryan] z)
shared_ptr[_Bryan] get_x()
shared_ptr[_Bryan] get_y()
shared_ptr[_Bryan] get_z()
cdef class Point:
cdef shared_ptr[_Point] c_point
[Point.pyx]
from Point cimport *
cdef class Point:
def __cinit__(self, Bryan x=Bryan("0", None), Bryan y=Bryan("0", None), Bryan z=Bryan("0", None)):
self.c_point = make_shared[_Point](x.thisptr, y.thisptr, z.thisptr)
def __dealloc(self):
self.c_point.reset()
def get_x(self) -> Bryan:
cdef shared_ptr[_Bryan] result = self.c_point.get().get_x()
cdef Bryan coord = Bryan("", None, make_with_pointer = True)
coord.thisptr = result
return coord
def get_y(self) -> Bryan:
cdef shared_ptr[_Bryan] result = self.c_point.get().get_y()
cdef Bryan coord = Bryan("", None, make_with_pointer = True)
coord.thisptr = result
return coord
def get_z(self) -> Bryan:
cdef shared_ptr[_Bryan] result = self.c_point.get().get_z()
cdef Bryan coord = Bryan("", None, make_with_pointer = True)
coord.thisptr = result
return coord
property x:
def __get__(self):
return self.get_x()
property y:
def __get__(self):
return self.get_y()
property z:
def __get__(self):
return self.get_z()
Thank you
This is a slightly speculative answer simply because I cannot build an example to compile the Cython modules now. I will assume that your setup.py
is successful in compiling the modules.
You are correct with your proposed directory structure, though you really should use lowercase module names. So:
CPP Folder
cython Folder
├── setup.py
└── geometry
├── __init__.py
├── geometry.pyx
├── geometry.pyi
├── geometry.pxd
├── circle
│ ├── __init__.py
│ ├── circle.pyx
│ ├── circle.pyi
│ └── circle.pxd
└── point
├── __init__.py
├── point.pyx
├── point.pyi
└── point.pxd
You will need to change your setup.py
to account for the lowercasing. Once you've done that, you can "hoist" (I don't know if there's a technical term for this) your classes up the directory hierarchy. Then they will be available under the parent (geometry
) namespace
Inside __init__.py
in the geometry
directory, you put:
from .circle import Circle
from .point import Point
The remaining question is whether you even need the other files inside geometry
. Once your Circle
and Point
classes are compiled, I'm not sure what you actually need in the geometry
module to be compiled.