Skip to content

Commit d0716bb

Browse files
vepadulanosiliataider
authored andcommitted
[PyROOT] Add cppyy patch
1 parent 81d6cf2 commit d0716bb

File tree

1 file changed

+239
-0
lines changed

1 file changed

+239
-0
lines changed
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
From 81d6cf2d75982e2fe0273befc8e61730035272ee Mon Sep 17 00:00:00 2001
2+
From: Vincenzo Eduardo Padulano <v.e.padulano@gmail.com>
3+
Date: Mon, 18 Oct 2021 19:03:19 +0200
4+
Subject: [PATCH] [PyROOT] Get names and types of all overloads' signature
5+
6+
Expose two new attributes of a CPPOverload object on the Python side,
7+
namely `func_overloads_names` and `func_overloads_types`. The first
8+
returns a dictionary with all the input parameter names for all the
9+
overloads, the second returns a dictionary with the types of the return
10+
and input parameters for all the overloads. An example:
11+
12+
```python
13+
import ROOT
14+
from pprint import pprint
15+
16+
ROOT.gInterpreter.Declare("""
17+
int foo(int a, float b);
18+
int foo(int a);
19+
float foo(float b);
20+
double foo(int a, float b, double c);
21+
""")
22+
23+
pprint(ROOT.foo.func_overloads_names)
24+
pprint(ROOT.foo.func_overloads_types)
25+
```
26+
Output:
27+
```
28+
{'double ::foo(int a, float b, double c)': ('a', 'b', 'c'),
29+
'float ::foo(float b)': ('b',),
30+
'int ::foo(int a)': ('a',),
31+
'int ::foo(int a, float b)': ('a', 'b')}
32+
{'double ::foo(int a, float b, double c)': {'input_types': ('int',
33+
'float',
34+
'double'),
35+
'return_type': 'double'},
36+
'float ::foo(float b)': {'input_types': ('float',), 'return_type': 'float'},
37+
'int ::foo(int a)': {'input_types': ('int',), 'return_type': 'int'},
38+
'int ::foo(int a, float b)': {'input_types': ('int', 'float'),
39+
'return_type': 'int'}}
40+
```
41+
---
42+
.../pyroot/cppyy/CPyCppyy/src/CPPMethod.cxx | 64 +++++++++++++++++++
43+
.../pyroot/cppyy/CPyCppyy/src/CPPMethod.h | 2 +
44+
.../pyroot/cppyy/CPyCppyy/src/CPPOverload.cxx | 58 ++++++++++++++++-
45+
.../pyroot/cppyy/CPyCppyy/src/PyCallable.h | 2 +
46+
4 files changed, 125 insertions(+), 1 deletion(-)
47+
48+
diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/CPPMethod.cxx b/bindings/pyroot/cppyy/CPyCppyy/src/CPPMethod.cxx
49+
index 9efac995ac..ff417468bf 100644
50+
--- a/bindings/pyroot/cppyy/CPyCppyy/src/CPPMethod.cxx
51+
+++ b/bindings/pyroot/cppyy/CPyCppyy/src/CPPMethod.cxx
52+
@@ -1055,6 +1055,70 @@ PyObject* CPyCppyy::CPPMethod::GetSignature(bool fa)
53+
return CPyCppyy_PyText_FromString(GetSignatureString(fa).c_str());
54+
}
55+
56+
+/**
57+
+ * @brief Returns a tuple with the names of the input parameters of this method.
58+
+ *
59+
+ * For example given a function with prototype:
60+
+ *
61+
+ * double foo(int a, float b, double c)
62+
+ *
63+
+ * this function returns:
64+
+ *
65+
+ * ('a', 'b', 'c')
66+
+ */
67+
+PyObject *CPyCppyy::CPPMethod::GetSignatureNames()
68+
+{
69+
+ // Build a tuple of the argument names for this signature.
70+
+ int argcount = GetMaxArgs();
71+
+ PyObject *signature_names = PyTuple_New(argcount);
72+
+
73+
+ for (int iarg = 0; iarg < argcount; ++iarg) {
74+
+ const std::string &argname_cpp = Cppyy::GetMethodArgName(fMethod, iarg);
75+
+ PyObject *argname_py = CPyCppyy_PyText_FromString(argname_cpp.c_str());
76+
+ PyTuple_SET_ITEM(signature_names, iarg, argname_py);
77+
+ }
78+
+
79+
+ return signature_names;
80+
+}
81+
+
82+
+/**
83+
+ * @brief Returns a dictionary with the types of the signature of this method.
84+
+ *
85+
+ * This dictionary will store both the return type and the input parameter
86+
+ * types of this method, respectively with keys "return_type" and
87+
+ * "input_types", for example given a function with prototype:
88+
+ *
89+
+ * double foo(int a, float b, double c)
90+
+ *
91+
+ * this function returns:
92+
+ *
93+
+ * {'input_types': ('int', 'float', 'double'), 'return_type': 'double'}
94+
+ */
95+
+PyObject *CPyCppyy::CPPMethod::GetSignatureTypes()
96+
+{
97+
+
98+
+ PyObject *signature_types_dict = PyDict_New();
99+
+
100+
+ // Insert the return type first
101+
+ std::string return_type = GetReturnTypeName();
102+
+ PyObject *return_type_py = CPyCppyy_PyText_FromString(return_type.c_str());
103+
+ PyDict_SetItem(signature_types_dict, CPyCppyy_PyText_FromString("return_type"), return_type_py);
104+
+
105+
+ // Build a tuple of the argument types for this signature.
106+
+ int argcount = GetMaxArgs();
107+
+ PyObject *parameter_types = PyTuple_New(argcount);
108+
+
109+
+ for (int iarg = 0; iarg < argcount; ++iarg) {
110+
+ const std::string &argtype_cpp = Cppyy::GetMethodArgType(fMethod, iarg);
111+
+ PyObject *argtype_py = CPyCppyy_PyText_FromString(argtype_cpp.c_str());
112+
+ PyTuple_SET_ITEM(parameter_types, iarg, argtype_py);
113+
+ }
114+
+
115+
+ PyDict_SetItem(signature_types_dict, CPyCppyy_PyText_FromString("input_types"), parameter_types);
116+
+
117+
+ return signature_types_dict;
118+
+}
119+
+
120+
//----------------------------------------------------------------------------
121+
std::string CPyCppyy::CPPMethod::GetReturnTypeName()
122+
{
123+
diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/CPPMethod.h b/bindings/pyroot/cppyy/CPyCppyy/src/CPPMethod.h
124+
index 88e49621ef..e9558f5c68 100644
125+
--- a/bindings/pyroot/cppyy/CPyCppyy/src/CPPMethod.h
126+
+++ b/bindings/pyroot/cppyy/CPyCppyy/src/CPPMethod.h
127+
@@ -51,6 +51,8 @@ public:
128+
129+
public:
130+
PyObject* GetSignature(bool show_formalargs = true) override;
131+
+ PyObject* GetSignatureNames() override;
132+
+ PyObject* GetSignatureTypes() override;
133+
PyObject* GetPrototype(bool show_formalargs = true) override;
134+
PyObject* GetTypeName() override;
135+
PyObject* Reflex(Cppyy::Reflex::RequestId_t request,
136+
diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/CPPOverload.cxx b/bindings/pyroot/cppyy/CPyCppyy/src/CPPOverload.cxx
137+
index d6aa4a747b..392dcc9a5e 100644
138+
--- a/bindings/pyroot/cppyy/CPyCppyy/src/CPPOverload.cxx
139+
+++ b/bindings/pyroot/cppyy/CPyCppyy/src/CPPOverload.cxx
140+
@@ -62,6 +62,12 @@ public:
141+
PyObject* GetSignature(bool /*show_formalargs*/ = true) override {
142+
return CPyCppyy_PyText_FromString("*args, **kwargs");
143+
}
144+
+ virtual PyObject* GetSignatureNames() {
145+
+ return PyTuple_New(0);
146+
+ }
147+
+ virtual PyObject* GetSignatureTypes() {
148+
+ return PyTuple_New(0);
149+
+ }
150+
PyObject* GetPrototype(bool /*show_formalargs*/ = true) override {
151+
return CPyCppyy_PyText_FromString("<callback>");
152+
}
153+
@@ -285,6 +291,54 @@ static int mp_doc_set(CPPOverload* pymeth, PyObject *val, void *)
154+
return 0;
155+
}
156+
157+
+/**
158+
+ * @brief Returns a dictionary with the input parameter names for all overloads.
159+
+ *
160+
+ * This dictionary may look like:
161+
+ *
162+
+ * {'double ::foo(int a, float b, double c)': ('a', 'b', 'c'),
163+
+ * 'float ::foo(float b)': ('b',),
164+
+ * 'int ::foo(int a)': ('a',),
165+
+ * 'int ::foo(int a, float b)': ('a', 'b')}
166+
+ */
167+
+static PyObject *mp_func_overloads_names(CPPOverload *pymeth)
168+
+{
169+
+
170+
+ const CPPOverload::Methods_t &methods = pymeth->fMethodInfo->fMethods;
171+
+
172+
+ PyObject *overloads_names_dict = PyDict_New();
173+
+
174+
+ for (PyCallable *method : methods) {
175+
+ PyDict_SetItem(overloads_names_dict, method->GetPrototype(), method->GetSignatureNames());
176+
+ }
177+
+
178+
+ return overloads_names_dict;
179+
+}
180+
+
181+
+/**
182+
+ * @brief Returns a dictionary with the types of all overloads.
183+
+ *
184+
+ * This dictionary may look like:
185+
+ *
186+
+ * {'double ::foo(int a, float b, double c)': {'input_types': ('int', 'float', 'double'), 'return_type': 'double'},
187+
+ * 'float ::foo(float b)': {'input_types': ('float',), 'return_type': 'float'},
188+
+ * 'int ::foo(int a)': {'input_types': ('int',), 'return_type': 'int'},
189+
+ * 'int ::foo(int a, float b)': {'input_types': ('int', 'float'), 'return_type': 'int'}}
190+
+ */
191+
+static PyObject *mp_func_overloads_types(CPPOverload *pymeth)
192+
+{
193+
+
194+
+ const CPPOverload::Methods_t &methods = pymeth->fMethodInfo->fMethods;
195+
+
196+
+ PyObject *overloads_types_dict = PyDict_New();
197+
+
198+
+ for (PyCallable *method : methods) {
199+
+ PyDict_SetItem(overloads_types_dict, method->GetPrototype(), method->GetSignatureTypes());
200+
+ }
201+
+
202+
+ return overloads_types_dict;
203+
+}
204+
+
205+
//----------------------------------------------------------------------------
206+
static PyObject* mp_meth_func(CPPOverload* pymeth, void*)
207+
{
208+
@@ -582,6 +636,8 @@ static PyGetSetDef mp_getset[] = {
209+
{(char*)"func_globals", (getter)mp_func_globals, nullptr, nullptr, nullptr},
210+
{(char*)"func_doc", (getter)mp_doc, (setter)mp_doc_set, nullptr, nullptr},
211+
{(char*)"func_name", (getter)mp_name, nullptr, nullptr, nullptr},
212+
+ {(char*)"func_overloads_types", (getter)mp_func_overloads_types, nullptr, nullptr, nullptr},
213+
+ {(char*)"func_overloads_names", (getter)mp_func_overloads_names, nullptr, nullptr, nullptr},
214+
215+
216+
// flags to control behavior
217+
@@ -1250,4 +1306,4 @@ CPyCppyy::CPPOverload::MethodInfo_t::~MethodInfo_t()
218+
Py_XDECREF(fDoc);
219+
}
220+
221+
-// TODO: something like PyMethod_Fini to clear up the free_list
222+
+// TODO: something like PyMethod_Fini to clear up the free_list
223+
\ No newline at end of file
224+
diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/PyCallable.h b/bindings/pyroot/cppyy/CPyCppyy/src/PyCallable.h
225+
index 62ce3aa1af..d2a072c5b3 100644
226+
--- a/bindings/pyroot/cppyy/CPyCppyy/src/PyCallable.h
227+
+++ b/bindings/pyroot/cppyy/CPyCppyy/src/PyCallable.h
228+
@@ -18,6 +18,8 @@ public:
229+
230+
public:
231+
virtual PyObject* GetSignature(bool show_formalargs = true) = 0;
232+
+ virtual PyObject* GetSignatureNames() = 0;
233+
+ virtual PyObject* GetSignatureTypes() = 0;
234+
virtual PyObject* GetPrototype(bool show_formalargs = true) = 0;
235+
virtual PyObject* GetTypeName() { return GetPrototype(false); }
236+
virtual PyObject* GetDocString() { return GetPrototype(); }
237+
--
238+
2.49.0
239+

0 commit comments

Comments
 (0)