Skip to content

Instantly share code, notes, and snippets.

@alexandre
Created December 9, 2016 21:00
Show Gist options
  • Save alexandre/9cd4496fcf9451e052aa20fdcedc070b to your computer and use it in GitHub Desktop.
Save alexandre/9cd4496fcf9451e052aa20fdcedc070b to your computer and use it in GitHub Desktop.
Forcing a decorator even when it is overridden.
from __future__ import print_function
import functools
from inspect import isfunction
def decorator_with_trace(force_super):
def wrapper(function):
if force_super:
function._wrapped = True
function._wrapper = decorator_with_trace
@functools.wraps(function)
def _inner(self, *args, **kwargs):
print("I wrapped a method from the class {}".format(self.__class__))
return function(self, *args, **kwargs)
return _inner
return wrapper
class WrapperEnforcement(type):
wrapped = {}
def __new__(meta, name, bases, dct):
_methods = [
(name, method) for name, method in dct.items() if isfunction(method)
]
for name, method in _methods:
if hasattr(method, '_wrapped'):
meta.wrapped[name] = getattr(method, '_wrapper')
elif not hasattr(method, '_wrapped') and meta.wrapped.get(name):
dct[name] = meta.wrapped[name](force_super=True)(method)
return super(WrapperEnforcement, meta).__new__(meta, name, bases, dct)
class Foo(object):
__metaclass__ = WrapperEnforcement
@decorator_with_trace(force_super=True)
def say_hi(self, name):
print("Hi, ", name)
@decorator_with_trace(force_super=False)
def say_bye(self, name):
print("Bye, ", name)
class Bar(Foo):
def say_hi(self, name):
print("Oi, ", name)
def say_bye(self, name):
print("Tchau, ", name)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment