784 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			784 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # postinstall script for pywin32
 | |
| #
 | |
| # copies PyWinTypesxx.dll and PythonCOMxx.dll into the system directory,
 | |
| # and creates a pth file
 | |
| import glob
 | |
| import os
 | |
| import shutil
 | |
| import sys
 | |
| import sysconfig
 | |
| 
 | |
| try:
 | |
|     import winreg as winreg
 | |
| except:
 | |
|     import winreg
 | |
| 
 | |
| # Send output somewhere so it can be found if necessary...
 | |
| import tempfile
 | |
| 
 | |
| tee_f = open(os.path.join(tempfile.gettempdir(), "pywin32_postinstall.log"), "w")
 | |
| 
 | |
| 
 | |
| class Tee:
 | |
|     def __init__(self, file):
 | |
|         self.f = file
 | |
| 
 | |
|     def write(self, what):
 | |
|         if self.f is not None:
 | |
|             try:
 | |
|                 self.f.write(what.replace("\n", "\r\n"))
 | |
|             except IOError:
 | |
|                 pass
 | |
|         tee_f.write(what)
 | |
| 
 | |
|     def flush(self):
 | |
|         if self.f is not None:
 | |
|             try:
 | |
|                 self.f.flush()
 | |
|             except IOError:
 | |
|                 pass
 | |
|         tee_f.flush()
 | |
| 
 | |
| 
 | |
| # For some unknown reason, when running under bdist_wininst we will start up
 | |
| # with sys.stdout as None but stderr is hooked up. This work-around allows
 | |
| # bdist_wininst to see the output we write and display it at the end of
 | |
| # the install.
 | |
| if sys.stdout is None:
 | |
|     sys.stdout = sys.stderr
 | |
| 
 | |
| sys.stderr = Tee(sys.stderr)
 | |
| sys.stdout = Tee(sys.stdout)
 | |
| 
 | |
| com_modules = [
 | |
|     # module_name,                      class_names
 | |
|     ("win32com.servers.interp", "Interpreter"),
 | |
|     ("win32com.servers.dictionary", "DictionaryPolicy"),
 | |
|     ("win32com.axscript.client.pyscript", "PyScript"),
 | |
| ]
 | |
| 
 | |
| # Is this a 'silent' install - ie, avoid all dialogs.
 | |
| # Different than 'verbose'
 | |
| silent = 0
 | |
| 
 | |
| # Verbosity of output messages.
 | |
| verbose = 1
 | |
| 
 | |
| root_key_name = "Software\\Python\\PythonCore\\" + sys.winver
 | |
| 
 | |
| try:
 | |
|     # When this script is run from inside the bdist_wininst installer,
 | |
|     # file_created() and directory_created() are additional builtin
 | |
|     # functions which write lines to Python23\pywin32-install.log. This is
 | |
|     # a list of actions for the uninstaller, the format is inspired by what
 | |
|     # the Wise installer also creates.
 | |
|     file_created
 | |
|     is_bdist_wininst = True
 | |
| except NameError:
 | |
|     is_bdist_wininst = False  # we know what it is not - but not what it is :)
 | |
| 
 | |
|     def file_created(file):
 | |
|         pass
 | |
| 
 | |
|     def directory_created(directory):
 | |
|         pass
 | |
| 
 | |
|     def get_root_hkey():
 | |
|         try:
 | |
|             winreg.OpenKey(
 | |
|                 winreg.HKEY_LOCAL_MACHINE, root_key_name, 0, winreg.KEY_CREATE_SUB_KEY
 | |
|             )
 | |
|             return winreg.HKEY_LOCAL_MACHINE
 | |
|         except OSError:
 | |
|             # Either not exist, or no permissions to create subkey means
 | |
|             # must be HKCU
 | |
|             return winreg.HKEY_CURRENT_USER
 | |
| 
 | |
| 
 | |
| try:
 | |
|     create_shortcut
 | |
| except NameError:
 | |
|     # Create a function with the same signature as create_shortcut provided
 | |
|     # by bdist_wininst
 | |
|     def create_shortcut(
 | |
|         path, description, filename, arguments="", workdir="", iconpath="", iconindex=0
 | |
|     ):
 | |
|         import pythoncom
 | |
|         from win32com.shell import shell
 | |
| 
 | |
|         ilink = pythoncom.CoCreateInstance(
 | |
|             shell.CLSID_ShellLink,
 | |
|             None,
 | |
|             pythoncom.CLSCTX_INPROC_SERVER,
 | |
|             shell.IID_IShellLink,
 | |
|         )
 | |
