[PATCH] command options: handle unicode defaults gracefully

Christophe de Vienne christophe at cdevienne.info
Tue Aug 29 18:11:18 EDT 2017


# HG changeset patch
# User Christophe de Vienne <christophe at cdevienne.info>
# Date 1504023891 -7200
#      Tue Aug 29 18:24:51 2017 +0200
# Node ID afba1cb303db6797e565907c277fd4150e76c141
# Parent  b1f75d8e887a4c06e6b120807f3defc5c7b78d33
command options: handle unicode defaults gracefully

If the default value of an option is a unicode string (something
than happen easily when using a 'from __future__ import unicode_literals'),
any value passed on the command line will be ignored because the fancyopts
module only checks for byte strings and not unicode strings.

Changing fancyopts behavior is easy but would make assumptions on how
the python3 port should be done, which is outside the scope of this patch.

The chosen approach is to encode the default value to ascii when parsing
the command line, and issue a devel warning for the sake of the extension
developers.

If encoding to ascii fails, the command is aborted.

diff -r b1f75d8e887a -r afba1cb303db mercurial/dispatch.py
--- a/mercurial/dispatch.py	Tue Aug 22 16:59:02 2017 -0400
+++ b/mercurial/dispatch.py	Tue Aug 29 18:24:51 2017 +0200
@@ -556,7 +556,23 @@
         if defaults:
             args = pycompat.maplist(
                 util.expandpath, pycompat.shlexsplit(defaults)) + args
-        c = list(entry[1])
+        c = []
+        for option in entry[1]:
+            default = option[2]
+            if not pycompat.ispy3 and isinstance(default, type(u'')):
+                ui.develwarn(
+                    "A unicode default value (%s) was passed to the "
+                    "%s.%s option" % (repr(default), cmd, option[1]))
+                try:
+                    default = default.encode('ascii')
+                except Exception:
+                    raise error.Abort(
+                        "Cannot encode %s.%s default value to ascii" %
+                        (cmd, option[1]),
+                        "Try changing the %s.%s default value to a "
+                        "non-unicode string" % (cmd, option[1]))
+                option = option[:2] + (default,) + option[3:]
+            c.append(option)
     else:
         cmd = None
         c = []
diff -r b1f75d8e887a -r afba1cb303db tests/test-devel-warnings.t
--- a/tests/test-devel-warnings.t	Tue Aug 22 16:59:02 2017 -0400
+++ b/tests/test-devel-warnings.t	Tue Aug 29 18:24:51 2017 +0200
@@ -250,3 +250,43 @@
   devel-warn: config item requires an explicit default value: 'test.dynamic' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
 
   $ cd ..
+
+Test warning on command options with unicode default value
+
+  $ hg init $TESTTMP/opt-unicode-default
+
+  $ cat > $TESTTMP/test_unicode_default_value.py << EOF
+  > from mercurial import registrar
+  > cmdtable = {}
+  > command = registrar.command(cmdtable)
+  > @command('ext', [('', 'opt', u'value', u'help')], 'ext [OPTIONS]')
+  > def ext(*args, **opts):
+  >     print(opts['opt'])
+  > EOF
+  $ cat > $TESTTMP/opt-unicode-default/.hg/hgrc << EOF
+  > [extensions]
+  > test_unicode_default_value = $TESTTMP/test_unicode_default_value.py
+  > EOF
+  $ hg -R $TESTTMP/opt-unicode-default ext --opt newvalue
+  devel-warn: A unicode default value (u'value') was passed to the ext.opt option at: */mercurial/dispatch.py:* (_dispatch) (glob)
+  newvalue
+
+Test abort on command options with non-ascii unicode default value
+
+  $ cat > $TESTTMP/test_unicode_default_value_noascii.py << EOF
+  > # encoding=utf-8
+  > from mercurial import registrar
+  > cmdtable = {}
+  > command = registrar.command(cmdtable)
+  > @command('ext', [('', 'opt', u'défaut', u'help')], 'ext [OPTIONS]')
+  > def ext(*args, **opts):
+  >     print(opts['opt'])
+  > EOF
+  $ cat > $TESTTMP/opt-unicode-default/.hg/hgrc << EOF
+  > [extensions]
+  > test_unicode_default_value = $TESTTMP/test_unicode_default_value_noascii.py
+  > EOF
+  $ hg -R $TESTTMP/opt-unicode-default ext
+  devel-warn: A unicode default value (u'd\xe9faut') was passed to the ext.opt option at: */mercurial/dispatch.py:* (_dispatch) (glob)
+  abort: ('Cannot encode ext.opt default value to ascii', 'Try changing the ext.opt default value to a non-unicode string')
+  [255]


More information about the Mercurial-devel mailing list