본문 바로가기
SW 개발/Python

Python 2.7과 3.8호환성: a bytes-like object is required, not 'str'에러 수정

by Kibua20 2020. 6. 28.

Python 2.7의 코드를 Python 3.8 버전에서 재 사용하는 경우 가끔 Type error가 발생한다.  개발하고 있는 python code가 2.7 버전과 3.8 버전에서 돌려야 하는 경우 아래와 같이 수정할 수 있다.  버전을 체크하는 경우 버전을 계속 올라감에 따라서 확인이 필요하기 때문에 code 유지 보수가 힘들다.  이 경우  try: except: 구문으로 exception 발생 여부를 체크해서 수정할 수 있다.  Python 2.7 에서는 try 구문에서 exception없이 처리하고, 3.8 버전에서 except구문으로 처리 가능하다.

 

수정 전 Code: 

def CreateMessage(sender, to, subject, message_text):
  message = MIMEText(message_text)
  message['to'] = to
  message['from'] = sender
  message['subject'] = subject

  return {'raw': base64.urlsafe_b64encode(message.as_string())}

수정 후 Code:  2.7 버전에서는 string으로 return 하고 3.8 버전에서는 byte로 return하도록 try / except 구문으로 적용

def CreateMessage(sender, to, subject, message_text):
  message = MIMEText(message_text)
  message['to'] = to
  message['from'] = sender
  message['subject'] = subject

  try:
    return {'raw': base64.urlsafe_b64encode(message.as_string())}
  except:
    return {'raw': base64.urlsafe_b64encode(message.as_bytes())}

 

Error Message: 

b64encode 함수에서 Type Error : a bytes-like object is required, not str 가 발생한다. 

kibua@ubuntu-pc:~/git/adcp-lge manager$ /usr/bin/python3 "/home/kibua/git/adcp-lge manager/adcp_mail.py"
Traceback (most recent call last):
File "/home/kibua/git/adcp-lge manager/adcp_mail.py", line 111, in <module>
print(CreateMessage("****@gmail.com", "****@gmail.com", "test1234", "messge_test1234"))
File "/home/kibua/git/adcp-lge manager/adcp_mail.py", line 55, in CreateMessage
return {'raw': base64.urlsafe_b64encode(message.as_string())}
File "/usr/lib/python3.8/base64.py", line 118, in urlsafe_b64encode
return b64encode(s).translate(_urlsafe_encode_translation)
File "/usr/lib/python3.8/base64.py", line 58, in b64encode
encoded = binascii.b2a_base64(s, newline=False)
TypeError: a bytes-like object is required, not 'str'

 

Python Reference 확인 

Python Doc에서 base64.urlsafe_b64encode(s)을 확인해보면 2.7 버전과 3.8 버전의 차이를 확인할 수 있다.  base64.encode()함수에서는 2.7 버전에서 string object를 처리했으나, 3.8 버전에서는 byte-object로 변경됨을 알 수 있다. 

 

 

python 2.7 Manual

base64.urlsafe_b64encode(s)

Encode strings using the URL- and filesystem-safe alphabet, which substitutes - instead of + and _ instead of / in the standard Base64 alphabet. The result can still contain =.

 

python 3.8 Manual

base64.urlsafe_b64encode(s)

Encode bytes-like object s using the URL- and filesystem-safe alphabet, which substitutes - instead of + and _ instead of / in the standard Base64 alphabet, and return the encoded bytes. The result can still contain =.

 

Python 2.7과 3.8 호환성 확보 가이드

Python 문서에서 2.7과 3.8 호환성 확보 내용은 아래와 같이 설명되어 있다.  코드 수정 시 버전을 직접 체크하는 것 보다는 기능을 체크해서 호환성을 확보해야 한다.

 

 

(출처:  https://docs.python.org/ko/3/howto/pyporting.html)


버전 감지 대신 기능 감지를 사용하십시오
필연적으로 실행 중인 파이썬 버전에 따라 수행할 작업을 선택해야 하는 코드를 갖게 됩니다. 가장 좋은 방법은 실행 중인 파이썬 버전이 필요한 것을 지원하는지에 대한 기능 감지를 사용하는 것입니다. 어떤 이유로 이 방법이 작동하지 않으면 버전 확인을 파이썬 3이 아닌 파이썬 2에 대해 수행해야 합니다. 이를 설명하기 위해, 예제를 살펴보겠습니다.

파이썬 3.3 이후로 파이썬의 표준 라이브러리에서 사용할 수 있고 PyPI의 importlib2를 통해 파이썬 2에서 사용할 수 있는 importlib의 기능에 액세스해야 한다고 가정해 봅시다. 다음과 같이 예를 들어 importlib.abc 모듈을 액세스하는 코드를 작성하려고 할 수 있습니다:다.

import sys 
if sys.version_info[0] == 3: 
    from importlib import abc 
else: from importlib2 import abc

이 코드는 문제점이 있는데, 파이썬 4가 나오면 어떻게 됩니까? 파이썬 3 대신 파이썬 2를 예외적인 사례로 취급하고 향후 파이썬 버전이 파이썬 2보다는 파이썬 3과 더 호환될 것이라고 가정하는 것이 좋습니다:

import sys 
if sys.version_info[0] > 2: 
    from importlib 
    import abc 
else: 
    from importlib2 import abc

그러나 가장 좋은 해결책은 버전 감지를 않고 기능 감지에 의존하는 것입니다. 그러면 버전 감지가 잘못될 수 있는 잠재적인 문제를 피하고 미래 호환성을 유지할 수 있습니다:

try: 
    from importlib import abc 
except ImportError: 
   from importlib2 import abc

호환성 회귀를 방지하십시오

 

<관련 글>

[모바일/Python] - SyntaxError: Non-ASCII character in file on, but no encoding declared

[모바일/Python] - Python 2와 3 버전 차이: a bytes-like object is required, not 'str'

[모바일/Android] - repo 실행 시 DeprecationWarning: imp module 대처법

[모바일/Android] - Android 소스 최적화 (100GB에서 65GB로 줄이기)

[모바일/Python] - [Tips] Python: XML Parsing 시 multiple elements on top level

[모바일/Python] - [Tips] Python 에서 XML comment 처리 - Sample code 제공

[모바일/Python] - [Tips] XML 에서 예약/특수 문자 처리

 




댓글