py3: convert arbitrary exception object to byte string more reliably
Our exception types implement __bytes__(), which should be tried first. Do
lossy encoding conversion as a last resort.
--- a/mercurial/bundle2.py Thu Aug 03 20:08:31 2017 -0700
+++ b/mercurial/bundle2.py Thu Aug 03 23:02:32 2017 +0900
@@ -1045,7 +1045,7 @@
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)
--- a/mercurial/extensions.py Thu Aug 03 20:08:31 2017 -0700
+++ b/mercurial/extensions.py Thu Aug 03 23:02:32 2017 +0900
@@ -19,7 +19,6 @@
from . import (
cmdutil,
configitems,
- encoding,
error,
pycompat,
util,
@@ -114,16 +113,11 @@
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 @@
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 @@
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 @@
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))
--- a/mercurial/util.py Thu Aug 03 20:08:31 2017 -0700
+++ b/mercurial/util.py Thu Aug 03 23:02:32 2017 +0900
@@ -2268,6 +2268,15 @@
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('\\\\', '\\')