Return out of date file and detail to run job.

def _out_of_date(func, *args, **kwargs):
    """Return out of date file and detail to run job."""
    storage_directory = os.path.join(tempfile.gettempdir(), "jobstamps")
    stamp_input = "".join([func.__name__] +
                          [repr(v) for v in args] +
                          [repr(kwargs[k])
                           for k in sorted(kwargs.keys())]).encode("utf-8")

    dependencies = kwargs.pop("jobstamps_dependencies", None) or list()
    expected_output_files = (kwargs.pop("jobstamps_output_files", None) or
                             list())
    cache_output_directory = kwargs.pop("jobstamps_cache_output_directory",
                                        None) or storage_directory
    method_class = _determine_method(kwargs.pop("jobstamps_method", None))

    stamp_file_name = os.path.join(cache_output_directory,
                                   hashlib.md5(stamp_input).hexdigest())

    detail = _OutOfDateActionDetail(stamp=stamp_file_name,
                                    dependencies=dependencies,
                                    method=method_class(stamp_file_name),
                                    kwargs=kwargs)

    if os.environ.get("JOBSTAMPS_DISABLED", None):
        return "JOBSTAMPS_DISABLED", detail

    _safe_mkdir(cache_output_directory)

    if not os.path.isdir(cache_output_directory):
        raise IOError("""{} exists and is """
                      """not a directory.""".format(cache_output_directory))

    if not os.path.exists(stamp_file_name):
        return stamp_file_name, detail

    for expected_output_file in expected_output_files:
        if not os.path.exists(expected_output_file):
            return expected_output_file, detail

    for dependency in dependencies:
        if (not os.path.exists(dependency) or
                not detail.method.check_dependency(dependency)):
            return dependency, detail

    return None, detail