Mercurial > public > mercurial-scm > hg
comparison mercurial/extensions.py @ 24734:fb6cb1b82f4f
extensions: extract partial application into a bind() function
We use partial function application for wrapping existing Mercurial functions,
and it's implemented separately each time. This patch extracts the partial
application into a new bind() function that can be used on its own by extensions
when appropriate.
In particular, the evolve extension needs to wrap functions in the various
bundle2 processing dictionaries, which the pre-existing methods don't support.
author | Eric Sumner <ericsumner@fb.com> |
---|---|
date | Wed, 15 Apr 2015 12:18:05 -0400 |
parents | 28af978c8f13 |
children | e6e7d1cce04d |
comparison
equal
deleted
inserted
replaced
24733:c00e4338fa4b | 24734:fb6cb1b82f4f |
---|---|
150 if extension in _extensions: | 150 if extension in _extensions: |
151 callback(loaded=True) | 151 callback(loaded=True) |
152 else: | 152 else: |
153 _aftercallbacks.setdefault(extension, []).append(callback) | 153 _aftercallbacks.setdefault(extension, []).append(callback) |
154 | 154 |
155 def bind(func, *args): | |
156 '''Partial function application | |
157 | |
158 Returns a new function that is the partial application of args and kwargs | |
159 to func. For example, | |
160 | |
161 f(1, 2, bar=3) === bind(f, 1)(2, bar=3)''' | |
162 assert callable(func) | |
163 def closure(*a, **kw): | |
164 return func(*(args + a), **kw) | |
165 return closure | |
166 | |
155 def wrapcommand(table, command, wrapper, synopsis=None, docstring=None): | 167 def wrapcommand(table, command, wrapper, synopsis=None, docstring=None): |
156 '''Wrap the command named `command' in table | 168 '''Wrap the command named `command' in table |
157 | 169 |
158 Replace command in the command table with wrapper. The wrapped command will | 170 Replace command in the command table with wrapper. The wrapped command will |
159 be inserted into the command table specified by the table argument. | 171 be inserted into the command table specified by the table argument. |
187 if e is entry: | 199 if e is entry: |
188 key = alias | 200 key = alias |
189 break | 201 break |
190 | 202 |
191 origfn = entry[0] | 203 origfn = entry[0] |
192 def wrap(*args, **kwargs): | 204 wrap = bind(util.checksignature(wrapper), util.checksignature(origfn)) |
193 return util.checksignature(wrapper)( | |
194 util.checksignature(origfn), *args, **kwargs) | |
195 | 205 |
196 wrap.__module__ = getattr(origfn, '__module__') | 206 wrap.__module__ = getattr(origfn, '__module__') |
197 | 207 |
198 doc = getattr(origfn, '__doc__') | 208 doc = getattr(origfn, '__doc__') |
199 if docstring is not None: | 209 if docstring is not None: |
239 work. Since you cannot control what other extensions are loaded by | 249 work. Since you cannot control what other extensions are loaded by |
240 your end users, you should play nicely with others by using the | 250 your end users, you should play nicely with others by using the |
241 subclass trick. | 251 subclass trick. |
242 ''' | 252 ''' |
243 assert callable(wrapper) | 253 assert callable(wrapper) |
244 def wrap(*args, **kwargs): | |
245 return wrapper(origfn, *args, **kwargs) | |
246 | 254 |
247 origfn = getattr(container, funcname) | 255 origfn = getattr(container, funcname) |
248 assert callable(origfn) | 256 assert callable(origfn) |
249 setattr(container, funcname, wrap) | 257 setattr(container, funcname, bind(wrapper, origfn)) |
250 return origfn | 258 return origfn |
251 | 259 |
252 def _disabledpaths(strip_init=False): | 260 def _disabledpaths(strip_init=False): |
253 '''find paths of disabled extensions. returns a dict of {name: path} | 261 '''find paths of disabled extensions. returns a dict of {name: path} |
254 removes /__init__.py from packages if strip_init is True''' | 262 removes /__init__.py from packages if strip_init is True''' |