Use my modulehacker recipe (recipe 577740) to apply decorators to any number of modules, or even (nearly) all of them.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | """decorations module"""
import types
import modulehacker
_modules = {}
_decorators = []
def register(decorator, modules=None):
"""Register a decorator for a list of module names."""
if not decorator:
return
if not modules and decorator in _decorators:
return
if not modules:
_decorators.append(decorator)
return
if isinstance(modules, str):
modules = (modules,)
for module in modules:
if module not in _modules:
_modules[module] = []
_modules[module].append(decorator)
class Hacker(modulehacker.Hacker):
def hack(self, module):
for decorator in _modules.get(module.__name__, ()):
self.decorate(module, decorator)
for decorator in _decorators:
self.decorate(module, decorator)
return module
def decorate(self, module, decorator):
for attr in module.__dict__:
obj = getattr(module, attr)
if isinstance(obj, types.FunctionType):
setattr(module, attr, decorator(obj))
modulehacker.register(Hacker())
|
Example
<rpc.py>
class Response:
def __init__(self, request, code=0):
self.request = request
self.code = code
self.result = None
class Request:
def __init__(self, id, method, args, access):
self.id = id
self.method = method
self.args = args
self.access = access
def generate_response(self):
return Response(self)
<something.py>
def f(request):
response = request.generate_response()
response.result = "Didn't do anything"
return response
<__main__>
import rpc
def log(message):
print(message)
# the decorators
def logs_in(f):
def newfunc(request):
log("handling <{o.method}> {o.args}".format(o=request))
return f(request)
return newfunc
def logs_out(f):
def newfunc(request):
response = f(request)
log("response: ({o.code}) {o.result}".format(o=response))
return response
return newfunc
import decorations
decorations.register(logs_in, "something")
decorations.register(logs_out, "something")
# now go for it
import something
request = rpc.Request(1, "help", {"module": "abc"}, None)
response = something.f(request)
# handling <help> {'module': 'abc'}
# response: (0) Didn't do anything
One neat thing is that you could use the modulehacker to automate some of this. In __main__, register one hacker that looks for some trigger in the module (like __decorate__ = True) and quickly registers another hacker that applies the decorator subsequently.