Mercurial > public > mercurial-scm > hg
comparison mercurial/extensions.py @ 34087:5361771f9714
wrapfunction: use functools.partial if possible
Every `extensions.bind` call inserts a frame in traceback:
... in closure
return func(*(args + a), **kw)
which makes traceback noisy.
The Python stdlib has a `functools.partial` which is backed by C code and
does not pollute traceback. However it does not support instancemethod and
sets `args` attribute which could be problematic for alias handling.
This patch makes `wrapfunction` use `functools.partial` if we are wrapping a
function directly exported by a module (so it's impossible to be a class or
instance method), and special handles `wrapfunction` results so alias
handling code could handle `args` just fine.
As an example, `hg rebase -s . -d . --traceback` got 6 lines removed in my
setup:
File "hg/mercurial/dispatch.py", line 898, in _dispatch
cmdpats, cmdoptions)
-File "hg/mercurial/extensions.py", line 333, in closure
- return func(*(args + a), **kw)
File "hg/hgext/journal.py", line 84, in runcommand
return orig(lui, repo, cmd, fullargs, *args)
-File "hg/mercurial/extensions.py", line 333, in closure
- return func(*(args + a), **kw)
File "fb-hgext/hgext3rd/fbamend/hiddenoverride.py", line 119, in runcommand
result = orig(lui, repo, cmd, fullargs, *args)
File "hg/mercurial/dispatch.py", line 660, in runcommand
ret = _runcommand(ui, options, cmd, d)
-File "hg/mercurial/extensions.py", line 333, in closure
- return func(*(args + a), **kw)
File "hg/hgext/pager.py", line 69, in pagecmd
return orig(ui, options, cmd, cmdfunc)
....
Differential Revision: https://phab.mercurial-scm.org/D632
author | Jun Wu <quark@fb.com> |
---|---|
date | Tue, 05 Sep 2017 13:37:36 -0700 |
parents | 0e0ac8f09048 |
children | a763c891f36e |
comparison
equal
deleted
inserted
replaced
34086:a39dce4a76b8 | 34087:5361771f9714 |
---|---|
5 # This software may be used and distributed according to the terms of the | 5 # This software may be used and distributed according to the terms of the |
6 # GNU General Public License version 2 or any later version. | 6 # GNU General Public License version 2 or any later version. |
7 | 7 |
8 from __future__ import absolute_import | 8 from __future__ import absolute_import |
9 | 9 |
10 import functools | |
10 import imp | 11 import imp |
11 import inspect | 12 import inspect |
12 import os | 13 import os |
13 | 14 |
14 from .i18n import ( | 15 from .i18n import ( |
330 return func(*(args + a), **kw) | 331 return func(*(args + a), **kw) |
331 return closure | 332 return closure |
332 | 333 |
333 def _updatewrapper(wrap, origfn, unboundwrapper): | 334 def _updatewrapper(wrap, origfn, unboundwrapper): |
334 '''Copy and add some useful attributes to wrapper''' | 335 '''Copy and add some useful attributes to wrapper''' |
336 wrap.__name__ = origfn.__name__ | |
335 wrap.__module__ = getattr(origfn, '__module__') | 337 wrap.__module__ = getattr(origfn, '__module__') |
336 wrap.__doc__ = getattr(origfn, '__doc__') | 338 wrap.__doc__ = getattr(origfn, '__doc__') |
337 wrap.__dict__.update(getattr(origfn, '__dict__', {})) | 339 wrap.__dict__.update(getattr(origfn, '__dict__', {})) |
338 wrap._origfunc = origfn | 340 wrap._origfunc = origfn |
339 wrap._unboundwrapper = unboundwrapper | 341 wrap._unboundwrapper = unboundwrapper |
457 ''' | 459 ''' |
458 assert callable(wrapper) | 460 assert callable(wrapper) |
459 | 461 |
460 origfn = getattr(container, funcname) | 462 origfn = getattr(container, funcname) |
461 assert callable(origfn) | 463 assert callable(origfn) |
462 wrap = bind(wrapper, origfn) | 464 if inspect.ismodule(container): |
465 # origfn is not an instance or class method. "partial" can be used. | |
466 # "partial" won't insert a frame in traceback. | |
467 wrap = functools.partial(wrapper, origfn) | |
468 else: | |
469 # "partial" cannot be safely used. Emulate its effect by using "bind". | |
470 # The downside is one more frame in traceback. | |
471 wrap = bind(wrapper, origfn) | |
463 _updatewrapper(wrap, origfn, wrapper) | 472 _updatewrapper(wrap, origfn, wrapper) |
464 setattr(container, funcname, wrap) | 473 setattr(container, funcname, wrap) |
465 return origfn | 474 return origfn |
466 | 475 |
467 def unwrapfunction(container, funcname, wrapper=None): | 476 def unwrapfunction(container, funcname, wrapper=None): |