Skip to content

Commit fedd8c1

Browse files
committed
[PyROOT] Get names and types of all overloads' signature
Expose two new attributes of a CPPOverload object on the Python side, namely `func_overloads_names` and `func_overloads_types`. The first returns a dictionary with all the input parameter names for all the overloads, the second returns a dictionary with the types of the return and input parameters for all the overloads. An example: ```python import ROOT from pprint import pprint ROOT.gInterpreter.Declare(""" int foo(int a, float b); int foo(int a); float foo(float b); double foo(int a, float b, double c); """) pprint(ROOT.foo.func_overloads_names) pprint(ROOT.foo.func_overloads_types) ``` Output: ``` {'double ::foo(int a, float b, double c)': ('a', 'b', 'c'), 'float ::foo(float b)': ('b',), 'int ::foo(int a)': ('a',), 'int ::foo(int a, float b)': ('a', 'b')} {'double ::foo(int a, float b, double c)': {'input_types': ('int', 'float', 'double'), 'return_type': 'double'}, 'float ::foo(float b)': {'input_types': ('float',), 'return_type': 'float'}, 'int ::foo(int a)': {'input_types': ('int',), 'return_type': 'int'}, 'int ::foo(int a, float b)': {'input_types': ('int', 'float'), 'return_type': 'int'}} ```
1 parent 353aa4a commit fedd8c1

File tree

4 files changed

+127
-0
lines changed

4 files changed

+127
-0
lines changed

bindings/pyroot/cppyy/CPyCppyy/src/CPPMethod.cxx

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,70 @@ PyObject* CPyCppyy::CPPMethod::GetSignature(bool fa)
801801
return CPyCppyy_PyText_FromString(GetSignatureString(fa).c_str());
802802
}
803803

