【问题标题】:How to properly write cross-references to external documentation with intersphinx?如何使用 intersphinx 正确编写对外部文档的交叉引用?
【发布时间】:2015-09-05 12:55:30
【问题描述】:

我正在尝试将外部 API 的交叉引用添加到我的文档中,但我面临三种不同的行为。

我将 sphinx(1.3.1) 与 Python(2.7.3) 一起使用,我的 intersphinx 映射配置为:

{
'python': ('https://docs.python.org/2.7', None),
'numpy': ('http://docs.scipy.org/doc/numpy/', None),
'cv2' : ('http://docs.opencv.org/2.4/', None),
'h5py' : ('http://docs.h5py.org/en/latest/', None)
}

使用:class:`numpy.ndarray`:func:`numpy.array` 编写对numpy API 的交叉引用没有问题,正如预期的那样,这给了我numpy.ndarray 之类的东西。

但是,使用 h5py,生成链接的唯一方法是省略模块名称。例如,:class:`Group`(或:class:`h5py:Group`)给了我Group,但:class:`h5py.Group` 无法生成链接。

最后,我找不到编写对 OpenCV API 的有效交叉引用的方法,这些似乎都不起作用:

:func:`cv2.convertScaleAbs`
:func:`cv2:cv2.convertScaleAbs`
:func:`cv2:convertScaleAbs`
:func:`convertScaleAbs`

如何正确编写对外部 API 的交叉引用,或配置 intersphinx,以在 numpy 情况下生成链接?

