Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork32k
Open
Description
I am trying to log all the function calls that happen. Within Python, as well as any of the C Extensions. But I see that dunder/magic methods defined within the C extensions are not registered withsys.setprofile
.
Is this the expected behaviour? If yes, are there any other means for me to log such events?
Or is this a bug in CPython?
Code to reproduce:
// c_extensions.c#definePY_SSIZE_T_CLEAN#include<Python.h>#include<stddef.h>/* for offsetof() */typedefstruct {PyObject_HEADPyObject*first;/* first name */PyObject*last;/* last name */intnumber;}CustomObject;staticvoidCustom_dealloc(CustomObject*self) {Py_XDECREF(self->first);Py_XDECREF(self->last);Py_TYPE(self)->tp_free((PyObject*)self);}staticPyObject*Custom_new(PyTypeObject*type,PyObject*args,PyObject*kwds) {CustomObject*self;self= (CustomObject*)type->tp_alloc(type,0);if (self!=NULL) {self->first=PyUnicode_FromString("");if (self->first==NULL) {Py_DECREF(self);returnNULL; }self->last=PyUnicode_FromString("");if (self->last==NULL) {Py_DECREF(self);returnNULL; }self->number=0; }return (PyObject*)self;}staticintCustom_init(CustomObject*self,PyObject*args,PyObject*kwds) {staticchar*kwlist[]= {"first","last","number",NULL};PyObject*first=NULL,*last=NULL;if (!PyArg_ParseTupleAndKeywords(args,kwds,"|OOi",kwlist,&first,&last,&self->number))return-1;if (first) {Py_XSETREF(self->first,Py_NewRef(first)); }if (last) {Py_XSETREF(self->last,Py_NewRef(last)); }return0;}staticPyMemberDefCustom_members[]= { {"first",Py_T_OBJECT_EX, offsetof(CustomObject,first),0,"first name"}, {"last",Py_T_OBJECT_EX, offsetof(CustomObject,last),0,"last name"}, {"number",Py_T_INT, offsetof(CustomObject,number),0,"custom number"}, {NULL}/* Sentinel */};staticPyObject*Custom_name(CustomObject*self,PyObject*Py_UNUSED(ignored)) {if (self->first==NULL) {PyErr_SetString(PyExc_AttributeError,"first");returnNULL; }if (self->last==NULL) {PyErr_SetString(PyExc_AttributeError,"last");returnNULL; }returnPyUnicode_FromFormat("%S %S",self->first,self->last);}staticPyMethodDefCustom_methods[]= { {"name", (PyCFunction)Custom_name,METH_NOARGS,"Return the name, combining the first and last name"}, {NULL}/* Sentinel */};staticPyTypeObjectCustomType= { .ob_base=PyVarObject_HEAD_INIT(NULL,0).tp_name="custom2.Custom", .tp_doc=PyDoc_STR("Custom objects"), .tp_basicsize=sizeof(CustomObject), .tp_itemsize=0, .tp_flags=Py_TPFLAGS_DEFAULT |Py_TPFLAGS_BASETYPE, .tp_new=Custom_new, .tp_init= (initproc)Custom_init, .tp_dealloc= (destructor)Custom_dealloc, .tp_members=Custom_members, .tp_methods=Custom_methods,};staticPyObject*print_stderr(PyObject*self,PyObject*args) {constchar*command;intsts;if (!PyArg_ParseTuple(args,"s",&command))returnNULL;sts=fprintf(stderr,"%s\n",command);returnPyLong_FromLong(sts);}staticPyMethodDefcustomMethods[]= { {"print_stderr",print_stderr,METH_VARARGS,"Prints."}, {NULL,NULL,0,NULL},};staticPyModuleDefcustommodule= { .m_base=PyModuleDef_HEAD_INIT, .m_name="custom2", .m_doc="Example module that creates an extension type.", .m_size=-1, .m_methods=customMethods,};PyMODINIT_FUNCPyInit_custom2(void) {PyObject*m;if (PyType_Ready(&CustomType)<0)returnNULL;m=PyModule_Create(&custommodule);if (m==NULL)returnNULL;if (PyModule_AddObjectRef(m,"Custom", (PyObject*)&CustomType)<0) {Py_DECREF(m);returnNULL; }returnm;}
# main.pyimportsysimportcustom2# C ExtensionclassMyClass:def__init__(self,*args,**kwargs):passdefdispatch_handler(frame,event,arg):ifevent.startswith("c_"):print(f"{event=} name ={arg.__name__}")else:print(f"{event=}{frame=}")returndispatch_handlerdeftest_dummy():custom2.print_stderr("Hello World")c=custom2.Custom(19)# XXX: Does not dispatch an event for custom2.Custom.__init__custom2.print_stderr(c.name())c=MyClass()# XXX: Dispatches an event for MyClass.__init__if__name__=="__main__":sys.setprofile(dispatch_handler)test_dummy()
# setup.py to compile the C Extension# ???: use pyproject.toml insteadfromsetuptoolsimportsetup,Extensionmodule=Extension("custom2",sources=["c_extension.c"])setup(name="custom2",version="0.0.1",description="Python C Extension",ext_modules=[module],)
❯ python ./main.py> output.txtHello World19
event = 'call' frame = <frame at 0x712491d45b40, file '/home/vipul-cariappa/Documents/Workspace/python/debugger/pxc-dbg/tmp/example0/./main.py', line 19, code test_dummy>event = 'c_call' name = print_stderrevent = 'c_return' name = print_stderrevent = 'c_call' name = nameevent = 'c_return' name = nameevent = 'c_call' name = print_stderrevent = 'c_return' name = print_stderrevent = 'call' frame = <frame at 0x712491d46740, file '/home/vipul-cariappa/Documents/Workspace/python/debugger/pxc-dbg/tmp/example0/./main.py', line 6, code __init__>event = 'return' frame = <frame at 0x712491d46740, file '/home/vipul-cariappa/Documents/Workspace/python/debugger/pxc-dbg/tmp/example0/./main.py', line 7, code __init__>event = 'return' frame = <frame at 0x712491d45b40, file '/home/vipul-cariappa/Documents/Workspace/python/debugger/pxc-dbg/tmp/example0/./main.py', line 25, code test_dummy>event = 'return' frame = <frame at 0x712491d45b40, file '/home/vipul-cariappa/Documents/Workspace/python/debugger/pxc-dbg/tmp/example0/./main.py', line 30, code <module>>