HYT MachineWorks

やったこととか思いついたことをメモしておくブログです。

2019年時点の俺流Windows10 64bitでのPython3環境構築と、condaでYAMLから環境復元が出来ない件について

Windows10におけるPython環境構築とは

本当に、一つの事しかしないのであればPythonの公式のバイナリをダウンロードして、パッケージのインストールにpipを使ってPyPIに集約された、いろいろな人が開発されたパッケージを使って構築してもいいと思います。ですが、Windowsの環境ではpipでは、絶妙に使いたいのにインストール出来ない場合も少なくないと思います。

また、使用されている方の多いAnacondaを使用するのも一つの手ではあると思いますがこれはこれで全部のせで、バージョンアップに時間がかかったり、複数の開発や分析をしている時に一つの開発のために同じパッケージのバージョンを上げると他の開発に思ってもないエラーが出たりして慌てることがあります。

そこで、使うのがAnacondaに内蔵されているパッケージ、仮想環境管理システムcondaです。これだけで、パッケージのインストール等の管理、仮想環境の管理が両方できます。

今回取り上げるのは、condaとpythonの最低限の状態で配布されているAnacondaの最小版Minicondaを使った環境構築について今回はメモしたいと思います。

あと、Windows上でcondaを使ってymlファイルでの環境の構築にバグがあってその対策方についても同時にメモします。

[2019/02/01 condaの仕様変更による大幅編集]

 Minicondaを使った環境構築

流れとしては、

  1. Minicondaを使ってpythonをインストール
  2. condaをアップデートし、conda initでPowerShellで使えるようにする
  3. 使いたいPythonバージョンとパッケージ環境を作成
  4. channelにconda-forgeを追加
  5. ymlファイル等から環境を作成する

という感じになります。

1.Minicondaを使ってpythonをインストール

下記、公式サイトからダウンロードしてインストール。

conda.io

このとき、全体か、個人に入れるかは推奨されているJust Meにします。

f:id:hytmachineworks:20190120192906p:plain

これにすると「C:\Users\{ユーザー名}」内にインストールされます。逆にall usersだとprogram filesに入るので他のユーザと共有するので勝手にパッケージを消されたりしたりしたら困るのであまり良くないと思います。

また、以前に記事にしたようにadministoratorの権限なしで使っている時に不具合もあったのでJust Meで使っています。

hytmachineworks.hatenablog.com

condaの仕様が変更になり、activateとdeactivateによる切り替えからconda activateとconda deactivateによる切り替えに変わりました。これは、以前は、仮想環境へとactivateで切り替えをして、deactivateでデフォルトのpythonに戻っていました。語弊があるかもしれませんが、はじめからbaseという仮想環境にいて、それをconda activateで他の環境に移るような動作に変わっています。そのため、あえてpathを通さなくても良いと思います。なのでMinicondaの推奨通り下のようにオプションを選択します。

f:id:hytmachineworks:20190201214607p:plain

後は、次へ次へでいいと思います。

 

2.condaをアップデートし、conda initでPowerShellで使えるようにする

MinicondaでインストールしたPythonにpathが通っていないのでコマンドプロンプトPowerShellpythonとかcondaとか打っただけでは、エラーになってしまうのでAnaconda Promptを使ってcondaのアップデートをします。

Anaconda Promptはスタートメニューから下の画像のようにMinicondaであってもAnaconda3の中にあるので注意してください。

f:id:hytmachineworks:20190202000509p:plain

Anaconda Promptが立ち上がったらcondaのバージョンアップを行いましょう。以下のコマンドでバージョンアップ出来ます。

C:\Users\username>conda update conda
Solving environment: done

## Package Plan ##

environment location: C:\Users\username\Miniconda3

added / updated specs:
- conda

The following packages will be UPDATED:

