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)) |
892 This may raise IOError or SyntaxError. |
891 This may raise IOError or SyntaxError. |
893 """ |
892 """ |
894 with open(path, b'rb') as src: |
893 with open(path, b'rb') as src: |
895 root = ast.parse(src.read(), path) |
894 root = ast.parse(src.read(), path) |
896 cmdtable = {} |
895 cmdtable = {} |
|
896 |
|
897 # Python 3.12 started removing Bytes and Str and deprecate harder |
|
898 use_constant = 'Bytes' not in vars(ast) |
|
899 |
897 for node in _walkcommand(root): |
900 for node in _walkcommand(root): |
898 if not node.args: |
901 if not node.args: |
899 continue |
902 continue |
900 a = node.args[0] |
903 a = node.args[0] |
901 if isinstance(a, ast.Str): |
904 if use_constant: # Valid since Python 3.8 |
902 name = pycompat.sysbytes(a.s) |
905 if isinstance(a, ast.Constant): |
903 elif isinstance(a, ast.Bytes): |
906 if isinstance(a.value, str): |
904 name = a.s |
907 name = pycompat.sysbytes(a.value) |
905 else: |
908 elif isinstance(a.value, bytes): |
906 continue |
909 name = a.value |
|
910 else: |
|
911 continue |
|
912 else: |
|
913 continue |
|
914 else: # Valid until 3.11 |
|
915 if isinstance(a, ast.Str): |
|
916 name = pycompat.sysbytes(a.s) |
|
917 elif isinstance(a, ast.Bytes): |
|
918 name = a.s |
|
919 else: |
|
920 continue |
907 cmdtable[name] = (None, [], b'') |
921 cmdtable[name] = (None, [], b'') |
908 return cmdtable |
922 return cmdtable |
909 |
923 |
910 |
924 |
911 def _finddisabledcmd(ui, cmd, name, path, strict): |
925 def _finddisabledcmd(ui, cmd, name, path, strict): |