804+
/**
805+
* @brief Returns a tuple with the names of the input parameters of this method.
806+
*
807+
* For example given a function with prototype:
808+
*
809+
* double foo(int a, float b, double c)
810+
*
811+
* this function returns:
812+
*
813+
* ('a', 'b', 'c')
814+
*/
815+
PyObject *CPyCppyy::CPPMethod::GetSignatureNames()
816+
{
817+
// Build a tuple of the argument names for this signature.
818+
int argcount = GetMaxArgs();
819+
PyObject *signature_names = PyTuple_New(argcount);
820+
821+
for (int iarg = 0; iarg < argcount; ++iarg) {
822+
const std::string &argname_cpp = Cppyy::GetMethodArgName(fMethod, iarg);
823+
PyObject *argname_py = CPyCppyy_PyText_FromString(argname_cpp.c_str());
824+
PyTuple_SET_ITEM(signature_names, iarg, argname_py);
825+
}
826+
827+
return signature_names;
828+
}
829+
830+
/**
831+
* @brief Returns a dictionary with the types of the signature of this method.
832+
*
833+
* This dictionary will store both the return type and the input parameter
834+
* types of this method, respectively with keys "return_type" and
835+
* "input_types", for example given a function with prototype:
836+
*
837+
* double foo(int a, float b, double c)
838+
*
839+
* this function returns:
840+
*
841+
* {'input_types': ('int', 'float', 'double'), 'return_type': 'double'}
842+
*/
843+
PyObject *CPyCppyy::CPPMethod::GetSignatureTypes()
844+
{
845+
846+
PyObject *signature_types_dict = PyDict_New();
847+
848+
// Insert the return type first
849+
std::string return_type = GetReturnTypeName();
850+
PyObject *return_type_py = CPyCppyy_PyText_FromString(return_type.c_str());
851+
PyDict_SetItem(signature_types_dict, CPyCppyy_PyText_FromString("return_type"), return_type_py);
852+
853+
// Build a tuple of the argument types for this signature.
854+
int argcount = GetMaxArgs();
855+
PyObject *parameter_types = PyTuple_New(argcount);
856+
857+
for (int iarg = 0; iarg < argcount; ++iarg) {
858+
const std::string &argtype_cpp = Cppyy::GetMethodArgType(fMethod, iarg);
859+
PyObject *argtype_py = CPyCppyy_PyText_FromString(argtype_cpp.c_str());
860+
PyTuple_SET_ITEM(parameter_types, iarg, argtype_py);
861+
}
862+
863+
PyDict_SetItem(signature_types_dict, CPyCppyy_PyText_FromString("input_types"), parameter_types);
864+
865+
return signature_types_dict;
866+
}
867+
804868
//----------------------------------------------------------------------------
805869
std::string CPyCppyy::CPPMethod::GetReturnTypeName()
806870
{

bindings/pyroot/cppyy/CPyCppyy/src/CPPMethod.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ class CPPMethod : public PyCallable {
2424

2525
public:
2626
virtual PyObject* GetSignature(bool show_formalargs = true);
27+
virtual PyObject* GetSignatureNames();
28+
virtual PyObject* GetSignatureTypes();
2729
virtual PyObject* GetPrototype(bool show_formalargs = true);
2830
virtual int GetPriority();
2931
virtual bool IsGreedy();

bindings/pyroot/cppyy/CPyCppyy/src/CPPOverload.cxx

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,15 @@ class TPythonCallback : public PyCallable {
5858
virtual PyObject* GetSignature(bool /*show_formalargs*/ = true) {
5959
return CPyCppyy_PyText_FromString("*args, **kwargs");
6060
}
61+
62+
virtual PyObject* GetSignatureNames() {
63+
return PyTuple_New(0);
64+
}
65+
66+
virtual PyObject* GetSignatureTypes() {
67+
return PyTuple_New(0);
68+
}
69+
6170
virtual PyObject* GetPrototype(bool /*show_formalargs*/ = true) {
6271
return CPyCppyy_PyText_FromString("<callback>");
6372
}
@@ -241,6 +250,54 @@ static PyObject* mp_doc(CPPOverload* pymeth, void*)
241250
return doc;
242251
}
243252

253+
/**
254+
* @brief Returns a dictionary with the input parameter names for all overloads.
255+
*
256+
* This dictionary may look like:
257+
*
258+
* {'double ::foo(int a, float b, double c)': ('a', 'b', 'c'),
259+
* 'float ::foo(float b)': ('b',),
260+
* 'int ::foo(int a)': ('a',),
261+
* 'int ::foo(int a, float b)': ('a', 'b')}
262+
*/
263+
static PyObject *mp_func_overloads_names(CPPOverload *pymeth)
264+
{
265+
266+
const CPPOverload::Methods_t &methods = pymeth->fMethodInfo->fMethods;
267+
268+
PyObject *overloads_names_dict = PyDict_New();
269+
270+
for (PyCallable *method : methods) {
271+
PyDict_SetItem(overloads_names_dict, method->GetPrototype(), method->GetSignatureNames());
272+
}
273+
274+
return overloads_names_dict;
275+
}
276+
277+
/**
278+
* @brief Returns a dictionary with the types of all overloads.
279+
*
280+
* This dictionary may look like:
281+
*
282+
* {'double ::foo(int a, float b, double c)': {'input_types': ('int', 'float', 'double'), 'return_type': 'double'},
283+
* 'float ::foo(float b)': {'input_types': ('float',), 'return_type': 'float'},
284+
* 'int ::foo(int a)': {'input_types': ('int',), 'return_type': 'int'},
285+
* 'int ::foo(int a, float b)': {'input_types': ('int', 'float'), 'return_type': 'int'}}
286+
*/
287+
static PyObject *mp_func_overloads_types(CPPOverload *pymeth)
288+
{
289+
290+
const CPPOverload::Methods_t &methods = pymeth->fMethodInfo->fMethods;
291+
292+
PyObject *overloads_types_dict = PyDict_New();
293+
294+
for (PyCallable *method : methods) {
295+
PyDict_SetItem(overloads_types_dict, method->GetPrototype(), method->GetSignatureTypes());
296+
}
297+
298+
return overloads_types_dict;
299+
}
300+
244301
//----------------------------------------------------------------------------
245302
static PyObject* mp_meth_func(CPPOverload* pymeth, void*)
246303
{
@@ -514,6 +571,8 @@ static PyGetSetDef mp_getset[] = {
514571
{(char*)"func_globals", (getter)mp_func_globals, nullptr, nullptr, nullptr},
515572
{(char*)"func_doc", (getter)mp_doc, nullptr, nullptr, nullptr},
516573
{(char*)"func_name", (getter)mp_name, nullptr, nullptr, nullptr},
574+
{(char*)"func_overloads_types", (getter)mp_func_overloads_types, nullptr, nullptr, nullptr},
575+
{(char*)"func_overloads_names", (getter)mp_func_overloads_names, nullptr, nullptr, nullptr},
517576

518577
{(char*)"__creates__", (getter)mp_getcreates, (setter)mp_setcreates,
519578
(char*)"For ownership rules of result: if true, objects are python-owned", nullptr},

bindings/pyroot/cppyy/CPyCppyy/src/PyCallable.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ class PyCallable {
1515

1616
public:
1717
virtual PyObject* GetSignature(bool show_formalargs = true) = 0;
18+
virtual PyObject* GetSignatureNames() = 0;
19+
virtual PyObject* GetSignatureTypes() = 0;
1820
virtual PyObject* GetPrototype(bool show_formalargs = true) = 0;
1921
virtual PyObject* GetDocString() { return GetPrototype(); }
2022

0 commit comments

Comments
 (0)