|         ilink.SetPath(path)
 | |
|         ilink.SetDescription(description)
 | |
|         if arguments:
 | |
|             ilink.SetArguments(arguments)
 | |
|         if workdir:
 | |
|             ilink.SetWorkingDirectory(workdir)
 | |
|         if iconpath or iconindex:
 | |
|             ilink.SetIconLocation(iconpath, iconindex)
 | |
|         # now save it.
 | |
|         ipf = ilink.QueryInterface(pythoncom.IID_IPersistFile)
 | |
|         ipf.Save(filename, 0)
 | |
| 
 | |
|     # Support the same list of "path names" as bdist_wininst.
 | |
|     def get_special_folder_path(path_name):
 | |
|         from win32com.shell import shell, shellcon
 | |
| 
 | |
|         for maybe in """
 | |
|             CSIDL_COMMON_STARTMENU CSIDL_STARTMENU CSIDL_COMMON_APPDATA
 | |
|             CSIDL_LOCAL_APPDATA CSIDL_APPDATA CSIDL_COMMON_DESKTOPDIRECTORY
 | |
|             CSIDL_DESKTOPDIRECTORY CSIDL_COMMON_STARTUP CSIDL_STARTUP
 | |
|             CSIDL_COMMON_PROGRAMS CSIDL_PROGRAMS CSIDL_PROGRAM_FILES_COMMON
 | |
|             CSIDL_PROGRAM_FILES CSIDL_FONTS""".split():
 | |
|             if maybe == path_name:
 | |
|                 csidl = getattr(shellcon, maybe)
 | |
|                 return shell.SHGetSpecialFolderPath(0, csidl, False)
 | |
|         raise ValueError("%s is an unknown path ID" % (path_name,))
 | |
| 
 | |
| 
 | |
| def CopyTo(desc, src, dest):
 | |
|     import win32api
 | |
|     import win32con
 | |
| 
 | |
|     while 1:
 | |
|         try:
 | |
|             win32api.CopyFile(src, dest, 0)
 | |
|             return
 | |
|         except win32api.error as details:
 | |
|             if details.winerror == 5:  # access denied - user not admin.
 | |
|                 raise
 | |
|             if silent:
 | |
|                 # Running silent mode - just re-raise the error.
 | |
|                 raise
 | |
|             full_desc = (
 | |
|                 "Error %s\n\n"
 | |
|                 "If you have any Python applications running, "
 | |
|                 "please close them now\nand select 'Retry'\n\n%s"
 | |
|                 % (desc, details.strerror)
 | |
|             )
 | |
|             rc = win32api.MessageBox(
 | |
|                 0, full_desc, "Installation Error", win32con.MB_ABORTRETRYIGNORE
 | |
|             )
 | |
|             if rc == win32con.IDABORT:
 | |
|                 raise
 | |
|             elif rc == win32con.IDIGNORE:
 | |
|                 return
 | |
|             # else retry - around we go again.
 | |
| 
 | |
| 
 | |
| # We need to import win32api to determine the Windows system directory,
 | |
| # so we can copy our system files there - but importing win32api will
 | |
| # load the pywintypes.dll already in the system directory preventing us
 | |
| # from updating them!
 | |
| # So, we pull the same trick pywintypes.py does, but it loads from
 | |
| # our pywintypes_system32 directory.
 | |
| def LoadSystemModule(lib_dir, modname):
 | |
|     # See if this is a debug build.
 | |
|     import importlib.machinery
 | |
|     import importlib.util
 | |
| 
 | |
|     suffix = "_d" if "_d.pyd" in importlib.machinery.EXTENSION_SUFFIXES else ""
 | |
|     filename = "%s%d%d%s.dll" % (
 | |
|         modname,
 | |
|         sys.version_info[0],
 | |
|         sys.version_info[1],
 | |
|         suffix,
 | |
|     )
 | |
|     filename = os.path.join(lib_dir, "pywin32_system32", filename)
 | |
|     loader = importlib.machinery.ExtensionFileLoader(modname, filename)
 | |
|     spec = importlib.machinery.ModuleSpec(name=modname, loader=loader, origin=filename)
 | |
|     mod = importlib.util.module_from_spec(spec)
 | |
|     spec.loader.exec_module(mod)
 | |
| 
 | |
| 
 | |
| def SetPyKeyVal(key_name, value_name, value):
 | |
|     root_hkey = get_root_hkey()
 | |
|     root_key = winreg.OpenKey(root_hkey, root_key_name)
 | |
