diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py --- a/mercurial/bundle2.py +++ b/mercurial/bundle2.py @@ -1045,7 +1045,7 @@ class bundlepart(object): ui.debug('bundle2-generatorexit\n') raise except BaseException as exc: - bexc = pycompat.bytestr(exc) + bexc = util.forcebytestr(exc) # backup exception data for later ui.debug('bundle2-input-stream-interrupt: encoding exception %s' % bexc) diff --git a/mercurial/extensions.py b/mercurial/extensions.py --- a/mercurial/extensions.py +++ b/mercurial/extensions.py @@ -19,7 +19,6 @@ from .i18n import ( from . import ( cmdutil, configitems, - encoding, error, pycompat, util, @@ -114,16 +113,11 @@ def _importext(name, path=None, reportfu mod = _importh(name) return mod -def _forbytes(inst): - """Portably format an import error into a form suitable for - %-formatting into bytestrings.""" - return encoding.strtolocal(str(inst)) - def _reportimporterror(ui, err, failed, next): # note: this ui.debug happens before --debug is processed, # Use --config ui.debug=1 to see them. ui.debug('could not import %s (%s): trying %s\n' - % (failed, _forbytes(err), next)) + % (failed, util.forcebytestr(err), next)) if ui.debugflag: ui.traceback() @@ -180,7 +174,7 @@ def _runuisetup(name, ui): uisetup(ui) except Exception as inst: ui.traceback() - msg = _forbytes(inst) + msg = util.forcebytestr(inst) ui.warn(_("*** failed to set up extension %s: %s\n") % (name, msg)) return False return True @@ -197,7 +191,7 @@ def _runextsetup(name, ui): extsetup() # old extsetup with no ui argument except Exception as inst: ui.traceback() - msg = _forbytes(inst) + msg = util.forcebytestr(inst) ui.warn(_("*** failed to set up extension %s: %s\n") % (name, msg)) return False return True @@ -215,7 +209,7 @@ def loadall(ui, whitelist=None): try: load(ui, name, path) except Exception as inst: - msg = _forbytes(inst) + msg = util.forcebytestr(inst) if path: ui.warn(_("*** failed to import extension %s from %s: %s\n") % (name, path, msg)) diff --git a/mercurial/util.py b/mercurial/util.py --- a/mercurial/util.py +++ b/mercurial/util.py @@ -2268,6 +2268,15 @@ def escapestr(s): def unescapestr(s): return codecs.escape_decode(s)[0] +def forcebytestr(obj): + """Portably format an arbitrary object (e.g. exception) into a byte + string.""" + try: + return pycompat.bytestr(obj) + except UnicodeEncodeError: + # non-ascii string, may be lossy + return pycompat.bytestr(encoding.strtolocal(str(obj))) + def uirepr(s): # Avoid double backslash in Windows path repr() return repr(s).replace('\\\\', '\\')