如何通过编程从Sphinx Builder获取man页字符串?
用Sphinx ManPage输出替换Click CLI默认--help内容
问题背景
正在开发Click CLI应用,需要用Sphinx manpage builder生成的man格式输出替换Click默认的--help内容。
当前尝试的代码
创建Sphinx实例:
def create_sphinx_app(): tempdir = tempfile.gettempdir() dir = "/path/to/docs/commands" sphinx = Sphinx(dir, dir, tempdir, tempdir, "man", freshenv=True) return sphinx
不依赖Sphinx扩展时,以下方法可行:
app = create_sphinx_app() man_page = publish_string(contents, writer=ManualPageWriter(ManualPageBuilder(app)))
但必须使用依赖Sphinx Build环境的扩展,改用Sphinx publisher后代码如下:
app = self.create_sphinx_app() pub = create_publisher(app, "rst", contents) man_page = pub.publish()
遇到的错误
运行cli --help时触发KeyError: 'docname',完整堆栈跟踪:
Traceback (most recent call last): File "/home/user/cli/venv/bin/cli", line 33, in <module> sys.exit(load_entry_point('cli', 'console_scripts', 'cli')()) File "/home/user/cli/cli/cli.py", line 428, in entrypoint cli() File "/home/user/cli/venv/lib/python3.7/site-packages/click/core.py", line 1130, in __call__ return self.main(*args, **kwargs) File "/home/user/cli/venv/lib/python3.7/site-packages/click/core.py", line 1055, in main rv = self.invoke(ctx) File "/home/user/cli/cli/cli.py", line 175, in invoke return super().invoke(ctx) File "/home/user/cli/venv/lib/python3.7/site-packages/click/core.py", line 1655, in invoke sub_ctx = cmd.make_context(cmd_name, args, parent=ctx) File "/home/user/cli/venv/lib/python3.7/site-packages/click/core.py", line 920, in make_context self.parse_args(ctx, args) File "/home/user/cli/venv/lib/python3.7/site-packages/click/core.py", line 1378, in parse_args value, args = param.handle_parse_result(ctx, opts, args) File "/home/user/cli/venv/lib/python3.7/site-packages/click/core.py", line 2360, in handle_parse_result value = self.process_value(ctx, value) File "/home/user/cli/venv/lib/python3.7/site-packages/click/core.py", line 2322, in process_value value = self.callback(ctx, self, value) File "/home/user/cli/venv/lib/python3.7/site-packages/click/core.py", line 1273, in show_help echo(ctx.get_help(), color=ctx.color) File "/home/user/cli/venv/lib/python3.7/site-packages/click/core.py", line 699, in get_help return self.command.get_help(self) File "/home/user/cli/venv/lib/python3.7/site-packages/click/core.py", line 1298, in get_help self.format_help(ctx, formatter) File "/home/user/cli/cli/cli_util.py", line 28, in format_help help_render.render(ctx, file.read_text()) File "/home/user/cli/cli/help.py", line 67, in render converted_content = self._convert_doc_content(ctx, contents) File "/home/user/cli/cli/help.py", line 100, in _convert_doc_content man_page = pub.publish() File "/home/user/cli/venv/lib/python3.7/site-packages/docutils/core.py", line 218, in publish self.settings) File "/home/user/cli/venv/lib/python3.7/site-packages/sphinx/io.py", line 103, in read self.input = self.read_source(settings.env) File "/home/user/cli/venv/lib/python3.7/site-packages/sphinx/io.py", line 113, in read_source env.events.emit('source-read', env.docname, arg) File "/home/user/cli/venv/lib/python3.7/site-packages/sphinx/environment/__init__.py", line 463, in docname return self.temp_data['docname'] KeyError: 'docname'
可行实现方法
1. 手动填充Sphinx环境的temp_data
错误核心是Sphinx环境的temp_data缺少docname字段,直接用publisher处理字符串时未设置文档名称。创建publisher前手动添加该字段即可:
app = self.create_sphinx_app() # 为Sphinx环境设置临时文档名,名称可自定义 app.env.temp_data['docname'] = 'cli_help' pub = create_publisher(app, "rst", contents) man_page = pub.publish()
2. 借助Sphinx内部API构建单页文档
如果上述方法仍无法满足扩展需求,可使用Sphinx的文档构建API处理内容:
import os import tempfile from sphinx.builders.manpage import ManualPageBuilder def convert_rst_to_man(rst_content, sphinx_app): docname = 'cli_help' # 初始化环境临时数据 sphinx_app.env.temp_data['docname'] = docname sphinx_app.env.found_docs.add(docname) # 确保srcdir有效 sphinx_app.env.srcdir = tempfile.gettempdir() # 初始化文档路径 sphinx_app.env.doc2path(docname, base=None) # 读取并处理RST内容 sphinx_app.env.read_doc(docname, rst_content) sphinx_app.build() # 读取生成的man文件内容 man_file_path = os.path.join(sphinx_app.outdir, f'{docname}.1') with open(man_file_path, 'r') as f: return f.read()
在帮助渲染逻辑中调用该函数:
app = create_sphinx_app() man_page = convert_rst_to_man(contents, app)
3. 扩展Click的HelpFormatter
直接扩展Click的HelpFormatter类,在format_help方法中注入Sphinx转换后的man内容:
import click class ManPageHelpFormatter(click.HelpFormatter): def format_help(self, ctx, formatter): # 自定义获取RST内容的逻辑,可根据ctx获取对应命令的文档 rst_content = self.get_command_rst(ctx) app = create_sphinx_app() app.env.temp_data['docname'] = 'cli_help' pub = create_publisher(app, "rst", rst_content) man_content = pub.publish() # 输出man格式的帮助内容 formatter.write(man_content) def get_command_rst(self, ctx): # 实现获取对应命令RST文档的逻辑 return """你的RST文档内容""" # 在CLI命令中使用自定义格式化器 @click.command(formatter_class=ManPageHelpFormatter) def cli(): """CLI命令描述""" pass
内容的提问来源于stack exchange,提问作者user17297103
相关产品推荐
相关产品推荐

