Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions Lib/site.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,13 +458,6 @@ def venv(known_paths):
env = os.environ
if sys.platform == 'darwin' and '__PYVENV_LAUNCHER__' in env:
executable = sys._base_executable = os.environ['__PYVENV_LAUNCHER__']
elif sys.platform == 'win32' and '__PYVENV_LAUNCHER__' in env:
executable = sys.executable
import _winapi
sys._base_executable = _winapi.GetModuleFileName(0)
# bpo-35873: Clear the environment variable to avoid it being
# inherited by child processes.
del os.environ['__PYVENV_LAUNCHER__']
else:
executable = sys.executable
exe_dir, _ = os.path.split(os.path.abspath(executable))
Expand Down
8 changes: 2 additions & 6 deletions Lib/test/test_venv.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,6 @@ def test_prefixes(self):
"""
Test that the prefix values are as expected.
"""
#check our prefixes
self.assertEqual(sys.base_prefix, sys.prefix)
self.assertEqual(sys.base_exec_prefix, sys.exec_prefix)

# check a venv's prefixes
rmtree(self.env_dir)
self.run_with_capture(venv.create, self.env_dir)
Expand All @@ -139,8 +135,8 @@ def test_prefixes(self):
for prefix, expected in (
('prefix', self.env_dir),
('prefix', self.env_dir),
('base_prefix', sys.prefix),
('base_exec_prefix', sys.exec_prefix)):
('base_prefix', sys.base_prefix),
('base_exec_prefix', sys.base_exec_prefix)):
cmd[2] = 'import sys; print(sys.%s)' % prefix
out, err = check_output(cmd)
self.assertEqual(out.strip(), expected.encode())
Expand Down
2 changes: 1 addition & 1 deletion Lib/venv/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ def setup_python(self, context):

for suffix in suffixes:
src = os.path.join(dirname, suffix)
if os.path.exists(src):
if os.path.lexists(src):
copier(src, os.path.join(binpath, suffix))

if sysconfig.is_python_build(True):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixes path for :data:`sys.executable` when running from the Microsoft Store.
12 changes: 9 additions & 3 deletions PC/getpathp.c
Original file line number Diff line number Diff line change
Expand Up @@ -540,14 +540,20 @@ get_program_full_path(const _PyCoreConfig *core_config,
wchar_t program_full_path[MAXPATHLEN+1];
memset(program_full_path, 0, sizeof(program_full_path));

if (!GetModuleFileNameW(NULL, program_full_path, MAXPATHLEN)) {
/* GetModuleFileName should never fail when passed NULL */
return _Py_INIT_ERR("Cannot determine program path");
}

/* The launcher may need to force the executable path to a
* different environment, so override it here. */
pyvenv_launcher = _wgetenv(L"__PYVENV_LAUNCHER__");
if (pyvenv_launcher && pyvenv_launcher[0]) {
_wputenv_s(L"__PYVENV_BASE_EXECUTABLE__", program_full_path);
wcscpy_s(program_full_path, MAXPATHLEN+1, pyvenv_launcher);
} else if (!GetModuleFileNameW(NULL, program_full_path, MAXPATHLEN)) {
/* GetModuleFileName should never fail when passed NULL */
return _Py_INIT_ERR("Cannot determine program path");
/* bpo-35873: Clear the environment variable to avoid it being
* inherited by child processes. */
_wputenv_s(L"__PYVENV_LAUNCHER__", L"");
}

config->program_full_path = PyMem_RawMalloc(
Expand Down
218 changes: 90 additions & 128 deletions PC/python_uwp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <shellapi.h>
#include <shlobj.h>

#include <string>

#include <winrt\Windows.ApplicationModel.h>
#include <winrt\Windows.Storage.h>
Expand Down Expand Up @@ -46,170 +49,129 @@ set_user_base()
}
}

