comparison mercurial/extensions.py @ 50757:19108906abaf stable

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.
author Mads Kiilerich <mads@kiilerich.com>
date Wed, 28 Jun 2023 14:23:13 +0200
parents b9eb65a1ec14
children 3ccef7902070
comparison
equal deleted inserted replaced
50756:847f703a4d13 50757:19108906abaf
7 7
8 8
9 import ast 9 import ast
10 import collections 10 import collections
11 import functools 11 import functools
12 import imp 12 import importlib
13 import inspect 13 import inspect
14 import os 14 import os
15 import sys
15 16
16 from .i18n import ( 17 from .i18n import (
17 _, 18 _,
18 gettext, 19 gettext,
19 ) 20 )
87 path = util.normpath(util.expandpath(path)) 88 path = util.normpath(util.expandpath(path))
88 module_name = pycompat.fsdecode(module_name) 89 module_name = pycompat.fsdecode(module_name)
89 path = pycompat.fsdecode(path) 90 path = pycompat.fsdecode(path)
90 if os.path.isdir(path): 91 if os.path.isdir(path):
91 # module/__init__.py style 92 # module/__init__.py style
92 d, f = os.path.split(path) 93 init_py_path = os.path.join(path, '__init__.py')
93 fd, fpath, desc = imp.find_module(f, [d]) 94 if not os.path.exists(init_py_path):
94 # When https://github.com/python/typeshed/issues/3466 is fixed 95 raise ImportError("No module named '%s'" % os.path.basename(path))
95 # and in a pytype release we can drop this disable. 96 path = init_py_path
96 return imp.load_module( 97
97 module_name, fd, fpath, desc # pytype: disable=wrong-arg-types 98 loader = importlib.machinery.SourceFileLoader(module_name, path)
98 ) 99 spec = importlib.util.spec_from_file_location(module_name, loader=loader)
99 else: 100 assert spec is not None # help Pytype
100 try: 101 module = importlib.util.module_from_spec(spec)
101 return imp.load_source(module_name, path) 102 sys.modules[module_name] = module
102 except IOError as exc: 103 spec.loader.exec_module(module)
103 if not exc.filename: 104 return module
104 exc.filename = path # python does not fill this
105 raise
106 105
107 106
108 def _importh(name): 107 def _importh(name):
109 """import and return the <name> module""" 108 """import and return the <name> module"""
110 mod = __import__(pycompat.sysstr(name)) 109 mod = __import__(pycompat.sysstr(name))