Addresses an issue where Fabric cannot pass unicode to fabric.api.abort

Fabric is convenient, isn't it? It's so convenient that you can do most of it with Fabric.

However, since Fabric is made by Python, handling unicode can sometimes be a problem. Specifically, unicode cannot be passed to fabric.api.abort or fabric.api.puts. abort writes str to sys.stderr and puts writes str to sys.stdout. Passing unicode will result in a UnicodeEncodeError.

To avoid this, you need to convert it to str instead of unicode in advance.

from fabric.api import abort, task

@task
def abort_test():
    abort(u"Japanese error message".encode('CP932'))

That's okay, but it's awkward to encode everywhere you use it.

If the argument passed to abort is unicode, try converting it according to the encoding of the output destination.

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/If you pass unicode to puts, you will get a UnicodeEncodeError on output, so
Decorator to avoid it
    """
    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))

Place fabric_patch.py in the same directory as fabfile.py and import it before abort. Now you can output Japanese error messages without any problems without converting 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"Japanese error message")

Recommended Posts

Addresses an issue where Fabric cannot pass unicode to fabric.api.abort
Addresses an issue where an error does not occur even if the path does not pass when trying to read an image with cv2.imread ()