我有一个小的python应用程序,我想将其作为类UNIX系统的可下载/可安装的可执行文件。我的印象是,setuptools将是实现这一目标的最佳方式,但不知何故,这似乎不是一项常见任务。
我的目录结构如下所示:
myappname/
|-- setup.py
|-- myappname/
| |-- __init__.py
| |-- myappname.py
| |-- src/
| |-- __init__.py
| |-- mainclassfile.py
| |-- morepython/
| |-- __init__.py
| |-- extrapython1.py
| |-- extrapython2.py
包含if __name__ == "__main__":
的文件是myappname.py。此文件顶部有一行import src.mainclassfile
。
下载后,我希望用户能够执行这样的操作:
$ python setup.py build
$ python setup.py install
然后它将是一个已安装的可执行文件,可以在命令行的任何位置调用它们:
$ myappname arg1 arg2
我的setup.py的重要部分如下:
from setuptools import setup, find_packages
setup(
name='code2flow',
scripts=['myappname/myappname.py'],
package_dir={'myappname': 'myappname'},
packages=find_packages(),
)
通过运行:
$ sudo python setup.py install
然后在新的shell中:
$ myapp.py
我收到No module named
错误
答案 0 :(得分:12)
问题在于您的包布局已损坏。
它恰好在原地工作,至少在2.x.为什么?你不是以myappname
的形式访问软件包 - 但是该软件包目录所在的目录也是顶级脚本目录,因此你最终会通过旧式的相对导入来获取它的任何兄弟。
安装完成后,当然,您最终会在您的站点包中安装myappname
软件包,然后在PATH的某处安装myappname.py
的副本,因此相对导入不可能工作。
执行此操作的正确方法是将顶级脚本放在包之外(或理想情况下放入bin
目录)。
此外,您的模块和脚本不应具有相同的名称。 (有一些方法可以让你的工作,但......不要试试。)
所以,例如:
myappname/
|-- setup.py
|-- myscriptname.py
|-- myappname/
| |-- __init__.py
| |-- src/
| |-- __init__.py
| |-- mainclassfile.py
当然,到目前为止,所有这一切都使得它在就地模式下中断与安装时中断的方式完全相同。但至少可以让调试变得更容易,对吧?
无论如何,您的myscriptname.py
必须使用绝对导入:
import myappname.src.mainclassfile
您的setup.py
必须在正确的位置找到该脚本:
scripts=['myscriptname.py'],
某些人如果需要myscriptname.py
中的某些代码可以在模块内部以及脚本中访问,那么正确的做法是将其重构为两个文件 - 但如果这对某些人来说太难了原因,你总是可以写一个包装脚本。
有关详细信息,请参阅Hitchhiker包装指南中的Arranging your file and directory structure及相关章节。
另请参阅PEP 328了解有关绝对导入与相对导入的详细信息(但请记住,当它引用“高达Python 2.5”时,它实际上意味着“高达2.7”,而“从2.6开始”意味着“从3.0开始。”
有关包含通过setup.py
(通常为easy_install
和pip
)以这种方式安装的脚本的软件包的一些示例,请参阅ipython
,{{ 1}},bpython
,modulegraph
,当然还有py2app
和easy_install
本身。