Patchwork [3,of,5] py3: byteify gendoc.py

login
register
mail settings
Submitter Matt Harbison
Date Dec. 19, 2018, 10:39 p.m.
Message ID <7935c7f28f9d098fa76d.1545259158@Envy>
Download mbox | patch
Permalink /patch/37252/
State Accepted
Headers show

Comments

Matt Harbison - Dec. 19, 2018, 10:39 p.m.
# HG changeset patch
# User Matt Harbison <matt_harbison@yahoo.com>
# Date 1545185847 18000
#      Tue Dec 18 21:17:27 2018 -0500
# Node ID 7935c7f28f9d098fa76d207e70455260a42e3190
# Parent  c96002c3968f7f74bfe68c5bacb1ba717a58e290
py3: byteify gendoc.py

This is mostly b'' prefixing, with some cargoculting of help.py to get around
`textwrap.dedent()` and __doc__ string requirements.
Yuya Nishihara - Dec. 20, 2018, 11:37 a.m.
On Wed, 19 Dec 2018 17:39:18 -0500, Matt Harbison wrote:
> # HG changeset patch
> # User Matt Harbison <matt_harbison@yahoo.com>
> # Date 1545185847 18000
> #      Tue Dec 18 21:17:27 2018 -0500
> # Node ID 7935c7f28f9d098fa76d207e70455260a42e3190
> # Parent  c96002c3968f7f74bfe68c5bacb1ba717a58e290
> py3: byteify gendoc.py

>  if __name__ == "__main__":
> -    doc = 'hg.1.gendoc'
> +    doc = b'hg.1.gendoc'
>      if len(sys.argv) > 1:
>          doc = sys.argv[1]
>  
>      ui = uimod.ui.load()
> -    if doc == 'hg.1.gendoc':
> +    if doc == b'hg.1.gendoc':
>          showdoc(ui)
>      else:
>          showtopic(ui, sys.argv[1])

sys.argv[n] is a unicode string on Python 3. We'll need to convert it back
to bytes.

Patch

diff --git a/doc/gendoc.py b/doc/gendoc.py
--- a/doc/gendoc.py
+++ b/doc/gendoc.py
@@ -10,11 +10,18 @@  import os
 import sys
 import textwrap
 
+try:
+    import msvcrt
+    msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
+    msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
+except ImportError:
+    pass
+
 # This script is executed during installs and may not have C extensions
 # available. Relax C module requirements.
-os.environ['HGMODULEPOLICY'] = 'allow'
+os.environ[r'HGMODULEPOLICY'] = r'allow'
 # import from the live mercurial repo
-sys.path.insert(0, "..")
+sys.path.insert(0, r"..")
 from mercurial import demandimport; demandimport.enable()
 # Load util so that the locale path is set by i18n.setdatapath() before
 # calling _().
