OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::anonymous_namespace{PythonInterpreter.cpp} Namespace Reference

Functions

std::string format_python_error (PyObject *ptype, PyObject *pvalue, PyObject *ptraceback)
std::string executable_name (const char *base)
bool add_sys_path_entry (const boost::filesystem::path &path, std::string &error, bool *inserted=nullptr)
void log_python_stream (PyObject *sys, const char *name)
void restore_python_stream (PyObject *sys, const char *name)
void install_python_stderr_redirect ()
void log_and_restore_python_stdio ()
bool valid_python_home (const boost::filesystem::path &candidate)
boost::filesystem::path find_bundled_python_home ()
boost::filesystem::path find_python_executable (const boost::filesystem::path &python_home)

Variables

constexpr const char * PYTHON_STDLIB_DIR = "python3.12"
constexpr const char * PYTHON_EXECUTABLE = "python3.12"

Function Documentation

◆ add_sys_path_entry()

bool Slic3r::anonymous_namespace{PythonInterpreter.cpp}::add_sys_path_entry ( const boost::filesystem::path & path,
std::string & error,
bool * inserted = nullptr )
193{
194 if (inserted)
195 *inserted = false;
196
197 PyObject* sys_path = PySys_GetObject("path");
198 if (!sys_path || !PyList_Check(sys_path)) {
199 error = "Python sys.path is not available";
200 return false;
201 }
202
203 const std::string path_str = path.string();
204 PyObjectPtr py_path(PyUnicode_DecodeFSDefault(path_str.c_str()));
205 if (!py_path) {
206 error = "Failed to decode path for Python sys.path: " + path_str;
207 PyErr_Clear();
208 return false;
209 }
210
211 const int contains = PySequence_Contains(sys_path, py_path.get());
212 if (contains == 1)
213 return true;
214 if (contains < 0)
215 PyErr_Clear();
216
217 if (PyList_Insert(sys_path, 0, py_path.get()) != 0) {
218 error = "Failed to add path to Python sys.path: " + path_str;
219 PyErr_Clear();
220 return false;
221 }
222
223 if (inserted)
224 *inserted = true;
225
226 return true;
227}
Definition PythonInterpreter.hpp:194
bool contains(const std::vector< T > &vector, const Point &point)
Definition Geometry.cpp:55

References add_sys_path_entry(), Slic3r::Geometry::contains(), and Slic3r::PyObjectPtr::get().

Referenced by add_sys_path_entry().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ executable_name()

std::string Slic3r::anonymous_namespace{PythonInterpreter.cpp}::executable_name ( const char * base)
184{
185#ifdef _WIN32
186 return std::string(base) + ".exe";
187#else
188 return base;
189#endif
190}

References executable_name().

Referenced by executable_name().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ find_bundled_python_home()