【问题讨论】:

    标签: python opencv documentation python-sphinx autodoc


    【解决方案1】:

    除了@gall 的详细回答,我发现intersphinx 也可以作为模块运行:

    python -m sphinx.ext.intersphinx 'http://python-eve.org/objects.inv'
    

    这会输出格式良好的信息。供参考:https://github.com/sphinx-doc/sphinx/blob/master/sphinx/ext/intersphinx.py#L390

    【讨论】:

    • 在 Sphinx 1.4.3 中损坏?我刚收到intersphinx inventory 'http://docs.python.org/' not readable due to AttributeError: 'MockApp' object has no attribute 'info'
    • 它确实适用于本地文件:wget http://python-eve.org/objects.inv,然后是 python -m sphinx.ext.intersphinx object.inv
    • python -m sphinx.ext.intersphinx 'http://python-eve.org/objects.inv' 在 Sphinx 1.6.2 中再次工作。
    【解决方案2】:

    我再次尝试理解 objects.inv 文件的内容,希望这次我检查了 numpy 和 h5py 而不仅仅是 OpenCV 的。

    如何读取 intersphinx 库存文件

    尽管我在阅读object.inv 文件的内容时找不到任何有用的信息,但实际上使用 intersphinx 模块非常简单。

    from sphinx.ext import intersphinx
    import warnings
    
    
    def fetch_inventory(uri):
        """Read a Sphinx inventory file into a dictionary."""
        class MockConfig(object):
            intersphinx_timeout = None  # type: int
            tls_verify = False
    
        class MockApp(object):
            srcdir = ''
            config = MockConfig()
    
            def warn(self, msg):
                warnings.warn(msg)
    
        return intersphinx.fetch_inventory(MockApp(), '', uri)
    
    
    uri = 'http://docs.python.org/2.7/objects.inv'
    
    # Read inventory into a dictionary
    inv = fetch_inventory(uri)
    # Or just print it
    intersphinx.debug(['', uri])
    

    文件结构(numpy)

    检查 numpy 后,您可以看到键是域:

    [u'np-c:function',
     u'std:label',
     u'c:member',
     u'np:classmethod',
     u'np:data',
     u'py:class',
     u'np-c:member',
     u'c:var',
     u'np:class',
     u'np:function',
     u'py:module',
     u'np-c:macro',
     u'np:exception',
     u'py:method',
     u'np:method',
     u'np-c:var',
     u'py:exception',
     u'np:staticmethod',
     u'py:staticmethod',
     u'c:type',
     u'np-c:type',
     u'c:macro',
     u'c:function',
     u'np:module',
     u'py:data',
     u'np:attribute',
     u'std:term',
     u'py:function',
     u'py:classmethod',
     u'py:attribute']
    

    您可以在查看特定域的内容时了解如何编写交叉引用。例如py:class:

    {u'numpy.DataSource': (u'NumPy',
      u'1.9',
      u'http://docs.scipy.org/doc/numpy/reference/generated/numpy.DataSource.html#numpy.DataSource',
      u'-'),
     u'numpy.MachAr': (u'NumPy',
      u'1.9',
      u'http://docs.scipy.org/doc/numpy/reference/generated/numpy.MachAr.html#numpy.MachAr',
      u'-'),
     u'numpy.broadcast': (u'NumPy',
      u'1.9',
      u'http://docs.scipy.org/doc/numpy/reference/generated/numpy.broadcast.html#numpy.broadcast',
      u'-'),
      ...}
    

    因此,:class:`numpy.DataSource` 将按预期工作。

    h5py

    ​​>

    对于 h5py,域是:

    [u'py:attribute', u'std:label', u'py:method', u'py:function', u'py:class']
    

    如果您查看py:class 域:

    {u'AttributeManager': (u'h5py',
      u'2.5',
      u'http://docs.h5py.org/en/latest/high/attr.html#AttributeManager',
      u'-'),
     u'Dataset': (u'h5py',
      u'2.5',
      u'http://docs.h5py.org/en/latest/high/dataset.html#Dataset',
      u'-'),
     u'ExternalLink': (u'h5py',
      u'2.5',
      u'http://docs.h5py.org/en/latest/high/group.html#ExternalLink',
      u'-'),
     ...}
    

    这就是为什么我不能让它作为 numpy 引用工作。所以格式化它们的好方法是:class:`h5py:Dataset`

    OpenCV

    OpenCV 的清单对象似乎格式不正确。我希望找到域的地方实际上有 902 个函数签名:

    [u':',
     u'AdjusterAdapter::create(const',
     u'AdjusterAdapter::good()',
     u'AdjusterAdapter::tooFew(int',
     u'AdjusterAdapter::tooMany(int',
     u'Algorithm::create(const',
     u'Algorithm::getList(vector<string>&',
     u'Algorithm::name()',
     u'Algorithm::read(const',
     u'Algorithm::set(const'
     ...]
    

    如果我们取第一个值:

    {u'Ptr<AdjusterAdapter>': (u'OpenCV',
      u'2.4',
      u'http://docs.opencv.org/2.4/detectorType)',
      u'ocv:function 1 modules/features2d/doc/common_interfaces_of_feature_detectors.html#$ -')}
    

    我很确定用这个文件编写 OpenCV 交叉引用是不可能的......

    结论

    我认为 intersphinx 根据文档项目的内容以标准方式生成了objects.inv,但似乎并非如此。 因此,编写交叉引用的正确方法似乎取决于 API,并且应该检查特定的清单对象以实际查看可用的内容。

    【讨论】:

    • 旁注:opencv3 已删除所有 sphinx 文档(支持 doxygen)
    • 我正在尝试获取指向 np.float_ 的链接,但它不起作用。我正在尝试:c:var:`NPY_FLOAT` 之类的东西,但 sphinx 抱怨“未知文本角色”。如果我使用:class:`NPY_FLOAT` intersphinx 不会正确放置在链接中。有什么想法吗? (顺便说一句,这里做得很好!)
    • @Brian 据我了解 Sphinx 文档,Domains 用于描述某些内容,Cross-references 基本上是指向这些资源的链接。如果您查看C domain,您会发现var 可用作(用于描述变量),但不能用作交叉引用。在这种情况下,您必须使用:c:data:`NPY_FLOAT`
    • 嗯,:c:data: 可能是我没有尝试过的。可以肯定的是,我至少尝试了:c:attr:,但没有成功。我会给data 一个机会...谢谢!
    • 不再编写这个不再工作的 Python 程序,而是可以通过运行 intersphinx 模块来提取信息,如this other answer: python -m sphinx.ext.intersphinx FILE.inv
    【解决方案3】:

    如何使用 OpenCV 2.4 (cv2) intersphinx

    受@Gall 回答的启发,我想比较 OpenCV 和 numpy 库存文件的内容。我无法让sphinx.ext.intersphinx.fetch_inventory 在 ipython 中工作,但以下方法确实有效:

    curl http://docs.opencv.org/2.4/objects.inv | tail -n +5 | zlib-flate -uncompress > cv2.inv
    curl https://docs.scipy.org/doc/numpy/objects.inv | tail -n +5 | zlib-flate -uncompress > numpy.inv
    

    numpy.inv 有这样的行:

    numpy.ndarray py:class 1 reference/generated/numpy.ndarray.html#$ -
    

    而 cv2.inv 有这样的行:

    cv2.imread ocv:pyfunction 1 modules/highgui/doc/reading_and_writing_images_and_video.html#$ -
    

    因此,您可能会使用:ocv:pyfunction:`cv2.imread` 而不是:py:function:`cv2.imread` 链接到OpenCV 文档。斯芬克斯不喜欢它:

    警告:未知的解释文本角色“ocv:pyfunction”。

    通过谷歌搜索发现 OpenCV 项目有自己的“ocv”sphinx 域:https://github.com/opencv/opencv/blob/2.4/doc/ocv.py——大概是因为他们需要同时记录 C、C++ 和 Python API。

    要使用它,请将ocv.py 保存在您的Sphinx conf.py 旁边,然后修改您的conf.py

    sys.path.insert(0, os.path.abspath('.'))
    import ocv
    extensions = [
        'ocv',
    ]
    intersphinx_mapping = {
        'cv2': ('http://docs.opencv.org/2.4/', None),
    }
    

    在你的第一个文件中你需要说:ocv:pyfunc:`cv2.imread`(不是:ocv:pyfunction:)。

    Sphinx 会打印一些警告 (unparseable C++ definition: u'cv2.imread'),但生成的 html 文档实际上看起来不错,带有指向 http://docs.opencv.org/2.4/modules/highgui/doc/reading_and_writing_images_and_video.html#cv2.imread 的链接。您可以编辑 ocv.py 并删除打印该警告的行。

    【讨论】:

      【解决方案4】:

      检查objects.inv 文件的另一种方法是使用sphobjinv 模块。

      您可以搜索本地甚至远程库存文件(使用模糊匹配)。以 scipy 为例:

      $ sphobjinv suggest -t 90 -u https://docs.scipy.org/doc/scipy/reference/objects.inv "signal.convolve2d"
      
      Remote inventory found.
      
      :py:function:`scipy.signal.convolve2d`
      :std:doc:`generated/scipy.signal.convolve2d`
      

      请注意,您可能需要使用 :py:func: 而不是 :py:function:(我很乐意知道原因)。

      【讨论】:

      • 必须在交叉引用中使用:func: 而不是objects.inv 中列出的:function:,这只是Sphinx 中Python 域的一个特性。所有这些术语都定义为here;您必须查阅底层 docutils 的文档,以了解所有语法的实际作用。
      • 这里也是文档中有关如何引用 Python 对象的相关部分:sphinx-doc.org/en/master/usage/restructuredtext/…
      【解决方案5】:

      已接受的答案在新版本 (1.5.x) 中不再有效...

      import requests
      import posixpath
      from sphinx.ext.intersphinx import read_inventory
      
      uri = 'http://docs.python.org/2.7/'
      
      r = requests.get(uri + 'objects.inv', stream=True)
      r.raise_for_status()
      
      inv = read_inventory(r.raw, uri, posixpath.join)
      

      【讨论】:

      • 这个答案也不起作用(用 1.6.2 测试):“ImportError: cannot import name read_inventory”。
      • 我当时使用的是 1.5.x,所以你可能是对的。想要提交适用于 1.6.2 的答案吗?
      • @lingfish 的答案在 1.4.3 中停止工作。但它在 1.6.2 中再次起作用。
      【解决方案6】:

      我是个顽固的傻瓜,我使用 2to3Sphinx deprecated APIs chart 恢复了 @david-röthlisberger's ocv.py-based answer,因此它可以在 Python 3.5 上与 Sphinx 2.3 一起使用。

      修正版在这里:

      https://gist.github.com/ssokolow/a230b27b7ea4a31f7fb40621e6461f9a

      ...我所做的快速版本是:

      1. 运行2to3 -w ocv.py &amp;&amp; rm ocv.py.bak
      2. 在运行 Sphinx 和将函数重命名为图表中的替换项之间来回循环。我相信这些是我在这一步中必须做出的唯一改变:
        1. Directive 现在必须从 docutils.parsers.rst 导入
        2. 将对l_(...) 的调用替换为对_(...) 的调用,并删除l_ 导入。
      3. 将对env.warn 的调用替换为对log.warn 的调用,其中log = sphinx.util.logging.getLogger(__name__)

      然后,您只需将它与这个 intersphinx 定义配对,您就会得到一些新的东西,足以与大多数用例相关:

      'cv2': ('https://docs.opencv.org/3.0-last-rst/', None)
      

      【讨论】:

        【解决方案7】:

        为方便起见,我对 intersphinx 交叉引用的别名做了一个小扩展。这很有用,因为有时当从包的__init__.py 导入子模块中的对象时,对象清单会变得混乱。

        另见https://github.com/sphinx-doc/sphinx/issues/5603

        ###
        # Workaround of
        # Intersphinx references to objects imported at package level can"t be mapped.
        #
        # See https://github.com/sphinx-doc/sphinx/issues/5603
        
        intersphinx_aliases = {
            ("py:class", "click.core.Group"):
                ("py:class", "click.Group"),
            ("py:class", "click.core.Command"):
                ("py:class", "click.Command"),
        }
        
        
        def add_intersphinx_aliases_to_inv(app):
            from sphinx.ext.intersphinx import InventoryAdapter
            inventories = InventoryAdapter(app.builder.env)
        
            for alias, target in app.config.intersphinx_aliases.items():
                alias_domain, alias_name = alias
                target_domain, target_name = target
                try:
                    found = inventories.main_inventory[target_domain][target_name]
                    try:
                        inventories.main_inventory[alias_domain][alias_name] = found
                    except KeyError:
                        print("could not add to inv")
                        continue
                except KeyError:
                    print("missed :(")
                    continue
        
        
        def setup(app):
            app.add_config_value("intersphinx_aliases", {}, "env")
            app.connect("builder-inited", add_intersphinx_aliases_to_inv)
        

        要使用它,我将上面的代码粘贴到我的 conf.py 中,并将别名添加到 intersphinx_aliases 字典中。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-09-24
          • 1970-01-01
          • 2011-05-25
          • 2021-10-05
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多