481{
482 std::unique_lock<std::shared_timed_mutex> runtime_lock(
m_runtime_mutex);
484 return true;
485 }
486
492
493 try {
494
495
496
497 namespace fs = boost::filesystem;
499
500 if (python_home.empty()) {
501 m_last_error =
"Could not locate bundled Python installation";
502 BOOST_LOG_TRIVIAL(error) << "Could not locate bundled Python installation";
503 BOOST_LOG_TRIVIAL(error) << "Configured bundled Python root: " << ORCA_BUNDLED_PYTHON_ROOT;
504#ifdef _WIN32
505 BOOST_LOG_TRIVIAL(error) << "Searched next to executable: "
506 << (boost::dll::program_location().parent_path() / "python").string();
507#endif
508 BOOST_LOG_TRIVIAL(error) <<
"Searched in resources_dir: " <<
resources_dir();
509#ifndef _WIN32
510 BOOST_LOG_TRIVIAL(error) <<
"Searched in data_dir: " <<
data_dir();
511#endif
512 BOOST_LOG_TRIVIAL(error) << "CMAKE_PREFIX_PATH: "
513 << (std::getenv("CMAKE_PREFIX_PATH") ? std::getenv("CMAKE_PREFIX_PATH") : "not set");
514 return false;
515 }
516
517 BOOST_LOG_TRIVIAL(info) << "Found bundled Python home: " << python_home;
518
519
520#ifdef _WIN32
521 fs::path python_lib = fs::path(python_home) / "Lib";
522#else
524#endif
525 if (!fs::exists(python_lib)) {
526 m_last_error =
"Python standard library directory not found at: " + python_lib.string();
527 BOOST_LOG_TRIVIAL(error) << "Python standard library directory not found at: " << python_lib.string();
528 BOOST_LOG_TRIVIAL(error) << "Please build Python dependencies or check installation";
529 return false;
530 }
531
532 BOOST_LOG_TRIVIAL(info) << "Python standard library found at: " << python_lib.string();
533
534#ifdef _WIN32
535 fs::path python_dll = fs::exists(fs::path(python_home) / PYTHON_DLL) ? fs::path(python_home) / PYTHON_DLL :
536 fs::path(python_home) / PYTHON_DEBUG_DLL;
537 if (!fs::exists(python_dll)) {
538 m_last_error =
"Python DLL not found in: " + python_home;
539 BOOST_LOG_TRIVIAL(error) << "Python DLL not found in: " << python_home;
540 return false;
541 }
542 BOOST_LOG_TRIVIAL(info) << "Python DLL found at: " << python_dll.string();
543 if (!fs::exists(fs::path(python_home) / "DLLs")) {
544 BOOST_LOG_TRIVIAL(warning) << "Python DLLs directory not found at: " << (fs::path(python_home) / "DLLs").string();
545 }
546#endif
547
548
549 BOOST_LOG_TRIVIAL(info) << "Setting Python home to: " << python_home;
550 BOOST_LOG_TRIVIAL(info) << "Python 3.12 stdlib path: " << python_lib.string();
551
552
553 fs::path encodings_path = python_lib / "encodings";
554 if (fs::exists(encodings_path)) {
555 BOOST_LOG_TRIVIAL(info) << "Encodings module found at: " << encodings_path.string();
556 } else {
557 BOOST_LOG_TRIVIAL(warning) << "Encodings module NOT found at: " << encodings_path.string();
558 }
559
560 BOOST_LOG_TRIVIAL(info) << "Using Python 3.12 PyConfig initialization API";
561
562
563 PyConfig config;
564 PyConfig_InitPythonConfig(&config);
565
566
567 config.use_environment = 0;
568 config.user_site_directory = 0;
569
570 BOOST_LOG_TRIVIAL(debug) << "Calling PyConfig_SetBytesString with home=" << python_home;
571 PyStatus status = PyConfig_SetBytesString(&config, &config.home, python_home.c_str());
572 if (PyStatus_Exception(status)) {
573 m_last_error = status.err_msg ? status.err_msg :
"Failed to set Python home";
574 BOOST_LOG_TRIVIAL(error) <<
"Failed to set Python home to: " << python_home <<
": " <<
m_last_error;
575 PyConfig_Clear(&config);
576 return false;
577 }
578 BOOST_LOG_TRIVIAL(debug) << "Python home set successfully";
579
580
581 status = PyConfig_SetBytesString(&config, &config.program_name, "OrcaSlicer");
582 if (PyStatus_Exception(status)) {
583 m_last_error = status.err_msg ? status.err_msg :
"Failed to set program name";
584 BOOST_LOG_TRIVIAL(error) <<
"Failed to set program name: " <<
m_last_error;
585 PyConfig_Clear(&config);
586 return false;
587 }
588 BOOST_LOG_TRIVIAL(debug) << "Program name set successfully";
589
590
591
592
593 const std::string pycache_prefix =
data_dir() +
"/python/pycache";
594#ifdef _WIN32
595 status = PyConfig_SetString(&config, &config.pycache_prefix, boost::nowide::widen(pycache_prefix).c_str());
596#else
597 status = PyConfig_SetBytesString(&config, &config.pycache_prefix, pycache_prefix.c_str());
598#endif
599 if (PyStatus_Exception(status))
600 BOOST_LOG_TRIVIAL(warning) << "Failed to set the Python bytecode cache to " << pycache_prefix << ": "
601 << (status.err_msg ? status.err_msg : "unknown error");
602
603
604
605
606 BOOST_LOG_TRIVIAL(debug) << "Creating py::scoped_interpreter with PyConfig...";
607 try {
608 m_interpreter = std::make_unique<pybind11::scoped_interpreter>(&config);
609 } catch (const std::exception& ex) {
610 m_last_error = std::string(
"Python initialization failed: ") + ex.what();
612 PyConfig_Clear(&config);
613 return false;
614 }
615
616 BOOST_LOG_TRIVIAL(debug) << "py::scoped_interpreter initialized successfully";
617
618 if (!Py_IsInitialized()) {
620 BOOST_LOG_TRIVIAL(error) << "Python interpreter not initialized";
621 return false;
622 }
623
624
625 PyObject* sys = PyImport_ImportModule("sys");
626 if (sys) {
627 PyObject* path = PyObject_GetAttrString(sys, "path");
628 if (path) {
629 PyObject* path_str = PyObject_Str(path);
630 if (path_str) {
631 const char* path_cstr = PyUnicode_AsUTF8(path_str);
632 if (path_cstr) {
633 BOOST_LOG_TRIVIAL(debug) << "Python sys.path: " << path_cstr;
634 }
635 Py_DECREF(path_str);
636 }
637 Py_DECREF(path);
638 }
639 Py_DECREF(sys);
640 }
641
642 BOOST_LOG_TRIVIAL(info) << "Python " << Py_GetVersion() << " initialized successfully";
643
645 boost::system::error_code ec;
646 fs::create_directories(shared_packages, ec);
647 if (ec) {
648 BOOST_LOG_TRIVIAL(warning) << "Failed to create Python shared package directory: " << shared_packages.string() << ": "
649 << ec.message();
650 } else {
651 std::string path_error;
653 BOOST_LOG_TRIVIAL(info) << "Added Python shared package directory to sys.path: " << shared_packages.string();
654 else
655 BOOST_LOG_TRIVIAL(warning) << path_error;
656 }
657
659 if (!uv_path.empty())
660 BOOST_LOG_TRIVIAL(info) << "Bundled uv executable found at: " << uv_path;
661 else
662 BOOST_LOG_TRIVIAL(info) << "Bundled uv executable not found";
663
665
666
667
669
670
671
672
674
675
676
679 BOOST_LOG_TRIVIAL(debug) << "Main thread released Python GIL after initialization";
680 return true;
681
682 } catch (const std::exception& ex) {
683 m_last_error = std::string(
"Exception initializing Python: ") + ex.what();
684 BOOST_LOG_TRIVIAL(error) << "Exception initializing Python: " << ex.what();
685 return false;
686 }
687}
void install_hook()
Definition PluginAuditManager.cpp:1800
static PluginAuditManager & instance()
Definition PluginAuditManager.cpp:535
PyThreadState * m_main_thread_state
Definition PythonInterpreter.hpp:127
std::shared_timed_mutex m_runtime_mutex
Definition PythonInterpreter.hpp:126
static std::string bundled_uv_path()
Definition PythonInterpreter.cpp:455
std::unordered_map< std::string, std::size_t > m_plugin_module_users
Definition PythonInterpreter.hpp:132
std::unordered_map< std::string, bool > m_plugin_module_owned
Definition PythonInterpreter.hpp:133
std::string m_last_error
Definition PythonInterpreter.hpp:129
static std::string shared_packages_dir()
Definition PythonInterpreter.cpp:440
void install_python_stderr_redirect()
Definition PythonInterpreter.cpp:276
constexpr const char * PYTHON_STDLIB_DIR
Definition PythonInterpreter.cpp:179
void install_python_thread_audit_shim()
Definition PythonPluginBridge.cpp:660
const std::string & data_dir()
Definition utils.cpp:365