如何创建Python模块分发以优雅地回退到纯Python代码

时间:2010-03-08 00:50:52

标签: python software-distribution

我编写了一个Python模块,我有两个版本:纯Python实现和C扩展。我编写了__init__.py文件,以便它尝试导入C扩展,如果失败,它会导入纯Python代码(这是合理的吗?)。

现在,我想知道分发此模块的最佳方式是什么(例如,写setup.py),以便有或没有设施的人可以轻松地使用它来构建或使用C扩展,只需运行:

python setup.py install

我的经验有限,但我看到两种可能的情况:

  • 用户没有安装在其计算机上的MS Visual Studio或GCC编译器套件来构建C扩展
  • 用户正在运行IronPython,Jython或CPython以外的任何其他内容。我只使用过CPython。所以我不确定如何分发这个模块,以便它能够顺利运行并且很容易在这些平台上安装,如果他们无法使用C扩展。

3 个答案:

答案 0 :(得分:7)

  

(这是合理的吗?)。

是的,非常明智。

要捕获“没有合适的C编译器案例”:对setup(...)的调用将在出现问题时执行sys.exit。因此,首先在ext_modules

中根据需要设置try参数
try:
  setup(..., ext_modules=...)
except SystemExit: ...

并在except子句中,再次致电setup(...) ,不用 ext_modules(因此它放弃了构建和安装扩展程序)。正在安装的用户仍会看到诸如“无法执行gcc-4.0:没有这样的文件或目录”之类的消息,但是您可以适当地添加自己的消息以通知用户这没什么大不了的,并且您正在尝试再次尝试扩展模块。

为了支持非CPython实现,在setup.py中你可以测试sys.version(我不确定每个非CPython实现的值是什么,但是IronPython有{{1}例如,在那里使用子串,以避免尝试'IronPython'部分。如果你在支票中错过了一些这样的实现,那么try / except应该可能会捕获大多数其他的,只需要适量的浪费工作; - )。

答案 1 :(得分:0)

“尝试导入C扩展,如果失败,则导入纯Python代码(这是合理的吗?)。”

几乎。阅读cStringIOStringIO。另请阅读cPicklePickle。另请阅读cElementTreeElementTree

如果无法构建C版本,那就是一个用例。纯Python版本是唯一可用的版本。

但是,如果可以构建C版本,我仍有很好的理由拒绝它。主要的,我会考虑拒绝C版本,因为它可能不允许我的应用程序所需的子类深度。

我不想被迫使用C版本,因为我碰巧有正确的编译器。我更喜欢自己做出这些决定。

因此,我不喜欢您的模块的某些部分为我做出架构决策的想法。我更喜欢选择要导入的内容。如果C版本不存在,那不会改变我的决策过程,因为我可能仍在创建纯Python版本的子类。

底线。自动化程度更低。提供两个模块。我更喜欢选择要导入哪一个。

答案 2 :(得分:0)

根据documentation for Planar,您可以制作setup.py文件以正常构建C扩展名,然后:

  

从源代码分发或存储库使用构建和安装Planar:

python setup.py install
  

要仅安装纯Python模块而不编译,请使用:

python setup.py build_py install --skip-build