Changeset View
Changeset View
Standalone View
Standalone View
source/blender/python/intern/bpy_interface.c
| Show First 20 Lines • Show All 298 Lines • ▼ Show 20 Lines | |||||
| #ifdef WITH_CYCLES | #ifdef WITH_CYCLES | ||||
| {"_cycles", CCL_initPython}, | {"_cycles", CCL_initPython}, | ||||
| #endif | #endif | ||||
| {"gpu", BPyInit_gpu}, | {"gpu", BPyInit_gpu}, | ||||
| {"idprop", BPyInit_idprop}, | {"idprop", BPyInit_idprop}, | ||||
| {NULL, NULL}, | {NULL, NULL}, | ||||
| }; | }; | ||||
| /** | |||||
| * Convenience function for #BPY_python_start. | |||||
| * | |||||
| * These should happen so rarely that having comprehensive errors isn't needed. | |||||
| * For example if `sys.argv` fails to allocate memory. | |||||
| * | |||||
| * Show an error just to avoid silent failure in the unlikely event something goes wrong, | |||||
| * in this case a developer will need to track down the root cause. | |||||
| */ | |||||
| static void pystatus_exit_on_error(PyStatus status) | |||||
| { | |||||
| if (UNLIKELY(PyStatus_Exception(status))) { | |||||
| fputs("Internal error initializing Python!\n", stderr); | |||||
| /* This calls `exit`. */ | |||||
| Py_ExitStatusException(status); | |||||
| } | |||||
| } | |||||
| /* call BPY_context_set first */ | /* call BPY_context_set first */ | ||||
| void BPY_python_start(bContext *C, int argc, const char **argv) | void BPY_python_start(bContext *C, int argc, const char **argv) | ||||
| { | { | ||||
| #ifndef WITH_PYTHON_MODULE | #ifndef WITH_PYTHON_MODULE | ||||
| PyThreadState *py_tstate = NULL; | |||||
| /* Needed for Python's initialization for portable Python installations. | /* #PyPreConfig (early-configuration). */ | ||||
| * We could use #Py_SetPath, but this overrides Python's internal logic | |||||
| * for calculating it's own module search paths. | |||||
| * | |||||
| * `sys.executable` is overwritten after initialization to the Python binary. */ | |||||
| { | { | ||||
| const char *program_path = BKE_appdir_program_path(); | PyPreConfig preconfig; | ||||
| wchar_t program_path_wchar[FILE_MAX]; | PyStatus status; | ||||
| BLI_strncpy_wchar_from_utf8(program_path_wchar, program_path, ARRAY_SIZE(program_path_wchar)); | |||||
| Py_SetProgramName(program_path_wchar); | |||||
| } | |||||
| /* must run before python initializes */ | |||||
| PyImport_ExtendInittab(bpy_internal_modules); | |||||
| /* Allow to use our own included Python. `py_path_bundle` may be NULL. */ | if (py_use_system_env) { | ||||
| { | PyPreConfig_InitPythonConfig(&preconfig); | ||||
| const char *py_path_bundle = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON, NULL); | |||||
| if (py_path_bundle != NULL) { | |||||
| PyC_SetHomePath(py_path_bundle); | |||||
| } | } | ||||
| else { | else { | ||||
| /* Common enough to use the system Python on Linux/Unix, warn on other systems. */ | /* Only use the systems environment variables and site when explicitly requested. | ||||
| # if defined(__APPLE__) || defined(_WIN32) | * Since an incorrect 'PYTHONPATH' causes difficult to debug errors, see: T72807. | ||||
| fprintf(stderr, | * An alternative to setting `preconfig.use_environment = 0` */ | ||||
| "Bundled Python not found and is expected on this platform " | PyPreConfig_InitIsolatedConfig(&preconfig); | ||||
| "(the 'install' target may have not been built)\n"); | |||||
| # endif | |||||
| } | |||||
| } | } | ||||
| /* Force `utf-8` on all platforms, since this is what's used for Blender's internal strings, | /* Force `utf-8` on all platforms, since this is what's used for Blender's internal strings, | ||||
| * providing consistent encoding behavior across all Blender installations. | * providing consistent encoding behavior across all Blender installations. | ||||
| * | * | ||||
| * This also uses the `surrogateescape` error handler ensures any unexpected bytes are escaped | * This also uses the `surrogateescape` error handler ensures any unexpected bytes are escaped | ||||
| * instead of raising an error. | * instead of raising an error. | ||||
| * | * | ||||
| * Without this `sys.getfilesystemencoding()` and `sys.stdout` for example may be set to ASCII | * Without this `sys.getfilesystemencoding()` and `sys.stdout` for example may be set to ASCII | ||||
| * or some other encoding - where printing some `utf-8` values will raise an error. | * or some other encoding - where printing some `utf-8` values will raise an error. | ||||
| * | * | ||||
| * This can cause scripts to fail entirely on some systems. | * This can cause scripts to fail entirely on some systems. | ||||
| * | * | ||||
| * This assignment is the equivalent of enabling the `PYTHONUTF8` environment variable. | * This assignment is the equivalent of enabling the `PYTHONUTF8` environment variable. | ||||
| * See `PEP-540` for details on exactly what this changes. */ | * See `PEP-540` for details on exactly what this changes. */ | ||||
| Py_UTF8Mode = 1; | preconfig.utf8_mode = true; | ||||
| /* Note that there is no reason to call #Py_PreInitializeFromBytesArgs here | |||||
| * as this is only used so that command line arguments can be handled by Python itself, | |||||
| * not for setting `sys.argv` (handled below). */ | |||||
| status = Py_PreInitialize(&preconfig); | |||||
| pystatus_exit_on_error(status); | |||||
| } | |||||
| /* Must run before python initializes, but after #PyPreConfig. */ | |||||
| PyImport_ExtendInittab(bpy_internal_modules); | |||||
| /* #PyConfig (initialize Python). */ | |||||
| { | |||||
| PyConfig config; | |||||
| PyStatus status; | |||||
| bool has_python_executable = false; | |||||
| PyConfig_InitPythonConfig(&config); | |||||
| /* Suppress error messages when calculating the module search path. | /* Suppress error messages when calculating the module search path. | ||||
| * While harmless, it's noisy. */ | * While harmless, it's noisy. */ | ||||
| Py_FrozenFlag = 1; | config.pathconfig_warnings = 0; | ||||
| /* Only use the systems environment variables and site when explicitly requested. | /* When using the system's Python, allow the site-directory as well. */ | ||||
| * Since an incorrect 'PYTHONPATH' causes difficult to debug errors, see: T72807. */ | config.user_site_directory = py_use_system_env; | ||||
| Py_IgnoreEnvironmentFlag = !py_use_system_env; | |||||
| Py_NoUserSiteDirectory = !py_use_system_env; | |||||
| /* Initialize Python (also acquires lock). */ | /* While `sys.argv` is set, we don't want Python to interpret it. */ | ||||
| Py_Initialize(); | config.parse_argv = 0; | ||||
| status = PyConfig_SetBytesArgv(&config, argc, (char *const *)argv); | |||||
| pystatus_exit_on_error(status); | |||||
| /* We could convert to #wchar_t then pass to #PySys_SetArgv (or use #PyConfig in Python 3.8+). | /* Needed for Python's initialization for portable Python installations. | ||||
| * However this risks introducing subtle changes in encoding that are hard to track down. | * We could use #Py_SetPath, but this overrides Python's internal logic | ||||
| * for calculating it's own module search paths. | |||||
| * | * | ||||
| * So rely on #PyC_UnicodeFromByte since it's a tried & true way of getting paths | * `sys.executable` is overwritten after initialization to the Python binary. */ | ||||
| * that include non `utf-8` compatible characters, see: T20021. */ | |||||
| { | { | ||||
| PyObject *py_argv = PyList_New(argc); | const char *program_path = BKE_appdir_program_path(); | ||||
| for (int i = 0; i < argc; i++) { | status = PyConfig_SetBytesString(&config, &config.program_name, program_path); | ||||
| PyList_SET_ITEM(py_argv, i, PyC_UnicodeFromByte(argv[i])); | pystatus_exit_on_error(status); | ||||
| } | |||||
| PySys_SetObject("argv", py_argv); | |||||
| Py_DECREF(py_argv); | |||||
| } | } | ||||
| /* Setting the program name is important so the 'multiprocessing' module | /* Setting the program name is important so the 'multiprocessing' module | ||||
| * can launch new Python instances. */ | * can launch new Python instances. */ | ||||
| { | { | ||||
| const char *sys_variable = "executable"; | |||||
| char program_path[FILE_MAX]; | char program_path[FILE_MAX]; | ||||
| if (BKE_appdir_program_python_search( | if (BKE_appdir_program_python_search( | ||||
| program_path, sizeof(program_path), PY_MAJOR_VERSION, PY_MINOR_VERSION)) { | program_path, sizeof(program_path), PY_MAJOR_VERSION, PY_MINOR_VERSION)) { | ||||
| PyObject *py_program_path = PyC_UnicodeFromByte(program_path); | status = PyConfig_SetBytesString(&config, &config.executable, program_path); | ||||
| PySys_SetObject(sys_variable, py_program_path); | pystatus_exit_on_error(status); | ||||
| Py_DECREF(py_program_path); | has_python_executable = true; | ||||
| } | } | ||||
| else { | else { | ||||
| /* Set to `sys.executable = None` below (we can't do before Python is initialized). */ | |||||
| fprintf(stderr, | fprintf(stderr, | ||||
| "Unable to find the python binary, " | "Unable to find the python binary, " | ||||
| "the multiprocessing module may not be functional!\n"); | "the multiprocessing module may not be functional!\n"); | ||||
| PySys_SetObject(sys_variable, Py_None); | } | ||||
| } | |||||
| /* Allow to use our own included Python. `py_path_bundle` may be NULL. */ | |||||
| { | |||||
| const char *py_path_bundle = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON, NULL); | |||||
| # ifdef __APPLE__ | |||||
| /* OSX allow file/directory names to contain : character (represented as / in the Finder) | |||||
| * but current Python lib (release 3.1.1) doesn't handle these correctly */ | |||||
| if (strchr(py_path_bundle, ':')) { | |||||
| fprintf(stderr, | |||||
| "Warning! Blender application is located in a path containing ':' or '/' chars\n" | |||||
| "This may make python import function fail\n"); | |||||
| } | |||||
| # endif | |||||
| if (py_path_bundle != NULL) { | |||||
| status = PyConfig_SetBytesString(&config, &config.home, py_path_bundle); | |||||
| pystatus_exit_on_error(status); | |||||
| } | |||||
| else { | |||||
| /* Common enough to use the system Python on Linux/Unix, warn on other systems. */ | |||||
| # if defined(__APPLE__) || defined(_WIN32) | |||||
| fprintf(stderr, | |||||
| "Bundled Python not found and is expected on this platform " | |||||
| "(the 'install' target may have not been built)\n"); | |||||
| # endif | |||||
| } | |||||
| } | |||||
| /* Initialize Python (also acquires lock). */ | |||||
| status = Py_InitializeFromConfig(&config); | |||||
| pystatus_exit_on_error(status); | |||||
| if (!has_python_executable) { | |||||
| PySys_SetObject("executable", Py_None); | |||||
| } | } | ||||
| } | } | ||||
| # ifdef WITH_FLUID | # ifdef WITH_FLUID | ||||
| /* Required to prevent assertion error, see: | /* Required to prevent assertion error, see: | ||||
| * https://stackoverflow.com/questions/27844676 */ | * https://stackoverflow.com/questions/27844676 */ | ||||
| Py_DECREF(PyImport_ImportModule("threading")); | Py_DECREF(PyImport_ImportModule("threading")); | ||||
| # endif | # endif | ||||
| Show All 33 Lines | #endif | ||||
| BPy_init_modules(C); | BPy_init_modules(C); | ||||
| pyrna_alloc_types(); | pyrna_alloc_types(); | ||||
| #ifndef WITH_PYTHON_MODULE | #ifndef WITH_PYTHON_MODULE | ||||
| /* py module runs atexit when bpy is freed */ | /* py module runs atexit when bpy is freed */ | ||||
| BPY_atexit_register(); /* this can init any time */ | BPY_atexit_register(); /* this can init any time */ | ||||
| py_tstate = PyGILState_GetThisThreadState(); | /* Free the lock acquired (implicitly) when Python is initialized. */ | ||||
| PyEval_ReleaseThread(py_tstate); | PyEval_ReleaseThread(PyGILState_GetThisThreadState()); | ||||
| #endif | #endif | ||||
| #ifdef WITH_PYTHON_MODULE | #ifdef WITH_PYTHON_MODULE | ||||
| /* Disable all add-ons at exit, not essential, it just avoids resource leaks, see T71362. */ | /* Disable all add-ons at exit, not essential, it just avoids resource leaks, see T71362. */ | ||||
| BPY_run_string_eval(C, | BPY_run_string_eval(C, | ||||
| (const char *[]){"atexit", "addon_utils", NULL}, | (const char *[]){"atexit", "addon_utils", NULL}, | ||||
| "atexit.register(addon_utils.disable_all)"); | "atexit.register(addon_utils.disable_all)"); | ||||
| #endif | #endif | ||||
| ▲ Show 20 Lines • Show All 383 Lines • Show Last 20 Lines | |||||