Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
GenericPyz.cxx
Go to the documentation of this file.
1// Author: Stefan Wunsch, Enric Tejedor CERN 06/2018
2// Original PyROOT code by Wim Lavrijsen, LBL
3
4/*************************************************************************
5 * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12#include "Python.h"
13
14#include "CPyCppyy/API.h"
15
18
19#include "PyROOTPythonize.h"
20
21#include "TClass.h"
22#include "TInterpreter.h"
23#include "TInterpreterValue.h"
24
25#include <map>
26
27using namespace CPyCppyy;
28
29// We take as unique identifier the declId of the class to
30// treat the case where a class is loaded, an instance printed,
31// the class unloaded and reloaded with changes.
32static ULong64_t GetClassID(const char *clName)
33{
34 if (auto cl = TClass::GetClass(clName)) {
35 if (auto clInfo = cl->GetClassInfo()) {
36 return reinterpret_cast<ULong64_t>(gInterpreter->GetDeclId(clInfo));
37 }
38 }
39 return 0;
40}
41
43{
44 // Map holding the classID of the classes and the pointer
45 // to the printer function.
46 static std::map<ULong64_t, void *> declIDPrinterMap;
47
49 if (!cppObj)
50 // Proxied cpp object is null, use cppyy's generic __repr__
51 return PyObject_Repr(self);
52
53 // We jit the helper only once, at the first invocation of any
54 // printer. The integer parameter is there to make sure we have
55 // different instances of the printing function in presence of
56 // unload-reload events.
57 if (0 == declIDPrinterMap.size()) {
58 std::string printerCode = "namespace ROOT::Internal::Pythonizations::ValuePrinters"
59 "{"
60 " template<class T, ULong64_t> std::string ValuePrinter(void *obj)"
61 " {"
62 " return cling::printValue((T *)obj);"
63 " }"
64 "}";
65 gInterpreter->Declare(printerCode.c_str());
66 }
67
68 const std::string className = CPyCppyy::Instance_GetScopedFinalName(self);
69
70 std::string printResult;
71
72 if (const auto classID = GetClassID(className.c_str())) {
73 // If we never encountered this class, we jit the function which
74 // is necessary to print it and store it in the map instantiated
75 // above. Otherwise, we just use the pointer to the previously
76 // jitted function. This allows to jit the printer only once per
77 // type, at the modest price of a typename and pointer stored in
78 // memory.
80
81 if (!printerFuncrPtr) {
82 std::string printFuncName = "ROOT::Internal::Pythonizations::ValuePrinters::ValuePrinter<" + className + ", " +
83 std::to_string(classID) + ">";
84 printerFuncrPtr = (void *)gInterpreter->Calc(printFuncName.c_str());
85 }
86 printResult = ((std::string(*)(void *))printerFuncrPtr)(cppObj);
87 } else {
88 // If something went wrong, we use the slow method
89 printResult = gInterpreter->ToString(className.c_str(), cppObj);
90 }
91
92 if (printResult.find("@0x") == 0) {
93 // Fall back to __repr__ if we just get an address from cling
94 return PyObject_Repr(self);
95 } else {
96 return PyUnicode_FromString(printResult.c_str());
97 }
98}
99
100////////////////////////////////////////////////////////////////////////////
101/// \brief Add pretty printing pythonization
102/// \param[in] self Always null, since this is a module function.
103/// \param[in] args Pointer to a Python tuple object containing the arguments
104/// received from Python.
105///
106/// This function adds the following pythonizations to print the object more
107/// user-friendly than cppyy by using the output of cling::printValue as the
108/// return value of the special method __str__.
#define Py_RETURN_NONE
Definition CPyCppyy.h:268
static ULong64_t GetClassID(const char *clName)
PyObject * ClingPrintValue(PyObject *self, PyObject *)
_object PyObject
unsigned long long ULong64_t
Portable unsigned long integer 8 bytes.
Definition RtypesCore.h:84
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define gInterpreter
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:2979
bool AddToClass(PyObject *pyclass, const char *label, PyCFunction cfunc, int flags=METH_VARARGS)
Definition Utility.cxx:186
CPYCPPYY_EXTERN std::string Instance_GetScopedFinalName(PyObject *pyobject)
Definition API.cxx:106
CPYCPPYY_EXTERN void * Instance_AsVoidPtr(PyObject *pyobject)
Definition API.cxx:118
PyObject * AddPrettyPrintingPyz(PyObject *self, PyObject *args)
Add pretty printing pythonization.