This PEP describes a Python launcher for the Windows platform. APython launcher is a single executable which uses a number ofheuristics to locate a Python executable and launch it with aspecified command line.
Windows provides “file associations” so an executable can be associatedwith an extension, allowing for scripts to be executed directly in somecontexts (eg., double-clicking the file in Windows Explorer.) Until now,a strategy of “last installed Python wins” has been used and while notideal, has generally been workable due to the conservative changes inPython 2.x releases. As Python 3.x scripts are often syntacticallyincompatible with Python 2.x scripts, a different strategy must be usedto allow files with a ‘.py’ extension to use a different executable basedon the Python version the script targets. This will be done by borrowingthe existing practices of another operating system - scripts will be ableto nominate the version of Python they need by way of a “shebang” line, asdescribed below.
Unix-like operating systems (referred to simply as “Unix” in thisPEP) allow scripts to be executed as if they were executable imagesby examining the script for a “shebang” line which specifies theactual executable to be used to run the script. This is described indetail in theevecve(2) man page[1] and while user documentation willbe created for this feature, for the purposes of this PEP that manpage describes a valid shebang line.
Additionally, these operating systems provide symbolic-links toPython executables in well-known directories. For example, manysystems will have a link /usr/bin/python which references aparticular version of Python installed under the operating-system.These symbolic links allow Python to be executed without regard forwhere Python it actually installed on the machine (eg., withoutrequiring the path where Python is actually installed to bereferenced in the shebang line or in thePATH.)PEP 394 ‘The “python”command on Unix-Like Systems’ describes additional conventionsfor more fine-grained specification of a particular Python version.
These 2 facilities combined allow for a portable and somewhatpredictable way of both starting Python interactively and for allowingPython scripts to execute. This PEP describes an implementation of alauncher which can offer the same benefits for Python on the Windowsplatform and therefore allows the launcher to be the executableassociated with ‘.py’ files to support multiple Python versionsconcurrently.
While this PEP offers the ability to use a shebang line which shouldwork on both Windows and Unix, this is not the primary motivation forthis PEP - the primary motivation is to allow a specific version to bespecified without inventing new syntax or conventions to describeit.
This PEP specifies features of the launcher; a prototypeimplementation is provided in[3] which will be distributedtogether with the Windows installer of Python, but will also beavailable separately (but released along with the Pythoninstaller). New features may be added to the launcher aslong as the features prescribed here continue to work.
The launcher comes in 2 versions - one which is a console program andone which is a “windows” (ie., GUI) program. These 2 launchers correspondto the ‘python.exe’ and ‘pythonw.exe’ executables which currently shipwith Python. The console launcher will be named ‘py.exe’ and the Windowsone named ‘pyw.exe’. The “windows” (ie., GUI) version of the launcherwill attempt to locate and launch pythonw.exe even if a virtual shebangline nominates simply “python” - in fact, the trailing ‘w’ notation isnot supported in the virtual shebang line at all.
The launcher is installed into the Windows directory (seediscussion below) if installed by a privileged user. Thestand-alone installer asks for an alternative location of theinstaller, and adds that location to the user’sPATH.
The installation in the Windows directory is a 32-bit executable(see discussion); the standalone installer may also offer to install64-bit versions of the launcher.
The launcher installation is registered inHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\CurrentVersion\SharedDLLswith a reference counter.It contains a version resource matching the version number of thepythonXY.dll with which it is distributed. Independentinstallations will overwrite older versionof the launcher with newer versions. Stand-alone releases usea release level of0x10 inFIELD3 of the CPython release on whichthey are based.
Once installed, the “console” version of the launcher isassociated with .py files and the “windows” version associated with .pywfiles.
The launcher is not tied to a specific version of Python - eg., alauncher distributed with Python 3.3 should be capable of locating andexecuting any Python 2.x and Python 3.x version. However, thelauncher binaries have a version resource that is the same as theversion resource in the Python binaries that they are released with.
The launcher is restricted to launching Python scripts.It is not intended as a general-purpose script launcher orshebang processor.
The launcher supports the syntax of shebang lines as describedin[1], including all restrictions listed.
The launcher supports shebang lines referring to Pythonexecutables with any of the (regex) prefixes “/usr/bin/”, “/usr/local/bin”and “/usr/bin/env *”, as well as binaries specified without
For example, a shebang line of ‘#! /usr/bin/python’ should work eventhough there is unlikely to be an executable in the relative Windowsdirectory “\usr\bin”. This means that many scripts can use a singleshebang line and be likely to work on both Unix and Windows withoutmodification.
The launcher will support fully-qualified paths to executables.While this will make the script inherently non-portable, it is afeature offered by Unix and would be useful for Windows users insome cases.
The launcher will be capable of supporting implementations other thanCPython, such as jython and IronPython, but given both the absence ofcommon links on Unix (such as “/usr/bin/jython”) and the inability for thelauncher to automatically locate the installation location of theseimplementations on Windows, the launcher will support this viacustomization options. Scripts taking advantage of this will not beportable (as these customization options must be set to reflect theconfiguration of the machine on which the launcher is running) but thisability is nonetheless considered worthwhile.
On Unix, the user can control which specific version of Python is usedby adjusting the links in /usr/bin to point to the desired version. Asthe launcher on Windows will not use Windows links, customization options(exposed via both environment variables and INI files) will be used tooverride the semantics for determining what version of Python will beused. For example, while a shebang line of “/usr/bin/python2” willautomatically locate a Python 2.x implementation, an environment variablecan override exactly which Python 2.x implementation will be chosen.Similarly for “/usr/bin/python” and “/usr/bin/python3”. This isspecified in detail later in this PEP.
If the first command-line argument does not start with a dash (‘-‘)character, an attempt will be made to open that argument as a fileand parsed for a shebang line according to the rules in[1]:
#! interpreter [optional-arg]Once parsed, the command will be categorized according to the following rules:
PATH)optionally followed by arguments. The contents of the string will notbe parsed - it will be passed directly to the Windows CreateProcessfunction after appending the name of the script and the launchercommand-line arguments. This means that the rules used byCreateProcess will be used, including how relative path names andexecutable references without extensions are treated. Notably, theWindows command processor will not be used, so special rules used by thecommand processor (such as automatic appending of extensions other than‘.exe’, support for batch files, etc) will not be used.The use of ‘virtual’ shebang lines is encouraged as this shouldallow for portable shebang lines to be specified which work onmultiple operating systems and different installations of the sameoperating system.
If the first argument can not be opened as a file or if no validshebang line can be found, the launcher will act as if a shebang line of‘#!python’ was found - ie., a default Python interpreter will belocated and the arguments passed to that. However, if a validshebang line is found but the process specified by that line can notbe started, the default interpreter will not be started - the errorto create the specified child process will cause the launcher to displayan appropriate message and terminate with a specific exit code.
Two .ini files will be searched by the launcher -py.ini in thecurrent user’s “application data” directory (i.e. the directory returnedby calling the Windows functionSHGetFolderPath withCSIDL_LOCAL_APPDATA,%USERPROFILE%\AppData\Local on Vista+,%USERPROFILE%\LocalSettings\ApplicationData on XP)andpy.ini in the same directory as the launcher. The same .inifiles are used for both the ‘console’ version of the launcher (i.e.py.exe) and for the ‘windows’ version (i.e. pyw.exe)
Customization specified in the “application directory” will haveprecedence over the one next to the executable, so a user, who may nothave write access to the .ini file next to the launcher, can overridecommands in that global .ini file)
Virtual Commands are shebang lines which start with strings which wouldbe expected to work on Unix platforms - examples include‘/usr/bin/python’, ‘/usr/bin/env python’ and ‘python’. Optionally, thevirtual command may be suffixed with a version qualifier (see below),such as ‘/usr/bin/python2’ or ‘/usr/bin/python3.2’. The command executedis based on the rules described in Python Version Qualifiersbelow.
The launcher will support the ability to define “Customized Commands” in aWindows .ini file (ie, a file which can be parsed by the Windows functionGetPrivateProfileString). A section called ‘[commands]’ can be createdwith key names defining the virtual command and the value specifying theactual command-line to be used for this virtual command.
For example, if an INI file has the contents:
[commands]vpython=c:\bin\vpython.exe-foo
Then a shebang line of ‘#! vpython’ in a script named ‘doit.py’ willresult in the launcher using the command-linec:\bin\vpython.exe-foodoit.py
The precise details about the names, locations and search order of the.ini files is in the launcher documentation[4]
Some of the features described allow an optional Python version qualifierto be used.
A version qualifier starts with a major version number and can optionallybe followed by a period (‘.’) and a minor version specifier. If the minorqualifier is specified, it may optionally be followed by “-32” to indicatethe 32bit implementation of that version be used. Note that no “-64”qualifier is necessary as this is the default implementation (see below).
On 64bit Windows with both 32bit and 64bit implementations of thesame (major.minor) Python version installed, the 64bit version willalways be preferred. This will be true for both 32bit and 64bitimplementations of the launcher - a 32bit launcher will prefer toexecute a 64bit Python installation of the specified version ifavailable. This is so the behavior of the launcher can be predictedknowing only what versions are installed on the PC and withoutregard to the order in which they were installed (ie, without knowingwhether a 32 or 64bit version of Python and corresponding launcher wasinstalled last). As noted above, an optional “-32” suffix can be usedon a version specifier to change this behaviour.
If no version qualifiers are found in a command, the environment variablePY_PYTHON can be set to specify the default version qualifier - the defaultvalue is “2”. Note this value could specify just a major version (e.g. “2”) ora major.minor qualifier (e.g. “2.6”), or even major.minor-32.
If no minor version qualifiers are found, the environment variablePY_PYTHON{major} (where{major} is the current major version qualifieras determined above) can be set to specify the full version. If no such optionis found, the launcher will enumerate the installed Python versions and usethe latest minor release found for the major version, which is likely,although not guaranteed, to be the most recently installed version in thatfamily.
In addition to environment variables, the same settings can be configuredin the .INI file used by the launcher. The section in the INI file iscalled[defaults] and the key name will be the same as theenvironment variables without the leadingPY_ prefix (and note thatthe key names in the INI file are case insensitive.) The contents ofan environment variable will override things specified in the INI file.
Only the first command-line argument will be checked for a shebang lineand only if that argument does not start with a ‘-‘.
If the only command-line argument is “-h” or “–help”, the launcher willprint a small banner and command-line usage, then pass the argument tothe default Python. This will cause help for the launcher being printedfollowed by help for Python itself. The output from the launcher willclearly indicate the extended help information is coming from thelauncher and not Python.
As a concession to interactively launching Python, the launcher willsupport the first command-line argument optionally being a dash (“-“)followed by a version qualifier, as described above, to nominate aspecific version be used. For example, while “py.exe” may locate andlaunch the latest Python 2.x implementation installed, a command-line suchas “py.exe -3” could specify the latest Python 3.x implementation belaunched, while “py.exe -2.6-32” could specify a 32bit implementationPython 2.6 be located and launched. If a Python 2.x implementation isdesired to be launched with the -3 flag, the command-line would need to besimilar to “py.exe -2 -3” (or the specific version of Python couldobviously be launched manually without use of this launcher.) Note thatthis feature can not be used with shebang processing as the file scannedfor a shebang line and this argument must both be the first argument andtherefore are mutually exclusive.
All other arguments will be passed untouched to the child Python process.
The launcher offers some conveniences for Python developers workinginteractively - for example, starting the launcher with no command-linearguments will launch the default Python with no command-line arguments.Further, command-line arguments will be supported to allow a specificPython version to be launched interactively - however, these conveniencesmust not detract from the primary purpose of launching scripts and mustbe easy to avoid if desired.
The launcher creates a subprocess to start the actualinterpreter. SeeDiscussion below for the rationale.
It may be surprising that the launcher is installed into theWindows directory, and not the System32 directory. The reason isthat the System32 directory is not on the Path of a 32-bit processrunning on a 64-bit system. However, the Windows directory isalways on the path.
The launcher that is installed into the Windows directory is a 32-bitexecutable so that the 32-bit CPython installer can provide the samebinary for both 32-bit and 64-bit Windows installations.
Ideally, the launcher process would execute Python directly insidethe same process, primarily so the parent of the launcher process couldterminate the launcher and have the Python interpreter terminate. If thelauncher executes Python as a sub-process and the parent of the launcherterminates the launcher, the Python process will be unaffected.
However, there are a number of practical problems associated with thisapproach. Windows does not support theexecv* family of Unix functions,so this could only be done by the launcher dynamically loading the PythonDLL, but this would have a number of side-effects. The most seriousside effect of this is that the value of sys.executable would refer to thelauncher instead of the Python implementation. Many Python scripts use thevalue ofsys.executable to launch child processes, and these scripts mayfail to work as expected if the launcher is used. Consider a “parent”script with a shebang line of ‘#! /usr/bin/python3’ which attempts tolaunch a child script (with no shebang) viasys.executable - currently thechild is launched using the exact same version running the parent script.Ifsys.executable referred to the launcher the child would be likelyexecuted using a Python 2.x version and would be likely to fail with aSyntaxError.
Another hurdle is the support for alternative Python implementationsusing the “customized commands” feature described above, where loadingthe command dynamically into a running executable is not possible.
The final hurdle is the rules above regarding 64bit and 32bit programs -a 32bit launcher would be unable to load the 64bit version of Python andvice-versa.
Given these considerations, the launcher will execute its command in achild process, remaining alive while the child process is executing, thenterminate with the same exit code as returned by the child. To addressconcerns regarding the termination of the launcher not killing the child,the Win32 Job API will be used to arrange so that the child process isautomatically killed when the parent is terminated (although children ofthat child process will continue as is the case now.) As this Windows APIis available in Windows XP and later, this launcher will not work onWindows 2000 or earlier.
This document has been placed in the public domain.
Source:https://github.com/python/peps/blob/main/peps/pep-0397.rst
Last modified:2025-02-01 08:55:40 GMT