92 if self._methods: |
92 if self._methods: |
93 return self.eval(t) |
93 return self.eval(t) |
94 return t |
94 return t |
95 |
95 |
96 def splitargspec(spec): |
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 >>> splitargspec('') |
99 >>> splitargspec('') |
100 ([], None, []) |
100 ([], None, [], None) |
101 >>> splitargspec('foo bar') |
101 >>> splitargspec('foo bar') |
102 ([], None, ['foo', 'bar']) |
102 ([], None, ['foo', 'bar'], None) |
103 >>> splitargspec('foo *bar baz') |
103 >>> splitargspec('foo *bar baz **qux') |
104 (['foo'], 'bar', ['baz']) |
104 (['foo'], 'bar', ['baz'], 'qux') |
105 >>> splitargspec('*foo') |
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 pres = pre.split() |
121 pres = pre.split() |
110 posts = post.split() |
122 posts = post.split() |
111 if sep: |
123 if sep: |
112 if not posts: |
124 if not posts: |
113 raise error.ProgrammingError('no *varkey name provided') |
125 raise error.ProgrammingError('no *varkey name provided') |
114 return pres, posts[0], posts[1:] |
126 return pres, posts[0], posts[1:], optkey |
115 return [], None, pres |
127 return [], None, pres, optkey |
116 |
128 |
117 def buildargsdict(trees, funcname, argspec, keyvaluenode, keynode): |
129 def buildargsdict(trees, funcname, argspec, keyvaluenode, keynode): |
118 """Build dict from list containing positional and keyword arguments |
130 """Build dict from list containing positional and keyword arguments |
119 |
131 |
120 Arguments are specified by a tuple of ``(poskeys, varkey, keys)`` where |
132 Arguments are specified by a tuple of ``(poskeys, varkey, keys, optkey)`` |
|
133 where |
121 |
134 |
122 - ``poskeys``: list of names of positional arguments |
135 - ``poskeys``: list of names of positional arguments |
123 - ``varkey``: optional argument name that takes up remainder |
136 - ``varkey``: optional argument name that takes up remainder |
124 - ``keys``: list of names that can be either positional or keyword arguments |
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 If ``varkey`` specified, all ``keys`` must be given as keyword arguments. |
140 If ``varkey`` specified, all ``keys`` must be given as keyword arguments. |
127 |
141 |
128 Invalid keywords, too few positional arguments, or too many positional |
142 Invalid keywords, too few positional arguments, or too many positional |
129 arguments are rejected, but missing keyword arguments are just omitted. |
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 kwstart = next((i for i, x in enumerate(trees) if x[0] == keyvaluenode), |
146 kwstart = next((i for i, x in enumerate(trees) if x[0] == keyvaluenode), |
133 len(trees)) |
147 len(trees)) |
134 if kwstart < len(poskeys): |
148 if kwstart < len(poskeys): |
135 raise error.ParseError(_("%(func)s takes at least %(nargs)d positional " |
149 raise error.ParseError(_("%(func)s takes at least %(nargs)d positional " |
136 "arguments") |
150 "arguments") |
148 args[varkey] = trees[len(args):kwstart] |
162 args[varkey] = trees[len(args):kwstart] |
149 else: |
163 else: |
150 for k, x in zip(keys, trees[len(args):kwstart]): |
164 for k, x in zip(keys, trees[len(args):kwstart]): |
151 args[k] = x |
165 args[k] = x |
152 # remainder should be keyword arguments |
166 # remainder should be keyword arguments |
|
167 if optkey: |
|
168 args[optkey] = {} |
153 for x in trees[kwstart:]: |
169 for x in trees[kwstart:]: |
154 if x[0] != keyvaluenode or x[1][0] != keynode: |
170 if x[0] != keyvaluenode or x[1][0] != keynode: |
155 raise error.ParseError(_("%(func)s got an invalid argument") |
171 raise error.ParseError(_("%(func)s got an invalid argument") |
156 % {'func': funcname}) |
172 % {'func': funcname}) |
157 k = x[1][1] |
173 k = x[1][1] |
158 if k not in keys: |
174 if k in keys: |
|
175 d = args |
|
176 elif not optkey: |
159 raise error.ParseError(_("%(func)s got an unexpected keyword " |
177 raise error.ParseError(_("%(func)s got an unexpected keyword " |
160 "argument '%(key)s'") |
178 "argument '%(key)s'") |
161 % {'func': funcname, 'key': k}) |
179 % {'func': funcname, 'key': k}) |
162 if k in args: |
180 else: |
|
181 d = args[optkey] |
|
182 if k in d: |
163 raise error.ParseError(_("%(func)s got multiple values for keyword " |
183 raise error.ParseError(_("%(func)s got multiple values for keyword " |
164 "argument '%(key)s'") |
184 "argument '%(key)s'") |
165 % {'func': funcname, 'key': k}) |
185 % {'func': funcname, 'key': k}) |
166 args[k] = x[2] |
186 d[k] = x[2] |
167 return args |
187 return args |
168 |
188 |
169 def unescapestr(s): |
189 def unescapestr(s): |
170 try: |
190 try: |
171 return util.unescapestr(s) |
191 return util.unescapestr(s) |