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]