Switching Python versions on windows

Wednesday 1 October 2008This is 16 years old. Be careful.

I forget what software first set up these associations, but I have .py files registered with Windows so that they can execute directly. The registry defines .py as a Python.File, which has a shell open command of:

"C:\Python24\python.exe" "%1" %*

My PATHEXT environment variable includes .py, so the command prompt will attempt to execute .py files, using the registry associations to find the executable.

But: I wanted to switch from Python 2.4 to Python 2.5. That meant updating the registry in a handful of places. A Python script to the rescue!

""" Change the .py file extension to point to a different
    Python installation.
"""
import _winreg as reg
import sys

pydir = sys.argv[1]

todo = [
    ('Applications\python.exe\shell\open\command',
                '"PYDIR\\python.exe" "%1" %*'),
    ('Applications\pythonw.exe\shell\open\command',
                '"PYDIR\\pythonw.exe" "%1" %*'),
    ('Python.CompiledFile\DefaultIcon',
                'PYDIR\\pyc.ico'),
    ('Python.CompiledFile\shell\open\command',
                '"PYDIR\\python.exe" "%1" %*'),
    ('Python.File\DefaultIcon',
                'PYDIR\\py.ico'),
    ('Python.File\shell\open\command',
                '"PYDIR\\python.exe" "%1" %*'),
    ('Python.NoConFile\DefaultIcon',
                'PYDIR\\py.ico'),
    ('Python.NoConFile\shell\open\command',
                '"PYDIR\\pythonw.exe" "%1" %*'),
    ]

classes_root = reg.OpenKey(reg.HKEY_CLASSES_ROOT, "")
for path, value in todo:
    key = reg.OpenKey(classes_root, path, 0, reg.KEY_SET_VALUE)
    reg.SetValue(key, '', reg.REG_SZ, value.replace('PYDIR', pydir))

Invoke this with your desired Python installation directory, and the registry is updated to point to it.

Note that this doesn’t affect what the command “python” means, that’s determined by your PATH environment variable. These registry settings change which Python executable is found when you invoke a .py file as a command.

Comments

[gravatar]
It's been a while since I have used Windows, but isn't there a little-known NTFS command line tool that basically makes symlinks (or was it hard-links?) That way, you could do the cool Unixy thing of symlinking C:\Python to C:\Python24 or C:\Python25 or whatever floats your boat and it can be changed on a whim.

...although it's probably just as easy (if not easier) to simply use the script you posted.
[gravatar]
I think I'd prefer updating the registry to use an environment variable for the folder, then just change that variable as necessary.

As Brian said, there are symlinks in windows, which are very handy. I use NTFSLink (google it) to update mine (I use one at work as my current working SVN branch, so everything that references a path on disk can be swapped as I see fit, even stuff like recent projects in visual studio etc).

But, cool to see all the spots you need to update to fix those file associations in windows.
[gravatar]
Couldn't you just reassign what program windows uses to open a file type? In Explorer go to Tools->Folder Options...->File Types. Scroll to the registered file type of PY and then click on the Change... button to choose the new program to associate.
[gravatar]
Why don't you use Windows to change Windows settings:

in explorer:
Tools> Folder Options> File Types
select py file extension, click advanced, and edit properties for action ``open``
In this case, change 24 to 25 in the executable path, this changes the default for execution.

This takes a few clicks and changing one number, instead of having to figure out which registry keys to change and risking that the windows registry gets screwed up (Which I would surely do, by the time I figure out how to change registry settings directly.)

And additionally, its easy to add actions through ``Folder Options``, I have (my default is still Python 2.4):
Edit with IDLE
Edit with IDLE no -n
Edit with IDLE py25
Edit with SPE
Edit with Wing

All these actions get automatically added to the context menu in windows explorer.

Josef
[gravatar]
Sorry, for the repetition, I did not see Paul Fiore's comment.
Josef
[gravatar]
I knew that I could use the UI, but I wasn't sure it would get all of the references, and I was more interested in having an automated way to make the change, and it was a good opportunity to learn the _winreg module.

But thanks for the pointers!
[gravatar]
It's curious that you are moving to 2.5 almost exactly when 2.6 starts to ship ... Is it a philosophical stance, like "I will only always use the previous-to-last version, it's more reliable"? Or just coincidence?
[gravatar]
There's no philosophical stance, though the coincidence is startling. I've used Python 2.5 for a long time, just not as my default Python installation. We had been considering switching our server deploy version to 2.5 for a while, and the server leak we just battled was a good reason to do it. Once the work version switched to 2.5, I switched my default installation as well.
[gravatar]
Hi Ned:

On my windows machine one of the paths failed, so I had to modify the code to get it to work.

When I ran it as coded, I received:
C:\dev>pyswitch.py C:\Python25
Traceback (most recent call last):
  File "C:\dev\pyswitch.py", line 30, in 
    key = reg.OpenKey(classes_root, path, 0, reg.KEY_SET_VALUE)
WindowsError: [Error 2] The system cannot find the file specified
So I changed it to have a try block:
for path, value in todo:
    try:
        key = reg.OpenKey(classes_root, path, 0, reg.KEY_SET_VALUE)
    except:
	print "Unable to find path: %s" % path
    else:
        reg.SetValue(key, '', reg.REG_SZ, value.replace('PYDIR', pydir))
Now I get:
C:\dev>pyswitch.py C:\Python25
Unable to find path: Applications\pythonw.exe\shell\open\command
[gravatar]
a big thanks, the above helped me to repair my python install. Problem was the missing %* in the registry which resulted sys.args always to have a len of 1 and omitting any parameters given in the command line. It was a problem of my user profile so I set it in HKEY_CURRENT_USER, guess I messed up the profile by installing Python as non-admin.
[gravatar]
For those suggesting using the Windows UI, for me (on WindowsXP) that simply doesn't work:

I type the name of a python file at the cmd prompt, it opens in Python 2.5.

I right click on 'xxx.py', select properties, and click the 'opens with' button. I browse to the Python 2.7 executable & hit OK and Apply.

Weirdly, at this point, the properties dialog now displays the 'Opens with' as a very old Python icon. (it was previously the modern Python icon)

Sure enough, typing 'xxx.py' in cmd.exe now opens the script using Python 2.4. This is wrong - I expected 2.7.
[gravatar]
For the record, the same problem happened using the Windows UI in the way joep suggested, going through Explorer Tools / File Types. I tried every combo of restoring .py files to default settings, deleting .py file extension and and re-adding it, to no avail.

Ned's script worked perfectly first time. Score one for using a script. :-)
[gravatar]
Thanks for the script nedbat; didn't work on first try, so I edited the following bits:

classes_root = reg.OpenKeyEx(reg.HKEY_CLASSES_ROOT, "")
for path, value in todo:
key = reg.CreateKeyEx(classes_root, path, 0, reg.KEY_SET_VALUE)
reg.SetValue(key, '', reg.REG_SZ, value.replace('PYDIR', pydir))

CreateKeyEx opens an existing key or creates it if it doesn't exists. I'm on 64 bit Windows 7 Pro. Everything works fine now.

Add a comment:

Ignore this:
Leave this empty:
Name is required. Either email or web are required. Email won't be displayed and I won't spam you. Your web site won't be indexed by search engines.
Don't put anything here:
Leave this empty:
Comment text is Markdown.