Home > Software design >  How to Access Current File Path in Python C Extension
How to Access Current File Path in Python C Extension

Time:01-18

In Python, you can get the current file path with the __file__ attribute.

print(__file__)

How can I access this attribute from a Python C Extension? I tried the following code, but the attribute doesn’t exist.

if (PyObject_HasAttrString(module, "__file__")) {
    PyObject *string = PyObject_GetAttrString(module, "__file__");
    const char *path = PyUnicode_AsUTF8(string);
}

CodePudding user response:

It depends on when you want to access the __file__ attribute and exactly how you create the module.

In single-phase initialization (when you call PyModule_Create within PyInit_yourmodulename) __file__ is set after the PyInit_* function is called. Therefore you can only access it after that point, when the module is fully imported.

In multi-phase initialization, where PyInit_yourmodulename returns a PyModuleDef object and then the Py_mod_create slot of that PyModuleDef is called, you can set the filename from the spec passed to Py_mod_create. The ModuleSpec object has an attribute origin. This corresponds to the file that the module was loaded from. Thus you can set the __file__ attribute of your module from spec.origin.

If you're creating your modules outside of the PyInit_yourmodulename system (for example, creating multiple modules from a single file) then you're out of luck and will have to work out what __file__ is yourself.

CodePudding user response:

Hooray! I can now access the __file__ attribute.

static int module_exec(PyObject *self) {
    PyObject *string = PyObject_GetAttrString(self, "__file__");
    const char *path = PyUnicode_AsUTF8(string);

    printf("Current path: %s\n", path);
    return 0;
}

static PyModuleDef_Slot ModuleSlots[] = {
    {Py_mod_exec, module_exec},
    {0, NULL}
};

static struct PyModuleDef Module = {
    .m_base = PyModuleDef_HEAD_INIT,
    .m_name = "__init__",
    .m_size = 0,
    .m_slots = ModuleSlots
};

PyMODINIT_FUNC PyInit_Module(void) {
    printf("Initialising...");
    return PyModuleDef_Init(&Module);
}

I could have added the Py_mod_create slot, but I do not need it for my project.

  •  Tags:  
  • Related