好的,我在setuptools源代码中进行了一些调查,发现问题归结为setuptools(easy_install.py)中的一个bug:
if group=='gui_scripts':
ext, launcher = '-script.pyw', 'gui.exe'
old = ['.pyw']
new_header = re.sub('(?i)python.exe','pythonw.exe',header)
else:
ext, launcher = '-script.py', 'cli.exe'
old = ['.py','.pyc','.pyo']
new_header = re.sub('(?i)pythonw.exe','python.exe',header)
if os.path.exists(new_header[2:-1]) or sys.platform!='win32':
hdr = new_header
else:
hdr = header
最后的if语句决定了将pythonw.exe或python.exe的路径写入"frontend-script.pyw"的shebang中。由于该shebang由创建的EXE文件评估,因此需要确保else语句不被执行。问题在于,在我的情况下,new_header[2:-1]是带引号的"C:\Program Files (x86)\Python26\pythonw.exe",所以os.path.exists由于引号而导致无法找到它。
我会尝试让setuptools的开发人员进行更正。剩下的问题将是absolute pythonw.exe路径。如果我创建一个Windows设置/MSI安装程序,shebang将包含我的pythonw.exe路径("C:\Program Files (x86)\Python26\pythonw.exe"),但用户可能已经安装了Python在"C:\Python26"。我会在报告这个问题后报告最终的解决方案。
我在两年前发布了这篇文章,很抱歉我还没有提供我的解决方案。不确定是否有更现代的解决方案(可能distribute提供了一些),但以下是我当时使用的内容(复制粘贴):
文件dogsync-frontend-script.pyw
import os
import sys
import subprocess
if sys.argv[-1] == "magic":
from dogsync_frontend.launcher import main
main()
else:
subprocess.Popen([os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "pythonw.exe")),
__file__,
"magic"])
文件 dogsync-frontend.exe
自动从<python安装路径>\lib\site-packages\setuptools\gui.exe
复制而来(见下文)。如果我没记错,此文件将自动执行脚本<EXE名称>-script.py[w]
。
文件 setup.py
from setuptools import __file__ as setupToolsFilename
if os.name == "nt":
shutil.copy2(os.path.join(os.path.dirname(setupToolsFilename), "gui.exe"),
"build-environment/windows-scripts/dogsync-frontend.exe")
startScripts = dict(scripts = ["build-environment/windows-scripts/dogsync-frontend-script.pyw",
"build-environment/windows-scripts/dogsync-frontend.exe"])
else:
startScripts = dict(entry_points = {"gui_scripts" : ['dogsync-frontend = dogsync_frontend.launcher:main']})
setup(<other options>,
**startScripts)
使用这个设置,exe/pyw文件会被复制到
<python installation>\Scripts
(在Windows上),启动
dogsync-frontend.exe
将运行pyw脚本而不需要控制台。由于setuptools多年来没有更新,这个解决方案仍然有效。