I was trying to implement the saving of requests in cache with Flask-Cache
, I have installed it and everything is fine, but when doing the import I get the import error.
ImportError: cannot import name 'import_string' from 'werkzeug' (/home/cc/Desktop/test/alg/envi/lib/python3.8/site-packages/werkzeug/__init__.py)
This is because the module Flask-cache
is being imported import_string
in this way:
from werkzeug import import_string
I have known this by looking for the file of the module installed in the virtual environment, clearly the solution is to change the way the function is imported, in this way:
from werkzeug.utils import import_string
But of course, I can't do this because if I manually modify __init__.py
a module file when deploying my app, it will give me the same error since everything happens automatically and I don't have the possibility to modify the file.
Modules version:
Werkzeug
:2.0.1
Flask-Cache
:0.13.1
What could be the solution in this case? Should I install another version of the module?
You have correctly diagnosed the problem.
flask_cache
tries to do afrom werkzeug import_string
and that syntax has been deprecated inwerkzeug
.Therefore
flask_cache
it contains a bug that needs to be fixed by its developer, but it seems that this module is no longer maintained (the last commits are eight years old), so it seems unlikely that it will be fixed.One solution could be to downgrade (
werkzeug
i.e. force install an older version where the import you're trying toflask_cahe
still work on), but that doesn't seem like a good idea. It is advisable to always use the latest versions because security flaws are supposed to be corrected and therefore installing old versions can be insecure.Luckily, thanks to Python's flexibility and everything being dynamic, there is another solution called monkey patching . This consists of modifying the behavior of a library "at runtime" (as opposed to doing it by modifying the source of the library)
The idea is to provide the module
werkzeug
with the symbolimport_string
before importingflask_cache
, but this without modifying the source ofwerkzeug
, but doing it from our program, through direct assignment.Namely:
As you can see, we start by importing the symbol in the correct way (because it
werkzeug
has moved that symbol to the submodule )utils
. Once we have it, weimport werkzeug
create the namespacewerkzeug
and finally in that namespace we create a new symbolimport_string
, and assign it the value of which we had imported fromutils
.Now we can import
flask_cache
. When it triesfrom werkzeug import import_string
, because Python doesn't reimport already imported namespaces, it won't try to loadwerkzeug/__init__.py
(which doesn't containimport_string
) but that line will just pass into the namespace offlask_cache
the symbolimport_strings
we added to the namespacewerkzeug
.We have patched the code of an external library without touching the code of the external library. This is what is called monkey patching . It goes without saying that this is not very well seen and that its use must be limited to justified causes, but this is one of them (other typical uses can be to patch blocking synchronous functions so that they become asynchronous and thus make them compatible with
asyncio
, or mocking for testing).