Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RPyROOTApplication.cxx
Go to the documentation of this file.
1// Author: Enric Tejedor CERN 04/2019
2// Original PyROOT code by Wim Lavrijsen, LBL
3
4/*************************************************************************
5 * Copyright (C) 1995-2019, 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// Bindings
13#include <Python.h>
14#include "RPyROOTApplication.h"
15
16// ROOT
17#include "TInterpreter.h"
18#include "TSystem.h"
19#include "TBenchmark.h"
20#include "TStyle.h"
21#include "TError.h"
22#include "Getline.h"
23#include "TVirtualMutex.h"
24#include "TVirtualPad.h"
25#include "TROOT.h"
26
27////////////////////////////////////////////////////////////////////////////
28/// \brief Create an RPyROOTApplication.
29/// \param[in] ignoreCmdLineOpts True if Python command line options should
30/// be ignored.
31/// \return false if gApplication is not null, true otherwise.
32///
33/// If ignoreCmdLineOpts is false, this method processes the command line
34/// arguments from sys.argv. A distinction between arguments for
35/// TApplication and user arguments can be made by using "-" or "--" as a
36/// separator on the command line.
37///
38/// For example, to enable batch mode from the command line:
39/// > python script_name.py -b -- user_arg1 ... user_argn
40/// or, if the user script receives no arguments:
41/// > python script_name.py -b
43{
44 if (!gApplication) {
45 int argc = 1;
46 char **argv = nullptr;
47
49 // Last argv must be null (see https://en.cppreference.com/cpp/language/main_function)
50 argv = new char *[argc + 1] {};
51 } else {
52 // Retrieve sys.argv list from Python
53 PyObject *argl = PySys_GetObject("argv");
54
55 if (argl) {
57 if (size > 0)
58 argc = static_cast<int>(size);
59 }
60
61 // Last argv must be null (see https://en.cppreference.com/cpp/language/main_function)
62 argv = new char *[argc + 1] {};
63
64 for (int i = 1; i < argc; ++i) {
66 const char *argi = PyUnicode_AsUTF8AndSize(item, nullptr);
67
68 if (strcmp(argi, "-") == 0 || strcmp(argi, "--") == 0) {
69 // Stop collecting options, the remaining are for the Python script
70 argc = i; // includes program name
71 break;
72 }
73 argv[i] = const_cast<char *>(argi);
74 }
75 }
76
77 argv[0] = (char *)"python";
78
79 gApplication = new RPyROOTApplication("PyROOT", &argc, argv);
80 delete[] argv; // TApplication ctor has copied argv, so done with it
81
82 return true;
83 }
84
85 return false;
86}
87
88////////////////////////////////////////////////////////////////////////////
89/// \brief Setup the basic ROOT globals gBenchmark, gStyle and gProgname,
90/// if not already set.
92{
93 if (!gBenchmark)
94 gBenchmark = new TBenchmark();
95 if (!gStyle)
96 gStyle = new TStyle();
97
98 if (!gProgName) // should have been set by TApplication
99 gSystem->SetProgname("python");
100}
101
102////////////////////////////////////////////////////////////////////////////
103/// \brief Translate ROOT error/warning to Python.
104static void ErrMsgHandler(int level, Bool_t abort, const char *location, const char *msg)
105{
106 // Initialization from gEnv (the default handler will return w/o msg b/c level too low)
108 ::DefaultErrorHandler(kUnset - 1, kFALSE, "", "");
109
110 if (level < gErrorIgnoreLevel)
111 return;
112
113 // Turn warnings into Python warnings
114 if (level >= kError) {
115 ::DefaultErrorHandler(level, abort, location, msg);
116 } else if (level >= kWarning) {
117 static const char *emptyString = "";
118 if (!location)
119 location = emptyString;
120 // This warning might be triggered while holding the ROOT lock, while
121 // some other thread is holding the GIL and waiting for the ROOT lock.
122 // That will trigger a deadlock.
123 // So if ROOT is in MT mode, use ROOT's error handler that doesn't take
124 // the GIL.
125 if (!gGlobalMutex) {
126 // Either printout or raise exception, depending on user settings
127 auto state = PyGILState_Ensure();
128 PyErr_WarnExplicit(NULL, (char *)msg, (char *)location, 0, (char *)"ROOT", NULL);
129 PyGILState_Release(state);
130 } else {
131 ::DefaultErrorHandler(level, abort, location, msg);
132 }
133 } else {
134 ::DefaultErrorHandler(level, abort, location, msg);
135 }
136}
137
138////////////////////////////////////////////////////////////////////////////
139/// \brief Install the ROOT message handler which will turn ROOT error
140/// messages into Python exceptions.
145
146////////////////////////////////////////////////////////////////////////////
147/// \brief Initialize an RPyROOTApplication.
148/// \param[in] self Always null, since this is a module function.
149/// \param[in] args [0] Boolean that tells whether to ignore the command line options.
151{
152 int argc = PyTuple_Size(args);
153 if (argc == 1) {
155
157 PyErr_SetString(PyExc_TypeError, "Expected boolean type as argument.");
158 return nullptr;
159 }
160
161 if (CreateApplication(PyObject_IsTrue(ignoreCmdLineOpts))) {
162 InitROOTGlobals();
163 InitROOTMessageCallback();
164 }
165 } else {
166 PyErr_Format(PyExc_TypeError, "Expected 1 argument, %d passed.", argc);
167 return nullptr;
168 }
169
171}
172
173////////////////////////////////////////////////////////////////////////////
174/// \brief Construct a TApplication for PyROOT.
175/// \param[in] name Application class name.
176/// \param[in] argc Number of arguments.
177/// \param[in] argv Arguments.
180{
181 // Save current interpreter context
182 gInterpreter->SaveContext();
183 gInterpreter->SaveGlobalsContext();
184
185 // Prevent crashes on accessing history
186 Gl_histinit((char *)"-");
187
188 // Prevent ROOT from exiting python
189 SetReturnFromRun(true);
190}
191
192namespace {
193static int (*sOldInputHook)() = nullptr;
195
196static int EventInputHook()
197{
198 // This method is supposed to be called from CPython's command line and
199 // drives the GUI
201 if (gPad && gPad->IsWeb())
202 gPad->UpdateAsync();
205
206 if (sOldInputHook)
207 return sOldInputHook();
208
209 return 0;
210}
211
212} // unnamed namespace
213
214////////////////////////////////////////////////////////////////////////////
215/// \brief Install a method hook for sending events to the GUI.
216/// \param[in] self Always null, since this is a module function.
217/// \param[in] args Pointer to an empty Python tuple.
#define Py_RETURN_NONE
Definition CPyCppyy.h:268
_object PyObject
static void ErrMsgHandler(int level, Bool_t abort, const char *location, const char *msg)
Translate ROOT error/warning to Python.
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
bool Bool_t
Boolean (0=false, 1=true) (bool)
Definition RtypesCore.h:78
constexpr Bool_t kFALSE
Definition RtypesCore.h:109
R__EXTERN TApplication * gApplication
R__EXTERN TBenchmark * gBenchmark
Definition TBenchmark.h:59
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
void DefaultErrorHandler(Int_t level, Bool_t abort_bool, const char *location, const char *msg)
The default error handler function.
constexpr Int_t kError
Definition TError.h:47
constexpr Int_t kWarning
Definition TError.h:46
void(* ErrorHandlerFunc_t)(int level, Bool_t abort, const char *location, const char *msg)
Definition TError.h:71
Int_t gErrorIgnoreLevel
errors with level below this value will be ignored. Default is kUnset.
Definition TError.cxx:33
ErrorHandlerFunc_t SetErrorHandler(ErrorHandlerFunc_t newhandler)
Set an errorhandler function. Returns the old handler.
Definition TError.cxx:92
constexpr Int_t kUnset
Definition TError.h:43
char name[80]
Definition TGX11.cxx:148
#define gInterpreter
R__EXTERN TStyle * gStyle
Definition TStyle.h:442
R__EXTERN const char * gProgName
Definition TSystem.h:252
R__EXTERN TSystem * gSystem
Definition TSystem.h:582
R__EXTERN TVirtualMutex * gGlobalMutex
#define gPad
static PyObject * InstallGUIEventInputHook(PyObject *self, PyObject *args)
Install a method hook for sending events to the GUI.
static void InitROOTMessageCallback()
Install the ROOT message handler which will turn ROOT error messages into Python exceptions.
RPyROOTApplication(const char *name, int *argc, char **argv)
Construct a TApplication for PyROOT.
static PyObject * InitApplication(PyObject *self, PyObject *args)
Initialize an RPyROOTApplication.
static void InitROOTGlobals()
Setup the basic ROOT globals gBenchmark, gStyle and gProgname, if not already set.
This class creates the ROOT Application Environment that interfaces to the windowing system eventloop...
void SetReturnFromRun(Bool_t ret)
static void CreateApplication()
Static function used to create a default application environment.
This class is a ROOT utility to help benchmarking applications.
Definition TBenchmark.h:29
TStyle objects may be created to define special styles.
Definition TStyle.h:29
virtual void SetProgname(const char *name)
Set the application name (from command line, argv[0]) and copy it in gProgName.
Definition TSystem.cxx:225
virtual Bool_t ProcessEvents()
Process pending events (GUI, timers, sockets).
Definition TSystem.cxx:418