Blender V4.5
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
16#ifdef WITH_PYTHON_MODULE
17# include "pylifecycle.h" /* For `Py_Version`. */
18#endif
19#include "../generic/python_compat.hh" /* IWYU pragma: keep. */
20
21#include "CLG_log.h"
22
23#include "BLI_path_utils.hh"
24#include "BLI_string.h"
25#include "BLI_threads.h"
26#include "BLI_utildefines.h"
27
28#include "BLT_translation.hh"
29
30#include "RNA_types.hh"
31
32#include "bpy.hh"
33#include "bpy_capi_utils.hh"
34#include "bpy_intern_string.hh"
35#include "bpy_path.hh"
36#include "bpy_props.hh"
37#include "bpy_rna.hh"
38
40
41#include "DNA_text_types.h"
42
43#include "BKE_appdir.hh"
44#include "BKE_context.hh"
45#include "BKE_global.hh" /* Only for script checking. */
46#include "BKE_main.hh"
47#include "BKE_text.h"
48
49#ifdef WITH_CYCLES
50# include "CCL_api.h"
51#endif
52
53#include "BPY_extern.hh"
54#include "BPY_extern_python.hh"
55#include "BPY_extern_run.hh"
56
58
59/* `inittab` initialization functions. */
61#include "../generic/bgl.hh"
66#include "../gpu/gpu_py_api.hh"
68
69/* Logging types to use anywhere in the Python modules. */
70
74
75/* For internal use, when starting and ending Python scripts. */
76
77/* In case a Python script triggers another Python call,
78 * stop #bpy_context_clear from invalidating. */
79static int py_call_level = 0;
80
81/* Set by command line arguments before Python starts. */
82static bool py_use_system_env = false;
83
84// #define TIME_PY_RUN /* Simple python tests. prints on exit. */
85
86#ifdef TIME_PY_RUN
87# include "BLI_time.h"
88static int bpy_timer_count = 0;
90static double bpy_timer;
92static double bpy_timer_run;
94static double bpy_timer_run_tot;
95#endif
96
98{
99 /* Don't do this from a non-main (e.g. render) thread, it can cause a race
100 * condition on `C->data.recursion`. Ideal solution would be to disable
101 * context entirely from non-main threads, but that's more complicated. */
102 if (!BLI_thread_is_main()) {
103 return;
104 }
105
107
108 /* Can give really bad results if this isn't here. */
110}
111
112void bpy_context_set(bContext *C, PyGILState_STATE *gilstate)
113{
115
116 if (gilstate) {
117 *gilstate = PyGILState_Ensure();
118 }
119
120 if (py_call_level == 1) {
122
123#ifdef TIME_PY_RUN
124 if (bpy_timer_count == 0) {
125 /* Record time from the beginning. */
126 bpy_timer = BLI_time_now_seconds();
127 bpy_timer_run = bpy_timer_run_tot = 0.0;
128 }
129 bpy_timer_run = BLI_time_now_seconds();
130
131 bpy_timer_count++;
132#endif
133 }
134}
135
136void bpy_context_clear(bContext * /*C*/, const PyGILState_STATE *gilstate)
137{
139
140 if (gilstate) {
141 PyGILState_Release(*gilstate);
142 }
143
144 if (py_call_level < 0) {
145 fprintf(stderr, "ERROR: Python context internal state bug. this should not happen!\n");
146 }
147 else if (py_call_level == 0) {
148 /* NOTE: Unfortunately calling classes currently won't store the context.
149 * Can't set nullptr because of this - but this is very unreliable still. */
150#if 0
151 BPY_context_set(nullptr);
152#endif
153
154#ifdef TIME_PY_RUN
155 bpy_timer_run_tot += BLI_time_now_seconds() - bpy_timer_run;
156 bpy_timer_count++;
157#endif
158 }
159}
160
162{
163 if (UNLIKELY(C == nullptr)) {
164 return;
165 }
167}
168
170 void *dict_orig,
171 const char *context_members[],
172 uint context_members_len)
173{
174 PyGILState_STATE gilstate;
175 const bool use_gil = !PyC_IsInterpreterActive();
176 if (use_gil) {
177 gilstate = PyGILState_Ensure();
178 }
179
180 /* Copy on write. */
181 if (*dict_p == dict_orig) {
182 *dict_p = PyDict_Copy(static_cast<PyObject *>(dict_orig));
183 }
184
185 PyObject *dict = static_cast<PyObject *>(*dict_p);
186 BLI_assert(PyDict_Check(dict));
187
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);
195 }
196
197 if (use_gil) {
198 PyGILState_Release(gilstate);
199 }
200}
201
203{
204 if (text->compiled) {
205 PyGILState_STATE gilstate;
206 const bool use_gil = !PyC_IsInterpreterActive();
207
208 if (use_gil) {
209 gilstate = PyGILState_Ensure();
210 }
211
212 Py_DECREF((PyObject *)text->compiled);
213 text->compiled = nullptr;
214
215 if (use_gil) {
216 PyGILState_Release(gilstate);
217 }
218 }
219}
220
222{
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
230
231 /* Refreshes the main struct. */
233}
234
236{
237 return static_cast<bContext *>(bpy_context_module->ptr->data);
238}
239
241{
242 bpy_context_module->ptr->data = (void *)C;
243}
244
245#ifdef WITH_FLUID
246/* Defined in `manta` module. */
247extern "C" PyObject *Manta_initPython();
248#endif
249
250#ifdef WITH_AUDASPACE_PY
251/* Defined in `AUD_C-API.cpp`. */
252extern "C" PyObject *AUD_initPython();
253#endif
254
255#ifdef WITH_CYCLES
256/* Defined in `cycles` module. */
257static PyObject *CCL_initPython()
258{
259 return (PyObject *)CCL_python_module_init();
260}
261#endif
262
263#ifdef WITH_HYDRA
264/* Defined in `render_hydra` module. */
265PyObject *BPyInit_hydra();
266#endif
267
268static _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},
301};
302
303#ifndef WITH_PYTHON_MODULE
313static void pystatus_exit_on_error(const PyStatus &status)
314{
315 if (UNLIKELY(PyStatus_Exception(status))) {
316 fputs("Internal error initializing Python!\n", stderr);
317 /* This calls `exit`. */
318 Py_ExitStatusException(status);
319 }
320}
321#endif
322
323void BPY_python_start(bContext *C, int argc, const char **argv)
324{
325#ifndef WITH_PYTHON_MODULE
326 BLI_assert_msg(Py_IsInitialized() == 0, "Python has already been initialized");
327
328 /* #PyPreConfig (early-configuration). */
329 {
330 PyPreConfig preconfig;
331 PyStatus status;
332
333 /* To narrow down reports where the systems Python is inexplicably used, see: #98131. */
334 CLOG_INFO(
336 2,
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*");
340
341 if (py_use_system_env) {
342 PyPreConfig_InitPythonConfig(&preconfig);
343 }
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);
349 }
350
351 /* Force UTF8 on all platforms, since this is what's used for Blender's internal strings,
352 * providing consistent encoding behavior across all Blender installations.
353 *
354 * This also uses the `surrogateescape` error handler ensures any unexpected bytes are escaped
355 * instead of raising an error.
356 *
357 * Without this `sys.getfilesystemencoding()` and `sys.stdout` for example may be set to ASCII
358 * or some other encoding - where printing some UTF8 values will raise an error.
359 *
360 * This can cause scripts to fail entirely on some systems.
361 *
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;
365
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);
371 }
372
373 /* Must run before python initializes, but after #PyPreConfig. */
374 PyImport_ExtendInittab(bpy_internal_modules);
375
376 /* #PyConfig (initialize Python). */
377 {
378 PyConfig config;
379 PyStatus status;
380 bool has_python_executable = false;
381
382 if (py_use_system_env) {
383 PyConfig_InitPythonConfig(&config);
384
385 BLI_assert(config.install_signal_handlers);
386 }
387 else {
388 PyConfig_InitIsolatedConfig(&config);
389 /* Python's isolated config disables its 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;
394 }
395
396 /* Suppress error messages when calculating the module search path.
397 * While harmless, it's noisy. */
398 config.pathconfig_warnings = 0;
399
400 /* Allow the user site directory because this is used
401 * when PIP installing packages from Blender, see: #104000.
402 *
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;
408
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);
413
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.
417 *
418 * `sys.executable` is overwritten after initialization to the Python binary. */
419 {
420 const char *program_path = BKE_appdir_program_path();
421 status = PyConfig_SetBytesString(&config, &config.program_name, program_path);
423 }
424
425 /* Setting the program name is important so the 'multiprocessing' module
426 * can launch new Python instances. */
427 {
428 char program_path[FILE_MAX];
430 program_path, sizeof(program_path), PY_MAJOR_VERSION, PY_MINOR_VERSION))
431 {
432 status = PyConfig_SetBytesString(&config, &config.executable, program_path);
434 has_python_executable = true;
435 }
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");
441 }
442 }
443
444 /* Allow to use our own included Python. `py_path_bundle` may be nullptr. */
445 {
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()) {
449
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");
458 }
459# endif /* __APPLE__ */
460
461 status = PyConfig_SetBytesString(&config, &config.home, py_path_bundle->c_str());
463
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];
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);
473 }
474# endif /* PYTHON_SSL_CERT_FILE */
475 }
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
483 }
484 }
485
486 /* Initialize Python (also acquires lock). */
487 status = Py_InitializeFromConfig(&config);
488 PyConfig_Clear(&config);
489
491
492 if (!has_python_executable) {
493 PySys_SetObject("executable", Py_None);
494 }
495 }
496
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
502
503#else /* WITH_PYTHON_MODULE */
504 (void)argc;
505 (void)argv;
506
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);
513
514#endif /* WITH_PYTHON_MODULE */
515
517
518#ifdef WITH_PYTHON_MODULE
519 {
520 /* Manually load all modules */
521 struct _inittab *inittab_item;
522 PyObject *sys_modules = PyImport_GetModuleDict();
523
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);
528 }
529 else {
530 PyErr_Print();
531 PyErr_Clear();
532 }
533 // Py_DECREF(mod); /* Ideally would decref, but in this case we never want to free. */
534 }
535 }
536#endif
537
538 /* Run first, initializes RNA types. */
539 BPY_rna_init();
540
541 /* Defines `bpy.*` and lets us import it. */
543
545
546#ifndef WITH_PYTHON_MODULE
547 /* Python module runs `atexit` when `bpy` is freed. */
548 BPY_atexit_register(); /* This can initialize any time. */
549
550 /* Free the lock acquired (implicitly) when Python is initialized. */
551 PyEval_ReleaseThread(PyGILState_GetThisThreadState());
552
553#endif
554
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
560}
561
562void BPY_python_end(const bool do_python_exit)
563{
564#ifndef WITH_PYTHON_MODULE
565 BLI_assert_msg(Py_IsInitialized() != 0, "Python must be initialized");
566#endif
567
568 /* Finalizing, no need to grab the state, except when we are a module. */
569 PyGILState_STATE gilstate = PyGILState_Ensure();
570
571 /* Frees the Python-driver name-space & cached data. */
573
574 /* Clear Python values in the context so freeing the context after Python exits doesn't crash. */
576
577 /* Decrement user counts of all callback functions. */
579
580 /* Free other Python data. */
581 RNA_bpy_exit();
582
583 BPY_rna_exit();
584
585 /* Clear all Python data from structs. */
586
588
589 /* `bpy.app` modules that need cleanup. */
591
592#ifndef WITH_PYTHON_MODULE
593 /* Without this we get recursive calls to #WM_exit_ex. */
595
596 if (do_python_exit) {
597 Py_Finalize();
598 }
599 (void)gilstate;
600#else
601 PyGILState_Release(gilstate);
602 (void)do_python_exit;
603#endif
604
605#ifdef TIME_PY_RUN
606 /* Measure time since Python started. */
607 bpy_timer = BLI_time_now_seconds() - bpy_timer;
608
609 printf("*bpy stats* - ");
610 printf("tot exec: %d, ", bpy_timer_count);
611 printf("tot run: %.4fsec, ", bpy_timer_run_tot);
612 if (bpy_timer_count > 0) {
613 printf("average run: %.6fsec, ", (bpy_timer_run_tot / bpy_timer_count));
614 }
615
616 if (bpy_timer > 0.0) {
617 printf("tot usage %.4f%%", (bpy_timer_run_tot / bpy_timer) * 100.0);
618 }
619
620 printf("\n");
621#endif
622}
623
625{
626 BLI_assert_msg(Py_IsInitialized() != 0, "Python must be initialized");
627
628 /* Unrelated security stuff. */
630 G.autoexec_fail[0] = '\0';
631
635}
636
638{
639 BLI_assert(!Py_IsInitialized());
640 py_use_system_env = true;
641}
642
647
649{
650 fputs("\n# Python backtrace\n", fp);
651
652 /* Can happen in rare cases. */
654 return;
655 }
656 PyFrameObject *frame = PyEval_GetFrame();
657 if (frame == nullptr) {
658 return;
659 }
660 do {
661 PyCodeObject *code = PyFrame_GetCode(frame);
662 const int line = PyFrame_GetLineNumber(frame);
663 const char *filepath = PyUnicode_AsUTF8(code->co_filename);
664 const char *funcname = PyUnicode_AsUTF8(code->co_name);
665 fprintf(fp, " File \"%s\", line %d in %s\n", filepath, line, funcname);
666 } while ((frame = PyFrame_GetBack(frame)));
667}
668
669void BPY_DECREF(void *pyob_ptr)
670{
671 const PyGILState_STATE gilstate = PyGILState_Ensure();
672 Py_DECREF((PyObject *)pyob_ptr);
673 PyGILState_Release(gilstate);
674}
675
676void BPY_DECREF_RNA_INVALIDATE(void *pyob_ptr)
677{
678 const PyGILState_STATE gilstate = PyGILState_Ensure();
679 const bool do_invalidate = (Py_REFCNT((PyObject *)pyob_ptr) > 1);
680 Py_DECREF((PyObject *)pyob_ptr);
681 if (do_invalidate) {
682 pyrna_invalidate(static_cast<BPy_DummyPointerRNA *>(pyob_ptr));
683 }
684 PyGILState_Release(gilstate);
685}
686
688{
689 PyGILState_STATE gilstate;
690 Main *bmain = CTX_data_main(C);
691 Text *text;
692
693 /* Can happen on file load. */
694 if (bmain == nullptr) {
695 return;
696 }
697
698 /* Update pointers since this can run from a nested script on file load. */
699 if (py_call_level) {
701 }
702
703 bpy_context_set(C, &gilstate);
704
705 for (text = static_cast<Text *>(bmain->texts.first); text;
706 text = static_cast<Text *>(text->id.next))
707 {
708 if (text->flags & TXT_ISSCRIPT) {
709 if (!(G.f & G_FLAG_SCRIPT_AUTOEXEC)) {
712 SNPRINTF(G.autoexec_fail, RPT_("Text '%s'"), text->id.name + 2);
713
714 printf("scripts disabled for \"%s\", skipping '%s'\n",
716 text->id.name + 2);
717 }
718 }
719 else {
720 BPY_run_text(C, text, nullptr, false);
721
722 /* Check if the script loaded a new file. */
723 if (bmain != CTX_data_main(C)) {
724 break;
725 }
726 }
727 }
728 }
729 bpy_context_clear(C, &gilstate);
730}
731
733{
734 PyGILState_STATE gilstate;
735 const bool use_gil = !PyC_IsInterpreterActive();
736 if (use_gil) {
737 gilstate = PyGILState_Ensure();
738 }
739
740 PyObject *pyctx;
741 PyObject *item;
742 PointerRNA *ptr = nullptr;
743 bool done = false;
744
745 pyctx = (PyObject *)CTX_py_dict_get(C);
746 item = PyDict_GetItemString(pyctx, member);
747
748 if (item == nullptr) {
749 /* Pass. */
750 }
751 else if (item == Py_None) {
752 done = true;
753 }
754 else if (BPy_StructRNA_Check(item)) {
755 ptr = &reinterpret_cast<BPy_StructRNA *>(item)->ptr.value();
756
757 // result->ptr = ((BPy_StructRNA *)item)->ptr;
760 done = true;
761 }
762 else if (PySequence_Check(item)) {
763 PyObject *seq_fast = PySequence_Fast(item, "bpy_context_get sequence conversion");
764 if (seq_fast == nullptr) {
765 PyErr_Print();
766 PyErr_Clear();
767 }
768 else {
769 const int len = PySequence_Fast_GET_SIZE(seq_fast);
770 PyObject **seq_fast_items = PySequence_Fast_ITEMS(seq_fast);
771 int i;
772
773 for (i = 0; i < len; i++) {
774 PyObject *list_item = seq_fast_items[i];
775
776 if (BPy_StructRNA_Check(list_item)) {
777 ptr = &reinterpret_cast<BPy_StructRNA *>(list_item)->ptr.value();
779 }
780 else {
782 1,
783 "'%s' list item not a valid type in sequence type '%s'",
784 member,
785 Py_TYPE(item)->tp_name);
786 }
787 }
788 Py_DECREF(seq_fast);
790 done = true;
791 }
792 }
793
794 if (done == false) {
795 if (item) {
796 CLOG_INFO(BPY_LOG_CONTEXT, 1, "'%s' not a valid type", member);
797 }
798 else {
799 CLOG_INFO(BPY_LOG_CONTEXT, 1, "'%s' not found", member);
800 }
801 }
802 else {
803 CLOG_INFO(BPY_LOG_CONTEXT, 2, "'%s' found", member);
804 }
805
806 if (use_gil) {
807 PyGILState_Release(gilstate);
808 }
809
810 return done;
811}
812
813#ifdef WITH_PYTHON_MODULE
814/* TODO: reloading the module isn't functional at the moment. */
815
816static void bpy_module_free(void *mod);
817
818/* Defined in 'creator.c' when building as a Python module. */
819extern int main_python_enter(int argc, const char **argv);
820extern void main_python_exit();
821
822static struct PyModuleDef bpy_proxy_def = {
823 /*m_base*/ PyModuleDef_HEAD_INIT,
824 /*m_name*/ "bpy",
825 /*m_doc*/ nullptr,
826 /*m_size*/ 0,
827 /*m_methods*/ nullptr,
828 /*m_slots*/ nullptr,
829 /*m_traverse*/ nullptr,
830 /*m_clear*/ nullptr,
831 /*m_free*/ bpy_module_free,
832};
833
834struct dealloc_obj {
835 PyObject_HEAD
836 /* Type-specific fields go here. */
837 PyObject *mod;
838};
839
840/* Call once `__file__` is set. */
841static void bpy_module_delay_init(PyObject *bpy_proxy)
842{
843 const int argc = 1;
844 const char *argv[2];
845
846 /* Updating the module dict below will lose the reference to `__file__`. */
847 PyObject *filepath_obj = PyModule_GetFilenameObject(bpy_proxy);
848
849 /* The file can be a relative path. */
850 const char *filepath_rel = PyUnicode_AsUTF8(filepath_obj);
851 char filepath_abs[1024];
852
853 STRNCPY(filepath_abs, filepath_rel);
854 BLI_path_abs_from_cwd(filepath_abs, sizeof(filepath_abs));
855 Py_DECREF(filepath_obj);
856
857 argv[0] = filepath_abs;
858 argv[1] = nullptr;
859
860 main_python_enter(argc, argv);
861
862 /* Initialized in #BPy_init_modules(). */
863 PyDict_Update(PyModule_GetDict(bpy_proxy), PyModule_GetDict(bpy_package_py));
864}
865
870static bool bpy_module_ensure_compatible_version()
871{
872 /* First check the Python version used matches the major version that Blender was built with.
873 * While this isn't essential, the error message in this case may be cryptic and misleading.
874 * NOTE: using `Py_LIMITED_API` would remove the need for this, in practice it's
875 * unlikely Blender will ever used the limited API though. */
876 const uint version_runtime = Py_Version;
877
878 uint version_compile_major = PY_VERSION_HEX >> 24;
879 uint version_compile_minor = ((PY_VERSION_HEX & 0x00ff0000) >> 16);
880 uint version_runtime_major = version_runtime >> 24;
881 uint version_runtime_minor = ((version_runtime & 0x00ff0000) >> 16);
882 if ((version_compile_major != version_runtime_major) ||
883 (version_compile_minor != version_runtime_minor))
884 {
885 PyErr_Format(PyExc_ImportError,
886 "The version of \"bpy\" was compiled with: "
887 "(%u.%u) is incompatible with: (%u.%u) used by the interpreter!",
888 version_compile_major,
889 version_compile_minor,
890 version_runtime_major,
891 version_runtime_minor);
892 return false;
893 }
894 return true;
895}
896
897static void dealloc_obj_dealloc(PyObject *self);
898
899static PyTypeObject dealloc_obj_Type;
900
901/* Use our own `dealloc` so we can free a property if we use one. */
902static void dealloc_obj_dealloc(PyObject *self)
903{
904 bpy_module_delay_init(((dealloc_obj *)self)->mod);
905
906 /* NOTE: for sub-classed `PyObject` objects
907 * we can't call #PyObject_DEL() directly or it will crash. */
908 dealloc_obj_Type.tp_free(self);
909}
910
911PyMODINIT_FUNC PyInit_bpy();
912
913PyMODINIT_FUNC PyInit_bpy()
914{
915 if (!bpy_module_ensure_compatible_version()) {
916 return nullptr; /* The error has been set. */
917 }
918
919 PyObject *bpy_proxy = PyModule_Create(&bpy_proxy_def);
920
921 /* Problem:
922 * 1) This initializing function is expected to have a private member defined - `md_def`
923 * but this is only set for CAPI defined modules (not Python packages)
924 * so we can't return `bpy_package_py` as is.
925 *
926 * 2) There is a `bpy` CAPI module for python to load which is basically all of blender,
927 * and there is `scripts/bpy/__init__.py`,
928 * we may end up having to rename this module so there is no naming conflict here eg:
929 * `from blender import bpy`
930 *
931 * 3) We don't know the file-path at this point, workaround by assigning a dummy value
932 * which calls back when its freed so the real loading can take place.
933 */
934
935 /* Assign an object which is freed after `__file__` is assigned. */
936 dealloc_obj *dob;
937
938 /* Assign dummy type. */
939 dealloc_obj_Type.tp_name = "dealloc_obj";
940 dealloc_obj_Type.tp_basicsize = sizeof(dealloc_obj);
941 dealloc_obj_Type.tp_dealloc = dealloc_obj_dealloc;
942 dealloc_obj_Type.tp_flags = Py_TPFLAGS_DEFAULT;
943
944 if (PyType_Ready(&dealloc_obj_Type) < 0) {
945 return nullptr;
946 }
947
948 dob = (dealloc_obj *)dealloc_obj_Type.tp_alloc(&dealloc_obj_Type, 0);
949 dob->mod = bpy_proxy; /* borrow */
950 PyModule_AddObject(bpy_proxy, "__file__", (PyObject *)dob); /* borrow */
951
952 return bpy_proxy;
953}
954
955static void bpy_module_free(void * /*mod*/)
956{
957 main_python_exit();
958}
959
960#endif
961
962bool BPY_string_is_keyword(const char *str)
963{
964 /* List is from: `", ".join(['"%s"' % kw for kw in __import__("keyword").kwlist])`. */
965 const char *kwlist[] = {
966 "False", "None", "True", "and", "as", "assert", "async", "await", "break",
967 "class", "continue", "def", "del", "elif", "else", "except", "finally", "for",
968 "from", "global", "if", "import", "in", "is", "lambda", "nonlocal", "not",
969 "or", "pass", "raise", "return", "try", "while", "with", "yield", nullptr,
970 };
971
972 for (int i = 0; kwlist[i]; i++) {
973 if (STREQ(str, kwlist[i])) {
974 return true;
975 }
976 }
977
978 return false;
979}
980
981/* -------------------------------------------------------------------- */
987
989{
990 return (ch < 255 && text_check_identifier(char(ch))) || Py_UNICODE_ISALNUM(ch);
991}
992
994{
995 return (ch < 255 && text_check_identifier_nodigit(char(ch))) || Py_UNICODE_ISALPHA(ch);
996}
997
PyObject * AUD_initPython(void)
const char * BKE_appdir_program_path() ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
Definition appdir.cc:952
@ BLENDER_SYSTEM_PYTHON
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:966
std::optional< std::string > BKE_appdir_folder_id(int folder_id, const char *subfolder) ATTR_WARN_UNUSED_RESULT
Definition appdir.cc:717
void CTX_wm_operator_poll_msg_clear(bContext *C)
@ CTX_DATA_TYPE_POINTER
@ CTX_DATA_TYPE_COLLECTION
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)
void * CTX_py_dict_get(const bContext *C)
void CTX_data_type_set(bContextDataResult *result, short type)
@ G_FLAG_SCRIPT_AUTOEXEC_FAIL_QUIET
@ G_FLAG_SCRIPT_AUTOEXEC_FAIL
@ G_FLAG_SCRIPT_AUTOEXEC
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:877
bool text_check_identifier_nodigit(char ch)
Definition text.cc:2339
bool text_check_identifier(char ch)
Definition text.cc:2316
#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)
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
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:65
#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
struct CLG_LogRef * BPY_LOG_CONTEXT
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 CLG_LOGREF_DECLARE_GLOBAL(var, id)
Definition CLG_log.h:145
#define CLOG_INFO(clg_ref, level,...)
Definition CLG_log.h:179
@ TXT_ISSCRIPT
#define C
Definition RandGen.cpp:29
PyObject * BPyInit_bgl()
Definition bgl.cc:2655
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:63
void BPy_init_modules(bContext *C)
Definition bpy.cc:725
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)
int text_check_identifier_unicode(const uint ch)
int BPY_context_member_get(bContext *C, const char *member, bContextDataResult *result)
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()
void BPY_text_free_code(Text *text)
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:179
PyObject * BPY_rna_module()
Definition bpy_rna.cc:8593
void BPY_rna_init()
Definition bpy_rna.cc:8517
void BPY_rna_exit()
Definition bpy_rna.cc:8570
PyObject * BPY_rna_types()
Definition bpy_rna.cc:8758
void pyrna_alloc_types()
Definition bpy_rna.cc:9909
void BPY_update_rna_module()
Definition bpy_rna.cc:8605
BPy_StructRNA * bpy_context_module
Definition bpy_rna.cc:94
#define BPy_StructRNA_Check(v)
Definition bpy_rna.hh:73
#define str(s)
VecBase< float, D > constexpr mod(VecOp< float, D >, VecOp< float, D >) RET
#define printf(...)
PyObject * BPyInit_gpu()
Definition gpu_py_api.cc:48
PyObject * BPyInit_idprop()
PyObject * BPyInit_imbuf()
PyObject * Manta_initPython(void)
PyMODINIT_FUNC PyInit_mathutils()
Definition mathutils.cc:781
PyMODINIT_FUNC PyInit_mathutils_geometry()
PyMODINIT_FUNC PyInit_mathutils_kdtree()
PyMODINIT_FUNC PyInit_mathutils_noise()
#define G(x, y, z)
bool PyC_IsInterpreterActive()
PyObject * BPyInit_hydra()
Definition python.cc:209
header-only compatibility defines.
#define PyThreadState_GetUnchecked
void RNA_bpy_exit()
void * next
Definition DNA_ID.h:407
char name[66]
Definition DNA_ID.h:415
void * first
ListBase texts
Definition BKE_main.hh:263
int flags
void * compiled
i
Definition text_draw.cc:230
uint len
PointerRNA * ptr
Definition wm_files.cc:4227