def _apply_patch(source, patch_text, forwards, name):
    # Cached ?
    try:
        return _patching_cache.retrieve(source, patch_text, forwards)
    except __HOLE__:
        pass

    # Write out files
    tempdir = mkdtemp(prefix='patchy')
    try:
        source_path = os.path.join(tempdir, name + '.py')
        with open(source_path, 'w') as source_file:
            source_file.write(source)

        patch_path = os.path.join(tempdir, name + '.patch')
        with open(patch_path, 'w') as patch_file:
            patch_file.write(patch_text)
            if not patch_text.endswith('\n'):
                patch_file.write('\n')

        # Call `patch` command
        command = ['patch']
        if not forwards:
            command.append('--reverse')
        command.extend([source_path, patch_path])
        proc = subprocess.Popen(
            command,
            stderr=subprocess.PIPE,
            stdout=subprocess.PIPE
        )
        stdout, stderr = proc.communicate()

        if proc.returncode != 0:
            msg = "Could not {action} the patch {prep} '{name}'.".format(
                action=("apply" if forwards else "unapply"),
                prep=("to" if forwards else "from"),
                name=name
            )
            if stdout or stderr:
                msg += " The message from `patch` was:\n{}\n{}".format(
                    stdout.decode('utf-8'),
                    stderr.decode('utf-8')
                )
            msg += (
                "\nThe code to patch was:\n{}\nThe patch was:\n{}"
                .format(source, patch_text)
            )
            raise ValueError(msg)

        with open(source_path, 'r') as source_file:
            new_source = source_file.read()
    finally:
        shutil.rmtree(tempdir)

    _patching_cache.store(source, patch_text, forwards, new_source)

    return new_source
dataset/ETHPy150Open adamchainz/patchy/patchy/api.py/_apply_patch