# Path: src/gwf/utils.py
# class PersistableDict(UserDict):
#     """A dictionary which can persist itself to JSON."""
# 
#     def __init__(self, path):
#         super().__init__()
# 
#         self.path = path
#         try:
#             with open(self.path) as fileobj:
#                 self.data.update(json.load(fileobj))
#         except (OSError, ValueError):
#             # Catch ValueError for compatibility with Python 3.4.2. I haven't been
#             # able to figure out what is different between 3.4.2 and 3.5 that
#             # causes this. Essentially, 3.4.2 raises a ValueError saying that it
#             # cannot parse the empty string instead of raising an OSError
#             # (FileNotFoundError does not exist in 3.4.2) saying that the file does
#             # not exist.
#             pass
# 
#     def persist(self):
#         with open(self.path + ".new", "w") as fileobj:
#             json.dump(self.data, fileobj)
#             fileobj.flush()
#             os.fsync(fileobj.fileno())
#             fileobj.close()
#         os.rename(self.path + ".new", self.path)
# 
# def retry(on_exc, max_retries=3, callback=None):
#     """Retry a function with exponentially increasing delay.
# 
#     This will retry the decorated function up to `max_retries` times. A retry
#     will only be attempted if the exception raised by the wrapped function is
#     in `on_exc`.
# 
#     If `callback(retries, delay)` is given, it must be a callable the number of
#     retries so far as the first argument and the current delay as the second
#     argument. Its return value is ignored.
#     """
# 
#     def retry_decorator(func):
#         @wraps(func)
#         def func_wrapper(*args, **kwargs):
#             last_exc = None
#             for retries in itertools.count():  # pragma: no cover
#                 if retries >= max_retries:
#                     raise RetryError(func.__name__) from last_exc
# 
#                 try:
#                     return func(*args, **kwargs)
#                 except on_exc as exc:
#                     last_exc = exc
# 
#                     delay = (2 ** retries) // 2
#                     if callback is not None:
#                         callback(retries, delay)
# 
#                     logger.exception(exc)
#                     logger.warning(
#                         "Call to %s failed, retrying in %d seconds.",
#                         func.__name__,
#                         delay,
#                     )
#                     time.sleep(delay)
# 
#         return func_wrapper
# 
#     return retry_decorator
# 
# Path: src/gwf/backends/exceptions.py
# class BackendError(GWFError):
#     pass
# 
# class DependencyError(BackendError):
#     pass
# 
# class TargetError(BackendError):
#     pass


import sys
import logging
    from importlib_metadata import entry_points
    from importlib.metadata import entry_points
from enum import Enum
from ..utils import PersistableDict, retry
from .exceptions import BackendError, DependencyError, TargetError
from .logmanager import FileLogManager
        :param bool stderr:
            default: False. If true, return standard error.
        :return:
            A file-like object. The user is responsible for closing the
            returned file(s) after use.
        :raises gwf.exceptions.NoLogFoundError:
            if the backend could not find a log for the given target.
        """
        if stderr:
            return cls.log_manager.open_stderr(target)
        return cls.log_manager.open_stdout(target)

    def close(self):
        """Close the backend.

        Called when the backend is no longer needed and should close all
        resources (open files, connections) used by the backend.
        """


class PbsLikeBackendBase(Backend):
    """PBS-like backend base class."""

    option_flags = {}
    option_defaults = {}
    log_manager = FileLogManager()

    def __init__(self):
        try:
            self._status = self.parse_queue_output(self.call_queue_command())

# Path: src/gwf/utils.py
# class PersistableDict(UserDict):
#     """A dictionary which can persist itself to JSON."""
# 
#     def __init__(self, path):
#         super().__init__()
# 
#         self.path = path
#         try:
#             with open(self.path) as fileobj:
#                 self.data.update(json.load(fileobj))
#         except (OSError, ValueError):
#             # Catch ValueError for compatibility with Python 3.4.2. I haven't been
#             # able to figure out what is different between 3.4.2 and 3.5 that
#             # causes this. Essentially, 3.4.2 raises a ValueError saying that it
#             # cannot parse the empty string instead of raising an OSError
#             # (FileNotFoundError does not exist in 3.4.2) saying that the file does
#             # not exist.
#             pass
# 
#     def persist(self):
#         with open(self.path + ".new", "w") as fileobj:
#             json.dump(self.data, fileobj)
#             fileobj.flush()
#             os.fsync(fileobj.fileno())
#             fileobj.close()
#         os.rename(self.path + ".new", self.path)
# 
# def retry(on_exc, max_retries=3, callback=None):
#     """Retry a function with exponentially increasing delay.
# 
#     This will retry the decorated function up to `max_retries` times. A retry
#     will only be attempted if the exception raised by the wrapped function is
#     in `on_exc`.
# 
#     If `callback(retries, delay)` is given, it must be a callable the number of
#     retries so far as the first argument and the current delay as the second
#     argument. Its return value is ignored.
#     """
# 
#     def retry_decorator(func):
#         @wraps(func)
#         def func_wrapper(*args, **kwargs):
#             last_exc = None
#             for retries in itertools.count():  # pragma: no cover
#                 if retries >= max_retries:
#                     raise RetryError(func.__name__) from last_exc
# 
#                 try:
#                     return func(*args, **kwargs)
#                 except on_exc as exc:
#                     last_exc = exc
# 
#                     delay = (2 ** retries) // 2
#                     if callback is not None:
#                         callback(retries, delay)
# 
#                     logger.exception(exc)
#                     logger.warning(
#                         "Call to %s failed, retrying in %d seconds.",
#                         func.__name__,
#                         delay,
#                     )
#                     time.sleep(delay)
# 
#         return func_wrapper
# 
#     return retry_decorator
# 
# Path: src/gwf/backends/exceptions.py
# class BackendError(GWFError):
#     pass
# 
# class DependencyError(BackendError):
#     pass
# 
# class TargetError(BackendError):
#     pass


# Path: src/gwf/backends/base.py
import sys
import logging
    from importlib_metadata import entry_points
    from importlib.metadata import entry_points
from enum import Enum
from ..utils import PersistableDict, retry
from .exceptions import BackendError, DependencyError, TargetError
from .logmanager import FileLogManager

        :param bool stderr:
            default: False. If true, return standard error.
        :return:
            A file-like object. The user is responsible for closing the
            returned file(s) after use.
        :raises gwf.exceptions.NoLogFoundError:
            if the backend could not find a log for the given target.
        """
        if stderr:
            return cls.log_manager.open_stderr(target)
        return cls.log_manager.open_stdout(target)

    def close(self):
        """Close the backend.

        Called when the backend is no longer needed and should close all
        resources (open files, connections) used by the backend.
        """


class PbsLikeBackendBase(Backend):
    """PBS-like backend base class."""

    option_flags = {}
    option_defaults = {}
    log_manager = FileLogManager()

    def __init__(self):
        try:
            self._status = self.parse_queue_output(self.call_queue_command())

        except retry.RetryError as exc: