pythonpython-3.xstringbyteimapclient

How to convert a byte like string to normal bytes?


I've a problem during exception-handling with the imapclient-library.

I tried to handle the LoginError like this:

source = IMAPClient(host=args.source_server, port=args.source_port, ssl=not args.source_no_ssl)

try:
    print('Login source...'.format(args.source_user), end='', flush=False)
    source.login(args.source_user, args.source_pass)
    print('OK')

except exceptions.LoginError as e:
    print('ERROR: {}'.format(e))
    exit()

In case of exception i've got this:

Login source...ERROR: b'Invalid login'

I think The problem is, that format is calling the __str__()-method of the Exception-object and do not try to decode.

So the main question is who can i convert this string

"b'Invalid login'"

to a normal bytes-object like this?

b'Invalid login'

edit 1

@lenik If i use e.message.decode() like this:

try:
    print('Login source...'.format(args.source_user), end='', flush=False)
    source.login(args.source_user, args.source_pass)
    print('OK')
except exceptions.LoginError as e:
    print('ERROR: {}'.format(e.message.decode()))
    exit()

I've got an AttributeError:

AttributeError: 'LoginError' object has no attribute 'message'

edit 2

@snakecharmerb

try:
    print('Login source...'.format(args.source_user), end='', flush=False)
    source.login(args.source_user, args.source_pass)
    print('OK')
except exceptions.LoginError as e:
    print('ERROR: {}'.format(e.args[0].decode()))
    exit()
AttributeError: 'str' object has no attribute 'decode'

Solution

  • imapclient's login method looks like this:

    def login(self, username, password):
        """Login using *username* and *password*, returning the
        server response.
        """
        try:
            rv = self._command_and_check(
                'login',
                to_unicode(username),
                to_unicode(password),
                unpack=True,
            )
        except exceptions.IMAPClientError as e:
            raise exceptions.LoginError(str(e))
    
        logger.info('Logged in as %s', username)
    return rv
    

    We can see that it calls str on IMAPClientError, so if IMAPClientError was created with a bytes instance as its argument then we end up with stringified bytes in LoginError*.

    There are two ways to deal with this:

    1. Access the original bytes via the exception's args tuple:

    msg = e.args[0].decode()

    1. Use ast.literal_eval to convert the stringified exception:

    msg = ast.literal_eval(str(e)).decode()

    Of the two approaches, I think (1) is better in this specific case, but (2) is more generally applicable when you have stringified bytes.


    *Looking at the history of the imaplib module on github, it looks as if it changed to explicitly decode error messages before raising errors from the authenticate command in Python 3.5. So another solution might be to upgrade to Python 3.5+.