/*========================================================================= Program: Visualization Toolkit Module: vtkPythonInteractiveInterpreter.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkPython.h" #include "vtkPythonInteractiveInterpreter.h" #include "vtkCommand.h" #include "vtkObjectFactory.h" #include "vtkPythonInterpreter.h" #include "vtkSmartPointer.h" #include class vtkPythonInteractiveInterpreter::vtkInternals { PyObject* InteractiveConsole; PyObject* InteractiveConsoleLocals; std::string PS1; std::string PS2; public: vtkSmartPointer Interpreter; vtkInternals() : InteractiveConsole(nullptr) , InteractiveConsoleLocals(nullptr) { } ~vtkInternals() { this->CleanupPythonObjects(); } PyObject* GetInteractiveConsolePyObject() { return this->InteractiveConsole; } PyObject* GetInteractiveConsoleLocalsPyObject() { return this->InteractiveConsoleLocals; } void CleanupPythonObjects() { if (this->InteractiveConsole) { vtkPythonScopeGilEnsurer gilEnsurer; Py_XDECREF(this->InteractiveConsoleLocals); Py_XDECREF(this->InteractiveConsole); this->InteractiveConsole = nullptr; this->InteractiveConsoleLocals = nullptr; if (vtkPythonInterpreter::IsInitialized()) { const char* code = "import gc; gc.collect()\n"; vtkPythonInterpreter::RunSimpleString(code); } } } PyObject* GetInteractiveConsole() { if (this->InteractiveConsole) { return this->InteractiveConsole; } vtkPythonInterpreter::Initialize(); vtkPythonScopeGilEnsurer gilEnsurer; // set up the code.InteractiveConsole instance that we'll use. const char* code = "import code\n" "__vtkConsoleLocals={'__name__':'__vtkconsole__','__doc__':None}\n" "__vtkConsole=code.InteractiveConsole(__vtkConsoleLocals)\n"; // The const_cast can be removed for Python 3.3 or later. PyRun_SimpleString(const_cast(code)); // Now get the reference to __vtkConsole and save the pointer. PyObject* main_module = PyImport_AddModule("__main__"); PyObject* global_dict = PyModule_GetDict(main_module); this->InteractiveConsole = PyDict_GetItemString(global_dict, "__vtkConsole"); this->InteractiveConsoleLocals = PyDict_GetItemString(global_dict, "__vtkConsoleLocals"); if (!this->InteractiveConsole || !this->InteractiveConsoleLocals) { vtkGenericWarningMacro( "Failed to locate the InteractiveConsole/InteractiveConsoleLocals object."); return nullptr; } Py_INCREF(this->InteractiveConsole); Py_INCREF(this->InteractiveConsoleLocals); // The const_cast can be removed for Python 3.3 or later. PyRun_SimpleString(const_cast("del __vtkConsole; del __vtkConsoleLocals")); // Maybe we need an API to enable developers to set the prompts. // (The const_cast can be removed for Python 3.3 or later). PyObject* ps1 = PySys_GetObject(const_cast("ps1")); if (!ps1) { #if PY_VERSION_HEX >= 0x03000000 ps1 = PyUnicode_FromString(">>> "); #else ps1 = PyString_FromString(">>> "); #endif // The const_cast can be removed for Python 3.3 or later. PySys_SetObject(const_cast("ps1"), ps1); Py_XDECREF(ps1); } // The const_cast can be removed for Python 3.3 or later. PyObject* ps2 = PySys_GetObject(const_cast("ps2")); if (!ps2) { #if PY_VERSION_HEX >= 0x03000000 ps2 = PyUnicode_FromString("... "); #else ps2 = PyString_FromString("... "); #endif // The const_cast can be removed for Python 3.3 or later. PySys_SetObject(const_cast("ps2"), ps2); Py_XDECREF(ps2); } return this->InteractiveConsole; } }; vtkStandardNewMacro(vtkPythonInteractiveInterpreter); //------------------------------------------------------------------------------ vtkPythonInteractiveInterpreter::vtkPythonInteractiveInterpreter() : Internals(new vtkPythonInteractiveInterpreter::vtkInternals()) { this->Internals->Interpreter = vtkSmartPointer::New(); this->Internals->Interpreter->AddObserver( vtkCommand::AnyEvent, this, &vtkPythonInteractiveInterpreter::HandleEvents); } //------------------------------------------------------------------------------ vtkPythonInteractiveInterpreter::~vtkPythonInteractiveInterpreter() { delete this->Internals; this->Internals = nullptr; } //------------------------------------------------------------------------------ void vtkPythonInteractiveInterpreter::HandleEvents( vtkObject* vtkNotUsed(caller), unsigned long eventid, void* calldata) { if (eventid == vtkCommand::ExitEvent) { this->Internals->CleanupPythonObjects(); } this->InvokeEvent(eventid, calldata); } //------------------------------------------------------------------------------ bool vtkPythonInteractiveInterpreter::Push(const char* const code) { PyObject* console = this->Internals->GetInteractiveConsole(); if (!console) { return false; } // The embedded python interpreter cannot handle DOS line-endings, see // http://sourceforge.net/tracker/?group_id=5470&atid=105470&func=detail&aid=1167922 std::string buffer = code ? code : ""; // replace "\r\n" with "\n" std::string::size_type i = buffer.find("\r\n"); for (; i != std::string::npos; i = buffer.find("\r\n", i)) { buffer.replace(i, 2, "\n"); i++; } // replace "\r" with "\n" (sometimes seen on Mac) i = buffer.find('\r'); for (; i != std::string::npos; i = buffer.find('\r', i)) { buffer.replace(i, 1, "\n"); i++; } vtkPythonScopeGilEnsurer gilEnsurer; bool ret_value = false; // The const_cast can be removed for Python 3.4 or later. PyObject* res = PyObject_CallMethod(console, const_cast("push"), const_cast("z"), buffer.c_str()); if (res) { int status = 0; if (PyArg_Parse(res, "i", &status)) { ret_value = (status > 0); } Py_DECREF(res); } return ret_value; } //------------------------------------------------------------------------------ int vtkPythonInteractiveInterpreter::RunStringWithConsoleLocals(const char* script) { // The implementation of this method is modeled after // PyRun_SimpleStringFlags() found in Python's pythonrun.c this->Internals->GetInteractiveConsole(); // ensure the console is initialized vtkPythonScopeGilEnsurer gilEnsurer; PyObject* context = this->Internals->GetInteractiveConsoleLocalsPyObject(); // The const_cast can be removed for Python 3.3 or later. PyObject* result = PyRun_String(const_cast(script), Py_file_input, context, context); if (result == nullptr) { PyErr_Print(); return -1; } Py_DECREF(result); #if PY_VERSION_HEX >= 0x03000000 // The const_cast can be removed for Python 3.3 or later. PyObject* f = PySys_GetObject(const_cast("stdout")); if (f == nullptr || PyFile_WriteString("\n", f) != 0) { PyErr_Clear(); } #else if (Py_FlushLine()) { PyErr_Clear(); } #endif return 0; } //------------------------------------------------------------------------------ void vtkPythonInteractiveInterpreter::Reset() { this->Internals->CleanupPythonObjects(); } //------------------------------------------------------------------------------ void* vtkPythonInteractiveInterpreter::GetInteractiveConsolePyObject() { return this->Internals->GetInteractiveConsolePyObject(); } //------------------------------------------------------------------------------ void* vtkPythonInteractiveInterpreter::GetInteractiveConsoleLocalsPyObject() { return this->Internals->GetInteractiveConsoleLocalsPyObject(); } //------------------------------------------------------------------------------ void vtkPythonInteractiveInterpreter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); }