static const wchar_t *
get_argv0(const wchar_t *argv0)
static winrt::hstring
get_package_family()
{
winrt::hstring installPath;
const wchar_t *launcherPath;
wchar_t *buffer;
size_t len;

launcherPath = _wgetenv(L"__PYVENV_LAUNCHER__");
if (launcherPath && launcherPath[0]) {
len = wcslen(launcherPath) + 1;
buffer = (wchar_t *)malloc(sizeof(wchar_t) * len);
if (!buffer) {
Py_FatalError("out of memory");
return NULL;
}
if (wcscpy_s(buffer, len, launcherPath)) {
Py_FatalError("failed to copy to buffer");
return NULL;
}
return buffer;
}

try {
const auto package = winrt::Windows::ApplicationModel::Package::Current();
if (package) {
const auto install = package.InstalledLocation();
if (install) {
installPath = install.Path();
}
const auto id = package.Id();
return id ? id.FamilyName() : winrt::hstring();
}
}
catch (...) {
}

if (!installPath.empty()) {
len = installPath.size() + wcslen(PROGNAME) + 2;
} else {
len = wcslen(argv0) + wcslen(PROGNAME) + 1;
}
return winrt::hstring();
}

buffer = (wchar_t *)malloc(sizeof(wchar_t) * len);
if (!buffer) {
Py_FatalError("out of memory");
return NULL;
}
static int
set_process_name()
{
std::wstring executable, home;

if (!installPath.empty()) {
if (wcscpy_s(buffer, len, installPath.c_str())) {
Py_FatalError("failed to copy to buffer");
return NULL;
}
if (wcscat_s(buffer, len, L"\\")) {
Py_FatalError("failed to concatenate backslash");
return NULL;
}
} else {
if (wcscpy_s(buffer, len, argv0)) {
Py_FatalError("failed to copy argv[0]");
return NULL;
const auto family = get_package_family();

if (!family.empty()) {
PWSTR localAppData;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0,
NULL, &localAppData))) {
executable = std::wstring(localAppData)
+ L"\\Microsoft\\WindowsApps\\"
+ family
+ L"\\"
+ PROGNAME;

CoTaskMemFree(localAppData);
}
}

