diff --git a/mercurial/extensions.py b/mercurial/extensions.py --- a/mercurial/extensions.py +++ b/mercurial/extensions.py @@ -122,6 +122,18 @@ def _reportimporterror(ui, err, failed, if ui.debugflag: ui.traceback() +def _rejectunicode(name, xs): + if isinstance(xs, (list, set, tuple)): + for x in xs: + _rejectunicode(name, x) + elif isinstance(xs, dict): + for k, v in xs.items(): + _rejectunicode(name, k) + _rejectunicode(b'%s.%s' % (name, util.forcebytestr(k)), v) + elif isinstance(xs, type(u'')): + raise error.ProgrammingError(b"unicode %r found in %s" % (xs, name), + hint="use b'' to make it byte string") + # attributes set by registrar.command _cmdfuncattrs = ('norepo', 'optionalrepo', 'inferrepo') @@ -134,19 +146,22 @@ def _validatecmdtable(ui, cmdtable): "registrar.command to register '%s'" % c, '4.6') missing = [a for a in _cmdfuncattrs if not util.safehasattr(f, a)] if not missing: - for option in e[1]: - default = option[2] - if isinstance(default, type(u'')): - raise error.ProgrammingError( - "option '%s.%s' has a unicode default value" - % (c, option[1]), - hint=("change the %s.%s default value to a " - "non-unicode string" % (c, option[1]))) continue raise error.ProgrammingError( 'missing attributes: %s' % ', '.join(missing), hint="use @command decorator to register '%s'" % c) +def _validatetables(ui, mod): + """Sanity check for loadable tables provided by extension module""" + for t in ['cmdtable', 'colortable', 'configtable']: + _rejectunicode(t, getattr(mod, t, {})) + for t in ['filesetpredicate', 'internalmerge', 'revsetpredicate', + 'templatefilter', 'templatefunc', 'templatekeyword']: + o = getattr(mod, t, None) + if o: + _rejectunicode(t, o._table) + _validatecmdtable(ui, getattr(mod, 'cmdtable', {})) + def load(ui, name, path): if name.startswith('hgext.') or name.startswith('hgext/'): shortname = name[6:] @@ -168,7 +183,7 @@ def load(ui, name, path): ui.warn(_('(third party extension %s requires version %s or newer ' 'of Mercurial; disabling)\n') % (shortname, minver)) return - _validatecmdtable(ui, getattr(mod, 'cmdtable', {})) + _validatetables(ui, mod) _extensions[shortname] = mod _order.append(shortname) diff --git a/tests/test-extension.t b/tests/test-extension.t --- a/tests/test-extension.t +++ b/tests/test-extension.t @@ -1707,8 +1707,8 @@ Prohibit the use of unicode strings as t > test_unicode_default_value = $TESTTMP/test_unicode_default_value.py > EOF $ hg -R $TESTTMP/opt-unicode-default dummy - *** failed to import extension test_unicode_default_value from $TESTTMP/test_unicode_default_value.py: option 'dummy.opt' has a unicode default value - *** (change the dummy.opt default value to a non-unicode string) + *** failed to import extension test_unicode_default_value from $TESTTMP/test_unicode_default_value.py: unicode u'value' found in cmdtable.dummy + *** (use b'' to make it byte string) hg: unknown command 'dummy' (did you mean summary?) [255]