Blender V5.0
bpy_interface.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
12
13#include <Python.h>
14#include <frameobject.h>
15#include <optional>
16
17#ifdef WITH_PYTHON_MODULE
18# include "pylifecycle.h" /* For `Py_Version`. */
19#endif
20#include "../generic/python_compat.hh" /* IWYU pragma: keep. */
21
22#include "CLG_log.h"
23
24#include "BLI_path_utils.hh"
25#include "BLI_string.h"
26#include "BLI_string_utf8.h"
27#include "BLI_threads.h"
28#include "BLI_utildefines.h"
29#ifdef WITH_PYTHON_MODULE
30# include "BLI_string.h"
31#endif
32
33#include "BLT_translation.hh"
34
35#include "RNA_types.hh"
36
37#include "bpy.hh"
38#include "bpy_capi_utils.hh"
39#include "bpy_intern_string.hh"
40#include "bpy_path.hh"
41#include "bpy_props.hh"
42#include "bpy_rna.hh"
43
45
46#include "DNA_text_types.h"
47
48#include "BKE_appdir.hh"
49#include "BKE_context.hh"
50#include "BKE_global.hh" /* Only for script checking. */
51#include "BKE_main.hh"
52#include "BKE_text.h"
53
54#ifdef WITH_CYCLES
55# include "CCL_api.h"
56#endif
57
58#include "BPY_extern.hh"
59#include "BPY_extern_python.hh"
60#include "BPY_extern_run.hh"
61
63
64/* `inittab` initialization functions. */
70#include "../gpu/gpu_py_api.hh"
72
73/* Logging types to use anywhere in the Python modules. */
74
77
79
80/* For internal use, when starting and ending Python scripts. */
81
82/* In case a Python script triggers another Python call,
83 * stop #bpy_context_clear from invalidating. */
84static int py_call_level = 0;
85
86/* Set by command line arguments before Python starts. */
87static bool py_use_system_env = false;
88
89// #define TIME_PY_RUN /* Simple python tests. prints on exit. */
90
91#ifdef TIME_PY_RUN
92# include "BLI_time.h"
93static int bpy_timer_count = 0;
95static double bpy_timer;
97static double bpy_timer_run;
99static double bpy_timer_run_tot;
100#endif
101
103{
104 /* Don't do this from a non-main (e.g. render) thread, it can cause a race
105 * condition on `C->data.recursion`. Ideal solution would be to disable
106 * context entirely from non-main threads, but that's more complicated. */
107 if (!BLI_thread_is_main()) {
108 return;
109 }
110
112
113 /* Can give really bad results if this isn't here. */
115}
116
117void bpy_context_set(bContext *C, PyGILState_STATE *gilstate)
118{
120
121 if (gilstate) {
122 *gilstate = PyGILState_Ensure();
123 }
124
125 if (py_call_level == 1) {
127
128#ifdef TIME_PY_RUN
129 if (bpy_timer_count == 0) {
130 /* Record time from the beginning. */
131 bpy_timer = BLI_time_now_seconds();
132 bpy_timer_run = bpy_timer_run_tot = 0.0;
133 }
134 bpy_timer_run = BLI_time_now_seconds();
135
136 bpy_timer_count++;
137#endif
138 }
139}
140
141void bpy_context_clear(bContext * /*C*/, const PyGILState_STATE *gilstate)
142{
144
145 if (gilstate) {
146 PyGILState_Release(*gilstate);
147 }
148
149 if (py_call_level < 0) {
150 fprintf(stderr, "ERROR: Python context internal state bug. this should not happen!\n");
151 }
152 else if (py_call_level == 0) {
153 /* NOTE: Unfortunately calling classes currently won't store the context.
154 * Can't set nullptr because of this - but this is very unreliable still. */
155#if 0
156 BPY_context_set(nullptr);
157#endif
158
159#ifdef TIME_PY_RUN
160 bpy_timer_run_tot += BLI_time_now_seconds() - bpy_timer_run;
161 bpy_timer_count++;
162#endif
163 }
164}
165
167{
168 if (UNLIKELY(C == nullptr)) {
169 return;
170 }
172}
173
175 void *dict_orig,
176 const char *context_members[],
177 uint context_members_len)
178{
179 PyGILState_STATE gilstate;
180 const bool use_gil = !PyC_IsInterpreterActive();
181 if (use_gil) {
182 gilstate = PyGILState_Ensure();
183 }
184
185 /* Copy on write. */
186 if (*dict_p == dict_orig) {
187 *dict_p = PyDict_Copy(static_cast<PyObject *>(dict_orig));
188 }
189
190 PyObject *dict = static_cast<PyObject *>(*dict_p);
191 BLI_assert(PyDict_Check(dict));
192
193 /* Use #PyDict_Pop instead of #PyDict_DelItemString to avoid setting the exception,
194 * while supported it's good to avoid for low level functions like this that run often. */
195 for (uint i = 0; i < context_members_len; i++) {
196 PyObject *key = PyUnicode_FromString(context_members[i]);
197 PyObject *item;
198
199#if PY_VERSION_HEX >= 0x030d0000
200 switch (PyDict_Pop(dict, key, &item)) {
201 case 1: {
202 Py_DECREF(item);
203 break;
204 }
205 case -1: {
206 /* Not expected, but allow for an error. */
207 BLI_assert(false);
208 PyErr_Clear();
209 break;
210 }
211 }
212#else /* Remove when Python 3.12 support is dropped. */
213 item = _PyDict_Pop(dict, key, Py_None);
214 Py_DECREF(item);
215#endif
216
217 Py_DECREF(key);
218 }
219
220 if (use_gil) {
221 PyGILState_Release(gilstate);
222 }
223}
224
226{
227 if (text->compiled) {
228 PyGILState_STATE gilstate;
229 const bool use_gil = !PyC_IsInterpreterActive();
230
231 if (use_gil) {
232 gilstate = PyGILState_Ensure();
233 }
234
235 Py_DECREF((PyObject *)text->compiled);
236 text->compiled = nullptr;
237
238 if (use_gil) {
239 PyGILState_Release(gilstate);
240 }
241 }
242}
243
245{
246 /* Correct but slow, this runs all the time operator poll, panel draw etc
247 * (100's of time a second). */
248#if 0
249 PyObject *mod = PyImport_ImportModuleLevel("bpy", nullptr, nullptr, nullptr, 0);
250 PyModule_AddObject(mod, "data", BPY_rna_module());
251 PyModule_AddObject(mod, "types", BPY_rna_types()); /* This does not need updating. */
252#endif
253
254 /* Refreshes the main struct. */
256}
257
259{
260 return static_cast<bContext *>(bpy_context_module->ptr->data);
261}
262
264{
265 bpy_context_module->ptr->data = (void *)C;
266}
267
268#ifdef WITH_FLUID
269/* Defined in `manta` module. */
270extern "C" PyObject *Manta_initPython();
271#endif
272
273#ifdef WITH_AUDASPACE_PY
274/* Defined in `AUD_C-API.cpp`. */
275extern "C" PyObject *AUD_initPython();
276#endif
277
278#ifdef WITH_CYCLES
279/* Defined in `cycles` module. */
280static PyObject *CCL_initPython()
281{
282 return (PyObject *)CCL_python_module_init();
283}
284#endif
285
286#ifdef WITH_HYDRA
287/* Defined in `render_hydra` module. */
288PyObject *BPyInit_hydra();
289#endif
290
291static _inittab bpy_internal_modules[] = {
292 {"mathutils", PyInit_mathutils},
293#if 0
294 {"mathutils.geometry", PyInit_mathutils_geometry},
295 {"mathutils.noise", PyInit_mathutils_noise},
296 {"mathutils.kdtree", PyInit_mathutils_kdtree},
297#endif
298 {"_bpy_path", BPyInit__bpy_path},
299 {"blf", BPyInit_blf},
300 {"bl_math", BPyInit_bl_math},
301 {"imbuf", BPyInit_imbuf},
302 {"bmesh", BPyInit_bmesh},
303#if 0
304 {"bmesh.types", BPyInit_bmesh_types},
305 {"bmesh.utils", BPyInit_bmesh_utils},
306 {"bmesh.utils", BPyInit_bmesh_geometry},
307#endif
308#ifdef WITH_FLUID
309 {"manta", Manta_initPython},
310#endif
311#ifdef WITH_AUDASPACE_PY
312 {"aud", AUD_initPython},
313#endif
314#ifdef WITH_CYCLES
315 {"_cycles", CCL_initPython},
316#endif
317 {"gpu", BPyInit_gpu},
318 {"idprop", BPyInit_idprop},
319#ifdef WITH_HYDRA
320 {"_bpy_hydra", BPyInit_hydra},
321#endif
322 {nullptr, nullptr},
323};
324
325#ifndef WITH_PYTHON_MODULE
335static void pystatus_exit_on_error(const PyStatus &status)
336{
337 if (UNLIKELY(PyStatus_Exception(status))) {
338 fputs("Internal error initializing Python!\n", stderr);
339 /* This calls `exit`. */
340 Py_ExitStatusException(status);
341 }
342}
343#endif
344
345void BPY_python_start(bContext *C, int argc, const char **argv)
346{
347#ifndef WITH_PYTHON_MODULE
348 BLI_assert_msg(Py_IsInitialized() == 0, "Python has already been initialized");
349
350 /* #PyPreConfig (early-configuration). */
351 {
352 PyPreConfig preconfig;
353 PyStatus status;
354
355 /* To narrow down reports where the systems Python is inexplicably used, see: #98131. */
358 "Initializing %s support for the systems Python environment such as 'PYTHONPATH' and "
359 "the user-site directory.",
360 py_use_system_env ? "*with*" : "*without*");
361
362 if (py_use_system_env) {
363 PyPreConfig_InitPythonConfig(&preconfig);
364 }
365 else {
366 /* Only use the systems environment variables and site when explicitly requested.
367 * Since an incorrect 'PYTHONPATH' causes difficult to debug errors, see: #72807.
368 * An alternative to setting `preconfig.use_environment = 0` */
369 PyPreConfig_InitIsolatedConfig(&preconfig);
370 }
371
372 /* Force UTF8 on all platforms, since this is what's used for Blender's internal strings,
373 * providing consistent encoding behavior across all Blender installations.
374 *
375 * This also uses the `surrogateescape` error handler ensures any unexpected bytes are escaped
376 * instead of raising an error.
377 *
378 * Without this `sys.getfilesystemencoding()` and `sys.stdout` for example may be set to ASCII
379 * or some other encoding - where printing some UTF8 values will raise an error.
380 *
381 * This can cause scripts to fail entirely on some systems.
382 *
383 * This assignment is the equivalent of enabling the `PYTHONUTF8` environment variable.
384 * See `PEP-540` for details on exactly what this changes. */
385 preconfig.utf8_mode = true;
386
387 /* Note that there is no reason to call #Py_PreInitializeFromBytesArgs here
388 * as this is only used so that command line arguments can be handled by Python itself,
389 * not for setting `sys.argv` (handled below). */
390 status = Py_PreInitialize(&preconfig);
392 }
393
394 /* Must run before python initializes, but after #PyPreConfig. */
395 PyImport_ExtendInittab(bpy_internal_modules);
396
397 /* #PyConfig (initialize Python). */
398 {
399 PyConfig config;
400 PyStatus status;
401 bool has_python_executable = false;
402
403 if (py_use_system_env) {
404 PyConfig_InitPythonConfig(&config);
405
406 BLI_assert(config.install_signal_handlers);
407 }
408 else {
409 PyConfig_InitIsolatedConfig(&config);
410 /* Python's isolated config disables its own signal overrides.
411 * While it makes sense not to interfering with other components of the process,
412 * the signal handlers are needed for Python's own error handling to work properly.
413 * Without this a `SIGPIPE` signal will crash Blender, see: #129657. */
414 config.install_signal_handlers = 1;
415 }
416
417 /* Suppress error messages when calculating the module search path.
418 * While harmless, it's noisy. */
419 config.pathconfig_warnings = 0;
420
421 {
422 /* NOTE: running scripts directly uses the default behavior *but* the default
423 * warning filter doesn't show warnings form module besides `__main__`.
424 * Use the default behavior unless debugging Python. See: !139487. */
425 bool show_python_warnings = false;
426
427# ifdef NDEBUG
428 show_python_warnings = G.debug & G_DEBUG_PYTHON;
429# else
430 /* Always show warnings for debug builds so developers are made aware
431 * of outdated API use before any breakages occur. */
432 show_python_warnings = true;
433# endif
434
435 if (show_python_warnings) {
436 /* Don't overwrite warning settings if they have been set by the environment. */
437 if (!(py_use_system_env && BLI_getenv("PYTHONWARNINGS"))) {
438 /* Confusingly `default` is not the default.
439 * Setting to `default` without any module names shows warnings for all modules.
440 * Useful for development since most functionality occurs outside of `__main__`. */
441 PyWideStringList_Append(&config.warnoptions, L"default");
442 }
443 }
444 }
445
446 /* Allow the user site directory because this is used
447 * when PIP installing packages from Blender, see: #104000.
448 *
449 * NOTE(@ideasman42): While an argument can be made for isolating Blender's Python
450 * from the users home directory entirely, an alternative directory should be used in that
451 * case - so PIP can be used to install packages. Otherwise PIP will install packages to a
452 * directory which us not in the users `sys.path`, see `site.USER_BASE` for details. */
453 // config.user_site_directory = py_use_system_env;
454
455 /* While `sys.argv` is set, we don't want Python to interpret it. */
456 config.parse_argv = 0;
457 status = PyConfig_SetBytesArgv(&config, argc, (char *const *)argv);
459
460 /* Needed for Python's initialization for portable Python installations.
461 * We could use #Py_SetPath, but this overrides Python's internal logic
462 * for calculating its own module search paths.
463 *
464 * `sys.executable` is overwritten after initialization to the Python binary. */
465 {
466 const char *program_path = BKE_appdir_program_path();
467 status = PyConfig_SetBytesString(&config, &config.program_name, program_path);
469 }
470
471 /* Setting the program name is important so the 'multiprocessing' module
472 * can launch new Python instances. */
473 {
474 char program_path[FILE_MAX];
476 program_path, sizeof(program_path), PY_MAJOR_VERSION, PY_MINOR_VERSION))
477 {
478 status = PyConfig_SetBytesString(&config, &config.executable, program_path);
480 has_python_executable = true;
481 }
482 else {
483 /* Set to `sys.executable = None` below (we can't do before Python is initialized). */
484 fprintf(stderr,
485 "Unable to find the Python binary, "
486 "the multiprocessing module may not be functional!\n");
487 }
488 }
489
490 /* Allow to use our own included Python. `py_path_bundle` may be nullptr. */
491 {
492 const std::optional<std::string> py_path_bundle = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON,
493 nullptr);
494 if (py_path_bundle.has_value()) {
495
496# ifdef __APPLE__
497 /* Mac-OS allows file/directory names to contain `:` character
498 * (represented as `/` in the Finder) but current Python lib (as of release 3.1.1)
499 * doesn't handle these correctly. */
500 if (strchr(py_path_bundle->c_str(), ':')) {
501 fprintf(stderr,
502 "Warning! Blender application is located in a path containing ':' or '/' chars\n"
503 "This may make Python import function fail\n");
504 }
505# endif /* __APPLE__ */
506
507 status = PyConfig_SetBytesString(&config, &config.home, py_path_bundle->c_str());
509
510# ifdef PYTHON_SSL_CERT_FILE
511 /* Point to the portable SSL certificate to support HTTPS access, see: #102300. */
512 const char *ssl_cert_file_env = "SSL_CERT_FILE";
513 if (BLI_getenv(ssl_cert_file_env) == nullptr) {
514 const char *ssl_cert_file_suffix = PYTHON_SSL_CERT_FILE;
515 char ssl_cert_file[FILE_MAX];
517 ssl_cert_file, sizeof(ssl_cert_file), py_path_bundle->c_str(), ssl_cert_file_suffix);
518 BLI_setenv(ssl_cert_file_env, ssl_cert_file);
519 }
520# endif /* PYTHON_SSL_CERT_FILE */
521 }
522 else {
523/* Common enough to use the system Python on Linux/Unix, warn on other systems. */
524# if defined(__APPLE__) || defined(_WIN32)
525 fprintf(stderr,
526 "Bundled Python not found and is expected on this platform "
527 "(the 'install' target may have not been built)\n");
528# endif
529 }
530 }
531
532 /* Initialize Python (also acquires lock). */
533 status = Py_InitializeFromConfig(&config);
534 PyConfig_Clear(&config);
535
537
538 if (!has_python_executable) {
539 PySys_SetObject("executable", Py_None);
540 }
541 }
542
543# ifdef WITH_FLUID
544 /* Required to prevent assertion error, see:
545 * https://stackoverflow.com/questions/27844676 */
546 Py_DECREF(PyImport_ImportModule("threading"));
547# endif
548
549#else /* WITH_PYTHON_MODULE */
550 (void)argc;
551 (void)argv;
552
553 /* NOTE(ideasman42): unfortunately the `inittab` can only be used
554 * before Python has been initialized.
555 * When built as a Python module, Python will have been initialized
556 * and using the `inittab` isn't supported.
557 * So it's necessary to load all modules as soon as `bpy` is imported. */
558 // PyImport_ExtendInittab(bpy_internal_modules);
559
560#endif /* WITH_PYTHON_MODULE */
561
563
564#ifdef WITH_PYTHON_MODULE
565 {
566 /* Manually load all modules */
567 struct _inittab *inittab_item;
568 PyObject *sys_modules = PyImport_GetModuleDict();
569
570 for (inittab_item = bpy_internal_modules; inittab_item->name; inittab_item++) {
571 PyObject *mod = inittab_item->initfunc();
572 if (mod) {
573 PyDict_SetItemString(sys_modules, inittab_item->name, mod);
574 }
575 else {
576 PyErr_Print();
577 }
578 // Py_DECREF(mod); /* Ideally would decref, but in this case we never want to free. */
579 }
580 }
581#endif
582
583 /* Run first, initializes RNA types. */
584 BPY_rna_init();
585
586 /* Defines `bpy.*` and lets us import it. */
588
590
591#ifndef WITH_PYTHON_MODULE
592 /* Python module runs `atexit` when `bpy` is freed. */
593 BPY_atexit_register(); /* This can initialize any time. */
594
595 /* Free the lock acquired (implicitly) when Python is initialized. */
596 PyEval_ReleaseThread(PyGILState_GetThisThreadState());
597
598#endif
599
600#ifdef WITH_PYTHON_MODULE
601 /* Disable all add-ons at exit, not essential, it just avoids resource leaks, see #71362. */
602 const char *imports[] = {"atexit", "addon_utils", nullptr};
603 BPY_run_string_eval(C, imports, "atexit.register(addon_utils.disable_all)");
604#endif
605}
606
607void BPY_python_end(const bool do_python_exit)
608{
609#ifndef WITH_PYTHON_MODULE
610 BLI_assert_msg(Py_IsInitialized() != 0, "Python must be initialized");
611#endif
612
613 /* Finalizing, no need to grab the state, except when we are a module. */
614 PyGILState_STATE gilstate = PyGILState_Ensure();
615
616 /* Frees the Python-driver name-space & cached data. */
618
619 /* Clear Python values in the context so freeing the context after Python exits doesn't crash. */
621
622 /* Decrement user counts of all callback functions. */
624
625 /* Free other Python data. */
626 RNA_bpy_exit();
627
628 BPY_rna_exit();
629
630 /* Clear all Python data from structs. */
631
633
634 /* `bpy.app` modules that need cleanup. */
636
637#ifndef WITH_PYTHON_MODULE
638 /* Without this we get recursive calls to #WM_exit_ex. */
640
641 if (do_python_exit) {
642 Py_Finalize();
643 }
644 (void)gilstate;
645#else
646 PyGILState_Release(gilstate);
647 (void)do_python_exit;
648#endif
649
650#ifdef TIME_PY_RUN
651 /* Measure time since Python started. */
652 bpy_timer = BLI_time_now_seconds() - bpy_timer;
653
654 printf("*bpy stats* - ");
655 printf("tot exec: %d, ", bpy_timer_count);
656 printf("tot run: %.4fsec, ", bpy_timer_run_tot);
657 if (bpy_timer_count > 0) {
658 printf("average run: %.6fsec, ", (bpy_timer_run_tot / bpy_timer_count));
659 }
660
661 if (bpy_timer > 0.0) {
662 printf("tot usage %.4f%%", (bpy_timer_run_tot / bpy_timer) * 100.0);
663 }
664
665 printf("\n");
666#endif
667}
668
670{
671 BLI_assert_msg(Py_IsInitialized() != 0, "Python must be initialized");
672
673 /* Unrelated security stuff. */
675 G.autoexec_fail[0] = '\0';
676
680}
681
683{
684 BLI_assert(!Py_IsInitialized());
685 py_use_system_env = true;
686}
687
692
694{
695 fputs("\n# Python backtrace\n", fp);
696
697 /* Can happen in rare cases. */
699 return;
700 }
701 PyFrameObject *frame = PyEval_GetFrame();
702 if (frame == nullptr) {
703 return;
704 }
705 do {
706 PyCodeObject *code = PyFrame_GetCode(frame);
707 const int line = PyFrame_GetLineNumber(frame);
708 const char *filepath = PyUnicode_AsUTF8(code->co_filename);
709 const char *funcname = PyUnicode_AsUTF8(code->co_name);
710 fprintf(fp, " File \"%s\", line %d in %s\n", filepath, line, funcname);
711 } while ((frame = PyFrame_GetBack(frame)));
712}
713
714void BPY_DECREF(void *pyob_ptr)
715{
716 const PyGILState_STATE gilstate = PyGILState_Ensure();
717 Py_DECREF((PyObject *)pyob_ptr);
718 PyGILState_Release(gilstate);
719}
720
721void BPY_DECREF_RNA_INVALIDATE(void *pyob_ptr)
722{
723 const PyGILState_STATE gilstate = PyGILState_Ensure();
724 const bool do_invalidate = (Py_REFCNT((PyObject *)pyob_ptr) > 1);
725 Py_DECREF((PyObject *)pyob_ptr);
726 if (do_invalidate) {
727 pyrna_invalidate(static_cast<BPy_DummyPointerRNA *>(pyob_ptr));
728 }
729 PyGILState_Release(gilstate);
730}
731
733{
734 PyGILState_STATE gilstate;
735 Main *bmain = CTX_data_main(C);
736 Text *text;
737
738 /* Can happen on file load. */
739 if (bmain == nullptr) {
740 return;
741 }
742
743 /* Update pointers since this can run from a nested script on file load. */
744 if (py_call_level) {
746 }
747
748 bpy_context_set(C, &gilstate);
749
750 for (text = static_cast<Text *>(bmain->texts.first); text;
751 text = static_cast<Text *>(text->id.next))
752 {
753 if (text->flags & TXT_ISSCRIPT) {
754 if (!(G.f & G_FLAG_SCRIPT_AUTOEXEC)) {
757 SNPRINTF_UTF8(G.autoexec_fail, RPT_("Text '%s'"), text->id.name + 2);
758
759 printf("scripts disabled for \"%s\", skipping '%s'\n",
761 text->id.name + 2);
762 }
763 }
764 else {
765 BPY_run_text(C, text, nullptr, false);
766
767 /* Check if the script loaded a new file. */
768 if (bmain != CTX_data_main(C)) {
769 break;
770 }
771 }
772 }
773 }
774 bpy_context_clear(C, &gilstate);
775}
776
778static void bpy_context_log_member_error(const bContext *C, const char *message)
779{
780 const bool use_logging_info = CLOG_CHECK(BKE_LOG_CONTEXT, CLG_LEVEL_INFO);
781 const bool use_logging_member = C && CTX_member_logging_get(C);
782 if (!(use_logging_info || use_logging_member)) {
783 return;
784 }
785
786 std::optional<std::string> python_location = BPY_python_current_file_and_line();
787 const char *location = python_location ? python_location->c_str() : "unknown:0";
788
789 if (use_logging_info) {
790 CLOG_INFO(BKE_LOG_CONTEXT, "%s: %s", location, message);
791 }
792 else if (use_logging_member) {
793 CLOG_AT_LEVEL_NOCHECK(BKE_LOG_CONTEXT, CLG_LEVEL_INFO, "%s: %s", location, message);
794 }
795 else {
797 }
798}
799
801{
802 PyGILState_STATE gilstate;
803 const bool use_gil = !PyC_IsInterpreterActive();
804 if (use_gil) {
805 gilstate = PyGILState_Ensure();
806 }
807
808 PyObject *pyctx;
809 PyObject *item;
810 PointerRNA *ptr = nullptr;
811 bool done = false;
812
813 pyctx = (PyObject *)CTX_py_dict_get(C);
814 item = PyDict_GetItemString(pyctx, member);
815
816 if (item == nullptr) {
817 /* Pass. */
818 }
819 else if (item == Py_None) {
820 done = true;
821 }
822 else if (BPy_StructRNA_Check(item)) {
823 ptr = &reinterpret_cast<BPy_StructRNA *>(item)->ptr.value();
824
825 // result->ptr = ((BPy_StructRNA *)item)->ptr;
828 done = true;
829 }
830 else if (PySequence_Check(item)) {
831 PyObject *seq_fast = PySequence_Fast(item, "bpy_context_get sequence conversion");
832 if (seq_fast == nullptr) {
833 PyErr_Print();
834 }
835 else {
836 const int len = PySequence_Fast_GET_SIZE(seq_fast);
837 PyObject **seq_fast_items = PySequence_Fast_ITEMS(seq_fast);
838 int i;
839
840 for (i = 0; i < len; i++) {
841 PyObject *list_item = seq_fast_items[i];
842
843 if (BPy_StructRNA_Check(list_item)) {
844 ptr = &reinterpret_cast<BPy_StructRNA *>(list_item)->ptr.value();
846 }
847 else {
848 /* Log invalid list item type */
849 std::string message = std::string("'") + member +
850 "' list item not a valid type in sequence type '" +
851 Py_TYPE(list_item)->tp_name + "'";
852 bpy_context_log_member_error(C, message.c_str());
853 }
854 }
855 Py_DECREF(seq_fast);
857 done = true;
858 }
859 }
860
861 if (done == false) {
862 if (item) {
863 /* Log invalid member type */
864 std::string message = std::string("'") + member + "' not a valid type";
865 bpy_context_log_member_error(C, message.c_str());
866 }
867 }
868
869 if (use_gil) {
870 PyGILState_Release(gilstate);
871 }
872
873 return done;
874}
875
876std::optional<std::string> BPY_python_current_file_and_line()
877{
878 /* Early return if Python is not initialized, usually during startup.
879 * This function shouldn't operate if Python isn't initialized yet.
880 *
881 * In most cases this shouldn't be done, make an exception as it's needed for logging. */
882 if (!Py_IsInitialized()) {
883 return std::nullopt;
884 }
885
886 PyGILState_STATE gilstate;
887 const bool use_gil = !PyC_IsInterpreterActive();
888 std::optional<std::string> result = std::nullopt;
889 if (use_gil) {
890 gilstate = PyGILState_Ensure();
891 }
892
893 const char *filename = nullptr;
894 int lineno = -1;
895 PyC_FileAndNum_Safe(&filename, &lineno);
896
897 if (filename) {
898 result = std::string(filename) + ":" + std::to_string(lineno);
899 }
900
901 if (use_gil) {
902 PyGILState_Release(gilstate);
903 }
904 return result;
905}
906
907#ifdef WITH_PYTHON_MODULE
908
909/* -------------------------------------------------------------------- */
921
922static void main_python_exit_ensure();
923
924static void bpy_detect_exit_singleton_cleanup(PyObject * /*capsule*/)
925{
926 main_python_exit_ensure();
927}
928
929static void bpy_detect_exit_singleton_add_to_module(PyObject *mod)
930{
931 static PyObject *singleton = nullptr;
932
933 /* Note that Python's API docs state that:
934 * - If this capsule will be stored as an attribute of a module,
935 * the name should be specified as `modulename.attributename`.
936 * This is ignored here because the capsule is not intended for script author access.
937 * It also wouldn't make sense as it is stored in multiple modules. */
938 const char *bpy_detect_exit_singleton_id = "_bpy_detect_exit_singleton";
939 if (singleton == nullptr) {
940 /* This is ignored, but must be non-null,
941 * set an address that is non-null and easily identifiable. */
942 void *pointer = reinterpret_cast<void *>(uintptr_t(-1));
943 singleton = PyCapsule_New(
944 pointer, bpy_detect_exit_singleton_id, bpy_detect_exit_singleton_cleanup);
945 BLI_assert(singleton);
946 }
947 else {
948 Py_INCREF(singleton);
949 }
950 PyModule_AddObject(mod, bpy_detect_exit_singleton_id, singleton);
951}
952
954
955/* TODO: reloading the module isn't functional at the moment. */
956
957static void bpy_module_free(void *mod);
958
959/* Defined in 'creator.c' when building as a Python module. */
960extern int main_python_enter(int argc, const char **argv);
961extern void main_python_exit();
962
963static void main_python_exit_ensure()
964{
965 static bool exit = false;
966 if (exit) {
967 return;
968 }
969 exit = true;
970 main_python_exit();
971}
972
973static struct PyModuleDef bpy_proxy_def = {
974 /*m_base*/ PyModuleDef_HEAD_INIT,
975 /*m_name*/ "bpy",
976 /*m_doc*/ nullptr,
977 /*m_size*/ 0,
978 /*m_methods*/ nullptr,
979 /*m_slots*/ nullptr,
980 /*m_traverse*/ nullptr,
981 /*m_clear*/ nullptr,
982 /*m_free*/ bpy_module_free,
983};
984
985struct dealloc_obj {
986 PyObject_HEAD
987 /* Type-specific fields go here. */
988 PyObject *mod;
989};
990
991/* Call once `__file__` is set. */
992static void bpy_module_delay_init(PyObject *bpy_proxy)
993{
994 const int argc = 1;
995 const char *argv[2];
996
997 /* Updating the module dict below will lose the reference to `__file__`. */
998 PyObject *filepath_obj = PyModule_GetFilenameObject(bpy_proxy);
999
1000 /* The file can be a relative path. */
1001 const char *filepath_rel = PyUnicode_AsUTF8(filepath_obj);
1002 char filepath_abs[1024];
1003
1004 STRNCPY(filepath_abs, filepath_rel);
1005 BLI_path_abs_from_cwd(filepath_abs, sizeof(filepath_abs));
1006 Py_DECREF(filepath_obj);
1007
1008 argv[0] = filepath_abs;
1009 argv[1] = nullptr;
1010
1011 main_python_enter(argc, argv);
1012
1013 /* Initialized in #BPy_init_modules(). */
1014 PyDict_Update(PyModule_GetDict(bpy_proxy), PyModule_GetDict(bpy_package_py));
1015
1016 {
1017 /* Modules which themselves require access to Blender
1018 * allocated resources to be freed should be included in this list.
1019 * Once the last module has been cleared, the singleton will be de-allocated
1020 * which calls #main_python_exit.
1021 *
1022 * Note that, other modules can be here as needed. */
1023 const char *bpy_modules_array[] = {
1024 "bpy.types",
1025 /* Not technically required however as this is created early on
1026 * in Blender's module initialization, it's likely to be cleared later,
1027 * since module cleanup runs in the reverse of the order added to `sys.modules`. */
1028 "_bpy",
1029 };
1030 PyObject *sys_modules = PyImport_GetModuleDict();
1031 for (int i = 0; i < ARRAY_SIZE(bpy_modules_array); i++) {
1032 PyObject *mod = PyDict_GetItemString(sys_modules, bpy_modules_array[i]);
1033 BLI_assert(mod);
1034 bpy_detect_exit_singleton_add_to_module(mod);
1035 }
1036 }
1037}
1038
1043static bool bpy_module_ensure_compatible_version()
1044{
1045 /* First check the Python version used matches the major version that Blender was built with.
1046 * While this isn't essential, the error message in this case may be cryptic and misleading.
1047 * NOTE: using `Py_LIMITED_API` would remove the need for this, in practice it's
1048 * unlikely Blender will ever used the limited API though. */
1049 const uint version_runtime = Py_Version;
1050
1051 uint version_compile_major = PY_VERSION_HEX >> 24;
1052 uint version_compile_minor = ((PY_VERSION_HEX & 0x00ff0000) >> 16);
1053 uint version_runtime_major = version_runtime >> 24;
1054 uint version_runtime_minor = ((version_runtime & 0x00ff0000) >> 16);
1055 if ((version_compile_major != version_runtime_major) ||
1056 (version_compile_minor != version_runtime_minor))
1057 {
1058 PyErr_Format(PyExc_ImportError,
1059 "The version of \"bpy\" was compiled with: "
1060 "(%u.%u) is incompatible with: (%u.%u) used by the interpreter!",
1061 version_compile_major,
1062 version_compile_minor,
1063 version_runtime_major,
1064 version_runtime_minor);
1065 return false;
1066 }
1067 return true;
1068}
1069
1070static void dealloc_obj_dealloc(PyObject *self);
1071
1072static PyTypeObject dealloc_obj_Type;
1073
1074/* Use our own `dealloc` so we can free a property if we use one. */
1075static void dealloc_obj_dealloc(PyObject *self)
1076{
1077 bpy_module_delay_init(((dealloc_obj *)self)->mod);
1078
1079 /* NOTE: for sub-classed `PyObject` objects
1080 * we can't call #PyObject_DEL() directly or it will crash. */
1081 dealloc_obj_Type.tp_free(self);
1082}
1083
1084PyMODINIT_FUNC PyInit_bpy();
1085
1086PyMODINIT_FUNC PyInit_bpy()
1087{
1088 if (!bpy_module_ensure_compatible_version()) {
1089 return nullptr; /* The error has been set. */
1090 }
1091
1092 PyObject *bpy_proxy = PyModule_Create(&bpy_proxy_def);
1093
1094 /* Problem:
1095 * 1) This initializing function is expected to have a private member defined - `md_def`
1096 * but this is only set for CAPI defined modules (not Python packages)
1097 * so we can't return `bpy_package_py` as is.
1098 *
1099 * 2) There is a `bpy` CAPI module for python to load which is basically all of blender,
1100 * and there is `scripts/bpy/__init__.py`,
1101 * we may end up having to rename this module so there is no naming conflict here eg:
1102 * `from blender import bpy`
1103 *
1104 * 3) We don't know the file-path at this point, workaround by assigning a dummy value
1105 * which calls back when its freed so the real loading can take place.
1106 */
1107
1108 /* Assign an object which is freed after `__file__` is assigned. */
1109 dealloc_obj *dob;
1110
1111 /* Assign dummy type. */
1112 dealloc_obj_Type.tp_name = "dealloc_obj";
1113 dealloc_obj_Type.tp_basicsize = sizeof(dealloc_obj);
1114 dealloc_obj_Type.tp_dealloc = dealloc_obj_dealloc;
1115 dealloc_obj_Type.tp_flags = Py_TPFLAGS_DEFAULT;
1116
1117 if (PyType_Ready(&dealloc_obj_Type) < 0) {
1118 return nullptr;
1119 }
1120
1121 dob = (dealloc_obj *)dealloc_obj_Type.tp_alloc(&dealloc_obj_Type, 0);
1122 dob->mod = bpy_proxy; /* borrow */
1123 PyModule_AddObject(bpy_proxy, "__file__", (PyObject *)dob); /* borrow */
1124
1125 return bpy_proxy;
1126}
1127
1128static void bpy_module_free(void * /*mod*/)
1129{
1130 main_python_exit_ensure();
1131}
1132
1133#endif
1134
1136{
1137 /* List is from: `", ".join(['"%s"' % kw for kw in __import__("keyword").kwlist])`. */
1138 const char *kwlist[] = {
1139 "False", "None", "True", "and", "as", "assert", "async", "await", "break",
1140 "class", "continue", "def", "del", "elif", "else", "except", "finally", "for",
1141 "from", "global", "if", "import", "in", "is", "lambda", "nonlocal", "not",
1142 "or", "pass", "raise", "return", "try", "while", "with", "yield", nullptr,
1143 };
1144
1145 for (int i = 0; kwlist[i]; i++) {
1146 if (STREQ(str, kwlist[i])) {
1147 return true;
1148 }
1149 }
1150
1151 return false;
1152}
1153
1154/* -------------------------------------------------------------------- */
1160
1162{
1163 return (ch < 255 && text_check_identifier(char(ch))) || Py_UNICODE_ISALNUM(ch);
1164}
1165
1167{
1168 return (ch < 255 && text_check_identifier_nodigit(char(ch))) || Py_UNICODE_ISALPHA(ch);
1169}
1170
PyObject * AUD_initPython(void)
const char * BKE_appdir_program_path() ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
Definition appdir.cc:956
bool BKE_appdir_program_python_search(char *program_filepath, size_t program_filepath_maxncpy, int version_major, int version_minor) ATTR_NONNULL(1)
Definition appdir.cc:970
std::optional< std::string > BKE_appdir_folder_id(int folder_id, const char *subfolder) ATTR_WARN_UNUSED_RESULT
Definition appdir.cc:721
@ BLENDER_SYSTEM_PYTHON
void CTX_data_type_set(bContextDataResult *result, ContextDataType type)
void CTX_wm_operator_poll_msg_clear(bContext *C)
Main * CTX_data_main(const bContext *C)
void CTX_data_list_add_ptr(bContextDataResult *result, const PointerRNA *ptr)
void CTX_data_pointer_set_ptr(bContextDataResult *result, const PointerRNA *ptr)
bool CTX_member_logging_get(const bContext *C)
void * CTX_py_dict_get(const bContext *C)
@ G_FLAG_SCRIPT_AUTOEXEC_FAIL_QUIET
@ G_FLAG_SCRIPT_AUTOEXEC_FAIL
@ G_FLAG_SCRIPT_AUTOEXEC
@ G_DEBUG_PYTHON
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:887
bool text_check_identifier_nodigit(char ch)
Definition text.cc:2340
bool text_check_identifier(char ch)
Definition text.cc:2317
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define FILE_MAX
void BLI_setenv(const char *env, const char *val) ATTR_NONNULL(1)
#define BLI_path_join(...)
const char * BLI_getenv(const char *env) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
bool BLI_path_abs_from_cwd(char *path, size_t path_maxncpy) ATTR_NONNULL(1)
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
#define SNPRINTF_UTF8(dst, format,...)
unsigned int uint
int BLI_thread_is_main(void)
Definition threads.cc:179
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.cc:113
#define ARRAY_SIZE(arr)
#define UNLIKELY(x)
#define STREQ(a, b)
#define RPT_(msgid)
void BPY_driver_reset()
void BPY_driver_exit()
void BPY_app_handlers_reset(bool do_all)
struct CLG_LogRef * BPY_LOG_RNA
bool bool BPY_run_text(bContext *C, Text *text, ReportList *reports, bool do_jump) ATTR_NONNULL(1
bool BPY_run_string_eval(bContext *C, const char *imports[], const char *expr)
void * CCL_python_module_init(void)
Definition python.cpp:810
#define CLOG_DEBUG(clg_ref,...)
Definition CLG_log.h:191
#define CLOG_AT_LEVEL_NOCHECK(clg_ref, verbose_level,...)
Definition CLG_log.h:159
#define CLOG_CHECK(clg_ref, verbose_level,...)
Definition CLG_log.h:147
@ CLG_LEVEL_INFO
Definition CLG_log.h:60
#define CLG_LOGREF_DECLARE_GLOBAL(var, id)
Definition CLG_log.h:139
#define CLOG_INFO(clg_ref,...)
Definition CLG_log.h:190
@ TXT_ISSCRIPT
#define C
Definition RandGen.cpp:29
PyMODINIT_FUNC BPyInit_bl_math()
PyObject * BPyInit_blf()
PyObject * BPyInit_bmesh()
PyObject * BPyInit_bmesh_geometry()
PyObject * BPyInit_bmesh_types()
PyObject * BPyInit_bmesh_utils()
PyObject * bpy_package_py
Definition bpy.cc:64
void BPy_init_modules(bContext *C)
Definition bpy.cc:719
void BPY_atexit_unregister()
void BPY_atexit_register()
struct CLG_LogRef * BPY_LOG_INTERFACE
void BPY_app_translations_end()
PyObject * self
int text_check_identifier_nodigit_unicode(const uint ch)
bool BPY_string_is_keyword(const char *str)
void BPY_python_use_system_env()
void BPY_context_dict_clear_members_array(void **dict_p, void *dict_orig, const char *context_members[], uint context_members_len)
CLG_LogRef * BKE_LOG_CONTEXT
int text_check_identifier_unicode(const uint ch)
std::optional< std::string > BPY_python_current_file_and_line()
void BPY_modules_update()
bContext * BPY_context_get()
void bpy_context_set(bContext *C, PyGILState_STATE *gilstate)
void BPY_context_set(bContext *C)
static void pystatus_exit_on_error(const PyStatus &status)
void BPY_DECREF_RNA_INVALIDATE(void *pyob_ptr)
void BPY_python_backtrace(FILE *fp)
static int py_call_level
static void bpy_context_end(bContext *C)
void BPY_python_reset(bContext *C)
static bool py_use_system_env
void BPY_context_update(bContext *C)
void BPY_python_end(const bool do_python_exit)
static _inittab bpy_internal_modules[]
bool BPY_python_use_system_env_get()
bool BPY_context_member_get(bContext *C, const char *member, bContextDataResult *result)
void BPY_text_free_code(Text *text)
static void bpy_context_log_member_error(const bContext *C, const char *message)
void bpy_context_clear(bContext *, const PyGILState_STATE *gilstate)
void BPY_modules_load_user(bContext *C)
void BPY_python_start(bContext *C, int argc, const char **argv)
void BPY_DECREF(void *pyob_ptr)
void bpy_intern_string_exit()
void bpy_intern_string_init()
PyObject * BPyInit__bpy_path()
Definition bpy_path.cc:35
void BPY_rna_props_clear_all()
void pyrna_invalidate(BPy_DummyPointerRNA *self)
Definition bpy_rna.cc:178
PyObject * BPY_rna_module()
Definition bpy_rna.cc:8703
void BPY_rna_init()
Definition bpy_rna.cc:8627
void BPY_rna_exit()
Definition bpy_rna.cc:8680
PyObject * BPY_rna_types()
Definition bpy_rna.cc:8868
void pyrna_alloc_types()
Definition bpy_rna.cc:10052
void BPY_update_rna_module()
Definition bpy_rna.cc:8715
BPy_StructRNA * bpy_context_module
Definition bpy_rna.cc:96
#define BPy_StructRNA_Check(v)
Definition bpy_rna.hh:73
#define str(s)
PyObject * BPyInit_gpu()
Definition gpu_py_api.cc:48
#define printf(...)
VecBase< float, D > constexpr mod(VecOp< float, D >, VecOp< float, D >) RET
PyObject * BPyInit_idprop()
PyObject * BPyInit_imbuf()
PyObject * Manta_initPython(void)
PyMODINIT_FUNC PyInit_mathutils()
Definition mathutils.cc:816
PyMODINIT_FUNC PyInit_mathutils_geometry()
PyMODINIT_FUNC PyInit_mathutils_kdtree()
PyMODINIT_FUNC PyInit_mathutils_noise()
#define L
#define G(x, y, z)
bool PyC_IsInterpreterActive()
void PyC_FileAndNum_Safe(const char **r_filename, int *r_lineno)
PyObject * BPyInit_hydra()
Definition python.cc:209
header-only compatibility defines.
Py_DECREF(oname)
const int status
#define PyThreadState_GetUnchecked
void RNA_bpy_exit()
char name[258]
Definition DNA_ID.h:432
void * next
Definition DNA_ID.h:417
void * first
ListBase texts
Definition BKE_main.hh:294
int flags
void * compiled
i
Definition text_draw.cc:230
uint len
PointerRNA * ptr
Definition wm_files.cc:4238