Fabric 便利ですよね。
便利すぎて大抵のことは Fabric で済ませることができます。
ただ Fabric は Python 製なので、 unicode の扱いでたまに困ることがあります。
具体的には fabric.api.abort や fabric.api.puts に unicode が渡せないこと。
abort は sys.stderr に、 puts は sys.stdout に str を書き込んでしまうため、
unicode を渡すと UnicodeEncodeError が発生します。
これを避けるためには、あらかじめ unicode ではなく str に変換しておく必要があります。
from fabric.api import abort, task
@task
def abort_test():
abort(u"日本語のエラーメッセージ".encode('CP932'))
これでも大丈夫ですが、すべての使用箇所でエンコードするのはダサいです。
abort に渡される引数が unicode だったら、出力先のエンコードに応じて変換するようにしてみましょう。
fabric_patch.py
# -*- encoding: utf-8 -*-
import sys
import fabric
from fabric.api import abort, puts
encodings = {
abort: sys.stderr.encoding,
puts: sys.stdout.encoding,
}
def safe_msg(original):
u"""
fabric.api.abort/puts に unicode を渡すと出力時に UnicodeEncodeError が発生するので、
それを回避するためのデコレータ
"""
def revised(msg, *args, **kwargs):
if isinstance(msg, unicode):
encoding = encodings.get(original, None)
if encoding:
msg = msg.encode(encoding)
return original(msg, *args, **kwargs)
return revised
setattr(fabric.api, "abort", safe_msg(abort))
setattr(fabric.api, "puts", safe_msg(puts))
fabfile.py と同じディレクトリに fabric_patch.py を配置して、 abort の前にインポートしましょう。
これで unicode を変換しなくても、何の問題もなく日本語のエラーメッセージが出力できるようになります。
fabfile.py
# -*- encoding: utf-8 -*-
from __future__ import absolute_import
from . import fabric_patch
from fabric.api import abort, task
@task
def abort_test():
abort(u"日本語のエラーメッセージ")