|     try:
 | |
|         my_key = winreg.CreateKey(root_key, key_name)
 | |
|         try:
 | |
|             winreg.SetValueEx(my_key, value_name, 0, winreg.REG_SZ, value)
 | |
|             if verbose:
 | |
|                 print("-> %s\\%s[%s]=%r" % (root_key_name, key_name, value_name, value))
 | |
|         finally:
 | |
|             my_key.Close()
 | |
|     finally:
 | |
|         root_key.Close()
 | |
| 
 | |
| 
 | |
| def UnsetPyKeyVal(key_name, value_name, delete_key=False):
 | |
|     root_hkey = get_root_hkey()
 | |
|     root_key = winreg.OpenKey(root_hkey, root_key_name)
 | |
|     try:
 | |
|         my_key = winreg.OpenKey(root_key, key_name, 0, winreg.KEY_SET_VALUE)
 | |
|         try:
 | |
|             winreg.DeleteValue(my_key, value_name)
 | |
|             if verbose:
 | |
|                 print("-> DELETE %s\\%s[%s]" % (root_key_name, key_name, value_name))
 | |
|         finally:
 | |
|             my_key.Close()
 | |
|         if delete_key:
 | |
|             winreg.DeleteKey(root_key, key_name)
 | |
|             if verbose:
 | |
|                 print("-> DELETE %s\\%s" % (root_key_name, key_name))
 | |
|     except OSError as why:
 | |
|         winerror = getattr(why, "winerror", why.errno)
 | |
|         if winerror != 2:  # file not found
 | |
|             raise
 | |
|     finally:
 | |
|         root_key.Close()
 | |
| 
 | |
| 
 | |
| def RegisterCOMObjects(register=True):
 | |
|     import win32com.server.register
 | |
| 
 | |
|     if register:
 | |
|         func = win32com.server.register.RegisterClasses
 | |
|     else:
 | |
|         func = win32com.server.register.UnregisterClasses
 | |
|     flags = {}
 | |
|     if not verbose:
 | |
|         flags["quiet"] = 1
 | |
|     for module, klass_name in com_modules:
 | |
|         __import__(module)
 | |
|         mod = sys.modules[module]
 | |
|         flags["finalize_register"] = getattr(mod, "DllRegisterServer", None)
 | |
|         flags["finalize_unregister"] = getattr(mod, "DllUnregisterServer", None)
 | |
|         klass = getattr(mod, klass_name)
 | |
|         func(klass, **flags)
 | |
| 
 | |
| 
 | |
| def RegisterHelpFile(register=True, lib_dir=None):
 | |
|     if lib_dir is None:
 | |
|         lib_dir = sysconfig.get_paths()["platlib"]
 | |
|     if register:
 | |
|         # Register the .chm help file.
 | |
|         chm_file = os.path.join(lib_dir, "PyWin32.chm")
 | |
|         if os.path.isfile(chm_file):
 | |
|             # This isn't recursive, so if 'Help' doesn't exist, we croak
 | |
|             SetPyKeyVal("Help", None, None)
 | |
|             SetPyKeyVal("Help\\Pythonwin Reference", None, chm_file)
 | |
|             return chm_file
 | |
|         else:
 | |
|             print("NOTE: PyWin32.chm can not be located, so has not " "been registered")
 | |
|     else:
 | |
|         UnsetPyKeyVal("Help\\Pythonwin Reference", None, delete_key=True)
 | |
|     return None
 | |
| 
 | |
| 
 | |
| def RegisterPythonwin(register=True, lib_dir=None):
 | |
|     """Add (or remove) Pythonwin to context menu for python scripts.
 | |
|     ??? Should probably also add Edit command for pys files also.
 | |
|     Also need to remove these keys on uninstall, but there's no function
 | |
|         like file_created to add registry entries to uninstall log ???
 | |
|     """
 | |
|     import os
 | |
| 
 | |
|     if lib_dir is None:
 | |
|         lib_dir = sysconfig.get_paths()["platlib"]
 | |
|     classes_root = get_root_hkey()
 | |
|     ## Installer executable doesn't seem to pass anything to postinstall script indicating if it's a debug build,
 | |
|     pythonwin_exe = os.path.join(lib_dir, "Pythonwin", "Pythonwin.exe")
 | |
|     pythonwin_edit_command = pythonwin_exe + ' -edit "%1"'
 | |
| 
 | |