ca-certificates: 2018.03.07-0 --> 2018.12.5-0
certifi: 2018.8.24-py37_1 --> 2018.11.29-py37_0
conda: 4.5.11-py37_0 --> 4.6.2-py37_0
cryptography: 2.3.1-py37h74b6da3_0 --> 2.4.2-py37h7a1dbc1_0
openssl: 1.0.2p-hfa6e2cd_0 --> 1.1.1a-he774522_0
vc: 14-h0510ff6_3 --> 14.1-h0510ff6_4
vs2015_runtime: 14.0.25123-3 --> 14.15.26706-h3a45250_0

The following packages will be DOWNGRADED:

yaml: 0.1.7-hc54c509_2 --> 0.1.7-vc14_0 conda-forge [vc14]

最新のcondaにアップデートされました。そうしたら、使うシェルを指定しましょう。

私は、PowerShellを使うので

conda init powershell

するとPowerShellのプロファイルもなければ作成、あれば修正されます。ここからは、PowerShellで進めてゆくのでAnaconda Promptを閉じます。そして、PowerShellを開いてみましょう。

Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

パーソナル プロファイルとシステム プロファイルの読み込みにかかった時間は 546 ミリ秒です。
(base) PS C:\Users\username>

上記の様に開けていれば成功です。PSの隣に(base)と表示されていますが、現在有効な環境を確認するとbaseが有効であるとわかります。このように、常に自分の環境を意識して切り替えて使ってゆきます。

(base) PS C:\Users\username> conda info -e
# conda environments:
#
base * C:\Users\username\Miniconda3

※もし、実行できないというエラーがでた場合、.ps1のスクリプトの実行許可が付与されていないので。一度PowerShellを終了して。

Start > Windows PowerShell > Windows PowerShellで右クリックし、メニューから「管理者として実行する」をクリック

f:id:hytmachineworks:20190120195628p:plain

ユーザーアカウント制御のウインドウが表示されるので許可してあげてください。すると管理者:Windows PowerShellというウィンドウが開かれるので下記コマンドを実行してください。

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned

 実行ポリシーの変更を聞かれるので「yと入力してエンター」をして許可して上げてください。

3.使いたいPythonバージョンとパッケージ環境を作成

例えば、python 3.4のpy34という名前の環境の作成は

conda create -n py34 python=3.4

で、作成されます。ここで、python=3.4としていますが、この指定法だとpython 3.4のなかで最新この場合は3.4.5がインストールされます。もしマイナーバージョンまで指定が必要であればpython=3.4.1を入れるのであれば

conda create -n py34 python=3.4.1

と指定します。このバージョンの指定方法はパッケージを入れるときも同様に行えます。また、バージョンの指定を行わない場合は最新版がインストールされます。試しにやってみると以下の様にpython3.7.2がインストールされています。

(base) PS C:\Users\username> conda create -n pylatest python
Collecting package metadata: done
Solving environment: done

## Package Plan ##

environment location: C:\Users\username\Miniconda3\envs\pylatest

added / updated specs:
- python

The following NEW packages will be INSTALLED:

ca-certificates pkgs/main/win-64::ca-certificates-2018.12.5-0
certifi pkgs/main/win-64::certifi-2018.11.29-py37_0
openssl pkgs/main/win-64::openssl-1.1.1a-he774522_0
pip pkgs/main/win-64::pip-18.1-py37_0
python pkgs/main/win-64::python-3.7.2-h8c8aaf0_0
setuptools pkgs/main/win-64::setuptools-40.6.3-py37_0
sqlite pkgs/main/win-64::sqlite-3.26.0-he774522_0
vc pkgs/main/win-64::vc-14.1-h0510ff6_4
vs2015_runtime pkgs/main/win-64::vs2015_runtime-14.15.26706-h3a45250_0
wheel pkgs/main/win-64::wheel-0.32.3-py37_0
wincertstore pkgs/main/win-64::wincertstore-0.2-py37_0


Proceed ([y]/n)? y


