From 03b5b4e07f3e5020804f2ed2ba385929315dc840 Mon Sep 17 00:00:00 2001
From: tytan652 <tytan652@tytanium.xyz>
Date: Wed, 10 Jun 2026 11:36:17 +0200
Subject: [PATCH] obs-scripting: Replace PySys_SetArgv with recent Python
 method

---
 .../obs-scripting-python-import.c             | 13 ++-
 .../obs-scripting-python-import.h             | 14 +++
 shared/obs-scripting/obs-scripting-python.c   | 90 ++++++++++++++-----
 3 files changed, 95 insertions(+), 22 deletions(-)

diff --git a/shared/obs-scripting/obs-scripting-python-import.c b/shared/obs-scripting/obs-scripting-python-import.c
index 048c0326a9017b..c68c856fde2b3f 100644
--- a/shared/obs-scripting/obs-scripting-python-import.c
+++ b/shared/obs-scripting/obs-scripting-python-import.c
@@ -145,7 +145,9 @@ bool import_python(const char *python_path, python_version_t *python_version)
 	}
 
 	IMPORT_FUNC(PyEval_ReleaseThread);
-	IMPORT_FUNC(PySys_SetArgv);
+	if (python_version->major == 3 && python_version->minor < 8) {
+		IMPORT_FUNC(PySys_SetArgv);
+	}
 	IMPORT_FUNC(PyImport_ImportModule);
 	IMPORT_FUNC(PyObject_CallFunctionObjArgs);
 	IMPORT_FUNC(_Py_NotImplementedStruct);
@@ -197,6 +199,15 @@ bool import_python(const char *python_path, python_version_t *python_version)
 #if defined(Py_DEBUG) || PY_VERSION_HEX >= 0x030900b0
 	IMPORT_FUNC(_Py_Dealloc);
 #endif
+#if PY_VERSION_HEX >= 0x03080000
+	if (python_version->major == 3 && python_version->minor >= 8) {
+		IMPORT_FUNC(PyWideStringList_Append);
+		IMPORT_FUNC(PyConfig_InitPythonConfig);
+		IMPORT_FUNC(PyConfig_Clear);
+		IMPORT_FUNC(Py_InitializeFromConfig);
+		IMPORT_FUNC(PyStatus_Exception);
+	}
+#endif
 #undef IMPORT_FUNC
 	success = true;
 
diff --git a/shared/obs-scripting/obs-scripting-python-import.h b/shared/obs-scripting/obs-scripting-python-import.h
index 3887ce48ec5250..6674164ee99b62 100644
--- a/shared/obs-scripting/obs-scripting-python-import.h
+++ b/shared/obs-scripting/obs-scripting-python-import.h
@@ -134,6 +134,13 @@ PY_EXTERN int (*Import_PyType_GetFlags)(PyTypeObject *o);
 #if defined(Py_DEBUG) || PY_VERSION_HEX >= 0x030900b0
 PY_EXTERN void (*Import__Py_Dealloc)(PyObject *obj);
 #endif
+#if PY_VERSION_HEX >= 0x03080000
+PY_EXTERN PyStatus (*Import_PyWideStringList_Append)(PyWideStringList *list, const wchar_t *item);
+PY_EXTERN void (*Import_PyConfig_InitPythonConfig)(PyConfig *config);
+PY_EXTERN void (*Import_PyConfig_Clear)(PyConfig *config);
+PY_EXTERN PyStatus (*Import_Py_InitializeFromConfig)(const PyConfig *config);
+PY_EXTERN int (*Import_PyStatus_Exception)(PyStatus err);
+#endif
 
 PY_EXTERN PyTypeObject PyCFunction_Type;
 
