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.
