Created
April 27, 2015 06:19
-
-
Save yosshy/5ae19e9bf965746b47c1 to your computer and use it in GitHub Desktop.
monkeypatch utils
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Copyright 2010 United States Government as represented by the | |
# Administrator of the National Aeronautics and Space Administration. | |
# Copyright 2011 Justin Santa Barbara | |
# All Rights Reserved. | |
# | |
# Licensed under the Apache License, Version 2.0 (the "License"); you may | |
# not use this file except in compliance with the License. You may obtain | |
# a copy of the License at | |
# | |
# http://www.apache.org/licenses/LICENSE-2.0 | |
# | |
# Unless required by applicable law or agreed to in writing, software | |
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
# License for the specific language governing permissions and limitations | |
# under the License. | |
"""Monkey Patching Helper.""" | |
import inspect | |
import pyclbr | |
import sys | |
import eventlet | |
from oslo.config import cfg | |
from nova.openstack.common import importutils | |
monkey_patch_opts = [ | |
cfg.BoolOpt('enabled', | |
default=False, | |
help='Whether to log monkey patching'), | |
cfg.ListOpt('target_modules', | |
default=[], | |
help='List of modules/decorators to monkey patch'), | |
cfg.ListOpt('exclude_methods', | |
default=[], | |
help='List of methods not to monkey patch'), | |
] | |
CONF = cfg.CONF | |
CONF.register_opts(monkey_patch_opts, 'monkey_patch') | |
def monkey_patch(): | |
"""If the CONF.monkey_patch set as True, | |
this function patches a decorator | |
for all functions in specified modules. | |
You can set decorators for each modules | |
using CONF.monkey_patch_modules. | |
The format is "Module path:Decorator function". | |
Example: | |
'nova.api.ec2.cloud:nova.notifications.notify_decorator' | |
Parameters of the decorator is as follows. | |
(See nova.notifications.notify_decorator) | |
name - name of the function | |
function - object of the function | |
""" | |
# If CONF.monkey_patch is not True, this function do nothing. | |
if not CONF.monkey_patch.enabled: | |
return | |
# Get list of modules and decorators | |
for module_and_decorator in CONF.monkey_patch.target_modules: | |
module, decorator_name = module_and_decorator.split(':') | |
if module not in sys.modules: | |
continue | |
print("monkey-patching to module %s" % module) | |
# import decorator function | |
decorator = importutils.import_class(decorator_name) | |
__import__(module) | |
# Retrieve module information using pyclbr | |
module_data = pyclbr.readmodule_ex(module) | |
for key in module_data.keys(): | |
# set the decorator for the class methods | |
if isinstance(module_data[key], pyclbr.Class): | |
clz = importutils.import_class("%s.%s" % (module, key)) | |
for method, func in inspect.getmembers(clz, inspect.ismethod): | |
# check exclude_methods | |
if method in CONF.monkey_patch.exclude_methods: | |
continue | |
# avoid applying patch to methods with @classmethod | |
m = getattr(clz, method) | |
if m.__self__ is clz: | |
continue | |
# apply it | |
setattr(clz, method, | |
decorator("%s.%s.%s" % (module, key, method), func)) | |
# set the decorator for the function | |
if isinstance(module_data[key], pyclbr.Function): | |
# check exclude_methods | |
if key in CONF.monkey_patch.exclude_methods: | |
continue | |
# apply it | |
func = importutils.import_class("%s.%s" % (module, key)) | |
setattr(sys.modules[module], key, | |
decorator("%s.%s" % (module, key), func)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment