pythonpython-2to3

AttributeError:'bytes' object has no attribute 'encode'


Trying to import a code from python2 to python 3 and this problem happens

    <ipython-input-53-e9f33b00348a> in aesEncrypt(text, secKey)
     43 def aesEncrypt(text, secKey):
     44     pad = 16 - len(text) % 16
---> 45     text = text.encode("utf-8") + (pad * chr(pad)).encode("utf-8")
     46     encryptor = AES.new(secKey, 2, '0102030405060708')
     47     ciphertext = encryptor.encrypt(text)

AttributeError:'bytes' object has no attribute 'encode'

If I remove .encode("utf-8") the error is "can't concat str to bytes". Apparently pad*chr(pad) seems to be a byte string. It cannot use encode()

    <ipython-input-65-9e84e1f3dd26> in aesEncrypt(text, secKey)
     43 def aesEncrypt(text, secKey):
     44     pad = 16 - len(text) % 16
---> 45     text = text.encode("utf-8") + (pad * chr(pad))
     46     encryptor = AES.new(secKey, 2, '0102030405060708')
     47     ciphertext = encryptor.encrypt(text)

TypeError: can't concat str to bytes

However, the weird thing is that if i just try the part along. encode() works fine.

text = { 'username': '', 'password': '', 'rememberLogin': 'true' }
text=json.dumps(text)
print(text)
pad = 16 - len(text) % 16 
print(type(text))
text = text + pad * chr(pad) 
print(type(pad * chr(pad)))
print(type(text))
text = text.encode("utf-8") + (pad * chr(pad)).encode("utf-8") 
print(type(text))

{"username": "", "password": "", "rememberLogin": "true"}
<class 'str'>
<class 'str'>
<class 'str'>
<class 'bytes'>

Solution

  • If you don't know if a stringlike object is a Python 2 string (bytes) or Python 3 string (unicode). You could have a generic converter.

    Python3 shell:

    >>> def to_bytes(s):
    ...     if type(s) is bytes:
    ...         return s
    ...     elif type(s) is str or (sys.version_info[0] < 3 and type(s) is unicode):
    ...         return codecs.encode(s, 'utf-8')
    ...     else:
    ...         raise TypeError("Expected bytes or string, but got %s." % type(s))
    ...         
    >>> to_bytes("hello")
    b'hello'
    >>> to_bytes("hello".encode('utf-8'))
    b'hello'
    

    On Python 2 both these expressions evaluate to True: type("hello") == bytes and type("hello") == str. And type(u"hello") == str evaluates to False, while type(u"hello") == unicode is True.

    On Python 3 type("hello") == bytes is False, and type("hello") == str is True. And type("hello") == unicode raises a NameError exception since unicode isn't defined on 3.

    Python 2 shell:

    >>> to_bytes(u"hello")
    'hello'
    >>> to_bytes("hello")
    'hello'