0

I'm attempting to create some complex C extension module for Python.

I have somewhat good results using the official documentation and can import my module with a syntax like

import my_custom_module

But I would also like to have submodules in my C extension like

import my_custom_module

my_custom_module.ClassA # exists in the my_custom_module module

import my_custom_module.subpart1
import my_custom_module.subpart2

my_custom_module.subpart1.ClassB # exists in the my_custom_module.subpart1 module
my_custom_module.subpart2.ClassC # exists in the my_custom_module.subpart2 module

Preferable I would like to keep only one shared library (for ease of build and distribution) and I wouldn't mind if the unique PyMODINIT_FUNC needed to load all of my classes and functions (that's not a problem, I'm not looking at optimizing loading times or to reduce memory consumption here). So this is mostly a syntaxical requirement in order to be able to categorize some classes in some submodules and some classes in other.

Does someone know how to do that, maybe a small example ?

I did a lot of research in the official documentation + by Googling, didn't found an answer.

Nicolas V
  • 31
  • 5
  • I may have found something useful in OpenCV's documentation: https://github.com/opencv/opencv/blob/0052d46b8e33c7bfe0e1450e4bff28b88f455570/modules/python/src2/cv2.cpp ( in a function named `createSubmodule`). I will try to use the same function calls in my code. – Nicolas V Apr 03 '23 at 14:56

1 Answers1

0

OK, I found it. You can to use PyImport_AddModule and PyDict_SetItemString in this way (comments are from OpenCV's python binding documentation):

PyMODINIT_FUNC PyInit_mycustommodule(void) {
  PyObject *main_module = PyModule_Create(&mycustommodule_moduledef);
  if (main_module == NULL) {
    return NULL;
  }

  PyObject* main_module_dict = PyModule_GetDict(main_module);
  if (main_module_dict == NULL) {
    return NULL;
  }

  PyObject * submodule = PyImport_AddModule("mycustommodule.mysubmodule");
  if (submodule == NULL) {
    return NULL;
  }

  /// Populates parent module dictionary. Submodule lifetime should be managed
  /// by the global modules dictionary and parent module dictionary, so Py_DECREF after
  /// successfull call to the `PyDict_SetItemString` is redundant.
  if (PyDict_SetItemString(main_module_dict, "mysubmodule", submodule) < 0) {
      return NULL;
  }

  return main_module;
}
Nicolas V
  • 31
  • 5