extensions: imp module is removed in Python 3.12 - use importlib to load files
imp has been deprecated for a long time, and has finally been removed in Python
3.12 .
imp was only used for loading extensions that has been specified with direct
.py path or path to a package directory. The same use cases can be achieved
quite simple with importlib, , possiby with small changes in corner cases with
undefined behaviour, such as extensions without .py source.
There might also be corner cases and undefined behaviour around use of
sys.modules and reloading.
--- a/mercurial/extensions.py Tue Jun 27 13:05:03 2023 +0200
+++ b/mercurial/extensions.py Wed Jun 28 14:23:13 2023 +0200
@@ -9,9 +9,10 @@
import ast
import collections
import functools
-import imp
+import importlib
import inspect
import os
+import sys
from .i18n import (
_,
@@ -89,20 +90,18 @@
path = pycompat.fsdecode(path)
if os.path.isdir(path):
# module/__init__.py style
- d, f = os.path.split(path)
- fd, fpath, desc = imp.find_module(f, [d])
- # When https://github.com/python/typeshed/issues/3466 is fixed
- # and in a pytype release we can drop this disable.
- return imp.load_module(
- module_name, fd, fpath, desc # pytype: disable=wrong-arg-types
- )
- else:
- try:
- return imp.load_source(module_name, path)
- except IOError as exc:
- if not exc.filename:
- exc.filename = path # python does not fill this
- raise
+ init_py_path = os.path.join(path, '__init__.py')
+ if not os.path.exists(init_py_path):
+ raise ImportError("No module named '%s'" % os.path.basename(path))
+ path = init_py_path
+
+ loader = importlib.machinery.SourceFileLoader(module_name, path)
+ spec = importlib.util.spec_from_file_location(module_name, loader=loader)
+ assert spec is not None # help Pytype
+ module = importlib.util.module_from_spec(spec)
+ sys.modules[module_name] = module
+ spec.loader.exec_module(module)
+ return module
def _importh(name):