Fixing the importlib load_module() DeprecationWarning
You may have come across this nasty warning:
DeprecationWarning: the load_module() method is deprecated and slated for removal in Python 3.12; use exec_module() instead
Say you have this piece of code, which is trying to load a settings.py
file at runtime:
from importlib.machinery import SourceFileLoader
from pathlib import Path
settings_file = Path.cwd() / "settings.py"
user_settings_module = SourceFileLoader(
settings_file.name,
str(settings_file.resolve()),
).load_module()
The first argument to SourceFileLoader
is the name of the file and the second is the absolute path.
To fix the warning, the code above must be rewritten as:
from importlib.util import module_from_spec, spec_from_file_location
from pathlib import Path
settings_file = Path.cwd() / "settings.py"
spec = spec_from_file_location(
settings_file.name, settings_file.resolve()
)
settings_module = module_from_spec(spec)
spec.loader.exec_module(settings_module)
spec_from_file_location
also supports Path
-like objects.
First, we create a ModuleSpec
instance to specify its import-system-related
state. Then, the actual module is created based on
that spec using module_from_spec
. Finally, we execute the module in its own
namespace using exec_module
.
Extra
One of my co-workers found this hack to pass in a global variable using the
return value of module_from_spec
.
You can use it for something like overriding a setting when the module is loaded.
from importlib.util import module_from_spec, spec_from_file_location
import os
from pathlib import Path
settings_file = Path.cwd() / "settings.py"
spec = spec_from_file_location(
settings_file.name, settings_file.resolve()
)
settings_module = module_from_spec(spec)
# allow overriding default settings
settings_module.user_date_format = os.getenv("DATE_FORMAT")
spec.loader.exec_module(settings_module)
Your settings.py
can use it this way:
date_format = user_date_format or "DD-MM-YY"
The code in the module will be executed using the global variable user_date_format
when
exec_module
is called. If the loaded module has breakpoints to debug, those
will also work as they would when run directly.