|     keys_vals = [
 | |
|         (
 | |
|             "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Pythonwin.exe",
 | |
|             "",
 | |
|             pythonwin_exe,
 | |
|         ),
 | |
|         (
 | |
|             "Software\\Classes\\Python.File\\shell\\Edit with Pythonwin",
 | |
|             "command",
 | |
|             pythonwin_edit_command,
 | |
|         ),
 | |
|         (
 | |
|             "Software\\Classes\\Python.NoConFile\\shell\\Edit with Pythonwin",
 | |
|             "command",
 | |
|             pythonwin_edit_command,
 | |
|         ),
 | |
|     ]
 | |
| 
 | |
|     try:
 | |
|         if register:
 | |
|             for key, sub_key, val in keys_vals:
 | |
|                 ## Since winreg only uses the character Api functions, this can fail if Python
 | |
|                 ##  is installed to a path containing non-ascii characters
 | |
|                 hkey = winreg.CreateKey(classes_root, key)
 | |
|                 if sub_key:
 | |
|                     hkey = winreg.CreateKey(hkey, sub_key)
 | |
|                 winreg.SetValueEx(hkey, None, 0, winreg.REG_SZ, val)
 | |
|                 hkey.Close()
 | |
|         else:
 | |
|             for key, sub_key, val in keys_vals:
 | |
|                 try:
 | |
|                     if sub_key:
 | |
|                         hkey = winreg.OpenKey(classes_root, key)
 | |
|                         winreg.DeleteKey(hkey, sub_key)
 | |
|                         hkey.Close()
 | |
|                     winreg.DeleteKey(classes_root, key)
 | |
|                 except OSError as why:
 | |
|                     winerror = getattr(why, "winerror", why.errno)
 | |
|                     if winerror != 2:  # file not found
 | |
|                         raise
 | |
|     finally:
 | |
|         # tell windows about the change
 | |
|         from win32com.shell import shell, shellcon
 | |
| 
 | |
|         shell.SHChangeNotify(
 | |
|             shellcon.SHCNE_ASSOCCHANGED, shellcon.SHCNF_IDLIST, None, None
 | |
|         )
 | |
| 
 | |
| 
 | |
| def get_shortcuts_folder():
 | |
|     if get_root_hkey() == winreg.HKEY_LOCAL_MACHINE:
 | |
|         try:
 | |
|             fldr = get_special_folder_path("CSIDL_COMMON_PROGRAMS")
 | |
|         except OSError:
 | |
|             # No CSIDL_COMMON_PROGRAMS on this platform
 | |
|             fldr = get_special_folder_path("CSIDL_PROGRAMS")
 | |
|     else:
 | |
|         # non-admin install - always goes in this user's start menu.
 | |
|         fldr = get_special_folder_path("CSIDL_PROGRAMS")
 | |
| 
 | |
|     try:
 | |
|         install_group = winreg.QueryValue(
 | |
|             get_root_hkey(), root_key_name + "\\InstallPath\\InstallGroup"
 | |
|         )
 | |
|     except OSError:
 | |
|         vi = sys.version_info
 | |
|         install_group = "Python %d.%d" % (vi[0], vi[1])
 | |
|     return os.path.join(fldr, install_group)
 | |
| 
 | |
| 
 | |
| # Get the system directory, which may be the Wow64 directory if we are a 32bit
 | |
| # python on a 64bit OS.
 | |
| def get_system_dir():
 | |
|     import win32api  # we assume this exists.
 | |
| 
 | |
|     try:
 | |
|         import pythoncom
 | |
|         import win32process
 | |
|         from win32com.shell import shell, shellcon
 | |
| 
 | |
|         try:
 | |
|             if win32process.IsWow64Process():
 | |
|                 return shell.SHGetSpecialFolderPath(0, shellcon.CSIDL_SYSTEMX86)
 | |
|             return shell.SHGetSpecialFolderPath(0, shellcon.CSIDL_SYSTEM)
 | |
|         except (pythoncom.com_error, win32process.error):
 | |
|             return win32api.GetSystemDirectory()
 | |
|     except ImportError:
 | |
|         return win32api.GetSystemDirectory()
 | |
| 
 | |
| 
 | |
| def fixup_dbi():
 | |
|     # We used to have a dbi.pyd with our .pyd files, but now have a .py file.
 | |
|     # If the user didn't uninstall, they will find the .pyd which will cause
 | |
|     # problems - so handle that.
 | |
|     import win32api
 | |
|     import win32con
 | |
| 
 | |
|     pyd_name = os.path.join(os.path.dirname(win32api.__file__), "dbi.pyd")
 | |
