diff --git a/mercurial/help.py b/mercurial/help.py --- a/mercurial/help.py +++ b/mercurial/help.py @@ -140,7 +140,7 @@ def topicmatch(ui, commands, kw): else: summary = '' # translate docs *before* searching there - docs = _(getattr(entry[0], '__doc__', None)) or '' + docs = _(pycompat.getdoc(entry[0])) or '' if kw in cmd or lowercontains(summary) or lowercontains(docs): doclines = docs.splitlines() if doclines: @@ -162,8 +162,9 @@ def topicmatch(ui, commands, kw): for cmd, entry in getattr(mod, 'cmdtable', {}).iteritems(): if kw in cmd or (len(entry) > 2 and lowercontains(entry[2])): cmdname = cmd.partition('|')[0].lstrip('^') - if entry[0].__doc__: - cmddoc = gettext(entry[0].__doc__).splitlines()[0] + cmddoc = pycompat.getdoc(entry[0]) + if cmddoc: + cmddoc = gettext(cmddoc).splitlines()[0] else: cmddoc = _('(no help text available)') if filtercmd(ui, cmdname, kw, cmddoc): @@ -259,7 +260,7 @@ def makeitemsdoc(ui, topic, doc, marker, """ entries = [] for name in sorted(items): - text = (items[name].__doc__ or '').rstrip() + text = (pycompat.getdoc(items[name]) or '').rstrip() if (not text or not ui.verbose and any(w in text for w in _exclkeywords)): continue @@ -345,7 +346,7 @@ def help_(ui, commands, name, unknowncmd rst.append('\n') # description - doc = gettext(entry[0].__doc__) + doc = gettext(pycompat.getdoc(entry[0])) if not doc: doc = _("(no help text available)") if util.safehasattr(entry[0], 'definition'): # aliased command @@ -367,7 +368,7 @@ def help_(ui, commands, name, unknowncmd # extension help text try: mod = extensions.find(name) - doc = gettext(mod.__doc__) or '' + doc = gettext(pycompat.getdoc(mod)) or '' if '\n' in doc.strip(): msg = _("(use 'hg help -e %s' to show help for " "the %s extension)") % (name, name) @@ -415,7 +416,7 @@ def help_(ui, commands, name, unknowncmd if name == "shortlist" and not f.startswith("^"): continue f = f.lstrip("^") - doc = e[0].__doc__ + doc = pycompat.getdoc(e[0]) if filtercmd(ui, f, name, doc): continue doc = gettext(doc) @@ -518,7 +519,7 @@ def help_(ui, commands, name, unknowncmd def helpext(name, subtopic=None): try: mod = extensions.find(name) - doc = gettext(mod.__doc__) or _('no help text available') + doc = gettext(pycompat.getdoc(mod)) or _('no help text available') except KeyError: mod = None doc = extensions.disabledext(name) @@ -554,7 +555,7 @@ def help_(ui, commands, name, unknowncmd def helpextcmd(name, subtopic=None): cmd, ext, mod = extensions.disabledcmd(ui, name, ui.configbool('ui', 'strict')) - doc = gettext(mod.__doc__).splitlines()[0] + doc = gettext(pycompat.getdoc(mod)).splitlines()[0] rst = listexts(_("'%s' is provided by the following " "extension:") % cmd, {ext: doc}, indent=4, diff --git a/mercurial/pycompat.py b/mercurial/pycompat.py --- a/mercurial/pycompat.py +++ b/mercurial/pycompat.py @@ -177,6 +177,14 @@ if ispy3: """Raise exception with the given traceback""" raise exc.with_traceback(tb) + def getdoc(obj): + """Get docstring as bytes; may be None so gettext() won't confuse it + with _('')""" + doc = getattr(obj, u'__doc__', None) + if doc is None: + return doc + return sysbytes(doc) + def _wrapattrfunc(f): @functools.wraps(f) def w(object, name, *args): @@ -255,6 +263,9 @@ else: # better not to touch Python 2 part as it's already working fine. fsdecode = identity + def getdoc(obj): + return getattr(obj, '__doc__', None) + def getoptb(args, shortlist, namelist): return getopt.getopt(args, shortlist, namelist) diff --git a/tests/test-py3-commands.t b/tests/test-py3-commands.t --- a/tests/test-py3-commands.t +++ b/tests/test-py3-commands.t @@ -137,6 +137,20 @@ Test bytes-ness of policy.policy with HG update: (current) phases: 2 draft +Test weird unicode-vs-bytes stuff + + $ $PYTHON3 $HGBIN help | egrep -v '^ |^$' + Mercurial Distributed SCM + list of commands: + additional help topics: + (use 'hg help -v' to show built-in aliases and global options) + + $ $PYTHON3 $HGBIN help help | egrep -v '^ |^$' + hg help [-ecks] [TOPIC] + show help for a given topic or a help overview + options ([+] can be repeated): + (some details hidden, use --verbose to show complete help) + Prove the repo is valid using the Python 2 `hg`: $ hg verify checking changesets