diff options
5 files changed, 148 insertions, 22 deletions
diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp index 7cca03c84..7b333f4ff 100644 --- a/sources/shiboken2/libshiboken/pep384impl.cpp +++ b/sources/shiboken2/libshiboken/pep384impl.cpp @@ -77,17 +77,22 @@ static struct PyMethodDef probe_methoddef[] = { {0} }; +static PyGetSetDef probe_getseters[] = { + {0} /* Sentinel */ +}; + #define probe_tp_call make_dummy(1) #define probe_tp_str make_dummy(2) #define probe_tp_traverse make_dummy(3) #define probe_tp_clear make_dummy(4) #define probe_tp_methods probe_methoddef -#define probe_tp_descr_get make_dummy(6) -#define probe_tp_init make_dummy(7) -#define probe_tp_alloc make_dummy(8) -#define probe_tp_new make_dummy(9) -#define probe_tp_free make_dummy(10) -#define probe_tp_is_gc make_dummy(11) +#define probe_tp_getset probe_getseters +#define probe_tp_descr_get make_dummy(7) +#define probe_tp_init make_dummy(8) +#define probe_tp_alloc make_dummy(9) +#define probe_tp_new make_dummy(10) +#define probe_tp_free make_dummy(11) +#define probe_tp_is_gc make_dummy(12) #define probe_tp_name "type.probe" #define probe_tp_basicsize make_dummy_int(42) @@ -98,6 +103,7 @@ static PyType_Slot typeprobe_slots[] = { {Py_tp_traverse, probe_tp_traverse}, {Py_tp_clear, probe_tp_clear}, {Py_tp_methods, probe_tp_methods}, + {Py_tp_getset, probe_tp_getset}, {Py_tp_descr_get, probe_tp_descr_get}, {Py_tp_init, probe_tp_init}, {Py_tp_alloc, probe_tp_alloc}, @@ -138,6 +144,7 @@ check_PyTypeObject_valid(void) || probe_tp_clear != check->tp_clear || probe_tp_weakrefoffset != typetype->tp_weaklistoffset || probe_tp_methods != check->tp_methods + || probe_tp_getset != check->tp_getset || probe_tp_base != typetype->tp_base || !PyDict_Check(check->tp_dict) || !PyDict_GetItemString(check->tp_dict, "dummy") diff --git a/sources/shiboken2/libshiboken/pep384impl.h b/sources/shiboken2/libshiboken/pep384impl.h index bfa8f38a7..d883677ce 100644 --- a/sources/shiboken2/libshiboken/pep384impl.h +++ b/sources/shiboken2/libshiboken/pep384impl.h @@ -113,7 +113,7 @@ typedef struct _typeobject { void *X26; // iternextfunc tp_iternext; struct PyMethodDef *tp_methods; void *X28; // struct PyMemberDef *tp_members; - void *X29; // struct PyGetSetDef *tp_getset; + struct PyGetSetDef *tp_getset; struct _typeobject *tp_base; PyObject *tp_dict; descrgetfunc tp_descr_get; diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp index a8874e2e0..da9c56c62 100644 --- a/sources/shiboken2/libshiboken/signature.cpp +++ b/sources/shiboken2/libshiboken/signature.cpp @@ -75,6 +75,7 @@ typedef struct safe_globals_struc { PyObject *sigparse_func; PyObject *createsig_func; PyObject *seterror_argument_func; + PyObject *make_helptext_func; } safe_globals_struc, *safe_globals; static safe_globals pyside_globals = 0; @@ -136,13 +137,15 @@ _get_class_of_cf(PyObject *ob_cf) // This must be an overloaded function that we handled special. Shiboken::AutoDecRef special(Py_BuildValue("(Os)", ob_cf, "overload")); selftype = PyDict_GetItem(pyside_globals->map_dict, special); + if (selftype == nullptr) { + // This is probably a module function. We will return type(None). + selftype = Py_None; + } } } - assert(selftype); PyObject *typemod = (PyType_Check(selftype) || PyModule_Check(selftype)) ? selftype : (PyObject *)Py_TYPE(selftype); - // do we support module functions? Py_INCREF(typemod); return typemod; } @@ -514,6 +517,9 @@ init_phase_2(safe_globals_struc *p, PyMethodDef *methods) p->seterror_argument_func = PyObject_GetAttrString(p->helper_module, "seterror_argument"); if (p->seterror_argument_func == NULL) goto error; + p->make_helptext_func = PyObject_GetAttrString(p->helper_module, "make_helptext"); + if (p->make_helptext_func == NULL) + goto error; return 0; error: @@ -524,20 +530,50 @@ error: } static int -add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp) +_fixup_getset(PyTypeObject *type, const char *name, PyGetSetDef *new_gsp) { + PyGetSetDef *gsp = type->tp_getset; + if (gsp != nullptr) { + for (; gsp->name != NULL; gsp++) { + if (strcmp(gsp->name, name) == 0) { + new_gsp->set = gsp->set; + new_gsp->doc = gsp->doc; + new_gsp->closure = gsp->closure; + return 1; + } + } + } + // staticmethod has just a __doc__ in the class + assert(strcmp(type->tp_name, "staticmethod") == 0); + return 0; +} + +static int +add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp, PyObject **old_descr) +{ + /* + * This function is used to assign a new __signature__ attribute, + * and also to override a __doc__ attribute. + */ assert(PyType_Check(type)); PyType_Ready(type); PyObject *dict = type->tp_dict; for (; gsp->name != NULL; gsp++) { - if (PyDict_GetItemString(dict, gsp->name)) - continue; + PyObject *have_descr = PyDict_GetItemString(dict, gsp->name); + if (have_descr != nullptr) { + assert(strcmp(gsp->name, "__doc__") == 0); + Py_INCREF(have_descr); + *old_descr = have_descr; + if (!_fixup_getset(type, gsp->name, gsp)) + continue; + } Shiboken::AutoDecRef descr(PyDescr_NewGetSet(type, gsp)); if (descr.isNull()) return -1; if (PyDict_SetItemString(dict, gsp->name, descr) < 0) return -1; } + PyType_Modified(type); return 0; } @@ -553,28 +589,91 @@ add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp) // Please note that in fact we are modifying 'type', the metaclass of all // objects, because we add new functionality. // +// Addendum 2019-01-12: We now also compute a docstring from the signature. +// + +// keep the original __doc__ functions +static PyObject *old_cf_doc_descr = 0; +static PyObject *old_sm_doc_descr = 0; +static PyObject *old_md_doc_descr = 0; +static PyObject *old_tp_doc_descr = 0; +static PyObject *old_wd_doc_descr = 0; + +static int handle_doc_in_progress = 0; + +static PyObject * +handle_doc(PyObject *ob, PyObject *old_descr) +{ + init_module_1(); + init_module_2(); + Shiboken::AutoDecRef ob_type(GetClassOfFunc(ob)); + PyTypeObject *type = reinterpret_cast<PyTypeObject *>(ob_type.object()); + if (handle_doc_in_progress || strncmp(type->tp_name, "PySide2.", 8) != 0) + return PyObject_CallMethod(old_descr, const_cast<char *>("__get__"), const_cast<char *>("(O)"), ob); + handle_doc_in_progress++; + PyObject *res = PyObject_CallFunction( + pyside_globals->make_helptext_func, + const_cast<char *>("(O)"), ob); + handle_doc_in_progress--; + if (res == nullptr) { + PyErr_Print(); + Py_FatalError("handle_doc did not receive a result"); + } + return res; +} + +static PyObject * +pyside_cf_get___doc__(PyObject *cf) { + return handle_doc(cf, old_cf_doc_descr); +} + +static PyObject * +pyside_sm_get___doc__(PyObject *sm) { + return handle_doc(sm, old_sm_doc_descr); +} + +static PyObject * +pyside_md_get___doc__(PyObject *md) { + return handle_doc(md, old_md_doc_descr); +} + +static PyObject * +pyside_tp_get___doc__(PyObject *tp) { + return handle_doc(tp, old_tp_doc_descr); +} + +static PyObject * +pyside_wd_get___doc__(PyObject *wd) { + return handle_doc(wd, old_wd_doc_descr); +} + static PyGetSetDef new_PyCFunction_getsets[] = { - {(char *) "__signature__", (getter)pyside_cf_get___signature__}, + {const_cast<char *>("__signature__"), (getter)pyside_cf_get___signature__}, + {const_cast<char *>("__doc__"), (getter)pyside_cf_get___doc__}, {0} }; static PyGetSetDef new_PyStaticMethod_getsets[] = { - {(char *) "__signature__", (getter)pyside_sm_get___signature__}, + {const_cast<char *>("__signature__"), (getter)pyside_sm_get___signature__}, + {const_cast<char *>("__doc__"), (getter)pyside_sm_get___doc__}, {0} }; static PyGetSetDef new_PyMethodDescr_getsets[] = { - {(char *) "__signature__", (getter)pyside_md_get___signature__}, + {const_cast<char *>("__signature__"), (getter)pyside_md_get___signature__}, + {const_cast<char *>("__doc__"), (getter)pyside_md_get___doc__}, {0} }; static PyGetSetDef new_PyType_getsets[] = { - {(char *) "__signature__", (getter)pyside_tp_get___signature__}, + {const_cast<char *>("__signature__"), (getter)pyside_tp_get___signature__}, + {const_cast<char *>("__doc__"), (getter)pyside_tp_get___doc__}, {0} }; static PyGetSetDef new_PyWrapperDescr_getsets[] = { - {(char *) "__signature__", (getter)pyside_wd_get___signature__}, + {const_cast<char *>("__signature__"), (getter)pyside_wd_get___signature__}, + {const_cast<char *>("__doc__"), (getter)pyside_wd_get___doc__}, {0} }; @@ -655,11 +754,11 @@ PySide_PatchTypes(void) Shiboken::AutoDecRef wd(PyObject_GetAttrString((PyObject *)Py_TYPE(Py_True), "__add__")); // wrapper-descriptor if (md.isNull() || wd.isNull() || PyType_Ready(Py_TYPE(md)) < 0 - || add_more_getsets(PepMethodDescr_TypePtr, new_PyMethodDescr_getsets) < 0 - || add_more_getsets(&PyCFunction_Type, new_PyCFunction_getsets) < 0 - || add_more_getsets(PepStaticMethod_TypePtr, new_PyStaticMethod_getsets) < 0 - || add_more_getsets(&PyType_Type, new_PyType_getsets) < 0 - || add_more_getsets(Py_TYPE(wd), new_PyWrapperDescr_getsets) < 0 + || add_more_getsets(PepMethodDescr_TypePtr, new_PyMethodDescr_getsets, &old_md_doc_descr) < 0 + || add_more_getsets(&PyCFunction_Type, new_PyCFunction_getsets, &old_cf_doc_descr) < 0 + || add_more_getsets(PepStaticMethod_TypePtr, new_PyStaticMethod_getsets, &old_sm_doc_descr) < 0 + || add_more_getsets(&PyType_Type, new_PyType_getsets, &old_tp_doc_descr) < 0 + || add_more_getsets(Py_TYPE(wd), new_PyWrapperDescr_getsets, &old_wd_doc_descr) < 0 ) return -1; #ifndef _WIN32 diff --git a/sources/shiboken2/shibokenmodule/support/signature/errorhandler.py b/sources/shiboken2/shibokenmodule/support/signature/errorhandler.py index 902bb05af..df24234e3 100644 --- a/sources/shiboken2/shibokenmodule/support/signature/errorhandler.py +++ b/sources/shiboken2/shibokenmodule/support/signature/errorhandler.py @@ -121,4 +121,20 @@ def seterror_argument(args, func_name): # We don't raise the error here, to avoid the loader in the traceback. return TypeError, msg + +def make_helptext(func): + existing_doc = func.__doc__ + sigs = get_signature(func) + if not sigs: + return existing_doc + if type(sigs) != list: + sigs = [sigs] + try: + func_name = func.__name__ + except AttribureError: + func_name = func.__func__.__name__ + sigtext = "\n".join(func_name + str(sig) for sig in sigs) + msg = sigtext + "\n\n" + existing_doc if existing_doc else sigtext + return msg + # end of file diff --git a/sources/shiboken2/shibokenmodule/support/signature/loader.py b/sources/shiboken2/shibokenmodule/support/signature/loader.py index be30483fe..8c7739d9a 100644 --- a/sources/shiboken2/shibokenmodule/support/signature/loader.py +++ b/sources/shiboken2/shibokenmodule/support/signature/loader.py @@ -201,4 +201,8 @@ def create_signature(props, key): def seterror_argument(args, func_name): return errorhandler.seterror_argument(args, func_name) +# name used in signature.cpp +def make_helptext(func): + return errorhandler.make_helptext(func) + # end of file |