sapling/extutil.py
Laurent Charignon 96fb5e9e89 extutil: move wrapfilecache from reflog to extutil
Summary:
We move wrapfilecache from reflog to extutil to be able to reuse it
in fastmanifest

Test Plan: Tests pass

Reviewers: ttung

Subscribers: mjpieters

Differential Revision: https://phabricator.intern.facebook.com/D3318762
2016-05-19 16:25:28 -07:00

57 lines
2.0 KiB
Python

# extutil.py - useful utility methods for extensions
#
# Copyright 2016 Facebook
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
def replaceclass(container, classname):
'''Replace a class with another in a module, and interpose it into
the hierarchies of all loaded subclasses. This function is
intended for use as a decorator.
import mymodule
@replaceclass(mymodule, 'myclass')
class mysubclass(mymodule.myclass):
def foo(self):
f = super(mysubclass, self).foo()
return f + ' bar'
Existing instances of the class being replaced will not have their
__class__ modified, so call this function before creating any
objects of the target type.
'''
def wrap(cls):
oldcls = getattr(container, classname)
for subcls in oldcls.__subclasses__():
if subcls is not cls:
assert oldcls in subcls.__bases__
newbases = [oldbase
for oldbase in subcls.__bases__
if oldbase != oldcls]
newbases.append(cls)
subcls.__bases__ = tuple(newbases)
setattr(container, classname, cls)
return cls
return wrap
def wrapfilecache(cls, propname, wrapper):
"""Wraps a filecache property. These can't be wrapped using the normal
wrapfunction. This should eventually go into upstream Mercurial.
"""
origcls = cls
assert callable(wrapper)
while cls is not object:
if propname in cls.__dict__:
origfn = cls.__dict__[propname].func
assert callable(origfn)
def wrap(*args, **kwargs):
return wrapper(origfn, *args, **kwargs)
cls.__dict__[propname].func = wrap
break
cls = cls.__bases__[0]
if cls is object:
raise AttributeError(_("type '%s' has no property '%s'") % (origcls,
propname))