Mercurial > public > mercurial-scm > hg
comparison mercurial/extensions.py @ 29765:19578bb84731
extensions: add unwrapfunction to undo wrapfunction
Before this patch, we don't have a safe way to undo a wrapfunction because
other extensions may wrap the same function and calling setattr will undo
them accidentally.
This patch adds an "unwrapfunction" to address the issue. It removes the
wrapper from the wrapper chain, and re-wraps everything, which is not the
most efficient but short and easy to understand. We can revisit the code
if we have perf issues with long chains.
The "undo" feature is useful in cases like wrapping a function just in a
scope. Like, having a "select" command to interactively (using arrow keys)
select content from some output (ex. smartlog). It could wrap "ui.label" to
extract interesting texts just in the "select" command.
author | Jun Wu <quark@fb.com> |
---|---|
date | Wed, 10 Aug 2016 16:27:33 +0100 |
parents | 8bf97c4c6c2a |
children | d5883fd055c6 |
comparison
equal
deleted
inserted
replaced
29764:8bf97c4c6c2a | 29765:19578bb84731 |
---|---|
306 assert callable(origfn) | 306 assert callable(origfn) |
307 wrap = bind(wrapper, origfn) | 307 wrap = bind(wrapper, origfn) |
308 _updatewrapper(wrap, origfn, wrapper) | 308 _updatewrapper(wrap, origfn, wrapper) |
309 setattr(container, funcname, wrap) | 309 setattr(container, funcname, wrap) |
310 return origfn | 310 return origfn |
311 | |
312 def unwrapfunction(container, funcname, wrapper=None): | |
313 '''undo wrapfunction | |
314 | |
315 If wrappers is None, undo the last wrap. Otherwise removes the wrapper | |
316 from the chain of wrappers. | |
317 | |
318 Return the removed wrapper. | |
319 Raise IndexError if wrapper is None and nothing to unwrap; ValueError if | |
320 wrapper is not None but is not found in the wrapper chain. | |
321 ''' | |
322 chain = getwrapperchain(container, funcname) | |
323 origfn = chain.pop() | |
324 if wrapper is None: | |
325 wrapper = chain[0] | |
326 chain.remove(wrapper) | |
327 setattr(container, funcname, origfn) | |
328 for w in reversed(chain): | |
329 wrapfunction(container, funcname, w) | |
330 return wrapper | |
311 | 331 |
312 def getwrapperchain(container, funcname): | 332 def getwrapperchain(container, funcname): |
313 '''get a chain of wrappers of a function | 333 '''get a chain of wrappers of a function |
314 | 334 |
315 Return a list of functions: [newest wrapper, ..., oldest wrapper, origfunc] | 335 Return a list of functions: [newest wrapper, ..., oldest wrapper, origfunc] |