Fred Mitchell
Fred Mitchell

Reputation: 2161

How do I use setuptools to create a python package with multiple modules?

I want to organize a distribution with several modules. Eventually there will be a C extension module, and at the same 'level', several pure python modules. I am not sure whether the top level should just be considered a namespace.

For starters, I would like to create a module monty.spam. It will be a C extension. I lifted this out of the Extending Python docs.

monty/spam/spammodule.c

#include <Python.h>

static PyObject * spam_system (PyObject * self, PyObject * args)
  {
  const char * command;
  int          sts;

  if (!PyArg_ParseTuple (args, "s", &command))
    return NULL;
  sts = system (command);
  return Py_BuildValue ("i", sts);
  }

static 
PyMethodDef SpamMethods [] = {
             { "system", spam_system, METH_VARARGS, "Execute a shell command" },
             { NULL, NULL, 0, NULL }    
             };

PyMODINIT_FUNC
initspam (void)
  {
  (void) Py_InitModule ("spam", SpamMethods);
  }

I created a setup tools setup.py in the same directory, ran "python setup.py develop" and the module worked fine.

monty/spam/setup.py

from setuptools import setup, Extension

module = Extension ('spam', sources = [ 'spammodule.c' ])

setup (
      name = 'MontyP',
      version = '0.2', 
      description = 'pure spam',
      ext_modules = [ module ]
      )

In the monty directory:

python -c 'import monty.spam'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: No module named monty.spam

So now I would like to create a distribution in which spam "lives in" monty. I have tried a number of variations on the setup.py them in the monty directory. (Both directories have an empty __init__.py)

My latest try at monty/setup.py: (yes, the find_packages () has no utility in this version.)

from setuptools import setup, Extension, find_packages

module = Extension ('spam', sources = [ './spam/spammodule.c' ])

print find_packages ()
setup (
      name               = 'MontyP',
      version            = '0.2', 
      namespace_packages = [ 'monty' ],
      packages           = find_packages (),
      description        = 'pure spam',
      ext_modules        = [ module ]
      )

No Joy!

python setup.py develop
['spam']
error in MontyP setup command: Distribution contains no modules or packages for namespace package 'monty'

Upvotes: 3

Views: 4250

Answers (1)

brandizzi
brandizzi

Reputation: 27050

You just need two or three changes to make it work.

First, instead of placing it at monty/spam, setup.py should be placed in the same level as monty/:

enter image description here

setup.py always goes in the root of the project.

Also, create an __init__.py file in monty but no __init__.py inside spam.

Now, in setup.py, in the line "module = Extension ('spam', sources = [ 'spammodule.c' ])", replace spam by monty.spam and spammodule.c by monty/spam/spammodule.c:

module = Extension ('monty.spam', sources = [ 'monty/spam/spammodule.c' ])

This is necessary because external modules should be declared with their full names (monty.spam instead of spam). Also, since now setup.py is in the root of the project, it should receive a relative but complete path to the C source file.

That's it, your module should work now.

Upvotes: 1

Related Questions