wchar_t *name = wcsrchr(buffer, L'\\');
if (name) {
name[1] = L'\0';
home.resize(MAX_PATH);
while (true) {
DWORD len = GetModuleFileNameW(
NULL, home.data(), (DWORD)home.size());
if (len == 0) {
home.clear();
break;
} else if (len == home.size() &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
home.resize(len * 2);
} else {
buffer[0] = L'\0';
home.resize(len);
size_t bslash = home.find_last_of(L"/\\");
if (bslash != std::wstring::npos) {
home.erase(bslash);
}
break;
}
}

if (wcscat_s(buffer, len, PROGNAME)) {
Py_FatalError("failed to concatenate program name");
return NULL;
if (executable.empty() && !home.empty()) {
executable = home + L"\\" + PROGNAME;
}

return buffer;
}

static wchar_t *
get_process_name()
{
DWORD bufferLen = MAX_PATH;
DWORD len = bufferLen;
wchar_t *r = NULL;

while (!r) {
r = (wchar_t *)malloc(bufferLen * sizeof(wchar_t));
if (!r) {
Py_FatalError("out of memory");
return NULL;
}
len = GetModuleFileNameW(NULL, r, bufferLen);
if (len == 0) {
free((void *)r);
return NULL;
} else if (len == bufferLen &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
free(r);
r = NULL;
bufferLen *= 2;
if (!home.empty()) {
Py_SetPythonHome(home.c_str());
}
if (!executable.empty()) {
const wchar_t *launcherPath = _wgetenv(L"__PYVENV_LAUNCHER__");
if (launcherPath) {
_wputenv_s(L"__PYVENV_BASE_EXECUTABLE__", executable.c_str());
_Py_SetProgramFullPath(launcherPath);
/* bpo-35873: Clear the environment variable to avoid it being
* inherited by child processes. */
_wputenv_s(L"__PYVENV_LAUNCHER__", L"");
} else {
_Py_SetProgramFullPath(executable.c_str());
}
}

return r;
return 1;
}

int
wmain(int argc, wchar_t **argv)
{
const wchar_t **new_argv;
int new_argc;
const wchar_t *exeName;

new_argc = argc;
new_argv = (const wchar_t**)malloc(sizeof(wchar_t *) * (argc + 2));
if (new_argv == NULL) {
Py_FatalError("out of memory");
return -1;
if (!set_process_name()) {
return 121;
}
set_user_base();

exeName = get_process_name();

new_argv[0] = get_argv0(exeName ? exeName : argv[0]);
for (int i = 1; i < argc; ++i) {
new_argv[i] = argv[i];
const wchar_t *p = wcsrchr(argv[0], L'\\');
if (!p) {
p = argv[0];
}
if (p) {
if (*p == L'\\') {
p++;
}

set_user_base();

if (exeName) {
const wchar_t *p = wcsrchr(exeName, L'\\');
if (p) {
const wchar_t *moduleName = NULL;
if (*p++ == L'\\') {
if (wcsnicmp(p, L"pip", 3) == 0) {
moduleName = L"pip";
_wputenv_s(L"PIP_USER", L"true");
}
else if (wcsnicmp(p, L"idle", 4) == 0) {
moduleName = L"idlelib";
}
}
const wchar_t *moduleName = NULL;
if (wcsnicmp(p, L"pip", 3) == 0) {
moduleName = L"pip";
/* No longer required when pip 19.1 is added */
_wputenv_s(L"PIP_USER", L"true");
} else if (wcsnicmp(p, L"idle", 4) == 0) {
moduleName = L"idlelib";
}

if (moduleName) {
new_argc += 2;
for (int i = argc; i >= 1; --i) {
new_argv[i + 2] = new_argv[i];
}
new_argv[1] = L"-m";
new_argv[2] = moduleName;
if (moduleName) {
/* Not even pretending we're going to free this memory.
* The OS will clean it all up when our process exits
*/
wchar_t **new_argv = (wchar_t **)PyMem_RawMalloc((argc + 2) * sizeof(wchar_t *));
new_argv[0] = argv[0];
new_argv[1] = _PyMem_RawWcsdup(L"-m");
new_argv[2] = _PyMem_RawWcsdup(moduleName);
for (int i = 1; i < argc; ++i) {
new_argv[i + 2] = argv[i];
}
argv = new_argv;
argc += 2;
}
}

/* Override program_full_path from here so that
sys.executable is set correctly. */
_Py_SetProgramFullPath(new_argv[0]);

int result = Py_Main(new_argc, (wchar_t **)new_argv);

free((void *)exeName);
free((void *)new_argv);

return result;
return Py_Main(argc, (wchar_t**)argv);
}

#ifdef PYTHONW
Expand Down
14 changes: 12 additions & 2 deletions Python/sysmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2448,8 +2448,6 @@ _PySys_BeginInit(PyObject **sysmod)
return _Py_INIT_ERR("can't initialize sys module");
}

#undef SET_SYS_FROM_STRING

/* Updating the sys namespace, returning integer error codes */
#define SET_SYS_FROM_STRING_INT_RESULT(key, value) \
do { \
Expand Down Expand Up @@ -2483,6 +2481,17 @@ _PySys_EndInit(PyObject *sysdict, _PyMainInterpreterConfig *config)
SET_SYS_FROM_STRING_BORROW("exec_prefix", config->exec_prefix);
SET_SYS_FROM_STRING_BORROW("base_exec_prefix", config->base_exec_prefix);

#ifdef MS_WINDOWS
const wchar_t *baseExecutable = _wgetenv(L"__PYVENV_BASE_EXECUTABLE__");
if (baseExecutable) {
SET_SYS_FROM_STRING("_base_executable",
PyUnicode_FromWideChar(baseExecutable, -1));
_wputenv_s(L"__PYVENV_BASE_EXECUTABLE__", L"");
} else {
SET_SYS_FROM_STRING_BORROW("_base_executable", config->executable);
}
#endif

if (config->argv != NULL) {
SET_SYS_FROM_STRING_BORROW("argv", config->argv);
}
Expand Down Expand Up @@ -2528,6 +2537,7 @@ _PySys_EndInit(PyObject *sysdict, _PyMainInterpreterConfig *config)
return -1;
}

#undef SET_SYS_FROM_STRING
#undef SET_SYS_FROM_STRING_BORROW
#undef SET_SYS_FROM_STRING_INT_RESULT

Expand Down