Search code examples
pythonpython-3.6python-decorators

How to fix "NoneType" error with python decorators?


I'm doing an LRU (Least Recently Used) cache with decorator to store recently used localization, but when I call function to read it from .json file I get "NoneType" error

def loc_cache(func):
    loc_cache.locale = {} # {lang:(local, count)} local:dict
    loc_cache.MAXLENGTH = 5
    def wrapper(key):
        print(key) #this function wasn't called
        if key not in loc_cache.locale.keys():
            try:
                locale = read_locale(key)
                loc_cache.locale[key] = (locale, 1)
                wrapper.locale = locale
            except KeyError:
                key = "en" # set default locale
                wrapper(key)
        else:
            locale, count = loc_cache.locale[key]
            loc_cache.locale[key] = (locale, count+1)
            wrapper.locale = locale
        return wrapper.locale

@loc_cache
def read_locale(key):
    locale = read_json("./config/locale.json", key)
    return locale

def auth(user:User):
    locale = read_locale(user.locale)
    print(locale["auth"])
    return

u = User(1) # __init__ takes 1 for id
u.locale = "en"
auth(u)

I expect that it would return phrase in "en" that stores in .json file, but it says

Traceback (most recent call last):
  File "main.py", line 61, in <module>
    auth(u)
  File "main.py", line 52, in auth
    locale = read_locale(user.locale)
TypeError: 'NoneType' object is not callable

Solution

  • You didn't return the wrapper function form the decorator, hence Python is returning None as usual and trying to call it when you do read_locale(user.locale). You need:

    def loc_cache(func):
        loc_cache.locale = {} # {lang:(local, count)} local:dict
        loc_cache.MAXLENGTH = 5
        def wrapper(key):
            print(key) #this function wasn't called
            if key not in loc_cache.locale.keys():
                try:
                    locale = read_locale(key)
                    loc_cache.locale[key] = (locale, 1)
                    wrapper.locale = locale
                except KeyError:
                    key = "en" # set default locale
                    wrapper(key)
            else:
                locale, count = loc_cache.locale[key]
                loc_cache.locale[key] = (locale, count+1)
                wrapper.locale = locale
            return wrapper.locale
        return wrapper
        # Here ^^^^