6

用setuptools_scm来自动控制Python包的版本

 3 years ago
source link: https://note.qidong.name/2018/04/setuptools-scm/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

用setuptools_scm来自动控制Python包的版本

2018-04-26 17:34:39 +08  字数:1167  标签: Python

手动管理Python包的版本号一段时间后,寻求自动化的手段,是自然而然的。

手动管理版本

手动管理Python包的版本,需要注意两个方面:

  1. 每次发布新包前,要更新包的版本号。
  2. 在安装后的默认模块下应该有一个__version__变量,其值为版本号。

关于第一点,可以参考《PEP 440 – Version Identification and Dependency Specification》; 关于第二点,可以参考《PEP 396 – Module Version Numbers》。 当然,两边的版本号必须是相同的

除了手动修改两个版本号这种愚蠢的方案以外,要保持两边的版本号一致,无外乎两种方式:

  1. 通过包的版本号来给出__version__的值。
  2. 通过__version__的值来设置包的版本号。

具体的做法,可以参考《Single-sourcing the package version — Python Packaging User Guide》,其中给出了6种可行方案。 其中也有陷阱,但这里不再详述。 无论如何,这些方案里的版本号总是要手动去改的。

本文着重介绍其中的第7个方案——setuptools_scm

自动生成版本号

setuptools_scm是PYPA推荐的一个自动管理Python包版本号的工具,是setuptools的一个插件。 它会根据包括Git在内的各大VCS的tag,来自动生成一个版本号。

  • 当前commit就在tag上,代码没有修改: {tag}
  • 当前commit就在tag上,代码有修改: {tag}+dYYYMMMDD
  • 当前commit不在tag上,代码没有修改: {next_version}.dev{distance}+{scm letter}{revision hash}
  • 当前commit不在tag上,代码有修改: {next_version}.dev{distance}+{scm letter}{revision hash}.dYYYMMMDD

使用方式十分简单。 首先,在setup_requires中指定它。 然后,设置use_scm_version。 当然,旧的方式version=*也应该去掉。

from setuptools import setup

setup(
    ...
    setup_requires=['setuptools_scm'],
    use_scm_version=True,
    # version='0.0.1',  # delete this
    ...
)

如果Git库的根目录不在setup.py所在的目录,则会出错。 届时,可把use_scm_version替换为以下内容。

    use_scm_version={
        "root": "..",
        "relative_to": __file__,
    },

relative_to是指相对于那里,通常设为setup.py所在目录; root是指定Git库的根目录的相对位置,这里示例的..表示上一级目录,可按需指定。

设置__version__

使用setuptools_scm方案,则版本号是在setup()函数中自动生成的。 主模块的__version__如果需要和它保持一致,就需要读取已安装的当前包的版本号。

def _get_version(default='x.x.x.dev'):
    try:
        from pkg_resources import DistributionNotFound, get_distribution
    except ImportError:
        return default
    else:
        try:
            return get_distribution(__package__).version
        except DistributionNotFound:  # Run without install
            return default
        except ValueError:  # Python 3 setup
            return default
        except TypeError:  # Python 2 setup
            return default


__version__ = _get_version()

以上代码就是孤常用的一个方案。 如果出现任何意外,则返回一个明显错误的版本号x.x.x.dev。 比一般方案更复杂的一点是,孤考虑到了在setup.py中调用这个文件的情况,分别对Python 2.x和3.x做出了处理。

总结

setuptools_scm是一个不错的工具,打消了孤自己写一个的念头。 当然它也有一些不如人意的细节,比如next_version的设计。 但瑕不掩瑜,值得一试。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK