PyCharmのTerminalで仮想環境が自動起動せずに躓いた話

PyCharmのTerminalから`pip`したのに何故かグローバルの`site-package`に追加されてしまう......
PyCharmのTerminalから`PyInstaller`してもパッケージを読み込んでくれない......
何かおかしいと感じつつも原因を特定できずにいたのですが、
<font color="red">**そもそも仮想環境が起動できていませんでした。**</font>
今回は仮想環境が起動できなかった原因とその対策について考えてみます。


# 追記(2023/11/17)
今更過ぎる追記ですが、PyCharmのバージョンを2023にアップデートしたところこの問題は発生しなくなりました。
結局原因はわかりませんでしたがとりあえず動くのでヨシ！


# 更新履歴
2022/03/11 : 初版


# 環境
* Windows10
* Python3.10
* PyCharm Community Edition 2021.2.2


# 1. PyCharmでの仮想環境

通常Pythonで仮想環境を扱う場合`venv`など色々なコマンドを使用して構築する訳ですが、PyCharmではそれらを自動で設定してくれます。
プロジェクトを作成するときに作成される`venv`フォルダがそれです。

```:プロジェクトフォルダ構成例
myproject
├ myproject（ソースコード）
│   ├ __init__.py
│   └ main.py
└ venv（仮想環境）
    ├ Lib
    │   └ site-packages
    └ Scripts
        ├ activate.bat
        ├ activate.ps1
        ├ ......
        └ python.exe
```

例えば`main.py`で次のように書いてみましょう。

```Python:main.py
import sys
print(sys.executable)
```

これは、実行中の`python.exe`のパスを表示するスクリプトです。
実際に実行してみると、次のようになると思います。

```powershell:実行結果
C:\work\myproject\venv\Scripts\python.exe
```

Pythonインストール時に生成されたグローバルの`python.exe`ではなく、先程仮想環境上に生成した`python.exe`を示していますね。
しっかり仮想環境が機能していることがわかると思います。

さて、このプロジェクトフォルダ内で色々作業する訳ですが、たまにコマンドを使うときがありますよね。
例えばパッケージをインストールしたいときはこんな風に。

```powershell: pip
python -m pip install numpy
```

PyCharmというのは優秀で、画面下にある`Terminal`をクリックした際、自動で仮想環境を起動してくれます。
つまりそのTerminal画面で`python`コマンドを使用したとき、実行されるのは仮想環境中の`python.exe`です。
そのため、このプロジェクトだけに対してパッケージをインストールし、他のプロジェクトに影響を与えない、といったことが可能になる訳です。

それを確かめるため、次のようなコマンドを打ってみましょう。
`-c`オプションで続く文字列を実行します。
`;`は改行を表しています。

```powershell:Terminal画面
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

PS C:\work\myproject>python -c "import sys; print(sys.executable)"
```

```powershell:実行結果
C:\Users\username\AppData\Local\Programs\Python\Python310\python.exe
```

......あれ？


# 2. 起動できてないやん！

冒頭にも書きましたが、Terminal上で仮想環境が起動できていないことに気付くまで長らく時間がかかりました。
だって、<font color="red">**起動に成功している画面を一度も見たことがなかったから。**</font>
そもそもPyCharm以外で仮想環境に触れたことがなかったので、起動失敗に気付けませんでした。
起動成功時はこんな画面になります。

```powershell:Terminal画面
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

(venv) PS C:\work\myproject>
```

一目で違いがわかりますね。
先頭に`(venv)`が付いています。
これは仮想環境のフォルダ名になります。

【補足】
Terminal上で`python`と打っても`python`としか表示されない、またはMicrosoft Storeが開いてしまうといった場合は、グローバルの`python.exe`にパスが通っていない可能性が高いです。
設定しているはず！という方は、優先順位まで気にしてみてください。
`Python\Python310`や`Python\Python310\Scripts`をリストの上位に持ってくると解決する場合があります。


# 3. 原因

