-1

I've embedded Python (3.6) code into my C++ application successfully. I use the Python/C API to call methods from this library. An overview of the python module is as follows:

class MyClass(object):
    def __init__(args: str) -> None:
        ...
        return
    
    def callable_method(*args) -> Tuple:
        ...
        return some_tuple

    @staticmethod()
    def create_from_cli_args(argv: List[str]) -> 'MyClass':
        ...
        return MyClass(parsed_args)

The static method is a new addition to my code to move exception logic from the __init__ function to another function and yield an object. The C++ code to construct an object before was as follows:

PyObject *module_name = PyUnicode_FromString("module_path.my_class");

// Load the module object
PyObject *module = PyImport_Import(module_name);
if(module == nullptr) return;
Py_DECREF(module_name);

// Get callable list from module
PyObject *dict = PyModule_GetDict(module);
if(dict == nullptr) return;
Py_DECREF(module);

// Builds the name of a callable class
PyObject *my_class = PyDict_GetItemString(dict, "MyClass");
if(python_class == nullptr) return;

// Check if python class is callable
if(!PyCallable_Check(my_class)) return;

// Populate args for class instantiation
PyObject *py_args = PyTuple_New(1);
PyTuple_SetItem(py_args, 0, PyUnicode_FromString("Initialize_Configs"));

// Construct object
PyObject *my_class_obj = PyObject_CallObject(my_class, py_args);
if(my_class_obj == nullptr) return;

The above code snippet works, however, with the addition of the static method I'm trying to use to create an object of my_class, I'm unable to figure out how to call a static method of a class. I've tried using PyObject *my_class = PyDict_GetItemString(dict, "MyClass.create_my_class"); as well as PyObject_CallMethod(my_class, "create_my_class", kargs, kwargs) but that doesn't work either. I'd appreciate any help.

Obibhand
  • 11
  • 3
  • "The above code snippet works" - it shouldn't. You're using `PyObject_CallMethod` wrong. You didn't even specify a method name, and its signature in general is nothing like how you called it. – user2357112 Feb 05 '22 at 02:26
  • [Check the docs](https://docs.python.org/3/c-api/call.html#c.PyObject_CallMethod), give it the right arguments, and you should be able to use it to call your static method. – user2357112 Feb 05 '22 at 02:27
  • You need the calls to Py_DECREF _before_ the early returns - otherwise you leak an object if the calls fail. Given you are coding in C++, I would actually wrap the PyObject* in a RAII class. – Martin Bonner supports Monica Dec 16 '22 at 08:06

1 Answers1

1

As the person in the comments suggested, I was incorrectly calling the static method. The solution is:

...
if(!PyCallable_Check(my_class)) return;

// A static method can be called the same as a normal method in python.
PyObject *my_class_object = PyObject_CallMethod(my_class, "create_from_cli_args", "s", "--cli_args");

if(!my_class_object) return;
Obibhand
  • 11
  • 3
  • Thank you! This (implicitly) answers my question of "does CallMethod handle the difference between instance methods, class methods, and static methods - and if not, how do I handle them". – Martin Bonner supports Monica Dec 16 '22 at 08:09