@@ -1197,6 +1197,32 @@ void qSlicerCoreApplication::handleURIArguments(const QStringList& fileNames)
11971197CTK_GET_CPP (qSlicerCoreApplication, bool , isURIArgumentHandlingEnabled, URIArgumentHandlingEnabled);
11981198CTK_SET_CPP (qSlicerCoreApplication, bool , setURIArgumentHandlingEnabled, URIArgumentHandlingEnabled);
11991199
1200+ // -----------------------------------------------------------------------------
1201+ namespace
1202+ {
1203+
1204+ // Mirrors CPython's PyWideStringList_Clear only available internally:
1205+ // Items in PyWideStringList are allocated with the "raw" allocator;
1206+ // free them with PyMem_RawFree (mirrors CPython).
1207+ void ClearWideStringList (PyWideStringList* list)
1208+ {
1209+ if (!list || !list->items )
1210+ {
1211+ list->length = 0 ;
1212+ list->items = nullptr ;
1213+ return ;
1214+ }
1215+ for (Py_ssize_t i = 0 ; i < list->length ; ++i)
1216+ {
1217+ PyMem_RawFree (list->items [i]);
1218+ }
1219+ PyMem_RawFree (list->items );
1220+ list->length = 0 ;
1221+ list->items = nullptr ;
1222+ }
1223+
1224+ } // namespace
1225+
12001226// -----------------------------------------------------------------------------
12011227void qSlicerCoreApplication::handleCommandLineArguments ()
12021228{
@@ -1218,9 +1244,9 @@ void qSlicerCoreApplication::handleCommandLineArguments()
12181244#else
12191245 if (!qSlicerCoreApplication::testAttribute (qSlicerCoreApplication::AA_DisablePython))
12201246 {
1221- // Snapshot current sys.path BEFORE applying the config
1222- // Rationale: _PyInterpreterState_SetConfig will replace sys.path from config.
1223- // We want an exact restore of the sys.path augmented during Slicer module discovery .
1247+ // Snapshot current sys.path BEFORE applying the config.
1248+ // Rationale: _PyInterpreterState_SetConfig replaces sys.path from the config.
1249+ // We capture the runtime-augmented sys.path so we can install it into the config .
12241250 PythonQtObjectPtr sys;
12251251 sys.setNewRef (PyImport_ImportModule (" sys" ));
12261252 PythonQtObjectPtr sysPath;
@@ -1275,6 +1301,23 @@ void qSlicerCoreApplication::handleCommandLineArguments()
12751301 qSlicerCoreApplication::terminate (EXIT_FAILURE);
12761302 }
12771303
1304+ // Preserve runtime-augmented sys.path in the config itself.
1305+ // Set module_search_paths_set=1 BEFORE PyConfig_SetArgv so argv changes
1306+ // won't trigger a path recompute that drops Slicer inserts.
1307+ ClearWideStringList (&config.module_search_paths );
1308+ config.module_search_paths_set = 1 ;
1309+
1310+ for (const QString& path : savedSysPath)
1311+ {
1312+ const std::wstring w = path.toStdWString ();
1313+ PyStatus status = PyWideStringList_Append (&config.module_search_paths , w.c_str ());
1314+ if (PyStatus_Exception (status))
1315+ {
1316+ PyConfig_Clear (&config);
1317+ Py_ExitStatusException (status);
1318+ }
1319+ }
1320+
12781321 // Apply updated command-line arguments to the interpreter.
12791322 PyStatus status = PyConfig_SetArgv (&config, pythonArgc, pythonArgv);
12801323 if (PyStatus_Exception (status))
@@ -1292,9 +1335,6 @@ void qSlicerCoreApplication::handleCommandLineArguments()
12921335 qSlicerCoreApplication::terminate (EXIT_FAILURE);
12931336 }
12941337
1295- // Restore sys.path exactly as it was before calling "_PyInterpreterState_SetConfig"
1296- PythonQt::self ()->overwriteSysPath (savedSysPath);
1297-
12981338 PyConfig_Clear (&config);
12991339
13001340 // Set 'sys.executable' so that Slicer can be used as a "regular" python interpreter
0 commit comments