Wednesday, January 11, 2012

How I install Python on Windows

I've wanted for some time now to document the process I use to install Python and develop, but on Windows. First, let me give a brief background.

I tend to use Windows and I've been programming in Python since 1997. I also tend to use a lot of Unix conventions, especially where they don't create a major incompatibility with Windows. I don't use compatibility layers like Cygwin, though. I find they create more trouble than they're worth. So where possible, I use native implementations of everything. I'm a command-line junkie, and I try to automate everything. One of the best things about Python is its cross-platform support. I've never encountered a better general-purpose language for cross-platform development.

So over the years, I've developed some routines to automate the installation and configuration of Python on my systems. Ever since Python 2.6 and Windows Vista, life has been pretty good. Vista added support for symbolic links and Python 2.6 had excellent 64-bit support.

Since then, I've install almost exclusively 64-bit versions of Python. In this article, I will assume one is using Windows 7 x64, although the routines generally translate to x86. The biggest challenge to using 64-bit Windows is access to compiled modules. To the best of my knowledge, it's not possible to compile 64-bit extension modules without the full version of Visual Studio.

Most Python programmers will find that having several different Python versions present is useful if not necessary. I typically install the latest Python 2 and the latest stable Python 3.

As any Python programmer knows, having distribute is a nearly essential part of any Python installation, so the installation routines should include support for installing distribute as well.

So to accomplish all of this, I needed a scripting language that comes pre-installed with Windows. Originally, I used cmd scripts, but found those not quite adequate. Bundled with the fact that PowerShell 2 comes with Windows 7, it became the language of choice. I developed this script. If you run that script in a PowerShell, it creates three functions:
  • InstallPythonMSI $installer, $target
  • get-python-version $version
  • bootstrap-python
InstallPythonMSI is simply a helper function used by get-python-version. It basically executes a Python .msi file so that it installs silently to the target location. It was not easy generating that code to work properly to pass the parameters to msiexec with quotes in the right places.
get-python-version completely automates installing a single Python version to an appropriate location in $env:ProgramFiles. The script assumes 64-bit, but can be easily modified to support 32-bit. It then also installs distribute by executing the bootstrap script directly from the server, enabling support for setuptools-packaged files.
Finally, bootstrap-python sets up some symbolic links and resets the file associations to create an authoritative (default) Python installation. By default, Python installs into C:\Python27 or similar. I've argued that this location is not appropriate and that the proper location for programs (including Python) is $env:ProgramFiles, so that's where I install it (after all, how do you differentiate between 32-bit and 64-bit versions of Python 2.6?). However, it is useful to have a symbolic link from an easy-to-type location. So bootstrap-python creates a symlink at C:\Python which refers to the "active" version of Python. It then installs jaraco.windows and uses one of its command-line scripts to set some environment variables (such as adding the Scripts directory to the path and registering .py files as executable scirpts). Then, bootstrap-python resets the file associations by calling this Python script.
What this all means is that running Python.exe or running scripts installed in the Scripts directory will use the active version of Python (whatever C:\Python points to). This configuration also means that one can easily switch the entire system Python environment from one version of Python to another by just repointing a symlink. To automate this process, I've created this Python script, which I call 'pythonver.py'. I usually place this script in a separate location somewhere on the search path (C:\Windows would work). The script searches $ProgramFiles and $ProgramFiles(x86) for PythonXX directories and then allows the user to select one of those, then repoints the C:\Python symbolic link at that version.
The end result is one can install multiple versions of Python in both 32-bit and 64-bit versions and rapidly switch the active version. Of course, it's also possible to select a specific version directly using its canonical location (e.g. C:\Program Files\Python32\python.exe).
With these few scripts, I can rapidly install, bootstrap, and switch between Python versions.
I hope sharing some of these techniques will give some useful techniques that I enjoy using to automate deploying Python on my Windows servers and workstations.

3 comments:

  1. For me the URL to the powershell script is broken, leads to some domain advertising.

    ReplyDelete
    Replies
    1. Hey Holger. Sorry for the broken links. Seems my favorite pastebin didn't renew the domain name. A real shame. So I've redeployed the pastebin on Heroku under my domain. Here are the updated links, which I'll attempt to update in the blog entry if possible:

      PowerShell script for installing Python: http://paste.jaraco.com/vbH-D
      Python Script for updating file associations:
      http://paste.jaraco.com/qmqc0
      Python Script for switching Python versions:
      http://paste.jaraco.com/Fewe4

      Delete
  2. I've once again updated the Powershell script (http://paste.jaraco.com/pYiRg), which I install as $profile/python.ps1 and source from my primary profile. This latest version uses the new Invoke-WebRequest available in Powershell as found with Windows 8, so it may not work for Windows 7 any longer.

    ReplyDelete