Path: blob/master/modules/patches.py
3055 views
from collections import defaultdict123def patch(key, obj, field, replacement):4"""Replaces a function in a module or a class.56Also stores the original function in this module, possible to be retrieved via original(key, obj, field).7If the function is already replaced by this caller (key), an exception is raised -- use undo() before that.89Arguments:10key: identifying information for who is doing the replacement. You can use __name__.11obj: the module or the class12field: name of the function as a string13replacement: the new function1415Returns:16the original function17"""1819patch_key = (obj, field)20if patch_key in originals[key]:21raise RuntimeError(f"patch for {field} is already applied")2223original_func = getattr(obj, field)24originals[key][patch_key] = original_func2526setattr(obj, field, replacement)2728return original_func293031def undo(key, obj, field):32"""Undoes the peplacement by the patch().3334If the function is not replaced, raises an exception.3536Arguments:37key: identifying information for who is doing the replacement. You can use __name__.38obj: the module or the class39field: name of the function as a string4041Returns:42Always None43"""4445patch_key = (obj, field)4647if patch_key not in originals[key]:48raise RuntimeError(f"there is no patch for {field} to undo")4950original_func = originals[key].pop(patch_key)51setattr(obj, field, original_func)5253return None545556def original(key, obj, field):57"""Returns the original function for the patch created by the patch() function"""58patch_key = (obj, field)5960return originals[key].get(patch_key, None)616263originals = defaultdict(dict)646566