py2exe 和文件系统

发布于 2024-08-07 10:12:38 字数 735 浏览 5 评论 0原文

我有一个Python应用程序。它通过以下方式加载配置文件(以及各种其他文件) 做诸如以下的事情:

_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
CONFIG_DIR = os.path.join(_path, 'conf')

这很好。但是,当我使用 py2exe 打包应用程序时,会发生不好的事情:

  File "proj\config.pyc", line 8, in <module>
WindowsError: [Error 3] The system cannot find the path specified: 'C:\\proj\
\dist\\library.zip\\conf'

显然这是一个无效的路径...有什么更可靠的方法来做到这一点?我不 想要在程序中指定绝对路径,因为它可以放置在不同的路径中 文件夹。我应该说“如果它说文件夹名称是“library.zip”,那么就去 再往下一层到“dist”文件夹”?

请注意,我有相当嵌套的目录层次结构......例如,我有 一个模块 gui.utils.images,存储在“gui/utils/images.py”中,它使用它的路径 例如,访问“gui/images/ok.png”。现在是py2exe版本 会尝试访问“proj/dist/library.zip/gui/images/ok.png”,或者其他东西, 这是行不通的。

I have a Python app. It loads config files (and various other files) by
doing stuff such as:

_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
CONFIG_DIR = os.path.join(_path, 'conf')

This works fine. However, when I package the app with py2exe, bad things happen:

  File "proj\config.pyc", line 8, in <module>
WindowsError: [Error 3] The system cannot find the path specified: 'C:\\proj\
\dist\\library.zip\\conf'

Obviously that's an invalid path... What's a more robust way of doing this? I don't
want to specify absolute paths in the program because it could be placed in different
folders. Should I just say "if it says the folder name is 'library.zip', then go
one more level down to the 'dist' folder"?

Note that I have pretty nested directory hierarchies... for example, I have
a module gui.utils.images, stored in "gui/utils/images.py", and it uses its path
to access "gui/images/ok.png", for example. Right now the py2exe version
would try to access "proj/dist/library.zip/gui/images/ok.png", or something,
which just won't work.

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

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

发布评论

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