|     pyd_d_name = os.path.join(os.path.dirname(win32api.__file__), "dbi_d.pyd")
 | |
|     py_name = os.path.join(os.path.dirname(win32con.__file__), "dbi.py")
 | |
|     for this_pyd in (pyd_name, pyd_d_name):
 | |
|         this_dest = this_pyd + ".old"
 | |
|         if os.path.isfile(this_pyd) and os.path.isfile(py_name):
 | |
|             try:
 | |
|                 if os.path.isfile(this_dest):
 | |
|                     print(
 | |
|                         "Old dbi '%s' already exists - deleting '%s'"
 | |
|                         % (this_dest, this_pyd)
 | |
|                     )
 | |
|                     os.remove(this_pyd)
 | |
|                 else:
 | |
|                     os.rename(this_pyd, this_dest)
 | |
|                     print("renamed '%s'->'%s.old'" % (this_pyd, this_pyd))
 | |
|                     file_created(this_pyd + ".old")
 | |
|             except os.error as exc:
 | |
|                 print("FAILED to rename '%s': %s" % (this_pyd, exc))
 | |
| 
 | |
| 
 | |
| def install(lib_dir):
 | |
|     import traceback
 | |
| 
 | |
|     # The .pth file is now installed as a regular file.
 | |
|     # Create the .pth file in the site-packages dir, and use only relative paths
 | |
|     # We used to write a .pth directly to sys.prefix - clobber it.
 | |
|     if os.path.isfile(os.path.join(sys.prefix, "pywin32.pth")):
 | |
|         os.unlink(os.path.join(sys.prefix, "pywin32.pth"))
 | |
|     # The .pth may be new and therefore not loaded in this session.
 | |
|     # Setup the paths just in case.
 | |
|     for name in "win32 win32\\lib Pythonwin".split():
 | |
|         sys.path.append(os.path.join(lib_dir, name))
 | |
|     # It is possible people with old versions installed with still have
 | |
|     # pywintypes and pythoncom registered.  We no longer need this, and stale
 | |
|     # entries hurt us.
 | |
|     for name in "pythoncom pywintypes".split():
 | |
|         keyname = "Software\\Python\\PythonCore\\" + sys.winver + "\\Modules\\" + name
 | |
|         for root in winreg.HKEY_LOCAL_MACHINE, winreg.HKEY_CURRENT_USER:
 | |
|             try:
 | |
|                 winreg.DeleteKey(root, keyname + "\\Debug")
 | |
|             except WindowsError:
 | |
|                 pass
 | |
|             try:
 | |
|                 winreg.DeleteKey(root, keyname)
 | |
|             except WindowsError:
 | |
|                 pass
 | |
|     LoadSystemModule(lib_dir, "pywintypes")
 | |
|     LoadSystemModule(lib_dir, "pythoncom")
 | |
|     import win32api
 | |
| 
 | |
|     # and now we can get the system directory:
 | |
|     files = glob.glob(os.path.join(lib_dir, "pywin32_system32\\*.*"))
 | |
|     if not files:
 | |
|         raise RuntimeError("No system files to copy!!")
 | |
|     # Try the system32 directory first - if that fails due to "access denied",
 | |
|     # it implies a non-admin user, and we use sys.prefix
 | |
|     for dest_dir in [get_system_dir(), sys.prefix]:
 | |
|         # and copy some files over there
 | |
|         worked = 0
 | |
|         try:
 | |
|             for fname in files:
 | |
|                 base = os.path.basename(fname)
 | |
|                 dst = os.path.join(dest_dir, base)
 | |
|                 CopyTo("installing %s" % base, fname, dst)
 | |
|                 if verbose:
 | |
|                     print("Copied %s to %s" % (base, dst))
 | |
|                 # Register the files with the uninstaller
 | |
|                 file_created(dst)
 | |
|                 worked = 1
 | |
|                 # Nuke any other versions that may exist - having
 | |
|                 # duplicates causes major headaches.
 | |
|                 bad_dest_dirs = [
 | |
|                     os.path.join(sys.prefix, "Library\\bin"),
 | |
|                     os.path.join(sys.prefix, "Lib\\site-packages\\win32"),
 | |
|                 ]
 | |
|                 if dest_dir != sys.prefix:
 | |
|                     bad_dest_dirs.append(sys.prefix)
 | |
|                 for bad_dest_dir in bad_dest_dirs:
 | |
|                     bad_fname = os.path.join(bad_dest_dir, base)
 | |
|                     if os.path.exists(bad_fname):
 | |
|                         # let exceptions go here - delete must succeed
 | |
