[DRF] simplejwt에서 발생한 "TypeError: 'str' object is not callable"

Eunsung Lim·2020년 12월 30일
0

Django 개발일지

목록 보기
1/3
post-thumbnail

에러

서버의 인증 라이브러리를 django-rest-framework-simplejwt 4.6.0 버전으로 이전하고 있던 어느 평화로운 오후에, 느닷없이 다음과 같은 에러가 등장하셨다.

File "/**/account/serializers.py", line 57, in validate
    if not api_settings.USER_AUTHENTICATION_RULE(self.user):
TypeError: 'str' object is not callable

디버깅

코드를 분해해보니 drf-simplejwt가 앱 시작시에 불러오는 세팅값 중에 유저 유효성 검사 함수를 가리키는 USER_AUTHENTICATION_RULE값이 함수로 올바르게 임포트되지 못하고 문자열로 세팅되는 버그가 있었다.

왜 이런 일이..?

simplejwt는 세팅시에 DRF의 APISettings 클래스를 활용한다. 에러 메시지의 api_settings 역시 이 클래스(를 상속하는 클래스)의 인스턴스인데, api_settings.USER_AUTHENTICATION_RULE 구문에서 다음 함수가 실행된다.

def __getattr__(self, attr):
    if attr not in self.defaults:
        raise AttributeError("Invalid API setting: '%s'" % attr)

    try:
        # Check if present in user settings
        val = self.user_settings[attr]			[1]
    except KeyError:
        # Fall back to defaults
        val = self.defaults[attr]			[2]

    # Coerce import strings into classes
    if attr in self.import_strings:			[3]
        val = perform_import(val, attr)			[4]

    # Cache the result
    self._cached_attrs.add(attr)
    setattr(self, attr, val)
    return val
  1. 먼저 settings.py에서 유저가 지정한 USER_AUTHENTICATION_RULE값이 있는지 확인 후
  2. 없으면 디폴트 값인 'rest_framework_simplejwt.authentication.default_user_authentication_rule'을 가져온다.
  3. 만약 self.import_strings 튜플에 'USER_AUTHENTICATION_RULE'가 있으면
  4. 이 값이 가리키는 함수를 임포트해 반환하게 된다.

그런데 self.import_strings의 디폴트 값인IMPORT_STRINGS'USER_AUTHENTICATION_RULE'가 누락돼 해당 값이 가리키는 함수가 아닌 값 자체를 반환하고 있었다.
따라서 해당 변수를 호출하면 타입에러가 발생하는 것이었다.


해결방안

다음과 같이 해당 변수에 'USER_AUTHENTICATION_RULE' 값을 추가하면 해결된다.

IMPORT_STRINGS = (
    'AUTH_TOKEN_CLASSES',
    'TOKEN_USER_CLASS',
    'USER_AUTHENTICATION_RULE',
)

+

현재 simplejwt의 깃헙레포(11/26)에는 누락된 변수가 추가되어 있으나, pip로 설치되는 PyPI 4.6.0 버전(11/13)에는 값이 누락되어 에러가 발생한다.
언제가 나올 다음 버젼에서는 해당 문제가 수정되겠지만, 지금은 에러가 나는 TokenObtainPairSerializer를 커스터마이징해 USER_AUTHENTICATION_RULE의 디폴트 값인 default_user_authentication_rule 함수를 직접 호출하는 방식으로 해결하였다.

-  if not api_settings.USER_AUTHENTICATION_RULE(self.user):
+  if not user_authentication_rule(self.user):
profile
Strong belief in connecting the dots. 찬찬히 배우고 있는 학생 개발자입니다.

0개의 댓글