You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过编程从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 21:06:23