Mercurial > hg
changeset 50923:c642c03969ff
dynamic-import: use sysstr for importing extension and others
This logic is used by extensions, and python hooks and merge-tools. All this
logic eventually deals with native string (unicode in Python 3). This patch
makes it handle `str` directly instead of relying on some pycompat low lever
layer to do the conversion at the last minutes.
We adjust the Python version filtering of a test as the output seems to be present with Python 3.7 too.
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Thu, 31 Aug 2023 02:41:33 +0200 |
parents | 0e6cea0c3113 |
children | 9bffc6c4e4c5 |
files | mercurial/extensions.py mercurial/filemerge.py mercurial/hook.py tests/test-hook.t |
diffstat | 4 files changed, 35 insertions(+), 29 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/extensions.py Thu Aug 31 01:54:48 2023 +0200 +++ b/mercurial/extensions.py Thu Aug 31 02:41:33 2023 +0200 @@ -84,9 +84,8 @@ def loadpath(path, module_name): - module_name = module_name.replace(b'.', b'_') + module_name = module_name.replace('.', '_') path = util.normpath(util.expandpath(path)) - module_name = pycompat.fsdecode(module_name) path = pycompat.fsdecode(path) if os.path.isdir(path): # module/__init__.py style @@ -106,30 +105,31 @@ def _importh(name): """import and return the <name> module""" - mod = __import__(pycompat.sysstr(name)) - components = name.split(b'.') + mod = __import__(name) + components = name.split('.') for comp in components[1:]: mod = getattr(mod, comp) return mod def _importext(name, path=None, reportfunc=None): + name = pycompat.fsdecode(name) if path: # the module will be loaded in sys.modules # choose an unique name so that it doesn't # conflicts with other modules - mod = loadpath(path, b'hgext.%s' % name) + mod = loadpath(path, 'hgext.%s' % name) else: try: - mod = _importh(b"hgext.%s" % name) + mod = _importh("hgext.%s" % name) except ImportError as err: if reportfunc: - reportfunc(err, b"hgext.%s" % name, b"hgext3rd.%s" % name) + reportfunc(err, "hgext.%s" % name, "hgext3rd.%s" % name) try: - mod = _importh(b"hgext3rd.%s" % name) + mod = _importh("hgext3rd.%s" % name) except ImportError as err: if reportfunc: - reportfunc(err, b"hgext3rd.%s" % name, name) + reportfunc(err, "hgext3rd.%s" % name, name) mod = _importh(name) return mod @@ -140,9 +140,9 @@ ui.log( b'extension', b' - could not import %s (%s): trying %s\n', - failed, + stringutil.forcebytestr(failed), stringutil.forcebytestr(err), - next, + stringutil.forcebytestr(next), ) if ui.debugflag and ui.configbool(b'devel', b'debug.extensions'): ui.traceback()
--- a/mercurial/filemerge.py Thu Aug 31 01:54:48 2023 +0200 +++ b/mercurial/filemerge.py Thu Aug 31 02:41:33 2023 +0200 @@ -834,12 +834,13 @@ # avoid cycle cmdutil->merge->filemerge->extensions->cmdutil from . import extensions - mod = extensions.loadpath(toolpath, b'hgmerge.%s' % tool) + mod_name = 'hgmerge.%s' % pycompat.sysstr(tool) + mod = extensions.loadpath(toolpath, mod_name) except Exception: raise error.Abort( _(b"loading python merge script failed: %s") % toolpath ) - mergefn = getattr(mod, scriptfn, None) + mergefn = getattr(mod, pycompat.sysstr(scriptfn), None) if mergefn is None: raise error.Abort( _(b"%s does not have function: %s") % (toolpath, scriptfn)
--- a/mercurial/hook.py Thu Aug 31 01:54:48 2023 +0200 +++ b/mercurial/hook.py Thu Aug 31 02:41:33 2023 +0200 @@ -40,13 +40,14 @@ if callable(funcname): obj = funcname - funcname = pycompat.sysbytes(obj.__module__ + "." + obj.__name__) + funcname = obj.__module__ + "." + obj.__name__ else: - d = funcname.rfind(b'.') + funcname = pycompat.sysstr(funcname) + d = funcname.rfind('.') if d == -1: raise error.HookLoadError( _(b'%s hook is invalid: "%s" not in a module') - % (hname, funcname) + % (hname, stringutil.forcebytestr(funcname)) ) modname = funcname[:d] oldpaths = sys.path @@ -89,27 +90,30 @@ ) else: tracebackhint = None - raise error.HookLoadError( - _(b'%s hook is invalid: import of "%s" failed') - % (hname, modname), - hint=tracebackhint, + msg = _(b'%s hook is invalid: import of "%s" failed') + msg %= ( + stringutil.forcebytestr(hname), + stringutil.forcebytestr(modname), ) + raise error.HookLoadError(msg, hint=tracebackhint) sys.path = oldpaths try: - for p in funcname.split(b'.')[1:]: + for p in funcname.split('.')[1:]: obj = getattr(obj, p) except AttributeError: raise error.HookLoadError( _(b'%s hook is invalid: "%s" is not defined') - % (hname, funcname) + % (hname, stringutil.forcebytestr(funcname)) ) if not callable(obj): raise error.HookLoadError( _(b'%s hook is invalid: "%s" is not callable') - % (hname, funcname) + % (hname, stringutil.forcebytestr(funcname)) ) - ui.note(_(b"calling hook %s: %s\n") % (hname, funcname)) + ui.note( + _(b"calling hook %s: %s\n") % (hname, stringutil.forcebytestr(funcname)) + ) starttime = util.timer() try: @@ -134,7 +138,7 @@ b'pythonhook', b'pythonhook-%s: %s finished in %0.2f seconds\n', htype, - funcname, + stringutil.forcebytestr(funcname), duration, ) if r: @@ -347,11 +351,12 @@ if repo: path = os.path.join(repo.root, path) try: - mod = extensions.loadpath(path, b'hghook.%s' % hname) + mod_name = 'hghook.%s' % pycompat.sysstr(hname) + mod = extensions.loadpath(path, mod_name) except Exception: ui.write(_(b"loading %s hook failed:\n") % hname) raise - hookfn = getattr(mod, cmd) + hookfn = getattr(mod, pycompat.sysstr(cmd)) else: hookfn = cmd[7:].strip() r, raised = pythonhook(
--- a/tests/test-hook.t Thu Aug 31 01:54:48 2023 +0200 +++ b/tests/test-hook.t Thu Aug 31 02:41:33 2023 +0200 @@ -991,7 +991,7 @@ Traceback (most recent call last): ModuleNotFoundError: No module named 'hgext_syntaxerror' Traceback (most recent call last): - raise error.HookLoadError( (py38 !) + raise error.HookLoadError(msg, hint=tracebackhint) (py37 !) mercurial.error.HookLoadError: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed abort: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed @@ -1156,7 +1156,7 @@ Traceback (most recent call last): ModuleNotFoundError: No module named 'hgext_importfail' Traceback (most recent call last): - raise error.HookLoadError( (py38 !) + raise error.HookLoadError(msg, hint=tracebackhint) (py37 !) mercurial.error.HookLoadError: precommit.importfail hook is invalid: import of "importfail" failed abort: precommit.importfail hook is invalid: import of "importfail" failed