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
Edit2:似乎与此相关 如何在Python中进行相对导入?
I want to distribute my app on OSX (using py2app) and as a Debian package.
The structure of my app is like:
app/
debian/
<lots of debian related stuff>
scripts/
app
app/
__init__.py
app.py
mod1/
__init__.py
a.py
mod2/
__init__.py
b.py
My setup.py looks something like:
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"]),
]
)
Then, in b.py (this is on OSX):
from app.mod2.b import *
I get:
ImportError: No module named mod2.b
So basically, mod2 can't acccess mod1. On Linux there's no problem, because the python module 'app' is installed globally in /usr/shared/pyshared. But on OSX the app will obviously be a self-contained .app thing built by py2app. I wonder if I approached this totally wrong, are there any best practices when distributing Python apps on OSX?
Edit: I also tried a hack like this in b.py:
from ..mod2.b import *
ValueError: Attempted relative import beyond toplevel package
Edit2: Seems to be related to this How to do relative imports in Python?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我不确定这是否是“最佳实践”(我没有将太多 python 软件放入正确的发行版中),但我只是确保顶级应用程序包位于 sys.path 中。比如将以下内容放入顶级
__init__.py
中:我认为应该以跨平台的方式做正确的事情。
编辑:正如 kaizer.se 指出的那样,这可能在 __init__.py 文件中不起作用,具体取决于您调用的代码的执行方式。仅当该文件被评估时它才有效。关键是确保顶级包位于实际运行的某些代码的 sys.path 中。
很多时候,为了直接执行包内的单个文件(用于使用
if __name__ eq '__main__'
习惯用法进行测试),我会执行类似放置一条语句的操作:有问题的单个文件,然后创建一个文件
_setup.py
,该文件根据需要进行路径修改。因此,类似于:如果您从
somemodule.py
导入 _setup,则该安装文件可以确保顶级包位于sys.path
中在评估somemodule.py
中的其余代码之前。I'm not sure if this is the 'best practice' or not (I've not put much python software into proper distribution), but I would just make sure that the top-level app package was in
sys.path
. Something like putting the following into the top-level__init__.py
:I think that should do the right thing in a cross platform way.
EDIT: As kaizer.se points out this might not work in the
__init__.py
file, depending on how the code you're invoking is getting executed. It would only work if that file is evaluated. The key is to make sure that the top-level package is insys.path
from some the code that actually is running.Often times, so that I an execute individual files inside of a package directly (for testing with the
if __name__ eq '__main__'
idiom), I'll do something like place a statement:At the top of the individual file in question, and then create a file
_setup.py
which does the path munging as necessary. So, something like:If you
import _setup
fromsomemodule.py
, that setup file can ensure that the top level package is insys.path
before the rest of the code insomemodule.py
is evaluated.