73

does anyone have an idea, why this Python 3.2 code

try:    
    raise Exception('X')
except Exception as e:
    print("Error {0}".format(str(e)))

works without problem (apart of unicode encoding in windows shell :/), but this

try:    
    raise Exception('X')
except Exception as e:
    print("Error {0}".format(str(e, encoding = 'utf-8')))

throws TypeError: coercing to str: need bytes, bytearray or buffer-like object, Exception found ?

How to convert an Error to a string with custom encoding?

Edit

It does not works either, if there is \u2019 in message:

try:    
    raise Exception(msg)
except Exception as e:
    b = bytes(str(e), encoding = 'utf-8')
    print("Error {0}".format(str(b, encoding = 'utf-8')))

But why cannot str() convert an exception internally to bytes?

7
  • 2
    Did you try str(e).encode('utf-8')? Commented Aug 16, 2011 at 8:06
  • 1
    @agf Itself it returns bytes instead of string. I can use it as replacement of bytes(str(e), encoding = 'utf-8'), but I have always to do second conversion bytes => str Commented Aug 16, 2011 at 8:24
  • “why cannot str() convert to bytes” — how would it know to which encoding to convert? Also, your new code is equivalent to .format(str(e)) Commented Aug 16, 2011 at 8:27
  • @Eugene is right. You should just encode it after formatting. If you try and use the encoding parameter, it requires the source be accessible as bytes. Commented Aug 16, 2011 at 8:28
  • @Eugene Try to run it in windows shell on french win7, you will see that it is not equivalent Commented Aug 16, 2011 at 8:33

6 Answers 6

76

In Python 3.x, str(e) should be able to convert any Exception to a string, even if it contains Unicode characters.

So unless your exception actually returns an UTF-8 encoded byte array in its custom __str__() method, str(e, 'utf-8') will not work as expected (it would try to interpret a 16bit Unicode character string in RAM as an UTF-8 encoded byte array ...)

My guess is that your problem isn't str() but the print() (i.e. the step which converts the Python Unicode string into something that gets dumped on your console). See this answer for solutions: Python, Unicode, and the Windows console

Sign up to request clarification or add additional context in comments.

1 Comment

indeed, initially i had a problem with UnicodeEncodeError: 'charmap' codec can't encode character... in shell under french version of Win 7. It seemed more portable to convert explicitly everything to utf-8, instead of using some custom, os-dependant wrappers.
16

Try this, it should work.

try:    
    raise Exception('X')
except Exception as e:
    print("Error {0}".format(str(e.args[0])).encode("utf-8"))

Considering you have only a message in your internal tuple.

4 Comments

It was first thing I've tried, alas: AttributeError: 'Exception' object has no attribute 'message'
Oh,you are right; it's because in version > 3 python uses args and not message.
@SebastianoMerlino does args[0] work in Python 2.7 AND Python 3.5?? And do you have any source/documentation why it was removed?
@matth I find that args[0] works in Python 2.7 as well.
6

In Python3, string does not have such attribute as encoding. It's always unicode internally. For encoded strings, there are byte arrays:

s = "Error {0}".format(str(e)) # string
utf8str = s.encode("utf-8") # byte array, representing utf8-encoded text

2 Comments

It's just a parameter for constructor, which causes it to decode byte array to unicode assuming this encoding.
So i don't understand your response. Could you elaborate it a little bit?
3

In Python 3, you are already in "unicode space" and don't need encoding. Depending on what you want to achieve, you should the conversion do immediately before doing stuff.

E.g. you can convert all this to bytes(), but rather in the direction

bytes("Error {0}".format(str(e)), encoding='utf-8')

.

Comments

2

There is a version-agnostic conversion here:

# from the `six` library
import sys
PY2 = sys.version_info[0] == 2
if PY2:
    text_type = unicode
    binary_type = str
else:
    text_type = str
    binary_type = bytes

def exc2str(e):
    if e.args and isinstance(e.args[0], binary_type):
        return e.args[0].decode('utf-8')
    return text_type(e)

and tests for it:

def test_exc2str():
    a = u"\u0856"
    try:
        raise ValueError(a)
    except ValueError as e:
        assert exc2str(e) == a
        assert isinstance(exc2str(e), text_type)
    try:
        raise ValueError(a.encode('utf-8'))
    except ValueError as e:
        assert exc2str(e) == a
        assert isinstance(exc2str(e), text_type)
    try:
        raise ValueError()
    except ValueError as e:
        assert exc2str(e) == ''
        assert isinstance(exc2str(e), text_type)

Comments

1

You can use the traceback module.

If you want to print the error:

import traceback
traceback.print_exc()

If you want to convert to string:

import traceback
print("Error {0}".format(traceback.format_exc()))

1 Comment

I use it, but its problem is that it doesn't only return the base of the error, but its entire path. I believe he only wants the base error.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.