How to package a Python C Extension such that it is a submodule of a normal Python module? [duplicate]
Asked Answered
S

1

0

I wrote a python library with two parts:

  1. A Python C extension
  2. A Python wrapper for the Python C extension

I would like to be able to package it in such a way that the Python wrapper is the top level module foo and the Python C extension is a submodule located at foo._foo. However I have so far only been able to create two top level modules, foo and _foo.

What do I need to do in setup.py and in the init_foo C function in order to accomplish this?

(My question is subtlety different from this)


Current directory structure:

foo/
    foo/
        __init__.py
    foo.c
    setup.py
    tests.py

setup.py looks something like:

from distutils.core import setup, Extension

module = Extension('_foo',
                   sources=['foo.c'])

setup(name='foo', packages=['foo'], ext_modules=[module])

foo.c looks something like:

PyMODINIT_FUNC init_foo(void) {
    PyObject *m;
    m = Py_InitModule("_foo", FooMethods);
    // ..
}
int main(int argc, char *argv[]) {
    Py_SetProgramName(argv[0])
    Py_Initialize();
    init_pychbase();
}

foo/__init__.py looks something like:

from _foo import _Foo, _Bar, _Baz

class Foo(object):
    def __init__(self):
        self._foo = _Foo()
Suspiration answered 5/2, 2017 at 4:4 Comment(2)
@MatthewMoisen You said "(My question is subtlety different from this)" could you explain why?Cohberg
@Cohberg after taking another go at it, I now realize it wasn't different enough to warrant a new question. (The difference is that I want my c extension one level deep, whereas the OP wanted his two levels deep). My issue was that my tests.py file was located in the same directory as the foo module so the imports were off when I ran it. Creating a tests/tests.py setup solved this.Suspiration
S
2

As mentioned in the linked question, the solution is simply to change _foo to foo._foo:

from distutils.core import setup, Extension

module = Extension('foo._foo',
                   sources=['foo.c'])

setup(name='foo', packages=['foo'], ext_modules=[module])

My issue was that I was running my tests.py from the same directory as the foo module was located in.

I fixed this by bringing it into its own directory:

/foo
    /foo
        __init__.py
    foo.c
    setup.py
    /tests
         test.py
Suspiration answered 6/2, 2017 at 5:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.