Determining application path in a Python EXE generated by pyInstaller
我有一个驻留在单个.py文件中的应用程序。 我已经能够让pyInstaller成功地将它捆绑到一个EXE for Windows中。 问题是,应用程序需要一个始终位于同一目录中的应用程序旁边的.cfg文件。
通常,我使用以下代码构建路径:
1 2 3 | import os config_name = 'myapp.cfg' config_path = os.path.join(sys.path[0], config_name) |
但是,当从pyInstaller生成的EXE调用sys.path时,它似乎是空白的。 当您运行python交互式命令行并尝试获取sys.path [0]时,会发生同样的行为。
有没有更具体的方法来获取当前运行的应用程序的路径,以便我可以找到相对于它的文件?
我找到了解决方案。您需要检查应用程序是作为脚本还是作为冻结的exe运行:
1 2 3 4 5 6 7 8 9 10 11 12 | import os import sys config_name = 'myapp.cfg' # determine if application is a script file or frozen exe if getattr(sys, 'frozen', False): application_path = os.path.dirname(sys.executable) elif __file__: application_path = os.path.dirname(__file__) config_path = os.path.join(application_path, config_name) |
根据pyInstaller的文档,建议的恢复应用程序路径的方法如下:
1 2 3 4 5 6 7 8 9 | #!/usr/bin/python3 import sys, os if getattr(sys, 'frozen', False): # If the application is run as a bundle, the pyInstaller bootloader #extends the sys module by a flag frozen=True and sets the app # path into variable _MEIPASS'. application_path = sys._MEIPASS else: application_path = os.path.dirname(os.path.abspath(__file__)) |
经过pyInstaller v3.2的测试,但这肯定也适用于早期版本。
Soviut的解决方案不起作用,至少对于最新版本的pyInstaller来说并不常见(注意OP已有很多年了)。例如,在MacOS上,当将应用程序捆绑到单文件包中时,
我稍微缩短了代码。
1 2 3 4 5 6 7 | import os, sys if getattr(sys, 'frozen', False): application_path = os.path.dirname(sys.executable) os.chdir(application_path) logging.debug('CWD: ' + os.getcwd()) |
但是,
1 | os.path.dirname(sys.argv[0]) |
这对我行得通。
以下内容适用于所有三种模式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import sys,os config_name = 'myapp.cfg' if getattr(sys, 'frozen', False): application_path = os.path.dirname(sys.executable) running_mode = 'Frozen/executable' else: try: app_full_path = os.path.realpath(__file__) application_path = os.path.dirname(app_full_path) running_mode ="Non-interactive (e.g. 'python myapp.py')" except NameError: application_path = os.getcwd() running_mode = 'Interactive' config_full_path = os.path.join(application_path, config_name) print('Running mode:', running_mode) print(' Appliction path :', application_path) print(' Config full path :', config_full_path) |
输出有三种不同的模式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | Running mode: Interactive Appliction path : C:\Projects\MyAppDir Config full path : C:\Projects\MyAppDir\myapp.cfg C:\Projects\MyAppDir>myapp.exe Running mode: Frozen/executable Appliction path : C:\Program Files\myapp Config full path : C:\Program Files\myapp\myapp.cfg C:\Projects\MyAppDir>python myapp.py Running mode: Non-interactive (e.g. 'python myapp.py') Appliction path : C:\Projects\MyAppDir Config full path : C:\Projects\MyAppDir\myapp.cfg C:\Projects\MyAppDir> |
这里有很多答案但我发现这个解决方案适用于大多数情况:
1 2 3 4 5 6 7 8 9 10 11 12 | import os import sys import os.path as op try: this_file = __file__ except NameError: this_file = sys.argv[0] this_file = op.abspath(this_file) if getattr(sys, 'frozen', False): application_path = getattr(sys, '_MEIPASS', op.dirname(sys.executable)) else: application_path = op.dirname(this_file) |