Logo ROOT   6.18/05
Reference Guide
Utility.cxx
Go to the documentation of this file.
1// @(#)root/pyroot:$Id$
2// Author: Wim Lavrijsen, Apr 2004
3
4// Bindings
5#include "PyROOT.h"
6#include "PyStrings.h"
7#include "Utility.h"
8#include "ObjectProxy.h"
9#include "MethodProxy.h"
10#include "TFunctionHolder.h"
11#include "TCustomPyTypes.h"
12#include "TemplateProxy.h"
13#include "RootWrapper.h"
14#include "PyCallable.h"
15
16// ROOT
17#include "TApplication.h"
18#include "TROOT.h"
19#include "TSystem.h"
20#include "TObject.h"
21#include "TClassEdit.h"
22#include "TClassRef.h"
23#include "TCollection.h"
24#include "TDataType.h"
25#include "TFunction.h"
26#include "TFunctionTemplate.h"
27#include "TMethod.h"
28#include "TMethodArg.h"
29#include "TError.h"
30#include "TInterpreter.h"
31
32// Standard
33#include <stdlib.h>
34#include <stdio.h>
35#include <string.h>
36#include <algorithm>
37#include <list>
38#include <mutex>
39#include <sstream>
40#include <utility>
41
42
43//- data _____________________________________________________________________
46
47typedef std::map< std::string, std::string > TC2POperatorMapping_t;
49
50namespace {
51
52 using namespace PyROOT::Utility;
53
54 struct InitOperatorMapping_t {
55 public:
56 InitOperatorMapping_t() {
57 // Initialize the global map of operator names C++ -> python.
58
59 // gC2POperatorMapping[ "[]" ] = "__setitem__"; // depends on return type
60 // gC2POperatorMapping[ "+" ] = "__add__"; // depends on # of args (see __pos__)
61 // gC2POperatorMapping[ "-" ] = "__sub__"; // id. (eq. __neg__)
62 // gC2POperatorMapping[ "*" ] = "__mul__"; // double meaning in C++
63
64 gC2POperatorMapping[ "[]" ] = "__getitem__";
65 gC2POperatorMapping[ "()" ] = "__call__";
67 gC2POperatorMapping[ "%" ] = "__mod__";
68 gC2POperatorMapping[ "**" ] = "__pow__";
69 gC2POperatorMapping[ "<<" ] = "__lshift__";
70 gC2POperatorMapping[ ">>" ] = "__rshift__";
71 gC2POperatorMapping[ "&" ] = "__and__";
72 gC2POperatorMapping[ "|" ] = "__or__";
73 gC2POperatorMapping[ "^" ] = "__xor__";
74 gC2POperatorMapping[ "~" ] = "__inv__";
75 gC2POperatorMapping[ "+=" ] = "__iadd__";
76 gC2POperatorMapping[ "-=" ] = "__isub__";
77 gC2POperatorMapping[ "*=" ] = "__imul__";
79 gC2POperatorMapping[ "%=" ] = "__imod__";
80 gC2POperatorMapping[ "**=" ] = "__ipow__";
81 gC2POperatorMapping[ "<<=" ] = "__ilshift__";
82 gC2POperatorMapping[ ">>=" ] = "__irshift__";
83 gC2POperatorMapping[ "&=" ] = "__iand__";
84 gC2POperatorMapping[ "|=" ] = "__ior__";
85 gC2POperatorMapping[ "^=" ] = "__ixor__";
86 gC2POperatorMapping[ "==" ] = "__eq__";
87 gC2POperatorMapping[ "!=" ] = "__ne__";
88 gC2POperatorMapping[ ">" ] = "__gt__";
89 gC2POperatorMapping[ "<" ] = "__lt__";
90 gC2POperatorMapping[ ">=" ] = "__ge__";
91 gC2POperatorMapping[ "<=" ] = "__le__";
92
93 // the following type mappings are "exact"
94 gC2POperatorMapping[ "const char*" ] = "__str__";
95 gC2POperatorMapping[ "char*" ] = "__str__";
96 gC2POperatorMapping[ "const char *" ] = gC2POperatorMapping[ "const char*" ];
97 gC2POperatorMapping[ "char *" ] = gC2POperatorMapping[ "char*" ];
98 gC2POperatorMapping[ "int" ] = "__int__";
100 gC2POperatorMapping[ "double" ] = "__float__";
101
102 // the following type mappings are "okay"; the assumption is that they
103 // are not mixed up with the ones above or between themselves (and if
104 // they are, that it is done consistently)
105 gC2POperatorMapping[ "short" ] = "__int__";
106 gC2POperatorMapping[ "unsigned short" ] = "__int__";
107 gC2POperatorMapping[ "unsigned int" ] = PYROOT__long__;
108 gC2POperatorMapping[ "unsigned long" ] = PYROOT__long__;
109 gC2POperatorMapping[ "long long" ] = PYROOT__long__;
110 gC2POperatorMapping[ "unsigned long long" ] = PYROOT__long__;
111 gC2POperatorMapping[ "float" ] = "__float__";
112
113 gC2POperatorMapping[ "->" ] = "__follow__"; // not an actual python operator
114 gC2POperatorMapping[ "=" ] = "__assign__"; // id.
115
116#if PY_VERSION_HEX < 0x03000000
117 gC2POperatorMapping[ "bool" ] = "__nonzero__";
118#else
119 gC2POperatorMapping[ "bool" ] = "__bool__";
120#endif
121 }
122 } initOperatorMapping_;
123
124 std::once_flag sOperatorTemplateFlag;
125 void InitOperatorTemplate() {
126 gROOT->ProcessLine(
127 "namespace _pyroot_internal { template<class C1, class C2>"
128 " bool is_equal(const C1& c1, const C2& c2){ return (bool)(c1 == c2); } }" );
129 gROOT->ProcessLine(
130 "namespace _pyroot_internal { template<class C1, class C2>"
131 " bool is_not_equal(const C1& c1, const C2& c2){ return (bool)(c1 != c2); } }" );
132 }
133
134 inline void RemoveConst( std::string& cleanName ) {
135 std::string::size_type spos = std::string::npos;
136 while ( ( spos = cleanName.find( "const" ) ) != std::string::npos ) {
137 cleanName.swap( cleanName.erase( spos, 5 ) );
138 }
139 }
140
141} // unnamed namespace
142
143
144//- public functions ---------------------------------------------------------
146{
147// Convert <pybject> to C++ unsigned long, with bounds checking, allow int -> ulong.
148 ULong_t ul = PyLong_AsUnsignedLong( pyobject );
149 if ( PyErr_Occurred() && PyInt_Check( pyobject ) ) {
150 PyErr_Clear();
151 Long_t i = PyInt_AS_LONG( pyobject );
152 if ( 0 <= i ) {
153 ul = (ULong_t)i;
154 } else {
155 PyErr_SetString( PyExc_ValueError,
156 "can\'t convert negative value to unsigned long" );
157 }
158 }
159
160 return ul;
161}
162
163////////////////////////////////////////////////////////////////////////////////
164/// Convert <pyobject> to C++ unsigned long long, with bounds checking.
165
167{
168 ULong64_t ull = PyLong_AsUnsignedLongLong( pyobject );
169 if ( PyErr_Occurred() && PyInt_Check( pyobject ) ) {
170 PyErr_Clear();
171 Long_t i = PyInt_AS_LONG( pyobject );
172 if ( 0 <= i ) {
173 ull = (ULong64_t)i;
174 } else {
175 PyErr_SetString( PyExc_ValueError,
176 "can\'t convert negative value to unsigned long long" );
177 }
178 }
179
180 return ull;
181}
182
183////////////////////////////////////////////////////////////////////////////////
184/// Add the given function to the class under name 'label'.
185
187 PyObject* pyclass, const char* label, PyCFunction cfunc, int flags )
188{
189// use list for clean-up (.so's are unloaded only at interpreter shutdown)
190 static std::list< PyMethodDef > s_pymeths;
191
192 s_pymeths.push_back( PyMethodDef() );
193 PyMethodDef* pdef = &s_pymeths.back();
194 pdef->ml_name = const_cast< char* >( label );
195 pdef->ml_meth = cfunc;
196 pdef->ml_flags = flags;
197 pdef->ml_doc = NULL;
198
199 PyObject* func = PyCFunction_New( pdef, NULL );
200 PyObject* method = TCustomInstanceMethod_New( func, NULL, pyclass );
201 Bool_t isOk = PyObject_SetAttrString( pyclass, pdef->ml_name, method ) == 0;
202 Py_DECREF( method );
203 Py_DECREF( func );
204
205 if ( PyErr_Occurred() )
206 return kFALSE;
207
208 if ( ! isOk ) {
209 PyErr_Format( PyExc_TypeError, "could not add method %s", label );
210 return kFALSE;
211 }
212
213 return kTRUE;
214}
215
216////////////////////////////////////////////////////////////////////////////////
217/// Add the given function to the class under name 'label'.
218
219Bool_t PyROOT::Utility::AddToClass( PyObject* pyclass, const char* label, const char* func )
220{
221 PyObject* pyfunc = PyObject_GetAttrString( pyclass, const_cast< char* >( func ) );
222 if ( ! pyfunc )
223 return kFALSE;
224
225 Bool_t isOk = PyObject_SetAttrString( pyclass, const_cast< char* >( label ), pyfunc ) == 0;
226
227 Py_DECREF( pyfunc );
228 return isOk;
229}
230
231////////////////////////////////////////////////////////////////////////////////
232/// Add the given function to the class under name 'label'.
233
234Bool_t PyROOT::Utility::AddToClass( PyObject* pyclass, const char* label, PyCallable* pyfunc )
235{
236 MethodProxy* method =
237 (MethodProxy*)PyObject_GetAttrString( pyclass, const_cast< char* >( label ) );
238
239 if ( ! method || ! MethodProxy_Check( method ) ) {
240 // not adding to existing MethodProxy; add callable directly to the class
241 if ( PyErr_Occurred() )
242 PyErr_Clear();
243 Py_XDECREF( (PyObject*)method );
244 method = MethodProxy_New( label, pyfunc );
245 Bool_t isOk = PyObject_SetAttrString(
246 pyclass, const_cast< char* >( label ), (PyObject*)method ) == 0;
247 Py_DECREF( method );
248 return isOk;
249 }
250
251 method->AddMethod( pyfunc );
252
253 Py_DECREF( method );
254 return kTRUE;
255}
256
257////////////////////////////////////////////////////////////////////////////////
258/// Helper to add base class methods to the derived class one (this covers the
259/// 'using' cases, which the dictionary does not provide).
260
261Bool_t PyROOT::Utility::AddUsingToClass( PyObject* pyclass, const char* method )
262{
263 MethodProxy* derivedMethod =
264 (MethodProxy*)PyObject_GetAttrString( pyclass, const_cast< char* >( method ) );
265 if ( ! MethodProxy_Check( derivedMethod ) ) {
266 Py_XDECREF( derivedMethod );
267 return kFALSE;
268 }
269
270 PyObject* mro = PyObject_GetAttr( pyclass, PyStrings::gMRO );
271 if ( ! mro || ! PyTuple_Check( mro ) ) {
272 Py_XDECREF( mro );
273 Py_DECREF( derivedMethod );
274 return kFALSE;
275 }
276
277 MethodProxy* baseMethod = 0;
278 for ( int i = 1; i < PyTuple_GET_SIZE( mro ); ++i ) {
279 baseMethod = (MethodProxy*)PyObject_GetAttrString(
280 PyTuple_GET_ITEM( mro, i ), const_cast< char* >( method ) );
281
282 if ( ! baseMethod ) {
283 PyErr_Clear();
284 continue;
285 }
286
287 if ( MethodProxy_Check( baseMethod ) )
288 break;
289
290 Py_DECREF( baseMethod );
291 baseMethod = 0;
292 }
293
294 Py_DECREF( mro );
295
296 if ( ! MethodProxy_Check( baseMethod ) ) {
297 Py_XDECREF( baseMethod );
298 Py_DECREF( derivedMethod );
299 return kFALSE;
300 }
301
302 derivedMethod->AddMethod( baseMethod );
303
304 Py_DECREF( baseMethod );
305 Py_DECREF( derivedMethod );
306
307 return kTRUE;
308}
309
310////////////////////////////////////////////////////////////////////////////////
311/// Install the named operator (op) into the left object's class if such a function
312/// exists as a global overload; a label must be given if the operator is not in
313/// gC2POperatorMapping (i.e. if it is ambiguous at the member level).
314
316 PyObject* left, PyObject* right, const char* op, const char* label, const char* alt )
317{
318// this should be a given, nevertheless ...
319 if ( ! ObjectProxy_Check( left ) )
320 return kFALSE;
321
322// retrieve the class names to match the signature of any found global functions
323 std::string rcname = ClassName( right );
324 std::string lcname = ClassName( left );
325 PyObject* pyclass = PyObject_GetAttr( left, PyStrings::gClass );
326
327 Bool_t result = AddBinaryOperator( pyclass, lcname, rcname, op, label, alt );
328
329 Py_DECREF( pyclass );
330 return result;
331}
332
333////////////////////////////////////////////////////////////////////////////////
334/// Install binary operator op in pyclass, working on two instances of pyclass.
335
337 PyObject* pyclass, const char* op, const char* label, const char* alt )
338{
339 PyObject* pyname = PyObject_GetAttr( pyclass, PyStrings::gCppName );
340 if ( ! pyname ) pyname = PyObject_GetAttr( pyclass, PyStrings::gName );
341 std::string cname = Cppyy::ResolveName( PyROOT_PyUnicode_AsString( pyname ) );
342 Py_DECREF( pyname ); pyname = 0;
343
344 return AddBinaryOperator( pyclass, cname, cname, op, label, alt );
345}
346
347////////////////////////////////////////////////////////////////////////////////
348/// Helper to find a function with matching signature in 'funcs'.
349
350static inline Cppyy::TCppMethod_t FindAndAddOperator( const std::string& lcname, const std::string& rcname,
351 const char* op, TClass* klass = 0 ) {
352 std::string opname = "operator";
353 opname += op;
354 std::string proto = lcname + ", " + rcname;
355
356// case of global namespace
357 if ( ! klass )
358 return (Cppyy::TCppMethod_t)gROOT->GetGlobalFunctionWithPrototype( opname.c_str(), proto.c_str() );
359
360// case of specific namespace
361 return (Cppyy::TCppMethod_t)klass->GetMethodWithPrototype( opname.c_str(), proto.c_str() );
362}
363
364Bool_t PyROOT::Utility::AddBinaryOperator( PyObject* pyclass, const std::string& lcname,
365 const std::string& rcname, const char* op, const char* label, const char* alt )
366{
367// Find a global function with a matching signature and install the result on pyclass;
368// in addition, __gnu_cxx, std::__1, and _pyroot_internal are searched pro-actively (as
369// there's AFAICS no way to unearth using information).
370
371// This function can be called too early when setting up some of the ROOT core classes,
372// which in turn can trigger the creation of a (default) TApplication. Wait with looking
373// for binary operators '!=' and '==' (which are set early in Pythonize.cxx) until fully
374// initialized. Other operators are expected to have entered from user code.
375 if ( !gApplication && (strcmp( op, "==" ) == 0 || strcmp( op, "!=" ) == 0) )
376 return kFALSE;
377
378// For GNU on clang, search the internal __gnu_cxx namespace for binary operators (is
379// typically the case for STL iterators operator==/!=.
380 static TClassRef gnucxx( "__gnu_cxx" );
381 static bool gnucxx_exists = (bool)gnucxx.GetClass();
382
383// Same for clang on Mac. TODO: find proper pre-processor magic to only use those specific
384// namespaces that are actually around; although to be sure, this isn't expensive.
385 static TClassRef std__1( "std::__1" );
386 static bool std__1_exists = (bool)std__1.GetClass();
387
388// One more, mostly for Mac, but again not sure whether this is not a general issue. Some
389// operators are declared as friends only in classes, so then they're not found in the
390// global namespace. That's why there's this little helper.
391 std::call_once( sOperatorTemplateFlag, InitOperatorTemplate );
392 static TClassRef _pr_int( "_pyroot_internal" );
393
394 PyCallable* pyfunc = 0;
395 if ( gnucxx_exists ) {
396 Cppyy::TCppMethod_t func = FindAndAddOperator( lcname, rcname, op, gnucxx.GetClass() );
397 if ( func ) pyfunc = new TFunctionHolder( Cppyy::GetScope( "__gnu_cxx" ), func );
398 }
399
400 if ( ! pyfunc && std__1_exists ) {
401 Cppyy::TCppMethod_t func = FindAndAddOperator( lcname, rcname, op, std__1.GetClass() );
402 if ( func ) pyfunc = new TFunctionHolder( Cppyy::GetScope( "std::__1" ), func );
403 }
404
405 if ( ! pyfunc ) {
406 std::string::size_type pos = lcname.substr(0, lcname.find('<')).rfind( "::" );
407 if ( pos != std::string::npos ) {
408 TClass* lcscope = TClass::GetClass( lcname.substr( 0, pos ).c_str() );
409 if ( lcscope ) {
410 Cppyy::TCppMethod_t func = FindAndAddOperator( lcname, rcname, op, lcscope );
411 if ( func ) pyfunc = new TFunctionHolder( Cppyy::GetScope( lcname.substr( 0, pos ) ), func );
412 }
413 }
414 }
415
416 if ( ! pyfunc ) {
417 Cppyy::TCppMethod_t func = FindAndAddOperator( lcname, rcname, op );
418 if ( func ) pyfunc = new TFunctionHolder( Cppyy::gGlobalScope, func );
419 }
420
421 if ( ! pyfunc && _pr_int.GetClass() &&
422 lcname.find( "iterator" ) != std::string::npos &&
423 rcname.find( "iterator" ) != std::string::npos ) {
424 // TODO: gets called too often; make sure it's purely lazy calls only; also try to
425 // find a better notion for which classes (other than iterators) this is supposed to
426 // work; right now it fails for cases where None is passed
427 std::stringstream fname;
428 if ( strncmp( op, "==", 2 ) == 0 ) { fname << "is_equal<"; }
429 else if ( strncmp( op, "!=", 2 ) == 0 ) { fname << "is_not_equal<"; }
430 else { fname << "not_implemented<"; }
431 fname << lcname << ", " << rcname << ">";
432 Cppyy::TCppMethod_t func = (Cppyy::TCppMethod_t)_pr_int->GetMethodAny( fname.str().c_str() );
433 if ( func ) pyfunc = new TFunctionHolder( Cppyy::GetScope( "_pyroot_internal" ), func );
434 }
435
436// last chance: there could be a non-instantiated templated method
437 TClass* lc = TClass::GetClass( lcname.c_str() );
438 if ( lc && strcmp(op, "==") != 0 && strcmp(op, "!=") != 0 ) {
439 std::string opname = "operator"; opname += op;
440 gInterpreter->LoadFunctionTemplates(lc);
441 gInterpreter->GetFunctionTemplate(lc->GetClassInfo(), opname.c_str());
442 TFunctionTemplate*f = lc->GetFunctionTemplate(opname.c_str());
444 (Cppyy::TCppMethod_t)lc->GetMethodWithPrototype( opname.c_str(), rcname.c_str() );
445 if ( func && f ) pyfunc = new TMethodHolder( Cppyy::GetScope( lcname ), func );
446 }
447
448 if ( pyfunc ) { // found a matching overload; add to class
449 Bool_t ok = AddToClass( pyclass, label, pyfunc );
450 if ( ok && alt )
451 return AddToClass( pyclass, alt, label );
452 }
453
454 return kFALSE;
455}
456
457////////////////////////////////////////////////////////////////////////////////
458/// Helper to construct the "< type, type, ... >" part of a templated name (either
459/// for a class as in MakeRootTemplateClass in RootModule.cxx) or for method lookup
460/// (as in TemplatedMemberHook, below).
461
463 PyObject* args, ArgPreference pref, int* pcnt, bool inferredTypes )
464{
465 if ( pyname )
467 else
470
471 Py_ssize_t nArgs = PyTuple_GET_SIZE( tpArgs );
472 for ( int i = argoff; i < nArgs; ++i ) {
473 // add type as string to name
474 PyObject* tn = PyTuple_GET_ITEM( tpArgs, i );
475 if ( PyROOT_PyUnicode_Check( tn ) ) {
477 } else if (PyObject_HasAttr( tn, PyStrings::gName ) ) {
478 // __cppname__ provides a better name for C++ classes (namespaces)
479 PyObject* tpName;
480 if ( PyObject_HasAttr( tn, PyStrings::gCppName ) ) {
481 tpName = PyObject_GetAttr( tn, PyStrings::gCppName );
482 } else {
483 tpName = PyObject_GetAttr( tn, PyStrings::gName );
484 }
485
486 // Check if parameter is reference, pointer or value
487 if (args) {
488 auto arg = PyTuple_GET_ITEM(args, i);
489 ObjectProxy* pyobj = (ObjectProxy*)arg;
490 if (ObjectProxy_Check(pyobj)) {
491 if (pcnt) *pcnt += 1;
492 if ((pyobj->fFlags & ObjectProxy::kIsReference) || pref == kPointer) {
494 } else if (pref != kValue) {
496 }
497 }
498 }
499
500 // special case for strings
501 auto tpNameStr = PyROOT_PyUnicode_AsString(tpName);
502 if ( strcmp( tpNameStr, "str" ) == 0 ) {
503 Py_DECREF( tpName );
504 tpName = PyROOT_PyUnicode_FromString( "std::string" );
505 }
506 // and Python float (should be double in C++) if types have been inferred
507 else if (inferredTypes && strcmp(tpNameStr, "float") == 0) {
508 Py_DECREF(tpName);
509 tpName = PyROOT_PyUnicode_FromString("double");
510 }
512 } else if ( PyInt_Check( tn ) || PyLong_Check( tn ) || PyFloat_Check( tn ) ) {
513 // last ditch attempt, works for things like int values; since this is a
514 // source of errors otherwise, it is limited to specific types and not
515 // generally used (str(obj) can print anything ...)
516 PyObject* pystr = PyObject_Str( tn );
518 } else {
519 Py_DECREF( pyname );
520 PyErr_SetString( PyExc_SyntaxError, "could not get __cppname__ from provided template argument. Is it a str, class, type or int?" );
521 return 0;
522 }
523
524 // add a comma, as needed
525 if ( i != nArgs - 1 )
527 }
528
529// close template name; prevent '>>', which should be '> >'
532 else
534
535 return pyname;
536}
537
538////////////////////////////////////////////////////////////////////////////////
539/// Initialize a proxy class for use by python, and add it to the ROOT module.
540
541Bool_t PyROOT::Utility::InitProxy( PyObject* module, PyTypeObject* pytype, const char* name )
542{
543// finalize proxy type
544 if ( PyType_Ready( pytype ) < 0 )
545 return kFALSE;
546
547// add proxy type to the given (ROOT) module
548 Py_INCREF( pytype ); // PyModule_AddObject steals reference
549 if ( PyModule_AddObject( module, (char*)name, (PyObject*)pytype ) < 0 ) {
550 Py_DECREF( pytype );
551 return kFALSE;
552 }
553
554// declare success
555 return kTRUE;
556}
557
558////////////////////////////////////////////////////////////////////////////////
559/// Retrieve a linear buffer pointer from the given pyobject.
560
561int PyROOT::Utility::GetBuffer( PyObject* pyobject, char tc, int size, void*& buf, Bool_t check )
562{
563// special case: don't handle character strings here (yes, they're buffers, but not quite)
564 if ( PyBytes_Check( pyobject ) )
565 return 0;
566
567// attempt to retrieve pointer to buffer interface
568 PyBufferProcs* bufprocs = Py_TYPE(pyobject)->tp_as_buffer;
569
570 PySequenceMethods* seqmeths = Py_TYPE(pyobject)->tp_as_sequence;
571 if ( seqmeths != 0 && bufprocs != 0
572#if PY_VERSION_HEX < 0x03000000
573 && bufprocs->bf_getwritebuffer != 0
574 && (*(bufprocs->bf_getsegcount))( pyobject, 0 ) == 1
575#else
576 && bufprocs->bf_getbuffer != 0
577#endif
578 ) {
579
580 // get the buffer
581#if PY_VERSION_HEX < 0x03000000
582 Py_ssize_t buflen = (*(bufprocs->bf_getwritebuffer))( pyobject, 0, &buf );
583#else
584 Py_buffer bufinfo;
585 (*(bufprocs->bf_getbuffer))( pyobject, &bufinfo, PyBUF_WRITABLE );
586 buf = (char*)bufinfo.buf;
587 Py_ssize_t buflen = bufinfo.len;
588#if PY_VERSION_HEX < 0x03010000
589 PyBuffer_Release( pyobject, &bufinfo );
590#else
591 PyBuffer_Release( &bufinfo );
592#endif
593#endif
594
595 if ( buf && check == kTRUE ) {
596 // determine buffer compatibility (use "buf" as a status flag)
597 PyObject* pytc = PyObject_GetAttr( pyobject, PyStrings::gTypeCode );
598 if ( pytc != 0 ) { // for array objects
599 if ( PyROOT_PyUnicode_AsString( pytc )[0] != tc )
600 buf = 0; // no match
601 Py_DECREF( pytc );
602 } else if ( seqmeths->sq_length &&
603 (int)(buflen / (*(seqmeths->sq_length))( pyobject )) == size ) {
604 // this is a gamble ... may or may not be ok, but that's for the user
605 PyErr_Clear();
606 } else if ( buflen == size ) {
607 // also a gamble, but at least 1 item will fit into the buffer, so very likely ok ...
608 PyErr_Clear();
609 } else {
610 buf = 0; // not compatible
611
612 // clarify error message
613 PyObject* pytype = 0, *pyvalue = 0, *pytrace = 0;
614 PyErr_Fetch( &pytype, &pyvalue, &pytrace );
616 (char*)"%s and given element size (%ld) do not match needed (%d)",
617 PyROOT_PyUnicode_AsString( pyvalue ),
618 seqmeths->sq_length ? (Long_t)(buflen / (*(seqmeths->sq_length))( pyobject )) : (Long_t)buflen,
619 size );
620 Py_DECREF( pyvalue );
621 PyErr_Restore( pytype, pyvalue2, pytrace );
622 }
623 }
624
625 return buflen;
626 }
627
628 return 0;
629}
630
631////////////////////////////////////////////////////////////////////////////////
632/// Map the given C++ operator name on the python equivalent.
633
634std::string PyROOT::Utility::MapOperatorName( const std::string& name, Bool_t bTakesParams )
635{
636 if ( 8 < name.size() && name.substr( 0, 8 ) == "operator" ) {
637 std::string op = name.substr( 8, std::string::npos );
638
639 // stripping ...
640 std::string::size_type start = 0, end = op.size();
641 while ( start < end && isspace( op[ start ] ) ) ++start;
642 while ( start < end && isspace( op[ end-1 ] ) ) --end;
643 op = TClassEdit::ResolveTypedef( op.substr( start, end - start ).c_str(), true );
644
645 // map C++ operator to python equivalent, or made up name if no equivalent exists
646 TC2POperatorMapping_t::iterator pop = gC2POperatorMapping.find( op );
647 if ( pop != gC2POperatorMapping.end() ) {
648 return pop->second;
649
650 } else if ( op == "*" ) {
651 // dereference v.s. multiplication of two instances
652 return bTakesParams ? "__mul__" : "__deref__";
653
654 } else if ( op == "+" ) {
655 // unary positive v.s. addition of two instances
656 return bTakesParams ? "__add__" : "__pos__";
657
658 } else if ( op == "-" ) {
659 // unary negative v.s. subtraction of two instances
660 return bTakesParams ? "__sub__" : "__neg__";
661
662 } else if ( op == "++" ) {
663 // prefix v.s. postfix increment
664 return bTakesParams ? "__postinc__" : "__preinc__";
665
666 } else if ( op == "--" ) {
667 // prefix v.s. postfix decrement
668 return bTakesParams ? "__postdec__" : "__predec__";
669 }
670
671 }
672
673// might get here, as not all operator methods are handled (new, delete, etc.)
674 return name;
675}
676
677////////////////////////////////////////////////////////////////////////////////
678/// Break down the compound of a fully qualified type name.
679
680const std::string PyROOT::Utility::Compound( const std::string& name )
681{
682 std::string cleanName = name;
683 RemoveConst( cleanName );
684
685 std::string compound = "";
686 for ( int ipos = (int)cleanName.size()-1; 0 <= ipos; --ipos ) {
687 char c = cleanName[ipos];
688 if ( isspace( c ) ) continue;
689 if ( isalnum( c ) || c == '_' || c == '>' ) break;
690
691 compound = c + compound;
692 }
693
694// for arrays (TODO: deal with the actual size)
695 if ( compound == "]" )
696 return "[]";
697
698 return compound;
699}
700
701////////////////////////////////////////////////////////////////////////////////
702/// Extract size from an array type, if available.
703
705{
706 std::string cleanName = name;
707 RemoveConst( cleanName );
708
709 if ( cleanName[cleanName.size()-1] == ']' ) {
710 std::string::size_type idx = cleanName.rfind( '[' );
711 if ( idx != std::string::npos ) {
712 const std::string asize = cleanName.substr( idx+1, cleanName.size()-2 );
713 return strtoul( asize.c_str(), NULL, 0 );
714 }
715 }
716
717 return -1;
718}
719
720////////////////////////////////////////////////////////////////////////////////
721/// Retrieve the class name from the given python object (which may be just an
722/// instance of the class).
723
724const std::string PyROOT::Utility::ClassName( PyObject* pyobj )
725{
726 std::string clname = "<unknown>";
727 PyObject* pyclass = PyObject_GetAttr( pyobj, PyStrings::gClass );
728 if ( pyclass != 0 ) {
729 PyObject* pyname = PyObject_GetAttr( pyclass, PyStrings::gCppName );
730
731 if ( pyname != 0 ) {
733 Py_DECREF( pyname );
734 } else {
735 PyErr_Clear();
736 pyname = PyObject_GetAttr( pyclass, PyStrings::gName );
737 if ( pyname != 0 ) {
739 Py_DECREF( pyname );
740 } else {
741 PyErr_Clear();
742 }
743 }
744 Py_DECREF( pyclass );
745 } else {
746 PyErr_Clear();
747 }
748
749 return clname;
750}
751
752////////////////////////////////////////////////////////////////////////////////
753/// Translate CINT error/warning into python equivalent.
754
755void PyROOT::Utility::ErrMsgCallback( char* /* msg */ )
756{
757// TODO (Cling): this function is probably not going to be used anymore and
758// may need removing at some point for cleanup
759
760/* Commented out for Cling ---
761
762// ignore the "*** Interpreter error recovered ***" message
763 if ( strstr( msg, "error recovered" ) )
764 return;
765
766// ignore CINT-style FILE/LINE messages
767 if ( strstr( msg, "FILE:" ) )
768 return;
769
770// get file name and line number
771 char* errFile = (char*)G__stripfilename( G__get_ifile()->name );
772 int errLine = G__get_ifile()->line_number;
773
774// ignore ROOT-style FILE/LINE messages
775 char buf[256];
776 snprintf( buf, 256, "%s:%d:", errFile, errLine );
777 if ( strstr( msg, buf ) )
778 return;
779
780// strip newline, if any
781 int len = strlen( msg );
782 if ( msg[ len-1 ] == '\n' )
783 msg[ len-1 ] = '\0';
784
785// concatenate message if already in error processing mode (e.g. if multiple CINT errors)
786 if ( PyErr_Occurred() ) {
787 PyObject *etype, *value, *trace;
788 PyErr_Fetch( &etype, &value, &trace ); // clears current exception
789
790 // need to be sure that error can be added; otherwise leave earlier error in place
791 if ( PyROOT_PyUnicode_Check( value ) ) {
792 if ( ! PyErr_GivenExceptionMatches( etype, PyExc_IndexError ) )
793 PyROOT_PyUnicode_AppendAndDel( &value, PyROOT_PyUnicode_FromString( (char*)"\n " ) );
794 PyROOT_PyUnicode_AppendAndDel( &value, PyROOT_PyUnicode_FromString( msg ) );
795 }
796
797 PyErr_Restore( etype, value, trace );
798 return;
799 }
800
801// else, translate known errors and warnings, or simply accept the default
802 char* format = (char*)"(file \"%s\", line %d) %s";
803 char* p = 0;
804 if ( ( p = strstr( msg, "Syntax Error:" ) ) )
805 PyErr_Format( PyExc_SyntaxError, format, errFile, errLine, p+14 );
806 else if ( ( p = strstr( msg, "Error: Array" ) ) )
807 PyErr_Format( PyExc_IndexError, format, errFile, errLine, p+12 );
808 else if ( ( p = strstr( msg, "Error:" ) ) )
809 PyErr_Format( PyExc_RuntimeError, format, errFile, errLine, p+7 );
810 else if ( ( p = strstr( msg, "Exception:" ) ) )
811 PyErr_Format( PyExc_RuntimeError, format, errFile, errLine, p+11 );
812 else if ( ( p = strstr( msg, "Limitation:" ) ) )
813 PyErr_Format( PyExc_NotImplementedError, format, errFile, errLine, p+12 );
814 else if ( ( p = strstr( msg, "Internal Error: malloc" ) ) )
815 PyErr_Format( PyExc_MemoryError, format, errFile, errLine, p+23 );
816 else if ( ( p = strstr( msg, "Internal Error:" ) ) )
817 PyErr_Format( PyExc_SystemError, format, errFile, errLine, p+16 );
818 else if ( ( p = strstr( msg, "Warning:" ) ) )
819// either printout or raise exception, depending on user settings
820 PyErr_WarnExplicit( NULL, p+9, errFile, errLine, (char*)"CINT", NULL );
821 else if ( ( p = strstr( msg, "Note:" ) ) )
822 fprintf( stdout, "Note: (file \"%s\", line %d) %s\n", errFile, errLine, p+6 );
823 else // unknown: printing it to screen is the safest action
824 fprintf( stdout, "Message: (file \"%s\", line %d) %s\n", errFile, errLine, msg );
825
826 --- Commented out for Cling */
827}
828
829////////////////////////////////////////////////////////////////////////////////
830/// Translate ROOT error/warning to python.
831
832void PyROOT::Utility::ErrMsgHandler( int level, Bool_t abort, const char* location, const char* msg )
833{
834// initialization from gEnv (the default handler will return w/o msg b/c level too low)
835 if ( gErrorIgnoreLevel == kUnset )
836 ::DefaultErrorHandler( kUnset - 1, kFALSE, "", "" );
837
838 if ( level < gErrorIgnoreLevel )
839 return;
840
841// turn warnings into python warnings
842 if (level >= kError)
843 ::DefaultErrorHandler( level, abort, location, msg );
844 else if ( level >= kWarning ) {
845 static const char* emptyString = "";
846 if (!location) location = emptyString;
847 // This warning might be triggered while holding the ROOT lock, while
848 // some othe rtherad is holding the GIL and waiting for the ROOT lock.
849 // That will trigger a deadlock.
850 // So if ROOT is in MT mode, use ROOT's error handler that doesn't take
851 // the GIL.
852 if (!gGlobalMutex) {
853 // either printout or raise exception, depending on user settings
854 PyErr_WarnExplicit( NULL, (char*)msg, (char*)location, 0, (char*)"ROOT", NULL );
855 } else {
856 ::DefaultErrorHandler( level, abort, location, msg );
857 }
858 }
859 else
860 ::DefaultErrorHandler( level, abort, location, msg );
861}
862
863
864////////////////////////////////////////////////////////////////////////////////
865/// Compile a function on the fly and return a function pointer for use on C-APIs.
866/// The callback should take a (void*)pyfunc and the (Long_t)user as well as the
867/// rest of the declare signature. It should also live in namespace PyROOT
868
870 const char* retType, const std::vector<std::string>& signature, const char* callback )
871{
872 static Long_t s_fid = 0;
873
874 if ( ! PyCallable_Check( pyfunc ) )
875 return 0;
876
877// keep alive (TODO: manage this intelligently)
878 Py_INCREF( pyfunc );
879
880 Long_t fid = s_fid++;
881
882// basic function name part
883 std::ostringstream funcName;
884 funcName << "pyrootGenFun" << fid;
885
886// build-up a signature
887 std::ostringstream sigDecl, argsig;
888 std::vector<std::string>::size_type nargs = signature.size();
889 for ( std::vector<std::string>::size_type i = 0; i < nargs; ++i ) {
890 sigDecl << signature[i] << " a" << i;
891 argsig << ", a" << i;
892 if ( i != nargs-1 ) sigDecl << ", ";
893 }
894
895// create full definition
896 std::ostringstream declCode;
897 declCode << "namespace PyROOT { "
898 << retType << " " << callback << "(void*, Long_t, " << sigDecl.str() << "); }\n"
899 << retType << " " << funcName.str() << "(" << sigDecl.str()
900 << ") { void* v0 = (void*)" << (void*)pyfunc << "; "
901 << "return PyROOT::" << callback << "(v0, " << user << argsig.str() << "); }";
902
903// body compilation
904 gInterpreter->LoadText( declCode.str().c_str() );
905
906// func-ptr retrieval code
907 std::ostringstream fptrCode;
908 fptrCode << "void* pyrootPtrVar" << fid << " = (void*)" << funcName.str()
909 << "; pyrootPtrVar" << fid << ";";
910
911// retrieve function pointer
912 void* fptr = (void*)gInterpreter->ProcessLineSynch( fptrCode.str().c_str() );
913 if ( fptr == 0 )
914 PyErr_SetString( PyExc_SyntaxError, "could not generate C++ callback wrapper" );
915
916 return fptr;
917}
918
919////////////////////////////////////////////////////////////////////////////////
920/// Re-acquire the GIL before calling PyErr_Occurred() in case it has been
921/// released; note that the p2.2 code assumes that there are no callbacks in
922/// C++ to python (or at least none returning errors).
923
925{
926#if PY_VERSION_HEX >= 0x02030000
927 PyGILState_STATE gstate = PyGILState_Ensure();
928 PyObject* e = PyErr_Occurred();
929 PyGILState_Release( gstate );
930#else
931 if ( PyThreadState_GET() )
932 return PyErr_Occurred();
933 PyObject* e = 0;
934#endif
935
936 return e;
937}
938
939////////////////////////////////////////////////////////////////////////////////
940
941namespace {
942 static int (*sOldInputHook)() = NULL;
943 static PyThreadState* sInputHookEventThreadState = NULL;
944
945 static int EventInputHook()
946 {
947 // This method is supposed to be called from CPython's command line and
948 // drives the GUI.
949 PyEval_RestoreThread( sInputHookEventThreadState );
951 PyEval_SaveThread();
952
953 if ( sOldInputHook ) return sOldInputHook();
954 return 0;
955 }
956
957} // unnamed namespace
958
960{
961// Install the method hook for sending events to the GUI
962 if ( PyOS_InputHook && PyOS_InputHook != &EventInputHook )
963 sOldInputHook = PyOS_InputHook;
964
965 sInputHookEventThreadState = PyThreadState_Get();
966
967 PyOS_InputHook = (int (*)())&EventInputHook;
968 Py_INCREF( Py_None );
969 return Py_None;
970}
971
973{
974// Remove event hook, if it was installed
975 PyOS_InputHook = sOldInputHook;
976 sInputHookEventThreadState = NULL;
977
978 Py_INCREF( Py_None );
979 return Py_None;
980}
#define Py_TYPE(ob)
Definition: PyROOT.h:161
#define PyROOT_PyUnicode_Append
Definition: PyROOT.h:84
int Py_ssize_t
Definition: PyROOT.h:166
#define PyROOT_PyUnicode_Check
Definition: PyROOT.h:76
#define PyBytes_Check
Definition: PyROOT.h:64
#define PyROOT_PyUnicode_AsString
Definition: PyROOT.h:78
#define PyROOT_PyUnicode_AppendAndDel
Definition: PyROOT.h:85
PyDictEntry *(* dict_lookup_func)(PyDictObject *, PyObject *, Long_t)
Definition: PyROOT.h:43
#define PYROOT__div__
Definition: PyROOT.h:102
#define PyROOT_PyUnicode_FromString
Definition: PyROOT.h:82
#define PyROOT_PyUnicode_FromFormat
Definition: PyROOT.h:81
#define PyROOT_PyUnicode_GetSize
Definition: PyROOT.h:54
#define PYROOT__idiv__
Definition: PyROOT.h:101
#define PYROOT__long__
Definition: PyROOT.h:100
#define f(i)
Definition: RSha256.hxx:104
#define c(i)
Definition: RSha256.hxx:101
#define e(i)
Definition: RSha256.hxx:103
const Bool_t kFALSE
Definition: RtypesCore.h:88
unsigned long ULong_t
Definition: RtypesCore.h:51
long Long_t
Definition: RtypesCore.h:50
bool Bool_t
Definition: RtypesCore.h:59
unsigned long long ULong64_t
Definition: RtypesCore.h:70
const Bool_t kTRUE
Definition: RtypesCore.h:87
R__EXTERN TApplication * gApplication
Definition: TApplication.h:165
@ kIsReference
Definition: TDictionary.h:81
void DefaultErrorHandler(int level, Bool_t abort, const char *location, const char *msg)
The default error handler function.
Definition: TError.cxx:125
const Int_t kError
Definition: TError.h:39
const Int_t kUnset
Definition: TError.h:35
const Int_t kWarning
Definition: TError.h:38
R__EXTERN Int_t gErrorIgnoreLevel
Definition: TError.h:105
char name[80]
Definition: TGX11.cxx:109
#define gInterpreter
Definition: TInterpreter.h:553
#define pyname
Definition: TMCParticle.cxx:19
_object PyObject
Definition: TPyArg.h:20
#define gROOT
Definition: TROOT.h:414
R__EXTERN TSystem * gSystem
Definition: TSystem.h:560
R__EXTERN TVirtualMutex * gGlobalMutex
Definition: TVirtualMutex.h:29
@ kPointer
Definition: TVirtualX.h:47
static Cppyy::TCppMethod_t FindAndAddOperator(const std::string &lcname, const std::string &rcname, const char *op, TClass *klass=0)
Helper to find a function with matching signature in 'funcs'.
Definition: Utility.cxx:350
static TC2POperatorMapping_t gC2POperatorMapping
Definition: Utility.cxx:48
std::map< std::string, std::string > TC2POperatorMapping_t
Definition: Utility.cxx:47
const char * proto
Definition: civetweb.c:16604
void AddMethod(PyCallable *pc)
Fill in the data of a freshly created method proxy.
TClassRef is used to implement a permanent reference to a TClass object.
Definition: TClassRef.h:29
TClass * GetClass() const
Definition: TClassRef.h:71
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:75
TMethod * GetMethodWithPrototype(const char *method, const char *proto, Bool_t objectIsConst=kFALSE, ROOT::EFunctionMatchMode mode=ROOT::kConversionMatch)
Find the method with a given prototype.
Definition: TClass.cxx:4326
ClassInfo_t * GetClassInfo() const
Definition: TClass.h:404
TMethod * GetMethodAny(const char *method)
Return pointer to method without looking at parameters.
Definition: TClass.cxx:4244
TFunctionTemplate * GetFunctionTemplate(const char *name)
Definition: TClass.cxx:3496
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2895
Dictionary for function template This class describes one single function template.
virtual Bool_t ProcessEvents()
Process pending events (GUI, timers, sockets).
Definition: TSystem.cxx:425
void compound()
Definition: compound.C:25
TCppScope_t gGlobalScope
Definition: Cppyy.cxx:64
std::string ResolveName(const std::string &cppitem_name)
Definition: Cppyy.cxx:167
TCppScope_t GetScope(const std::string &scope_name)
Definition: Cppyy.cxx:193
ptrdiff_t TCppMethod_t
Definition: Cppyy.h:18
R__EXTERN PyObject * gClass
Definition: PyStrings.h:18
R__EXTERN PyObject * gName
Definition: PyStrings.h:33
R__EXTERN PyObject * gMRO
Definition: PyStrings.h:32
R__EXTERN PyObject * gTypeCode
Definition: PyStrings.h:36
R__EXTERN PyObject * gCppName
Definition: PyStrings.h:34
PyObject * RemoveGUIEventInputHook()
Definition: Utility.cxx:972
Bool_t InitProxy(PyObject *module, PyTypeObject *pytype, const char *name)
Initialize a proxy class for use by python, and add it to the ROOT module.
Definition: Utility.cxx:541
void ErrMsgHandler(int level, Bool_t abort, const char *location, const char *msg)
Translate ROOT error/warning to python.
Definition: Utility.cxx:832
Bool_t AddBinaryOperator(PyObject *left, PyObject *right, const char *op, const char *label, const char *alt_label=NULL)
Install the named operator (op) into the left object's class if such a function exists as a global ov...
Definition: Utility.cxx:315
PyObject * PyErr_Occurred_WithGIL()
Re-acquire the GIL before calling PyErr_Occurred() in case it has been released; note that the p2....
Definition: Utility.cxx:924
Bool_t AddUsingToClass(PyObject *pyclass, const char *method)
Helper to add base class methods to the derived class one (this covers the 'using' cases,...
Definition: Utility.cxx:261
std::string MapOperatorName(const std::string &name, Bool_t bTakesParames)
Map the given C++ operator name on the python equivalent.
Definition: Utility.cxx:634
PyObject * InstallGUIEventInputHook()
Definition: Utility.cxx:959
const std::string Compound(const std::string &name)
Break down the compound of a fully qualified type name.
Definition: Utility.cxx:680
int GetBuffer(PyObject *pyobject, char tc, int size, void *&buf, Bool_t check=kTRUE)
Retrieve a linear buffer pointer from the given pyobject.
Definition: Utility.cxx:561
PyObject * BuildTemplateName(PyObject *pyname, PyObject *tpArgs, int argoff, PyObject *args=nullptr, ArgPreference=kNone, int *pcnt=nullptr, bool inferredTypes=false)
Helper to construct the "< type, type, ... >" part of a templated name (either for a class as in Make...
Definition: Utility.cxx:462
Bool_t AddToClass(PyObject *pyclass, const char *label, PyCFunction cfunc, int flags=METH_VARARGS)
Add the given function to the class under name 'label'.
Definition: Utility.cxx:186
void ErrMsgCallback(char *msg)
Translate CINT error/warning into python equivalent.
Definition: Utility.cxx:755
Py_ssize_t ArraySize(const std::string &name)
Extract size from an array type, if available.
Definition: Utility.cxx:704
void * CreateWrapperMethod(PyObject *pyfunc, Long_t user, const char *retType, const std::vector< std::string > &signature, const char *callback)
Compile a function on the fly and return a function pointer for use on C-APIs.
Definition: Utility.cxx:869
const std::string ClassName(PyObject *pyobj)
Retrieve the class name from the given python object (which may be just an instance of the class).
Definition: Utility.cxx:724
R__EXTERN dict_lookup_func gDictLookupOrg
Definition: Utility.h:15
Bool_t ObjectProxy_Check(T *object)
Definition: ObjectProxy.h:91
ULong64_t PyLongOrInt_AsULong64(PyObject *pyobject)
Convert <pyobject> to C++ unsigned long long, with bounds checking.
Definition: Utility.cxx:166
MethodProxy * MethodProxy_New(const std::string &name, std::vector< PyCallable * > &methods)
Definition: MethodProxy.h:75
Bool_t MethodProxy_Check(T *object)
Definition: MethodProxy.h:63
R__EXTERN Bool_t gDictLookupActive
Definition: Utility.h:18
ULong_t PyLongOrInt_AsULong(PyObject *pyobject)
Definition: Utility.cxx:145
PyObject * TCustomInstanceMethod_New(PyObject *func, PyObject *self, PyObject *pyclass)
std::string ResolveTypedef(const char *tname, bool resolveAll=false)