boost::filesystem::path Slic3r::anonymous_namespace{PythonInterpreter.cpp}::find_bundled_python_home ( )
329{
330 PyObject* sys = PyImport_ImportModule("sys");
331 if (!sys) {
332 PyErr_Clear();
333 BOOST_LOG_TRIVIAL(warning) << "Python shutdown: failed to import sys for stdio diagnostics";
334 return;
335 }
336
337 log_python_stream(sys, "stdout");
338 log_python_stream(sys, "stderr");
339 restore_python_stream(sys, "stdout");
340 restore_python_stream(sys, "stderr");
341
342 Py_DECREF(sys);
343}
344
345bool valid_python_home(const boost::filesystem::path& candidate)
346{
347#ifdef _WIN32
348 return boost::filesystem::exists(candidate / "Lib" / "encodings") &&
349 (boost::filesystem::exists(candidate / PYTHON_DLL) || boost::filesystem::exists(candidate / PYTHON_DEBUG_DLL));
350#else
351 return boost::filesystem::exists(candidate / "lib" / PYTHON_STDLIB_DIR / "encodings");
352#endif
353}
354
355boost::filesystem::path find_bundled_python_home()
356{
357 namespace fs = boost::filesystem;
358
359#ifdef __APPLE__
360 fs::path bundle_python = fs::path(resources_dir()).parent_path() / "MacOS" / "python";
361 if (valid_python_home(bundle_python))
362 return bundle_python;
363#elif !defined(_WIN32)
364 fs::path linux_python = fs::path(resources_dir()).parent_path() / "lib" / "python";
365 if (valid_python_home(linux_python))
366 return linux_python;
367#endif
368
369 // Next to the executable: the Windows install layout, and the runtime copied
370 // beside every platform's unit-test binary (tests/slic3rutils/CMakeLists.txt).
void log_python_stream(PyObject *sys, const char *name)
Definition PythonInterpreter.cpp:229
bool valid_python_home(const boost::filesystem::path &candidate)
Definition PythonInterpreter.cpp:315
boost::filesystem::path find_bundled_python_home()
Definition PythonInterpreter.cpp:325
void restore_python_stream(PyObject *sys, const char *name)
Definition PythonInterpreter.cpp:251
constexpr const char * PYTHON_STDLIB_DIR
Definition PythonInterpreter.cpp:179
const std::string & resources_dir()
Definition utils.cpp:296

◆ find_python_executable()

boost::filesystem::path Slic3r::anonymous_namespace{PythonInterpreter.cpp}::find_python_executable ( const boost::filesystem::path & python_home)
383 {
384 fs::path libpython = fs::path(prefix_path) / "libpython";
385 if (valid_python_home(libpython))
386 return libpython;
387 }
388
389 fs::path res_python = fs::path(resources_dir()) / "python";
390 if (valid_python_home(res_python))
391 return res_python;
392
393#ifndef _WIN32
394 fs::path data_python = fs::path(data_dir()) / "python";
395 if (valid_python_home(data_python))
const std::string & data_dir()
Definition utils.cpp:365

References valid_python_home().

Here is the call graph for this function:

◆ format_python_error()

std::string Slic3r::anonymous_namespace{PythonInterpreter.cpp}::format_python_error ( PyObject * ptype,
PyObject * pvalue,
PyObject * ptraceback )
133{
134 std::string result;
135
136 if (ptype) {
137 PyObject* type_name = PyObject_GetAttrString(ptype, "__name__");
138 if (type_name) {
139 const char* s = PyUnicode_AsUTF8(type_name);
140 if (s) result += s;
141 Py_DECREF(type_name);
142 }
143 }
144
145 if (pvalue) {
146 if (!result.empty()) result += ": ";
147 PyObject* s = PyObject_Str(pvalue);
148 if (s) {
149 const char* cstr = PyUnicode_AsUTF8(s);
150 if (cstr) result += cstr;
151 Py_DECREF(s);
152 }
153 }
154
155 if (ptraceback) {
156 result += "\nTraceback (most recent call last):";
157 PyTracebackObject* tb = reinterpret_cast<PyTracebackObject*>(ptraceback);
158 while (tb) {
159 PyFrameObject* frame = tb->tb_frame;
160 int line = PyFrame_GetLineNumber(frame);
161 PyCodeObject* code = PyFrame_GetCode(frame); // returns a NEW strong reference; must be released
162 const char* filename = code ? PyUnicode_AsUTF8(code->co_filename) : nullptr;
163 const char* funcname = code ? PyUnicode_AsUTF8(code->co_name) : nullptr;
164 result += "\n File \"" + std::string(filename ? filename : "?") +
165 "\", line " + std::to_string(line) +
166 ", in " + std::string(funcname ? funcname : "?");
167 Py_XDECREF(code);
168 tb = tb->tb_next;
169 }
170 }
171
172 return result;
173}

References format_python_error().

Referenced by format_python_error().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ install_python_stderr_redirect()

void Slic3r::anonymous_namespace{PythonInterpreter.cpp}::install_python_stderr_redirect ( )
277{
278 // Mirror the session filename convention from GUI_App: python_<weekday>_<mon>_<day>_<HH>_<MM>_<SS>_<pid>.log
279 std::time_t t = std::time(nullptr);
280 std::tm* now = std::localtime(&t);
281 std::ostringstream name;
282 name << std::put_time(now, "python_%a_%b_%d_%H_%M_%S_") << get_current_pid() << ".log";
283 const std::string log_path = (boost::filesystem::path(data_dir()) / "log" / name.str()).generic_string();
284
285 const std::string redirect_script =
286 "import io, os, sys, threading\n"
287 "_ORCA_PYTHON_LOG = \"" + log_path + "\"\n"
288 + std::string(R"REDIRECT_SCRIPT(
289class _OrcaTeeStderr(io.TextIOBase):
290 def __init__(self, original, path):
291 self._original = original
292 self._path = path
293 self._lock = threading.Lock()
294 def writable(self):
295 return True
296 def write(self, s):
unsigned get_current_pid()
Definition utils.cpp:1480

References Slic3r::data_dir(), Slic3r::get_current_pid(), and install_python_stderr_redirect().

Referenced by install_python_stderr_redirect().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ log_and_restore_python_stdio()

void Slic3r::anonymous_namespace{PythonInterpreter.cpp}::log_and_restore_python_stdio ( )
298 :
299 self._original.write(s)
300 except Exception:
301 pass
302 try:
303 with self._lock, open(self._path, "a", encoding="utf-8", errors="replace") as f:
304 f.write(s)
305 except Exception:
306 pass
307 return len(s)
308 def flush(self):
309 try:
310 if self._original is not None:
311 self._original.flush()
312 except Exception:
313 pass
Definition Exception.hpp:13
static double f(double x, double z_sin, double z_cos, bool vertical, bool flip)
Definition FillGyroid.cpp:124
@ None
Definition SketchEngine.hpp:180

◆ log_python_stream()

void Slic3r::anonymous_namespace{PythonInterpreter.cpp}::log_python_stream ( PyObject * sys,
const char * name )
230{
231 PyObject* stream = PyObject_GetAttrString(sys, name);
232 if (!stream) {
233 PyErr_Clear();
234 BOOST_LOG_TRIVIAL(info) << "Python shutdown: sys." << name << " is not set";
235 return;
236 }
237
238 PyObject* original = nullptr;
239 std::string original_name = std::string("__") + name + "__";
240 original = PyObject_GetAttrString(sys, original_name.c_str());
241 if (!original)
242 PyErr_Clear();
243
244 BOOST_LOG_TRIVIAL(info) << "Python shutdown: sys." << name << " type=" << Py_TYPE(stream)->tp_name << " ptr=" << stream
245 << " original_ptr=" << original << " is_original=" << (stream == original);
246
247 Py_XDECREF(original);
248 Py_DECREF(stream);
249}

References log_python_stream().

Referenced by log_python_stream().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ restore_python_stream()

void Slic3r::anonymous_namespace{PythonInterpreter.cpp}::restore_python_stream ( PyObject * sys,
const char * name )
252{
253 std::string original_name = std::string("__") + name + "__";
254 PyObject* original = PyObject_GetAttrString(sys, original_name.c_str());
255 if (!original) {
256 PyErr_Clear();
257 original = Py_NewRef(Py_None);
258 }
259
260 if (PyObject_SetAttrString(sys, name, original) < 0) {
261 PyErr_Clear();
262 BOOST_LOG_TRIVIAL(warning) << "Python shutdown: failed to restore sys." << name;
263 } else {
264 BOOST_LOG_TRIVIAL(info) << "Python shutdown: restored sys." << name << " to type=" << Py_TYPE(original)->tp_name
265 << " ptr=" << original;
266 }
267
268 Py_DECREF(original);
269}

References restore_python_stream().

Referenced by restore_python_stream().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ valid_python_home()

bool Slic3r::anonymous_namespace{PythonInterpreter.cpp}::valid_python_home ( const boost::filesystem::path & candidate)
320 {
321 PyErr_Clear();
322 BOOST_LOG_TRIVIAL(warning) << "Failed to install Python stderr redirect to " << log_path;
323 } else {

Referenced by find_python_executable().

Here is the caller graph for this function:

Variable Documentation

◆ PYTHON_EXECUTABLE

const char* Slic3r::anonymous_namespace{PythonInterpreter.cpp}::PYTHON_EXECUTABLE = "python3.12"
constexpr

◆ PYTHON_STDLIB_DIR

const char* Slic3r::anonymous_namespace{PythonInterpreter.cpp}::PYTHON_STDLIB_DIR = "python3.12"
constexpr