Preparing transaction: done
Verifying transaction: done
Executing transaction: done
#
# To activate this environment, use
#
# $ conda activate pylatest
#
# To deactivate an active environment, use
#
# $ conda deactivate

最後に出ているように上で作成したpylatestという環境に移るには

conda activate pylatest

逆に出るには、以下のコマンドで出ることが出来ます。

conda deactivate 

作成された環境の一覧を確認するのは、以下のコマンドで確認。現在アクティブな環境に名前の後に*がついています

(base) PS C:\Users\username> conda info -e
# conda environments:
#
base * C:\Users\username\Miniconda3
py34 C:\Users\username\Miniconda3\envs\py34
pylatest C:\Users\username\Miniconda3\envs\pylatest

試しに、環境を切り替えて確認してみます。py34に切り替えてみます。

(base) PS C:\Users\username>conda activate py34
(py34) PS C:\Users\username>

PSの前に環境名(py34)がついたと思います。また、環境一覧を見ると

(py34) PS C:\Users\username> conda info -e
# conda environments:
#
base C:\Users\username\Miniconda3
py34 * C:\Users\username\Miniconda3\envs\py34
pylatest C:\Users\username\Miniconda3\envs\pylatest

ちゃんとpy34に移ってますね。元に戻す場合は、

(py34) PS C:\Users\username> conda deactivate
(base) PS C:\Users\username>

PSの前の環境名が外れてますね。また、環境一覧を見ると

(base) PS C:\Users\username> conda info -e
# conda environments:
#
base * C:\Users\username\Miniconda3
py34 C:\Users\username\Miniconda3\envs\py34
pylatest C:\Users\username\Miniconda3\envs\pylatest

元のbaseに戻ってますね。環境を使わなくなった場合は、試しにpy34を消すのは

(base) PS C:\Users\username> conda env remove -n py34

Remove all packages in environment C:\Users\username\Miniconda3\envs\py34:

 環境一覧を見ると

(base) PS C:\Users\username> conda info -e
# conda environments:
#
base * C:\Users\username\Miniconda3
pylatest C:\Users\username\Miniconda3\envs\pylatest

ちゃんと消えてますね。

ちなみに、環境を作る時に同時にパッケージをインストールも可能で例えばnumpyとscipyを同時にインストールであればスペースで区切って入れれば同時に環境が作成されます。

conda create -n py34 python=3.4 numpy scipy

また、ここで、anacondaを指定するとanacondaを入れたのと同じ事になります。

環境作成後に、環境に対してパッケージを入れる場合は、py34という環境にpandasを入れる場合は -n で環境名を指定してあげてインストール出来ます。

conda install pandas -n py34

もしくは、conda activateを用いて一旦、環境を有効にしてからインストールも出来ます。

conda activate py34

conda install pandas

 のどちらでも可能です。ちなみに、私は -n をつけて行う方が多いです。

4.channelにconda-forgeを追加

condaでパッケージをインストールする際に、パッケージのデータベース、condaではchannelと読んでいる物へ探しに行くのですが、デフォルトだとたまに無いことがあってその時にお世話になるのが、conda-forgeです。-c conda-forgeという感じで指定することもできるのですがデフォルトで検索対象に加えてしまいましょう。

conda config --append channels conda-forge

追加されたか確認すると

(base) PS C:\Users\username> conda config --get channels
--add channels 'conda-forge' # lowest priority
--add channels 'defaults' # highest priority

ちゃんと追加されていますね。

5.ymlファイル等から環境を作成する

まず、例を示すために環境を作成します。

conda create -n py34 python=3.4 numpy scipy

この環境をymlファイルに書き出す方法は、

conda env export -n py34 > py34.yml

[2019/02/07 追記はじめ]

このコマンドは間違っています。正確には、

conda env export -n py34 -f py34.yml

です。" > "でなくて、" -f "でしたこうすればちゃんとUTF-8で保存されて下の

conda env create -n py34 -f py34.yml

で復元出来ます。ですが、初めのコマンドは、PowerShellの機能ので

conda env export -n py34

の出力結果をpy34.ymlに対して書き出す。っていうコマンドになっていました。それが、おかしなエンコードになった原因でした。そのおかしなコマンドで慌ててやった色んなことの結果が以下に続いています。pipとの話もあるので最後まで読んでいただけると幸いです。

[2019/02/07 追記おわり]

現在のフォルダにpy34.ymlが保存されると思います。

一回、py34の環境を削除してそのファイルを使ってpy34という環境を作成してみましょう。

(base) PS C:\Users\username> conda env create -n py34 -f py34.yml

# >>>>>>>>>>>>>>>>>>>>>> ERROR REPORT <<<<<<<<<<<<<<<<<<<<<<

Traceback (most recent call last):
File "C:\Users\username\Miniconda3\lib\site-packages\conda\exceptions.py", line 1001, in __call__
return func(*args, **kwargs)
File "C:\Users\username\Miniconda3\lib\site-packages\conda_env\cli\main.py", line 73, in do_call
exit_code = getattr(module, func_name)(args, parser)
File "C:\Users\username\Miniconda3\lib\site-packages\conda_env\cli\main_create.py", line 77, in execute
directory=os.getcwd())
File "C:\Users\username\Miniconda3\lib\site-packages\conda_env\specs\__init__.py", line 40, in detect
if spec.can_handle():
File "C:\Users\username\Miniconda3\lib\site-packages\conda_env\specs\yaml_file.py", line 18, in can_handle
self._environment = env.from_file(self.filename)
File "C:\Users\username\Miniconda3\lib\site-packages\conda_env\env.py", line 131, in from_file
return from_yaml(yamlstr, filename=filename)
File "C:\Users\username\Miniconda3\lib\site-packages\conda_env\env.py", line 116, in from_yaml
data = yaml_load_standard(yamlstr)
File "C:\Users\username\Miniconda3\lib\site-packages\conda\common\serialize.py", line 76, in yaml_load_standard
return yaml.load(string, Loader=yaml.Loader, version="1.2")
File "C:\Users\username\Miniconda3\lib\site-packages\ruamel_yaml\main.py", line 638, in load
loader = Loader(stream, version, preserve_quotes=preserve_quotes)
File "C:\Users\username\Miniconda3\lib\site-packages\ruamel_yaml\loader.py", line 46, in __init__
Reader.__init__(self, stream, loader=self)
File "C:\Users\username\Miniconda3\lib\site-packages\ruamel_yaml\reader.py", line 80, in __init__
self.stream = stream # type: Any # as .read is called
File "C:\Users\username\Miniconda3\lib\site-packages\ruamel_yaml\reader.py", line 112, in stream
self.check_printable(val)
File "C:\Users\username\Miniconda3\lib\site-packages\ruamel_yaml\reader.py", line 233, in check_printable
'unicode', "special characters are not allowed")
ruamel_yaml.reader.ReaderError: unacceptable character #x0000: special characters are not allowed
in "<unicode string>", position 3

以下略

 py34.ymlに書いて文字が読めねーぞって怒られてます。ここがハマりポイント!

っていうかネットで誰も困って無いのが不思議なんだけどね。Linuxとかでは普通に読み込めるエンコードで書き出されるのかな?

エンコードが怪しいって事で 以前、取り上げたchardetを使って以下の内容のconda_chardet.pyを作成。もし、utf-8じゃなかったら保存し直すようにしてある。

from chardet.universaldetector import UniversalDetector
import sys


def file_encoding_detect(file_path):
""" detect text file encoding

:param file_path: file path string
:return: encoding string
"""

detector = UniversalDetector()

with open(file_path, mode="rb") as f:
read_data = f.readlines()

for line_data in read_data:
detector.feed(line_data)

if detector.done:
break

detector.close()

detect_result = detector.result

if detect_result["encoding"]:
detect_encoding = detect_result["encoding"]

