[Bf-blender-cvs] [f7a4ede79f9] master: Python: change bpy.app.binary_path behavior WITH_PYTHON_MODULE

Campbell Barton noreply at git.blender.org
Fri Sep 9 06:06:11 CEST 2022


Commit: f7a4ede79f9512f39db8632ff112e08a93f3a9d4
Author: Campbell Barton
Date:   Fri Sep 9 13:59:53 2022 +1000
Branches: master
https://developer.blender.org/rBf7a4ede79f9512f39db8632ff112e08a93f3a9d4

Python: change bpy.app.binary_path behavior WITH_PYTHON_MODULE

The following changes have been made to this attribute with
WITH_PYTHON_MODULE is defined:

- Defaults to an empty string (instead of pointing to __init__.so).
- It's writable, so script authors can point to a valid Blender binary.

`where_am_i(..)` is no longer used by BKE_appdir_program_path_init,
there is now a separate code-path for setting the initial program
directory, calls after this can be used to set the binary path.

===================================================================

M	source/blender/blenkernel/intern/appdir.c
M	source/blender/python/intern/bpy_app.c

===================================================================

diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index 845a890ba8b..295e85a5fc4 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -782,6 +782,7 @@ const char *BKE_appdir_folder_id_version(const int folder_id,
  * Access locations of Blender & Python.
  * \{ */
 
+#ifndef WITH_PYTHON_MODULE
 /**
  * Checks if name is a fully qualified filename to an executable.
  * If not it searches `$PATH` for the file. On Windows it also
@@ -793,14 +794,12 @@ const char *BKE_appdir_folder_id_version(const int folder_id,
  * \param fullname: The full path and full name of the executable
  * (must be #FILE_MAX minimum)
  * \param name: The name of the executable (usually `argv[0]`) to be checked
- * \param strict: When true, use `argv0` unmodified (besides making absolute & normalizing).
- * Otherwise other methods may be used to find the program path, including searching `$PATH`.
  */
-static void where_am_i(char *fullname, const size_t maxlen, const char *name, const bool strict)
+static void where_am_i(char *fullname, const size_t maxlen, const char *name)
 {
-#ifdef WITH_BINRELOC
+#  ifdef WITH_BINRELOC
   /* Linux uses `binreloc` since `argv[0]` is not reliable, call `br_init(NULL)` first. */
-  if (!strict) {
+  {
     const char *path = NULL;
     path = br_find_exe(NULL);
     if (path) {
@@ -809,9 +808,9 @@ static void where_am_i(char *fullname, const size_t maxlen, const char *name, co
       return;
     }
   }
-#endif
+#  endif
 
-#ifdef _WIN32
+#  ifdef _WIN32
   if (!strict) {
     wchar_t *fullname_16 = MEM_mallocN(maxlen * sizeof(wchar_t), "ProgramPath");
     if (GetModuleFileNameW(0, fullname_16, maxlen)) {
@@ -827,7 +826,7 @@ static void where_am_i(char *fullname, const size_t maxlen, const char *name, co
 
     MEM_freeN(fullname_16);
   }
-#endif
+#  endif
 
   /* Unix and non Linux. */
   if (name && name[0]) {
@@ -835,36 +834,35 @@ static void where_am_i(char *fullname, const size_t maxlen, const char *name, co
     BLI_strncpy(fullname, name, maxlen);
     if (name[0] == '.') {
       BLI_path_abs_from_cwd(fullname, maxlen);
-#ifdef _WIN32
+#  ifdef _WIN32
       if (!strict) {
         BLI_path_program_extensions_add_win32(fullname, maxlen);
       }
-#endif
+#  endif
     }
     else if (BLI_path_slash_rfind(name)) {
       /* Full path. */
       BLI_strncpy(fullname, name, maxlen);
-#ifdef _WIN32
+#  ifdef _WIN32
       if (!strict) {
         BLI_path_program_extensions_add_win32(fullname, maxlen);
       }
-#endif
+#  endif
     }
     else {
-      if (!strict) {
-        BLI_path_program_search(fullname, maxlen, name);
-      }
+      BLI_path_program_search(fullname, maxlen, name);
     }
     /* Remove "/./" and "/../" so string comparisons can be used on the path. */
     BLI_path_normalize(NULL, fullname);
 
-#if defined(DEBUG)
+#  if defined(DEBUG)
     if (!STREQ(name, fullname)) {
       CLOG_INFO(&LOG, 2, "guessing '%s' == '%s'", name, fullname);
     }
-#endif
+#  endif
   }
 }
+#endif /* WITH_PYTHON_MODULE */
 
 void BKE_appdir_program_path_init(const char *argv0)
 {
@@ -872,17 +870,28 @@ void BKE_appdir_program_path_init(const char *argv0)
   /* NOTE(@campbellbarton): Always use `argv[0]` as is, when building as a Python module.
    * Otherwise other methods of detecting the binary that override this argument
    * which must point to the Python module for data-files to be detected. */
-  const bool strict = true;
+  STRNCPY(g_app.program_filepath, argv0);
+  BLI_path_abs_from_cwd(g_app.program_filepath, sizeof(g_app.program_filepath));
+  BLI_path_normalize(NULL, g_app.program_filepath);
+
+  if (g_app.program_dirname[0] == '\0') {
+    /* First time initializing, the file binary path isn't valid from a Python module.
+     * Calling again must set the `filepath` and leave the directory as-is. */
+    BLI_split_dir_part(
+        g_app.program_filepath, g_app.program_dirname, sizeof(g_app.program_dirname));
+    g_app.program_filepath[0] = '\0';
+  }
 #else
-  const bool strict = false;
-#endif
-  where_am_i(g_app.program_filepath, sizeof(g_app.program_filepath), argv0, strict);
+  where_am_i(g_app.program_filepath, sizeof(g_app.program_filepath), argv0);
   BLI_split_dir_part(g_app.program_filepath, g_app.program_dirname, sizeof(g_app.program_dirname));
+#endif
 }
 
 const char *BKE_appdir_program_path(void)
 {
+#ifndef WITH_PYTHON_MODULE /* Default's to empty when building as as Python module. */
   BLI_assert(g_app.program_filepath[0]);
+#endif
   return g_app.program_filepath;
 }
 
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index 939473ceaa0..a0129157b95 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -79,8 +79,6 @@ static PyStructSequence_Field app_info_fields[] = {
     {"version_string", "The Blender version formatted as a string"},
     {"version_cycle", "The release status of this build alpha/beta/rc/release"},
     {"version_char", "Deprecated, always an empty string"},
-    {"binary_path",
-     "The location of Blender's executable, useful for utilities that open new instances"},
     {"background",
      "Boolean, True when blender is running without a user interface (started with -b)"},
     {"factory_startup", "Boolean, True when blender is running with --factory-startup)"},
@@ -151,7 +149,6 @@ static PyObject *make_app_info(void)
 
   SetStrItem(STRINGIFY(BLENDER_VERSION_CYCLE));
   SetStrItem("");
-  SetStrItem(BKE_appdir_program_path());
   SetObjItem(PyBool_FromLong(G.background));
   SetObjItem(PyBool_FromLong(G.factory_startup));
 
@@ -345,6 +342,33 @@ static PyObject *bpy_app_autoexec_fail_message_get(PyObject *UNUSED(self), void
   return PyC_UnicodeFromByte(G.autoexec_fail);
 }
 
+PyDoc_STRVAR(bpy_app_binary_path_doc,
+             "The location of Blender's executable, useful for utilities that open new instances. "
+             "Read-only unless Blender is built as a Python module - in this case the value is "
+             "an empty string which script authors may point to a Blender binary.");
+static PyObject *bpy_app_binary_path_get(PyObject *UNUSED(self), void *UNUSED(closure))
+{
+  return PyC_UnicodeFromByte(BKE_appdir_program_path());
+}
+
+static int bpy_app_binary_path_set(PyObject *UNUSED(self), PyObject *value, void *UNUSED(closure))
+{
+#ifndef WITH_PYTHON_MODULE
+  PyErr_SetString(PyExc_AttributeError,
+                  "bpy.app.binary_path is only writable when built as a Python module");
+  return -1;
+#endif
+  PyObject *value_coerce = NULL;
+  const char *filepath = PyC_UnicodeAsByte(value, &value_coerce);
+  if (filepath == NULL) {
+    PyErr_Format(PyExc_ValueError, "expected a string or bytes, got %s", Py_TYPE(value)->tp_name);
+    return -1;
+  }
+  BKE_appdir_program_path_init(filepath);
+  Py_XDECREF(value_coerce);
+  return 0;
+}
+
 static PyGetSetDef bpy_app_getsets[] = {
     {"debug", bpy_app_debug_get, bpy_app_debug_set, bpy_app_debug_doc, (void *)G_DEBUG},
     {"debug_ffmpeg",
@@ -450,7 +474,14 @@ static PyGetSetDef bpy_app_getsets[] = {
      (void *)G_FLAG_SCRIPT_AUTOEXEC_FAIL_QUIET},
     {"autoexec_fail_message", bpy_app_autoexec_fail_message_get, NULL, NULL, NULL},
 
-    /* End-of-list marker. */
+    /* Support script authors setting the Blender binary path to use, otherwise this value
+     * is not known when built as a Python module. */
+    {"binary_path",
+     bpy_app_binary_path_get,
+     bpy_app_binary_path_set,
+     bpy_app_binary_path_doc,
+     NULL},
+
     {NULL, NULL, NULL, NULL, NULL},
 };



More information about the Bf-blender-cvs mailing list