Python应用跨平台分发
我想在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.py
中 import _setup
,那么这个设置文件可以确保顶层包在执行 somemodule.py
中其他代码之前被添加到 sys.path
中。