WSL1+外部ストレージ+Pipenvの組み合わせでハマった
Introduction
Pythonの環境構築を行うツールとして,最近はAnacondaやPipenvなど収まるところに収まってきている感があります。比較的シンプルにPython仮想環境の構築を行うことができ,依存パッケージの再現やデプロイもしやすいです。
ただ,公式ドキュメント含め多くのサイトではMacやUbuntu上でPipenvのインストールを行っていることが多く,WSL上でインストールを行った際のトラブルシューティングを紹介しているサイトがあまりありません。Anacondaはロックインがこわいので,個人的にもPipenvをメインにしたのですが,当初は原因不明のエラーに悩まされました。
最終的には何とか解決したので,ことの経過を書いてみたいと思います。
環境
- Windows 10 Home バージョン 1909 (OSビルド 18363.836)
- Windows Subsystem for Linux
- Ubuntu 18.04.4 LTS
- Python 3.7.5
- Pipenv, version 2018.11.26
PIPENV_VENV_IN_PROJECT
をtrueに設定すると(何故か)仮想環境の作成に失敗する
デフォルトでは仮想環境の実体である.venv
ディレクトリは,~/.local/share/virtualenvs
に作成されます1。しかし,このPIPENV_VENV_IN_PROJECT
環境変数をセットすると,プロジェクトを作成するディレクトリに.venv
を作成することができます2。そのため,仮想環境をそのまま移動させたい時や,既に存在する仮想環境に新たにpipenv install
したい時,仮想環境を消し去りたい時などに便利です。
しかし,ある時WSL上で外部ストレージに仮想環境を作成しようとすると,以下のようなエラーメッセージが表示されました。
✘ Failed creating virtual environment [pipenv.exceptions.VirtualenvCreationException]: File "/home/ubuntu-user/.local/lib/python2.7/site-packages/pipenv/cli/command.py", line 254, in install [pipenv.exceptions.VirtualenvCreationException]: editable_packages=state.installstate.editables, [pipenv.exceptions.VirtualenvCreationException]: File "/home/ubuntu-user/.local/lib/python2.7/site-packages/pipenv/core.py", line 1741, in do_install [pipenv.exceptions.VirtualenvCreationException]: pypi_mirror=pypi_mirror, [pipenv.exceptions.VirtualenvCreationException]: File "/home/ubuntu-user/.local/lib/python2.7/site-packages/pipenv/core.py", line 574, in ensure_project [pipenv.exceptions.VirtualenvCreationException]: pypi_mirror=pypi_mirror, [pipenv.exceptions.VirtualenvCreationException]: File "/home/ubuntu-user/.local/lib/python2.7/site-packages/pipenv/core.py", line 506, in ensure_virtualenv [pipenv.exceptions.VirtualenvCreationException]: python=python, site_packages=site_packages, pypi_mirror=pypi_mirror [pipenv.exceptions.VirtualenvCreationException]: File "/home/ubuntu-user/.local/lib/python2.7/site-packages/pipenv/core.py", line 935, in do_create_virtualenv [pipenv.exceptions.VirtualenvCreationException]: extra=[crayons.blue("{0}".format(c.err)),] [pipenv.exceptions.VirtualenvCreationException]: Traceback (most recent call last): File "/home/ubuntu-user/.local/lib/python2.7/site-packages/virtualenv.py", line 417, in copyfile os.symlink(os.path.realpath(src), dest) PermissionError: [Errno 1] Operation not permitted: '/usr/lib/python3.7/config-3.7m-x86_64-linux-gnu' -> '/mnt/d/python_projects/test/.venv/lib/python3.7/config-3.7m-x86_64-linux-gnu' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/home/ubuntu-user/.local/lib/python2.7/site-packages/virtualenv.py", line 2580, in <module> main() File "/home/ubuntu-user/.local/lib/python2.7/site-packages/virtualenv.py", line 831, in main symlink=options.symlink, File "/home/ubuntu-user/.local/lib/python2.7/site-packages/virtualenv.py", line 1106, in create_environment install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages=site_packages, clear=clear, symlink=symlink) File "/home/ubuntu-user/.local/lib/python2.7/site-packages/virtualenv.py", line 1390, in install_python copy_required_files(stdlib_dir, lib_dir, symlink) File "/home/ubuntu-user/.local/lib/python2.7/site-packages/virtualenv.py", line 1300, in copy_required_files copyfile(join(src_dir, fn), join(lib_dir, fn), symlink) File "/home/ubuntu-user/.local/lib/python2.7/site-packages/virtualenv.py", line 420, in copyfile copy_file_or_folder(src, dest, symlink) File "/home/ubuntu-user/.local/lib/python2.7/site-packages/virtualenv.py", line 398, in copy_file_or_folder shutil.copytree(src, dest, symlink) File "/usr/lib/python3.7/shutil.py", line 368, in copytree raise Error(errors) shutil.Error: [('/usr/lib/python3.7/config-3.7m-x86_64-linux-gnu/libpython3.7.so', '/mnt/d/python_projects/test/.venv/lib/python3.7/config-3.7m-x86_64-linux-gnu/libpython3.7.so', "[Errno 1] Operation not permitted: '../../x86_64-linux-gnu/libpython3.7m.so.1' -> '/mnt/d/python_projects/test/.venv/lib/python3.7/config-3.7m-x86_64-linux-gnu/libpython3.7.so'"), ('/usr/lib/python3.7/config-3.7m-x86_64-linux-gnu/libpython3.7m.so', '/mnt/d/python_projects/test/.venv/lib/python3.7/config-3.7m-x86_64-linux-gnu/libpython3.7m.so', "[Errno 1] Operation not permitted: '../../x86_64-linux-gnu/libpython3.7m.so.1' -> '/mnt/d/python_projects/test/.venv/lib/python3.7/config-3.7m-x86_64-linux-gnu/libpython3.7m.so'")] Error in sys.excepthook: Traceback (most recent call last): File "/usr/lib/python3/dist-packages/apport_python_hook.py", line 63, in apport_excepthook from apport.fileutils import likely_packaged, get_recent_crashes File "/usr/lib/python3/dist-packages/apport/__init__.py", line 5, in <module> from apport.report import Report File "/usr/lib/python3/dist-packages/apport/report.py", line 30, in <module> import apport.fileutils File "/usr/lib/python3/dist-packages/apport/fileutils.py", line 23, in <module> from apport.packaging_impl import impl as packaging File "/usr/lib/python3/dist-packages/apport/packaging_impl.py", line 24, in <module> import apt File "/usr/lib/python3/dist-packages/apt/__init__.py", line 23, in <module> import apt_pkg ModuleNotFoundError: No module named 'apt_pkg' Original exception was: Traceback (most recent call last): File "/home/ubuntu-user/.local/lib/python2.7/site-packages/virtualenv.py", line 417, in copyfile os.symlink(os.path.realpath(src), dest) PermissionError: [Errno 1] Operation not permitted: '/usr/lib/python3.7/config-3.7m-x86_64-linux-gnu' -> '/mnt/d/python_projects/test/.venv/lib/python3.7/config-3.7m-x86_64-linux-gnu' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/home/ubuntu-user/.local/lib/python2.7/site-packages/virtualenv.py", line 2580, in <module> main() File "/home/ubuntu-user/.local/lib/python2.7/site-packages/virtualenv.py", line 831, in main symlink=options.symlink, File "/home/ubuntu-user/.local/lib/python2.7/site-packages/virtualenv.py", line 1106, in create_environment install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages=site_packages, clear=clear, symlink=symlink) File "/home/ubuntu-user/.local/lib/python2.7/site-packages/virtualenv.py", line 1390, in install_python copy_required_files(stdlib_dir, lib_dir, symlink) File "/home/ubuntu-user/.local/lib/python2.7/site-packages/virtualenv.py", line 1300, in copy_required_files copyfile(join(src_dir, fn), join(lib_dir, fn), symlink) File "/home/ubuntu-user/.local/lib/python2.7/site-packages/virtualenv.py", line 420, in copyfile copy_file_or_folder(src, dest, symlink) File "/home/ubuntu-user/.local/lib/python2.7/site-packages/virtualenv.py", line 398, in copy_file_or_folder shutil.copytree(src, dest, symlink) File "/usr/lib/python3.7/shutil.py", line 368, in copytree raise Error(errors) shutil.Error: [('/usr/lib/python3.7/config-3.7m-x86_64-linux-gnu/libpython3.7.so', '/mnt/d/python_projects/test/.venv/lib/python3.7/config-3.7m-x86_64-linux-gnu/libpython3.7.so', "[Errno 1] Operation not permitted: '../../x86_64-linux-gnu/libpython3.7m.so.1' -> '/mnt/d/python_projects/test/.venv/lib/python3.7/config-3.7m-x86_64-linux-gnu/libpython3.7.so'"), ('/usr/lib/python3.7/config-3.7m-x86_64-linux-gnu/libpython3.7m.so', '/mnt/d/python_projects/test/.venv/lib/python3.7/config-3.7m-x86_64-linux-gnu/libpython3.7m.so', "[Errno 1] Operation not permitted: '../../x86_64-linux-gnu/libpython3.7m.so.1' -> '/mnt/d/python_projects/test/.venv/lib/python3.7/config-3.7m-x86_64-linux-gnu/libpython3.7m.so'")] Failed to create virtual environment.
クソ長いエラーメッセージ(と例外)を吐いて,仮想環境の作成に失敗します。どうも,以下のエラーメッセージが怪しそうです。
PermissionError: [Errno 1] Operation not permitted: '/usr/lib/python3.7/config-3.7m-x86_64-linux-gnu' -> '/mnt/d/python_projects/test/.venv/lib/python3.7/config-3.7m-x86_64-linux-gnu'
ファイルをコピーする際に,許可されていない操作(Operation not permitted)というエラーが発生します。今回は外部ストレージをDドライブとしてマウントしています。そこで,mount
コマンドでDドライブの詳細を見てみます。
C:\ on /mnt/c type drvfs (rw,noatime,uid=1000,gid=1000,umask=22,metadata,case=off) D:\ on /mnt/d type drvfs (rw,noatime,uid=1000,gid=1000,umask=22,case=off)
なんとDドライブにmetadata
がありません!Cドライブでは正常に仮想環境が作成できるので,このオプションが無いことが原因のようです。「なら付ければいいじゃん」と思ってmount -t drvfs D: /mnt/d -o metadata
しても,何とmetadata
オプションが反映されません…
WSLではVolFsとDrvFsという2種類のファイルシステムが使用されています3。Cドライブを含め,Windowsのすべてのボリュームをマウントする際はDrvFsが使用されます。
ここで,DrvFsの仕様4を読むと
Previously, WSL would automatically mount all fixed NTFS drives when you launch Bash, but there was no support for mounting additional storage like removable drives or network locations. Now, not only can you manually mount any drives on your system, we've also added support for other file systems such as FAT, as well as mounting network locations.
とあります。NTFSとReFS,FATが対応しているようです。
ここでようやく原因が分かりました。以前Macを使っていたので,外部ストレージをexFATでフォーマットしていたのです…だからmetadata
オプション反映されなかったのか~😭
ということで,大人しくデフォルトのままでPipenvを使うことにしました…