知に至る病

お勉強したことを忘れないように書き留めています。

WSL の Python で venv による仮想環境の作成がエラーになる

仮想環境の作成に失敗

WSL の Python で仮想環境を作ろうとしたら以下のエラーが出ました。

$ python3 -m venv .venv
The virtual environment was not created successfully because ensurepip is not
available.  On Debian/Ubuntu systems, you need to install the python3-venv
package using the following command.

    apt-get install python3-venv

You may need to use sudo with that command.  After installing the python3-venv
package, recreate your virtual environment.

Failing command: ['/path/to/project/.venv/bin/python3', '-Im', 'ensurepip', '--upgrade', '--default-pip']

エラーメッセージによると,仮想環境を作るためには python3-venv をインストールする必要があるとのことです。 メッセージの指示に従い,下記のコマンドを実行してインストールしたところ,無事に仮想環境を作れるようになりました。

$ sudo apt install python3-venv

ensurepip が無効化されている

エラーメッセージにある通り,このエラーは Ubuntuensurepip が無効化されているために起こっているようです。 グローバル環境に pip が入っていると意図せずシステムを壊してしまう可能性があるため,DebianUbuntu では ensurepip が無効化されているとのことです。

$ python3 -m ensurepip
ensurepip is disabled in Debian/Ubuntu for the system python.

Python modules for the system python are usually handled by dpkg and apt-get.

    apt-get install python-<module name>

Install the python-pip package to use pip itself.  Using pip together
with the system python might have unexpected results for any system installed
module, so use it on your own risk, or make sure to only use it in virtual
environments.

python3-venv をインストールしたことで仮想環境内では pip が使えるようになったのですが,グローバル環境では pip は使えないままです。

(.venv) $ pip3 --version
pip 8.1.1 from /path/to/project/.venv/lib/python3.5/site-packages (python 3.5)

$ pip3 --version
The program 'pip3' is currently not installed. You can install it by typing:
sudo apt install python3-pip

グローバル環境で pip を使いたい場合は,python3-pip をインストールすればよいようです。 以下のコマンドを実行すると pip3 が使えるようになりました。

$ sudo apt install python3-pip

Python3 on Windows10 で仮想環境を使う: venv モジュール編

Miniconda を利用せずに Python3 を Windows10 にインストールし,Python3 標準の仮想環境機能を利用するやり方のメモ。 Miniconda を利用する場合は前のエントリーを参照。

セットアップ

Chocolatey で Python3 をインストール。

choco install python3

仮想環境の操作

仮想環境は venv モジュールを利用する。 venv では Python のバージョン管理はできないことに注意。

仮想環境の作成

python -m venv hoge

Python3 環境一式のコピーが入ったディレクトリが hoge という名前でカレントディレクトリに作成される。

仮想環境の出入り

./hoge/Scripts/Activate.ps1
deactivate

仮想環境の削除

ディレクトリを削除するだけ。

rm -r hoge

パッケージの管理

パッケージ管理は pip を利用する。

パッケージのインストール

pip install --upgrade pip
pip install flake8

パッケージの一覧

pip freeze

参考資料

Python3 on Windows10 で仮想環境を使う: Miniconda 編

Miniconda を利用して Python3 を Windows10 にインストールし,Miniconda が提供する仮想環境機能を使用する方法のメモ。 Miniconda を利用しない場合は次のエントリーを参照。

セットアップ

Chocolatey で Miniconda をインストール。

choco install miniconda3

環境変数 PATH に以下のディレクトリを追加。

C:\ProgramData\Miniconda3
C:\ProgramData\Miniconda3\Library\bin
C:\ProgramData\Miniconda3\Scripts

仮想環境の操作

仮想環境の作成

conda create -n py36 python=3.6

仮想環境の削除

conda remove -n py36 --all

仮想環境の確認

conda info -e

または

conda env list

仮想環境の出入り

conda コマンドではないことに注意。

activate py36
deactivate

パッケージの管理

パッケージのインストール

conda install numpy scipy

パッケージの一覧

conda list

PowerShell で使用する場合

PowerShellactivate するには PSCondaEnvs が必要らしい。

以下のコマンドでインストールできる。

conda install -n root -c pscondaenvs pscondaenvs

参考資料

Ctrl + Shift で IME が切り替わるのを止める

