WindowsでのPython外部モジュール導入のはまりどころ

ちゃお……†

先日のこと､急に｢[自分がPyPIで公開してるモジュールたち](https://pypi.python.org/pypi?%3Aaction=search&term=yukino&submit=search)はWindowsでも動くのかな？｣と疑問が頭によぎったので調べました。(普段はMac使ってます)

結論から言うと､全部使えました！

ですが、試行錯誤が過酷だったのでノウハウを共有したいと思います。

1. 文字コードの問題
2. CやC++などのファイルをコンパイルできない場合
3. ファイルをなかなか離してくれない問題

# 文字コードの問題

PythonのモジュールはUTF-8前提のものがほとんどですが､
WindowsではCP932という文字コードを前提にしているので､
setup.pyでのインストール時に他のファイルを読み込むと下記のようなエラーが起こります｡

```
C:\Users\yukino>pip install jctconv
Collecting jctconv
  Downloading jctconv-0.1.tar.gz
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 20, in <module>
      File "C:\Users\yukino\AppData\Local\Temp\pip-build-32okbcay\jctconv\setup.py", line 8, in <module>
        r".*__version__ = '(.*?)'", re.S).match(f.read()).group(1)
    UnicodeDecodeError: 'cp932' codec can't decode byte 0x85 in position 327: illegal multibyte sequence
```

## 開発者側でできる対策
ファイルを読むときは`open` の代わりに `codecs.open` を使って文字コードを明示するとうまくいきます。

```py
from codecs import open

with open(path, 'r', encoding='utf8') as fd:
    pass
```

## ユーザー側でできる対策
Python2系の場合なら以下の内容の`Python27/Lib/sitecustomize.py`を作ればCP932ではなくutf-8を前提にファイルを扱うようになります｡

```py
#-*- coding: utf-8 -*-
import sys
sys.setdefaultencoding('utf-8')
```

# CやC++などのファイルをコンパイルできない場合

次のはまりポイントです。Pythonモジュールの中にはCythonやSWIGなどを使ってるものがあり､CやC++等のファイルをコンパイルできる環境でないと以下の様なエラーが出ます｡

```
C:\Users\yukino>pip install　neologdn
running install
running build
running build_ext
building 'neologdn' extension
error: Unable to find vcvarsall.bat
```

ここではユーザー側での対処法のみ扱うことにします｡

1. 下記URLからMicrosoft Visual C++ Compiler for Python 2.7
をダウンロードしてインストール｡
https://www.microsoft.com/en-us/download/details.aspx?id=44266
2. 開発者コマンドプロンプトを起動します。場所は、`Windowsボタン > すべてのプログラム > Microsoft Visual C++ Compiler Package`
3. 以下の環境変数をさっきのコマンドプロンプトから設定します｡

```
SET DISTUTILS_USE_SDK=1
SET MSSdk=1
```

あとはpipを使うなり、setup.pyから入れるなりできると思います。

# ファイルをなかなか離してくれない問題

Windowsでテストを実行したらファイル絡みのテストがこけるようになりました。
例えばこういうテストコードがあったときに

```py
        try:
            sketch = self.target_class(width=100)
            sketch.open(sketch_file)
            assert_equal(sketch['mami'], 14)
        finally:
            os.remove(sketch_file)
```

ファイルにアクセスできないエラーが発生します。

```
======================================================================
ERROR: test_madoka.Test_Sketch.test_save_and_load
----------------------------------------------------------------------
Traceback (most recent call last):
  File "c:\python35\lib\site-packages\nose\case.py", line 198, in runTest
    self.test(*self.arg)
  File "C:\Users\yukino\Desktop\git\madoka-python\test_madoka.py", line 113, in
test_save_and_load
    os.remove(sketch_file)
PermissionError: [WinError 32] プロセスはファイルにアクセスできません。別のプロ
セスが使用中です。: 'C:\\Users\\yukino\\AppData\\Local\\Temp\\tmpiyc0dho8'

----------------------------------------------------------------------
```

なのでなるべくファイルを解放してあげることを意識する必要があります。

```py
        try:
            sketch = self.target_class(width=100)
            sketch.open(sketch_file)
            assert_equal(sketch['mami'], 14)
        finally:
            del sketch
            os.remove(sketch_file)
```

# おわりに
意外とはまってしまって苦労しました……。この記事が誰かの役に立てればと願います🙏

ちなみにわたしが公開してるモジュールでのおすすめは、[jctconv (Pure-Pythonで半角全角ひらがなカタカナの相互変換をするもの)](http://pypi.python.org/pypi/jctconv) と、[neologdn (MeCab-neologd用の高速な前処理モジュール)](https://pypi.python.org/pypi/neologdn/)です！