Show More
@@ -94,41 +94,55 b' class parser(object):' | |||
|
94 | 94 | return t |
|
95 | 95 | |
|
96 | 96 | def splitargspec(spec): |
|
97 | """Parse spec of function arguments into (poskeys, varkey, keys) | |
|
97 | """Parse spec of function arguments into (poskeys, varkey, keys, optkey) | |
|
98 | 98 | |
|
99 | 99 | >>> splitargspec('') |
|
100 | ([], None, []) | |
|
100 | ([], None, [], None) | |
|
101 | 101 | >>> splitargspec('foo bar') |
|
102 | ([], None, ['foo', 'bar']) | |
|
103 | >>> splitargspec('foo *bar baz') | |
|
104 | (['foo'], 'bar', ['baz']) | |
|
102 | ([], None, ['foo', 'bar'], None) | |
|
103 | >>> splitargspec('foo *bar baz **qux') | |
|
104 | (['foo'], 'bar', ['baz'], 'qux') | |
|
105 | 105 | >>> splitargspec('*foo') |
|
106 | ([], 'foo', []) | |
|
106 | ([], 'foo', [], None) | |
|
107 | >>> splitargspec('**foo') | |
|
108 | ([], None, [], 'foo') | |
|
107 | 109 | """ |
|
108 | pre, sep, post = spec.partition('*') | |
|
110 | optkey = None | |
|
111 | pre, sep, post = spec.partition('**') | |
|
112 | if sep: | |
|
113 | posts = post.split() | |
|
114 | if not posts: | |
|
115 | raise error.ProgrammingError('no **optkey name provided') | |
|
116 | if len(posts) > 1: | |
|
117 | raise error.ProgrammingError('excessive **optkey names provided') | |
|
118 | optkey = posts[0] | |
|
119 | ||
|
120 | pre, sep, post = pre.partition('*') | |
|
109 | 121 | pres = pre.split() |
|
110 | 122 | posts = post.split() |
|
111 | 123 | if sep: |
|
112 | 124 | if not posts: |
|
113 | 125 | raise error.ProgrammingError('no *varkey name provided') |
|
114 | return pres, posts[0], posts[1:] | |
|
115 | return [], None, pres | |
|
126 | return pres, posts[0], posts[1:], optkey | |
|
127 | return [], None, pres, optkey | |
|
116 | 128 | |
|
117 | 129 | def buildargsdict(trees, funcname, argspec, keyvaluenode, keynode): |
|
118 | 130 | """Build dict from list containing positional and keyword arguments |
|
119 | 131 | |
|
120 |
Arguments are specified by a tuple of ``(poskeys, varkey, keys)`` |
|
|
132 | Arguments are specified by a tuple of ``(poskeys, varkey, keys, optkey)`` | |
|
133 | where | |
|
121 | 134 | |
|
122 | 135 | - ``poskeys``: list of names of positional arguments |
|
123 | 136 | - ``varkey``: optional argument name that takes up remainder |
|
124 | 137 | - ``keys``: list of names that can be either positional or keyword arguments |
|
138 | - ``optkey``: optional argument name that takes up excess keyword arguments | |
|
125 | 139 | |
|
126 | 140 | If ``varkey`` specified, all ``keys`` must be given as keyword arguments. |
|
127 | 141 | |
|
128 | 142 | Invalid keywords, too few positional arguments, or too many positional |
|
129 | 143 | arguments are rejected, but missing keyword arguments are just omitted. |
|
130 | 144 | """ |
|
131 | poskeys, varkey, keys = argspec | |
|
145 | poskeys, varkey, keys, optkey = argspec | |
|
132 | 146 | kwstart = next((i for i, x in enumerate(trees) if x[0] == keyvaluenode), |
|
133 | 147 | len(trees)) |
|
134 | 148 | if kwstart < len(poskeys): |
@@ -150,20 +164,26 b' def buildargsdict(trees, funcname, argsp' | |||
|
150 | 164 | for k, x in zip(keys, trees[len(args):kwstart]): |
|
151 | 165 | args[k] = x |
|
152 | 166 | # remainder should be keyword arguments |
|
167 | if optkey: | |
|
168 | args[optkey] = {} | |
|
153 | 169 | for x in trees[kwstart:]: |
|
154 | 170 | if x[0] != keyvaluenode or x[1][0] != keynode: |
|
155 | 171 | raise error.ParseError(_("%(func)s got an invalid argument") |
|
156 | 172 | % {'func': funcname}) |
|
157 | 173 | k = x[1][1] |
|
158 |
if k |
|
|
174 | if k in keys: | |
|
175 | d = args | |
|
176 | elif not optkey: | |
|
159 | 177 | raise error.ParseError(_("%(func)s got an unexpected keyword " |
|
160 | 178 | "argument '%(key)s'") |
|
161 | 179 | % {'func': funcname, 'key': k}) |
|
162 | if k in args: | |
|
180 | else: | |
|
181 | d = args[optkey] | |
|
182 | if k in d: | |
|
163 | 183 | raise error.ParseError(_("%(func)s got multiple values for keyword " |
|
164 | 184 | "argument '%(key)s'") |
|
165 | 185 | % {'func': funcname, 'key': k}) |
|
166 |
|
|
|
186 | d[k] = x[2] | |
|
167 | 187 | return args |
|
168 | 188 | |
|
169 | 189 | def unescapestr(s): |
@@ -467,7 +467,19 b' def buildfunc(exp, context):' | |||
|
467 | 467 | |
|
468 | 468 | def _buildfuncargs(exp, context, curmethods, funcname, argspec): |
|
469 | 469 | """Compile parsed tree of function arguments into list or dict of |
|
470 |
(func, data) pairs |
|
|
470 | (func, data) pairs | |
|
471 | ||
|
472 | >>> context = engine(lambda t: (runsymbol, t)) | |
|
473 | >>> def fargs(expr, argspec): | |
|
474 | ... x = _parseexpr(expr) | |
|
475 | ... n = getsymbol(x[1]) | |
|
476 | ... return _buildfuncargs(x[2], context, exprmethods, n, argspec) | |
|
477 | >>> sorted(fargs('a(l=1, k=2)', 'k l m').keys()) | |
|
478 | ['k', 'l'] | |
|
479 | >>> args = fargs('a(opts=1, k=2)', '**opts') | |
|
480 | >>> args.keys(), sorted(args['opts'].keys()) | |
|
481 | (['opts'], ['k', 'opts']) | |
|
482 | """ | |
|
471 | 483 | def compiledict(xs): |
|
472 | 484 | return dict((k, compileexp(x, context, curmethods)) |
|
473 | 485 | for k, x in xs.iteritems()) |
@@ -479,12 +491,14 b' def _buildfuncargs(exp, context, curmeth' | |||
|
479 | 491 | return compilelist(getlist(exp)) |
|
480 | 492 | |
|
481 | 493 | # function with argspec: return dict of named args |
|
482 | _poskeys, varkey, _keys = argspec = parser.splitargspec(argspec) | |
|
494 | _poskeys, varkey, _keys, optkey = argspec = parser.splitargspec(argspec) | |
|
483 | 495 | treeargs = parser.buildargsdict(getlist(exp), funcname, argspec, |
|
484 | 496 | keyvaluenode='keyvalue', keynode='symbol') |
|
485 | 497 | compargs = {} |
|
486 | 498 | if varkey: |
|
487 | 499 | compargs[varkey] = compilelist(treeargs.pop(varkey)) |
|
500 | if optkey: | |
|
501 | compargs[optkey] = compiledict(treeargs.pop(optkey)) | |
|
488 | 502 | compargs.update(compiledict(treeargs)) |
|
489 | 503 | return compargs |
|
490 | 504 |
General Comments 0
You need to be logged in to leave comments.
Login now