评论(5

我恋#小黄人 2024-08-14 10:12:38

做这类事情的通常方法(如果我理解正确的话)是这样的:

  1. 检查 sys.frozen,py2exe 设法设置它,使用 getattr(sys, 'frozen', '') 之类的东西,
  2. 如果没有设置,则使用通常的方法,因为如果已设置,则从源运行
  3. ,请检查 sys.executable,因为这会将您指向 .exe 所在的位置(而不是 python.exe 所在的位置,这是它通常指向的位置)。使用类似 os.path.dirname(sys.executable) 的内容,然后将其与相对路径连接起来以查找子文件夹等

示例:

frozen = getattr(sys, 'frozen', '')

if not frozen:
    # not frozen: in regular python interpreter
    approot = os.path.dirname(__file__)

elif frozen in ('dll', 'console_exe', 'windows_exe'):
    # py2exe:
    approot = os.path.dirname(sys.executable)

elif frozen in ('macosx_app',):
    # py2app:
    # Notes on how to find stuff on MAC, by an expert (Bob Ippolito):
    # http://mail.python.org/pipermail/pythonmac-sig/2004-November/012121.html
    approot = os.environ['RESOURCEPATH']

或其某些变体...后一个处理 py2app 的使用。如果需要,您可以为其他构建器扩展此功能。

The usual approach to doing this sort of thing (if I understand properly) is this:

  1. check sys.frozen, which py2exe contrives to set, using something like getattr(sys, 'frozen', '')
  2. if that's not set, use the usual method since you're running from source
  3. if it's set, check sys.executable since that will point you to where the .exe is (instead of to where python.exe is, which is what it normally points to). Use something like os.path.dirname(sys.executable) and then join that with your relative paths to find subfolders etc

Example:

frozen = getattr(sys, 'frozen', '')

if not frozen:
    # not frozen: in regular python interpreter
    approot = os.path.dirname(__file__)

elif frozen in ('dll', 'console_exe', 'windows_exe'):
    # py2exe:
    approot = os.path.dirname(sys.executable)

elif frozen in ('macosx_app',):
    # py2app:
    # Notes on how to find stuff on MAC, by an expert (Bob Ippolito):
    # http://mail.python.org/pipermail/pythonmac-sig/2004-November/012121.html
    approot = os.environ['RESOURCEPATH']

Or some variant thereof... the latter one handles the use of py2app. You could extend this for other builders, if needed.

離殇 2024-08-14 10:12:38

这是我的解决方案(在 Windows、Linux 和 Mac 上测试)。如果应用程序或 Python 脚本通过符号链接启动,它也可以工作。

# Get if frozen
is_frozen = bool( getattr(sys, 'frozen', None) )

# Get path variable
path = sys.path if is_frozen else sys.argv

# Get nonempty first element or raise error
if path and path[0]:
    apppath = path[0]
elif is_frozen():
    raise RuntimeError('Cannot determine app path because sys.path[0] is empty.')
else:
    raise RuntimeError('Cannot determine app path in interpreter mode.')

# Make absolute (eliminate symbolic links)
apppath = os.path.abspath( os.path.realpath(apppath) )

# Split and return
appdir, appname = os.path.split(apppath)

Here's my solution (tested on Windows, Linux and Mac). It also works if the application or Python script is started via a symbolic link.

# Get if frozen
is_frozen = bool( getattr(sys, 'frozen', None) )

# Get path variable
path = sys.path if is_frozen else sys.argv

# Get nonempty first element or raise error
if path and path[0]:
    apppath = path[0]
elif is_frozen():
    raise RuntimeError('Cannot determine app path because sys.path[0] is empty.')
else:
    raise RuntimeError('Cannot determine app path in interpreter mode.')

# Make absolute (eliminate symbolic links)
apppath = os.path.abspath( os.path.realpath(apppath) )

# Split and return
appdir, appname = os.path.split(apppath)
囚你心 2024-08-14 10:12:38

您对所有包含的文件使用相对路径有何看法?我想应该可以使用 sys.path.append(".." + os.path.sep + "images") 作为关于 ok.png 的示例,然后你就可以 打开(“ok.png”,“rb”)。使用相对路径应该可以解决 py2exe 生成的library.zip 文件的问题,至少它对我来说是这样的。

What do you think about using relative paths for all of the included files? I guess it should be possible to use sys.path.append(".." + os.path.sep + "images") for your example about ok.png, then you could just open("ok.png", "rb"). Using relative paths should fix the issues with the library.zip file that's generated by py2exe, at least that's what it does for me.

兮颜 2024-08-14 10:12:38

从 py2exe 应用程序使用 os.path.dirname(os.path.abspath(sys.argv[0])) ,它将以与 python 脚本相同的方式工作(因此您可以进行测试,而无需每次都创建 exe)来自exe。

这比使用相对路径要好得多,因为您不必担心应用程序(.py 或 .exe)从哪里运行。

Use os.path.dirname(os.path.abspath(sys.argv[0])) from a py2exe app, it'll work the same way from the python script (so you can test without creating the exe every time) and from the exe.

This can be much better than using relative paths because you don't have to worry about where your app (.py or .exe) is running from.

孤千羽 2024-08-14 10:12:38

我在 Windows 中使用以下技巧。
当程序冻结在 py2exe“可执行文件”(即 my_application.exe)中时,dirname(__file__) 返回主 Python 脚本运行的文件夹。
奇怪的是,该文件夹不是包含 my_application.exe 的文件夹,而是包含 my_application.exe 本身的文件夹。
请注意,my_application.exe 不是二进制文件,而是一个压缩文件夹(您可以解压缩它),其中包含 python 库和已编译的脚本。
这就是为什么 __file__os.path.dirname 实际上是 my_application.exe

因此,这段代码为您提供了配置文件或图像的根目录(如果是冻结的应用程序,则为包含 py2exe 可执行文件的文件夹,否则为运行 python 脚本的文件夹):

dirname = os.path.dirname(__file__)
if dirname.endswith('.exe'):
    dirname = os.path.split(dirname)[0]

显然,您可以使用更通用的、可移植的方法来检测文件是否被冻结,如其他答案所示,而不是 endswith 方法。

I use the following trick in windows.
When the program is frozen in a py2exe 'executable' (i.e my_application.exe), dirname(__file__) returns the folder where your main python script is running.
Oddly enough, that folder is not the folder containing my_application.exe but my_application.exe itself.
Note that my_application.exe is not a binary file but a compressed folder (you can unzip it) that contains python libs and your compiled scripts.
That's why the os.path.dirname of your __file__ is in fact my_application.exe.

Thus, this code gives you the root directory for your configuration files or images (in case of a frozen application, the folder containing the py2exe executable, otherwise the folder from where your python script is running):

dirname = os.path.dirname(__file__)
if dirname.endswith('.exe'):
    dirname = os.path.split(dirname)[0]

Obviously you can use more general, portable methods to detect if the file is frozen as other answers show instead of the endswith method.

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