LoginSignup
4

More than 5 years have passed since last update.

Fabric で fabric.api.abort に unicode が渡せない問題に対応する

Posted at

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"日本語のエラーメッセージ")

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4