我想为我的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安装程序以创建桌面或开始菜单快捷方式?
答案 0 :(得分:1)
如果要确认脚本是否正在运行,可以打印到文件而不是控制台。看起来在安装后脚本中打印到控制台的文本不会显示。
试试这个:
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)
答案 1 :(得分:1)
就像其他人在这里和其他地方评论过的那样,支持功能似乎根本不起作用(至少没有使用setuptools)。经过一天的搜索各种资源后,我找到了至少创建桌面快捷方式的方法。我正在分享我的解决方案(基本上是我发现here和here的代码混合。我应该补充一点,我的情况与yasar略有不同,因为它创建了一个已安装软件包的快捷方式(即Python的 Scripts 目录中的.exe文件)而不是脚本。
简而言之,我在我的setup.py中添加了 post_install 函数,然后使用Python extensions for Windows创建了快捷方式。从Windows注册表中读取Desktop文件夹的位置(还有其他方法,但如果桌面位于非标准位置,则它们可能不可靠)。
#!/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 :(得分:0)
至少使用Python 3.6.5,Windows上的32位,setuptools
为此工作。但根据接受的答案,通过反复试验,我发现了一些可能导致您的脚本无法按照您的意愿行事的问题。
create_shortcut
不接受关键字参数,只接受位置,因此在代码中的使用无效.lnk
扩展名才能识别快捷方式sys.executable
将是安装程序可执行文件的名称,而不是python可执行文件stdout
或stderr
,因此您可能希望登录到文本文件。我建议还将sys.stdout
和sys.stderr
重定向到日志文件。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)