【问题标题】:How to create a shortcut in startmenu using setuptools windows installer如何使用 setuptools windows 安装程序在开始菜单中创建快捷方式
【发布时间】:2014-09-10 13:02:51
【问题描述】:

我想为我的 Python Windows 安装程序包创建一个开始菜单或桌面快捷方式。我正在尝试关注https://docs.python.org/3.4/distutils/builtdist.html#the-postinstallation-script

这是我的脚本;

import sys

from os.path import dirname, join, expanduser

pyw_executable = sys.executable.replace('python.exe','pythonw.exe')
script_file = join(dirname(pyw_executable), 'Scripts', 'tklsystem-script.py')
w_dir = expanduser(join('~','lsf_files'))

print(sys.argv)

if sys.argv[1] == '-install':
    print('Creating Shortcut')
    create_shortcut(
        target=pyw_executable,
        description='A program to work with L-System Equations',
        filename='L-System Tool',
        arguments=script_file,
        workdir=wdir
    )

如上述文档所示,我还在脚本设置选项中指定了此脚本。

这是我用来创建安装程序的命令;

python setup.py bdist_wininst --install-script tklsystem-post-install.py

使用创建的 Windows 安装程序安装我的包后,我找不到我的快捷方式创建的位置,也无法确认我的脚本是否运行?

如何让 setuptools 生成 windows 安装程序来创建桌面或开始菜单快捷方式?