仮想環境が起動できていないことに気付いてから、その原因と対策を調べまわりました。
そして、**手動では**仮想環境を起動できるようになりました。
が、なぜか<font color="red">**PyCharmのTerminalだと自動起動してくれない。**</font>
これについては正直、「これだ！」と確信できるような原因が見つかりませんでした。
現状、「PyCharmのバグの可能性が一番高い」という結論に落ち着いています。
ちなみにこの問題について以下のスレッドで議論が交わされてますが、最新投稿が2022/03/04と最近なので、今後新しい情報が出るかもしれません。
【参考】[Python virtual envirnment is not automatically activated with powershell - youtrack](https://youtrack.jetbrains.com/issue/PY-52766)



ただし、他の環境では違う原因の可能性もあるので、私が試してみたことを列挙してみます。

## 3.1 PyCharmの設定

`File/Settings/Tools/Terminal`で、`Shell integration`と`Activate virtualenv`にチェックが入っていることを確認します。

![settings_terminal.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2573710/859c40f2-52c8-b4d8-2926-7bcffcae653a.png)

これで解決したら苦労はしない。

## 3.2 PowerShellの権限

PyCharmが仮想環境を起動する際、特定のファイルを実行しています。
それが`venv/Scripts`にある`activate`と名前がついているファイルです。
拡張子が色々ありますが、デフォルトではPowerShellスクリプト`activate.ps1`を実行しています。
（と、信じられています。）
しかし、Windowsのデフォルト設定ではPowerShellスクリプトの実行が「禁止」になっているようです。
PowerShellを起動して次のコマンドを打つことで、現在のPowerShell実行ポリシーを確認することができます。

```powershell:PowerShell
Get-ExecutionPolicy -List
```

```:実行結果
        Scope ExecutionPolicy
        ----- ---------------
MachinePolicy       Undefined
   UserPolicy       Undefined
      Process       Undefined
  CurrentUser       Undefined
 LocalMachine    RemoteSigned
```

この実行ポリシーを色々変えてみたのですが、Terminalで仮想環境が自動起動されることはありませんでした。
【参考】[PowerShellの実行ポリシー変更](https://qiita.com/earthdiver1/items/b3f529c81f5892972a72#fnref3)

## 3.3 パスに日本語などが入っている

プロジェクトのパスに日本語（全角文字）が入っていると自動起動が失敗する場合があります。

* パスに"デスクトップ"を含む
* パスに自分の名前（漢字）を含む
* パスに全角空白を含む

こういった場合は注意が必要です。
`C:\work`など半角文字のみの場所にプロジェクトを作成してみて、自動起動できるかを試してみてください。

## 3.4 再起動

色々な設定を変更後、反映されていない可能性があります。
一度Terminal画面、PyCharm、PC本体などを再起動してみてください。


# 4. 対策

## 4.1 PowerShellではなくCMDを使用する

恐らくPyCharmのデフォルト設定では、Terminal画面でPowerShellを使用するようになっていると思います。
下の画像の`Shell path`に`powershell.exe`が指定されています。

![settings_terminal.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2573710/859c40f2-52c8-b4d8-2926-7bcffcae653a.png)

この`Shell path`を`cmd.exe`に書き換えた後、Terminal画面を再起動すると......

```:Terminal画面
Microsoft Windows [Version 10.0.19043.1526]
(c) Microsoft Corporation. All rights reserved.

(venv) C:\work\myproject>
```

仮想環境が起動できました。
PowerShellの表記が消え、コマンドプロンプトの形式になっていることがわかります。
色が付いていない、再起動すると前回のコマンド履歴が消えるといった問題はありますが、一番簡単な対策なのではと思います。

## 4.2 activate.ps1を直接指定

やっぱりPowerShellが使いたい！という方へ。
下の画像の`Shell path`に次のように入力します。

```:Shell path
powershell -NoExit -File ".\venv\Scripts\activate.ps1"
```

![settings_terminal.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2573710/859c40f2-52c8-b4d8-2926-7bcffcae653a.png)

Terminal画面を再起動すると......

```:Terminal画面
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

(venv) PS C:\work\programming\PyCharm\myproject>
```

仮想環境が起動できました。
しっかりPowerShellを使用できていることもわかりますね。

【参考】[PowerShell prompt doesn't show virtualenv - youtrack](https://youtrack.jetbrains.com/issue/PY-22469)

## 4.3 PowerShell Profileを書き換える

私はPowerShellがさっぱりなのであくまで参考程度に。
PowerShellというのは「スクリプト実行前に必ず実行する処理」を別のスクリプトに用意しておけるらしいです。
【参考】[owerShellでプロファイルを作成する方法](https://www.zacoding.com/post/powershell-profile/)
【参考】[プロファイルについて - PowerShell | Microsoft](https://docs.microsoft.com/ja-JP/powershell/module/microsoft.powershell.core/about/about_profiles?view=powershell-7.2)

そのスクリプトに色々書いておくことで対応するという方法です。
【参考】[PyCharmでteminalを(venv)pwshにする](https://qiita.com/bounoki/items/346d164a2016b55b0a7d)
【参考】[PowerShell prompt doesn't show virtualenv](https://youtrack.jetbrains.com/issue/PY-22469#focus=Comments-27-4341640.0-0)


# 5. まとめ

という訳で、PyCharmのTerminalで仮想環境を自動起動できない原因と対処についてまとめました。
デフォルト設定だと誰もが引っかかりそうな罠だと思うのですが、あんまり情報が集まらず......
皆さんはうまく回避できているのでしょうか？