确定 pyInstaller 生成的 Python EXE 中的应用程序路径

发布于 2024-07-10 16:12:05 字数 421 浏览 12 评论 0原文

我有一个驻留在单个 .py 文件中的应用程序。 我已经能够让 pyInstaller 将其成功捆绑到 Windows 的 EXE 中。 问题是,应用程序需要一个 .cfg 文件,该文件始终直接位于应用程序旁边的同一目录中。

通常,我使用以下代码构建路径:

import os
config_name = 'myapp.cfg'
config_path = os.path.join(sys.path[0], config_name)

但是,当从 pyInstaller 生成的 EXE 调用时,sys.path 似乎是空白的。 当您运行 python 交互式命令行并尝试获取 sys.path[0] 时,会发生相同的行为。

是否有更具体的方法来获取当前正在运行的应用程序的路径,以便我可以找到与其相关的文件?

I have an application that resides in a single .py file. I've been able to get pyInstaller to bundle it successfully into an EXE for Windows. The problem is, the application requires a .cfg file that always sits directly beside the application in the same directory.

Normally, I build the path using the following code:

import os
config_name = 'myapp.cfg'
config_path = os.path.join(sys.path[0], config_name)

However, it seems the sys.path is blank when its called from an EXE generated by pyInstaller. This same behaviour occurs when you run the python interactive command line and try to fetch sys.path[0].

Is there a more concrete way of getting the path of the currently running application so that I can find files that are relative to it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

许一世地老天荒 2024-07-17 16:12:05

我找到了解决方案。 您需要检查应用程序是作为脚本运行还是作为冻结的 exe 运行:

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)

I found a solution. You need to check if the application is running as a script or as a frozen exe:

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)
我恋#小黄人 2024-07-17 16:12:05

根据PyInstaller的文档,恢复应用程序路径的建议方法是如下:

#!/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 上,将应用程序捆绑到单文件包中时,sys.executable 仅指向嵌入式存档的位置,而这不是在 pyInstaller 引导加载程序创建临时应用程序环境后应用程序实际运行的位置。 只有 sys._MEIPASS 正确指向该位置。 有关 PyInstaller 如何工作的更多信息,请参阅此文档页面

According to the documentation of PyInstaller, the suggested method of recovering application path is as follows:

#!/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__))

Tested for PyInstaller v3.2, but this certainly has been working for earlier versions as well.

Soviut's solution does not work, at least not in general for recent versions of pyInstaller (note that the OP is many years old). For instance, on MacOS, when bundling an application into a one-file-bundle, sys.executable points only to the location of the embedded archive, which is not the location where the application actually runs after the pyInstaller bootloader has created a temporary application environment. Only sys._MEIPASS correctly points to that location. Refer to this doc-page for further information on how PyInstaller works.

归属感 2024-07-17 16:12:05

我稍微缩短了代码。

import os, sys

if getattr(sys, 'frozen', False):
    application_path = os.path.dirname(sys.executable)
    os.chdir(application_path)

logging.debug('CWD: ' + os.getcwd())

但是,sys._MEIPASS 指向了错误的目录。 我认为它还需要 sys._MEIPASS + \app_name

I shortened the code a bit.

import os, sys

if getattr(sys, 'frozen', False):
    application_path = os.path.dirname(sys.executable)
    os.chdir(application_path)

logging.debug('CWD: ' + os.getcwd())

But, sys._MEIPASS pointed to a wrong directory. I think it also needs sys._MEIPASS + \app_name

澉约 2024-07-17 16:12:05

我很惊讶没有人提到 getattr() 有一个内置的默认参数,如果该属性不存在,该参数将被返回。 使用 pathlib 也可以使其更具可读性。 无论代码是否与 PyInstaller 捆绑在一起,此代码都可以工作。

from pathlib import Path
bundle_dir = Path(getattr(sys, '_MEIPASS', Path.cwd()))
config_path = bundle_dir / 'myapp.cfg'

I'm surprised nobody has mentioned that getattr() has a built-in default argument which will be returned if the attribute doesn't exist. This can also be made a bit more readable with pathlib. This code works whether or not the code is bundled with PyInstaller.

from pathlib import Path
bundle_dir = Path(getattr(sys, '_MEIPASS', Path.cwd()))
config_path = bundle_dir / 'myapp.cfg'
梦醒灬来后我 2024-07-17 16:12:05

__file__ 从命令行使用 python 可执行文件工作。 它还给出了冻结模式下没有实际路径的脚本文件名。 然而,它在交互模式下给出错误。

以下内容适用于所有三种模式:

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)

三种不同模式下的输出:

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>

__file__ works from command line with python executable. It also gives the script file name without actual path in frozen mode. However it gives error in interactive mode.

The following will work for all three modes:

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)

Output in three different modes:

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>
焚却相思 2024-07-17 16:12:05
os.path.dirname(sys.argv[0])

这对我行得通。

os.path.dirname(sys.argv[0])

That works for me.

ㄟ。诗瑗 2024-07-17 16:12:05

这里有很多答案,但我发现这个解决方案在大多数情况下都有效:

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)

Many answers here but I found this solution works in most situations:

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)
最佳男配角 2024-07-17 16:12:05

我的案例是使用一个使用 pyinstaller 运行可执行 .exe 构建的服务。 我使用 os.path.dirname(**os.path.realpath(sys.executable)**)

import os
import sys
# determine if application is a script file or frozen exe
if getattr(sys, 'frozen', False):
    application_path = os.path.dirname(os.path.realpath(sys.executable))
elif __file__:
    application_path = os.path.dirname(__file__)

My case is using a service that runs an executable .exe build with pyinstaller. I use os.path.dirname(**os.path.realpath(sys.executable)**)

import os
import sys
# determine if application is a script file or frozen exe
if getattr(sys, 'frozen', False):
    application_path = os.path.dirname(os.path.realpath(sys.executable))
elif __file__:
    application_path = os.path.dirname(__file__)
余生一个溪 2024-07-17 16:12:05

如果我想使用的 .exe 旁边有一个文件夹,那么我将如何处理 pyinstaller 相对路径:

import os
import pathlib

os.environ['base_path'] = os.path.dirname(sys.argv[0])
files_to_process = glob.glob( str(pathlib.Path(os.environ.get('base_path')) / 'to_process/*.pdf') )

无论您是作为脚本还是 exe 执行,这都有效。

Here's how I handle my pyinstaller relative paths if I have a folder next to the .exe I want to use:

import os
import pathlib

os.environ['base_path'] = os.path.dirname(sys.argv[0])
files_to_process = glob.glob( str(pathlib.Path(os.environ.get('base_path')) / 'to_process/*.pdf') )

This works whether you're executing as a script or exe.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文