如果我这样做
sphinx-quickstart
我会被问到项目的版本。
我想避免有两个地方存放我的项目版本。
如何在Python打包世界中做到这一点?
最简单(也可能是最干净)的方法是为顶级包的 __version__
定义
__init__.py
,然后导入该包并读取 setup.py
和 Sphinx 项目的 conf.py
中的版本.
假设您的项目名为
myproject
。
将当前版本移出
setup.py
,并将其设为 myproject/__init__.py
中的变量:
myproject/__init__.py
:
# import foo
# ...
__version__ = '1.5'
在项目的
myproject
中导入 setup.py
,并将硬编码版本替换为 myproject.__version__
:
setup.py
:
from setuptools import setup
from myproject import __version__
project = "myproject"
setup(
name=project,
version=__version__,
# ...
)
在您的 Sphinx 项目的
conf.py
中,执行相同的操作。因此,请按照以下方式编辑生成的 conf.py
:
docs/conf.py
:
from myproject import __version__
# ...
# The short X.Y version.
version = __version__
# The full version, including alpha/beta/rc tags.
release = version
requests
模块 (__init__.py
| setup.py
| conf.py
)。
这将处理使用项目版本的自动生成的文本(例如文档首页的链接)。如果您想在特定的自定义位置使用您的版本,您可以使用
rst_epilog
指令动态插入 conf.py
中定义的配置值。
也许更干净的选择是从
setup.py
命令实际构建 sphinx,如 http://www.sphinx-doc.org/en/master/setuptools.html: 中所述
设置.py
# this is only necessary when not using setuptools/distribute
from sphinx.setup_command import BuildDoc
cmdclass = {'build_sphinx': BuildDoc}
name = 'My project'
version = '1.2'
release = '1.2.0'
setup(
name=name,
author='Bernard Montgomery',
version=release,
cmdclass=cmdclass,
# these are optional and override conf.py settings
command_options={
'build_sphinx': {
'project': ('setup.py', name),
'version': ('setup.py', version),
'release': ('setup.py', release),
'source_dir': ('setup.py', 'doc')}},
)
然后使用
构建文档$ python setup.py build_sphinx
好处:
setup.py
成为版本号的单一来源如果您使用
pyproject.toml
,您也可以在 conf.py
中使用 tomli 解析它,或者在使用 python ^3.11 时使用等效的 tomllib。pyproject.toml
中提取信息并在 sphinx 文档配置中使用它。
这里是一个使用
tomli
的简短不完整示例,假设 conf.py
<project-root>/docs/source/conf.py
:
# conf.py
import tomli
with open("../../pyproject.toml", "rb") as f:
toml = tomli.load(f)
# -- Project information -----------------------------------------------------
pyproject = toml["tool"]["poetry"]
project = pyproject["name"]
version = pyproject["version"]
release = pyproject["version"]
copyright = ...
author = ...
# and the rest of the configuration
这是一个简单的解决方案,讽刺的是来自 setuptools_scm PyPI 页面:
# contents of docs/conf.py
from importlib.metadata import version
release = version('myproject')
# for example take major/minor
version = '.'.join(release.split('.')[:2])
这是他们为什么不鼓励使用他们的 Sphinx 软件包的解释:
根本原因是,像阅读文档这样的服务有时会出于充分的原因更改工作目录,并且使用已安装的元数据可以防止在那里使用不必要的易失性数据。
另一种方法是将
setuptools_scm
集成到您的项目中。这样你就可以
from setuptools_scm import get_version
version = get_version()
在你的
conf.py
这是https://stackoverflow.com/users/2614160/jan's优秀的answer的hatchling(而不是诗歌)变体,还有一些额外的东西。
额外的一件事是它具有
my_package/__about__.py
中版本的真实来源,
所以我不会把它从pyproject.toml
中拉出来。
我的狮身人面像
conf.py
包含类似的东西。
# conf.py
import os
import sys
# ...
sys.path.insert(0, os.path.abspath("."))
sys.path.insert(0, os.path.abspath("../../src"))
from my_package import __about__ # noqa: E402
version = __about__.__version__
请注意,
"../../src"
路径可能会有所不同,具体取决于您的项目布局。
pyproject.toml
# conf.py
import tomllib
# ...
# Pull general sphinx project info from pyproject.toml
# Modified from https://stackoverflow.com/a/75396624/1304076
with open("../../pyproject.toml", "rb") as f:
toml = tomllib.load(f)
pyproject = toml["project"]
project = pyproject["name"]
release = version
author = ",".join(
[author["name"] for author in pyproject["authors"]]
)
copyright = f"2024 {author}"