// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include "vtkPythonInterpreter.h" #include "vtkPython.h" // this must be the first include. #include "vtkBuild.h" #include "vtkCommand.h" #include "vtkLogger.h" #include "vtkNew.h" #include "vtkObjectFactory.h" #include "vtkOutputWindow.h" #include "vtkPythonStdStreamCaptureHelper.h" #include "vtkResourceFileLocator.h" #include "vtkStringFormatter.h" #include "vtkVersion.h" #include "vtkWeakPointer.h" #include "vtksys/Encoding.h" #include #include #include #include #include #include #include #include #include #include #include #if defined(_WIN32) && !defined(__CYGWIN__) #define VTK_PATH_SEPARATOR "\\" #else #define VTK_PATH_SEPARATOR "/" #endif #define VTKPY_DEBUG_MESSAGE(x) \ vtkVLog(vtkLogger::ConvertToVerbosity(vtkPythonInterpreter::GetLogVerbosity()), x) #define VTKPY_DEBUG_MESSAGE_VV(x) \ vtkVLog(vtkLogger::ConvertToVerbosity(vtkPythonInterpreter::GetLogVerbosity() + 1), x) #if defined(_WIN32) && !defined(__CYGWIN__) && defined(VTK_BUILD_SHARED_LIBS) && \ PY_VERSION_HEX >= 0x03080000 #define vtkPythonInterpreter_USE_DIRECTORY_COOKIE #endif namespace { template class PoolT { std::vector Strings; public: ~PoolT() { for (T* astring : this->Strings) { PyMem_RawFree(astring); } } T* push_back(T* val) { this->Strings.push_back(val); return val; } T* pop_last() { if (this->Strings.empty()) { return nullptr; } T* last = *this->Strings.rbegin(); this->Strings.pop_back(); return last; } }; using StringPool = PoolT; using WCharStringPool = PoolT; wchar_t* vtk_Py_UTF8ToWide(const char* arg) { wchar_t* result = nullptr; if (arg != nullptr) { size_t length = vtksysEncoding_mbstowcs(nullptr, arg, 0); if (length > 0) { result = (wchar_t*)PyMem_RawMalloc(sizeof(wchar_t) * (length + 1)); vtksysEncoding_mbstowcs(result, arg, length + 1); } } return result; } #if PY_VERSION_HEX < 0x03080000 std::string vtk_Py_WideToUTF8(const wchar_t* arg) { std::string result; size_t length = vtksysEncoding_wcstombs(nullptr, arg, 0); if (length > 0) { std::vector chars(length + 1); vtksysEncoding_wcstombs(chars.data(), arg, length + 1); result.assign(chars.data(), length); } return result; } #endif std::vector>* GlobalInterpreters; std::vector PythonPaths; void NotifyInterpreters(unsigned long eventid, void* calldata = nullptr) { std::vector>::iterator iter; for (iter = GlobalInterpreters->begin(); iter != GlobalInterpreters->end(); ++iter) { if (iter->GetPointer()) { iter->GetPointer()->InvokeEvent(eventid, calldata); } } } inline void vtkPrependPythonPath(const char* pathtoadd) { VTKPY_DEBUG_MESSAGE("adding module search path " << pathtoadd); vtkPythonScopeGilEnsurer gilEnsurer; PyObject* path = PySys_GetObject("path"); PyObject* newpath = PyUnicode_FromString(pathtoadd); // avoid adding duplicate paths. if (PySequence_Contains(path, newpath) == 0) { PyList_Insert(path, 0, newpath); } Py_DECREF(newpath); } } VTK_ABI_NAMESPACE_BEGIN // Schwarz counter idiom for GlobalInterpreters object static unsigned int vtkPythonInterpretersCounter; vtkPythonGlobalInterpreters::vtkPythonGlobalInterpreters() { if (vtkPythonInterpretersCounter++ == 0) { GlobalInterpreters = new std::vector>(); } } vtkPythonGlobalInterpreters::~vtkPythonGlobalInterpreters() { if (--vtkPythonInterpretersCounter == 0) { delete GlobalInterpreters; GlobalInterpreters = nullptr; } } bool vtkPythonInterpreter::InitializedOnce = false; bool vtkPythonInterpreter::CaptureStdin = false; bool vtkPythonInterpreter::RedirectOutput = true; bool vtkPythonInterpreter::ConsoleBuffering = false; std::string vtkPythonInterpreter::StdErrBuffer; std::string vtkPythonInterpreter::StdOutBuffer; int vtkPythonInterpreter::LogVerbosity = vtkLogger::VERBOSITY_TRACE; std::vector> vtkPythonInterpreter::UserPythonPaths; std::vector vtkPythonInterpreter::AtExitCallbacks; #if PY_VERSION_HEX >= 0x03000000 struct CharDeleter { void operator()(wchar_t* str) { PyMem_RawFree(str); } }; #endif vtkStandardNewMacro(vtkPythonInterpreter); //------------------------------------------------------------------------------ vtkPythonInterpreter::vtkPythonInterpreter() { GlobalInterpreters->emplace_back(this); } //------------------------------------------------------------------------------ vtkPythonInterpreter::~vtkPythonInterpreter() { // We need to check that GlobalInterpreters has not been deleted yet. It can be // deleted prior to a call to this destructor if another static object with a // reference to a vtkPythonInterpreter object deletes that object after // GlobalInterpreters has been destructed. It all depends on the destruction order // of the other static object and GlobalInterpreters. if (!GlobalInterpreters) { return; } std::vector>::iterator iter; for (iter = GlobalInterpreters->begin(); iter != GlobalInterpreters->end(); ++iter) { if (*iter == this) { GlobalInterpreters->erase(iter); break; } } } //------------------------------------------------------------------------------ bool vtkPythonInterpreter::IsInitialized() { return (Py_IsInitialized() != 0); } //------------------------------------------------------------------------------ void vtkPythonInterpreter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); } //------------------------------------------------------------------------------ bool vtkPythonInterpreter::Initialize(int initsigs /*=0*/) { return vtkPythonInterpreter::InitializeWithArgs(initsigs, 0, nullptr); } #if PY_VERSION_HEX >= 0x03080000 static WCharStringPool PythonProgramName; #endif //------------------------------------------------------------------------------ // Ensure that Python is pre-initialized enough for VTK to do its // initialization. Must be called before any `PyMem_*` calls are made. static bool vtkPythonPreConfig() { // Guard against doing this multiple times. static bool done = false; if (done) { return false; } done = true; #if PY_VERSION_HEX >= 0x03080000 PyStatus status; PyPreConfig preconfig; PyPreConfig_InitPythonConfig(&preconfig); preconfig.allocator = PYMEM_ALLOCATOR_NOT_SET; preconfig.utf8_mode = 1; status = Py_PreInitialize(&preconfig); if (PyStatus_Exception(status)) { Py_ExitStatusException(status); } return preconfig.isolated; #else return Py_FrozenFlag; #endif } //------------------------------------------------------------------------------ namespace { /** * Since vtkPythonInterpreter is often used outside CPython executable, e.g. * vtkpython, the default logic to locate Python standard libraries used by * Python (which depends on the executable path) may fail or pickup incorrect * Python libs. This methods address the issue by setting program name to help * guide Python's default prefix/exec_prefix searching logic. */ void SetupPythonPrefix(bool isolated) { using systools = vtksys::SystemTools; // Check if we're using an isolated Python. if (isolated) { VTKPY_DEBUG_MESSAGE("Isolated Python detected; skipping setting up of program path."); return; } std::string pythonlib = vtkGetLibraryPathForSymbol(Py_InitializeEx); if (pythonlib.empty()) { VTKPY_DEBUG_MESSAGE("static Python build or `Py_InitializeEx` library couldn't be found. " "Set `PYTHONHOME` if Python standard library fails to load."); return; } const std::string newprogramname = systools::GetFilenamePath(pythonlib) + VTK_PATH_SEPARATOR "vtkpython"; VTKPY_DEBUG_MESSAGE("calling vtkPythonInterpreter::SetProgramName(" << newprogramname << ") to aid in setup of Python prefix."); vtkPythonInterpreter::SetProgramName(newprogramname.c_str()); } #ifdef vtkPythonInterpreter_USE_DIRECTORY_COOKIE PyObject* DLLDirectoryCookie = nullptr; void CloseDLLDirectoryCookie() { if (DLLDirectoryCookie) { if (PyObject_HasAttrString(DLLDirectoryCookie, "close")) { PyObject* result = PyObject_CallMethod(DLLDirectoryCookie, "close", nullptr); Py_XDECREF(result); } Py_XDECREF(DLLDirectoryCookie); DLLDirectoryCookie = nullptr; } } #endif //------------------------------------------------------------------------------ /** * Add paths to VTK's Python modules. */ void SetupPythonPaths(bool isolated, std::string vtklib, const char* landmark) { // Check if we're using an isolated Python. if (isolated) { VTKPY_DEBUG_MESSAGE("Isolated Python detected; skipping setting up of `vtk` package."); return; } using systools = vtksys::SystemTools; if (vtklib.empty()) { VTKPY_DEBUG_MESSAGE( "`GetVTKVersion` library couldn't be found. Will use `sys.executable` next."); } if (vtklib.empty()) { #if PY_VERSION_HEX >= 0x03080000 vtkPythonScopeGilEnsurer gilEnsurer; PyObject* executable_path = PySys_GetObject("executable"); if (executable_path != Py_None) { vtklib = PyUnicode_AsUTF8AndSize(executable_path, nullptr); } #else vtklib = vtk_Py_WideToUTF8(Py_GetProgramName()); #endif } vtklib = systools::CollapseFullPath(vtklib); const std::string vtkdir = systools::GetFilenamePath(vtklib); #if defined(_WIN32) && !defined(__CYGWIN__) && defined(VTK_BUILD_SHARED_LIBS) // On Windows, based on how the executable is run, we end up failing to load // pyd files due to inability to load dependent dlls. This seems to overcome // the issue. if (!vtkdir.empty()) { #if PY_VERSION_HEX >= 0x03080000 vtkPythonScopeGilEnsurer gilEnsurer; CloseDLLDirectoryCookie(); PyObject* os = PyImport_ImportModule("os"); if (os) { PyObject* add_dll_directory = PyObject_GetAttrString(os, "add_dll_directory"); if (add_dll_directory && PyCallable_Check(add_dll_directory)) { PyObject* newpath = PyUnicode_FromString(vtkdir.c_str()); DLLDirectoryCookie = PyObject_CallFunctionObjArgs(add_dll_directory, newpath, nullptr); Py_XDECREF(newpath); } Py_XDECREF(add_dll_directory); } Py_XDECREF(os); #else std::string env_path; if (systools::GetEnv("PATH", env_path)) { env_path = vtkdir + ";" + env_path; } else { env_path = vtkdir; } systools::PutEnv(std::string("PATH=") + env_path); #endif } #endif #if defined(VTK_BUILD_SHARED_LIBS) vtkPythonInterpreter::PrependPythonPath(vtkdir.c_str(), landmark); #else // since there may be other packages not zipped (e.g. mpi4py), we added path to _vtk.zip // to the search path as well. vtkPythonInterpreter::PrependPythonPath(vtkdir.c_str(), "_vtk.zip", /*add_landmark*/ false); vtkPythonInterpreter::PrependPythonPath(vtkdir.c_str(), "_vtk.zip", /*add_landmark*/ true); #endif } } //------------------------------------------------------------------------------ void vtkPythonInterpreter::AddUserPythonPath(const char* libraryPath, const char* landmark) { vtkPythonInterpreter::UserPythonPaths.emplace_back(libraryPath, landmark); } int vtkPythonInterpreter::AddAtExitCallback(void (*func)()) { if (Py_IsInitialized() == 0) { vtkPythonInterpreter::AtExitCallbacks.emplace_back(func); return 1; } return Py_AtExit(func); } //------------------------------------------------------------------------------ bool vtkPythonInterpreter::InitializeWithArgs( int initsigs, int argc, char* argv[], const char* programName) { bool isolated = vtkPythonPreConfig(); if (Py_IsInitialized() == 0) { if (programName) { vtkPythonInterpreter::SetProgramName(programName); } else { // If no program name is specified, // guide the mechanism to locate Python standard library, if possible. SetupPythonPrefix(isolated); } bool signals_installed = initsigs != 0; // Need two copies of args, because programs might modify the first using OwnedWideString = std::unique_ptr; std::vector argvForPython; std::vector argvCleanup; for (int i = 0; i < argc; i++) { OwnedWideString argCopy(vtk_Py_UTF8ToWide(argv[i]), CharDeleter()); if (argCopy == nullptr) { vtk::print(stderr, "Fatal vtkpython error: " "unable to decode the command line argument #{:d}\n", i + 1); return false; } argvForPython.push_back(argCopy.get()); argvCleanup.emplace_back(std::move(argCopy)); } argvForPython.push_back(nullptr); #if PY_VERSION_HEX < 0x03080000 Py_InitializeEx(initsigs); // setup default argv. Without this, code snippets that check `sys.argv` may // fail when run in embedded VTK Python environment. PySys_SetArgvEx(argc, argvForPython.data(), 0); isolated = Py_FrozenFlag; #else PyConfig config; PyStatus status; PyConfig_InitPythonConfig(&config); config.install_signal_handlers = initsigs; config.program_name = PythonProgramName.pop_last(); status = PyConfig_SetArgv(&config, argc, argvForPython.data()); if (PyStatus_IsError(status)) { PyConfig_Clear(&config); return false; } status = Py_InitializeFromConfig(&config); if (PyStatus_IsError(status)) { PyConfig_Clear(&config); return false; } isolated = config.pathconfig_warnings == 0; PyConfig_Clear(&config); #endif #ifdef VTK_PYTHON_FULL_THREADSAFE #if PY_VERSION_HEX < 0x03090000 // In Python 3.9 and higher, PyEval_ThreadsInitialized() and // PyEval_InitThreads() are deprecated and do nothing. // GIL initialization is handled by Py_InitializeEx(). int threadInit = PyEval_ThreadsInitialized(); if (!threadInit) { PyEval_InitThreads(); // initialize and acquire GIL } #endif // Always release GIL, as it has been acquired either by PyEval_InitThreads // prior to Python 3.7 or by Py_InitializeEx in Python 3.7 and after PyEval_SaveThread(); #endif #ifdef SIGINT if (signals_installed) { // Put default SIGINT handler back after Py_Initialize/Py_InitializeEx. signal(SIGINT, SIG_DFL); } #endif } if (!vtkPythonInterpreter::InitializedOnce) { vtkPythonInterpreter::InitializedOnce = true; // HACK: Calling PyRun_SimpleString for the first time for some reason results in // a "\n" message being generated which is causing the error dialog to // popup. So we flush that message out of the system before setting up the // callbacks. vtkPythonInterpreter::RunSimpleString(""); // Redirect Python's stdout and stderr and stdin - GIL protected operation if (vtkPythonInterpreter::RedirectOutput) { // Setup handlers for stdout/stdin/stderr. vtkPythonStdStreamCaptureHelper* wrapperOut = NewPythonStdStreamCaptureHelper(false); vtkPythonStdStreamCaptureHelper* wrapperErr = NewPythonStdStreamCaptureHelper(true); vtkPythonScopeGilEnsurer gilEnsurer; PySys_SetObject("stdout", reinterpret_cast(wrapperOut)); PySys_SetObject("stderr", reinterpret_cast(wrapperErr)); PySys_SetObject("stdin", reinterpret_cast(wrapperOut)); Py_DECREF(wrapperOut); Py_DECREF(wrapperErr); } // We call this before processing any of Python paths added by the // application using `PrependPythonPath`. This ensures that application // specified paths are preferred to the ones `vtkPythonInterpreter` adds. std::string vtklib = vtkGetLibraryPathForSymbol(GetVTKVersion); SetupPythonPaths(isolated, vtklib, "vtkmodules/__init__.py"); // Used to setup additional user python paths added by `AddUserPythonPath` method. for (const auto& pair : vtkPythonInterpreter::UserPythonPaths) { if (!pair.first.empty()) { SetupPythonPaths(isolated, pair.first, pair.second.c_str()); } } for (size_t cc = 0; cc < PythonPaths.size(); cc++) { vtkPrependPythonPath(PythonPaths[cc].c_str()); } for (auto* func : vtkPythonInterpreter::AtExitCallbacks) { if (Py_AtExit(func)) { return false; } } vtkPythonInterpreter::AtExitCallbacks.clear(); NotifyInterpreters(vtkCommand::EnterEvent); return true; } return false; } //------------------------------------------------------------------------------ void vtkPythonInterpreter::Finalize() { if (Py_IsInitialized() != 0) { NotifyInterpreters(vtkCommand::ExitEvent); vtkPythonScopeGilEnsurer gilEnsurer(false, true); #ifdef vtkPythonInterpreter_USE_DIRECTORY_COOKIE CloseDLLDirectoryCookie(); #endif // Py_Finalize will take care of releasing gil Py_Finalize(); } } //------------------------------------------------------------------------------ void vtkPythonInterpreter::SetProgramName(const char* programname) { vtkPythonPreConfig(); if (programname) { #if PY_VERSION_HEX >= 0x03080000 if (wchar_t* argv0 = vtk_Py_UTF8ToWide(programname)) { PythonProgramName.push_back(argv0); } else { vtk::print(stderr, "Fatal vtkpython error: " "unable to decode the program name\n"); wchar_t* empty = (wchar_t*)PyMem_RawMalloc(sizeof(wchar_t)); empty[0] = 0; PythonProgramName.push_back(empty); } #else // From Python Docs: The argument should point to a zero-terminated character // string in static storage whose contents will not change for the duration of // the program's execution. No code in the Python interpreter will change the // contents of this storage. wchar_t* argv0 = vtk_Py_UTF8ToWide(programname); if (argv0 == nullptr) { vtk::print(stderr, "Fatal vtkpython error: " "unable to decode the program name\n"); static wchar_t empty[1] = { 0 }; argv0 = empty; Py_SetProgramName(argv0); } else { static WCharStringPool wpool; Py_SetProgramName(wpool.push_back(argv0)); } #endif } } //------------------------------------------------------------------------------ void vtkPythonInterpreter::PrependPythonPath(const char* dir) { if (!dir) { return; } std::string out_dir = dir; #if defined(_WIN32) && !defined(__CYGWIN__) // Convert slashes for this platform. std::replace(out_dir.begin(), out_dir.end(), '/', '\\'); #endif if (Py_IsInitialized() == 0) { // save path for future use. PythonPaths.push_back(out_dir); return; } // Append the path to the python sys.path object. vtkPrependPythonPath(out_dir.c_str()); } //------------------------------------------------------------------------------ void vtkPythonInterpreter::PrependPythonPath( const char* anchor, const char* landmark, bool add_landmark) { const std::vector prefixes = { VTK_PYTHON_SITE_PACKAGES_SUFFIX #if defined(__APPLE__) // if in an App bundle, the `sitepackages` dir is /Contents/Python , "Contents/Python" #endif , "." }; vtkNew locator; locator->SetLogVerbosity(vtkPythonInterpreter::GetLogVerbosity() + 1); std::string path = locator->Locate(anchor, prefixes, landmark); if (!path.empty()) { if (add_landmark) { path = path + "/" + landmark; } vtkPythonInterpreter::PrependPythonPath(path.c_str()); } } //------------------------------------------------------------------------------ int vtkPythonInterpreter::PyMain(int argc, char** argv) { vtksys::SystemTools::EnableMSVCDebugHook(); int count_v = 0; for (int cc = 0; cc < argc; ++cc) { if (argv[cc] && strcmp(argv[cc], "-v") == 0) { ++count_v; } if (argv[cc] && strcmp(argv[cc], "-vv") == 0) { count_v += 2; } } if (count_v > 0) { // change the vtkPythonInterpreter's log verbosity. We only touch it // if the command line arguments explicitly requested a certain verbosity. vtkPythonInterpreter::SetLogVerbosity(vtkLogger::VERBOSITY_INFO); vtkLogger::SetStderrVerbosity(vtkLogger::ConvertToVerbosity(count_v - 1)); } vtkLogger::Init(argc, argv, nullptr); // since `-v` and `-vv` are parsed as Python verbosity flags // and not log verbosity flags. // Need two copies of args, because the first array may be modified elsewhere. using OwnedCString = std::unique_ptr; std::vector argvForPython; std::vector argvCleanup; for (int i = 0; i < argc; i++) { if (!argv[i]) { continue; } if (strcmp(argv[i], "--enable-bt") == 0) { vtksys::SystemInformation::SetStackTraceOnError(1); continue; } if (strcmp(argv[i], "-V") == 0) { // print out VTK version and let argument pass to Py_RunMain(). At which // point, Python will print its version and exit. std::cout << vtkVersion::GetVTKSourceVersion() << std::endl; } OwnedCString argCopy(strdup(argv[i]), &std::free); if (argCopy == nullptr) { vtk::print(stderr, "Fatal vtkpython error: " "unable to copy the command line argument #{:d}\n", i + 1); return 1; } argvForPython.push_back(argCopy.get()); argvCleanup.emplace_back(std::move(argCopy)); } int argvForPythonSize = static_cast(argvForPython.size()); argvForPython.push_back(nullptr); vtkPythonInterpreter::InitializeWithArgs(1, argvForPythonSize, argvForPython.data()); #if PY_VERSION_HEX >= 0x03070000 && PY_VERSION_HEX < 0x03080000 // Python 3.7.0 has a bug where Py_InitializeEx (called above) followed by // Py_Main (at the end of this block) causes a crash. Gracefully exit with // failure if we're using 3.7.0 and suggest getting the newest 3.7.x release. // See for details. { bool is_ok = true; vtkPythonScopeGilEnsurer gilEnsurer(false, true); PyObject* sys = PyImport_ImportModule("sys"); if (sys) { // XXX: Check sys.implementation.name == 'cpython'? PyObject* version_info = PyObject_GetAttrString(sys, "version_info"); if (version_info) { PyObject* major = PyObject_GetAttrString(version_info, "major"); PyObject* minor = PyObject_GetAttrString(version_info, "minor"); PyObject* micro = PyObject_GetAttrString(version_info, "micro"); auto py_number_cmp = [](PyObject* obj, long expected) { return obj && PyLong_Check(obj) && PyLong_AsLong(obj) == expected; }; // Only 3.7.0 has this issue. Any failures to get the version // information is OK; we'll just crash later anyways if the version is // bad. is_ok = !py_number_cmp(major, 3) || !py_number_cmp(minor, 7) || !py_number_cmp(micro, 0); Py_XDECREF(micro); Py_XDECREF(minor); Py_XDECREF(major); } Py_XDECREF(version_info); } Py_XDECREF(sys); if (!is_ok) { std::cerr << "Python 3.7.0 has a known issue that causes a crash with a " "specific API usage pattern. This has been fixed in 3.7.1 and all " "newer 3.7.x Python releases. Exiting now to avoid the crash." << std::endl; return 1; } } #endif #if PY_VERSION_HEX < 0x03080000 // Need two copies of args, because programs might modify the first using OwnedWideString = std::unique_ptr; std::vector argvForPythonWide; std::vector argvCleanupWide; for (size_t i = 0; i < argvCleanup.size(); i++) { OwnedWideString argCopy(vtk_Py_UTF8ToWide(argvCleanup[i].get()), CharDeleter()); if (argCopy == nullptr) { vtk::print(stderr, "Fatal vtkpython error: " "unable to decode the command line argument #{:d}\n", i + 1); return 1; } argvForPythonWide.push_back(argCopy.get()); argvCleanupWide.emplace_back(std::move(argCopy)); } int argvForPythonWideSize = static_cast(argvForPythonWide.size()); argvForPythonWide.push_back(nullptr); vtkPythonScopeGilEnsurer gilEnsurer(false, true); return Py_Main(argvForPythonWideSize, argvForPythonWide.data()); #else vtkPythonScopeGilEnsurer gilEnsurer(false, true); return Py_RunMain(); #endif } //------------------------------------------------------------------------------ int vtkPythonInterpreter::RunSimpleString(const char* script) { vtkPythonInterpreter::Initialize(1); vtkPythonInterpreter::ConsoleBuffering = true; // 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 = script ? script : ""; buffer.erase(std::remove(buffer.begin(), buffer.end(), '\r'), buffer.end()); // The cast is necessary because PyRun_SimpleString() hasn't always been const-correct int pyReturn; { vtkPythonScopeGilEnsurer gilEnsurer; pyReturn = PyRun_SimpleString(buffer.c_str()); } vtkPythonInterpreter::ConsoleBuffering = false; if (!vtkPythonInterpreter::StdErrBuffer.empty()) { vtkOutputWindow::GetInstance()->DisplayErrorText(vtkPythonInterpreter::StdErrBuffer.c_str()); NotifyInterpreters( vtkCommand::ErrorEvent, const_cast(vtkPythonInterpreter::StdErrBuffer.c_str())); vtkPythonInterpreter::StdErrBuffer.clear(); } if (!vtkPythonInterpreter::StdOutBuffer.empty()) { vtkOutputWindow::GetInstance()->DisplayText(vtkPythonInterpreter::StdOutBuffer.c_str()); NotifyInterpreters( vtkCommand::SetOutputEvent, const_cast(vtkPythonInterpreter::StdOutBuffer.c_str())); vtkPythonInterpreter::StdOutBuffer.clear(); } return pyReturn; } //------------------------------------------------------------------------------ void vtkPythonInterpreter::SetCaptureStdin(bool val) { vtkPythonInterpreter::CaptureStdin = val; } //------------------------------------------------------------------------------ bool vtkPythonInterpreter::GetCaptureStdin() { return vtkPythonInterpreter::CaptureStdin; } //------------------------------------------------------------------------------ void vtkPythonInterpreter::SetRedirectOutput(bool redirect) { vtkPythonInterpreter::RedirectOutput = redirect; } //------------------------------------------------------------------------------ bool vtkPythonInterpreter::GetRedirectOutput() { return vtkPythonInterpreter::RedirectOutput; } //------------------------------------------------------------------------------ void vtkPythonInterpreter::WriteStdOut(const char* txt) { if (vtkPythonInterpreter::ConsoleBuffering) { vtkPythonInterpreter::StdOutBuffer += std::string(txt); } else { vtkOutputWindow::GetInstance()->DisplayText(txt); NotifyInterpreters(vtkCommand::SetOutputEvent, const_cast(txt)); } } //------------------------------------------------------------------------------ void vtkPythonInterpreter::FlushStdOut() {} //------------------------------------------------------------------------------ void vtkPythonInterpreter::WriteStdErr(const char* txt) { if (vtkPythonInterpreter::ConsoleBuffering) { vtkPythonInterpreter::StdErrBuffer += std::string(txt); } else { vtkOutputWindow::GetInstance()->DisplayErrorText(txt); NotifyInterpreters(vtkCommand::ErrorEvent, const_cast(txt)); } } //------------------------------------------------------------------------------ void vtkPythonInterpreter::FlushStdErr() {} //------------------------------------------------------------------------------ vtkStdString vtkPythonInterpreter::ReadStdin() { if (!vtkPythonInterpreter::CaptureStdin) { vtkStdString string; std::cin >> string; return string; } vtkStdString string; NotifyInterpreters(vtkCommand::UpdateEvent, &string); return string; } //------------------------------------------------------------------------------ void vtkPythonInterpreter::SetLogVerbosity(int val) { vtkPythonInterpreter::LogVerbosity = vtkLogger::ConvertToVerbosity(val); } //------------------------------------------------------------------------------ int vtkPythonInterpreter::GetLogVerbosity() { return vtkPythonInterpreter::LogVerbosity; } #if defined(_WIN32) //------------------------------------------------------------------------------ vtkWideArgsConverter::vtkWideArgsConverter(int argc, wchar_t* wargv[]) { this->Argc = argc; for (int i = 0; i < argc; i++) { std::string str = vtksys::Encoding::ToNarrow(wargv[i]); char* cstr = vtksys::SystemTools::DuplicateString(str.c_str()); Args.push_back(cstr); MemCache.push_back(cstr); } Args.push_back(nullptr); } //------------------------------------------------------------------------------ vtkWideArgsConverter::~vtkWideArgsConverter() { for (auto cstr : MemCache) { delete[] cstr; } } #endif VTK_ABI_NAMESPACE_END