@@ -25,6 +32,7 @@  from mercurial import (
     extensions,
     help,
     minirst,
+    pycompat,
     ui as uimod,
 )
 from mercurial.i18n import (
@@ -39,19 +47,19 @@  loaddoc = help.loaddoc
 
 def get_desc(docstr):
     if not docstr:
-        return "", ""
+        return b"", b""
     # sanitize
-    docstr = docstr.strip("\n")
+    docstr = docstr.strip(b"\n")
     docstr = docstr.rstrip()
     shortdesc = docstr.splitlines()[0].strip()
 
-    i = docstr.find("\n")
+    i = docstr.find(b"\n")
     if i != -1:
         desc = docstr[i + 2:]
     else:
         desc = shortdesc
 
-    desc = textwrap.dedent(desc)
+    desc = textwrap.dedent(desc.decode('latin1')).encode('latin1')
 
     return (shortdesc, desc)
 
@@ -61,91 +69,93 @@  def get_opts(opts):
             shortopt, longopt, default, desc, optlabel = opt
         else:
             shortopt, longopt, default, desc = opt
-            optlabel = _("VALUE")
+            optlabel = _(b"VALUE")
         allopts = []
         if shortopt:
-            allopts.append("-%s" % shortopt)
+            allopts.append(b"-%s" % shortopt)
         if longopt:
-            allopts.append("--%s" % longopt)
+            allopts.append(b"--%s" % longopt)
         if isinstance(default, list):
-            allopts[-1] += " <%s[+]>" % optlabel
+            allopts[-1] += b" <%s[+]>" % optlabel
         elif (default is not None) and not isinstance(default, bool):
-            allopts[-1] += " <%s>" % optlabel
-        if '\n' in desc:
+            allopts[-1] += b" <%s>" % optlabel
+        if b'\n' in desc:
             # only remove line breaks and indentation
-            desc = ' '.join(l.lstrip() for l in desc.split('\n'))
-        desc += default and _(" (default: %s)") % default or ""
-        yield (", ".join(allopts), desc)
+            desc = b' '.join(l.lstrip() for l in desc.split(b'\n'))
+        desc += default and _(b" (default: %s)") % bytes(default) or b""
+        yield (b", ".join(allopts), desc)
 
 def get_cmd(cmd, cmdtable):
     d = {}
     attr = cmdtable[cmd]
-    cmds = cmd.lstrip("^").split("|")
+    cmds = cmd.lstrip(b"^").split(b"|")
 
-    d['cmd'] = cmds[0]
-    d['aliases'] = cmd.split("|")[1:]
-    d['desc'] = get_desc(gettext(attr[0].__doc__))
-    d['opts'] = list(get_opts(attr[1]))
+    d[b'cmd'] = cmds[0]
+    d[b'aliases'] = cmd.split(b"|")[1:]
+    d[b'desc'] = get_desc(gettext(pycompat.getdoc(attr[0])))
+    d[b'opts'] = list(get_opts(attr[1]))
 
-    s = 'hg ' + cmds[0]
+    s = b'hg ' + cmds[0]
     if len(attr) > 2:
-        if not attr[2].startswith('hg'):
-            s += ' ' + attr[2]
+        if not attr[2].startswith(b'hg'):
+            s += b' ' + attr[2]
         else:
             s = attr[2]
-    d['synopsis'] = s.strip()
+    d[b'synopsis'] = s.strip()
 
     return d
 
 def showdoc(ui):
     # print options
-    ui.write(minirst.section(_("Options")))
+    ui.write(minirst.section(_(b"Options")))
     multioccur = False
     for optstr, desc in get_opts(globalopts):
-        ui.write("%s\n    %s\n\n" % (optstr, desc))
-        if optstr.endswith("[+]>"):
+        ui.write(b"%s\n    %s\n\n" % (optstr, desc))
+        if optstr.endswith(b"[+]>"):
             multioccur = True
     if multioccur:
-        ui.write(_("\n[+] marked option can be specified multiple times\n"))
-        ui.write("\n")
+        ui.write(_(b"\n[+] marked option can be specified multiple times\n"))
+        ui.write(b"\n")
 
     # print cmds
-    ui.write(minirst.section(_("Commands")))
+    ui.write(minirst.section(_(b"Commands")))
     commandprinter(ui, table, minirst.subsection)
 
     # print help topics
     # The config help topic is included in the hgrc.5 man page.
-    helpprinter(ui, helptable, minirst.section, exclude=['config'])
+    helpprinter(ui, helptable, minirst.section, exclude=[b'config'])
 
-    ui.write(minirst.section(_("Extensions")))
-    ui.write(_("This section contains help for extensions that are "
-               "distributed together with Mercurial. Help for other "
-               "extensions is available in the help system."))
-    ui.write(("\n\n"
-             ".. contents::\n"
-             "   :class: htmlonly\n"
-             "   :local:\n"
-             "   :depth: 1\n\n"))
+    ui.write(minirst.section(_(b"Extensions")))
+    ui.write(_(b"This section contains help for extensions that are "
+               b"distributed together with Mercurial. Help for other "
+               b"extensions is available in the help system."))
+    ui.write((b"\n\n"
+              b".. contents::\n"
+              b"   :class: htmlonly\n"
+              b"   :local:\n"
+              b"   :depth: 1\n\n"))
 
     for extensionname in sorted(allextensionnames()):
         mod = extensions.load(ui, extensionname, None)
         ui.write(minirst.subsection(extensionname))
-        ui.write("%s\n\n" % gettext(mod.__doc__))
+        ui.write(b"%s\n\n" % gettext(pycompat.getdoc(mod)))
         cmdtable = getattr(mod, 'cmdtable', None)
         if cmdtable:
-            ui.write(minirst.subsubsection(_('Commands')))
+            ui.write(minirst.subsubsection(_(b'Commands')))
             commandprinter(ui, cmdtable, minirst.subsubsubsection)
 
 def showtopic(ui, topic):
     extrahelptable = [
-        (["common"], '', loaddoc('common'), help.TOPIC_CATEGORY_MISC),
-        (["hg.1"], '', loaddoc('hg.1'), help.TOPIC_CATEGORY_CONFIG),
-        (["hg-ssh.8"], '', loaddoc('hg-ssh.8'), help.TOPIC_CATEGORY_CONFIG),
-        (["hgignore.5"], '', loaddoc('hgignore.5'), help.TOPIC_CATEGORY_CONFIG),
-        (["hgrc.5"], '', loaddoc('hgrc.5'), help.TOPIC_CATEGORY_CONFIG),
-        (["hgignore.5.gendoc"], '', loaddoc('hgignore'),
+        ([b"common"], b'', loaddoc(b'common'), help.TOPIC_CATEGORY_MISC),
+        ([b"hg.1"], b'', loaddoc(b'hg.1'), help.TOPIC_CATEGORY_CONFIG),
+        ([b"hg-ssh.8"], b'', loaddoc(b'hg-ssh.8'), help.TOPIC_CATEGORY_CONFIG),
+        ([b"hgignore.5"], b'', loaddoc(b'hgignore.5'),
+          help.TOPIC_CATEGORY_CONFIG),
+        ([b"hgrc.5"], b'', loaddoc(b'hgrc.5'), help.TOPIC_CATEGORY_CONFIG),
+        ([b"hgignore.5.gendoc"], b'', loaddoc(b'hgignore'),
          help.TOPIC_CATEGORY_CONFIG),
-        (["hgrc.5.gendoc"], '', loaddoc('config'), help.TOPIC_CATEGORY_CONFIG),
+        ([b"hgrc.5.gendoc"], b'', loaddoc(b'config'),
+          help.TOPIC_CATEGORY_CONFIG),
     ]
     helpprinter(ui, helptable + extrahelptable, None, include=[topic])
 
@@ -157,74 +167,73 @@  def helpprinter(ui, helptable, sectionfu
         if include and names[0] not in include:
             continue
         for name in names:
-            ui.write(".. _%s:\n" % name)
-        ui.write("\n")
+            ui.write(b".. _%s:\n" % name)
+        ui.write(b"\n")
         if sectionfunc:
             ui.write(sectionfunc(sec))
         if callable(doc):
             doc = doc(ui)
         ui.write(doc)
-        ui.write("\n")
+        ui.write(b"\n")
 
 def commandprinter(ui, cmdtable, sectionfunc):
     h = {}
     for c, attr in cmdtable.items():
-        f = c.split("|")[0]
-        f = f.lstrip("^")
+        f = c.split(b"|")[0]
+        f = f.lstrip(b"^")
         h[f] = c
     cmds = h.keys()
-    cmds.sort()
 
-    for f in cmds:
-        if f.startswith("debug"):
+    for f in sorted(cmds):
+        if f.startswith(b"debug"):
             continue
         d = get_cmd(h[f], cmdtable)
-        ui.write(sectionfunc(d['cmd']))
+        ui.write(sectionfunc(d[b'cmd']))
         # short description
-        ui.write(d['desc'][0])
+        ui.write(d[b'desc'][0])
         # synopsis
-        ui.write("::\n\n")
-        synopsislines = d['synopsis'].splitlines()
+        ui.write(b"::\n\n")
+        synopsislines = d[b'synopsis'].splitlines()
         for line in synopsislines:
             # some commands (such as rebase) have a multi-line
             # synopsis
-            ui.write("   %s\n" % line)
-        ui.write('\n')
+            ui.write(b"   %s\n" % line)
+        ui.write(b'\n')
         # description
-        ui.write("%s\n\n" % d['desc'][1])
+        ui.write(b"%s\n\n" % d[b'desc'][1])
         # options
-        opt_output = list(d['opts'])
+        opt_output = list(d[b'opts'])
         if opt_output:
             opts_len = max([len(line[0]) for line in opt_output])
-            ui.write(_("Options:\n\n"))
+            ui.write(_(b"Options:\n\n"))
             multioccur = False
             for optstr, desc in opt_output:
                 if desc:
-                    s = "%-*s  %s" % (opts_len, optstr, desc)
+                    s = b"%-*s  %s" % (opts_len, optstr, desc)
                 else:
                     s = optstr
-                ui.write("%s\n" % s)
-                if optstr.endswith("[+]>"):
+                ui.write(b"%s\n" % s)
+                if optstr.endswith(b"[+]>"):
                     multioccur = True
             if multioccur:
-                ui.write(_("\n[+] marked option can be specified"
-                           " multiple times\n"))
-            ui.write("\n")
+                ui.write(_(b"\n[+] marked option can be specified"
+                           b" multiple times\n"))
+            ui.write(b"\n")
         # aliases
-        if d['aliases']:
-            ui.write(_("    aliases: %s\n\n") % " ".join(d['aliases']))
+        if d[b'aliases']:
+            ui.write(_(b"    aliases: %s\n\n") % b" ".join(d[b'aliases']))
 
 
 def allextensionnames():
-    return extensions.enabled().keys() + extensions.disabled().keys()
+    return set(extensions.enabled().keys()) | set(extensions.disabled().keys())
 
 if __name__ == "__main__":
-    doc = 'hg.1.gendoc'
+    doc = b'hg.1.gendoc'
     if len(sys.argv) > 1:
         doc = sys.argv[1]
 
     ui = uimod.ui.load()
-    if doc == 'hg.1.gendoc':
+    if doc == b'hg.1.gendoc':
         showdoc(ui)
     else:
         showtopic(ui, sys.argv[1])