Last year, Mark Hammond proposed PEP 397 (Python launcher for Windows), to bring some much needed functionality for Python on Windows. Historically, Python on Windows does not add itself to the system path; this needs to be done manually by users as a separate step. This may change in the future, but it remains the case for Python versions that are already released. With the increasing use of Python 2 and Python 3 on the same system, you can’t be sure if a particular script will run with a version of Python which may have been added to the system path.
Some Python distributions add the .py and .pyw extensions to the PATHEXT environment variable, and if not, they can be added manually. This tells the Windows shell to try and execute foo.py when you invoke just plain foo on the command line. The shell then uses file associations to try to locate the actual executable to be invoked with foo.py as a parameter, along with any parameters you passed when you typed foo on the command line.
File associations typically involve a two-step process: extensions are mapped to file types (also called vendor keys), and file types are mapped to executables which are used to perform operations on those files. These mappings are maintained in the registry; only one Python executable can be associated with .py files, which is clearly insufficient in environments where multiple Python versions are installed on the same machine.
On Unix, Linux, OS X and other similar systems, individual scripts can specify which executable should be used to execute them, using the first line of the script – commonly called the shebang line. This is conventionally a comment line in the scripting language, and is ignored by the scripting language interpreter, but used by the command shell. The typical line for a Python script would be #!/usr/bin/env python, which directs the shell to invoke the script using the default Python interpreter for the system (usually a 2.x version, except on Arch Linux, where it’s a 3.x version).
All of these systems allow symlinks for python3 and or python2 pointing to a suitable Python 3.x or 2.x version, so individual scripts can easily specify which version of Python is appropriate for them.
This functionality has not been available in the Windows environment, until recently, when an implementation of a PEP 397-compliant launcher was released. This aims to provide shebang line functionality for Windows, and early adopters have indicated that the launcher is genuinely useful for Python users on Windows.
The launcher installer comes in four variants, offering different architectures and installation locations:
Windows folder | "%ProgramFiles%\Python Launcher" | |
32-bit | launchwin.msi | launcher.msi |
64-bit | launchwin.amd64.msi | launcher.amd64.msi |
The main advantage of choosing the launchwin variants is that they are on the system path, so you can invoke the launcher directly (i.e. not indirectly through a script) using the commands py, py –2 or py –3. These commands will result in launching respectively the latest default Python version (2.x or 3.x depending on configuration, described below), the latest installed Python 2.x or the latest installed Python 3.x.
The launcher installation program associates the Python file types with the launcher executable, so that (with .py and .pyw in PATHEXT), typing e.g. foo -abc def in a command shell (where foo.py exists) will lead to Windows starting the launcher using the command line <path>\py.exe foo.py –abc def, where <path> is wherever the launcher was installed to. The launcher then opens foo.py, reads the first line, looks for a shebang line, and from it tries to determine which executable is needed to actually run the script. If it fails to do this, it exits with an error message; otherwise, it invokes that executable, passing it the same arguments it was passed.
In order for the shebang line processing to correctly identify an executable to run the script, the shebang line (the first line in the script) must begin with #! and then be followed by some optional whitespace and then an executable specifier. This can take a number of forms:
Executable specifier | What will happen |
/usr/bin/env python | Look for an optional version specifier and arguments, and launch the appropriate version of Python with any arguments from the shebang line, the script name and the parameters passed to the script. |
/usr/bin/python | As above. |
/usr/local/bin/python | As above. |
python | As above. |
/usr/bin/env progname | Look in the launcher’s configuration (see below) to identify the executable for progname, and if found, launch it with any arguments from the shebang line, the script name and the parameters passed to the script. |
/usr/bin/progname | As above. |
/usr/local/bin/progname | As above. |
progname | As above. |
The progname in the above table is an identifier other than 'python'. It is regarded as a 'customised command' (see below).
The version specifier can take one of the following forms:
Version specifier | Which Python will be run |
2 | The default 2.x version of Python, as configured (see below) |
3 | The default 3.x version of Python, as configured (see below) |
2.x where x is a digit | The specified version 2.x of Python with the same architecture as the OS |
3.x where x is a digit | The specified version 3.x of Python with the same architecture as the OS |
2.x-32 where x is a digit | The same as 2.x, except that on a 64-bit system, the 32-bit Python is run |
3.x-32 where x is a digit | The same as 3.x, except that on a 64-bit system, the 32-bit Python is run |
The optional –32 suffix, if present, will have no effect when processed by a 32-bit launcher executable. If a specified Python version is not installed on the system, the launcher will terminate with an error message.
Customised commands are treated as follows. A py.ini file is looked for in two locations: adjacent to the launcher, and in the user’s local AppData folder (non-roaming). This has a standard .ini format; the [commands] section is expected to contain a list of lines with the format progname=path. The file adjacent to the launcher is read first, then the one in the user’s profile location; these commands are read into an internal command table. If the same progname is in both configuration files, the value read from the user’s profile will overwrite the value read from the launcher-adjacent configuration. This table is searched when a progname variant of the shebang line is encountered; if a match is found, the corresponding path is assumed to be the path to the custom executable.
Customised commands allow the launcher to operate as a very flexible shebang line processor, not limited to launching Python scripts. For example, you can launch Perl, Ruby or Haskell scripts using the launcher (as long as the file type associations are set up for the corresponding .pl, .rb and .hs extensions to point to the launcher, and that the launcher’s configuration allows it to map perl, ruby and runhaskell progname values to the paths of the corresponding executables). Of course, those programs already set the registry up to point to their launchers: but using the customisability of the Python launcher, you could (for example) cause ‘perl’ in a shebang line to invoke the Perl interpreter with useful default arguments such as –w (which enables many useful warnings and is recommended).
PEP 397 has been accepted, and so the launcher should be incorporated into Python 3.3 (now in beta). If you are a Windows user, please download the launcher (or the Python 3.3 beta), try it out and give feedback (if you find any bugs or have any enhancement requests, you can raise an issue here for the standalone launcher, or here for the Python 3.3 beta). The standalone launcher will remain available for use with older Python versions.
Add a comment