We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
slurm mandatory `partition` and non-mandatory `qos` are not always mandatory and non-mandatory. 
See Parsl/libsubmit#66

--- 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/slurm/slurm.py`
Content:
```
1 import os
2 import math
3 import time
4 import logging
5 import typeguard
6 
7 from typing import Optional
8 
9 from parsl.channels import LocalChannel
10 from parsl.channels.base import Channel
11 from parsl.launchers import SingleNodeLauncher
12 from parsl.launchers.launchers import Launcher
13 from parsl.providers.cluster_provider import ClusterProvider
14 from parsl.providers.provider_base import JobState, JobStatus
15 from parsl.providers.slurm.template import template_string
16 from parsl.utils import RepresentationMixin, wtime_to_minutes
17 
18 logger = logging.getLogger(__name__)
19 
20 translate_table = {
21     'PD': JobState.PENDING,
22     'R': JobState.RUNNING,
23     'CA': JobState.CANCELLED,
24     'CF': JobState.PENDING,  # (configuring),
25     'CG': JobState.RUNNING,  # (completing),
26     'CD': JobState.COMPLETED,
27     'F': JobState.FAILED,  # (failed),
28     'TO': JobState.TIMEOUT,  # (timeout),
29     'NF': JobState.FAILED,  # (node failure),
30     'RV': JobState.FAILED,  # (revoked) and
31     'SE': JobState.FAILED
32 }  # (special exit state
33 
34 
35 class SlurmProvider(ClusterProvider, RepresentationMixin):
36     """Slurm Execution Provider
37 
38     This provider uses sbatch to submit, squeue for status and scancel to cancel
39     jobs. The sbatch script to be used is created from a template file in this
40     same module.
41 
42     Parameters
43     ----------
44     partition : str
45         Slurm partition to request blocks from.
46     channel : Channel
47         Channel for accessing this provider. Possible channels include
48         :class:`~parsl.channels.LocalChannel` (the default),
49         :class:`~parsl.channels.SSHChannel`, or
50         :class:`~parsl.channels.SSHInteractiveLoginChannel`.
51     nodes_per_block : int
52         Nodes to provision per block.
53     cores_per_node : int
54         Specify the number of cores to provision per node. If set to None, executors
55         will assume all cores on the node are available for computation. Default is None.
56     mem_per_node : int
57         Specify the real memory to provision per node in GB. If set to None, no
58         explicit request to the scheduler will be made. Default is None.
59     min_blocks : int
60         Minimum number of blocks to maintain.
61     max_blocks : int
62         Maximum number of blocks to maintain.
63     parallelism : float
64         Ratio of provisioned task slots to active tasks. A parallelism value of 1 represents aggressive
65         scaling where as many resources as possible are used; parallelism close to 0 represents
66         the opposite situation in which as few resources as possible (i.e., min_blocks) are used.
67     walltime : str
68         Walltime requested per block in HH:MM:SS.
69     scheduler_options : str
70         String to prepend to the #SBATCH blocks in the submit script to the scheduler.
71     worker_init : str
72         Command to be run before starting a worker, such as 'module load Anaconda; source activate env'.
73     exclusive : bool (Default = True)
74         Requests nodes which are not shared with other running jobs.
75     launcher : Launcher
76         Launcher for this provider. Possible launchers include
77         :class:`~parsl.launchers.SingleNodeLauncher` (the default),
78         :class:`~parsl.launchers.SrunLauncher`, or
79         :class:`~parsl.launchers.AprunLauncher`
80      move_files : Optional[Bool]: should files be moved? by default, Parsl will try to move files.
81     """
82 
83     @typeguard.typechecked
84     def __init__(self,
85                  partition: str,
86                  channel: Channel = LocalChannel(),
87                  nodes_per_block: int = 1,
88                  cores_per_node: Optional[int] = None,
89                  mem_per_node: Optional[int] = None,
90                  init_blocks: int = 1,
91                  min_blocks: int = 0,
92                  max_blocks: int = 10,
93                  parallelism: float = 1,
94                  walltime: str = "00:10:00",
95                  scheduler_options: str = '',
96                  worker_init: str = '',
97                  cmd_timeout: int = 10,
98                  exclusive: bool = True,
99                  move_files: bool = True,
100                  launcher: Launcher = SingleNodeLauncher()):
101         label = 'slurm'
102         super().__init__(label,
103                          channel,
104                          nodes_per_block,
105                          init_blocks,
106                          min_blocks,
107                          max_blocks,
108                          parallelism,
109                          walltime,
110                          cmd_timeout=cmd_timeout,
111                          launcher=launcher)
112 
113         self.partition = partition
114         self.cores_per_node = cores_per_node
115         self.mem_per_node = mem_per_node
116         self.exclusive = exclusive
117         self.move_files = move_files
118         self.scheduler_options = scheduler_options + '\n'
119         if exclusive:
120             self.scheduler_options += "#SBATCH --exclusive\n"
121         self.worker_init = worker_init + '\n'
122 
123     def _status(self):
124         ''' Internal: Do not call. Returns the status list for a list of job_ids
125 
126         Args:
127               self
128 
129         Returns:
130               [status...] : Status list of all jobs
131         '''
132         job_id_list = ','.join(self.resources.keys())
133         cmd = "squeue --job {0}".format(job_id_list)
134 
135         retcode, stdout, stderr = self.execute_wait(cmd)
136 
137         # Execute_wait failed. Do no update
138         if retcode != 0:
139             return
140 
141         jobs_missing = list(self.resources.keys())
142         for line in stdout.split('\n'):
143             parts = line.split()
144             if parts and parts[0] != 'JOBID':
145                 job_id = parts[0]
146                 status = translate_table.get(parts[4], JobState.UNKNOWN)
147                 self.resources[job_id]['status'] = JobStatus(status)
148                 jobs_missing.remove(job_id)
149 
150         # squeue does not report on jobs that are not running. So we are filling in the
151         # blanks for missing jobs, we might lose some information about why the jobs failed.
152         for missing_job in jobs_missing:
153             self.resources[missing_job]['status'] = JobStatus(JobState.COMPLETED)
154 
155     def submit(self, command, tasks_per_node, job_name="parsl.slurm"):
156         """Submit the command as a slurm job.
157 
158         Parameters
159         ----------
160         command : str
161             Command to be made on the remote side.
162         tasks_per_node : int
163             Command invocations to be launched per node
164         job_name : str
165             Name for the job (must be unique).
166         Returns
167         -------
168         None or str
169             If at capacity, returns None; otherwise, a string identifier for the job
170         """
171 
172         if self.provisioned_blocks >= self.max_blocks:
173             logger.warning("Slurm provider '{}' is at capacity (no more blocks will be added)".format(self.label))
174             return None
175 
176         scheduler_options = self.scheduler_options
177         worker_init = self.worker_init
178         if self.mem_per_node is not None:
179             scheduler_options += '#SBATCH --mem={}g\n'.format(self.mem_per_node)
180             worker_init += 'export PARSL_MEMORY_GB={}\n'.format(self.mem_per_node)
181         if self.cores_per_node is not None:
182             cpus_per_task = math.floor(self.cores_per_node / tasks_per_node)
183             scheduler_options += '#SBATCH --cpus-per-task={}'.format(cpus_per_task)
184             worker_init += 'export PARSL_CORES={}\n'.format(cpus_per_task)
185 
186         job_name = "{0}.{1}".format(job_name, time.time())
187 
188         script_path = "{0}/{1}.submit".format(self.script_dir, job_name)
189         script_path = os.path.abspath(script_path)
190 
191         logger.debug("Requesting one block with {} nodes".format(self.nodes_per_block))
192 
193         job_config = {}
194         job_config["submit_script_dir"] = self.channel.script_dir
195         job_config["nodes"] = self.nodes_per_block
196         job_config["tasks_per_node"] = tasks_per_node
197         job_config["walltime"] = wtime_to_minutes(self.walltime)
198         job_config["scheduler_options"] = scheduler_options
199         job_config["worker_init"] = worker_init
200         job_config["partition"] = self.partition
201         job_config["user_script"] = command
202 
203         # Wrap the command
204         job_config["user_script"] = self.launcher(command,
205                                                   tasks_per_node,
206                                                   self.nodes_per_block)
207 
208         logger.debug("Writing submit script")
209         self._write_submit_script(template_string, script_path, job_name, job_config)
210 
211         if self.move_files:
212             logger.debug("moving files")
213             channel_script_path = self.channel.push_file(script_path, self.channel.script_dir)
214         else:
215             logger.debug("not moving files")
216             channel_script_path = script_path
217 
218         retcode, stdout, stderr = self.execute_wait("sbatch {0}".format(channel_script_path))
219 
220         job_id = None
221         if retcode == 0:
222             for line in stdout.split('\n'):
223                 if line.startswith("Submitted batch job"):
224                     job_id = line.split("Submitted batch job")[1].strip()
225                     self.resources[job_id] = {'job_id': job_id, 'status': JobStatus(JobState.PENDING)}
226         else:
227             print("Submission of command to scale_out failed")
228             logger.error("Retcode:%s STDOUT:%s STDERR:%s", retcode, stdout.strip(), stderr.strip())
229         return job_id
230 
231     def cancel(self, job_ids):
232         ''' Cancels the jobs specified by a list of job ids
233 
234         Args:
235         job_ids : [<job_id> ...]
236 
237         Returns :
238         [True/False...] : If the cancel operation fails the entire list will be False.
239         '''
240 
241         job_id_list = ' '.join(job_ids)
242         retcode, stdout, stderr = self.execute_wait("scancel {0}".format(job_id_list))
243         rets = None
244         if retcode == 0:
245             for jid in job_ids:
246                 self.resources[jid]['status'] = JobStatus(JobState.CANCELLED)  # Setting state to cancelled
247             rets = [True for i in job_ids]
248         else:
249             rets = [False for i in job_ids]
250 
251         return rets
252 
253     def _test_add_resource(self, job_id):
254         self.resources.extend([{'job_id': job_id, 'status': JobStatus(JobState.PENDING), 'size': 1}])
255         return True
256 
257 
258 if __name__ == "__main__":
259 
260     print("None")
261
```

Path: `parsl/providers/slurm/template.py`
Content:
```
1 template_string = '''#!/bin/bash
2 
3 #SBATCH --job-name=${jobname}
4 #SBATCH --output=${submit_script_dir}/${jobname}.submit.stdout
5 #SBATCH --error=${submit_script_dir}/${jobname}.submit.stderr
6 #SBATCH --nodes=${nodes}
7 #SBATCH --partition=${partition}
8 #SBATCH --time=${walltime}
9 #SBATCH --ntasks-per-node=${tasks_per_node}
10 ${scheduler_options}
11 
12 ${worker_init}
13 
14 export JOBNAME="${jobname}"
15 
16 $user_script
17 '''
18
```
--- 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()

```

