@@ -88,6 +88,9 @@ class PyTextCtrlHook {
88
88
static PyObject* PythonEventClass; // the event object to pass to PostEvent
89
89
static PyObject* PythonWindow; // the window that will handle the event
90
90
static PyMethodDef Methods[];
91
+ #if (PY_MAJOR_VERSION >= 3)
92
+ static PyModuleDef ModuleDef;
93
+ #endif
91
94
static cmnCallbackStreambuf<char > *Streambuf;
92
95
static cmnLogMask Mask;
93
96
@@ -108,7 +111,7 @@ class PyTextCtrlHook {
108
111
static void PrintLog (const char * str, int len);
109
112
110
113
// Initialize the Python module
111
- static void InitModule (const char * name );
114
+ static PyObject * InitModule ();
112
115
113
116
// Cleanup
114
117
static void Cleanup ();
@@ -201,7 +204,6 @@ void PyTextCtrlHook::SetupStreambuf(void)
201
204
// len: the length of the string
202
205
void PyTextCtrlHook::PrintLog (const char * str, int len)
203
206
{
204
- #if (PY_MAJOR_VERSION == 2)
205
207
PyObject* result;
206
208
207
209
// If PythonFunc is set, we know that PythonEventClass is also set
@@ -211,32 +213,38 @@ void PyTextCtrlHook::PrintLog(const char * str, int len)
211
213
// This function is defined in Python 2.3 or greater.
212
214
PyGILState_STATE gstate = PyGILState_Ensure ();
213
215
214
- PyObject* event = PyObject_CallObject (PythonEventClass, NULL );
216
+ // Create an instance of the event class and set the msg attribute
217
+ PyObject *empty = Py_BuildValue (" ()" );
218
+ PyObject *kwargs = Py_BuildValue (" {s:s}" , " msg" , str);
219
+ PyObject* event = PyObject_Call (PythonEventClass, empty, kwargs);
215
220
CMN_ASSERT (event);
221
+ Py_DECREF (empty);
222
+ Py_DECREF (kwargs);
216
223
217
- // Convert the C string to a Python string
218
- PyObject* pystr = Py_BuildValue (" s" , str);
219
- // Store the string as the "msg" attribute in the event object
220
- CMN_ASSERT (PyObject_SetAttrString (event, " msg" , pystr) == 0 );
221
- // Decrement "pystr" reference count (PyObject_SetAttrString incremented it).
222
- Py_DECREF (pystr);
223
224
// Build the args for the Python function
224
225
PyObject* args = Py_BuildValue (" OO" , PythonWindow, event);
225
226
// Decrement "event" reference count (Py_BuildValue incremented it)
226
227
Py_DECREF (event);
227
228
// Call the callback function
229
+ #if (PY_MAJOR_VERSION == 2)
228
230
if (PyCFunction_Check (PythonFunc)) {
229
231
// If it is a (wrapped) C function, call it directly.
230
232
try {
231
233
result = PyCFunction_Call (PythonFunc, args, 0 );
234
+ result = PyObject_CallObject (PythonFunc, args);
232
235
}
233
236
catch (...) {
234
237
std::cout << " PyCFunction_Call exception" << std::endl;
235
238
}
236
239
}
237
- else
240
+ else {
238
241
// Call the Python function (via the interpreter)
239
- result = PyEval_CallObject (PythonFunc, args);
242
+ result = PyObject_CallObject (PythonFunc, args);
243
+ }
244
+ #else
245
+ // Call the Python function (via the interpreter)
246
+ result = PyObject_CallObject (PythonFunc, args);
247
+ #endif
240
248
// Decrement reference count
241
249
Py_DECREF (args);
242
250
@@ -251,7 +259,6 @@ void PyTextCtrlHook::PrintLog(const char * str, int len)
251
259
// Release Python global interpreter lock
252
260
PyGILState_Release (gstate);
253
261
}
254
- #endif
255
262
}
256
263
257
264
// Cleanup: remove logger channel, delete Streambuf object,
@@ -295,11 +302,31 @@ PyMethodDef PyTextCtrlHook::Methods[] = {
295
302
{ NULL , NULL , 0 , NULL }
296
303
};
297
304
298
- void PyTextCtrlHook::InitModule (const char * name)
305
+ #if (PY_MAJOR_VERSION >= 3)
306
+ PyModuleDef PyTextCtrlHook::ModuleDef = {
307
+ PyModuleDef_HEAD_INIT,
308
+ " ireLogger" ,
309
+ " ireLogger documentation" ,
310
+ -1 ,
311
+ PyTextCtrlHook::Methods,
312
+ NULL ,
313
+ NULL ,
314
+ NULL ,
315
+ NULL
316
+ };
317
+ #endif
318
+
319
+ PyObject *PyTextCtrlHook::InitModule ()
299
320
{
321
+ PyObject *pModule;
300
322
#if (PY_MAJOR_VERSION == 2)
301
- Py_InitModule (name, Methods);
323
+ pModule = Py_InitModule (" ireLogger" , Methods);
324
+ #else
325
+ pModule = PyModule_Create (&ModuleDef);
302
326
#endif
327
+ if (pModule == NULL )
328
+ CMN_LOG_INIT_ERROR << " PyTextCtrlHook::InitModule failed" << std::endl;
329
+ return pModule;
303
330
}
304
331
305
332
// ****************************************************************************
@@ -333,8 +360,8 @@ ireFramework* ireFramework::Instance(void) {
333
360
//
334
361
void ireFramework::InitShellInstance (void )
335
362
{
336
- if (IsInitialized () ) {
337
- CMN_LOG_INIT_WARNING << " ireFramework already initialized " << std::endl;
363
+ if (IRE_State != IRE_NOT_CONSTRUCTED ) {
364
+ CMN_LOG_INIT_WARNING << " ireFramework already constructed " << std::endl;
338
365
return ;
339
366
}
340
367
#if (CISST_OS == CISST_LINUX)
@@ -353,22 +380,7 @@ void ireFramework::InitShellInstance(void)
353
380
<< " : " << msg << std::endl;
354
381
}
355
382
#endif
356
- Py_Initialize ();
357
- #if (PY_MAJOR_VERSION < 3) || (PY_MINOR_VERSION < 7)
358
- // PyEval_InitThreads was deprecated in Python 3.7 (it is no longer needed)
359
- PyEval_InitThreads ();
360
- #endif
361
- #if (CISST_OS == CISST_LINUX)
362
- #if (PY_MAJOR_VERSION == 2)
363
- // TODO: check if this is needed for Python3
364
- // For Linux, change dlopenflags to avoid swig::stop_iterator exceptions
365
- PyGILState_STATE gstate = PyGILState_Ensure ();
366
- PyThreadState *threadState = PyThreadState_Get ();
367
- threadState->interp ->dlopenflags |= RTLD_GLOBAL;
368
- PyGILState_Release (gstate);
369
- #endif
370
- #endif
371
- IRE_State = IRE_INITIALIZED;
383
+ IRE_State = IRE_CONSTRUCTED;
372
384
}
373
385
374
386
// ****************************************************************************
@@ -400,27 +412,66 @@ void ireFramework::FinalizeShellInstance(void)
400
412
// of any PyObject s that use hard references.
401
413
//
402
414
void ireFramework::LaunchIREShellInstance (const char * startup, bool newPythonThread, bool useIPython,
403
- bool useStreambuf) {
404
- // start python
405
- const char * python_args[] = { " " , startup };
406
-
407
- if (IRE_State != IRE_INITIALIZED) {
415
+ bool useStreambuf)
416
+ {
417
+ if (IRE_State != IRE_CONSTRUCTED) {
408
418
CMN_LOG_INIT_ERROR << " LaunchIREShellInstance: IRE state is " << IRE_State << " ." << std::endl;
409
419
cmnThrow (std::runtime_error (" LaunchIREShellInstance: invalid IRE state." ));
410
420
}
411
- IRE_State = IRE_LAUNCHED;
421
+
412
422
NewPythonThread = newPythonThread;
413
423
414
424
if (pInstance)
415
425
Py_DECREF (pInstance);
416
426
pInstance = 0 ;
417
427
418
428
#if (PY_MAJOR_VERSION == 2)
419
- // Initialize ireLogger module, which is used for the cmnLogger output window
420
- PyTextCtrlHook::InitModule (" ireLogger" );
429
+ Py_Initialize ();
430
+ // Set python_args as argv.
431
+ // Note that currently, startup script run separately for IPython.
432
+ const char * python_args[] = { " " , startup };
421
433
PySys_SetArgv (2 , const_cast <char **>(python_args));
434
+ // Initialize ireLogger module, which is used for the cmnLogger output window
435
+ PyTextCtrlHook::InitModule ();
436
+ #else
437
+ // Following setting of python_args appears to be necessary when using Python 3
438
+ // with wxPython. Note that currently, startup script run separately for IPython.
439
+ const char * python_args[] = { " " , " IRE" , startup };
440
+ PyConfig config;
441
+ PyConfig_InitPythonConfig (&config);
442
+ PyConfig_SetBytesArgv (&config, 3 , const_cast <char **>(python_args));
443
+ // Initialize ireLogger module, which is used for the cmnLogger output window
444
+ if (PyImport_AppendInittab (" ireLogger" , PyTextCtrlHook::InitModule) == -1 )
445
+ CMN_LOG_INIT_WARNING << " LaunchIREShellInstance: failed to import ireLogger" << std::endl;
446
+ PyStatus status;
447
+ status = Py_InitializeFromConfig (&config);
448
+ PyConfig_Clear (&config);
449
+ if (PyStatus_IsError (status)) {
450
+ CMN_LOG_INIT_ERROR << " LaunchIREShellInstance: init error: " << status.err_msg << std::endl;
451
+ cmnThrow (std::runtime_error (" LaunchIREShellInstance: init error" ));
452
+ }
453
+ else if (PyStatus_IsExit (status)) {
454
+ CMN_LOG_INIT_ERROR << " LaunchIREShellInstance: init exit: " << status.err_msg << std::endl;
455
+ cmnThrow (std::runtime_error (" LaunchIREShellInstance: init exit" ));
456
+ }
457
+ #endif
458
+ #if (PY_MAJOR_VERSION < 3) || (PY_MINOR_VERSION < 7)
459
+ // PyEval_InitThreads was deprecated in Python 3.7 (it is no longer needed)
460
+ PyEval_InitThreads ();
461
+ #endif
462
+ #if (CISST_OS == CISST_LINUX)
463
+ #if (PY_MAJOR_VERSION == 2)
464
+ // TODO: check if this is needed for Python3
465
+ // For Linux, change dlopenflags to avoid swig::stop_iterator exceptions
466
+ PyGILState_STATE gstate = PyGILState_Ensure ();
467
+ PyThreadState *threadState = PyThreadState_Get ();
468
+ threadState->interp ->dlopenflags |= RTLD_GLOBAL;
469
+ PyGILState_Release (gstate);
470
+ #endif
422
471
#endif
423
472
473
+ IRE_State = IRE_LAUNCHED;
474
+
424
475
// Get global dictionary (pModule and pDict are borrowed references)
425
476
PyObject *pModule = PyImport_AddModule (" __main__" );
426
477
PyObject *pDict = PyModule_GetDict (pModule);
@@ -432,6 +483,7 @@ void ireFramework::LaunchIREShellInstance(const char * startup, bool newPythonTh
432
483
433
484
char launchString[128 ];
434
485
if (useIPython) {
486
+ // Could instead add "argv=[%s]" to launchString, where %s is startup string
435
487
PyRun_SimpleString (startup);
436
488
// Following code is for very old versions of IPython (possibly prior to 1.0)
437
489
// PyRun_SimpleString("from IPython.Shell import IPShellEmbed\n");
@@ -526,12 +578,8 @@ bool ireFramework::IsInitialized()
526
578
527
579
void ireFramework::Reset ()
528
580
{
529
- if (IRE_State == IRE_FINISHED) {
530
- if (!IsInitialized ())
531
- InitShell ();
532
- else
533
- IRE_State = IRE_INITIALIZED;
534
- }
581
+ if (IRE_State == IRE_FINISHED)
582
+ IRE_State = IRE_CONSTRUCTED;
535
583
}
536
584
537
585
void ireFramework::UnblockThreads ()
0 commit comments