Skip to content

Embedded Python on Windows, site_import=0: sys.path contains executable path rather than sys.prefix #135769

Open
@boimart1

Description

@boimart1

Bug report

Bug description:

I'm noticing a discrepancy between running embedded Python with isolated=1 and site_import=0, and running a Python script with the equivalent flags -I -S. I'm unsure if this is intentional or not, or if this has any actual consequences, so I'm reporting it to be sure. This is potentially related to #131484.

The difference I'm seeing is that when running a python script, the 4th path in sys.path is C:\Python313; running an embedded application, the 4th path is the embedding executable's parent directory, e.g. C:\Work\Demos\py-embed-path\build\Debug.

In fact, in both cases, the 4th path is sys.executable's parent directory. But for embedded applications, I'm unsure if this is intentional, or if it should in fact also be C:\Python313, the directory containing python313.dll that the executable loaded.

To reproduce

On Windows, with Python 3.13.3 installed, given the following source files:

# script.py
import sys, os

print(f'{sys.executable=}')
print(f'{sys.prefix=}')
print(f'{os.getcwd()=}')

print('sys.path:')
for path in sys.path:
    print(f'- {path}')
// main.cpp
#include <Python.h>

int main() {
    PyConfig config;
    PyConfig_InitIsolatedConfig(&config);
    config.site_import = 0;

    PyStatus s = Py_InitializeFromConfig(&config);
    PyConfig_Clear(&config);

    if (PyStatus_Exception(s)) {
        Py_ExitStatusException(s);
    }

    PyRun_SimpleString(R"(
import sys, os

print(f'{sys.executable=}')
print(f'{sys.prefix=}')
print(f'{os.getcwd()=}')

print('sys.path:')
for path in sys.path:
    print(f'- {path}')
)");

    Py_Finalize();
    return 0;
}
# CMakeLists.txt
cmake_minimum_required(VERSION 3.12)
project(PythonPathRepro)
find_package(Python3 3.13 REQUIRED COMPONENTS Development.Embed)
add_executable(python_path_repro main.cpp)
target_link_libraries(python_path_repro PRIVATE Python3::Python)

if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
  # disable Python's auto-linking
  target_link_options(python_path_repro PRIVATE "/NODEFAULTLIB:python313_d.lib" "/NODEFAULTLIB:python313.lib")
endif()

Running the python script with the -I -S flags produces the following:

λ py -3.13 -I -S script.py
sys.executable='C:\\Python313\\python.exe'
sys.prefix='C:\\Python313'
os.getcwd()='C:\\Work\\Demos\\py-embed-path'
sys.path:
- C:\Python313\python313.zip
- C:\Python313\DLLs
- C:\Python313\Lib
- C:\Python313

Compiling and running the C++ code produces the following:

(I made sure to run the code from a different directory than the executable to demonstrate that the path is deduced from the executable, not from the cwd)

λ build\Debug\python_path_repro.exe 
sys.executable='C:\\Work\\Demos\\py-embed-path\\build\\Debug\\python_path_repro.exe'
sys.prefix='C:\\Python313'
os.getcwd()='C:\\Work\\Demos\\py-embed-path'
sys.path:
- C:\Python313\python313.zip
- C:\Python313\DLLs
- C:\Python313\Lib
- C:\Work\Demos\py-embed-path\build\Debug

These two modes of executions produce a different value for the fourth item in sys.path.

Notes

I understand that the repro above is not the usual use-case for embedded Python, and that it's better to include the Python "Windows embeddable package" in the app and use that, and possibly fully control sys.path through config.search_module_paths or python313._pth in the embeddable package. I am indeed using the embeddable package for the actual app. But the use-case I'm working with here is rather when building and running unit tests on developers' machines using their Python installation. Installing the embeddable package just to run the unit tests is something I would like to avoid, if possible, considering a full Python installation is already required to build the library and tests in the first place.

As I stated above, this difference in behavior is not actually causing any problems for the moment. I'm just reporting it in case it could potentially cause problems in the future, and to understand if this behavior is intended or not.

p.s. is there a reason for sys.path to contain C:\Python313 when running scripts with python.exe? By default, Python does not seem to have any modules available there. And the embeddable package which does have modules in its root directory also provides a python313._pth which overrides sys.path to include ..

CPython versions tested on:

3.13

Operating systems tested on:

Windows

Metadata

Metadata

Assignees

No one assigned

    Labels

    OS-windowsinterpreter-core(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions