Patchwork [1,of,3] py3: convert __doc__ back to bytes in help.py

login
register
mail settings
Submitter Yuya Nishihara
Date June 1, 2017, 2:35 p.m.
Message ID <80919de85aade5f931d6.1496327745@mimosa>
Download mbox | patch
Permalink /patch/21125/
State Accepted
Headers show

Comments

Yuya Nishihara - June 1, 2017, 2:35 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1496323455 -32400
#      Thu Jun 01 22:24:15 2017 +0900
# Node ID 80919de85aade5f931d6fd5c8231f490c0b81125
# Parent  5d44d7d4076e5a96001b0f88c730fa7ea24a9e02
py3: convert __doc__ back to bytes in help.py

pycompat.getdoc() is pretty simple, but we wouldn't want to write handling
of None inline.

Patch

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