|                         os.unlink(bad_fname)
 | |
|             if worked:
 | |
|                 break
 | |
|         except win32api.error as details:
 | |
|             if details.winerror == 5:
 | |
|                 # access denied - user not admin - try sys.prefix dir,
 | |
|                 # but first check that a version doesn't already exist
 | |
|                 # in that place - otherwise that one will still get used!
 | |
|                 if os.path.exists(dst):
 | |
|                     msg = (
 | |
|                         "The file '%s' exists, but can not be replaced "
 | |
|                         "due to insufficient permissions.  You must "
 | |
|                         "reinstall this software as an Administrator" % dst
 | |
|                     )
 | |
|                     print(msg)
 | |
|                     raise RuntimeError(msg)
 | |
|                 continue
 | |
|             raise
 | |
|     else:
 | |
|         raise RuntimeError(
 | |
|             "You don't have enough permissions to install the system files"
 | |
|         )
 | |
| 
 | |
|     # Pythonwin 'compiles' config files - record them for uninstall.
 | |
|     pywin_dir = os.path.join(lib_dir, "Pythonwin", "pywin")
 | |
|     for fname in glob.glob(os.path.join(pywin_dir, "*.cfg")):
 | |
|         file_created(fname[:-1] + "c")  # .cfg->.cfc
 | |
| 
 | |
|     # Register our demo COM objects.
 | |
|     try:
 | |
|         try:
 | |
|             RegisterCOMObjects()
 | |
|         except win32api.error as details:
 | |
|             if details.winerror != 5:  # ERROR_ACCESS_DENIED
 | |
|                 raise
 | |
|             print("You do not have the permissions to install COM objects.")
 | |
|             print("The sample COM objects were not registered.")
 | |
|     except Exception:
 | |
|         print("FAILED to register the Python COM objects")
 | |
|         traceback.print_exc()
 | |
| 
 | |
|     # There may be no main Python key in HKCU if, eg, an admin installed
 | |
|     # python itself.
 | |
|     winreg.CreateKey(get_root_hkey(), root_key_name)
 | |
| 
 | |
|     chm_file = None
 | |
|     try:
 | |
|         chm_file = RegisterHelpFile(True, lib_dir)
 | |
|     except Exception:
 | |
|         print("Failed to register help file")
 | |
|         traceback.print_exc()
 | |
|     else:
 | |
|         if verbose:
 | |
|             print("Registered help file")
 | |
| 
 | |
|     # misc other fixups.
 | |
|     fixup_dbi()
 | |
| 
 | |
|     # Register Pythonwin in context menu
 | |
|     try:
 | |
|         RegisterPythonwin(True, lib_dir)
 | |
|     except Exception:
 | |
|         print("Failed to register pythonwin as editor")
 | |
|         traceback.print_exc()
 | |
|     else:
 | |
|         if verbose:
 | |
|             print("Pythonwin has been registered in context menu")
 | |
| 
 | |
|     # Create the win32com\gen_py directory.
 | |
|     make_dir = os.path.join(lib_dir, "win32com", "gen_py")
 | |
|     if not os.path.isdir(make_dir):
 | |
|         if verbose:
 | |
|             print("Creating directory %s" % (make_dir,))
 | |
|         directory_created(make_dir)
 | |
|         os.mkdir(make_dir)
 | |
| 
 | |
|     try:
 | |
|         # create shortcuts
 | |
|         # CSIDL_COMMON_PROGRAMS only available works on NT/2000/XP, and
 | |
|         # will fail there if the user has no admin rights.
 | |
|         fldr = get_shortcuts_folder()
 | |
|         # If the group doesn't exist, then we don't make shortcuts - its
 | |
|         # possible that this isn't a "normal" install.
 | |
|         if os.path.isdir(fldr):
 | |
|             dst = os.path.join(fldr, "PythonWin.lnk")
 | |
|             create_shortcut(
 | |
|                 os.path.join(lib_dir, "Pythonwin\\Pythonwin.exe"),
 | |
|                 "The Pythonwin IDE",
 | |
|                 dst,
 | |
|                 "",
 | |
|                 sys.prefix,
 | |
|             )
 | |
|             file_created(dst)
 | |
|             if verbose:
 | |
|                 print("Shortcut for Pythonwin created")
 | |
|             # And the docs.
 | |
|             if chm_file:
 | |
|                 dst = os.path.join(fldr, "Python for Windows Documentation.lnk")
 | |
|                 doc = "Documentation for the PyWin32 extensions"
 | |
