comparison mercurial/hook.py @ 50920: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 2761ce777fc4
children 18c8c18993f0
comparison
equal deleted inserted replaced
50919:0e6cea0c3113 50920:c642c03969ff
38 unmodified commands (e.g. mercurial.commands.update) can 38 unmodified commands (e.g. mercurial.commands.update) can
39 be run as hooks without wrappers to convert return values.""" 39 be run as hooks without wrappers to convert return values."""
40 40
41 if callable(funcname): 41 if callable(funcname):
42 obj = funcname 42 obj = funcname
43 funcname = pycompat.sysbytes(obj.__module__ + "." + obj.__name__) 43 funcname = obj.__module__ + "." + obj.__name__
44 else: 44 else:
45 d = funcname.rfind(b'.') 45 funcname = pycompat.sysstr(funcname)
46 d = funcname.rfind('.')
46 if d == -1: 47 if d == -1:
47 raise error.HookLoadError( 48 raise error.HookLoadError(
48 _(b'%s hook is invalid: "%s" not in a module') 49 _(b'%s hook is invalid: "%s" not in a module')
49 % (hname, funcname) 50 % (hname, stringutil.forcebytestr(funcname))
50 ) 51 )
51 modname = funcname[:d] 52 modname = funcname[:d]
52 oldpaths = sys.path 53 oldpaths = sys.path
53 if resourceutil.mainfrozen(): 54 if resourceutil.mainfrozen():
54 # binary installs require sys.path manipulation 55 # binary installs require sys.path manipulation
87 tracebackhint = _( 88 tracebackhint = _(
88 b'run with --traceback for stack trace' 89 b'run with --traceback for stack trace'
89 ) 90 )
90 else: 91 else:
91 tracebackhint = None 92 tracebackhint = None
92 raise error.HookLoadError( 93 msg = _(b'%s hook is invalid: import of "%s" failed')
93 _(b'%s hook is invalid: import of "%s" failed') 94 msg %= (
94 % (hname, modname), 95 stringutil.forcebytestr(hname),
95 hint=tracebackhint, 96 stringutil.forcebytestr(modname),
96 ) 97 )
98 raise error.HookLoadError(msg, hint=tracebackhint)
97 sys.path = oldpaths 99 sys.path = oldpaths
98 try: 100 try:
99 for p in funcname.split(b'.')[1:]: 101 for p in funcname.split('.')[1:]:
100 obj = getattr(obj, p) 102 obj = getattr(obj, p)
101 except AttributeError: 103 except AttributeError:
102 raise error.HookLoadError( 104 raise error.HookLoadError(
103 _(b'%s hook is invalid: "%s" is not defined') 105 _(b'%s hook is invalid: "%s" is not defined')
104 % (hname, funcname) 106 % (hname, stringutil.forcebytestr(funcname))
105 ) 107 )
106 if not callable(obj): 108 if not callable(obj):
107 raise error.HookLoadError( 109 raise error.HookLoadError(
108 _(b'%s hook is invalid: "%s" is not callable') 110 _(b'%s hook is invalid: "%s" is not callable')
109 % (hname, funcname) 111 % (hname, stringutil.forcebytestr(funcname))
110 ) 112 )
111 113
112 ui.note(_(b"calling hook %s: %s\n") % (hname, funcname)) 114 ui.note(
115 _(b"calling hook %s: %s\n") % (hname, stringutil.forcebytestr(funcname))
116 )
113 starttime = util.timer() 117 starttime = util.timer()
114 118
115 try: 119 try:
116 r = obj(ui=ui, repo=repo, hooktype=htype, **pycompat.strkwargs(args)) 120 r = obj(ui=ui, repo=repo, hooktype=htype, **pycompat.strkwargs(args))
117 except Exception as exc: 121 except Exception as exc:
132 duration = util.timer() - starttime 136 duration = util.timer() - starttime
133 ui.log( 137 ui.log(
134 b'pythonhook', 138 b'pythonhook',
135 b'pythonhook-%s: %s finished in %0.2f seconds\n', 139 b'pythonhook-%s: %s finished in %0.2f seconds\n',
136 htype, 140 htype,
137 funcname, 141 stringutil.forcebytestr(funcname),
138 duration, 142 duration,
139 ) 143 )
140 if r: 144 if r:
141 if throw: 145 if throw:
142 raise error.HookAbort(_(b'%s hook failed') % hname) 146 raise error.HookAbort(_(b'%s hook failed') % hname)
345 path, cmd = cmd[7:].rsplit(b':', 1) 349 path, cmd = cmd[7:].rsplit(b':', 1)
346 path = util.expandpath(path) 350 path = util.expandpath(path)
347 if repo: 351 if repo:
348 path = os.path.join(repo.root, path) 352 path = os.path.join(repo.root, path)
349 try: 353 try:
350 mod = extensions.loadpath(path, b'hghook.%s' % hname) 354 mod_name = 'hghook.%s' % pycompat.sysstr(hname)
355 mod = extensions.loadpath(path, mod_name)
351 except Exception: 356 except Exception:
352 ui.write(_(b"loading %s hook failed:\n") % hname) 357 ui.write(_(b"loading %s hook failed:\n") % hname)
353 raise 358 raise
354 hookfn = getattr(mod, cmd) 359 hookfn = getattr(mod, pycompat.sysstr(cmd))
355 else: 360 else:
356 hookfn = cmd[7:].strip() 361 hookfn = cmd[7:].strip()
357 r, raised = pythonhook( 362 r, raised = pythonhook(
358 ui, repo, htype, hname, hookfn, args, throw 363 ui, repo, htype, hname, hookfn, args, throw
359 ) 364 )