Umi Uyuraのブログ

プログラミング関連の作業ログ

WSL + Homebrewの環境でMkDocsがModuleNotFoundError: No module named '_ctypes'

Markdownベースでドキュメントサイトを作ることができるPython製のツール MkDocs を使おうとしたところ、 ModuleNotFoundError が発生してコマンドが動かない問題が出てしまいました。

原因はHomebrew (Linuxbrew)で入れていたライブラリで、それを除去してPythonを入れ直すことで解消したので、経緯をメモしておきます。

環境

エラーが出た状況と考察

WSL (Ubuntu)環境で、venvで作ったPython仮想環境に pip install mkdocs でMkDocsをインストールしました。

インストール自体は問題なかったものの、 mkdocs new を実行時にエラーが発生しました。

$ mkdocs new
Traceback (most recent call last):
...
ModuleNotFoundError: No module named '_ctypes'

参考になったのは Pythonでの ctype の依存関係エラー対策の備忘録 / ModuleNotFoundError: No module named ctypes 対策 | simple blog という記事でした。

WSL上にPythonをインストールするにあたり、asdfとそのプラグインであるasdf-pythonを使っています。

asdf-pythonの内部ではpyenvが使われており、pyenvはPythonのバージョンをインストールするときにソースコードからビルドをおこないますが、その際環境に応じて事前に必要なパッケージをインストールしておく必要があります。

Suggested build environment

そういえば、WSL上にPython環境を構築するとき、Homebrewも導入していたこともあり、一度Linuxbrew用の指定パッケージを入れてしまっていました。

umi-uyura.hatenablog.com

ただ、これではうまくいかず、Ubuntu用の指定パッケージを入れることでasdf-pythonが使えるようになりました。

そのため、もしかするとこのときに入れてしまったLinuxbrew用のパッケージが影響しているのではないかと考えました。

Homebrew (Linuxbrew) の依存関係を取り除く

先のpyenvのサイトによると、Linuxbrewの場合は以下のパッケージが指定されています。

brew install bzip2 libffi libxml2 libxmlsec1 openssl readline sqlite xz zlib

よって、これらを削除すれば良いかなと思いましたが、Homebrewの他のアプリケーションなどで使われているものがあるかもしれないので、念のため調べてみます。

参考: Homebrew でパッケージの依存関係を調べる方法 - Qiita

brew uses <package> --installed で、そのパッケージがインストールされている他のパッケージから使われているかどうかを調べることができるとのこと。

$ brew uses bzip2 --installed
$ brew uses libffi --installed
autogen gnutls guile guile@2 libxmlsec1 p11-kit
$ brew uses libxml2 --installed
autogen gettext gnutls libidn2 libxmlsec1 nghttp2
$ brew uses libxmlsec1 --installed
$ brew uses openssl@1.1 --installed
asdf autoconf automake berkeley-db gnutls libevent libxmlsec1 nghttp2 perl unbound
$ brew uses readline --installed
asdf autogen gettext gnutls guile guile@2 libidn2 libxml2 libxmlsec1 nghttp2 sqlite
$ brew uses sqlite --installed
$ brew uses xz --installed
$ brew uses zlib --installed
autogen binutils fnm gcc gettext gnutls libidn2 libxml2 libxmlsec1 nghttp2 sqlite zstd

こう見ると、依存されているものがあるのは libffi libxml2 openssl@1.1 readline zlib でした。

また、 brew deps <package> とすることで、指定パッケージが依存しているパッケージを調べることができます。

今のところ、Homebrewで使っているものとしては asdfgcc、direnv、fnm といったあたりだったので、今度はそれらが依存しているパッケージを調べてみます。

$ brew deps asdf
attr
autoconf
automake
berkeley-db
ca-certificates
coreutils
expat
gdbm
gmp
libtool
libyaml
m4
ncurses
openssl@1.1
perl
readline
unixodbc
$ brew deps gcc
binutils
gmp
isl
libmpc
mpfr
zlib
zstd
$ brew deps direnv
$ brew deps fnm
zlib

こうしてみると、 openssl@1.1 readline zlib あたりは他のものでも使っているようなので、それらはいったん残すことにして、それ以外のパッケージをアンインストールしてみることにします。

$ brew uninstall bzip2 libffi libxml2 libxmlsec1 sqlite xz
Error: Refusing to uninstall /home/linuxbrew/.linuxbrew/Cellar/libffi/3.4.2 and /home/linuxbrew/.linuxbrew/Cellar/libxml2/2.9.12
because they are required by autogen, gettext, gnutls, guile, guile@2, libidn2, nghttp2 and p11-kit, which are currently installed.
You can override this and force removal with:
  brew uninstall --ignore-dependencies bzip2 libffi libxml2 libxmlsec1 sqlite xz

libxml2 に依存しているパッケージがあるため、エラーになりました。

これを無視したい場合は --ignore-dependencies を付ければ良いようなので、オプションを付けて再実行します。

$ brew uninstall --ignore-dependencies bzip2 libffi libxml2 libxmlsec1 sqlite xz

Python再インストールとMkDocsの動作確認

これでHomebrewの不要と思われる依存関係を取り除けたので、Pythonを再ビルドするためにアンインストール&再インストールをおこないます。

$ asdf uninstall python 3.10.2
$ asdf install python 3.10.2
python-build 3.10.2 /home/<user>/.asdf/installs/python/3.10.2
Downloading Python-3.10.2.tar.xz...
-> https://www.python.org/ftp/python/3.10.2/Python-3.10.2.tar.xz
Installing Python-3.10.2...
python-build: use readline from homebrew
python-build: use zlib from homebrew
Installed Python-3.10.2 to /home/<user>/.asdf/installs/python/3.10.2

よく見ると、 python-build: use readline from homebrew のようにHomebrewのパッケージを参照しているものが出力されていました。

もしかすると、当初Pythonをインストールしたときには除去した依存関係も出力されていたのかもしれません。

Pythonインストール後、venvで仮想環境を作ってからMkDocsのインストール&実行してみます。

$ python -m venv .venv
$ . .venv/bin/activate
(.venv) $ python -m pip install mkdocs
(.venv) $ mkdocs new hoge
INFO     -  Creating project directory: hoge
INFO     -  Writing config file: hoge/mkdocs.yml
INFO     -  Writing initial docs: hoge/docs/index.md
(.venv) $ cd hoge
(.venv) hoge$ mkdocs serve
$ mkdocs serve
INFO     -  Building documentation...
INFO     -  Cleaning site directory
INFO     -  Documentation built in 0.05 seconds
INFO     -  [14:21:23] Serving on http://127.0.0.1:8000/

MkDocs、使えるようになりました。

定期メンテナンス

こうしてみると、依存関係でインストールされたものの、その後使われなくなるパッケージというのもけっこうありそうなので、そういったメンテナンスするのに以下の記事が参考になりそう。

Homebrew で使われていない formula を削除する :: by and for engineers