|                 create_shortcut(chm_file, doc, dst)
 | |
|                 file_created(dst)
 | |
|                 if verbose:
 | |
|                     print("Shortcut to documentation created")
 | |
|         else:
 | |
|             if verbose:
 | |
|                 print("Can't install shortcuts - %r is not a folder" % (fldr,))
 | |
|     except Exception as details:
 | |
|         print(details)
 | |
| 
 | |
|     # importing win32com.client ensures the gen_py dir created - not strictly
 | |
|     # necessary to do now, but this makes the installation "complete"
 | |
|     try:
 | |
|         import win32com.client  # noqa
 | |
|     except ImportError:
 | |
|         # Don't let this error sound fatal
 | |
|         pass
 | |
|     print("The pywin32 extensions were successfully installed.")
 | |
| 
 | |
|     if is_bdist_wininst:
 | |
|         # Open a web page with info about the .exe installers being deprecated.
 | |
|         import webbrowser
 | |
| 
 | |
|         try:
 | |
|             webbrowser.open("https://mhammond.github.io/pywin32_installers.html")
 | |
|         except webbrowser.Error:
 | |
|             print("Please visit https://mhammond.github.io/pywin32_installers.html")
 | |
| 
 | |
| 
 | |
| def uninstall(lib_dir):
 | |
|     # First ensure our system modules are loaded from pywin32_system, so
 | |
|     # we can remove the ones we copied...
 | |
|     LoadSystemModule(lib_dir, "pywintypes")
 | |
|     LoadSystemModule(lib_dir, "pythoncom")
 | |
| 
 | |
|     try:
 | |
|         RegisterCOMObjects(False)
 | |
|     except Exception as why:
 | |
|         print("Failed to unregister COM objects: %s" % (why,))
 | |
| 
 | |
|     try:
 | |
|         RegisterHelpFile(False, lib_dir)
 | |
|     except Exception as why:
 | |
|         print("Failed to unregister help file: %s" % (why,))
 | |
|     else:
 | |
|         if verbose:
 | |
|             print("Unregistered help file")
 | |
| 
 | |
|     try:
 | |
|         RegisterPythonwin(False, lib_dir)
 | |
|     except Exception as why:
 | |
|         print("Failed to unregister Pythonwin: %s" % (why,))
 | |
|     else:
 | |
|         if verbose:
 | |
|             print("Unregistered Pythonwin")
 | |
| 
 | |
|     try:
 | |
|         # remove gen_py directory.
 | |
|         gen_dir = os.path.join(lib_dir, "win32com", "gen_py")
 | |
|         if os.path.isdir(gen_dir):
 | |
|             shutil.rmtree(gen_dir)
 | |
|             if verbose:
 | |
|                 print("Removed directory %s" % (gen_dir,))
 | |
| 
 | |
|         # Remove pythonwin compiled "config" files.
 | |
|         pywin_dir = os.path.join(lib_dir, "Pythonwin", "pywin")
 | |
|         for fname in glob.glob(os.path.join(pywin_dir, "*.cfc")):
 | |
|             os.remove(fname)
 | |
| 
 | |
|         # The dbi.pyd.old files we may have created.
 | |
|         try:
 | |
|             os.remove(os.path.join(lib_dir, "win32", "dbi.pyd.old"))
 | |
|         except os.error:
 | |
|             pass
 | |
|         try:
 | |
|             os.remove(os.path.join(lib_dir, "win32", "dbi_d.pyd.old"))
 | |
|         except os.error:
 | |
|             pass
 | |
| 
 | |
|     except Exception as why:
 | |
|         print("Failed to remove misc files: %s" % (why,))
 | |
| 
 | |
|     try:
 | |
|         fldr = get_shortcuts_folder()
 | |
|         for link in ("PythonWin.lnk", "Python for Windows Documentation.lnk"):
 | |
|             fqlink = os.path.join(fldr, link)
 | |
|             if os.path.isfile(fqlink):
 | |
|                 os.remove(fqlink)
 | |
|                 if verbose:
 | |
|                     print("Removed %s" % (link,))
 | |
|     except Exception as why:
 | |
|         print("Failed to remove shortcuts: %s" % (why,))
 | |
|     # Now remove the system32 files.
 | |
|     files = glob.glob(os.path.join(lib_dir, "pywin32_system32\\*.*"))
 | |
|     # Try the system32 directory first - if that fails due to "access denied",
 | |
|     # it implies a non-admin user, and we use sys.prefix
 | |
|     try:
 | |
|         for dest_dir in [get_system_dir(), sys.prefix]:
 | |
