mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 03:44:55 +00:00 
			
		
		
		
	Issue #23465: Implement PEP 486 - Make the Python Launcher aware of virtual environments (patch by Paul Moore)
This commit is contained in:
		
							parent
							
								
									b48af340b9
								
							
						
					
					
						commit
						76998fef2c
					
				
					 4 changed files with 73 additions and 4 deletions
				
			
		| 
						 | 
				
			
			@ -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
 | 
			
		||||
--------------------------
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
======================
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
        /* 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue