rcmdnk's blog

20211103_readthedocs_200_200

homebrew-file などのドキュメントを Read the Docs というサービスを使って公開しているのですが、 そこでドキュメントのビルドが1週間ほど前から失敗するようになっていたので それを直した話。

Read the Docs

Read the Docs はSphinxというPython製のドキュメントビルダーを使って ドキュメントを作成してWebに公開してくれるサービスです。

GitHubと連携して、GitHubと連携して、GitHubのレポジトリにドキュメントのソースファイルを入れておくと、 push時に自動的にレポジトリを取得してドキュメントをビルドして公開してくれます。

もともとSphinxはPythonのドキュメンテーション用に作られたもので また、Read the Docsも サービスがDjangoで作られたりしていて、 PythonのモジュールのドキュメントとかがよくSphinxでビルドしたものがあって、 Read the Docsで公開されているものも多くあります。

SphixはreStructuredTextというマークアップを利用しますが、 Markdownのビルドにも一応対応しています。

GitHubで公開したツールとかに対して、GitHubのReadmeとは一味違った 形でドキュメントを付けるにはお手軽で良い感じに出来るかと思います。

基本的には無料で、表示される広告を消したい場合などは有料で消すこともできます。

起こった問題

んな感じのエラーを出していました:

Running Sphinx v1.8.5
loading translations [en]... done
making output directory...
building [mo]: targets for 0 po files that are out of date
building [html]: targets for 10 source files that are out of date
updating environment: 10 added, 0 changed, 0 removed
reading sources... [ 10%] brew-wrap
reading sources... [ 20%] completion

Traceback (most recent call last):
  File "/home/docs/checkouts/readthedocs.org/user_builds/homebrew-file/envs/stable/lib/python3.7/site-packages/sphinx/cmd/build.py", line 304, in build_main
    app.build(args.force_all, filenames)
  File "/home/docs/checkouts/readthedocs.org/user_builds/homebrew-file/envs/stable/lib/python3.7/site-packages/sphinx/application.py", line 341, in build
    self.builder.build_update()
  File "/home/docs/checkouts/readthedocs.org/user_builds/homebrew-file/envs/stable/lib/python3.7/site-packages/sphinx/builders/__init__.py", line 347, in build_update
    len(to_build))
  File "/home/docs/checkouts/readthedocs.org/user_builds/homebrew-file/envs/stable/lib/python3.7/site-packages/sphinx/builders/__init__.py", line 360, in build
    updated_docnames = set(self.read())
  File "/home/docs/checkouts/readthedocs.org/user_builds/homebrew-file/envs/stable/lib/python3.7/site-packages/sphinx/builders/__init__.py", line 468, in read
    self._read_serial(docnames)
  File "/home/docs/checkouts/readthedocs.org/user_builds/homebrew-file/envs/stable/lib/python3.7/site-packages/sphinx/builders/__init__.py", line 490, in _read_serial
    self.read_doc(docname)
  File "/home/docs/checkouts/readthedocs.org/user_builds/homebrew-file/envs/stable/lib/python3.7/site-packages/sphinx/builders/__init__.py", line 534, in read_doc
    doctree = read_doc(self.app, self.env, self.env.doc2path(docname))
  File "/home/docs/checkouts/readthedocs.org/user_builds/homebrew-file/envs/stable/lib/python3.7/site-packages/sphinx/io.py", line 318, in read_doc
    pub.publish()
  File "/home/docs/checkouts/readthedocs.org/user_builds/homebrew-file/envs/stable/lib/python3.7/site-packages/docutils/core.py", line 219, in publish
    self.apply_transforms()
  File "/home/docs/checkouts/readthedocs.org/user_builds/homebrew-file/envs/stable/lib/python3.7/site-packages/docutils/core.py", line 200, in apply_transforms
    self.document.transformer.apply_transforms()
  File "/home/docs/checkouts/readthedocs.org/user_builds/homebrew-file/envs/stable/lib/python3.7/site-packages/sphinx/transforms/__init__.py", line 90, in apply_transforms
    Transformer.apply_transforms(self)
  File "/home/docs/checkouts/readthedocs.org/user_builds/homebrew-file/envs/stable/lib/python3.7/site-packages/docutils/transforms/__init__.py", line 171, in apply_transforms
    transform.apply(**kwargs)
  File "/home/docs/checkouts/readthedocs.org/user_builds/homebrew-file/envs/stable/lib/python3.7/site-packages/sphinx/transforms/__init__.py", line 245, in apply
    apply_source_workaround(n)
  File "/home/docs/checkouts/readthedocs.org/user_builds/homebrew-file/envs/stable/lib/python3.7/site-packages/sphinx/util/nodes.py", line 94, in apply_source_workaround
    for classifier in reversed(node.parent.traverse(nodes.classifier)):
TypeError: 'generator' object is not reversible

Exception occurred:
  File "/home/docs/checkouts/readthedocs.org/user_builds/homebrew-file/envs/stable/lib/python3.7/site-packages/sphinx/util/nodes.py", line 94, in apply_source_workaround
    for classifier in reversed(node.parent.traverse(nodes.classifier)):
TypeError: 'generator' object is not reversible
The full traceback has been saved in /tmp/sphinx-err-fwowl5pk.log, if you want to report the issue to the developers.
Please also report this if it was a user error, so that a better error message can be provided next time.
A bug report can be filed in the tracker at <https://github.com/sphinx-doc/sphinx/issues>. Thanks!

ドキュメントのソースがおかしいのかな、と思って手元でビルドしてみると特に問題は出ず。

で、ちょっと調べて見ると、どうやら docutils というモジュールの0.18というバージョンが出て、 Sphinxがその変更に対応できていない、とのこと。

“TypeError: ‘generator’ object is not reversible” during RTD builds · Issue #973 · ivadomed/ivadomed

2021年10月26日にdocutilsの0.18がリリースされてるのでそのあたりから問題が出ていたようです。

一方でSphinx最新の4.2ではdocutilsへの依存性を<0.18以下というrequirementsにすることで 一旦回避しています。

Update Sphinx to work with docutils-0.18.x · Issue #9777 · sphinx-doc/sphinx

なので手元でSphinxを(pip install sphinxで)入れて試したときは問題なかったようです。

ただ、Read the Docsではsphinxのバージョンを<2で要求していて、 これだとdocutils>=0.11で要求しているので最新の物が入り問題が起きていた模様。

したがってとりあえずはビルド環境でdocutils-0.18より前のバージョンを使う かsphinxの新しいバージョンを入れるようにすれば問題が解決できそうです。

Read the Docsの設定もsphinx-4.2.0を入れる様に変更された(される?)みたいですが、 現状ではまだ実際に実行するとsphinx<2のバージョンで実行されています。

readthedocs.org/pip.txt at master · readthedocs/readthedocs.org

Read the Docsの環境設定

Read the Docsに関してはレポジトリを連携するだけで特に細かい設定をしてませんでしたが、 GitHubのレポジトリに設定ファイルを置くことでビルド環境を設定することができます。

Reproducible Builds — Read the Docs 6.1.1 documentation

まずは以下の様な.readthedocs.yamlというファイルをレポジトリのトップディレクトリに用意します。

.readthedocs.yaml
1
2
3
4
5
6
7
8
9
10
11
version: 2

# Build from the docs/ directory with Sphinx
sphinx:
  configuration: docs/conf.py

# Explicitly set the version of Python and its requirements
python:
  version: 3.7
  install:
    - requirements: docs/requirements.txt

Pythonのバージョンは現状では3.9はまだ使えないようです。 3.7にしてあるのはドキュメントとかでそうなっていたから、というだけで 3.8は使おうと思えば使えます。

docs/conf.pyはsphinxでsphinx-quickstartとかで初期化していれば 最初にできているかと思います。

この指定はデフォルトでこの値なので書かなくても同じです。

一方でPythonの設定は、Pythonのバージョンはデフォルトで3.7ですが、 インストールに関しては指定しないとRead the Docsのデフォルトのパッケージを取得するだけで、 docs/requirements.txtがあったとしてもその中身は読まれません。

上のドキュメントにもありますが、requirements.txtを使って モジュールのバージョン指定などをきちんといておきなさい、と。

というわけで、以下を用意します。

docs/requirements.txt
1
sphinx>=4

これでsphinx-4以上のものが入ります。

もしくは、

docs/requirements.txt
1
docutils<0.18

でもOK。せっかくだからSphinxの新しいものを使おうかと、上の方を使います。

これらをaddしてcommitしてpushすればOK。

requirements.txtを使うようにすると、ビルドのところで、 下の絵の様に7番目のタスクとしてrequirements.txtを使ったインストールが追加されます。

20211103_readthedocs.jpg

その上の部分でRead the Docsデフォルトのパッケージが追加されていますが、そこを見ると

Collecting sphinx<2
  Downloading Sphinx-1.8.5-py2.py3-none-any.whl (3.1 MB)
...
Collecting docutils>=0.11
  Downloading docutils-0.18-py2.py3-none-any.whl (569 kB)

みたいな感じでsphinxのバージョン2未満と、docutilsの最新の0.18が入れられてる事がわかります。

これらを上書きする形で次のタスクで必要なものが入っていればビルドが成功します。

Read the Docsの対応などを見る感じ、何もしなくてもそのうち ビルドがうまく行くようにもなるとは思いますが、 もし現在ビルドの失敗が気になるようならこれで直すことができます。

Sponsored Links
Sponsored Links

« Oura Ring Generation 3を購入(a free lifetime Oura membership) Windowsターミナルの起動時の初期ディレクトリ設定 »