# Path: src/gwf/backends/base.py
# class Status(Enum):
#     """Status of a target.
# 
#     A target is unknown to the backend if it has not been submitted or the
#     target has completed and thus isn't being tracked anymore by the backend.
# 
#     A target is submitted if it has been successfully submitted to the backend
#     and is pending execution.
# 
#     A target is running if it is currently being executed by the backend.
#     """
# 
#     UNKNOWN = 0
#     SUBMITTED = 1
#     RUNNING = 2
# 
# Path: src/gwf/utils.py
# def cache(obj):
#     _cache = obj._cache = {}
# 
#     @functools.wraps(obj)
#     def memoizer(*args, **kwargs):
#         if args not in _cache:
#             _cache[args] = obj(*args, **kwargs)
#         return _cache[args]
# 
#     return memoizer
# 
# def is_valid_name(candidate):
#     """Check whether `candidate` is a valid name for a target or workflow."""
#     return re.match(r"^[a-zA-Z_][a-zA-Z0-9._]*$", candidate) is not None
# 
# class timer(ContextDecorator):
#     def __init__(self, msg, logger=None):
#         self.msg = msg
#         self.logger = logger or logging.getLogger(__name__)
# 
#     def __enter__(self):
#         self.start = time.perf_counter()
#         return self
# 
#     def __exit__(self, *args):
#         self.end = time.perf_counter()
#         self.duration = self.end - self.start
#         self.logger.debug(self.msg, self.duration)


import collections
import logging
import os
import os.path
import unicodedata
from collections import defaultdict
from enum import Enum
from .backends import Status
from .compat import fspath
from .exceptions import NameError, WorkflowError
from .utils import cache, is_valid_name, timer
    """Schedule one or more targets.

    Scheduling a target will determine whether the target needs to run.

    When scheduling a target, the scheduler checks whether any of its inputs
    are unresolved, meaning that during construction of the graph, no other
    target providing the file was found. This means that the file should then
    exist on disk. If it doesn't the following exception is raised:

    :raises gwf.exceptions.WorkflowError:
        Raised if a target has an input file that does not exist on the file
        system and that is not provided by another target.

    Returns a tuple `(scheduled, reasons)` where `scheduled` is a map from
    a target to its scheduled direct dependencies, and `reasons` is a map from
    a target to a string describing why (or why not) the target was scheduled.
    """
    return Scheduler(filesystem=filesystem).schedule(targets, graph)


def get_status(target, scheduled, backend):
    """Return the status of a target.

    Returns the status of a target where it is taken into account whether
    the target should run or not.

    :param Target target:
        The target to return status for.
    """
    status = backend.status(target)

# Path: src/gwf/backends/base.py
# class Status(Enum):
#     """Status of a target.
# 
#     A target is unknown to the backend if it has not been submitted or the
#     target has completed and thus isn't being tracked anymore by the backend.
# 
#     A target is submitted if it has been successfully submitted to the backend
#     and is pending execution.
# 
#     A target is running if it is currently being executed by the backend.
#     """
# 
#     UNKNOWN = 0
#     SUBMITTED = 1
#     RUNNING = 2
# 
# Path: src/gwf/utils.py
# def cache(obj):
#     _cache = obj._cache = {}
# 
#     @functools.wraps(obj)
#     def memoizer(*args, **kwargs):
#         if args not in _cache:
#             _cache[args] = obj(*args, **kwargs)
#         return _cache[args]
# 
#     return memoizer
# 
# def is_valid_name(candidate):
#     """Check whether `candidate` is a valid name for a target or workflow."""
#     return re.match(r"^[a-zA-Z_][a-zA-Z0-9._]*$", candidate) is not None
# 
# class timer(ContextDecorator):
#     def __init__(self, msg, logger=None):
#         self.msg = msg
#         self.logger = logger or logging.getLogger(__name__)
# 
#     def __enter__(self):
#         self.start = time.perf_counter()
#         return self
# 
#     def __exit__(self, *args):
#         self.end = time.perf_counter()
#         self.duration = self.end - self.start
#         self.logger.debug(self.msg, self.duration)


# Path: src/gwf/core.py
import collections
import logging
import os
import os.path
import unicodedata
from collections import defaultdict
from enum import Enum
from .backends import Status
from .compat import fspath
from .exceptions import NameError, WorkflowError
from .utils import cache, is_valid_name, timer

    """Schedule one or more targets.

    Scheduling a target will determine whether the target needs to run.

    When scheduling a target, the scheduler checks whether any of its inputs
    are unresolved, meaning that during construction of the graph, no other
    target providing the file was found. This means that the file should then
    exist on disk. If it doesn't the following exception is raised:

    :raises gwf.exceptions.WorkflowError:
        Raised if a target has an input file that does not exist on the file
        system and that is not provided by another target.

    Returns a tuple `(scheduled, reasons)` where `scheduled` is a map from
    a target to its scheduled direct dependencies, and `reasons` is a map from
    a target to a string describing why (or why not) the target was scheduled.
    """
    return Scheduler(filesystem=filesystem).schedule(targets, graph)


def get_status(target, scheduled, backend):
    """Return the status of a target.

    Returns the status of a target where it is taken into account whether
    the target should run or not.

    :param Target target:
        The target to return status for.
    """
    status = backend.status(target)

    if status == Status.UNKNOWN: