Refactor: Clarify code around scheduling composite nodes
[blender.git] / source / blender / python / intern / bpy_interface.cc
blobbf155c484274d002c57d71fcafc8b0de219b5aba
1 /* SPDX-FileCopyrightText: 2023 Blender Authors
3 * SPDX-License-Identifier: GPL-2.0-or-later */
5 /** \file
6 * \ingroup pythonintern
8 * This file deals with embedding the python interpreter within blender,
9 * starting and stopping python and exposing blender/python modules so they can
10 * be accesses from scripts.
13 #include <Python.h>
14 #include <frameobject.h>
16 #ifdef WITH_PYTHON_MODULE
17 # include "pylifecycle.h" /* For `Py_Version`. */
18 #endif
20 #include "CLG_log.h"
22 #include "BLI_path_utils.hh"
23 #include "BLI_string.h"
24 #include "BLI_threads.h"
25 #include "BLI_utildefines.h"
27 #include "BLT_translation.hh"
29 #include "RNA_types.hh"
31 #include "bpy.hh"
32 #include "bpy_capi_utils.hh"
33 #include "bpy_intern_string.hh"
34 #include "bpy_path.hh"
35 #include "bpy_props.hh"
36 #include "bpy_rna.hh"
38 #include "bpy_app_translations.hh"
40 #include "DNA_text_types.h"
42 #include "BKE_appdir.hh"
43 #include "BKE_context.hh"
44 #include "BKE_global.hh" /* Only for script checking. */
45 #include "BKE_main.hh"
46 #include "BKE_text.h"
48 #ifdef WITH_CYCLES
49 # include "CCL_api.h"
50 #endif
52 #include "BPY_extern.hh"
53 #include "BPY_extern_python.hh"
54 #include "BPY_extern_run.hh"
56 #include "../generic/py_capi_utils.hh"
58 /* `inittab` initialization functions. */
59 #include "../bmesh/bmesh_py_api.hh"
60 #include "../generic/bgl.hh"
61 #include "../generic/bl_math_py_api.hh"
62 #include "../generic/blf_py_api.hh"
63 #include "../generic/idprop_py_api.hh"
64 #include "../generic/imbuf_py_api.hh"
65 #include "../gpu/gpu_py_api.hh"
66 #include "../mathutils/mathutils.hh"
68 /* Logging types to use anywhere in the Python modules. */
70 CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_CONTEXT, "bpy.context");
71 CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_INTERFACE, "bpy.interface");
72 CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_RNA, "bpy.rna");
74 /* For internal use, when starting and ending Python scripts. */
76 /* In case a Python script triggers another Python call,
77 * stop #bpy_context_clear from invalidating. */
78 static int py_call_level = 0;
80 /* Set by command line arguments before Python starts. */
81 static bool py_use_system_env = false;
83 // #define TIME_PY_RUN /* Simple python tests. prints on exit. */
85 #ifdef TIME_PY_RUN
86 # include "BLI_time.h"
87 static int bpy_timer_count = 0;
88 /** Time since python starts. */
89 static double bpy_timer;
90 /** Time for each Python script run. */
91 static double bpy_timer_run;
92 /** Accumulate Python runs. */
93 static double bpy_timer_run_tot;
94 #endif
96 void BPY_context_update(bContext *C)
98 /* Don't do this from a non-main (e.g. render) thread, it can cause a race
99 * condition on `C->data.recursion`. Ideal solution would be to disable
100 * context entirely from non-main threads, but that's more complicated. */
101 if (!BLI_thread_is_main()) {
102 return;
105 BPY_context_set(C);
107 /* Can give really bad results if this isn't here. */
108 BPY_modules_update();
111 void bpy_context_set(bContext *C, PyGILState_STATE *gilstate)
113 py_call_level++;
115 if (gilstate) {
116 *gilstate = PyGILState_Ensure();
119 if (py_call_level == 1) {
120 BPY_context_update(C);
122 #ifdef TIME_PY_RUN
123 if (bpy_timer_count == 0) {
124 /* Record time from the beginning. */
125 bpy_timer = BLI_time_now_seconds();
126 bpy_timer_run = bpy_timer_run_tot = 0.0;
128 bpy_timer_run = BLI_time_now_seconds();
130 bpy_timer_count++;
131 #endif
135 void bpy_context_clear(bContext * /*C*/, const PyGILState_STATE *gilstate)
137 py_call_level--;
139 if (gilstate) {
140 PyGILState_Release(*gilstate);
143 if (py_call_level < 0) {
144 fprintf(stderr, "ERROR: Python context internal state bug. this should not happen!\n");
146 else if (py_call_level == 0) {
147 /* NOTE: Unfortunately calling classes currently won't store the context.
148 * Can't set nullptr because of this - but this is very flaky still. */
149 #if 0
150 BPY_context_set(nullptr);
151 #endif
153 #ifdef TIME_PY_RUN
154 bpy_timer_run_tot += BLI_time_now_seconds() - bpy_timer_run;
155 bpy_timer_count++;
156 #endif
160 static void bpy_context_end(bContext *C)
162 if (UNLIKELY(C == nullptr)) {
163 return;
165 CTX_wm_operator_poll_msg_clear(C);
168 void BPY_context_dict_clear_members_array(void **dict_p,
169 void *dict_orig,
170 const char *context_members[],
171 uint context_members_len)
173 PyGILState_STATE gilstate;
174 const bool use_gil = !PyC_IsInterpreterActive();
176 if (use_gil) {
177 gilstate = PyGILState_Ensure();
180 /* Copy on write. */
181 if (*dict_p == dict_orig) {
182 *dict_p = PyDict_Copy(static_cast<PyObject *>(dict_orig));
185 PyObject *dict = static_cast<PyObject *>(*dict_p);
186 BLI_assert(PyDict_Check(dict));
188 /* Use #PyDict_Pop instead of #PyDict_DelItemString to avoid setting the exception,
189 * while supported it's good to avoid for low level functions like this that run often. */
190 for (uint i = 0; i < context_members_len; i++) {
191 PyObject *key = PyUnicode_FromString(context_members[i]);
192 PyObject *item = _PyDict_Pop(dict, key, Py_None);
193 Py_DECREF(key);
194 Py_DECREF(item);
197 if (use_gil) {
198 PyGILState_Release(gilstate);
202 void BPY_text_free_code(Text *text)
204 if (text->compiled) {
205 PyGILState_STATE gilstate;
206 const bool use_gil = !PyC_IsInterpreterActive();
208 if (use_gil) {
209 gilstate = PyGILState_Ensure();
212 Py_DECREF((PyObject *)text->compiled);
213 text->compiled = nullptr;
215 if (use_gil) {
216 PyGILState_Release(gilstate);
221 void BPY_modules_update()
223 /* Correct but slow, this runs all the time operator poll, panel draw etc
224 * (100's of time a second). */
225 #if 0
226 PyObject *mod = PyImport_ImportModuleLevel("bpy", nullptr, nullptr, nullptr, 0);
227 PyModule_AddObject(mod, "data", BPY_rna_module());
228 PyModule_AddObject(mod, "types", BPY_rna_types()); /* This does not need updating. */
229 #endif
231 /* Refreshes the main struct. */
232 BPY_update_rna_module();
235 bContext *BPY_context_get()
237 return static_cast<bContext *>(bpy_context_module->ptr->data);
240 void BPY_context_set(bContext *C)
242 bpy_context_module->ptr->data = (void *)C;
245 #ifdef WITH_FLUID
246 /* Defined in `manta` module. */
247 extern "C" PyObject *Manta_initPython();
248 #endif
250 #ifdef WITH_AUDASPACE_PY
251 /* Defined in `AUD_C-API.cpp`. */
252 extern "C" PyObject *AUD_initPython();
253 #endif
255 #ifdef WITH_CYCLES
256 /* Defined in `cycles` module. */
257 static PyObject *CCL_initPython()
259 return (PyObject *)CCL_python_module_init();
261 #endif
263 #ifdef WITH_HYDRA
264 /* Defined in `render_hydra` module. */
265 PyObject *BPyInit_hydra();
266 #endif
268 static _inittab bpy_internal_modules[] = {
269 {"mathutils", PyInit_mathutils},
270 #if 0
271 {"mathutils.geometry", PyInit_mathutils_geometry},
272 {"mathutils.noise", PyInit_mathutils_noise},
273 {"mathutils.kdtree", PyInit_mathutils_kdtree},
274 #endif
275 {"_bpy_path", BPyInit__bpy_path},
276 {"bgl", BPyInit_bgl},
277 {"blf", BPyInit_blf},
278 {"bl_math", BPyInit_bl_math},
279 {"imbuf", BPyInit_imbuf},
280 {"bmesh", BPyInit_bmesh},
281 #if 0
282 {"bmesh.types", BPyInit_bmesh_types},
283 {"bmesh.utils", BPyInit_bmesh_utils},
284 {"bmesh.utils", BPyInit_bmesh_geometry},
285 #endif
286 #ifdef WITH_FLUID
287 {"manta", Manta_initPython},
288 #endif
289 #ifdef WITH_AUDASPACE_PY
290 {"aud", AUD_initPython},
291 #endif
292 #ifdef WITH_CYCLES
293 {"_cycles", CCL_initPython},
294 #endif
295 {"gpu", BPyInit_gpu},
296 {"idprop", BPyInit_idprop},
297 #ifdef WITH_HYDRA
298 {"_bpy_hydra", BPyInit_hydra},
299 #endif
300 {nullptr, nullptr},
303 #ifndef WITH_PYTHON_MODULE
305 * Convenience function for #BPY_python_start.
307 * These should happen so rarely that having comprehensive errors isn't needed.
308 * For example if `sys.argv` fails to allocate memory.
310 * Show an error just to avoid silent failure in the unlikely event something goes wrong,
311 * in this case a developer will need to track down the root cause.
313 static void pystatus_exit_on_error(const PyStatus &status)
315 if (UNLIKELY(PyStatus_Exception(status))) {
316 fputs("Internal error initializing Python!\n", stderr);
317 /* This calls `exit`. */
318 Py_ExitStatusException(status);
321 #endif
323 void BPY_python_start(bContext *C, int argc, const char **argv)
325 #ifndef WITH_PYTHON_MODULE
326 BLI_assert_msg(Py_IsInitialized() == 0, "Python has already been initialized");
328 /* #PyPreConfig (early-configuration). */
330 PyPreConfig preconfig;
331 PyStatus status;
333 /* To narrow down reports where the systems Python is inexplicably used, see: #98131. */
334 CLOG_INFO(
335 BPY_LOG_INTERFACE,
337 "Initializing %s support for the systems Python environment such as 'PYTHONPATH' and "
338 "the user-site directory.",
339 py_use_system_env ? "*with*" : "*without*");
341 if (py_use_system_env) {
342 PyPreConfig_InitPythonConfig(&preconfig);
344 else {
345 /* Only use the systems environment variables and site when explicitly requested.
346 * Since an incorrect 'PYTHONPATH' causes difficult to debug errors, see: #72807.
347 * An alternative to setting `preconfig.use_environment = 0` */
348 PyPreConfig_InitIsolatedConfig(&preconfig);
351 /* Force `utf-8` on all platforms, since this is what's used for Blender's internal strings,
352 * providing consistent encoding behavior across all Blender installations.
354 * This also uses the `surrogateescape` error handler ensures any unexpected bytes are escaped
355 * instead of raising an error.
357 * Without this `sys.getfilesystemencoding()` and `sys.stdout` for example may be set to ASCII
358 * or some other encoding - where printing some `utf-8` values will raise an error.
360 * This can cause scripts to fail entirely on some systems.
362 * This assignment is the equivalent of enabling the `PYTHONUTF8` environment variable.
363 * See `PEP-540` for details on exactly what this changes. */
364 preconfig.utf8_mode = true;
366 /* Note that there is no reason to call #Py_PreInitializeFromBytesArgs here
367 * as this is only used so that command line arguments can be handled by Python itself,
368 * not for setting `sys.argv` (handled below). */
369 status = Py_PreInitialize(&preconfig);
370 pystatus_exit_on_error(status);
373 /* Must run before python initializes, but after #PyPreConfig. */
374 PyImport_ExtendInittab(bpy_internal_modules);
376 /* #PyConfig (initialize Python). */
378 PyConfig config;
379 PyStatus status;
380 bool has_python_executable = false;
382 if (py_use_system_env) {
383 PyConfig_InitPythonConfig(&config);
385 BLI_assert(config.install_signal_handlers);
387 else {
388 PyConfig_InitIsolatedConfig(&config);
389 /* Python's isolated config disables it's own signal overrides.
390 * While it makes sense not to interfering with other components of the process,
391 * the signal handlers are needed for Python's own error handling to work properly.
392 * Without this a `SIGPIPE` signal will crash Blender, see: #129657. */
393 config.install_signal_handlers = 1;
396 /* Suppress error messages when calculating the module search path.
397 * While harmless, it's noisy. */
398 config.pathconfig_warnings = 0;
400 /* Allow the user site directory because this is used
401 * when PIP installing packages from Blender, see: #104000.
403 * NOTE(@ideasman42): While an argument can be made for isolating Blender's Python
404 * from the users home directory entirely, an alternative directory should be used in that
405 * case - so PIP can be used to install packages. Otherwise PIP will install packages to a
406 * directory which us not in the users `sys.path`, see `site.USER_BASE` for details. */
407 // config.user_site_directory = py_use_system_env;
409 /* While `sys.argv` is set, we don't want Python to interpret it. */
410 config.parse_argv = 0;
411 status = PyConfig_SetBytesArgv(&config, argc, (char *const *)argv);
412 pystatus_exit_on_error(status);
414 /* Needed for Python's initialization for portable Python installations.
415 * We could use #Py_SetPath, but this overrides Python's internal logic
416 * for calculating its own module search paths.
418 * `sys.executable` is overwritten after initialization to the Python binary. */
420 const char *program_path = BKE_appdir_program_path();
421 status = PyConfig_SetBytesString(&config, &config.program_name, program_path);
422 pystatus_exit_on_error(status);
425 /* Setting the program name is important so the 'multiprocessing' module
426 * can launch new Python instances. */
428 char program_path[FILE_MAX];
429 if (BKE_appdir_program_python_search(
430 program_path, sizeof(program_path), PY_MAJOR_VERSION, PY_MINOR_VERSION))
432 status = PyConfig_SetBytesString(&config, &config.executable, program_path);
433 pystatus_exit_on_error(status);
434 has_python_executable = true;
436 else {
437 /* Set to `sys.executable = None` below (we can't do before Python is initialized). */
438 fprintf(stderr,
439 "Unable to find the Python binary, "
440 "the multiprocessing module may not be functional!\n");
444 /* Allow to use our own included Python. `py_path_bundle` may be nullptr. */
446 const std::optional<std::string> py_path_bundle = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON,
447 nullptr);
448 if (py_path_bundle.has_value()) {
450 # ifdef __APPLE__
451 /* Mac-OS allows file/directory names to contain `:` character
452 * (represented as `/` in the Finder) but current Python lib (as of release 3.1.1)
453 * doesn't handle these correctly. */
454 if (strchr(py_path_bundle->c_str(), ':')) {
455 fprintf(stderr,
456 "Warning! Blender application is located in a path containing ':' or '/' chars\n"
457 "This may make Python import function fail\n");
459 # endif /* __APPLE__ */
461 status = PyConfig_SetBytesString(&config, &config.home, py_path_bundle->c_str());
462 pystatus_exit_on_error(status);
464 # ifdef PYTHON_SSL_CERT_FILE
465 /* Point to the portable SSL certificate to support HTTPS access, see: #102300. */
466 const char *ssl_cert_file_env = "SSL_CERT_FILE";
467 if (BLI_getenv(ssl_cert_file_env) == nullptr) {
468 const char *ssl_cert_file_suffix = PYTHON_SSL_CERT_FILE;
469 char ssl_cert_file[FILE_MAX];
470 BLI_path_join(
471 ssl_cert_file, sizeof(ssl_cert_file), py_path_bundle->c_str(), ssl_cert_file_suffix);
472 BLI_setenv(ssl_cert_file_env, ssl_cert_file);
474 # endif /* PYTHON_SSL_CERT_FILE */
476 else {
477 /* Common enough to use the system Python on Linux/Unix, warn on other systems. */
478 # if defined(__APPLE__) || defined(_WIN32)
479 fprintf(stderr,
480 "Bundled Python not found and is expected on this platform "
481 "(the 'install' target may have not been built)\n");
482 # endif
486 /* Initialize Python (also acquires lock). */
487 status = Py_InitializeFromConfig(&config);
488 PyConfig_Clear(&config);
490 pystatus_exit_on_error(status);
492 if (!has_python_executable) {
493 PySys_SetObject("executable", Py_None);
497 # ifdef WITH_FLUID
498 /* Required to prevent assertion error, see:
499 * https://stackoverflow.com/questions/27844676 */
500 Py_DECREF(PyImport_ImportModule("threading"));
501 # endif
503 #else /* WITH_PYTHON_MODULE */
504 (void)argc;
505 (void)argv;
507 /* NOTE(ideasman42): unfortunately the `inittab` can only be used
508 * before Python has been initialized.
509 * When built as a Python module, Python will have been initialized
510 * and using the `inittab` isn't supported.
511 * So it's necessary to load all modules as soon as `bpy` is imported. */
512 // PyImport_ExtendInittab(bpy_internal_modules);
514 #endif /* WITH_PYTHON_MODULE */
516 bpy_intern_string_init();
518 #ifdef WITH_PYTHON_MODULE
520 /* Manually load all modules */
521 struct _inittab *inittab_item;
522 PyObject *sys_modules = PyImport_GetModuleDict();
524 for (inittab_item = bpy_internal_modules; inittab_item->name; inittab_item++) {
525 PyObject *mod = inittab_item->initfunc();
526 if (mod) {
527 PyDict_SetItemString(sys_modules, inittab_item->name, mod);
529 else {
530 PyErr_Print();
531 PyErr_Clear();
533 // Py_DECREF(mod); /* Ideally would decref, but in this case we never want to free. */
536 #endif
538 /* Run first, initializes RNA types. */
539 BPY_rna_init();
541 /* Defines `bpy.*` and lets us import it. */
542 BPy_init_modules(C);
544 pyrna_alloc_types();
546 #ifndef WITH_PYTHON_MODULE
547 /* Python module runs `atexit` when `bpy` is freed. */
548 BPY_atexit_register(); /* This can initialize any time. */
550 /* Free the lock acquired (implicitly) when Python is initialized. */
551 PyEval_ReleaseThread(PyGILState_GetThisThreadState());
553 #endif
555 #ifdef WITH_PYTHON_MODULE
556 /* Disable all add-ons at exit, not essential, it just avoids resource leaks, see #71362. */
557 const char *imports[] = {"atexit", "addon_utils", nullptr};
558 BPY_run_string_eval(C, imports, "atexit.register(addon_utils.disable_all)");
559 #endif
562 void BPY_python_end(const bool do_python_exit)
564 #ifndef WITH_PYTHON_MODULE
565 BLI_assert_msg(Py_IsInitialized() != 0, "Python must be initialized");
566 #endif
568 PyGILState_STATE gilstate;
570 /* Finalizing, no need to grab the state, except when we are a module. */
571 gilstate = PyGILState_Ensure();
573 /* Frees the Python-driver name-space & cached data. */
574 BPY_driver_exit();
576 /* Clear Python values in the context so freeing the context after Python exits doesn't crash. */
577 bpy_context_end(BPY_context_get());
579 /* Decrement user counts of all callback functions. */
580 BPY_rna_props_clear_all();
582 /* Free other Python data. */
583 RNA_bpy_exit();
585 BPY_rna_exit();
587 /* Clear all Python data from structs. */
589 bpy_intern_string_exit();
591 /* `bpy.app` modules that need cleanup. */
592 BPY_app_translations_end();
594 #ifndef WITH_PYTHON_MODULE
595 /* Without this we get recursive calls to #WM_exit_ex. */
596 BPY_atexit_unregister();
598 if (do_python_exit) {
599 Py_Finalize();
601 (void)gilstate;
602 #else
603 PyGILState_Release(gilstate);
604 (void)do_python_exit;
605 #endif
607 #ifdef TIME_PY_RUN
608 /* Measure time since Python started. */
609 bpy_timer = BLI_time_now_seconds() - bpy_timer;
611 printf("*bpy stats* - ");
612 printf("tot exec: %d, ", bpy_timer_count);
613 printf("tot run: %.4fsec, ", bpy_timer_run_tot);
614 if (bpy_timer_count > 0) {
615 printf("average run: %.6fsec, ", (bpy_timer_run_tot / bpy_timer_count));
618 if (bpy_timer > 0.0) {
619 printf("tot usage %.4f%%", (bpy_timer_run_tot / bpy_timer) * 100.0);
622 printf("\n");
623 #endif
626 void BPY_python_reset(bContext *C)
628 BLI_assert_msg(Py_IsInitialized() != 0, "Python must be initialized");
630 /* Unrelated security stuff. */
631 G.f &= ~(G_FLAG_SCRIPT_AUTOEXEC_FAIL | G_FLAG_SCRIPT_AUTOEXEC_FAIL_QUIET);
632 G.autoexec_fail[0] = '\0';
634 BPY_driver_reset();
635 BPY_app_handlers_reset(false);
636 BPY_modules_load_user(C);
639 void BPY_python_use_system_env()
641 BLI_assert(!Py_IsInitialized());
642 py_use_system_env = true;
645 bool BPY_python_use_system_env_get()
647 return py_use_system_env;
650 void BPY_python_backtrace(FILE *fp)
652 fputs("\n# Python backtrace\n", fp);
654 /* Can happen in rare cases. */
655 if (!_PyThreadState_UncheckedGet()) {
656 return;
658 PyFrameObject *frame = PyEval_GetFrame();
659 if (frame == nullptr) {
660 return;
662 do {
663 PyCodeObject *code = PyFrame_GetCode(frame);
664 const int line = PyFrame_GetLineNumber(frame);
665 const char *filepath = PyUnicode_AsUTF8(code->co_filename);
666 const char *funcname = PyUnicode_AsUTF8(code->co_name);
667 fprintf(fp, " File \"%s\", line %d in %s\n", filepath, line, funcname);
668 } while ((frame = PyFrame_GetBack(frame)));
671 void BPY_DECREF(void *pyob_ptr)
673 const PyGILState_STATE gilstate = PyGILState_Ensure();
674 Py_DECREF((PyObject *)pyob_ptr);
675 PyGILState_Release(gilstate);
678 void BPY_DECREF_RNA_INVALIDATE(void *pyob_ptr)
680 const PyGILState_STATE gilstate = PyGILState_Ensure();
681 const bool do_invalidate = (Py_REFCNT((PyObject *)pyob_ptr) > 1);
682 Py_DECREF((PyObject *)pyob_ptr);
683 if (do_invalidate) {
684 pyrna_invalidate(static_cast<BPy_DummyPointerRNA *>(pyob_ptr));
686 PyGILState_Release(gilstate);
689 void BPY_modules_load_user(bContext *C)
691 PyGILState_STATE gilstate;
692 Main *bmain = CTX_data_main(C);
693 Text *text;
695 /* Can happen on file load. */
696 if (bmain == nullptr) {
697 return;
700 /* Update pointers since this can run from a nested script on file load. */
701 if (py_call_level) {
702 BPY_context_update(C);
705 bpy_context_set(C, &gilstate);
707 for (text = static_cast<Text *>(bmain->texts.first); text;
708 text = static_cast<Text *>(text->id.next))
710 if (text->flags & TXT_ISSCRIPT) {
711 if (!(G.f & G_FLAG_SCRIPT_AUTOEXEC)) {
712 if (!(G.f & G_FLAG_SCRIPT_AUTOEXEC_FAIL_QUIET)) {
713 G.f |= G_FLAG_SCRIPT_AUTOEXEC_FAIL;
714 SNPRINTF(G.autoexec_fail, RPT_("Text '%s'"), text->id.name + 2);
716 printf("scripts disabled for \"%s\", skipping '%s'\n",
717 BKE_main_blendfile_path(bmain),
718 text->id.name + 2);
721 else {
722 BPY_run_text(C, text, nullptr, false);
724 /* Check if the script loaded a new file. */
725 if (bmain != CTX_data_main(C)) {
726 break;
731 bpy_context_clear(C, &gilstate);
734 int BPY_context_member_get(bContext *C, const char *member, bContextDataResult *result)
736 PyGILState_STATE gilstate;
737 const bool use_gil = !PyC_IsInterpreterActive();
739 PyObject *pyctx;
740 PyObject *item;
741 PointerRNA *ptr = nullptr;
742 bool done = false;
744 if (use_gil) {
745 gilstate = PyGILState_Ensure();
748 pyctx = (PyObject *)CTX_py_dict_get(C);
749 item = PyDict_GetItemString(pyctx, member);
751 if (item == nullptr) {
752 /* Pass. */
754 else if (item == Py_None) {
755 done = true;
757 else if (BPy_StructRNA_Check(item)) {
758 ptr = &reinterpret_cast<BPy_StructRNA *>(item)->ptr.value();
760 // result->ptr = ((BPy_StructRNA *)item)->ptr;
761 CTX_data_pointer_set_ptr(result, ptr);
762 CTX_data_type_set(result, CTX_DATA_TYPE_POINTER);
763 done = true;
765 else if (PySequence_Check(item)) {
766 PyObject *seq_fast = PySequence_Fast(item, "bpy_context_get sequence conversion");
767 if (seq_fast == nullptr) {
768 PyErr_Print();
769 PyErr_Clear();
771 else {
772 const int len = PySequence_Fast_GET_SIZE(seq_fast);
773 PyObject **seq_fast_items = PySequence_Fast_ITEMS(seq_fast);
774 int i;
776 for (i = 0; i < len; i++) {
777 PyObject *list_item = seq_fast_items[i];
779 if (BPy_StructRNA_Check(list_item)) {
780 ptr = &reinterpret_cast<BPy_StructRNA *>(list_item)->ptr.value();
781 CTX_data_list_add_ptr(result, ptr);
783 else {
784 CLOG_INFO(BPY_LOG_CONTEXT,
786 "'%s' list item not a valid type in sequence type '%s'",
787 member,
788 Py_TYPE(item)->tp_name);
791 Py_DECREF(seq_fast);
792 CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
793 done = true;
797 if (done == false) {
798 if (item) {
799 CLOG_INFO(BPY_LOG_CONTEXT, 1, "'%s' not a valid type", member);
801 else {
802 CLOG_INFO(BPY_LOG_CONTEXT, 1, "'%s' not found", member);
805 else {
806 CLOG_INFO(BPY_LOG_CONTEXT, 2, "'%s' found", member);
809 if (use_gil) {
810 PyGILState_Release(gilstate);
813 return done;
816 #ifdef WITH_PYTHON_MODULE
817 /* TODO: reloading the module isn't functional at the moment. */
819 static void bpy_module_free(void *mod);
821 /* Defined in 'creator.c' when building as a Python module. */
822 extern int main_python_enter(int argc, const char **argv);
823 extern void main_python_exit();
825 static struct PyModuleDef bpy_proxy_def = {
826 /*m_base*/ PyModuleDef_HEAD_INIT,
827 /*m_name*/ "bpy",
828 /*m_doc*/ nullptr,
829 /*m_size*/ 0,
830 /*m_methods*/ nullptr,
831 /*m_slots*/ nullptr,
832 /*m_traverse*/ nullptr,
833 /*m_clear*/ nullptr,
834 /*m_free*/ bpy_module_free,
837 struct dealloc_obj {
838 PyObject_HEAD
839 /* Type-specific fields go here. */
840 PyObject *mod;
843 /* Call once `__file__` is set. */
844 static void bpy_module_delay_init(PyObject *bpy_proxy)
846 const int argc = 1;
847 const char *argv[2];
849 /* Updating the module dict below will lose the reference to `__file__`. */
850 PyObject *filepath_obj = PyModule_GetFilenameObject(bpy_proxy);
852 /* The file can be a relative path. */
853 const char *filepath_rel = PyUnicode_AsUTF8(filepath_obj);
854 char filepath_abs[1024];
856 STRNCPY(filepath_abs, filepath_rel);
857 BLI_path_abs_from_cwd(filepath_abs, sizeof(filepath_abs));
858 Py_DECREF(filepath_obj);
860 argv[0] = filepath_abs;
861 argv[1] = nullptr;
863 main_python_enter(argc, argv);
865 /* Initialized in #BPy_init_modules(). */
866 PyDict_Update(PyModule_GetDict(bpy_proxy), PyModule_GetDict(bpy_package_py));
870 * Raise an error and return false if the Python version used to compile Blender
871 * isn't compatible with the interpreter loading the `bpy` module.
873 static bool bpy_module_ensure_compatible_version()
875 /* First check the Python version used matches the major version that Blender was built with.
876 * While this isn't essential, the error message in this case may be cryptic and misleading.
877 * NOTE: using `Py_LIMITED_API` would remove the need for this, in practice it's
878 * unlikely Blender will ever used the limited API though. */
879 const uint version_runtime = Py_Version;
881 uint version_compile_major = PY_VERSION_HEX >> 24;
882 uint version_compile_minor = ((PY_VERSION_HEX & 0x00ff0000) >> 16);
883 uint version_runtime_major = version_runtime >> 24;
884 uint version_runtime_minor = ((version_runtime & 0x00ff0000) >> 16);
885 if ((version_compile_major != version_runtime_major) ||
886 (version_compile_minor != version_runtime_minor))
888 PyErr_Format(PyExc_ImportError,
889 "The version of \"bpy\" was compiled with: "
890 "(%u.%u) is incompatible with: (%u.%u) used by the interpreter!",
891 version_compile_major,
892 version_compile_minor,
893 version_runtime_major,
894 version_runtime_minor);
895 return false;
897 return true;
900 static void dealloc_obj_dealloc(PyObject *self);
902 static PyTypeObject dealloc_obj_Type;
904 /* Use our own `dealloc` so we can free a property if we use one. */
905 static void dealloc_obj_dealloc(PyObject *self)
907 bpy_module_delay_init(((dealloc_obj *)self)->mod);
909 /* NOTE: for sub-classed `PyObject` objects
910 * we can't call #PyObject_DEL() directly or it will crash. */
911 dealloc_obj_Type.tp_free(self);
914 PyMODINIT_FUNC PyInit_bpy();
916 PyMODINIT_FUNC PyInit_bpy()
918 if (!bpy_module_ensure_compatible_version()) {
919 return nullptr; /* The error has been set. */
922 PyObject *bpy_proxy = PyModule_Create(&bpy_proxy_def);
924 /* Problem:
925 * 1) This initializing function is expected to have a private member defined - `md_def`
926 * but this is only set for CAPI defined modules (not Python packages)
927 * so we can't return `bpy_package_py` as is.
929 * 2) There is a `bpy` CAPI module for python to load which is basically all of blender,
930 * and there is `scripts/bpy/__init__.py`,
931 * we may end up having to rename this module so there is no naming conflict here eg:
932 * `from blender import bpy`
934 * 3) We don't know the file-path at this point, workaround by assigning a dummy value
935 * which calls back when its freed so the real loading can take place.
938 /* Assign an object which is freed after `__file__` is assigned. */
939 dealloc_obj *dob;
941 /* Assign dummy type. */
942 dealloc_obj_Type.tp_name = "dealloc_obj";
943 dealloc_obj_Type.tp_basicsize = sizeof(dealloc_obj);
944 dealloc_obj_Type.tp_dealloc = dealloc_obj_dealloc;
945 dealloc_obj_Type.tp_flags = Py_TPFLAGS_DEFAULT;
947 if (PyType_Ready(&dealloc_obj_Type) < 0) {
948 return nullptr;
951 dob = (dealloc_obj *)dealloc_obj_Type.tp_alloc(&dealloc_obj_Type, 0);
952 dob->mod = bpy_proxy; /* borrow */
953 PyModule_AddObject(bpy_proxy, "__file__", (PyObject *)dob); /* borrow */
955 return bpy_proxy;
958 static void bpy_module_free(void * /*mod*/)
960 main_python_exit();
963 #endif
965 bool BPY_string_is_keyword(const char *str)
967 /* List is from: `", ".join(['"%s"' % kw for kw in __import__("keyword").kwlist])`. */
968 const char *kwlist[] = {
969 "False", "None", "True", "and", "as", "assert", "async", "await", "break",
970 "class", "continue", "def", "del", "elif", "else", "except", "finally", "for",
971 "from", "global", "if", "import", "in", "is", "lambda", "nonlocal", "not",
972 "or", "pass", "raise", "return", "try", "while", "with", "yield", nullptr,
975 for (int i = 0; kwlist[i]; i++) {
976 if (STREQ(str, kwlist[i])) {
977 return true;
981 return false;
984 /* -------------------------------------------------------------------- */
985 /** \name Character Classification
987 * Define `text.cc` functions here (declared in `BKE_text.h`),
988 * This could be removed if Blender gets its own unicode library.
989 * \{ */
991 int text_check_identifier_unicode(const uint ch)
993 return (ch < 255 && text_check_identifier(char(ch))) || Py_UNICODE_ISALNUM(ch);
996 int text_check_identifier_nodigit_unicode(const uint ch)
998 return (ch < 255 && text_check_identifier_nodigit(char(ch))) || Py_UNICODE_ISALPHA(ch);
1001 /** \} */