当前位置: 首页 > 工具软件 > Sphinx > 使用案例 >

Sphinx入门

姜泰宁
2023-12-01

文章目录
Sphinx画流程图和时序图

最近在使用sphinx的时候遇到了一点问题,首先是不支持中文检索,为此进行了一些配置,参考链接
首先安装jieba库,python3的安装命令是:pip install jieba3k,然后把sphinx项目的conf.py文件中的language键值改为 zh_CN,再进行编译应该就可以了。

配置完之后发现很多目录的内容依旧没有检索到,于是决定稍微深挖一下sphinx在编译的过程中是怎么寻找内容并构建索引的(结论在此)。

首先定位到sphinx的安装目录,并进入这个目录:

import sphinx
print(sphinx.__file__)

跟搜索相关的文件在search/目录下

sphinx-autobuild命令是按字典序升序,深度优先搜索每个目录下的每一个rst文件,依次进行构建;检索到的文件会在编译过程中用绿色字体标示出来。当然,如果我们没有手动对sphinx的代码进行修改,添加一些print语句,编译过程基本都是在同一行内显示,每个文件就闪一下就过去了,基本是看不到的。

接下来一段提及的内容都属于search/__init__.py文件中的代码:
visitor.found_title_words返回每个文档的标题文字,标题包括每个文档的开头标题和每一个用=====-----+++++等修饰的文字。
IndexBuilder在初始化后,它的lang成员根据sphinx项目目录下conf.pylanguage键值的不同,可能是SearchEnglish类也可能是SearchChinese类。对IndexBuilder的调用是在builders/html/__init__.py里头;

self.indexer = IndexBuilder(self.env, lang,
                            self.config.html_search_options,
                            self.config.html_search_scorer)
self.load_indexer(docnames)

第一行的参数没有什么特别,第二个是语言,后两个是空的;docnames是所有的rst文件的路径,load_indexer()函数依次给出每个文件的指针,并调用IndexBuilderload()方法令其按sphinx.search._JavaScriptIndex 的方式读取文件,得到的变量frozen有很多个键值,这里只挑对我们有用的键值出来讲:

docnames: 一个list,包含rst文件在sphinx文档树中的路径(又名索引index),如best_practices/git
filenames: 一个list,包含rst文件的实际相对路径,如best_practices\git.rst
titles: 一个list,包含所有rst文件的大标题(每个文件只有一个大标题)
docnames,filenames和titles三者是一一对应的,顺序也是相同的
objtypes: 一个dict,看起来像是固定的,内容为 {'0': 'py:attribute', '1': 'py:class', '2': 'py:method'}
objnames: 一个dict,与objtypes相对应,内容为 {'0': ['py', 'attribute', 'Python 属性'], '1': ['py', 'class', 'Python 类'], '2': ['py', 'method', 'Python 方法']}
titleterms: 一个{str: int/list}的dict,保存的是由标题分词得到的索引词与titles所指页面的对应关系,例如{"位置": [4, 27, 32]}表示位置这个词出现在了titles[4], titles[27], titles[32]所对应的三个页面中,也即三个检索结果。需要注意的是,虽然titles只包含了大标题,但titleterms里头是有包含小标题的分词结果的,也即小标题可以正常搜索,正常对应到某个页面
terms: 与titleterms相似,唯一的不同是它保存了由正文分词得到的索引词与titles所指页面的对应关系
objects: 一个{name: list[list]}的dict,保存被autoclassautomodule等引用的模块和类,形如{'mixedai.sys_layer.log': [[26, 0, 1, '', 'logger']], ...},key是模块名,相当于from xxx import yyy里面的xxx,value是嵌套list,每个list是一条引用,26表示title[26]对应的页面,‘logger’是yyy;第二项的0与前面objtypes内容相对应,0是属性,1是类,2是方法。第三项和第四项的1和’'没有看出啥名堂来,每一条这两项都是一样的。

回到load()方法,self._filenamesself._titles分别保存了索引(这里的索引是指形如best_practices/git的字符串)与文件名、标题名称的对应关系,self._mappingself._title_mapping分别保存了正文分词、标题行分词与索引index的对应关系,到这里就准备好检索所需的材料了。

stem()函数在分词之后执行,对分词结果做预处理,如统一变为小写等,这样可以将同类项合并到一个索引中,提高搜索效率和准确度。

