prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Provider base and cluster provider to be added to reference
  **Is your feature request related to a problem? Please describe.**
  
  In the last set of doc updates where we trimmed some of the developer docs we've moved to relying more on the references to point someone to. It looks like the [provider base](https://github.com/Parsl/parsl/blob/master/parsl/providers/provider_base.py) class and [cluster provider](https://github.com/Parsl/parsl/blob/master/parsl/providers/cluster_provider.py) are missing from there. 
  
  **Describe the solution you'd like**
  Update docs to add these to the reference.
  
  Provider base and cluster provider to be added to reference
  **Is your feature request related to a problem? Please describe.**
  
  In the last set of doc updates where we trimmed some of the developer docs we've moved to relying more on the references to point someone to. It looks like the [provider base](https://github.com/Parsl/parsl/blob/master/parsl/providers/provider_base.py) class and [cluster provider](https://github.com/Parsl/parsl/blob/master/parsl/providers/cluster_provider.py) are missing from there. 
  
  **Describe the solution you'd like**
  Update docs to add these to the reference.
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `parsl/providers/cluster_provider.py`
  Content:
  ```
  1 import logging
  2 from abc import abstractmethod
  3 from string import Template
  4 
  5 from parsl.providers.error import SchedulerMissingArgs, ScriptPathError
  6 from parsl.launchers.error import BadLauncher
  7 from parsl.providers.provider_base import ExecutionProvider
  8 
  9 logger = logging.getLogger(__name__)
  10 
  11 
  12 class ClusterProvider(ExecutionProvider):
  13     """ This class defines behavior common to all cluster/supercompute-style scheduler systems.
  14 
  15     Parameters
  16     ----------
  17     label : str
  18         Label for this provider.
  19     channel : Channel
  20         Channel for accessing this provider. Possible channels include
  21         :class:`~parsl.channels.LocalChannel` (the default),
  22         :class:`~parsl.channels.SSHChannel`, or
  23         :class:`~parsl.channels.SSHInteractiveLoginChannel`.
  24     walltime : str
  25         Walltime requested per block in HH:MM:SS.
  26     launcher : str
  27         FIXME
  28     cmd_timeout : int
  29         Timeout for commands made to the scheduler in seconds
  30 
  31     .. code:: python
  32 
  33                                 +------------------
  34                                 |
  35           script_string ------->|  submit
  36                id      <--------|---+
  37                                 |
  38           [ ids ]       ------->|  status
  39           [statuses]   <--------|----+
  40                                 |
  41           [ ids ]       ------->|  cancel
  42           [cancel]     <--------|----+
  43                                 |
  44                                 +-------------------
  45     """
  46 
  47     def __init__(self,
  48                  label,
  49                  channel,
  50                  nodes_per_block,
  51                  init_blocks,
  52                  min_blocks,
  53                  max_blocks,
  54                  parallelism,
  55                  walltime,
  56                  launcher,
  57                  cmd_timeout=10):
  58 
  59         self._label = label
  60         self.channel = channel
  61         self.nodes_per_block = nodes_per_block
  62         self.init_blocks = init_blocks
  63         self.min_blocks = min_blocks
  64         self.max_blocks = max_blocks
  65         self.parallelism = parallelism
  66         self.launcher = launcher
  67         self.walltime = walltime
  68         self.cmd_timeout = cmd_timeout
  69         if not callable(self.launcher):
  70             raise(BadLauncher(self.launcher,
  71                               "Launcher for executor: {} is of type: {}. Expects a parsl.launcher.launcher.Launcher or callable".format(
  72                                   label, type(self.launcher))))
  73 
  74         self.script_dir = None
  75 
  76         # Dictionary that keeps track of jobs, keyed on job_id
  77         self.resources = {}
  78 
  79     def execute_wait(self, cmd, timeout=None):
  80         t = self.cmd_timeout
  81         if timeout is not None:
  82             t = timeout
  83         return self.channel.execute_wait(cmd, t)
  84 
  85     def _write_submit_script(self, template, script_filename, job_name, configs):
  86         """Generate submit script and write it to a file.
  87 
  88         Args:
  89               - template (string) : The template string to be used for the writing submit script
  90               - script_filename (string) : Name of the submit script
  91               - job_name (string) : job name
  92               - configs (dict) : configs that get pushed into the template
  93 
  94         Returns:
  95               - True: on success
  96 
  97         Raises:
  98               SchedulerMissingArgs : If template is missing args
  99               ScriptPathError : Unable to write submit script out
  100         """
  101 
  102         try:
  103             submit_script = Template(template).substitute(jobname=job_name, **configs)
  104             # submit_script = Template(template).safe_substitute(jobname=job_name, **configs)
  105             with open(script_filename, 'w') as f:
  106                 f.write(submit_script)
  107 
  108         except KeyError as e:
  109             logger.error("Missing keys for submit script : %s", e)
  110             raise (SchedulerMissingArgs(e.args, self.label))
  111 
  112         except IOError as e:
  113             logger.error("Failed writing to submit script: %s", script_filename)
  114             raise (ScriptPathError(script_filename, e))
  115         except Exception as e:
  116             print("Template : ", template)
  117             print("Args : ", job_name)
  118             print("Kwargs : ", configs)
  119             logger.error("Uncategorized error: %s", e)
  120             raise (e)
  121 
  122         return True
  123 
  124     @abstractmethod
  125     def _status(self):
  126         pass
  127 
  128     def status(self, job_ids):
  129         """ Get the status of a list of jobs identified by the job identifiers
  130         returned from the submit request.
  131 
  132         Args:
  133              - job_ids (list) : A list of job identifiers
  134 
  135         Returns:
  136              - A list of JobStatus objects corresponding to each job_id in the job_ids list.
  137 
  138         Raises:
  139              - ExecutionProviderException or its subclasses
  140 
  141         """
  142         if job_ids:
  143             self._status()
  144         return [self.resources[jid]['status'] for jid in job_ids]
  145 
  146     @property
  147     def label(self):
  148         return self._label
  149
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/parsl/providers/cluster_provider.py b/parsl/providers/cluster_provider.py
  --- a/parsl/providers/cluster_provider.py
  +++ b/parsl/providers/cluster_provider.py
  @@ -14,18 +14,18 @@
   
       Parameters
       ----------
  -    label : str
  +      label : str
           Label for this provider.
  -    channel : Channel
  +      channel : Channel
           Channel for accessing this provider. Possible channels include
           :class:`~parsl.channels.LocalChannel` (the default),
           :class:`~parsl.channels.SSHChannel`, or
           :class:`~parsl.channels.SSHInteractiveLoginChannel`.
  -    walltime : str
  +      walltime : str
           Walltime requested per block in HH:MM:SS.
  -    launcher : str
  +      launcher : str
           FIXME
  -    cmd_timeout : int
  +      cmd_timeout : int
           Timeout for commands made to the scheduler in seconds
   
       .. code:: python
  
verification_info: {"golden_diff": "diff --git a/parsl/providers/cluster_provider.py b/parsl/providers/cluster_provider.py\n--- a/parsl/providers/cluster_provider.py\n+++ b/parsl/providers/cluster_provider.py\n@@ -14,18 +14,18 @@\n \n     Parameters\n     ----------\n-    label : str\n+      label : str\n         Label for this provider.\n-    channel : Channel\n+      channel : Channel\n         Channel for accessing this provider. Possible channels include\n         :class:`~parsl.channels.LocalChannel` (the default),\n         :class:`~parsl.channels.SSHChannel`, or\n         :class:`~parsl.channels.SSHInteractiveLoginChannel`.\n-    walltime : str\n+      walltime : str\n         Walltime requested per block in HH:MM:SS.\n-    launcher : str\n+      launcher : str\n         FIXME\n-    cmd_timeout : int\n+      cmd_timeout : int\n         Timeout for commands made to the scheduler in seconds\n \n     .. code:: python\n", "issue": "Provider base and cluster provider to be added to reference\n**Is your feature request related to a problem? Please describe.**\r\n\r\nIn the last set of doc updates where we trimmed some of the developer docs we've moved to relying more on the references to point someone to. It looks like the [provider base](https://github.com/Parsl/parsl/blob/master/parsl/providers/provider_base.py) class and [cluster provider](https://github.com/Parsl/parsl/blob/master/parsl/providers/cluster_provider.py) are missing from there. \r\n\r\n**Describe the solution you'd like**\r\nUpdate docs to add these to the reference.\r\n\nProvider base and cluster provider to be added to reference\n**Is your feature request related to a problem? Please describe.**\r\n\r\nIn the last set of doc updates where we trimmed some of the developer docs we've moved to relying more on the references to point someone to. It looks like the [provider base](https://github.com/Parsl/parsl/blob/master/parsl/providers/provider_base.py) class and [cluster provider](https://github.com/Parsl/parsl/blob/master/parsl/providers/cluster_provider.py) are missing from there. \r\n\r\n**Describe the solution you'd like**\r\nUpdate docs to add these to the reference.\r\n\n", "before_files": [{"content": "import logging\nfrom abc import abstractmethod\nfrom string import Template\n\nfrom parsl.providers.error import SchedulerMissingArgs, ScriptPathError\nfrom parsl.launchers.error import BadLauncher\nfrom parsl.providers.provider_base import ExecutionProvider\n\nlogger = logging.getLogger(__name__)\n\n\nclass ClusterProvider(ExecutionProvider):\n    \"\"\" This class defines behavior common to all cluster/supercompute-style scheduler systems.\n\n    Parameters\n    ----------\n    label : str\n        Label for this provider.\n    channel : Channel\n        Channel for accessing this provider. Possible channels include\n        :class:`~parsl.channels.LocalChannel` (the default),\n        :class:`~parsl.channels.SSHChannel`, or\n        :class:`~parsl.channels.SSHInteractiveLoginChannel`.\n    walltime : str\n        Walltime requested per block in HH:MM:SS.\n    launcher : str\n        FIXME\n    cmd_timeout : int\n        Timeout for commands made to the scheduler in seconds\n\n    .. code:: python\n\n                                +------------------\n                                |\n          script_string ------->|  submit\n               id      <--------|---+\n                                |\n          [ ids ]       ------->|  status\n          [statuses]   <--------|----+\n                                |\n          [ ids ]       ------->|  cancel\n          [cancel]     <--------|----+\n                                |\n                                +-------------------\n    \"\"\"\n\n    def __init__(self,\n                 label,\n                 channel,\n                 nodes_per_block,\n                 init_blocks,\n                 min_blocks,\n                 max_blocks,\n                 parallelism,\n                 walltime,\n                 launcher,\n                 cmd_timeout=10):\n\n        self._label = label\n        self.channel = channel\n        self.nodes_per_block = nodes_per_block\n        self.init_blocks = init_blocks\n        self.min_blocks = min_blocks\n        self.max_blocks = max_blocks\n        self.parallelism = parallelism\n        self.launcher = launcher\n        self.walltime = walltime\n        self.cmd_timeout = cmd_timeout\n        if not callable(self.launcher):\n            raise(BadLauncher(self.launcher,\n                              \"Launcher for executor: {} is of type: {}. Expects a parsl.launcher.launcher.Launcher or callable\".format(\n                                  label, type(self.launcher))))\n\n        self.script_dir = None\n\n        # Dictionary that keeps track of jobs, keyed on job_id\n        self.resources = {}\n\n    def execute_wait(self, cmd, timeout=None):\n        t = self.cmd_timeout\n        if timeout is not None:\n            t = timeout\n        return self.channel.execute_wait(cmd, t)\n\n    def _write_submit_script(self, template, script_filename, job_name, configs):\n        \"\"\"Generate submit script and write it to a file.\n\n        Args:\n              - template (string) : The template string to be used for the writing submit script\n              - script_filename (string) : Name of the submit script\n              - job_name (string) : job name\n              - configs (dict) : configs that get pushed into the template\n\n        Returns:\n              - True: on success\n\n        Raises:\n              SchedulerMissingArgs : If template is missing args\n              ScriptPathError : Unable to write submit script out\n        \"\"\"\n\n        try:\n            submit_script = Template(template).substitute(jobname=job_name, **configs)\n            # submit_script = Template(template).safe_substitute(jobname=job_name, **configs)\n            with open(script_filename, 'w') as f:\n                f.write(submit_script)\n\n        except KeyError as e:\n            logger.error(\"Missing keys for submit script : %s\", e)\n            raise (SchedulerMissingArgs(e.args, self.label))\n\n        except IOError as e:\n            logger.error(\"Failed writing to submit script: %s\", script_filename)\n            raise (ScriptPathError(script_filename, e))\n        except Exception as e:\n            print(\"Template : \", template)\n            print(\"Args : \", job_name)\n            print(\"Kwargs : \", configs)\n            logger.error(\"Uncategorized error: %s\", e)\n            raise (e)\n\n        return True\n\n    @abstractmethod\n    def _status(self):\n        pass\n\n    def status(self, job_ids):\n        \"\"\" Get the status of a list of jobs identified by the job identifiers\n        returned from the submit request.\n\n        Args:\n             - job_ids (list) : A list of job identifiers\n\n        Returns:\n             - A list of JobStatus objects corresponding to each job_id in the job_ids list.\n\n        Raises:\n             - ExecutionProviderException or its subclasses\n\n        \"\"\"\n        if job_ids:\n            self._status()\n        return [self.resources[jid]['status'] for jid in job_ids]\n\n    @property\n    def label(self):\n        return self._label\n", "path": "parsl/providers/cluster_provider.py"}], "after_files": [{"content": "import logging\nfrom abc import abstractmethod\nfrom string import Template\n\nfrom parsl.providers.error import SchedulerMissingArgs, ScriptPathError\nfrom parsl.launchers.error import BadLauncher\nfrom parsl.providers.provider_base import ExecutionProvider\n\nlogger = logging.getLogger(__name__)\n\n\nclass ClusterProvider(ExecutionProvider):\n    \"\"\" This class defines behavior common to all cluster/supercompute-style scheduler systems.\n\n    Parameters\n    ----------\n      label : str\n        Label for this provider.\n      channel : Channel\n        Channel for accessing this provider. Possible channels include\n        :class:`~parsl.channels.LocalChannel` (the default),\n        :class:`~parsl.channels.SSHChannel`, or\n        :class:`~parsl.channels.SSHInteractiveLoginChannel`.\n      walltime : str\n        Walltime requested per block in HH:MM:SS.\n      launcher : str\n        FIXME\n      cmd_timeout : int\n        Timeout for commands made to the scheduler in seconds\n\n    .. code:: python\n\n                                +------------------\n                                |\n          script_string ------->|  submit\n               id      <--------|---+\n                                |\n          [ ids ]       ------->|  status\n          [statuses]   <--------|----+\n                                |\n          [ ids ]       ------->|  cancel\n          [cancel]     <--------|----+\n                                |\n                                +-------------------\n    \"\"\"\n\n    def __init__(self,\n                 label,\n                 channel,\n                 nodes_per_block,\n                 init_blocks,\n                 min_blocks,\n                 max_blocks,\n                 parallelism,\n                 walltime,\n                 launcher,\n                 cmd_timeout=10):\n\n        self._label = label\n        self.channel = channel\n        self.nodes_per_block = nodes_per_block\n        self.init_blocks = init_blocks\n        self.min_blocks = min_blocks\n        self.max_blocks = max_blocks\n        self.parallelism = parallelism\n        self.launcher = launcher\n        self.walltime = walltime\n        self.cmd_timeout = cmd_timeout\n        if not callable(self.launcher):\n            raise(BadLauncher(self.launcher,\n                              \"Launcher for executor: {} is of type: {}. Expects a parsl.launcher.launcher.Launcher or callable\".format(\n                                  label, type(self.launcher))))\n\n        self.script_dir = None\n\n        # Dictionary that keeps track of jobs, keyed on job_id\n        self.resources = {}\n\n    def execute_wait(self, cmd, timeout=None):\n        t = self.cmd_timeout\n        if timeout is not None:\n            t = timeout\n        return self.channel.execute_wait(cmd, t)\n\n    def _write_submit_script(self, template, script_filename, job_name, configs):\n        \"\"\"Generate submit script and write it to a file.\n\n        Args:\n              - template (string) : The template string to be used for the writing submit script\n              - script_filename (string) : Name of the submit script\n              - job_name (string) : job name\n              - configs (dict) : configs that get pushed into the template\n\n        Returns:\n              - True: on success\n\n        Raises:\n              SchedulerMissingArgs : If template is missing args\n              ScriptPathError : Unable to write submit script out\n        \"\"\"\n\n        try:\n            submit_script = Template(template).substitute(jobname=job_name, **configs)\n            # submit_script = Template(template).safe_substitute(jobname=job_name, **configs)\n            with open(script_filename, 'w') as f:\n                f.write(submit_script)\n\n        except KeyError as e:\n            logger.error(\"Missing keys for submit script : %s\", e)\n            raise (SchedulerMissingArgs(e.args, self.label))\n\n        except IOError as e:\n            logger.error(\"Failed writing to submit script: %s\", script_filename)\n            raise (ScriptPathError(script_filename, e))\n        except Exception as e:\n            print(\"Template : \", template)\n            print(\"Args : \", job_name)\n            print(\"Kwargs : \", configs)\n            logger.error(\"Uncategorized error: %s\", e)\n            raise (e)\n\n        return True\n\n    @abstractmethod\n    def _status(self):\n        pass\n\n    def status(self, job_ids):\n        \"\"\" Get the status of a list of jobs identified by the job identifiers\n        returned from the submit request.\n\n        Args:\n             - job_ids (list) : A list of job identifiers\n\n        Returns:\n             - A list of JobStatus objects corresponding to each job_id in the job_ids list.\n\n        Raises:\n             - ExecutionProviderException or its subclasses\n\n        \"\"\"\n        if job_ids:\n            self._status()\n        return [self.resources[jid]['status'] for jid in job_ids]\n\n    @property\n    def label(self):\n        return self._label\n", "path": "parsl/providers/cluster_provider.py"}]}