Issue #23465: Implement PEP 486 - Make the Python Launcher aware of virtual environments (patch by Paul Moore)

This commit is contained in:
Steve Dower 2015-02-26 14:25:33 -08:00
parent b48af340b9
commit 76998fef2c
4 changed files with 73 additions and 4 deletions

View File

@ -404,6 +404,16 @@ If you see the following error, you do not have the launcher installed:
Per-user installations of Python do not add the launcher to :envvar:`PATH`
unless the option was selected on installation.
Virtual environments
^^^^^^^^^^^^^^^^^^^^
If the launcher is run with no explicit Python version specification, and a
virtual environment (created with the standard library :mod:`venv` module or
the external ``virtualenv`` tool) active, the launcher will run the virtual
environment's interpreter rather than the global one. To run the global
interpreter, either deactivate the virtual environment, or explicitly specify
the global Python version.
From a script
^^^^^^^^^^^^^
@ -478,6 +488,16 @@ be used by the launcher without modification. If you are writing a new script
on Windows which you hope will be useful on Unix, you should use one of the
shebang lines starting with ``/usr``.
Any of the above virtual commands can be suffixed with an explicit version
(either just the major version, or the major and minor version) - for example
``/usr/bin/python2.7`` - which will cause that specific version to be located
and used.
The ``/usr/bin/env`` form of shebang line has one further special property.
Before looking for installed Python interpreters, this form will search the
executable :envvar:`PATH` for a Python executable. This corresponds to the
behaviour of the Unix ``env`` program, which performs a :envvar:`PATH` search.
Arguments in shebang lines
--------------------------

View File

@ -123,6 +123,18 @@ manually, and should make it more robust against asynchronous signal reception.
:pep:`475` -- Retry system calls failing with EINTR
PEP 486: Make the Python Launcher aware of virtual environments
---------------------------------------------------------------
:pep:`486` makes the Windows launcher (see :pep:`397`) aware of an active
virtual environment. When the default interpreter would be used and the
``VIRTUAL_ENV`` environment variable is set, the interpreter in the virtual
environment will be used.
.. seealso::
:pep:`486` -- Make the Python Launcher aware of virtual environments
Other Language Changes
======================

View File

@ -77,6 +77,9 @@ Build
Windows
-------
- Issue #23465: Implement PEP 486 - Make the Python Launcher aware of virtual
environments. Patch by Paul Moore.
- Issue #23437: Make user scripts directory versioned on Windows. Patch by Paul
Moore.

View File

@ -384,6 +384,31 @@ find_python_by_version(wchar_t const * wanted_ver)
}
static wchar_t *
find_python_by_venv()
{
static wchar_t venv_python[MAX_PATH];
wchar_t *virtual_env = get_env(L"VIRTUAL_ENV");
DWORD attrs;
/* Check for VIRTUAL_ENV environment variable */
if (virtual_env == NULL || virtual_env[0] == L'\0') {
return NULL;
}
/* Check for a python executable in the venv */
debug(L"Checking for Python executable in virtual env '%ls'\n", virtual_env);
_snwprintf_s(venv_python, MAX_PATH, _TRUNCATE,
L"%ls\\Scripts\\%ls", virtual_env, PYTHON_EXECUTABLE);
attrs = GetFileAttributesW(venv_python);
if (attrs == INVALID_FILE_ATTRIBUTES) {
debug(L"Python executable %ls missing from virtual env\n", venv_python);
return NULL;
}
return venv_python;
}
static wchar_t appdata_ini_path[MAX_PATH];
static wchar_t launcher_ini_path[MAX_PATH];
@ -1309,6 +1334,7 @@ process(int argc, wchar_t ** argv)
{
wchar_t * wp;
wchar_t * command;
wchar_t * executable;
wchar_t * p;
int rc = 0;
size_t plen;
@ -1453,6 +1479,7 @@ process(int argc, wchar_t ** argv)
if (ip == NULL)
error(RC_NO_PYTHON, L"Requested Python version (%ls) not \
installed", &p[1]);
executable = ip->executable;
command += wcslen(p);
command = skip_whitespace(command);
}
@ -1470,9 +1497,16 @@ installed", &p[1]);
#endif
if (!valid) {
ip = locate_python(L"");
if (ip == NULL)
error(RC_NO_PYTHON, L"Can't find a default Python.");
/* Look for an active virtualenv */
executable = find_python_by_venv();
/* If we didn't find one, look for the default Python */
if (executable == NULL) {
ip = locate_python(L"");
if (ip == NULL)
error(RC_NO_PYTHON, L"Can't find a default Python.");
executable = ip->executable;
}
if ((argc == 2) && (!_wcsicmp(p, L"-h") || !_wcsicmp(p, L"--help"))) {
#if defined(_M_X64)
BOOL canDo64bit = TRUE;
@ -1500,7 +1534,7 @@ Launcher arguments:\n\n\
fflush(stdout);
}
}
invoke_child(ip->executable, NULL, command);
invoke_child(executable, NULL, command);
return rc;
}