Mercurial > public > mercurial-scm > hg
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 ) |