背景
Visual Studio 2019でboostを使ってC++上でPython3.7で作ったプログラムを動かそうとしたところ、コンパイル、ビルドはできたのですがPythonプログラムの実行の途中でエラーが出てしまいました。
ログを見てみると、
...
import contextvars
File "C:\Users\〇〇\AppData\Local\Programs\Python\Python37\Lib\contextvars.py", line 1, in <module>
from _contextvars import Context, ContextVar, Token, copy_context
ModuleNotFoundError: No module named '_contextvars'
といったエラーが出ているようです。
このエラーに対する情報はネット上で散見されますが、対処法が示されているものは少なく、どの対処法を試しても解決できませんでした。しかし、ちょっとした力わざで解決することができたので情報共有と備忘録を兼ねて投稿します。
エラーの詳細
上記のログを見ればわかるように、_contextvarsをインポートしようとしたときに、_contextvarsが見つからないか何かでインポートできないようです。ここでログにあったパス(C:\Users\〇〇\AppData\Local\Programs\Python\Python37\Lib)に飛んでみましょう。
ここにはVS2019でインストールしたPythonが入っている(たぶん)のですが、確かに_contextvars.pyというファイルは見つかりません。代わりにcontextvars.py(_がない)があったのでその中身を見てみます。
from _contextvars import Context, ContextVar, Token, copy_context
__all__ = ('Context', 'ContextVar', 'Token', 'copy_context')
ログでもわかるように、_contextvarsのインポートの前にcontextvarsのインポートを行っているのですが、contextvars.pyは「_contextvars.pyからContext, ContextVar, Token, copy_contextという関数をインポートするよ」と言っているだけのようです。つまり、「contextvars.pyを動かすには_contextvars.pyが必要。だけど_contextvars.pyが存在しないからエラーが出た。」ということのようです。
_contextvars.pyはいずこへ
これによると、Python3.7をインストールしたときにすべてのパッケージがインストールされず、aptでインストールしなおしたら正常に動作したよ!とのことです。
早速やってみました。ダメでした。
WSL上でubuntuにPython3.7をインストールしなおしましたが(手順:Masashi Murakami様)、ubuntu内のPythonの中身(user/lib/Python3.7)に_contextvars.pyは存在しませんでした。(_contextvars.pyがあったらwindowsのほうにコピペるれば行けると思ったのですが、、、)
次に
によると、virtualenvを再インストールすれば直った!とのことです。
早速やってみました。ダメでした。
VS2019上で
pip install virtualenv
したのですが結局_contextvars.pyは作られず、プロジェクトを実行しなおしてもやはりModuleNotFoundErrorがでます。
_contextvars.py発見!
もうあきらめてふて寝しようとしたとき、その前にほんとに_contextvars.pyはどこにも存在しないのかと駄目もとでエクスプローラで検索したところ、dummy_contextvars.pyというものをC:\Users\〇〇\AppData\Local\Programs\Python\Python37\Lib\site-packages\prompt_toolkit\eventloopで発見しました。
中身を見てみると、
"""
Dummy contextvars implementation, to make prompt_toolkit work on Python 3.6.
As long as there is only one application running at a time, we don't need the
real contextvars. So, stuff like the telnet-server and so on requires 3.7.
"""
from typing import Any, Callable, Generic, Optional, TypeVar
def copy_context() -> "Context":
return Context()
_T = TypeVar("_T")
class Context:
def run(self, callable: Callable[..., _T], *args: Any, **kwargs: Any) -> _T:
return callable(*args, **kwargs)
def copy(self) -> "Context":
return self
class Token(Generic[_T]):
pass
class ContextVar(Generic[_T]):
def __init__(self, name: str, *, default: Optional[_T] = None) -> None:
self._name = name
self._value = default
@property
def name(self) -> str:
return self._name
def get(self, default: Optional[_T] = None) -> _T:
result = self._value or default
if result is None:
raise LookupError
return result
def set(self, value: _T) -> Token[_T]:
self._value = value
return Token()
def reset(self, token: Token[_T]) -> None:
pass
Python3.6でcontextvarsを使えるようにする(contextvarsは3.7で実装されたらしい)ためのもののようですが、おやおや~、 Context,、ContextVar, Token, copy_contextが定義されていますね。
これは使えるのではということで、C:\Users\〇〇\AppData\Local\Programs\Python\Python37\Libにコピペ、名前を_contextvars.pyに変更しました。
そしてプロジェクトを実行、、、
ModuleNotFoundErrorは出ず、無事実行できました!
まとめ
ModuleNotFoundError: No module named '_contextvars'が出たときは_contextvars.pyがないか探し、なければdummy_contextvars.pyを探してきてコピペして名前変更すればOK!
このエラーにどれだけの方々が直面するかわかりませんが、直面した際ネット上にはあまり情報がないのでこの記事が参考になれば幸いです。
最後にcontextvarsについて、公式ドキュメントのリンクを載せておきます。