We use custom builds of Python 2.6.4 x64 for each game project, and have project-change scripts that reassociate everything with the correct Python build. That includes fixing up registry to think that Python build was actually installed, so extension installers find it. Below is the function I wrote to handle most of those details. It probably won’t run as-is, but it should be clear what it’s doing.
def set_python_file_associations( python_dir ):
"""
Changes default Python interpreter/file associations in Windows Registry.
*Arguments:*
* ``python_dir`` Path to root Python directory to use, ie "C:\Python26"
*Keyword Arguments:*
* none
*Returns:*
* none
*Author:*
* Adam Pletcher, [email][email protected][/email], 7/31/2012 7:35:04 AM
"""
# Change file associations in registry
reg_entries = [
( r'HKEY_CLASSES_ROOT\Python.CompiledFile\DefaultIcon', r'{python_dir}\DLLs\pyc.ico' ),
( r'HKEY_CLASSES_ROOT\Python.CompiledFile\shell\open\command', r'"{python_dir}\python.exe" "%1" %*' ),
( r'HKEY_CLASSES_ROOT\Python.File\DefaultIcon', r'{python_dir}\DLLs\py.ico' ),
( r'HKEY_CLASSES_ROOT\Python.File\shell\Edit with IDLE\command', r'"{python_dir}\pythonw.exe" "{python_dir}\Lib\idlelib\idle.pyw" -n -e "%1"' ),
( r'HKEY_CLASSES_ROOT\Python.File\shell\open\command', r'"{python_dir}\python.exe" "%1" %*' ),
( r'HKEY_CLASSES_ROOT\Python.NoConFile\DefaultIcon', r'{python_dir}\DLLs\py.ico' ),
( r'HKEY_CLASSES_ROOT\Python.NoConFile\shell\Edit with IDLE\command', r'"{python_dir}\pythonw.exe" "{python_dir}\idlelib\idle.pyw" -n -e "%1"' ),
( r'HKEY_CLASSES_ROOT\Python.NoConFile\shell\open\command', r'"{python_dir}\pythonw.exe" "%1" %*' ),
]
for reg_entry in reg_entries:
key = reg_entry[ 0 ].rstrip( '\\' )
value = reg_entry[ 1 ].format( python_dir = python_dir )
set_registry_value( key, VALUE_DEFAULT, value )
# Set file associations for .py and .pyc to their respective file types, since this sometimes goes missing.
proc = subprocess.Popen( 'assoc .py=Python.File', shell = True ).wait( )
proc = subprocess.Popen( 'assoc .pyw=Python.NoConFile', shell = True ).wait( )
# Add the new Python path to the system PATH, also via registry. Requires user to log in again to take effect(?)
old_path_value = get_registry_value( r'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'Path' )
old_paths = old_path_value.split( ';' )
new_paths = [ ]
old_python_dirs = [ ]
for old_path in old_paths:
# If a "python.exe" exists in this dir, it's the old Python path, so add it to list of dirs to omit.
python_exe = os.path.join( old_path, 'python.exe' )
if os.path.exists( python_exe ):
# found it, add to skip list
old_python_dirs.append( old_path.lower( ) )
if old_python_dirs:
# Build new paths list, leaving out any old ones underneath an old python dir
for old_path in old_paths:
skip = False
for old_python_dir in old_python_dirs:
if old_path.lower( ).startswith( old_python_dir ):
skip = True
break
if not skip:
new_paths.append( old_path )
else:
# No changes necessary
new_paths = old_paths
# Add new Python dir, if it's not in there already
if python_dir not in new_paths:
new_paths.append( python_dir )
# Add a subdir required by pywin32 extensions
pywin32_dir = os.path.join( python_dir, 'lib\site-packages\pywin32_system32' )
if pywin32_dir not in new_paths:
new_paths.append( pywin32_dir )
# Add separators
new_path_value = ';'.join( new_paths )
if new_path_value == old_path_value:
# No changes made, return
return
# Make it official
set_registry_value( r'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'Path', new_path_value )
# Finally, restart Windows Explorer. This is often required for changes to stick without requiring logging out/in again
subprocess.Popen( 'taskkill /f /IM explorer.exe', shell = True ).wait( )
explorer_filename = os.path.join( os.getenv( 'windir' ), 'explorer.exe' )
subprocess.Popen( explorer_filename, shell = True )