mimetypes.guess_type()の挙動はOS依存だよ

なんだこれゎ。

mimetypes.guess_type() でどのmimetypeが返ってくるかは動作している環境のOSに依存する様子。
そのため、たとえば hogehoge.csv というファイルを引数に与えたとき、
Windowsでは application/vnd.ms-excel が返り、Linuxでは text/csv が返る。
動作環境を変えたときにこれ使ってるとハマるので注意。

Windows

>>> import platform
>>> platform.platform()
'Windows-10-10.0.17763-SP0'

>>> import mimetypes
>>> mimetypes.guess_type('hogehoge.csv')
('application/vnd.ms-excel', None)

>>> mimetypes.guess_type('hogehoge.xlsx')
('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', None)

Linux

>>> import platform
>>> platform.platform()
'Linux-4.9.125-linuxkit-x86_64-with-debian-9.4'

>>> import mimetypes
>>> mimetypes.guess_type('hogehoge.csv')
('text/csv', None)

>>> mimetypes.guess_type('hogehoge.xlsx')
('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', None)

ただ text/csv を取りたかっただけなのに。。。
実用的な関数でないなぁ

Djangoのテストでsettingsの値をモックする

定期的に忘れるのでメモ

settingsの値をモックしたいときは、 django.test.utils.override_settingsTestCase.settings を使う。

override_settingsを使う場合

参考: https://gist.github.com/blaix/2294982#gistcomment-1318400

👆に書いてある通り。

from django.test.utils import override_settings

をインポートして、デコレーターとして使う。

@override_settings(DEBUG=False)

これだけ。

TestCase.settingsを使う場合

参考: https://stackoverflow.com/questions/36611393/how-to-mock-django-settings-attribute-used-in-another-module

with句で使う。withの範囲中だけsettingsのモックが有効になる。

class TestSample(TestCase):
    def test_1(self):
        try:
            val = settings.AA
        except AttributeError:
            print('AAはないよ!')

        with self.settings(AA='hogedayo'):
            print('AA='+settings.AA)

        try:
            val = settings.AA
        except AttributeError:
            print('withを抜けたからAAはないよ!')

    def test_2(self):
        try:
            val = settings.AA
        except AttributeError:
            print('AAはなくなったよ!')

出力

AAはないよ!
AA=hogedayo
withを抜けたからAAはないよ!
AAはなくなったよ!

デコレーターでやったほうがテストコードの見通しが良い気がする。わかりやすい。
お好みでお使いください。

moto+boto3のテストでOSError、NoCredentialErrorが出る場合

現象

moto == 1.3.7,
boto3 == 1.9.130
環境でテスト実行時に発生。

urllib3.exceptions.NewConnectionError: <botocore.awsrequest.AWSHTTPConnection object at xxxxxxxxxxxxxxxx>: Failed to establish a new connection: [WinError 10051] 到達できないネットワークでソケット操作を実行しようとしました。

テストのときにboto3がモックできておらず、AWSに通信が行ってしまっているが、認証情報不足でErrorになっているっぽい。

原因

開発環境にAWS接続用環境変数が存在しなかったため。
ダミーでもいいので何らかの値がないとmotoが動かない。
コマンドラインから、 AWS CLIaws configure を実行して、何らかの値をセットしておく。
(AWS CLIが入っていない場合は、

docs.aws.amazon.com

を参照。)

パソコン変えてからこれが発生して苦しんだ…初期設定はだいじ。

Windows環境でpipenvコマンドが認識されないとき

pip install pipenv したのに

C:\Users\foo\var\ >pipenv
'pipenv' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。

になるときの対処法。

stackoverflow.com

stackoverflowに対処法があった。
原因は virtualenv の競合とのこと。

pip uninstall virtualenv

pip uninstall pipenv

pip install pipenv

で解決。

dependabotのcompatibilityとは何か

dependabotがGitHubに買収された ので、これを機に最近dependabotの利用を始めた方も多いはず。
しかしいざdependabotからPRが飛んで来ると見方に困ったので記録に残します。

f:id:komajou:20190529202945p:plain

タイトルの通り、「compatibility」って書いてるけどこれ何??状態になった。
公式の説明はこちら。
https://dependabot.com/compatibility-score/

まとめると、
「①dependabotを導入していて ②同じ内容のアップデートをdependabotが作成した を満たす世界中のプロジェクトのうち、
更新後のCIテストがグリーンになった確率」。

具体的にいくつのプロジェクトを母数としているかは、PRのnoteに含まれるdependabotのバッジをクリックすることで確認することができる。
こんな感じ。
https://dependabot.com/compatibility-score/?dependency-name=django&package-manager=pip&previous-version=2.1.7&new-version=2.2.1

↑のページにはCIテストで失敗している公開リポジトリ一覧も表示される。
もしそれらが同じ原因で失敗しているなら、何が悪かったのかの原因究明の役に立つかも。

というわけで、dependabotの言う互換性(compatibility)とは、他のプロジェクトでの移行成功確率の実績値でした。
コードベースで機械的に何かを判別しているわけではない。
なので、リファレンスに倣ってお作法通りの使い方をしている場合は、スコアが高ければおそらく大丈夫といえるでしょう。
そうじゃないときは、スコアを過信すると事故があるかもしれない。
かもしれない、しか言えないけど。

この説明でいくと、ときどきでる compatibility unknown は、同じ内容の更新を反映したプロジェクトが他にない or 母数が少ないことが原因だと推測。

serverless-python-requirementsで変名Pipfileを読むことはできない

タイトルの通り。
serverless-python-requirements で無理をしたかったができなかった話。

serverless-python-requirementsはpipだけでなくpipenvにも対応している。

custom:
  pythonRequirements:
    usePipenv: true

でpipenvのPipfileを読むことが可能になるが、

  • serverless.ymlと同じディレクトリにある
  • ファイル名が Pipfile である

を満たす場合のみ、pipenvを使うことができる。
つまり、「変名Pipfileを別のディレクトリに置いておく」などはできないのである。
しょんぼりなのじゃ。

どうしてもそういうことをやりたい場合は、requirements.txt を毎回ジェネレートする方法でごり押し可能。
serverless.ymlは以下のように設定する。

custom:
  pythonRequirements:
    fileName: ../requirements.txt

そして、slsの前にpipenvをlockして、requirements.txtをジェネレートする。

$ pipenv lock -r > requirements.txt