如何组织Python模块以支持2.x和3.x发布到PyPI

17 投票
2 回答
1713 浏览
提问于 2025-04-15 20:08

我有一个Python模块,想把它上传到PyPI(Python的包管理网站)。目前这个模块可以在Python 2.x上运行。现在为3.x版本写一个也应该不难。

不过,我按照以下这些地方的指南来制作模块:

但是我不太清楚怎么支持不同Python版本的多个源代码分发,也不太清楚PyPI是否能支持这个。我想象中,我可能需要为以下版本准备不同的代码:

  • 2.x
  • 2.6(可能作为一个特殊情况,使用新的缓冲区API)
  • 3.x

那么,如何在PyPI上设置一个Python模块,让用户可以这样做:

easy_install modulename

无论用户使用的是2.x还是3.x,都能安装到合适的版本呢?

2 个回答

1

最简单的解决办法就是使用一个统一的源代码包。

18

我发现httplib2的setup.py文件似乎有一种优雅的方法来支持Python 2.x和3.x。所以我决定借鉴这个方法。

我的任务是制作一个单一的setup.py文件,用于打包分发,能够兼容所有支持的Python版本。这样,你就可以用同一个setup.py来做:

python2 setup.py install

还有

python3 setup.py install

应该可以保持setup.py简单到可以被所有支持的Python版本解析。我已经成功地做到这一点,创建了一个支持2.4到2.6以及3.1的包cobs。这个包包含了纯Python代码(Python 2.x和3.x的代码是分开的)以及C扩展,分别为2.x和3.x编写。

具体步骤如下:

1) 我把Python 2.x的代码放在一个python2子目录里,把Python 3.x的代码放在python3子目录里。

2) 我把2.x和3.x的C扩展代码放在python2python3下的src目录里。

所以,目录结构是:

root
  |
  +--python2
  |     |
  |     +--src
  |
  +--python3
  |     |
  |     +--src
  |
  +--setup.py
  +--MANIFEST.in

3) 在setup.py的顶部,我添加了这些行:

if sys.version_info[0] == 2:
    base_dir = 'python2'
elif sys.version_info[0] == 3:
    base_dir = 'python3'

4) 在调用setup时,我像平常一样指定了包:

setup(
    ...
    packages=[ 'cobs', 'cobs.cobs', 'cobs.cobsr', ],

5) 我使用package_dir选项指定了Python代码的基础目录(参考步骤3中的base_dir):

    package_dir={
        'cobs' : base_dir + '/cobs',
    },

6) 对于C扩展,我给出了路径:

    ext_modules=[
        Extension('cobs.cobs._cobs_ext', [ base_dir + '/src/_cobs_ext.c', ]),
        Extension('cobs.cobsr._cobsr_ext', [ base_dir + '/src/_cobsr_ext.c', ]),
    ],

这就是setup.py的主要内容。这个setup.py文件可以被Python 2.x和3.x解析。

7) 最后,如果你使用以下命令构建源分发:

python2 setup.py sdist

那么默认情况下,它只会拉取构建该Python版本所需的文件。例如,在上面的情况下,你只会在源分发中得到python2下的文件,而不会得到python3下的文件。但如果你想要一个完整的源分发,你需要包含2.x和3.x的文件。为此,创建一个MANIFEST.in文件,内容类似于:

include *.txt
recursive-include python2 *
recursive-include python3 *

想了解我做了什么,可以查看cobs的源代码,或者在BitBucket上查看。

撰写回答