Mercurial > public > mercurial-scm > hg-stable
diff mercurial/parser.py @ 31921:2156934b7917
parser: extend buildargsdict() to support arbitrary number of **kwargs
Prepares for adding dict(key1=value1, ...) template function. More tests
will be added later.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Mon, 03 Apr 2017 22:07:09 +0900 |
parents | a98540ea1e42 |
children | 0f41f1e3c75c |
line wrap: on
line diff
--- a/mercurial/parser.py Sat Apr 08 20:07:37 2017 +0900 +++ b/mercurial/parser.py Mon Apr 03 22:07:09 2017 +0900 @@ -94,41 +94,55 @@ return t def splitargspec(spec): - """Parse spec of function arguments into (poskeys, varkey, keys) + """Parse spec of function arguments into (poskeys, varkey, keys, optkey) >>> splitargspec('') - ([], None, []) + ([], None, [], None) >>> splitargspec('foo bar') - ([], None, ['foo', 'bar']) - >>> splitargspec('foo *bar baz') - (['foo'], 'bar', ['baz']) + ([], None, ['foo', 'bar'], None) + >>> splitargspec('foo *bar baz **qux') + (['foo'], 'bar', ['baz'], 'qux') >>> splitargspec('*foo') - ([], 'foo', []) + ([], 'foo', [], None) + >>> splitargspec('**foo') + ([], None, [], 'foo') """ - pre, sep, post = spec.partition('*') + optkey = None + pre, sep, post = spec.partition('**') + if sep: + posts = post.split() + if not posts: + raise error.ProgrammingError('no **optkey name provided') + if len(posts) > 1: + raise error.ProgrammingError('excessive **optkey names provided') + optkey = posts[0] + + pre, sep, post = pre.partition('*') pres = pre.split() posts = post.split() if sep: if not posts: raise error.ProgrammingError('no *varkey name provided') - return pres, posts[0], posts[1:] - return [], None, pres + return pres, posts[0], posts[1:], optkey + return [], None, pres, optkey def buildargsdict(trees, funcname, argspec, keyvaluenode, keynode): """Build dict from list containing positional and keyword arguments - Arguments are specified by a tuple of ``(poskeys, varkey, keys)`` where + Arguments are specified by a tuple of ``(poskeys, varkey, keys, optkey)`` + where - ``poskeys``: list of names of positional arguments - ``varkey``: optional argument name that takes up remainder - ``keys``: list of names that can be either positional or keyword arguments + - ``optkey``: optional argument name that takes up excess keyword arguments If ``varkey`` specified, all ``keys`` must be given as keyword arguments. Invalid keywords, too few positional arguments, or too many positional arguments are rejected, but missing keyword arguments are just omitted. """ - poskeys, varkey, keys = argspec + poskeys, varkey, keys, optkey = argspec kwstart = next((i for i, x in enumerate(trees) if x[0] == keyvaluenode), len(trees)) if kwstart < len(poskeys): @@ -150,20 +164,26 @@ for k, x in zip(keys, trees[len(args):kwstart]): args[k] = x # remainder should be keyword arguments + if optkey: + args[optkey] = {} for x in trees[kwstart:]: if x[0] != keyvaluenode or x[1][0] != keynode: raise error.ParseError(_("%(func)s got an invalid argument") % {'func': funcname}) k = x[1][1] - if k not in keys: + if k in keys: + d = args + elif not optkey: raise error.ParseError(_("%(func)s got an unexpected keyword " "argument '%(key)s'") % {'func': funcname, 'key': k}) - if k in args: + else: + d = args[optkey] + if k in d: raise error.ParseError(_("%(func)s got multiple values for keyword " "argument '%(key)s'") % {'func': funcname, 'key': k}) - args[k] = x[2] + d[k] = x[2] return args def unescapestr(s):