Ошибка подмодуля Python C-extension: нет модуля с именем x

У меня возникли трудности с созданием C-расширения в качестве подмодуля в моем коде. Приведенное ниже расширение C компилируется просто отлично. Проблема возникает, когда я пытаюсь добавить его в другой модуль.

Вот код C: Имя файла prctl3-0.c. Я могу компилировать его как для Python2.7, так и для Python 3.0.

#include <Python.h>

#include <stdio.h>
#include <string.h>
#include <sys/prctl.h>

// Now we need to identify which version of Python we are working with.
//  For backwards compatibility, we need to be able to be compiled by either
//  Python 2.7 or Python3.x.

#if PY_MAJOR_VERSION >=3
#define PY_3CODE            // We will use this pre-compile statement to differentiate
                            //  between code for Py2.7 and 3.x
#endif

/* osCall_changeName
  Calls prctl() to change the name of the calling thread, process or subprocess

*/
static PyObject* osCall_changeName(PyObject*self, PyObject* args)
{
  const char *passedInName;   // Name passed in by the system
  size_t nameLength;          // Calculated by calling strlen() on passedInName

  char newName[16];           // In Python newName= passedInName[0:15]+ \0
  int nameChangeRes;          // stores error code for calling prctl()

  PyObject *retName;          // Return value; Python None if error occurs

  // Check if argument passed in successfully
  if(! PyArg_ParseTuple(args, "s", &passedInName)){
    printf("Error in arg passing\n");
    Py_RETURN_NONE;
  }

  nameLength = strlen(passedInName);
  if( nameLength > 15){       // prctl() automatically truncates, but unsure if new string is null-terminated
     strncpy(newName, passedInName, 15);
     newName[15] = '\0';
  } else {
    strcpy(newName, passedInName);
  }

  //Actual function call
  nameChangeRes = prctl(PR_SET_NAME, newName, 0,0,0);

  if( nameChangeRes == 0 )    // Success; pass back the changed name value
  {
    retName = Py_BuildValue("s", newName);
    return retName;
  }

  // Method failed; return None
  Py_RETURN_NONE;
}

static PyObject* osCall_getName(PyObject* self) {

  char procName[16];          // Buffer to put prctl results into
  int  nameRetrieveRes;       // Result of the name retrieval operation
  PyObject *retName;          // Python object to return values


  nameRetrieveRes = prctl(PR_GET_NAME, procName, 0,0,0);

  if ( nameRetrieveRes == 0 ) //
  {
      retName = Py_BuildValue("s", procName);
      return retName;
  }
  printf("Process name change failed\n");
  // Operation failed; return None
  Py_RETURN_NONE;
}

//==========================================================
//  STEP 2: COMPILE THE PIECES NEEDED FOR EITHER 2.7 OR 3.X
//    PYTHON LIBRARIES
//==========================================================

static PyMethodDef proc_OsFunc[] = {
  { "changeName",
  (PyCFunction)osCall_changeName,
  METH_VARARGS,
  "Function to give Python process a new associated string ID"},

  { "getName",
  (PyCFunction)osCall_getName,
  METH_NOARGS,
  "Function to get Python process's current string ID"
  },

  {NULL, NULL, 0, NULL} //function array terminator
};

#ifdef PY_3CODE
static struct PyModuleDef osCallDefine = {
  PyModuleDef_HEAD_INIT,
  "prctl3_0",
  "A simple library for accessing prctl() on Linux from Python 3.0",
  -1,
  proc_OsFunc
};

#endif

#ifdef PY_3CODE
// Python 3.0 initialization syntax
PyMODINIT_FUNC PyInit_prctl3_0(void)
{
  Py_Initialize();

  return PyModule_Create(&osCallDefine);
}

#else
// Python 2.0 initialization syntax
PyMODINIT_FUNC initprctl3_0() {
  Py_InitModule3("prctl3_0",proc_OsFunc,
        "A simple library for accessing prctl() on Linux from Python 2.0");
}



#endif

Я надеюсь, что этот код будет в модуле с именем mpIPC как часть более крупного проекта. Проблема, с которой я сталкиваюсь, заключается в том, что когда я помещаю ее в более крупный модуль и пытаюсь получить к ней доступ, используя следующий код, я получаю следующее:

>>> import mpIPC.prctl3_0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named prctl3_0

Мой файл setup.py выглядит следующим образом:

from setuptools import setup, find_packages, Extension

prctl_module = Extension("mpIPC.prctl3_0",
                                sources = ["mpIPC/prctl3_0.c"])

setup(name = "mpIPC",
    version = '0.0',
    description = "Python C module for accessing Linux commands for IPC",
    packages = ['mpIPC'],
    ext_modules = [prctl_module] )

Мой каталог файлов для этого модуля:

project/
+- setup.py
+- mkdir/
-+- __init__.py 
-+- prctl3_0.c
-+- os.py   # used for other Linux os calls

Я не совсем уверен, что мне не хватает. Я также проверил следующую ссылку: Как создать расширение Python C, чтобы я мог импортировать его из модуля, но на данный момент это мне не очень помогает.


person A. Reed    schedule 02.05.2018    source источник
comment
Если я что-то не упустил, определенно не создавайте модуль с именем os.py, потому что он потенциально может затенить модуль os стандартной библиотеки (особенно на Python 2), и это смутит вас и других.   -  person Iguananaut    schedule 02.05.2018
comment
Хорошая точка зрения. Сообщим нашему менеджеру, чтобы он изменил название модуля на что-то менее конфликтное.   -  person A. Reed    schedule 03.05.2018
comment
Как бы то ни было, вы можете обычно избежать подобных проблем, включив from __future__ import absolute_import (что на самом деле вы, вероятно, уже делаете, иначе вам очень повезло, что все не ломается :) Но все же лучше не в первую очередь использовать имена модулей Python stdlib.   -  person Iguananaut    schedule 03.05.2018


Ответы (1)


У меня все заработало без каких-либо модификаций исходного кода.

  1. Ваш каталог "mkdir" должен называться "mpIPC", что соответствует имени модуля. Вы хотите, чтобы ваша структура каталогов выглядела внизу

  2. не пытайтесь проверить это из вашего исходного каталога, т. е. ни из какого места в project, так как это будет пытаться импортировать, в соответствии со структурой модуля Python, из каталога «mpIPC» (который вы создали в 1)) (за эту подсказку следует этот комментарий в сообщении, которое вы упомянули. Вместо этого попробуйте, например, из любого места в вашем домашнем каталоге. То есть, предположим, вы сначала запустили python setup.py install :)

Дерево каталогов:

foobar
    ├── mpIPC
    │   ├── __init__.py
    │   ├── os.py
    │   └── prctl3_0.c
    └── setup.py
person Oliver Baumann    schedule 02.05.2018
comment
Если вы хотите протестировать модуль расширения из исходного дерева, запустите ./setup.py build_ext --inplace. Это помещает встроенный общий модуль в исходный код. То есть процесс сборки скопирует prctl3_0.so в каталог mpIPC вместе с исходным кодом. Затем из вершины исходного дерева вы можете запустить import mpIPC.prctl3_0, и это сработает. Обычно я нахожу это более удобным для разработки, но у других есть другое мнение (в любом случае убедитесь, что это не передано в систему контроля версий!). - person Iguananaut; 02.05.2018