@@ -222,6 +229,13 @@ extern bool import_python(const char *python_path, python_version_t *python_vers
 #if defined(Py_DEBUG) || PY_VERSION_HEX >= 0x030900b0
 #define _Py_Dealloc Import__Py_Dealloc
 #endif
+#if PY_VERSION_HEX >= 0x03080000
+#define PyWideStringList_Append Import_PyWideStringList_Append
+#define PyConfig_InitPythonConfig Import_PyConfig_InitPythonConfig
+#define PyConfig_Clear Import_PyConfig_Clear
+#define Py_InitializeFromConfig Import_Py_InitializeFromConfig
+#define PyStatus_Exception Import_PyStatus_Exception
+#endif
 
 #if PY_VERSION_HEX >= 0x030800f0
 static inline void Import__Py_DECREF(const char *filename, int lineno, PyObject *op)
diff --git a/shared/obs-scripting/obs-scripting-python.c b/shared/obs-scripting/obs-scripting-python.c
index 4b391282adb877..a055785fbd5daa 100644
--- a/shared/obs-scripting/obs-scripting-python.c
+++ b/shared/obs-scripting/obs-scripting-python.c
@@ -1594,6 +1594,65 @@ extern void add_python_frontend_funcs(PyObject *module);
 
 static bool python_loaded_at_all = false;
 
+#if RUNTIME_LINK || PY_VERSION_HEX < 0x03070000
+static bool python_pre37_init_threads()
+{
+	PyEval_InitThreads();
+	if (!PyEval_ThreadsInitialized())
+		return false;
+
+	return true;
+}
+#endif
+
+#if RUNTIME_LINK || PY_VERSION_HEX < 0x03080000
+static bool python_pre38_init()
+{
+	Py_Initialize();
+	if (!Py_IsInitialized())
+		return false;
+
+#if RUNTIME_LINK
+	if (python_version.minor < 7 && !python_pre37_init_threads())
+		return false;
+#elif PY_VERSION_HEX < 0x03070000
+	if (!python_pre37_init_threads())
+		return false;
+#endif
+
+	/* ---------------------------------------------- */
+	/* Must set arguments for guis to work            */
+
+	wchar_t *argv[] = {L"", NULL};
+	int argc = sizeof(argv) / sizeof(wchar_t *) - 1;
+
+	PySys_SetArgv(argc, argv);
+
+	return true;
+}
+#endif
+
+#if RUNTIME_LINK || PY_VERSION_HEX >= 0x03080000
+static bool python_init()
+{
+	PyConfig config;
+	PyConfig_InitPythonConfig(&config);
+
+	/* ---------------------------------------------- */
+	/* Must set arguments for guis to work            */
+	config.parse_argv = 1;
+	PyWideStringList_Append(&config.argv, L"");
+
+	PyStatus status = Py_InitializeFromConfig(&config);
+	PyConfig_Clear(&config);
+
+	if (PyStatus_Exception(status))
+		return false;
+
+	return true;
+}
+#endif
+
 bool obs_scripting_load_python(const char *python_path)
 {
 	if (python_loaded)
@@ -1621,33 +1680,22 @@ bool obs_scripting_load_python(const char *python_path)
 	UNUSED_PARAMETER(python_path);
 #endif
 
-	Py_Initialize();
-	if (!Py_IsInitialized())
-		return false;
-
 #if RUNTIME_LINK
-	if (python_version.major == 3 && python_version.minor < 7) {
-		PyEval_InitThreads();
-		if (!PyEval_ThreadsInitialized())
+	if (python_version.minor < 8) {
+		if (!python_pre38_init())
+			return false;
+	} else {
+		if (!python_init())
 			return false;
 	}
-#elif PY_VERSION_HEX < 0x03070000
-	PyEval_InitThreads();
-	if (!PyEval_ThreadsInitialized())
+#elif PY_VERSION_HEX < 0x03080000
+	if (!python_pre38_init())
+		return false;
+#else
+	if (!python_init())
 		return false;
 #endif
 
-	/* ---------------------------------------------- */
-	/* Must set arguments for guis to work            */
-
-	wchar_t *argv[] = {L"", NULL};
-	int argc = sizeof(argv) / sizeof(wchar_t *) - 1;
-
-	PRAGMA_WARN_PUSH
-	PRAGMA_WARN_DEPRECATION
-	PySys_SetArgv(argc, argv);
-	PRAGMA_WARN_POP
-
 #ifdef __APPLE__
 	PyRun_SimpleString("import sys");
 	PyRun_SimpleString("sys.dont_write_bytecode = True");
