Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 76998fe

Browse files
committed
Issue #23465: Implement PEP 486 - Make the Python Launcher aware of virtual environments (patch by Paul Moore)
1 parent b48af34 commit 76998fe

4 files changed

Lines changed: 73 additions & 4 deletions

File tree

Doc/using/windows.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,16 @@ If you see the following error, you do not have the launcher installed:
404404
Per-user installations of Python do not add the launcher to :envvar:`PATH`
405405
unless the option was selected on installation.
406406

407+
Virtual environments
408+
^^^^^^^^^^^^^^^^^^^^
409+
410+
If the launcher is run with no explicit Python version specification, and a
411+
virtual environment (created with the standard library :mod:`venv` module or
412+
the external ``virtualenv`` tool) active, the launcher will run the virtual
413+
environment's interpreter rather than the global one. To run the global
414+
interpreter, either deactivate the virtual environment, or explicitly specify
415+
the global Python version.
416+
407417
From a script
408418
^^^^^^^^^^^^^
409419

@@ -478,6 +488,16 @@ be used by the launcher without modification. If you are writing a new script
478488
on Windows which you hope will be useful on Unix, you should use one of the
479489
shebang lines starting with ``/usr``.
480490

491+
Any of the above virtual commands can be suffixed with an explicit version
492+
(either just the major version, or the major and minor version) - for example
493+
``/usr/bin/python2.7`` - which will cause that specific version to be located
494+
and used.
495+
496+
The ``/usr/bin/env`` form of shebang line has one further special property.
497+
Before looking for installed Python interpreters, this form will search the
498+
executable :envvar:`PATH` for a Python executable. This corresponds to the
499+
behaviour of the Unix ``env`` program, which performs a :envvar:`PATH` search.
500+
481501
Arguments in shebang lines
482502
--------------------------
483503

Doc/whatsnew/3.5.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,18 @@ manually, and should make it more robust against asynchronous signal reception.
123123
:pep:`475` -- Retry system calls failing with EINTR
124124

125125

126+
PEP 486: Make the Python Launcher aware of virtual environments
127+
---------------------------------------------------------------
128+
129+
:pep:`486` makes the Windows launcher (see :pep:`397`) aware of an active
130+
virtual environment. When the default interpreter would be used and the
131+
``VIRTUAL_ENV`` environment variable is set, the interpreter in the virtual
132+
environment will be used.
133+
134+
.. seealso::
135+
136+
:pep:`486` -- Make the Python Launcher aware of virtual environments
137+
126138
Other Language Changes
127139
======================
128140

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ Build
7777
Windows
7878
-------
7979

80+
- Issue #23465: Implement PEP 486 - Make the Python Launcher aware of virtual
81+
environments. Patch by Paul Moore.
82+
8083
- Issue #23437: Make user scripts directory versioned on Windows. Patch by Paul
8184
Moore.
8285

PC/launcher.c

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,31 @@ find_python_by_version(wchar_t const * wanted_ver)
384384
}
385385

386386

387+
static wchar_t *
388+
find_python_by_venv()
389+
{
390+
static wchar_t venv_python[MAX_PATH];
391+
wchar_t *virtual_env = get_env(L"VIRTUAL_ENV");
392+
DWORD attrs;
393+
394+
/* Check for VIRTUAL_ENV environment variable */
395+
if (virtual_env == NULL || virtual_env[0] == L'\0') {
396+
return NULL;
397+
}
398+
399+
/* Check for a python executable in the venv */
400+
debug(L"Checking for Python executable in virtual env '%ls'\n", virtual_env);
401+
_snwprintf_s(venv_python, MAX_PATH, _TRUNCATE,
402+
L"%ls\\Scripts\\%ls", virtual_env, PYTHON_EXECUTABLE);
403+
attrs = GetFileAttributesW(venv_python);
404+
if (attrs == INVALID_FILE_ATTRIBUTES) {
405+
debug(L"Python executable %ls missing from virtual env\n", venv_python);
406+
return NULL;
407+
}
408+
409+
return venv_python;
410+
}
411+
387412
static wchar_t appdata_ini_path[MAX_PATH];
388413
static wchar_t launcher_ini_path[MAX_PATH];
389414

@@ -1309,6 +1334,7 @@ process(int argc, wchar_t ** argv)
13091334
{
13101335
wchar_t * wp;
13111336
wchar_t * command;
1337+
wchar_t * executable;
13121338
wchar_t * p;
13131339
int rc = 0;
13141340
size_t plen;
@@ -1453,6 +1479,7 @@ process(int argc, wchar_t ** argv)
14531479
if (ip == NULL)
14541480
error(RC_NO_PYTHON, L"Requested Python version (%ls) not \
14551481
installed", &p[1]);
1482+
executable = ip->executable;
14561483
command += wcslen(p);
14571484
command = skip_whitespace(command);
14581485
}
@@ -1470,9 +1497,16 @@ installed", &p[1]);
14701497
#endif
14711498

14721499
if (!valid) {
1473-
ip = locate_python(L"");
1474-
if (ip == NULL)
1475-
error(RC_NO_PYTHON, L"Can't find a default Python.");
1500+
/* Look for an active virtualenv */
1501+
executable = find_python_by_venv();
1502+
1503+
/* If we didn't find one, look for the default Python */
1504+
if (executable == NULL) {
1505+
ip = locate_python(L"");
1506+
if (ip == NULL)
1507+
error(RC_NO_PYTHON, L"Can't find a default Python.");
1508+
executable = ip->executable;
1509+
}
14761510
if ((argc == 2) && (!_wcsicmp(p, L"-h") || !_wcsicmp(p, L"--help"))) {
14771511
#if defined(_M_X64)
14781512
BOOL canDo64bit = TRUE;
@@ -1500,7 +1534,7 @@ Launcher arguments:\n\n\
15001534
fflush(stdout);
15011535
}
15021536
}
1503-
invoke_child(ip->executable, NULL, command);
1537+
invoke_child(executable, NULL, command);
15041538
return rc;
15051539
}
15061540

0 commit comments

Comments
 (0)