|             # and copy some files over there
 | |
|             worked = 0
 | |
|             for fname in files:
 | |
|                 base = os.path.basename(fname)
 | |
|                 dst = os.path.join(dest_dir, base)
 | |
|                 if os.path.isfile(dst):
 | |
|                     try:
 | |
|                         os.remove(dst)
 | |
|                         worked = 1
 | |
|                         if verbose:
 | |
|                             print("Removed file %s" % (dst))
 | |
|                     except Exception:
 | |
|                         print("FAILED to remove %s" % (dst,))
 | |
|             if worked:
 | |
|                 break
 | |
|     except Exception as why:
 | |
|         print("FAILED to remove system files: %s" % (why,))
 | |
| 
 | |
| 
 | |
| # NOTE: If this script is run from inside the bdist_wininst created
 | |
| # binary installer or uninstaller, the command line args are either
 | |
| # '-install' or '-remove'.
 | |
| 
 | |
| # Important: From inside the binary installer this script MUST NOT
 | |
| # call sys.exit() or raise SystemExit, otherwise not only this script
 | |
| # but also the installer will terminate! (Is there a way to prevent
 | |
| # this from the bdist_wininst C code?)
 | |
| 
 | |
| 
 | |
| def verify_destination(location):
 | |
|     if not os.path.isdir(location):
 | |
|         raise argparse.ArgumentTypeError('Path "{}" does not exist!'.format(location))
 | |
|     return location
 | |
| 
 | |
| 
 | |
| def main():
 | |
|     import argparse
 | |
| 
 | |
|     parser = argparse.ArgumentParser(
 | |
|         formatter_class=argparse.RawDescriptionHelpFormatter,
 | |
|         description="""A post-install script for the pywin32 extensions.
 | |
| 
 | |
|     * Typical usage:
 | |
| 
 | |
|     > python pywin32_postinstall.py -install
 | |
| 
 | |
|     If you installed pywin32 via a .exe installer, this should be run
 | |
|     automatically after installation, but if it fails you can run it again.
 | |
| 
 | |
|     If you installed pywin32 via PIP, you almost certainly need to run this to
 | |
|     setup the environment correctly.
 | |
| 
 | |
|     Execute with script with a '-install' parameter, to ensure the environment
 | |
|     is setup correctly.
 | |
|     """,
 | |
|     )
 | |
|     parser.add_argument(
 | |
|         "-install",
 | |
|         default=False,
 | |
|         action="store_true",
 | |
|         help="Configure the Python environment correctly for pywin32.",
 | |
|     )
 | |
|     parser.add_argument(
 | |
|         "-remove",
 | |
|         default=False,
 | |
|         action="store_true",
 | |
|         help="Try and remove everything that was installed or copied.",
 | |
|     )
 | |
|     parser.add_argument(
 | |
|         "-wait",
 | |
|         type=int,
 | |
|         help="Wait for the specified process to terminate before starting.",
 | |
|     )
 | |
|     parser.add_argument(
 | |
|         "-silent",
 | |
|         default=False,
 | |
|         action="store_true",
 | |
|         help='Don\'t display the "Abort/Retry/Ignore" dialog for files in use.',
 | |
|     )
 | |
|     parser.add_argument(
 | |
|         "-quiet",
 | |
|         default=False,
 | |
|         action="store_true",
 | |
|         help="Don't display progress messages.",
 | |
|     )
 | |
|     parser.add_argument(
 | |
|         "-destination",
 | |
|         default=sysconfig.get_paths()["platlib"],
 | |
|         type=verify_destination,
 | |
|         help="Location of the PyWin32 installation",
 | |
|     )
 | |
| 
 | |
|     args = parser.parse_args()
 | |
| 
 | |
|     if not args.quiet:
 | |
|         print("Parsed arguments are: {}".format(args))
 | |
| 
 | |
|     if not args.install ^ args.remove:
 | |
|         parser.error("You need to either choose to -install or -remove!")
 | |
| 
 | |
|     if args.wait is not None:
 | |
|         try:
 | |
|             os.waitpid(args.wait, 0)
 | |
|         except os.error:
 | |
|             # child already dead
 | |
|             pass
 | |
| 
 | |
|     silent = args.silent
 | |
|     verbose = not args.quiet
 | |
| 
 | |
|     if args.install:
 | |
|         install(args.destination)
 | |
| 
 | |
|     if args.remove:
 | |
|         if not is_bdist_wininst:
 | |
|             uninstall(args.destination)
 | |
| 
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     main()
 |