ATLAS Offline Software
Loading...
Searching...
No Matches
PyROOTTTreePatch.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
10
11// Called from python, so only excuted single-threaded (GIL).
14
17#include "Utility.h"
18
19#include "Python.h"
20#include "TTree.h"
21#include "TBranch.h"
22#include "TPython.h"
23#include "TNotifyLink.h"
24
25
26//***************************************************************************
27// Most of the PyROOT headers are not exported.
28// So we need to copy pieces of some PyROOT declarations here.
29//
30
31namespace PyROOT {
32
34public:
35 enum EFlags { kIsReference = 0x0008 };
36
37 PyObject_HEAD
38 void* fObject;
39 int fFlags;
40};
41
42} // namespace PyROOT
43
44using namespace PyROOT;
45
46
47//=========================================================================
48
49
50
51namespace RootUtils {
52
53
54// Interned string constants that we use for dictionary lookups.
57
58
68 : public TNotifyLinkBase
69{
70public:
78 TreeNotifier (TTree* tree, PyObject* treeobj_ref);
79
81 virtual ~TreeNotifier();
82
84 virtual Bool_t Notify() override;
85
87 virtual void Clear (Option_t* /*option*/ = "") override;
88
89
90private:
94
96 TObject* m_chain;
97
99 TTree* m_tree;
100};
101
102
111 PyObject* treeobj_ref)
112 : m_treeobj_ref (treeobj_ref),
113 m_chain (tree->GetNotify()),
114 m_tree (tree)
115{
116 // We acquire ownership of treeobj_ref.
117}
118
119
124{
126 if (m_tree) {
127 // Clear the reference from the tree to this object.
128 m_tree->SetNotify (m_chain);
129 }
130 Py_XDECREF (m_treeobj_ref);
131}
132
133
138{
140
141 // Intern __pynotify__ if needed.
142 if (pynotify_str == 0)
143 pynotify_str = PyUnicode_InternFromString("__pynotify__");
144
145 // Look for a notification object.
146#if PY_VERSION_HEX >= 0x030d0000
147 PyObject* treeobj = nullptr;
148 (void)PyWeakref_GetRef (m_treeobj_ref, &treeobj);
149#else
150 PyObject* treeobj = PyWeakref_GetObject (m_treeobj_ref);
151#endif
152 if (treeobj) {
153 PyObject** dictptr = _PyObject_GetDictPtr (treeobj);
154 if (dictptr && *dictptr) {
155 PyObject* notobj = PyObject_GetItem (*dictptr, pynotify_str);
156#if PY_VERSION_HEX >= 0x030d0000
157 Py_DECREF(treeobj);
158#endif
159 if (notobj) {
160 // Got it --- call @c Notify.
161 PyObject* ret =
162 PyObject_CallMethod (notobj, const_cast<char*> ("Notify"), NULL);
163#if PY_VERSION_HEX >= 0x030d0000
164 Py_DECREF (notobj);
165#endif
166 if (!ret) return 0;
167 Py_DECREF (ret);
168 }
169 else
170 PyErr_Clear();
171 }
172 }
173
174 if (m_chain) m_chain->Notify();
175 return true;
176}
177
178
180void TreeNotifier::Clear (Option_t* /*option = ""*/)
181{
182 m_tree = nullptr;
183}
184
185
191{
192 // Decode the objects --- the tree and the notifier object.
193 PyObject* self = 0;
194 PyObject* obj = 0;
195 if ( ! PyArg_ParseTuple( args, const_cast< char* >( "OO:SetNotify" ),
196 &self, &obj ) )
197 return 0;
198
199 // Intern strings if needed.
200 if (pynotify_str == 0) {
201 pynotify_str = PyUnicode_InternFromString("__pynotify__");
202 }
203 if (notifier_str == 0) {
204 notifier_str = PyUnicode_InternFromString("__notifier__");
205 }
206
207 // Set up notifier.
208 if (!PyObject_HasAttr (self, notifier_str)) {
209 // get hold of actual tree
210 void* vp = TPython::CPPInstance_AsVoidPtr (self);
211 TTree* tree =
212 (TTree*)objectIsA(self)->DynamicCast ( TTree::Class(), vp );
213
214 PyObject* treeobj_ref = PyWeakref_NewRef (self, 0);
215 if (!treeobj_ref)
216 return 0;
217 TObject* notifier = new TreeNotifier (tree, treeobj_ref);
218 PyObject* notobj = TPython::CPPInstance_FromVoidPtr (notifier, "TObject");
219 setOwnership (notobj, true);
220 int stat = PyObject_SetAttr (self, notifier_str, notobj);
221 Py_XDECREF (notobj);
222 if (stat < 0)
223 return 0;
224 tree->SetNotify (notifier);
225 }
226
227 // Install the object.
228 int stat = PyObject_SetAttr (self, pynotify_str, obj);
229 if (stat < 0)
230 return 0;
231
232 Py_INCREF (Py_None);
233 return Py_None;
234}
235
236
242{
243 // Decode the objects --- the tree.
244 PyObject* self = 0;
245 if ( ! PyArg_ParseTuple( args, const_cast< char* >( "O:SetNotify" ),
246 &self ) )
247 return 0;
248
249 // Intern string if needed.
250 if (pynotify_str == 0)
251 pynotify_str = PyUnicode_InternFromString("__pynotify__");
252
253 // Retrieve the notifier.
254 PyObject* ret = PyObject_GetAttr (self, pynotify_str);
255 if (!ret) {
256 PyErr_Clear();
257 Py_INCREF (Py_None);
258 ret = Py_None;
259 }
260 return ret;
261}
262
263
269{
270 // Decode arguments --- the branch and the buffer.
271 PyObject* self = 0;
272 PyObject* address = 0;
273 if ( ! PyArg_ParseTuple( args, const_cast< char* >( "OO:SetBranchAddress" ),
274 &self, &address ) )
275 return 0;
276
277 // The branch as a Root object.
278 TBranch* branch = 0;
279 if (TPython::CPPInstance_Check (self)) {
280 branch = (TBranch*)objectIsA(self)->DynamicCast
281 ( TBranch::Class(),
282 TPython::CPPInstance_AsVoidPtr(self) );
283 }
284
285 if ( ! branch ) {
286 PyErr_SetString( PyExc_TypeError,
287 "TBranch::SetAddress must be called with a "
288 "TBranch instance as first argument" );
289 return 0;
290 }
291
292 // Convert the buffer argument to an address.
293 void* buf = 0;
294 if ( TPython::CPPInstance_Check( address ) ) {
295 auto* inst = reinterpret_cast<CPPInstance*>(address);
296 if ( inst->fFlags & CPPInstance::kIsReference )
297 buf = inst->fObject;
298 else
299 buf = &inst->fObject;
300 }
301 else
302 RootUtils::GetBuffer( address, '*', 1, buf, kFALSE );
303
304 // Make the call and return.
305 if ( buf != 0 )
306 branch->SetAddress( buf );
307
308 Py_INCREF( Py_None );
309 return Py_None;
310}
311
312
320void installMethod (PyObject* pyclass,
321 PyMethodDef& pdef,
322 const char* name,
323 PyCFunction cfunc)
324{
325 pdef.ml_name = const_cast<char*> (name);
326 pdef.ml_meth = cfunc;
327 pdef.ml_flags = METH_VARARGS;
328 pdef.ml_doc = 0;
329
330 PyObject* func = PyCFunction_New (&pdef, 0);
331 PyObject* method = PyInstanceMethod_New (func);
332 Bool_t isOK = PyObject_SetAttrString (pyclass, pdef.ml_name, method) == 0;
333
334 if (PyErr_Occurred())
335 fprintf (stderr, "Py error");
336 else if (!isOK) {
337 fprintf (stderr, "Could not add method %s\n", name);
338 }
339}
340
341
349 PyObject* /*chain_pyclass*/,
350 PyObject* branch_pyclass)
351{
352# define INSTALL_METHOD(pyclass, name, func) do { \
353 static PyMethodDef pdef; \
354 installMethod (pyclass, pdef, name, (PyCFunction)func); \
355 } while(0)
356
357 INSTALL_METHOD (tree_pyclass, "SetNotify", treeSetNotify);
358 INSTALL_METHOD (tree_pyclass, "GetNotify", treeGetNotify);
359 INSTALL_METHOD (branch_pyclass, "SetAddress", branchSetAddress);
360#undef INSTALL_METHOD
361}
362
363
364} // namespace RootUtils
_object PyObject
#define INSTALL_METHOD(pyclass, name, func)
Additions to root's pythonized TTree.
Utility code originally from pyroot.
Define macros for attributes used to control the static checker.
#define ATLAS_NO_CHECK_FILE_THREAD_SAFETY
PyObject_HEAD void * fObject
static void Initialize(PyObject *tree_pyclass, PyObject *chain_pyclass, PyObject *branch_pyclass)
Install the PyROOT patches.
Tree notification handler.
virtual ~TreeNotifier()
Destructor.
virtual Bool_t Notify() override
Root notification hook.
TObject * m_chain
Notification tree.
TTree * m_tree
The tree to which we're attached.
virtual void Clear(Option_t *="") override
Called when the tree we're attached to is deleted.
TreeNotifier(TTree *tree, PyObject *treeobj_ref)
Constructor.
PyObject * m_treeobj_ref
A weak reference to the Python object for the tree.
PyObject * treeGetNotify(PyObject *, PyObject *args)
Implementation for pythonization of TTree::SetNotify.
static PyObject * pynotify_str
void installMethod(PyObject *pyclass, PyMethodDef &pdef, const char *name, PyCFunction cfunc)
Helper to install a method in a Python class.
bool setOwnership(PyObject *obj, bool flag)
Definition Utility.cxx:141
PyObject * treeSetNotify(PyObject *, PyObject *args)
Implementation for pythonization of TTree::SetNotify.
static PyObject * notifier_str
int GetBuffer(PyObject *pyobject, char tc, int size, void *&buf, Bool_t check)
Definition Utility.cxx:26
TClass * objectIsA(PyObject *obj)
Definition Utility.cxx:103
PyObject * branchSetAddress(PyObject *, PyObject *args)
Pythonization of TBranch::SetAddress.
TChain * tree