def patch_unless_ci(target, new): if not ci(): return patch(target, new) else: getter, attribute = _get_target(target) return patch(target, getattr(getter(), attribute))
def patch_method(unpatched_method): context = get_context(unpatched_method) getter, attribute = _get_target(import_path) klass = getter() getattr_path = ".".join(import_path.split(".")[0:-1] + ["__getattr__"]) def wrapper(wrapped_method, instance, attr): lazy_loaded = wrapped_method.original(instance, attr) if attr != attribute: return lazy_loaded return get_replacement_method( lazy_loaded, side_effect=side_effect, rvalue=rvalue, ignore=ignore, callback=callback, context=context ) @patch(getattr_path, side_effect=WrappedMethod(klass.__getattr__, wrapper), ctxt=context) def patched_method(*args, **kwargs): try: return unpatched_method(*args, **kwargs) finally: context.exit() return patched_method
def patched_test(*args, **kwargs): caliendo.util.current_test_module = context.module caliendo.util.current_test_handle = context.handle caliendo.util.current_test = "%s.%s" % (context.module, context.handle.__name__) getter, attribute = _get_target(import_path) method_to_patch = getattr(getter(), attribute) patch_with = get_replacement_method( method_to_patch, side_effect=side_effect, rvalue=rvalue, ignore=ignore, callback=callback, context=context, subsequent_rvalue=subsequent_rvalue, ) to_patch = find_modules_importing(import_path, context.module) # Patch methods in all modules requiring it drawer = {} for module, name, obj in to_patch: if hasattr(obj, "__len__") and len(obj) == 2: # We're patching an unbound method klass, attribute = obj get_or_store_backup_method(drawer, klass, attribute) setattr(getattr(module, name), attribute, patch_with) else: get_or_store_backup_method(drawer, module, name) setattr(module, name, patch_with) try: # Run the test with patched methods. return unpatched_test(*args, **kwargs) finally: # Un-patch patched methods for module, name, obj in to_patch: if hasattr(obj, "__len__") and len(obj) == 2: # We're patching an unbound method klass, attribute = obj method = get_or_store_backup_method(drawer, klass, attribute) setattr(getattr(module, name), attribute, method) else: method = get_or_store_backup_method(drawer, module, name) setattr(module, name, method) context.exit() # One level shallower
def get_recorder(import_path, ctxt): """ Gets a recorder for a particular target given a particular context :param str import_path: The import path of the method to record :param caliendo.hooks.Context ctxt: The context to record :rtype: function :returns: A method that acts like the target, but adds a hook for each call. """ getter, attribute = _get_target(import_path) method_to_patch = getattr(getter(), attribute) def recorder(*args, **kwargs): ctxt.stack.add_hook(Hook(call_descriptor_hash=util.get_current_hash(), callback=lambda cd: method_to_patch(*args, **kwargs))) ctxt.stack.skip_once(util.get_current_hash()) return method_to_patch(*args, **kwargs) return recorder
def find_modules_importing(dot_path, starting_with): """ Finds all the modules importing a particular attribute of a module pointed to by dot_path that starting_with is dependent on. :param dot_path: The dot path to the object of interest :type dot_path: str :param starting_with: The module from which to start resolving dependencies. The only modules importing dot_path returned will be dependencies of this module. :type starting_with: types.ModuleType :rtype: list of tuples :returns: A list of module, name, object representing modules depending on dot_path where module is a reference to the module, name is the name of the object in that module, and object is the imported object in that module. """ klass = None filtered = [] if "." not in dot_path: module_or_method = __import__(dot_path) else: getter, attribute = _get_target(dot_path) module_or_method = getattr(getter(), attribute) if isinstance(module_or_method, types.UnboundMethodType): klass = getter() module_or_method = klass deps = find_dependencies(inspect.getmodule(starting_with)) for depth, dependencies in deps.items(): for dependency in dependencies: module, name, object = dependency if object == module_or_method: if klass: filtered.append((module, name, (klass, attribute))) else: filtered.append((module, name, object)) return filtered