else:
raise KeyError("Expected file is not text file!!!")

return detect_encoding


def main():
""" detect file encoding
:return: encoding string
"""
args = sys.argv

if len(args) < 2:
raise KeyError("File is not set")

file_yml = args[1].strip(".\\")

file_encoding = file_encoding_detect(file_yml)

print(file_encoding)

if file_encoding not in ["ascii", "utf-8"]:

with open(file_yml, mode="r", encoding=file_encoding) as fr:
data = fr.read()

mod_yml = "_mod.".join(file_yml.split("."))

with open(mod_yml, mode="w", encoding="utf-8") as fw:
fw.write(data)

message = "{old} saved new file {new} with encoding utf-8"

print(message.format(old=file_yml, new=mod_yml))


if __name__ == "__main__":
main()

そして、そのconda_chardet.pyとpy34.ymlを同じディレクトリにおいて実行すると

(base) PS C:\Users\username> python conda_chardet.py py34.yml
UTF-16
py34.yml saved new file py34_mod.yml with encoding utf-8

 という訳で、UTF-8でなくUTF-16なので読めないのが原因です。そんな訳でutf-8で保存したファイルで実行してみると

(base) PS C:\Users\username> conda env create -n py34 -f py34_mod.yml
Collecting package metadata: done
Solving environment: done
Preparing transaction: done
Verifying transaction: done
Executing transaction: done
#
# To activate this environment, use
#
# $ conda activate py34
#
# To deactivate an active environment, use
#
# $ conda deactivate

出来ているか環境一覧を見ると

(base) PS C:\Users\username> conda info -e
# conda environments:
#
base * C:\Users\username\Miniconda3
py34 C:\Users\username\Miniconda3\envs\py34
pylatest C:\Users\username\Miniconda3\envs\pylatest

ちゃんとできてますね。 パッケージも確認すると

(base) PS C:\Users\username> conda list -n py34
# packages in environment at C:\Users\username\Miniconda3\envs\py34:
#
# Name Version Build Channel
blas 1.0 mkl
intel-openmp 2019.1 144
mkl 2017.0.4 h6d528fc_0
numpy 1.11.3 py34_0
pip 9.0.1 py34_1
python 3.4.5 0
scipy 0.19.1 np111py34_0
setuptools 27.2.0 py34_1
vc 10 0
vs2010_runtime 10.00.40219.1 2
wheel 0.29.0 py34_0

python 3.4で、numpyとscipyがちゃんとインストールされてますね。

今回は、エンコード確認から、変更までpythonでやりましたが別にテキストエディタエンコードを指定して保存すれば大丈夫です。ただ、UTF-8のBOM無し(UTF-8N)で保存する必要があります。

 

一応、これで一通り環境構築はできると思います。皆さんのお役にたてば幸いです。

 

[2019/02/01 condaの仕様変更による大幅編集のメモ]

www.anaconda.com

以下で、触れているPowerShellへの対応と、pipとの相互乗り入れへの試験適用と結構盛りだくさんな内容です。当分目が離せなさそうです。

 

[2019/02/02  pipとの相互乗り入れを試したので追記]

参考までに、pipと相互乗り入れを可能にするコマンド

conda config --set pip_interop_enabled True

これを実行するとPyPiからのパッケージは、pipからインストールしなくてはいけませんが、その後のパッケージの削除や、バージョン変更等はcondaから行えます。

元に戻すのは、逆にFalseにして

conda config --set pip_interop_enabled False

で元に戻ります。この状態だとpipとcondaで同じパッケージを入れてもpipで入れた方しか見えなくなるみたい。そのうえでcondaからは消せないっていう状態になるみたい。前みたいにpipとcondaで入れたものが並列に並ぶ事は無くなったみたい。

どっちの状態でもpipで入れるとconda listではチャンネルがpypiというような表現に変わっています。でも、conda からチャンネルをpypiでやっても入りません。

また、状況がかわったら更新します。