接下来一段提及的内容都属于search/zh.py文件中的代码:
search/zh.py是针对中文检索的文件,支持jieba库;self.latin_terms在每次分词的时候都会收录分出来的英文单词,在stem环节用来判断需不需要做stem。由于我没有看到过这个条件生效的情况,should_not_be_stemmed一直都是False,所以这点暂时不管。

结论:要想支持中文检索,安装jieba3k库就万事大吉了。之所以看起来搜到的结果不够完整, 是因为要保持搜索结果有条理,所以同一个html页面如果出现多次搜索词,只会显示为一条结果,但在点进该页面时会高亮显示每个匹配的词。

如果检索失败,查看编译结果目录下的searchindex.js文件,有\uxxxx字样就是有中文检索材料,应该是可以检索出来的,没有的话要再回去看看中间过程。

Sphinx画流程图和时序图

需要借助sphinxcontrib-plantuml插件:pip install sphinxcontrib-plantuml,同时在conf.py中做一些配置:

extensions = [
    'sphinxcontrib.plantuml',
]
plantuml = 'java -jar plantuml.1.2021.12.jar'

plantuml的jar文件下载地址在这
另外需要安装jdk,我们需要在Docker中安装jdk,这里使用Docker构建jdk1.8镜像,参考链接。然后还要安装graphviz,不然只能画时序图跟活动图。
Linux版jdk点此下载,提取码是idyn,资源来自此链接中的评论。

切换主题
这里有很多内置主题,在写普通uml语句的时候通过!theme bluegray导入主题,现在是在sphinx的一个插件里头使用,它只支持!include命令,因此只能手动把.puml文件拉到本地,使用!include命令导入主题文件。这里提供了内置主题的快速预览。

plantuml官方教程,图文并茂

plantuml刚装好的时候找不到中文,中文会显示成方块,需要安装一下,参考链接

以上n多步最终的Dockerfile如下,ADD涉及的文件都需要手动下载,下载链接在参考链接中或上文中:

FROM xxxx
RUN mkdir /usr/local/jdk && mkdir /usr/local/packages && mkdir -p /usr/share/fonts/simsun && pip install sphinxcontrib-plantuml && apt-get install -y graphviz fontconfig xfonts-utils
ADD jdk-8u281-linux-x64.tar.gz /usr/local/jdk
ADD plantuml.1.2021.12.jar /usr/local/packages
ADD plantuml_official_themes/ /usr/local/packages/plantuml_official_themes/
ADD plantuml-style-c4/ /usr/local/packages/plantuml-style-c4/
ADD simsun.ttc /usr/share/fonts/simsun

RUN mkfontscale && mkfontdir && fc-cache -fv && /bin/bash -c "source /etc/profile"

ENV JAVA_HOME /usr/local/jdk/jdk1.8.0_281
ENV JRE_HOME /usr/local/jdk/jdk1.8.0_281/jre
ENV PATH $JAVA_HOME/bin:$PATH

第一行代码的开头不可以是中文,否则中文会全部变方块,不在第一行就没事,很神奇(后面重新做了一个容器又没有这个问题了,不知道是怎么一回事)

plantuml样式表,所有能改的参数都在这里了

在容器中使用sphinx-autobuild时报错:OSError: [Errno 28] inotify watch limit reached,这个是宿主机的配置的问题,在宿主机上进行如下配置即可(参考链接1参考链接2):

# 查看当前的配置,默认值是8192
cat /proc/sys/fs/inotify/max_user_watches
# 临时更改,重启后会失效
sudo sysctl fs.inotify.max_user_watches=1048576
# 永久更改,在文件后面添加一句 fs.inotify.max_user_watches=1048576
sudo vim /etc/sysctl.conf

一些让人摸不着头脑的警告:

  • WARNING: Definition list ends without a blank line; unexpected unindent.
def func1(self, p1, p2, p3, p4):
    """ balabala.
    Args:
        p1: xxx
        p2: xxx
        p3: xxx
    """

注释换行的时候,要跟"""对齐,而不是跟第一个单词对齐,因此要把第三行的e.g跟Args对齐,就不会报warning了。
再来看第二个例子:

def func2(self, p1, p2, p3, p4, p5):
    """balabala
    This method will create the following files:
        1. p1p1
        2. p2p2

    Args:
        name: xxx

    Returns:
        str: xxx
    """

也是类似的原因,把1.与2.跟This对齐就不报warning了。

 类似资料: