Python应用跨平台分发

2 投票
1 回答
1643 浏览
提问于 2025-04-15 15:44

我想在OSX上发布我的应用程序(使用py2app),同时也想做成Debian包。

我的应用程序结构大致是这样的:

app/
     debian/
            <lots of debian related stuff>
     scripts/
             app
     app/
         __init__.py
         app.py
         mod1/
              __init__.py
              a.py
         mod2/
              __init__.py
              b.py

我的setup.py文件大概是这样的:

from setuptools import setup
import os
import os.path

osname = os.uname()[0]

if osname == 'Darwin':
    APP = ['app/app.py']
    DATA_FILES = []
    OPTIONS = {'argv_emulation': True}

    setup(
        app=APP,
        data_files=DATA_FILES,
        options={'py2app': OPTIONS},
        setup_requires=['py2app'],
    )
elif osname == 'Linux':
        setup(
        name = "app",
        version = "0.0.1",
        description = "foo bar",
        packages = ["app", "app.mod1", "app.mod2"],
        scripts = ["scripts/app"],
        data_files = [
            ("/usr/bin", ["scripts/app"]),
       ]
    )

然后,在b.py文件中(这是在OSX上):

from app.mod2.b import *

我遇到了:

ImportError: No module named mod2.b

简单来说,mod2无法访问mod1。在Linux上没有问题,因为Python模块'app'是全局安装在/usr/shared/pyshared目录下的。但在OSX上,应用程序显然是一个由py2app构建的独立的.app文件。我在想我是不是完全走错了方向,关于在OSX上发布Python应用程序有没有什么好的做法?

补充:我在b.py中尝试了这样的一个小技巧:

from ..mod2.b import *

ValueError: Attempted relative import beyond toplevel package

补充2:似乎和这个如何在Python中进行相对导入?有关。

1 个回答

5

我不太确定这是不是“最佳做法”(因为我没有把很多Python软件放到正式的发布中),但我会确保顶层的应用包在 sys.path 中。可以在顶层的 __init__.py 文件里放入以下内容:

try:
    import myapp
except ImportError:
    import sys
    from os.path import abspath, dirname, split
    parent_dir = split(dirname(abspath(__file__)))[0]
    sys.path.append(parent_dir)

我觉得这样做在不同平台上都能正常工作。

补充说明:正如kaizer.se提到的,这可能在 __init__.py 文件中不起作用,这取决于你调用的代码是如何执行的。只有当那个文件被执行时,这才有效。关键是要确保顶层包在某些实际运行的代码中被添加到 sys.path

通常,为了让我能够直接执行包中的单个文件(比如用 if __name__ == '__main__' 这种方式测试),我会在相关文件的顶部放一个语句:

import _setup

然后创建一个 _setup.py 文件,按需处理路径。比如说:

package/
    __init__.py
    _setup.py
    mod1/
        __init__.py
        _setup.py
        somemodule.py

如果你从 somemodule.pyimport _setup,那么这个设置文件可以确保顶层包在执行 somemodule.py 中其他代码之前被添加到 sys.path 中。

撰写回答