我正在尝试将外部API的交叉引用添加到我的文档中,但我面临三种不同的行为。
我正在使用狮身人面像(1.3.1)和Python(2.7.3),我的狮身人面像映射配置为:
{
'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`
)为我提供了组,但:class:`h5py.Group`
无法生成链接。
最后,我找不到一种方法来编写对OpenCV API的工作交叉引用,这些似乎都不起作用:
:func:`cv2.convertScaleAbs`
:func:`cv2:cv2.convertScaleAbs`
:func:`cv2:convertScaleAbs`
:func:`convertScaleAbs`
如何正确编写对外部 API 的交叉引用,或配置 intersphinx,以像 numpy 情况一样生成链接?
除了@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
我再次尝试理解objects.inv
文件的内容,希望这次我检查了numpy和h5py,而不仅仅是OpenCV的一个。
如何读取狮身人面像库存文件
尽管我找不到任何关于读取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 的后,您可以看到键是域:
[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`
将按预期工作。
H5岁
在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,应该检查特定的清单对象以实际查看可用的内容。
检查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:
(我很高兴知道为什么)。
如何使用 OpenCV 2.4 (cv2) 狮身人面像
受到@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"狮身人面像域:https://github.com/opencv/opencv/blob/2.4/doc/ocv.py - 大概是因为它们需要同时记录C,C++和Python API。
要使用它,请将ocv.py
保存在狮身人面像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),
}
在您的 rst 文件中,您需要说:ocv:pyfunc:`cv2.imread`
(不是 :ocv:pyfunction:
)。
狮身人面像打印了一些警告(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
并删除打印该警告的行。
接受的答案在新版本 (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)
我是个顽固的傻瓜,我用2to3
和狮身人面像弃用的API图表来恢复@david-röthlisberger基于ocv.py
的答案,这样它就可以在Python 3.5上与Sphinx 2.3一起使用。
修复版本在这里:
https://gist.github.com/ssokolow/a230b27b7ea4a31f7fb40621e6461f9a
。我所做的快速版本是:
- 运行
2to3 -w ocv.py && rm ocv.py.bak
- 在运行狮身人面像和重命名函数以替换图表之间来回循环。我相信这些是我在此步骤中必须进行的唯一更改:
-
Directive
现在必须从docutils.parsers.rst
进口 - 将
l_(...)
调用替换为对_(...)
的调用,并删除l_
导入。
-
- 将
env.warn
的呼叫替换为对log.warn
log = sphinx.util.logging.getLogger(__name__)
的呼叫。
然后,您只需将其与这个狮身人面像定义配对,您就会得到一些足够新的东西,足以与大多数用例相关:
'cv2': ('https://docs.opencv.org/3.0-last-rst/', None)
为了方便起见,我做了一个小的扩展,用于别名狮身人面像交叉引用。 这很有用,因为有时当从包的__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
字典中。