IME が勝手に切り替わる

ATOK を使っていたはずなのに,いつの間にか MS-IME に切り替わっていることがありました。 はじめは Win + Space を間違って押してしまったのかなと思ったのですが,しばらく Win キーを触っていないはずのときにも発生したので,どうも違いそうです。

よくよく調べてみると,Windows では Ctrl + Shift が「キーボードレイアウトの切り替え」のショートカットキー に割り当てられており,何かの拍子にこれを押してしまっているのが原因のようでした。 エディタなどで Ctrl + Shift + 何か のショートカットを実行しようとして,気が変わって最後のキーを押さずにやめたときに意図せず IME が切り替わっていたと思われます。

ショートカットキーの無効化

このショートカットの設定を解除するには以下の手順に従います。

  1. コントロールパネルから[時計、言語、および地域] > [言語の追加]をクリック f:id:amano41:20171213164504p:plain
  2. 左側のメニューから[詳細設定]をクリック f:id:amano41:20171213164515p:plain
  3. [入力方式の切り替え] > [言語バーのホットキーの変更]をクリック f:id:amano41:20171213164522p:plain
  4. [入力言語を切り替える]を選択して[キーシーケンスの変更]をクリック f:id:amano41:20171213164556p:plain
  5. [キーボードレイアウトの切り替え]を[割り当てなし]にして[OK]をクリック(ついでに[入力言語の切り替え]の方も[割り当てなし]にしておくとよい) f:id:amano41:20171213164606p:plain

設定を変更して以来,勝手に MS-IME に変わっているということはなくなりました。 なんでこんなよく利用するキーの組み合わせに IME の切り替えなんてものを設定しているのでしょうね……。

参考資料

apm でスターとローカルの差分をとって同期するスクリプトを書いた

apm のスター連携機能

Atom のパッケージマネージャー apm には atom.io のスターと連携する機能があります。 スターをつけたパッケージを一括インストールしたり,インストール済みのパッケージにスターをつけることができます。 これは既存の環境を新しいマシンに移行する場合にとても便利です。

しかし,パッケージをあれこれ試して,それを職場と自宅など複数のマシンで同期したいような場合には不満があります。

たとえば,apm stars --install を実行すると,スターがついているパッケージであれば,たとえインストール済みであってもすべてインストールしようとします。 利用しているパッケージの数が多いと結構な時間がかかります。 また,apm unstar <package_name> でスターを外せるのですが,スターはついているけれどもローカルにはないパッケージのスターを一括で外すような機能はありません。

差分同期スクリプト apm-sync

そこで,atom.io のスターの状態とローカルのインストール状況をもとに差分をとって同期する簡単なスクリプトを書いてみました。

同期

リモートのスターの状態にあわせたり,ローカルのインストール状況にあわせたりすることができます。

リモートを基準に同期

スターの状態をもとに差分インストール・差分アンインストールを行います。 スターがついていてローカルにないパッケージをインストールし,スターがついていないがローカルにあるパッケージをアンインストールします。

apm-sync pull

ローカルを基準に同期

インストール状況をもとにスター・アンスターを行います。 インストールされていてスターがついていないパッケージにスターをつけ,インストールされていないがスターがついているパッケージのスターを外します。

apm-sync push

差分情報をつかった処理

ローカルかリモートの状態に同期するだけでなく,差分情報をつかってインストール・アンインストール・スター・アンスターを個別に行うこともできます。

差分インストール

スターがついているけれどインストールされていないパッケージをインストールします。

apm-sync install

差分アンインストール

スターがついてないけれどインストールされているパッケージをアンインストールします。

apm-sync uninstall

差分スター

インストールされているけれどスターがついていないパッケージにスターをつけます。

apm-sync star

差分アンスター

インストールされてないけれどスターがついているパッケージのスターを外します。

apm-sync unstar

参考資料

bash の配列を for ループで使う

bash で for ループを使って配列の要素を参照するやり方のメモです。

for-each

配列の全要素を列挙するには ${array[@]} または ${array[*]} を使います。 インデックスの情報が必要ないのであれば,これが一番シンプルなやり方ですね。

for v in "${array[@]}"
do
    echo "$v"
done

インデックスの情報が必要な場合は,変数を用意して自前でカウントしなくてはなりません。

