我想在OSX(使用py2app)和Debian软件包上分发我的应用程序.
我的应用程序的结构如下:
app/ debian/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中试过这样的hack:
from ..mod2.b import * ValueError: Attempted relative import beyond toplevel package
Edit2:似乎与此相关如何在Python中进行相对导入?
我不确定这是否是"最佳实践"(我没有把很多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__ eq '__main__'
成语进行测试),我会做一些像放置语句的事情:
import _setup
在相关单个文件的顶部,然后创建一个文件_setup.py
,根据需要执行路径修改.所以,像:
package/ __init__.py _setup.py mod1/ __init__.py _setup.py somemodule.py
如果你import _setup
来自somemodule.py
,那个安装文件可以确保sys.path
在somemodule.py
评估其余代码之前顶层包.