diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index ae5d028da71..52797f73160 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -27,8 +27,9 @@ Initialization, Finalization, and Threads Initialize the Python interpreter. In an application embedding Python, this should be called before using any other Python/C API functions; with the - exception of :cfunc:`Py_SetProgramName`, :cfunc:`PyEval_InitThreads`, - :cfunc:`PyEval_ReleaseLock`, and :cfunc:`PyEval_AcquireLock`. This initializes + exception of :cfunc:`Py_SetProgramName`, :cfunc:`Py_SetPath`, + :cfunc:`PyEval_InitThreads`, :cfunc:`PyEval_ReleaseLock`, and + :cfunc:`PyEval_AcquireLock`. This initializes the table of loaded modules (``sys.modules``), and creates the fundamental modules :mod:`builtins`, :mod:`__main__` and :mod:`sys`. It also initializes the module search path (``sys.path``). It does not set ``sys.argv``; use @@ -256,6 +257,7 @@ Initialization, Finalization, and Threads .. index:: triple: module; search; path single: path (in module sys) + single: Py_SetPath() Return the default module search path; this is computed from the program name (set by :cfunc:`Py_SetProgramName` above) and some environment variables. @@ -270,6 +272,25 @@ Initialization, Finalization, and Threads .. XXX should give the exact rules +.. cfunction:: void Py_SetPath(const wchar_t *) + + .. index:: + triple: module; search; path + single: path (in module sys) + single: Py_GetPath() + + Set the default module search path. If this function is called before + :cfunc: `Py_Initialize` then :cfunc: Py_GetPath won't attempt to compute + a default serarch path but uses the provided one in stead. This is useful + if Python is being embedded by an application that has full knowledge + of the location of all modules. The path components should be separated + by semicolons. + + This also causes `sys.executable` to be set only to the raw program name + (see :cfunc:`Py_SetProgramName`) and `for sys.prefix` and + `sys.exec_prefix` to be empty. It is up to the caller to modify these if + required after calling :cfunc: `Py_Initialize`. + .. cfunction:: const char* Py_GetVersion() Return the version of this Python interpreter. This is a string that looks diff --git a/Include/pythonrun.h b/Include/pythonrun.h index b9da550469f..108b6473799 100644 --- a/Include/pythonrun.h +++ b/Include/pythonrun.h @@ -113,6 +113,7 @@ PyAPI_FUNC(wchar_t *) Py_GetProgramFullPath(void); PyAPI_FUNC(wchar_t *) Py_GetPrefix(void); PyAPI_FUNC(wchar_t *) Py_GetExecPrefix(void); PyAPI_FUNC(wchar_t *) Py_GetPath(void); +PyAPI_FUNC(void) Py_SetPath(const wchar_t *); /* In their own files */ PyAPI_FUNC(const char *) Py_GetVersion(void); diff --git a/Modules/getpath.c b/Modules/getpath.c index c55b3d74be1..6f2e5371c86 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -90,6 +90,9 @@ * known use of sys.prefix and sys.exec_prefix is for the ILU installation * process to find the installed Python tree. * + * An embedding application can use Py_SetPath() to override all of + * these authomatic path computations. + * * NOTE: Windows MSVC builds use PC/getpathp.c instead! */ @@ -771,6 +774,23 @@ calculate_path(void) /* External interface */ +void +Py_SetPath(const wchar_t *path) +{ + if (module_search_path != NULL) { + free(module_search_path); + module_search_path = NULL; + } + if (path != NULL) { + extern wchar_t *Py_GetProgramName(void); + wchar_t *prog = Py_GetProgramName(); + wcsncpy(progpath, prog, MAXPATHLEN); + exec_prefix[0] = prefix[0] = L'\0'; + module_search_path = malloc((wcslen(path) + 1) * sizeof(wchar_t)); + if (module_search_path != NULL) + wcscpy(module_search_path, path); + } +} wchar_t * Py_GetPath(void) diff --git a/PC/getpathp.c b/PC/getpathp.c index 0fe04c7fa44..3a87411d0fd 100644 --- a/PC/getpathp.c +++ b/PC/getpathp.c @@ -51,6 +51,9 @@ exe, some very strange installation setup) you get a path with some default, but relative, paths. + * An embedding application can use Py_SetPath() to override all of + these authomatic path computations. + ---------------------------------------------------------------- */ @@ -79,6 +82,9 @@ * The approach is an adaptation for Windows of the strategy used in * ../Modules/getpath.c; it uses the Windows Registry as one of its * information sources. + * + * Py_SetPath() can be used to override this mechanism. Call Py_SetPath + * with a semicolon separated path prior to calling Py_Initialize. */ #ifndef LANDMARK @@ -654,6 +660,24 @@ calculate_path(void) /* External interface */ +void +Py_SetPath(const wchar_t *path) +{ + if (module_search_path != NULL) { + free(module_search_path); + module_search_path = NULL; + } + if (path != NULL) { + extern wchar_t *Py_GetProgramName(void); + wchar_t *prog = Py_GetProgramName(); + wcsncpy(progpath, prog, MAXPATHLEN); + prefix[0] = L'\0'; + module_search_path = malloc((wcslen(path) + 1) * sizeof(wchar_t)); + if (module_search_path != NULL) + wcscpy(module_search_path, path); + } +} + wchar_t * Py_GetPath(void) {