i=0
for v in "${array[@]}"
do
    echo "$i => $v"
    let i++
done

@ と * の違い

@* の違いは,ダブルクォーテーションで括ったときに,前者が配列の各要素を個別に出力するのに対して,後者は全要素を 1 つに結合した結果を出力する点です。 配列を使って join 相当の処理をしたいといった特別な理由がない限り,添え字に @ を使ってダブルクォーテーションで括っておけば間違いがありません。

素数を使って C 言語風に

配列の要素数${#array[@]} または ${#array[*]} で取得できます。 これを使って C 言語風の for ループを以下のように書けます。

for ((i = 0; i < ${#array[@]}; i++))
do
    echo "$i => ${array[$i]}"
done

添え字のリストでよりスマートに

${!array[@]}${!array[*]} とすると,配列 array の添え字のリストに展開されます。 C 言語風の for ループよりもスマートに書けます。 インデックスの情報が必要なら,この書き方が一番よいのではないでしょうか。

for i in "${!array[@]}"
do
    echo "$i => ${array[$i]}"
done

参考

DisplayPort 接続で省電力モードからの復帰時にマルチディスプレイの設定がリセットされる問題

省電力モードからの復帰時に不具合

ディスプレイの接続端子を DisplayPort に変更したら,省電力モードからの復帰時にマルチディスプレイの設定がリセットされる現象が発生しました。

サブディスプレイにログイン画面が映る

先にサブディスプレイが点いてログイン画面が映り,少し遅れてメインディスプレイが点いてログイン画面がそちらに移動するようになりました。 メインディスプレイは入力信号を自動検出する設定になっているため,DisplayPort の信号を検出するのに時間がかかることもあります。 サブディスプレイを縦置きにしているので,その間ずっと 90° 回転した横向きのログイン画面が表示されている状態です。

ウィンドウがメインディスプレイに移動する

画面が遅れるだけならばまだ我慢できるのですが,サブディスプレイに置いていたウィンドウがすべてメインディスプレイの方に移動してしまうという副作用もありました。 ディスプレイが再認識されるまでの時間に差があることで一時的にデュアルディスプレイが解除されてしまい,すべてのウィンドウが先に復帰したディスプレイに集まってしまうようです。

サブディスプレイには,作業中のプロジェクトに関連する資料を表示しておいたり,Slack や ToDo リストのような常時確認するものを置いてあったりします。 仕事の都合上,短時間の離席をすることも多いので,その度にいちいちウィンドウの配置を戻したりするのが非常に面倒です。

Compatibility Mode を有効にして解決

入力信号を自動検出しているせいかと思い,DisplayPort に固定してみることにしました。 しかし,わたしがメインディスプレイに使っている EIZO EV2750 は,標準の状態ではメニューから入力信号を指定することができませんでした。

入力信号を固定する方法があるはずと思って取扱説明書を眺めていると,管理者向け設定のところに気になる記述が見つかりました。

Compatibility Mode

コンピュータをDisplayPortコネクタに接続している場合、電源のオン/オフ時、および省電力モードからの復帰時に、ウィンドウやアイコンの位置がずれることがあります。その場合は、この機能を「ON」にしてください。

試しに Compatibility Mode を有効にしてみたところ,サブディスプレイが先に復帰する問題が無事に解決しました。 EV2750 で Compatibility Mode を有効にするには,ディスプレイの電源が ON の状態で一番左側のボタン(Input)を 3 秒以上長押しします。 画面に Compatibility Mode: On という表示が出ます。

DisplayPort のホットプラグ検出信号が原因らしい

調べてみたところ,DisplayPort のプラグアンドプレイの仕様(が厳格すぎること)が原因らしいです。

DisplayPort インターフェイスにはホットプラグ検出信号というものが含まれており,ディスプレイが PC に接続されていることを確認するためなどに使われているそうです。 ディスプレイの電源が Off になったり,省電力モードになったりすると,この信号が途切れてしまうため,PC から見るとディスプレイが切断されたように見えます。

EV2750 で Compatibility Mode を有効にすると,仕様に完全に準拠することをやめて,省電力時でもホットプラグ検出信号を送り続けるのでしょうね。 これは有名なトラブルらしく,今回の例のようにディスプレイ側で対策を用意していることも多いようです。 DisplayPort はまったく使ったことなかったので知りませんでした。