My code is here works fine in python2.7
but fails inpython 3
functools.lru_cache(maxsize=32)
any change in from python 2 to python 3.
The error I am getting is for my configparser
object while caching in functools.lru_cache
it says
TypeError: unhashable type: 'ConfigParser'
Want to understand the changes in 'functools.lru_cache'
from python 2 and python 3?
#CONFI FILE
[translate]
api_url = https://url
api_version = version_num
api_key = key_value
#code goes here
import functools
from configparser import ConfigParser as SafeConfigParser
config = SafeConfigParser()
path ="./conf/services.ini"
config.read(path)
@functools.lru_cache(maxsize=32)
def build_api_params_key(config):
"""Build the api url and return with key."""
api_url = config.get('translate', 'api_url')
api_version = config.get('translate', 'api_version')
api_key = config.get('translate', 'api_key')
full_api_url = api_url + api_version
return api_key
The issue here is not functools.lru_cache
, it is actually the ConfigParser. ConfigParser
inherits from RawConfigParser
, which in Python 3x, inherits from collections.abc.MutableMapping
. The MutableMapping
abstract class is not hashable, as it is mutable and does not implement the __hash__
magic method.
Since the ConfigParser
instance is not hashable, it cannot be used as a key to the cache dictionary within the functools.lru_cache
decorator.
For further reference, see this section of the configparser docs.
Assuming that it is necessary to cache the contents of the config file, another option would be to read the the contents of the file and then pass the contents string to the cached function, like so
import functools
from configparser import ConfigParser as SafeConfigParser
path = "./conf/services.ini"
config_contents = open(path).read()
@functools.lru_cache(maxsize=32)
def build_api_params_key(config_contents: str):
"""Build the api url and return with key."""
config = SafeConfigParser()
config.read_string(config_contents)
api_url = config.get('translate', 'api_url')
api_version = config.get('translate', 'api_version')
api_key = config.get('translate', 'api_key')
full_api_url = api_url + api_version
return api_key
In the solution above, the config file is read to get string containing its contents. Since strings are hashable, this can be passed to the cached function. You can also do something similar with the file pointer if you would rather read the contents of the file within the function. However, these solutions are not compatible to Python 2.7 as read_string
is not defined.