diff --git a/parsl/providers/slurm/slurm.py b/parsl/providers/slurm/slurm.py
--- a/parsl/providers/slurm/slurm.py
+++ b/parsl/providers/slurm/slurm.py
@@ -42,7 +42,7 @@
     Parameters
     ----------
     partition : str
-        Slurm partition to request blocks from.
+        Slurm partition to request blocks from. If none, no partition slurm directive will be specified.
     channel : Channel
         Channel for accessing this provider. Possible channels include
         :class:`~parsl.channels.LocalChannel` (the default),
@@ -82,7 +82,7 @@
 
     @typeguard.typechecked
     def __init__(self,
-                 partition: str,
+                 partition: Optional[str],
                  channel: Channel = LocalChannel(),
                  nodes_per_block: int = 1,
                  cores_per_node: Optional[int] = None,
@@ -118,6 +118,8 @@
         self.scheduler_options = scheduler_options + '\n'
         if exclusive:
             self.scheduler_options += "#SBATCH --exclusive\n"
+        if partition:
+            self.scheduler_options += "#SBATCH --partition={}\n".format(partition)
         self.worker_init = worker_init + '\n'
 
     def _status(self):
@@ -197,7 +199,6 @@
         job_config["walltime"] = wtime_to_minutes(self.walltime)
         job_config["scheduler_options"] = scheduler_options
         job_config["worker_init"] = worker_init
-        job_config["partition"] = self.partition
         job_config["user_script"] = command
 
         # Wrap the command
diff --git a/parsl/providers/slurm/template.py b/parsl/providers/slurm/template.py
--- a/parsl/providers/slurm/template.py
+++ b/parsl/providers/slurm/template.py
@@ -4,7 +4,6 @@
 #SBATCH --output=${submit_script_dir}/${jobname}.submit.stdout
 #SBATCH --error=${submit_script_dir}/${jobname}.submit.stderr
 #SBATCH --nodes=${nodes}
-#SBATCH --partition=${partition}
 #SBATCH --time=${walltime}
 #SBATCH --ntasks-per-node=${tasks_per_node}
 ${scheduler_options}

{"golden_diff": "diff --git a/parsl/providers/slurm/slurm.py b/parsl/providers/slurm/slurm.py\n--- a/parsl/providers/slurm/slurm.py\n+++ b/parsl/providers/slurm/slurm.py\n@@ -42,7 +42,7 @@\n     Parameters\n     ----------\n     partition : str\n-        Slurm partition to request blocks from.\n+        Slurm partition to request blocks from. If none, no partition slurm directive will be specified.\n     channel : Channel\n         Channel for accessing this provider. Possible channels include\n         :class:`~parsl.channels.LocalChannel` (the default),\n@@ -82,7 +82,7 @@\n \n     @typeguard.typechecked\n     def __init__(self,\n-                 partition: str,\n+                 partition: Optional[str],\n                  channel: Channel = LocalChannel(),\n                  nodes_per_block: int = 1,\n                  cores_per_node: Optional[int] = None,\n@@ -118,6 +118,8 @@\n         self.scheduler_options = scheduler_options + '\\n'\n         if exclusive:\n             self.scheduler_options += \"#SBATCH --exclusive\\n\"\n+        if partition:\n+            self.scheduler_options += \"#SBATCH --partition={}\\n\".format(partition)\n         self.worker_init = worker_init + '\\n'\n \n     def _status(self):\n@@ -197,7 +199,6 @@\n         job_config[\"walltime\"] = wtime_to_minutes(self.walltime)\n         job_config[\"scheduler_options\"] = scheduler_options\n         job_config[\"worker_init\"] = worker_init\n-        job_config[\"partition\"] = self.partition\n         job_config[\"user_script\"] = command\n \n         # Wrap the command\ndiff --git a/parsl/providers/slurm/template.py b/parsl/providers/slurm/template.py\n--- a/parsl/providers/slurm/template.py\n+++ b/parsl/providers/slurm/template.py\n@@ -4,7 +4,6 @@\n #SBATCH --output=${submit_script_dir}/${jobname}.submit.stdout\n #SBATCH --error=${submit_script_dir}/${jobname}.submit.stderr\n #SBATCH --nodes=${nodes}\n-#SBATCH --partition=${partition}\n #SBATCH --time=${walltime}\n #SBATCH --ntasks-per-node=${tasks_per_node}\n ${scheduler_options}\n", "issue": "slurm mandatory `partition` and non-mandatory `qos` are not always mandatory and non-mandatory. \nSee Parsl/libsubmit#66\n", "before_files": [{"content": "import os\nimport math\nimport time\nimport logging\nimport typeguard\n\nfrom typing import Optional\n\nfrom parsl.channels import LocalChannel\nfrom parsl.channels.base import Channel\nfrom parsl.launchers import SingleNodeLauncher\nfrom parsl.launchers.launchers import Launcher\nfrom parsl.providers.cluster_provider import ClusterProvider\nfrom parsl.providers.provider_base import JobState, JobStatus\nfrom parsl.providers.slurm.template import template_string\nfrom parsl.utils import RepresentationMixin, wtime_to_minutes\n\nlogger = logging.getLogger(__name__)\n\ntranslate_table = {\n    'PD': JobState.PENDING,\n    'R': JobState.RUNNING,\n    'CA': JobState.CANCELLED,\n    'CF': JobState.PENDING,  # (configuring),\n    'CG': JobState.RUNNING,  # (completing),\n    'CD': JobState.COMPLETED,\n    'F': JobState.FAILED,  # (failed),\n    'TO': JobState.TIMEOUT,  # (timeout),\n    'NF': JobState.FAILED,  # (node failure),\n    'RV': JobState.FAILED,  # (revoked) and\n    'SE': JobState.FAILED\n}  # (special exit state\n\n\nclass SlurmProvider(ClusterProvider, RepresentationMixin):\n    \"\"\"Slurm Execution Provider\n\n    This provider uses sbatch to submit, squeue for status and scancel to cancel\n    jobs. The sbatch script to be used is created from a template file in this\n    same module.\n\n    Parameters\n    ----------\n    partition : str\n        Slurm partition to request blocks from.\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    nodes_per_block : int\n        Nodes to provision per block.\n    cores_per_node : int\n        Specify the number of cores to provision per node. If set to None, executors\n        will assume all cores on the node are available for computation. Default is None.\n    mem_per_node : int\n        Specify the real memory to provision per node in GB. If set to None, no\n        explicit request to the scheduler will be made. Default is None.\n    min_blocks : int\n        Minimum number of blocks to maintain.\n    max_blocks : int\n        Maximum number of blocks to maintain.\n    parallelism : float\n        Ratio of provisioned task slots to active tasks. A parallelism value of 1 represents aggressive\n        scaling where as many resources as possible are used; parallelism close to 0 represents\n        the opposite situation in which as few resources as possible (i.e., min_blocks) are used.\n    walltime : str\n        Walltime requested per block in HH:MM:SS.\n    scheduler_options : str\n        String to prepend to the #SBATCH blocks in the submit script to the scheduler.\n    worker_init : str\n        Command to be run before starting a worker, such as 'module load Anaconda; source activate env'.\n    exclusive : bool (Default = True)\n        Requests nodes which are not shared with other running jobs.\n    launcher : Launcher\n        Launcher for this provider. Possible launchers include\n        :class:`~parsl.launchers.SingleNodeLauncher` (the default),\n        :class:`~parsl.launchers.SrunLauncher`, or\n        :class:`~parsl.launchers.AprunLauncher`\n     move_files : Optional[Bool]: should files be moved? by default, Parsl will try to move files.\n    \"\"\"\n\n    @typeguard.typechecked\n    def __init__(self,\n                 partition: str,\n                 channel: Channel = LocalChannel(),\n                 nodes_per_block: int = 1,\n                 cores_per_node: Optional[int] = None,\n                 mem_per_node: Optional[int] = None,\n                 init_blocks: int = 1,\n                 min_blocks: int = 0,\n                 max_blocks: int = 10,\n                 parallelism: float = 1,\n                 walltime: str = \"00:10:00\",\n                 scheduler_options: str = '',\n                 worker_init: str = '',\n                 cmd_timeout: int = 10,\n                 exclusive: bool = True,\n                 move_files: bool = True,\n                 launcher: Launcher = SingleNodeLauncher()):\n        label = 'slurm'\n        super().__init__(label,\n                         channel,\n                         nodes_per_block,\n                         init_blocks,\n                         min_blocks,\n                         max_blocks,\n                         parallelism,\n                         walltime,\n                         cmd_timeout=cmd_timeout,\n                         launcher=launcher)\n\n        self.partition = partition\n        self.cores_per_node = cores_per_node\n        self.mem_per_node = mem_per_node\n        self.exclusive = exclusive\n        self.move_files = move_files\n        self.scheduler_options = scheduler_options + '\\n'\n        if exclusive:\n            self.scheduler_options += \"#SBATCH --exclusive\\n\"\n        self.worker_init = worker_init + '\\n'\n\n    def _status(self):\n        ''' Internal: Do not call. Returns the status list for a list of job_ids\n\n        Args:\n              self\n\n        Returns:\n              [status...] : Status list of all jobs\n        '''\n        job_id_list = ','.join(self.resources.keys())\n        cmd = \"squeue --job {0}\".format(job_id_list)\n\n        retcode, stdout, stderr = self.execute_wait(cmd)\n\n        # Execute_wait failed. Do no update\n        if retcode != 0:\n            return\n\n        jobs_missing = list(self.resources.keys())\n        for line in stdout.split('\\n'):\n            parts = line.split()\n            if parts and parts[0] != 'JOBID':\n                job_id = parts[0]\n                status = translate_table.get(parts[4], JobState.UNKNOWN)\n                self.resources[job_id]['status'] = JobStatus(status)\n                jobs_missing.remove(job_id)\n\n        # squeue does not report on jobs that are not running. So we are filling in the\n        # blanks for missing jobs, we might lose some information about why the jobs failed.\n        for missing_job in jobs_missing:\n            self.resources[missing_job]['status'] = JobStatus(JobState.COMPLETED)\n\n    def submit(self, command, tasks_per_node, job_name=\"parsl.slurm\"):\n        \"\"\"Submit the command as a slurm job.\n\n        Parameters\n        ----------\n        command : str\n            Command to be made on the remote side.\n        tasks_per_node : int\n            Command invocations to be launched per node\n        job_name : str\n            Name for the job (must be unique).\n        Returns\n        -------\n        None or str\n            If at capacity, returns None; otherwise, a string identifier for the job\n        \"\"\"\n\n        if self.provisioned_blocks >= self.max_blocks:\n            logger.warning(\"Slurm provider '{}' is at capacity (no more blocks will be added)\".format(self.label))\n            return None\n\n        scheduler_options = self.scheduler_options\n        worker_init = self.worker_init\n        if self.mem_per_node is not None:\n            scheduler_options += '#SBATCH --mem={}g\\n'.format(self.mem_per_node)\n            worker_init += 'export PARSL_MEMORY_GB={}\\n'.format(self.mem_per_node)\n        if self.cores_per_node is not None:\n            cpus_per_task = math.floor(self.cores_per_node / tasks_per_node)\n            scheduler_options += '#SBATCH --cpus-per-task={}'.format(cpus_per_task)\n            worker_init += 'export PARSL_CORES={}\\n'.format(cpus_per_task)\n\n        job_name = \"{0}.{1}\".format(job_name, time.time())\n\n        script_path = \"{0}/{1}.submit\".format(self.script_dir, job_name)\n        script_path = os.path.abspath(script_path)\n\n        logger.debug(\"Requesting one block with {} nodes\".format(self.nodes_per_block))\n\n        job_config = {}\n        job_config[\"submit_script_dir\"] = self.channel.script_dir\n        job_config[\"nodes\"] = self.nodes_per_block\n        job_config[\"tasks_per_node\"] = tasks_per_node\n        job_config[\"walltime\"] = wtime_to_minutes(self.walltime)\n        job_config[\"scheduler_options\"] = scheduler_options\n        job_config[\"worker_init\"] = worker_init\n        job_config[\"partition\"] = self.partition\n        job_config[\"user_script\"] = command\n\n        # Wrap the command\n        job_config[\"user_script\"] = self.launcher(command,\n                                                  tasks_per_node,\n                                                  self.nodes_per_block)\n\n        logger.debug(\"Writing submit script\")\n        self._write_submit_script(template_string, script_path, job_name, job_config)\n\n        if self.move_files:\n            logger.debug(\"moving files\")\n            channel_script_path = self.channel.push_file(script_path, self.channel.script_dir)\n        else:\n            logger.debug(\"not moving files\")\n            channel_script_path = script_path\n\n        retcode, stdout, stderr = self.execute_wait(\"sbatch {0}\".format(channel_script_path))\n\n        job_id = None\n        if retcode == 0:\n            for line in stdout.split('\\n'):\n                if line.startswith(\"Submitted batch job\"):\n                    job_id = line.split(\"Submitted batch job\")[1].strip()\n                    self.resources[job_id] = {'job_id': job_id, 'status': JobStatus(JobState.PENDING)}\n        else:\n            print(\"Submission of command to scale_out failed\")\n            logger.error(\"Retcode:%s STDOUT:%s STDERR:%s\", retcode, stdout.strip(), stderr.strip())\n        return job_id\n\n    def cancel(self, job_ids):\n        ''' Cancels the jobs specified by a list of job ids\n\n        Args:\n        job_ids : [<job_id> ...]\n\n        Returns :\n        [True/False...] : If the cancel operation fails the entire list will be False.\n        '''\n\n        job_id_list = ' '.join(job_ids)\n        retcode, stdout, stderr = self.execute_wait(\"scancel {0}\".format(job_id_list))\n        rets = None\n        if retcode == 0:\n            for jid in job_ids:\n                self.resources[jid]['status'] = JobStatus(JobState.CANCELLED)  # Setting state to cancelled\n            rets = [True for i in job_ids]\n        else:\n            rets = [False for i in job_ids]\n\n        return rets\n\n    def _test_add_resource(self, job_id):\n        self.resources.extend([{'job_id': job_id, 'status': JobStatus(JobState.PENDING), 'size': 1}])\n        return True\n\n\nif __name__ == \"__main__\":\n\n    print(\"None\")\n", "path": "parsl/providers/slurm/slurm.py"}, {"content": "template_string = '''#!/bin/bash\n\n#SBATCH --job-name=${jobname}\n#SBATCH --output=${submit_script_dir}/${jobname}.submit.stdout\n#SBATCH --error=${submit_script_dir}/${jobname}.submit.stderr\n#SBATCH --nodes=${nodes}\n#SBATCH --partition=${partition}\n#SBATCH --time=${walltime}\n#SBATCH --ntasks-per-node=${tasks_per_node}\n${scheduler_options}\n\n${worker_init}\n\nexport JOBNAME=\"${jobname}\"\n\n$user_script\n'''\n", "path": "parsl/providers/slurm/template.py"}], "after_files": [{"content": "import os\nimport math\nimport time\nimport logging\nimport typeguard\n\nfrom typing import Optional\n\nfrom parsl.channels import LocalChannel\nfrom parsl.channels.base import Channel\nfrom parsl.launchers import SingleNodeLauncher\nfrom parsl.launchers.launchers import Launcher\nfrom parsl.providers.cluster_provider import ClusterProvider\nfrom parsl.providers.provider_base import JobState, JobStatus\nfrom parsl.providers.slurm.template import template_string\nfrom parsl.utils import RepresentationMixin, wtime_to_minutes\n\nlogger = logging.getLogger(__name__)\n\ntranslate_table = {\n    'PD': JobState.PENDING,\n    'R': JobState.RUNNING,\n    'CA': JobState.CANCELLED,\n    'CF': JobState.PENDING,  # (configuring),\n    'CG': JobState.RUNNING,  # (completing),\n    'CD': JobState.COMPLETED,\n    'F': JobState.FAILED,  # (failed),\n    'TO': JobState.TIMEOUT,  # (timeout),\n    'NF': JobState.FAILED,  # (node failure),\n    'RV': JobState.FAILED,  # (revoked) and\n    'SE': JobState.FAILED\n}  # (special exit state\n\n\nclass SlurmProvider(ClusterProvider, RepresentationMixin):\n    \"\"\"Slurm Execution Provider\n\n    This provider uses sbatch to submit, squeue for status and scancel to cancel\n    jobs. The sbatch script to be used is created from a template file in this\n    same module.\n\n    Parameters\n    ----------\n    partition : str\n        Slurm partition to request blocks from. If none, no partition slurm directive will be specified.\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    nodes_per_block : int\n        Nodes to provision per block.\n    cores_per_node : int\n        Specify the number of cores to provision per node. If set to None, executors\n        will assume all cores on the node are available for computation. Default is None.\n    mem_per_node : int\n        Specify the real memory to provision per node in GB. If set to None, no\n        explicit request to the scheduler will be made. Default is None.\n    min_blocks : int\n        Minimum number of blocks to maintain.\n    max_blocks : int\n        Maximum number of blocks to maintain.\n    parallelism : float\n        Ratio of provisioned task slots to active tasks. A parallelism value of 1 represents aggressive\n        scaling where as many resources as possible are used; parallelism close to 0 represents\n        the opposite situation in which as few resources as possible (i.e., min_blocks) are used.\n    walltime : str\n        Walltime requested per block in HH:MM:SS.\n    scheduler_options : str\n        String to prepend to the #SBATCH blocks in the submit script to the scheduler.\n    worker_init : str\n        Command to be run before starting a worker, such as 'module load Anaconda; source activate env'.\n    exclusive : bool (Default = True)\n        Requests nodes which are not shared with other running jobs.\n    launcher : Launcher\n        Launcher for this provider. Possible launchers include\n        :class:`~parsl.launchers.SingleNodeLauncher` (the default),\n        :class:`~parsl.launchers.SrunLauncher`, or\n        :class:`~parsl.launchers.AprunLauncher`\n     move_files : Optional[Bool]: should files be moved? by default, Parsl will try to move files.\n    \"\"\"\n\n    @typeguard.typechecked\n    def __init__(self,\n                 partition: Optional[str],\n                 channel: Channel = LocalChannel(),\n                 nodes_per_block: int = 1,\n                 cores_per_node: Optional[int] = None,\n                 mem_per_node: Optional[int] = None,\n                 init_blocks: int = 1,\n                 min_blocks: int = 0,\n                 max_blocks: int = 10,\n                 parallelism: float = 1,\n                 walltime: str = \"00:10:00\",\n                 scheduler_options: str = '',\n                 worker_init: str = '',\n                 cmd_timeout: int = 10,\n                 exclusive: bool = True,\n                 move_files: bool = True,\n                 launcher: Launcher = SingleNodeLauncher()):\n        label = 'slurm'\n        super().__init__(label,\n                         channel,\n                         nodes_per_block,\n                         init_blocks,\n                         min_blocks,\n                         max_blocks,\n                         parallelism,\n                         walltime,\n                         cmd_timeout=cmd_timeout,\n                         launcher=launcher)\n\n        self.partition = partition\n        self.cores_per_node = cores_per_node\n        self.mem_per_node = mem_per_node\n        self.exclusive = exclusive\n        self.move_files = move_files\n        self.scheduler_options = scheduler_options + '\\n'\n        if exclusive:\n            self.scheduler_options += \"#SBATCH --exclusive\\n\"\n        if partition:\n            self.scheduler_options += \"#SBATCH --partition={}\\n\".format(partition)\n        self.worker_init = worker_init + '\\n'\n\n    def _status(self):\n        ''' Internal: Do not call. Returns the status list for a list of job_ids\n\n        Args:\n              self\n\n        Returns:\n              [status...] : Status list of all jobs\n        '''\n        job_id_list = ','.join(self.resources.keys())\n        cmd = \"squeue --job {0}\".format(job_id_list)\n\n        retcode, stdout, stderr = self.execute_wait(cmd)\n\n        # Execute_wait failed. Do no update\n        if retcode != 0:\n            return\n\n        jobs_missing = list(self.resources.keys())\n        for line in stdout.split('\\n'):\n            parts = line.split()\n            if parts and parts[0] != 'JOBID':\n                job_id = parts[0]\n                status = translate_table.get(parts[4], JobState.UNKNOWN)\n                self.resources[job_id]['status'] = JobStatus(status)\n                jobs_missing.remove(job_id)\n\n        # squeue does not report on jobs that are not running. So we are filling in the\n        # blanks for missing jobs, we might lose some information about why the jobs failed.\n        for missing_job in jobs_missing:\n            self.resources[missing_job]['status'] = JobStatus(JobState.COMPLETED)\n\n    def submit(self, command, tasks_per_node, job_name=\"parsl.slurm\"):\n        \"\"\"Submit the command as a slurm job.\n\n        Parameters\n        ----------\n        command : str\n            Command to be made on the remote side.\n        tasks_per_node : int\n            Command invocations to be launched per node\n        job_name : str\n            Name for the job (must be unique).\n        Returns\n        -------\n        None or str\n            If at capacity, returns None; otherwise, a string identifier for the job\n        \"\"\"\n\n        if self.provisioned_blocks >= self.max_blocks:\n            logger.warning(\"Slurm provider '{}' is at capacity (no more blocks will be added)\".format(self.label))\n            return None\n\n        scheduler_options = self.scheduler_options\n        worker_init = self.worker_init\n        if self.mem_per_node is not None:\n            scheduler_options += '#SBATCH --mem={}g\\n'.format(self.mem_per_node)\n            worker_init += 'export PARSL_MEMORY_GB={}\\n'.format(self.mem_per_node)\n        if self.cores_per_node is not None:\n            cpus_per_task = math.floor(self.cores_per_node / tasks_per_node)\n            scheduler_options += '#SBATCH --cpus-per-task={}'.format(cpus_per_task)\n            worker_init += 'export PARSL_CORES={}\\n'.format(cpus_per_task)\n\n        job_name = \"{0}.{1}\".format(job_name, time.time())\n\n        script_path = \"{0}/{1}.submit\".format(self.script_dir, job_name)\n        script_path = os.path.abspath(script_path)\n\n        logger.debug(\"Requesting one block with {} nodes\".format(self.nodes_per_block))\n\n        job_config = {}\n        job_config[\"submit_script_dir\"] = self.channel.script_dir\n        job_config[\"nodes\"] = self.nodes_per_block\n        job_config[\"tasks_per_node\"] = tasks_per_node\n        job_config[\"walltime\"] = wtime_to_minutes(self.walltime)\n        job_config[\"scheduler_options\"] = scheduler_options\n        job_config[\"worker_init\"] = worker_init\n        job_config[\"user_script\"] = command\n\n        # Wrap the command\n        job_config[\"user_script\"] = self.launcher(command,\n                                                  tasks_per_node,\n                                                  self.nodes_per_block)\n\n        logger.debug(\"Writing submit script\")\n        self._write_submit_script(template_string, script_path, job_name, job_config)\n\n        if self.move_files:\n            logger.debug(\"moving files\")\n            channel_script_path = self.channel.push_file(script_path, self.channel.script_dir)\n        else:\n            logger.debug(\"not moving files\")\n            channel_script_path = script_path\n\n        retcode, stdout, stderr = self.execute_wait(\"sbatch {0}\".format(channel_script_path))\n\n        job_id = None\n        if retcode == 0:\n            for line in stdout.split('\\n'):\n                if line.startswith(\"Submitted batch job\"):\n                    job_id = line.split(\"Submitted batch job\")[1].strip()\n                    self.resources[job_id] = {'job_id': job_id, 'status': JobStatus(JobState.PENDING)}\n        else:\n            print(\"Submission of command to scale_out failed\")\n            logger.error(\"Retcode:%s STDOUT:%s STDERR:%s\", retcode, stdout.strip(), stderr.strip())\n        return job_id\n\n    def cancel(self, job_ids):\n        ''' Cancels the jobs specified by a list of job ids\n\n        Args:\n        job_ids : [<job_id> ...]\n\n        Returns :\n        [True/False...] : If the cancel operation fails the entire list will be False.\n        '''\n\n        job_id_list = ' '.join(job_ids)\n        retcode, stdout, stderr = self.execute_wait(\"scancel {0}\".format(job_id_list))\n        rets = None\n        if retcode == 0:\n            for jid in job_ids:\n                self.resources[jid]['status'] = JobStatus(JobState.CANCELLED)  # Setting state to cancelled\n            rets = [True for i in job_ids]\n        else:\n            rets = [False for i in job_ids]\n\n        return rets\n\n    def _test_add_resource(self, job_id):\n        self.resources.extend([{'job_id': job_id, 'status': JobStatus(JobState.PENDING), 'size': 1}])\n        return True\n\n\nif __name__ == \"__main__\":\n\n    print(\"None\")\n", "path": "parsl/providers/slurm/slurm.py"}, {"content": "template_string = '''#!/bin/bash\n\n#SBATCH --job-name=${jobname}\n#SBATCH --output=${submit_script_dir}/${jobname}.submit.stdout\n#SBATCH --error=${submit_script_dir}/${jobname}.submit.stderr\n#SBATCH --nodes=${nodes}\n#SBATCH --time=${walltime}\n#SBATCH --ntasks-per-node=${tasks_per_node}\n${scheduler_options}\n\n${worker_init}\n\nexport JOBNAME=\"${jobname}\"\n\n$user_script\n'''\n", "path": "parsl/providers/slurm/template.py"}]}