24 void TemplateProxy::Set(
const std::string& name, PyObject* pyclass )
26 fPyName = PyROOT_PyUnicode_FromString( const_cast< char* >( name.c_str() ) );
27 Py_XINCREF( pyclass );
30 std::vector< PyCallable* > dummy;
31 fNonTemplated = MethodProxy_New( name, dummy );
32 fTemplated = MethodProxy_New( name, dummy );
38 void TemplateProxy::AddOverload( MethodProxy* mp ) {
39 fNonTemplated->AddMethod( mp );
42 void TemplateProxy::AddOverload( PyCallable* pc ) {
44 fNonTemplated->AddMethod( pc );
47 void TemplateProxy::AddTemplate( PyCallable* pc )
50 fTemplated->AddMethod( pc );
57 TemplateProxy* tpp_new( PyTypeObject*, PyObject*, PyObject* )
60 TemplateProxy* pytmpl = PyObject_GC_New( TemplateProxy, &TemplateProxy_Type );
61 pytmpl->fPyName = NULL;
62 pytmpl->fPyClass = NULL;
64 pytmpl->fNonTemplated = NULL;
65 pytmpl->fTemplated = NULL;
67 PyObject_GC_Track( pytmpl );
74 int tpp_clear( TemplateProxy* pytmpl )
76 Py_CLEAR( pytmpl->fPyName );
77 Py_CLEAR( pytmpl->fPyClass );
78 Py_CLEAR( pytmpl->fSelf );
79 Py_CLEAR( pytmpl->fNonTemplated );
80 Py_CLEAR( pytmpl->fTemplated );
88 void tpp_dealloc( TemplateProxy* pytmpl )
90 PyObject_GC_UnTrack( pytmpl );
92 PyObject_GC_Del( pytmpl );
98 PyObject* tpp_doc( TemplateProxy* pytmpl,
void* )
100 PyObject* doc =
nullptr;
101 if ( pytmpl->fNonTemplated )
102 doc = PyObject_GetAttrString( (PyObject*)pytmpl->fNonTemplated,
"__doc__" );
103 if ( pytmpl->fTemplated ) {
104 PyObject* doc2 = PyObject_GetAttrString( (PyObject*)pytmpl->fTemplated,
"__doc__" );
106 PyROOT_PyUnicode_AppendAndDel( &doc, PyROOT_PyUnicode_FromString(
"\n" ));
107 PyROOT_PyUnicode_AppendAndDel( &doc, doc2 );
108 }
else if ( !doc && doc2 ) {
116 return PyROOT_PyUnicode_FromString( TemplateProxy_Type.tp_doc );
122 int tpp_traverse( TemplateProxy* pytmpl, visitproc visit,
void* arg )
124 Py_VISIT( pytmpl->fPyName );
125 Py_VISIT( pytmpl->fPyClass );
126 Py_VISIT( pytmpl->fSelf );
127 Py_VISIT( pytmpl->fNonTemplated );
128 Py_VISIT( pytmpl->fTemplated );
134 PyObject* tpp_call( TemplateProxy* pytmpl, PyObject* args, PyObject* kwds )
173 PyObject* pymeth = MethodProxy_Type.tp_descr_get(
174 (PyObject*)pytmpl->fNonTemplated, pytmpl->fSelf, (PyObject*)&MethodProxy_Type );
175 if ( MethodProxy_Check( pymeth ) ) {
177 PyObject* result = MethodProxy_Type.tp_call( pymeth, args, kwds );
178 Py_DECREF( pymeth ); pymeth = 0;
185 Py_XDECREF( pymeth ); pymeth = 0;
189 Py_ssize_t nArgs = PyTuple_GET_SIZE( args );
191 PyErr_Format( PyExc_TypeError,
"template method \'%s\' with no arguments must be explicit",
192 PyROOT_PyUnicode_AsString( pytmpl->fPyName ) );
198 Bool_t isType = kFALSE;
200 PyObject* tpArgs = PyTuple_New( nArgs );
201 for ( Int_t i = 0; i < nArgs; ++i ) {
202 PyObject* itemi = PyTuple_GET_ITEM( args, i );
203 if ( PyType_Check( itemi ) ) isType = kTRUE;
204 #if PY_VERSION_HEX >= 0x03000000
205 else if ( ! isType && PyUnicode_Check( itemi ) ) nStrings += 1;
207 else if ( ! isType && PyBytes_Check( itemi ) ) nStrings += 1;
210 PyObject* pytc = PyObject_GetAttr( itemi, PyStrings::gTypeCode );
211 if ( ! ( pytc && PyROOT_PyUnicode_Check( pytc ) ) ) {
214 PyObject* tp = (PyObject*)Py_TYPE( itemi );
216 PyTuple_SET_ITEM( tpArgs, i, tp );
219 char tc = ((
char*)PyROOT_PyUnicode_AsString( pytc ))[0];
220 const char* ptrname = 0;
222 case 'b': ptrname =
"char*";
break;
223 case 'h': ptrname =
"short*";
break;
224 case 'H': ptrname =
"unsigned short*";
break;
225 case 'i': ptrname =
"int*";
break;
226 case 'I': ptrname =
"unsigned int*";
break;
227 case 'l': ptrname =
"long*";
break;
228 case 'L': ptrname =
"unsigned long*";
break;
229 case 'f': ptrname =
"float*";
break;
230 case 'd': ptrname =
"double*";
break;
231 default: ptrname =
"void*";
235 PyObject *pyptrname = PyROOT_PyUnicode_FromString(ptrname);
236 PyTuple_SET_ITEM( tpArgs, i, pyptrname );
241 PyTuple_SET_ITEM( tpArgs, i, pytc );
248 PyObject* pyname_v1 = Utility::BuildTemplateName( pytmpl->fPyName, args, 0 );
249 if ((isType || nStrings == nArgs) && pyname_v1) {
251 pymeth = PyObject_GetAttr( pytmpl->fSelf ? pytmpl->fSelf : pytmpl->fPyClass, pyname_v1 );
253 Py_DECREF( pyname_v1 );
254 if (PyErr_WarnEx(PyExc_FutureWarning,
255 "Instantiating a function template with parentheses ( f(type1, ..., typeN) ) "
256 "is deprecated and will not be supported in a future version of ROOT. "
257 "Instead, use square brackets: f[type1, ..., typeN]", 1) < 0) {
266 pymeth = MethodProxy_Type.tp_descr_get(
267 (PyObject*)pytmpl->fTemplated, pytmpl->fSelf, (PyObject*)&MethodProxy_Type );
268 if ( MethodProxy_Check( pymeth ) ) {
270 PyObject* result = MethodProxy_Type.tp_call( pymeth, args, kwds );
271 Py_DECREF( pymeth ); pymeth = 0;
273 Py_XDECREF( pyname_v1 );
280 Py_XDECREF( pymeth ); pymeth = 0;
285 PyObject* clName = PyObject_GetAttr( pytmpl->fPyClass, PyStrings::gCppName );
288 clName = PyObject_GetAttr(pytmpl->fPyClass, PyStrings::gName);
290 auto clNameStr = std::string(PyROOT_PyUnicode_AsString(clName));
291 if (clNameStr ==
"_global_cpp")
293 TClass* klass = TClass::GetClass(clNameStr.c_str());
295 const std::string& tmplname = pytmpl->fNonTemplated->fMethodInfo->fName;
298 if ( ! isType && ! ( nStrings == nArgs ) ) {
299 for (
auto pref : {Utility::kReference, Utility::kPointer, Utility::kValue}) {
301 PyObject* pyname_v2 = Utility::BuildTemplateName( NULL, tpArgs, 0, args, pref, &pcnt,
true );
303 std::string mname = PyROOT_PyUnicode_AsString( pyname_v2 );
304 Py_DECREF( pyname_v2 );
305 std::string proto = mname.substr( 1, mname.size() - 2 );
307 auto scope = Cppyy::GetScope(clNameStr);
308 auto cppmeth = Cppyy::GetMethodTemplate(scope, tmplname, proto);
310 Py_XDECREF( pyname_v1 );
311 if (Cppyy::IsNamespace(scope) || Cppyy::IsStaticMethod(cppmeth)) {
312 pytmpl->fTemplated->AddMethod(
new TFunctionHolder( scope, cppmeth ) );
313 pymeth = (PyObject*)MethodProxy_New(
314 Cppyy::GetMethodName(cppmeth).c_str(),
new TFunctionHolder( scope, cppmeth ) );
316 pytmpl->fTemplated->AddMethod(
new TMethodHolder( scope, cppmeth ) );
317 pymeth = (PyObject*)MethodProxy_New(
318 Cppyy::GetMethodName(cppmeth).c_str(),
new TMethodHolder( scope, cppmeth ) );
320 PyObject_SetAttrString( pytmpl->fPyClass, (
char*)Cppyy::GetMethodName(cppmeth).c_str(), (PyObject*)pymeth );
322 pymeth = PyObject_GetAttrString(
323 pytmpl->fSelf ? pytmpl->fSelf : pytmpl->fPyClass, (
char*)Cppyy::GetMethodName(cppmeth).c_str() );
324 PyObject* result = MethodProxy_Type.tp_call( pymeth, args, kwds );
335 std::string mname = PyROOT_PyUnicode_AsString( pyname_v1 );
337 TMethod* cppmeth = klass ? klass->GetMethodAny( mname.c_str() ) : 0;
339 pymeth = (PyObject*)MethodProxy_New(
340 mname,
new TMethodHolder( Cppyy::GetScope( klass->GetName() ), (Cppyy::TCppMethod_t)cppmeth ) );
341 PyObject_SetAttr( pytmpl->fPyClass, pyname_v1, (PyObject*)pymeth );
342 if ( mname != cppmeth->GetName() )
343 PyObject_SetAttrString( pytmpl->fPyClass, (
char*)mname.c_str(), (PyObject*)pymeth );
345 pymeth = PyObject_GetAttr( pytmpl->fSelf ? pytmpl->fSelf : pytmpl->fPyClass, pyname_v1 );
346 Py_DECREF( pyname_v1 );
347 if (PyErr_WarnEx(PyExc_FutureWarning,
348 "Instantiating a function template with parentheses ( f(type1, ..., typeN) ) "
349 "is deprecated and will not be supported in a future version of ROOT. "
350 "Instead, use square brackets: f[type1, ..., typeN]", 1) < 0) {
355 Py_DECREF( pyname_v1 );
359 PyErr_Format( PyExc_TypeError,
"can not resolve method template call for \'%s\'",
360 PyROOT_PyUnicode_AsString( pytmpl->fPyName ) );
367 TemplateProxy* tpp_descrget( TemplateProxy* pytmpl, PyObject* pyobj, PyObject* )
369 TemplateProxy* newPyTmpl = (TemplateProxy*)TemplateProxy_Type.tp_alloc( &TemplateProxy_Type, 0 );
372 Py_INCREF( pytmpl->fPyName );
373 newPyTmpl->fPyName = pytmpl->fPyName;
375 Py_XINCREF( pytmpl->fPyClass );
376 newPyTmpl->fPyClass = pytmpl->fPyClass;
379 Py_INCREF( pytmpl->fNonTemplated );
380 newPyTmpl->fNonTemplated = pytmpl->fNonTemplated;
383 Py_INCREF( pytmpl->fTemplated );
384 newPyTmpl->fTemplated = pytmpl->fTemplated;
388 newPyTmpl->fSelf = pyobj;
397 PyObject *tpp_subscript(TemplateProxy *pytmpl, PyObject *args)
399 bool justOne = !PyTuple_CheckExact(args);
404 args = PyTuple_New(nArgs);
406 PyTuple_SET_ITEM(args, 0, item);
408 nArgs = PyTuple_GET_SIZE(args);
411 Bool_t isType =
false;
413 for (
int i = 0; i < nArgs; ++i) {
414 PyObject* itemi = PyTuple_GET_ITEM(args, i);
415 if (PyType_Check(itemi)) isType = kTRUE;
416 #if PY_VERSION_HEX >= 0x03000000
417 else if (! isType && PyUnicode_Check(itemi)) nStrings += 1;
419 else if (! isType && PyBytes_Check(itemi)) nStrings += 1;
424 PyObject* pyname = Utility::BuildTemplateName(pytmpl->fPyName, args, 0);
425 if (justOne) Py_DECREF(args);
428 if ((isType || nStrings == nArgs) && pyname) {
430 PyObject* pymeth = PyObject_GetAttr(pytmpl->fSelf ? pytmpl->fSelf : pytmpl->fPyClass, pyname);
439 PyObject* clName = PyObject_GetAttr(pytmpl->fPyClass, PyStrings::gCppName);
442 clName = PyObject_GetAttr(pytmpl->fPyClass, PyStrings::gName);
444 auto clNameStr = std::string(PyROOT_PyUnicode_AsString(clName));
445 if (clNameStr ==
"_global_cpp")
447 auto klass = TClass::GetClass(clNameStr.c_str());
452 std::string mname = PyROOT_PyUnicode_AsString(pyname);
454 TMethod *cppmeth = klass ? klass->GetMethodAny(mname.c_str()) :
nullptr;
456 PyObject *pymeth = (PyObject*)MethodProxy_New(
457 mname,
new TMethodHolder(Cppyy::GetScope(klass->GetName()),(Cppyy::TCppMethod_t)cppmeth));
458 PyObject_SetAttr(pytmpl->fPyClass, pyname, (PyObject*)pymeth);
459 if (mname != cppmeth->GetName())
460 PyObject_SetAttrString(pytmpl->fPyClass, (
char*)mname.c_str(), (PyObject*)pymeth);
462 pymeth = PyObject_GetAttr(pytmpl->fSelf ? pytmpl->fSelf : pytmpl->fPyClass, pyname);
469 PyErr_Format(PyExc_TypeError,
"cannot resolve method template instantiation for \'%s\'",
470 PyROOT_PyUnicode_AsString(pytmpl->fPyName));
476 static PyMappingMethods tpp_as_mapping = {
477 nullptr, (binaryfunc)tpp_subscript,
nullptr
480 PyGetSetDef tpp_getset[] = {
481 { (
char*)
"__doc__", (getter)tpp_doc, NULL, NULL, NULL },
482 { (
char*)NULL, NULL, NULL, NULL, NULL }
489 PyTypeObject TemplateProxy_Type = {
490 PyVarObject_HEAD_INIT( &PyType_Type, 0 )
491 (
char*)
"ROOT.TemplateProxy",
492 sizeof(TemplateProxy),
494 (destructor)tpp_dealloc,
504 (ternaryfunc)tpp_call,
509 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
510 (
char*)
"PyROOT template proxy (internal)",
511 (traverseproc)tpp_traverse,
522 (descrgetfunc)tpp_descrget,
535 #if PY_VERSION_HEX >= 0x02030000
538 #if PY_VERSION_HEX >= 0x02060000
541 #if PY_VERSION_HEX >= 0x03040000