【问题讨论】:

    标签: python windows installation setuptools startmenu


    【解决方案1】:

    就像其他人在这里和其他地方评论的那样,支持功能似乎根本不起作用(至少不适用于 setuptools)。经过一整天的各种资源搜索后,我找到了一种至少可以创建桌面快捷方式的方法。我正在分享我的解决方案(基本上是我找到的 herehere 的代码组合)。我应该补充一点,我的情况与yasar 的情况略有不同,因为它创建了一个已安装包的快捷方式(即 Python 的 Scripts 目录中的 .exe 文件)而不是脚本。

    简而言之,我在 setup.py 中添加了一个 post_install 函数,然后使用 Python extensions for Windows 创建快捷方式。桌面文件夹的位置是从 Windows 注册表中读取的(还有其他方法可以做到这一点,但如果桌面位于非标准位置,它们可能不可靠)。

    #!/usr/bin/env python
    
    import os
    import sys
    import sysconfig
    if sys.platform == 'win32':
        from win32com.client import Dispatch
        import winreg
    
    def get_reg(name,path):
        # Read variable from Windows Registry
        # From https://stackoverflow.com/a/35286642
        try:
            registry_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, path, 0,
                                           winreg.KEY_READ)
            value, regtype = winreg.QueryValueEx(registry_key, name)
            winreg.CloseKey(registry_key)
            return value
        except WindowsError:
            return None
    
    def post_install():
        # Creates a Desktop shortcut to the installed software
    
        # Package name
        packageName = 'mypackage'
    
        # Scripts directory (location of launcher script)
        scriptsDir = sysconfig.get_path('scripts')
    
        # Target of shortcut
        target = os.path.join(scriptsDir, packageName + '.exe')
    
        # Name of link file
        linkName = packageName + '.lnk'
    
        # Read location of Windows desktop folder from registry
        regName = 'Desktop'
        regPath = r'Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders'
        desktopFolder = os.path.normpath(get_reg(regName,regPath))
    
        # Path to location of link file
        pathLink = os.path.join(desktopFolder, linkName)
        shell = Dispatch('WScript.Shell')
        shortcut = shell.CreateShortCut(pathLink)
        shortcut.Targetpath = target
        shortcut.WorkingDirectory = scriptsDir
        shortcut.IconLocation = target
        shortcut.save()
    
    setup(name='mypackage',
          ...,
          ...)
    
    if sys.argv[1] == 'install' and sys.platform == 'win32':
        post_install()
    

    这是一个完整设置脚本的链接,我在其中使用了这个:

    https://github.com/KBNLresearch/iromlab/blob/master/setup.py

    【讨论】:

      【解决方案2】:

      如果要确认脚本是否正在运行,可以打印到文件而不是控制台。看起来您在安装后脚本中打印到控制台的文本不会显示。

      试试这个:

      import sys
      from os.path import expanduser, join
      
      pyw_executable = join(sys.prefix, "pythonw.exe")
      shortcut_filename = "L-System Toolsss.lnk"
      working_dir = expanduser(join('~','lsf_files'))
      script_path = join(sys.prefix, "Scripts", "tklsystem-script.py")
      
      if sys.argv[1] == '-install':
          # Log output to a file (for test)
          f = open(r"C:\test.txt",'w')
          print('Creating Shortcut', file=f)
      
          # Get paths to the desktop and start menu
          desktop_path = get_special_folder_path("CSIDL_COMMON_DESKTOPDIRECTORY")
          startmenu_path = get_special_folder_path("CSIDL_COMMON_STARTMENU")
      
          # Create shortcuts.
          for path in [desktop_path, startmenu_path]:
              create_shortcut(pyw_executable,
                          "A program to work with L-System Equations",
                          join(path, shortcut_filename),
                          script_path,
                          working_dir)
      

      【讨论】:

      • 这真的适用于新的 setuptools 模块吗?似乎连支持函数 get_special_folder_path 都不存在了。 setuptools 不能完全替代旧的 distutils。
      【解决方案3】:

      至少对于 Windows 上的 32 位 Python 3.6.5,setuptools 确实 可以解决这个问题。但是根据接受的答案,通过反复试验,我发现了一些可能导致您的脚本无法执行您想要的操作的问题。

      1. create_shortcut 不接受关键字参数,只接受位置参数,因此它在您的代码中的使用无效
      2. 您必须添加.lnk 扩展名,Windows 才能识别快捷方式
      3. 我发现sys.executable 将是安装程序可执行文件的名称,而不是 python 可执行文件的名称
      4. 如前所述,您看不到stdoutstderr,因此您可能需要登录到文本文件。我建议还将sys.stdoutsys.stderr 重定向到日志文件。
      5. (可能不相关)如in this question 所述,bdist_wininst 生成的版本字符串似乎存在错误。我使用那里的答案中的 hexediting hack 来解决这个问题。答案中的位置不一样,要自己找-32

      完整示例脚本:

      import sys
      import os
      import datetime
      global datadir
      datadir = os.path.join(get_special_folder_path("CSIDL_APPDATA"), "mymodule")
      def main(argv):
          if "-install" in argv:
              desktop = get_special_folder_path("CSIDL_DESKTOPDIRECTORY")
              print("Desktop path: %s" % repr(desktop))
              if not os.path.exists(datadir):
                  os.makedirs(datadir)
                  dir_created(datadir)
                  print("Created data directory: %s" % repr(datadir))
              else:
                  print("Data directory already existed at %s" % repr(datadir))
      
              shortcut = os.path.join(desktop, "MyModule.lnk")
              if os.path.exists(shortcut):
                  print("Remove existing shortcut at %s" % repr(shortcut))
                  os.unlink(shortcut)
      
              print("Creating shortcut at %s...\n" % shortcut)
              create_shortcut(
                  r'C:\Python36\python.exe',
                  "MyModuleScript",
                  shortcut, 
                  "",
                  datadir)
              file_created(shortcut)
              print("Successfull!")
          elif "-remove" in sys.argv:
              print("Removing...")
              pass
      
      
      if __name__ == "__main__":
          logfile = r'C:\mymodule_install.log' # Fallback location
          if os.path.exists(datadir):
              logfile = os.path.join(datadir, "install.log")
          elif os.environ.get("TEMP") and os.path.exists(os.environ.get("TEMP"),""):
              logfile = os.path.join(os.environ.get("TEMP"), "mymodule_install.log")
      
          with open(logfile, 'a+') as f:
              f.write("Opened\r\n")
              f.write("Ran %s %s at %s" % (sys.executable, " ".join(sys.argv), datetime.datetime.now().isoformat()))
              sys.stdout = f
              sys.stderr = f
              try:
                  main(sys.argv)
              except Exception as e:
                  raise
              f.close()
      
          sys.exit(0)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-02-23
        • 1970-01-01
        • 2017-11-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多