]> granicus.if.org Git - python/commitdiff
Issue #23465: Implement PEP 486 - Make the Python Launcher aware of virtual environme...
authorSteve Dower <steve.dower@microsoft.com>
Thu, 26 Feb 2015 22:25:33 +0000 (14:25 -0800)
committerSteve Dower <steve.dower@microsoft.com>
Thu, 26 Feb 2015 22:25:33 +0000 (14:25 -0800)
Doc/using/windows.rst
Doc/whatsnew/3.5.rst
Misc/NEWS
PC/launcher.c

index af661969d047e54447353ac3fc0854e0a3cc43c1..f0f24e8150f072aa5123e350599131a8332d67d3 100644 (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
 --------------------------
 
index 7c4e530c2478a792aea66c7d8b695365637fabeb..2a777293964428ab43ed694bedf742a7c88be45f 100644 (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
 ======================
 
index 796e9bf7e5f5d4774bb3215e0b14e098a2298154..17641ceeab80a3a9c431ecdb1ce867f44a008092 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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.
 
index d450d9f71e186c4a0e0509c9cf188fe8e21fee56..33dd5dab5d60fbbab603bcc36d6370a4ff86ef3d 100644 (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;
 }