We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Condor provider has a hard-coded `cmd_timeout`. 
This timeout should be configurable and probably default to something much longer.

https://github.com/Parsl/parsl/blob/1d8c9e35752274af6ae2ce2f07107474ece4561c/parsl/providers/condor/condor.py#L225

cc @ZhuozhaoLi who noted this in a comment to #889 

--- 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/condor/condor.py`
Content:
```
1 import logging
2 import os
3 import re
4 import time
5 
6 from parsl.channels import LocalChannel
7 from parsl.utils import RepresentationMixin
8 from parsl.launchers import SingleNodeLauncher
9 from parsl.providers.condor.template import template_string
10 from parsl.providers.cluster_provider import ClusterProvider
11 
12 logger = logging.getLogger(__name__)
13 
14 # See http://pages.cs.wisc.edu/~adesmet/status.html
15 translate_table = {
16     '1': 'PENDING',
17     '2': 'RUNNING',
18     '3': 'CANCELLED',
19     '4': 'COMPLETED',
20     '5': 'FAILED',
21     '6': 'FAILED',
22 }
23 
24 
25 class CondorProvider(RepresentationMixin, ClusterProvider):
26     """HTCondor Execution Provider.
27 
28     Parameters
29     ----------
30     channel : Channel
31         Channel for accessing this provider. Possible channels include
32         :class:`~parsl.channels.LocalChannel` (the default),
33         :class:`~parsl.channels.SSHChannel`, or
34         :class:`~parsl.channels.SSHInteractiveLoginChannel`.
35     nodes_per_block : int
36         Nodes to provision per block.
37     init_blocks : int
38         Number of blocks to provision at time of initialization
39     min_blocks : int
40         Minimum number of blocks to maintain
41     max_blocks : int
42         Maximum number of blocks to maintain.
43     parallelism : float
44         Ratio of provisioned task slots to active tasks. A parallelism value of 1 represents aggressive
45         scaling where as many resources as possible are used; parallelism close to 0 represents
46         the opposite situation in which as few resources as possible (i.e., min_blocks) are used.
47     environment : dict of str
48         A dictionary of environmant variable name and value pairs which will be set before
49         running a task.
50     project : str
51         Project which the job will be charged against
52     scheduler_options : str
53         String to add specific condor attributes to the HTCondor submit script.
54     transfer_input_files : list(str)
55         List of strings of paths to additional files or directories to transfer to the job
56     worker_init : str
57         Command to be run before starting a worker.
58     requirements : str
59         Condor requirements.
60     launcher : Launcher
61         Launcher for this provider. Possible launchers include
62         :class:`~parsl.launchers.SingleNodeLauncher` (the default),
63     """
64     def __init__(self,
65                  channel=LocalChannel(),
66                  nodes_per_block=1,
67                  init_blocks=1,
68                  min_blocks=0,
69                  max_blocks=10,
70                  parallelism=1,
71                  environment=None,
72                  project='',
73                  scheduler_options='',
74                  transfer_input_files=[],
75                  walltime="00:10:00",
76                  worker_init='',
77                  launcher=SingleNodeLauncher(),
78                  requirements=''):
79 
80         label = 'condor'
81         super().__init__(label,
82                          channel,
83                          nodes_per_block,
84                          init_blocks,
85                          min_blocks,
86                          max_blocks,
87                          parallelism,
88                          walltime,
89                          launcher)
90 
91         self.provisioned_blocks = 0
92 
93         self.environment = environment if environment is not None else {}
94         for key, value in self.environment.items():
95             # To escape literal quote marks, double them
96             # See: http://research.cs.wisc.edu/htcondor/manual/v8.6/condor_submit.html
97             try:
98                 self.environment[key] = "'{}'".format(value.replace("'", '"').replace('"', '""'))
99             except AttributeError:
100                 pass
101 
102         self.project = project
103         self.scheduler_options = scheduler_options
104         self.worker_init = worker_init
105         self.requirements = requirements
106         self.transfer_input_files = transfer_input_files
107 
108     def _status(self):
109         """Update the resource dictionary with job statuses."""
110 
111         job_id_list = ' '.join(self.resources.keys())
112         cmd = "condor_q {0} -af:jr JobStatus".format(job_id_list)
113         retcode, stdout, stderr = super().execute_wait(cmd)
114         """
115         Example output:
116 
117         $ condor_q 34524642.0 34524643.0 -af:jr JobStatus
118         34524642.0 2
119         34524643.0 1
120         """
121 
122         for line in stdout.strip().split('\n'):
123             parts = line.split()
124             job_id = parts[0]
125             status = translate_table.get(parts[1], 'UNKNOWN')
126             self.resources[job_id]['status'] = status
127 
128     def status(self, job_ids):
129         """Get the status of a list of jobs identified by their ids.
130 
131         Parameters
132         ----------
133         job_ids : list of int
134             Identifiers of jobs for which the status will be returned.
135 
136         Returns
137         -------
138         List of int
139             Status codes for the requested jobs.
140 
141         """
142         self._status()
143         return [self.resources[jid]['status'] for jid in job_ids]
144 
145     def submit(self, command, blocksize, tasks_per_node, job_name="parsl.auto"):
146         """Submits the command onto an Local Resource Manager job of blocksize parallel elements.
147 
148         example file with the complex case of multiple submits per job:
149             Universe =vanilla
150             output = out.$(Cluster).$(Process)
151             error = err.$(Cluster).$(Process)
152             log = log.$(Cluster)
153             leave_in_queue = true
154             executable = test.sh
155             queue 5
156             executable = foo
157             queue 1
158 
159         $ condor_submit test.sub
160         Submitting job(s)......
161         5 job(s) submitted to cluster 118907.
162         1 job(s) submitted to cluster 118908.
163 
164         Parameters
165         ----------
166         command : str
167             Command to execute
168         blocksize : int
169             Number of blocks to request.
170         job_name : str
171             Job name prefix.
172         tasks_per_node : int
173             command invocations to be launched per node
174         Returns
175         -------
176         None or str
177             None if at capacity and cannot provision more; otherwise the identifier for the job.
178         """
179 
180         logger.debug("Attempting to launch with blocksize: {}".format(blocksize))
181         if self.provisioned_blocks >= self.max_blocks:
182             template = "Provider {} is currently using {} blocks while max_blocks is {}; no blocks will be added"
183             logger.warn(template.format(self.label, self.provisioned_blocks, self.max_blocks))
184             return None
185 
186         # Note: Fix this later to avoid confusing behavior.
187         # We should always allocate blocks in integer counts of node_granularity
188         blocksize = max(self.nodes_per_block, blocksize)
189 
190         job_name = "parsl.{0}.{1}".format(job_name, time.time())
191 
192         script_path = "{0}/{1}.submit".format(self.script_dir, job_name)
193         script_path = os.path.abspath(script_path)
194         userscript_path = "{0}/{1}.script".format(self.script_dir, job_name)
195         userscript_path = os.path.abspath(userscript_path)
196 
197         self.environment["JOBNAME"] = "'{}'".format(job_name)
198 
199         job_config = {}
200         job_config["job_name"] = job_name
201         job_config["submit_script_dir"] = self.channel.script_dir
202         job_config["project"] = self.project
203         job_config["nodes"] = self.nodes_per_block
204         job_config["scheduler_options"] = self.scheduler_options
205         job_config["worker_init"] = self.worker_init
206         job_config["user_script"] = command
207         job_config["tasks_per_node"] = tasks_per_node
208         job_config["requirements"] = self.requirements
209         job_config["environment"] = ' '.join(['{}={}'.format(key, value) for key, value in self.environment.items()])
210 
211         # Move the user script
212         # This is where the command should be wrapped by the launchers.
213         wrapped_command = self.launcher(command,
214                                         tasks_per_node,
215                                         self.nodes_per_block)
216 
217         with open(userscript_path, 'w') as f:
218             f.write(job_config["worker_init"] + '\n' + wrapped_command)
219 
220         user_script_path = self.channel.push_file(userscript_path, self.channel.script_dir)
221         the_input_files = [user_script_path] + self.transfer_input_files
222         job_config["input_files"] = ','.join(the_input_files)
223         job_config["job_script"] = os.path.basename(user_script_path)
224 
225         # Construct and move the submit script
226         self._write_submit_script(template_string, script_path, job_name, job_config)
227         channel_script_path = self.channel.push_file(script_path, self.channel.script_dir)
228 
229         cmd = "condor_submit {0}".format(channel_script_path)
230         retcode, stdout, stderr = super().execute_wait(cmd, 30)
231         logger.debug("Retcode:%s STDOUT:%s STDERR:%s", retcode, stdout.strip(), stderr.strip())
232 
233         job_id = []
234 
235         if retcode == 0:
236             for line in stdout.split('\n'):
237                 if re.match('^[0-9]', line) is not None:
238                     cluster = line.split(" ")[5]
239                     # We know the first job id ("process" in condor terms) within a
240                     # cluster is 0 and we know the total number of jobs from
241                     # condor_submit, so we use some list comprehensions to expand
242                     # the condor_submit output into job IDs
243                     # e.g., ['118907.0', '118907.1', '118907.2', '118907.3', '118907.4', '118908.0']
244                     processes = [str(x) for x in range(0, int(line[0]))]
245                     job_id += [cluster + process for process in processes]
246 
247             self._add_resource(job_id)
248         return job_id[0]
249 
250     def cancel(self, job_ids):
251         """Cancels the jobs specified by a list of job IDs.
252 
253         Parameters
254         ----------
255         job_ids : list of str
256             The job IDs to cancel.
257 
258         Returns
259         -------
260         list of bool
261             Each entry in the list will be True if the job is cancelled succesfully, otherwise False.
262         """
263 
264         job_id_list = ' '.join(job_ids)
265         cmd = "condor_rm {0}; condor_rm -forcex {0}".format(job_id_list)
266         logger.debug("Attempting removal of jobs : {0}".format(cmd))
267         retcode, stdout, stderr = self.channel.execute_wait(cmd, 30)
268         rets = None
269         if retcode == 0:
270             for jid in job_ids:
271                 self.resources[jid]['status'] = 'CANCELLED'
272             rets = [True for i in job_ids]
273         else:
274             rets = [False for i in job_ids]
275 
276         return rets
277 
278     @property
279     def scaling_enabled(self):
280         return True
281 
282     @property
283     def current_capacity(self):
284         return self
285 
286     def _add_resource(self, job_id):
287         for jid in job_id:
288             self.resources[jid] = {'status': 'PENDING', 'size': 1}
289         return True
290 
291 
292 if __name__ == "__main__":
293 
294     print("None")
295
```
--- 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/condor/condor.py b/parsl/providers/condor/condor.py
--- a/parsl/providers/condor/condor.py
+++ b/parsl/providers/condor/condor.py
@@ -60,6 +60,8 @@
     launcher : Launcher
         Launcher for this provider. Possible launchers include
         :class:`~parsl.launchers.SingleNodeLauncher` (the default),
+    cmd_timeout : int
+        Timeout for commands made to the scheduler in seconds
     """
     def __init__(self,
                  channel=LocalChannel(),
@@ -75,7 +77,8 @@
                  walltime="00:10:00",
                  worker_init='',
                  launcher=SingleNodeLauncher(),
-                 requirements=''):
+                 requirements='',
+                 cmd_timeout=60):
 
         label = 'condor'
         super().__init__(label,
@@ -86,8 +89,8 @@
                          max_blocks,
                          parallelism,
                          walltime,
-                         launcher)
-
+                         launcher,
+                         cmd_timeout=cmd_timeout)
         self.provisioned_blocks = 0
 
         self.environment = environment if environment is not None else {}
@@ -227,7 +230,7 @@
         channel_script_path = self.channel.push_file(script_path, self.channel.script_dir)
 
         cmd = "condor_submit {0}".format(channel_script_path)
-        retcode, stdout, stderr = super().execute_wait(cmd, 30)
+        retcode, stdout, stderr = super().execute_wait(cmd)
         logger.debug("Retcode:%s STDOUT:%s STDERR:%s", retcode, stdout.strip(), stderr.strip())
 
         job_id = []
@@ -264,7 +267,7 @@
         job_id_list = ' '.join(job_ids)
         cmd = "condor_rm {0}; condor_rm -forcex {0}".format(job_id_list)
         logger.debug("Attempting removal of jobs : {0}".format(cmd))
-        retcode, stdout, stderr = self.channel.execute_wait(cmd, 30)
+        retcode, stdout, stderr = super().execute_wait(cmd)
         rets = None
         if retcode == 0:
             for jid in job_ids:

{"golden_diff": "diff --git a/parsl/providers/condor/condor.py b/parsl/providers/condor/condor.py\n--- a/parsl/providers/condor/condor.py\n+++ b/parsl/providers/condor/condor.py\n@@ -60,6 +60,8 @@\n     launcher : Launcher\n         Launcher for this provider. Possible launchers include\n         :class:`~parsl.launchers.SingleNodeLauncher` (the default),\n+    cmd_timeout : int\n+        Timeout for commands made to the scheduler in seconds\n     \"\"\"\n     def __init__(self,\n                  channel=LocalChannel(),\n@@ -75,7 +77,8 @@\n                  walltime=\"00:10:00\",\n                  worker_init='',\n                  launcher=SingleNodeLauncher(),\n-                 requirements=''):\n+                 requirements='',\n+                 cmd_timeout=60):\n \n         label = 'condor'\n         super().__init__(label,\n@@ -86,8 +89,8 @@\n                          max_blocks,\n                          parallelism,\n                          walltime,\n-                         launcher)\n-\n+                         launcher,\n+                         cmd_timeout=cmd_timeout)\n         self.provisioned_blocks = 0\n \n         self.environment = environment if environment is not None else {}\n@@ -227,7 +230,7 @@\n         channel_script_path = self.channel.push_file(script_path, self.channel.script_dir)\n \n         cmd = \"condor_submit {0}\".format(channel_script_path)\n-        retcode, stdout, stderr = super().execute_wait(cmd, 30)\n+        retcode, stdout, stderr = super().execute_wait(cmd)\n         logger.debug(\"Retcode:%s STDOUT:%s STDERR:%s\", retcode, stdout.strip(), stderr.strip())\n \n         job_id = []\n@@ -264,7 +267,7 @@\n         job_id_list = ' '.join(job_ids)\n         cmd = \"condor_rm {0}; condor_rm -forcex {0}\".format(job_id_list)\n         logger.debug(\"Attempting removal of jobs : {0}\".format(cmd))\n-        retcode, stdout, stderr = self.channel.execute_wait(cmd, 30)\n+        retcode, stdout, stderr = super().execute_wait(cmd)\n         rets = None\n         if retcode == 0:\n             for jid in job_ids:\n", "issue": "Condor provider has a hard-coded `cmd_timeout`. \nThis timeout should be configurable and probably default to something much longer.\r\n\r\nhttps://github.com/Parsl/parsl/blob/1d8c9e35752274af6ae2ce2f07107474ece4561c/parsl/providers/condor/condor.py#L225\r\n\r\ncc @ZhuozhaoLi who noted this in a comment to #889 \n", "before_files": [{"content": "import logging\nimport os\nimport re\nimport time\n\nfrom parsl.channels import LocalChannel\nfrom parsl.utils import RepresentationMixin\nfrom parsl.launchers import SingleNodeLauncher\nfrom parsl.providers.condor.template import template_string\nfrom parsl.providers.cluster_provider import ClusterProvider\n\nlogger = logging.getLogger(__name__)\n\n# See http://pages.cs.wisc.edu/~adesmet/status.html\ntranslate_table = {\n    '1': 'PENDING',\n    '2': 'RUNNING',\n    '3': 'CANCELLED',\n    '4': 'COMPLETED',\n    '5': 'FAILED',\n    '6': 'FAILED',\n}\n\n\nclass CondorProvider(RepresentationMixin, ClusterProvider):\n    \"\"\"HTCondor Execution Provider.\n\n    Parameters\n    ----------\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    init_blocks : int\n        Number of blocks to provision at time of initialization\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    environment : dict of str\n        A dictionary of environmant variable name and value pairs which will be set before\n        running a task.\n    project : str\n        Project which the job will be charged against\n    scheduler_options : str\n        String to add specific condor attributes to the HTCondor submit script.\n    transfer_input_files : list(str)\n        List of strings of paths to additional files or directories to transfer to the job\n    worker_init : str\n        Command to be run before starting a worker.\n    requirements : str\n        Condor requirements.\n    launcher : Launcher\n        Launcher for this provider. Possible launchers include\n        :class:`~parsl.launchers.SingleNodeLauncher` (the default),\n    \"\"\"\n    def __init__(self,\n                 channel=LocalChannel(),\n                 nodes_per_block=1,\n                 init_blocks=1,\n                 min_blocks=0,\n                 max_blocks=10,\n                 parallelism=1,\n                 environment=None,\n                 project='',\n                 scheduler_options='',\n                 transfer_input_files=[],\n                 walltime=\"00:10:00\",\n                 worker_init='',\n                 launcher=SingleNodeLauncher(),\n                 requirements=''):\n\n        label = 'condor'\n        super().__init__(label,\n                         channel,\n                         nodes_per_block,\n                         init_blocks,\n                         min_blocks,\n                         max_blocks,\n                         parallelism,\n                         walltime,\n                         launcher)\n\n        self.provisioned_blocks = 0\n\n        self.environment = environment if environment is not None else {}\n        for key, value in self.environment.items():\n            # To escape literal quote marks, double them\n            # See: http://research.cs.wisc.edu/htcondor/manual/v8.6/condor_submit.html\n            try:\n                self.environment[key] = \"'{}'\".format(value.replace(\"'\", '\"').replace('\"', '\"\"'))\n            except AttributeError:\n                pass\n\n        self.project = project\n        self.scheduler_options = scheduler_options\n        self.worker_init = worker_init\n        self.requirements = requirements\n        self.transfer_input_files = transfer_input_files\n\n    def _status(self):\n        \"\"\"Update the resource dictionary with job statuses.\"\"\"\n\n        job_id_list = ' '.join(self.resources.keys())\n        cmd = \"condor_q {0} -af:jr JobStatus\".format(job_id_list)\n        retcode, stdout, stderr = super().execute_wait(cmd)\n        \"\"\"\n        Example output:\n\n        $ condor_q 34524642.0 34524643.0 -af:jr JobStatus\n        34524642.0 2\n        34524643.0 1\n        \"\"\"\n\n        for line in stdout.strip().split('\\n'):\n            parts = line.split()\n            job_id = parts[0]\n            status = translate_table.get(parts[1], 'UNKNOWN')\n            self.resources[job_id]['status'] = status\n\n    def status(self, job_ids):\n        \"\"\"Get the status of a list of jobs identified by their ids.\n\n        Parameters\n        ----------\n        job_ids : list of int\n            Identifiers of jobs for which the status will be returned.\n\n        Returns\n        -------\n        List of int\n            Status codes for the requested jobs.\n\n        \"\"\"\n        self._status()\n        return [self.resources[jid]['status'] for jid in job_ids]\n\n    def submit(self, command, blocksize, tasks_per_node, job_name=\"parsl.auto\"):\n        \"\"\"Submits the command onto an Local Resource Manager job of blocksize parallel elements.\n\n        example file with the complex case of multiple submits per job:\n            Universe =vanilla\n            output = out.$(Cluster).$(Process)\n            error = err.$(Cluster).$(Process)\n            log = log.$(Cluster)\n            leave_in_queue = true\n            executable = test.sh\n            queue 5\n            executable = foo\n            queue 1\n\n        $ condor_submit test.sub\n        Submitting job(s)......\n        5 job(s) submitted to cluster 118907.\n        1 job(s) submitted to cluster 118908.\n\n        Parameters\n        ----------\n        command : str\n            Command to execute\n        blocksize : int\n            Number of blocks to request.\n        job_name : str\n            Job name prefix.\n        tasks_per_node : int\n            command invocations to be launched per node\n        Returns\n        -------\n        None or str\n            None if at capacity and cannot provision more; otherwise the identifier for the job.\n        \"\"\"\n\n        logger.debug(\"Attempting to launch with blocksize: {}\".format(blocksize))\n        if self.provisioned_blocks >= self.max_blocks:\n            template = \"Provider {} is currently using {} blocks while max_blocks is {}; no blocks will be added\"\n            logger.warn(template.format(self.label, self.provisioned_blocks, self.max_blocks))\n            return None\n\n        # Note: Fix this later to avoid confusing behavior.\n        # We should always allocate blocks in integer counts of node_granularity\n        blocksize = max(self.nodes_per_block, blocksize)\n\n        job_name = \"parsl.{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        userscript_path = \"{0}/{1}.script\".format(self.script_dir, job_name)\n        userscript_path = os.path.abspath(userscript_path)\n\n        self.environment[\"JOBNAME\"] = \"'{}'\".format(job_name)\n\n        job_config = {}\n        job_config[\"job_name\"] = job_name\n        job_config[\"submit_script_dir\"] = self.channel.script_dir\n        job_config[\"project\"] = self.project\n        job_config[\"nodes\"] = self.nodes_per_block\n        job_config[\"scheduler_options\"] = self.scheduler_options\n        job_config[\"worker_init\"] = self.worker_init\n        job_config[\"user_script\"] = command\n        job_config[\"tasks_per_node\"] = tasks_per_node\n        job_config[\"requirements\"] = self.requirements\n        job_config[\"environment\"] = ' '.join(['{}={}'.format(key, value) for key, value in self.environment.items()])\n\n        # Move the user script\n        # This is where the command should be wrapped by the launchers.\n        wrapped_command = self.launcher(command,\n                                        tasks_per_node,\n                                        self.nodes_per_block)\n\n        with open(userscript_path, 'w') as f:\n            f.write(job_config[\"worker_init\"] + '\\n' + wrapped_command)\n\n        user_script_path = self.channel.push_file(userscript_path, self.channel.script_dir)\n        the_input_files = [user_script_path] + self.transfer_input_files\n        job_config[\"input_files\"] = ','.join(the_input_files)\n        job_config[\"job_script\"] = os.path.basename(user_script_path)\n\n        # Construct and move the submit script\n        self._write_submit_script(template_string, script_path, job_name, job_config)\n        channel_script_path = self.channel.push_file(script_path, self.channel.script_dir)\n\n        cmd = \"condor_submit {0}\".format(channel_script_path)\n        retcode, stdout, stderr = super().execute_wait(cmd, 30)\n        logger.debug(\"Retcode:%s STDOUT:%s STDERR:%s\", retcode, stdout.strip(), stderr.strip())\n\n        job_id = []\n\n        if retcode == 0:\n            for line in stdout.split('\\n'):\n                if re.match('^[0-9]', line) is not None:\n                    cluster = line.split(\" \")[5]\n                    # We know the first job id (\"process\" in condor terms) within a\n                    # cluster is 0 and we know the total number of jobs from\n                    # condor_submit, so we use some list comprehensions to expand\n                    # the condor_submit output into job IDs\n                    # e.g., ['118907.0', '118907.1', '118907.2', '118907.3', '118907.4', '118908.0']\n                    processes = [str(x) for x in range(0, int(line[0]))]\n                    job_id += [cluster + process for process in processes]\n\n            self._add_resource(job_id)\n        return job_id[0]\n\n    def cancel(self, job_ids):\n        \"\"\"Cancels the jobs specified by a list of job IDs.\n\n        Parameters\n        ----------\n        job_ids : list of str\n            The job IDs to cancel.\n\n        Returns\n        -------\n        list of bool\n            Each entry in the list will be True if the job is cancelled succesfully, otherwise False.\n        \"\"\"\n\n        job_id_list = ' '.join(job_ids)\n        cmd = \"condor_rm {0}; condor_rm -forcex {0}\".format(job_id_list)\n        logger.debug(\"Attempting removal of jobs : {0}\".format(cmd))\n        retcode, stdout, stderr = self.channel.execute_wait(cmd, 30)\n        rets = None\n        if retcode == 0:\n            for jid in job_ids:\n                self.resources[jid]['status'] = '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    @property\n    def scaling_enabled(self):\n        return True\n\n    @property\n    def current_capacity(self):\n        return self\n\n    def _add_resource(self, job_id):\n        for jid in job_id:\n            self.resources[jid] = {'status': 'PENDING', 'size': 1}\n        return True\n\n\nif __name__ == \"__main__\":\n\n    print(\"None\")\n", "path": "parsl/providers/condor/condor.py"}], "after_files": [{"content": "import logging\nimport os\nimport re\nimport time\n\nfrom parsl.channels import LocalChannel\nfrom parsl.utils import RepresentationMixin\nfrom parsl.launchers import SingleNodeLauncher\nfrom parsl.providers.condor.template import template_string\nfrom parsl.providers.cluster_provider import ClusterProvider\n\nlogger = logging.getLogger(__name__)\n\n# See http://pages.cs.wisc.edu/~adesmet/status.html\ntranslate_table = {\n    '1': 'PENDING',\n    '2': 'RUNNING',\n    '3': 'CANCELLED',\n    '4': 'COMPLETED',\n    '5': 'FAILED',\n    '6': 'FAILED',\n}\n\n\nclass CondorProvider(RepresentationMixin, ClusterProvider):\n    \"\"\"HTCondor Execution Provider.\n\n    Parameters\n    ----------\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    init_blocks : int\n        Number of blocks to provision at time of initialization\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    environment : dict of str\n        A dictionary of environmant variable name and value pairs which will be set before\n        running a task.\n    project : str\n        Project which the job will be charged against\n    scheduler_options : str\n        String to add specific condor attributes to the HTCondor submit script.\n    transfer_input_files : list(str)\n        List of strings of paths to additional files or directories to transfer to the job\n    worker_init : str\n        Command to be run before starting a worker.\n    requirements : str\n        Condor requirements.\n    launcher : Launcher\n        Launcher for this provider. Possible launchers include\n        :class:`~parsl.launchers.SingleNodeLauncher` (the default),\n    cmd_timeout : int\n        Timeout for commands made to the scheduler in seconds\n    \"\"\"\n    def __init__(self,\n                 channel=LocalChannel(),\n                 nodes_per_block=1,\n                 init_blocks=1,\n                 min_blocks=0,\n                 max_blocks=10,\n                 parallelism=1,\n                 environment=None,\n                 project='',\n                 scheduler_options='',\n                 transfer_input_files=[],\n                 walltime=\"00:10:00\",\n                 worker_init='',\n                 launcher=SingleNodeLauncher(),\n                 requirements='',\n                 cmd_timeout=60):\n\n        label = 'condor'\n        super().__init__(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=cmd_timeout)\n        self.provisioned_blocks = 0\n\n        self.environment = environment if environment is not None else {}\n        for key, value in self.environment.items():\n            # To escape literal quote marks, double them\n            # See: http://research.cs.wisc.edu/htcondor/manual/v8.6/condor_submit.html\n            try:\n                self.environment[key] = \"'{}'\".format(value.replace(\"'\", '\"').replace('\"', '\"\"'))\n            except AttributeError:\n                pass\n\n        self.project = project\n        self.scheduler_options = scheduler_options\n        self.worker_init = worker_init\n        self.requirements = requirements\n        self.transfer_input_files = transfer_input_files\n\n    def _status(self):\n        \"\"\"Update the resource dictionary with job statuses.\"\"\"\n\n        job_id_list = ' '.join(self.resources.keys())\n        cmd = \"condor_q {0} -af:jr JobStatus\".format(job_id_list)\n        retcode, stdout, stderr = super().execute_wait(cmd)\n        \"\"\"\n        Example output:\n\n        $ condor_q 34524642.0 34524643.0 -af:jr JobStatus\n        34524642.0 2\n        34524643.0 1\n        \"\"\"\n\n        for line in stdout.strip().split('\\n'):\n            parts = line.split()\n            job_id = parts[0]\n            status = translate_table.get(parts[1], 'UNKNOWN')\n            self.resources[job_id]['status'] = status\n\n    def status(self, job_ids):\n        \"\"\"Get the status of a list of jobs identified by their ids.\n\n        Parameters\n        ----------\n        job_ids : list of int\n            Identifiers of jobs for which the status will be returned.\n\n        Returns\n        -------\n        List of int\n            Status codes for the requested jobs.\n\n        \"\"\"\n        self._status()\n        return [self.resources[jid]['status'] for jid in job_ids]\n\n    def submit(self, command, blocksize, tasks_per_node, job_name=\"parsl.auto\"):\n        \"\"\"Submits the command onto an Local Resource Manager job of blocksize parallel elements.\n\n        example file with the complex case of multiple submits per job:\n            Universe =vanilla\n            output = out.$(Cluster).$(Process)\n            error = err.$(Cluster).$(Process)\n            log = log.$(Cluster)\n            leave_in_queue = true\n            executable = test.sh\n            queue 5\n            executable = foo\n            queue 1\n\n        $ condor_submit test.sub\n        Submitting job(s)......\n        5 job(s) submitted to cluster 118907.\n        1 job(s) submitted to cluster 118908.\n\n        Parameters\n        ----------\n        command : str\n            Command to execute\n        blocksize : int\n            Number of blocks to request.\n        job_name : str\n            Job name prefix.\n        tasks_per_node : int\n            command invocations to be launched per node\n        Returns\n        -------\n        None or str\n            None if at capacity and cannot provision more; otherwise the identifier for the job.\n        \"\"\"\n\n        logger.debug(\"Attempting to launch with blocksize: {}\".format(blocksize))\n        if self.provisioned_blocks >= self.max_blocks:\n            template = \"Provider {} is currently using {} blocks while max_blocks is {}; no blocks will be added\"\n            logger.warn(template.format(self.label, self.provisioned_blocks, self.max_blocks))\n            return None\n\n        # Note: Fix this later to avoid confusing behavior.\n        # We should always allocate blocks in integer counts of node_granularity\n        blocksize = max(self.nodes_per_block, blocksize)\n\n        job_name = \"parsl.{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        userscript_path = \"{0}/{1}.script\".format(self.script_dir, job_name)\n        userscript_path = os.path.abspath(userscript_path)\n\n        self.environment[\"JOBNAME\"] = \"'{}'\".format(job_name)\n\n        job_config = {}\n        job_config[\"job_name\"] = job_name\n        job_config[\"submit_script_dir\"] = self.channel.script_dir\n        job_config[\"project\"] = self.project\n        job_config[\"nodes\"] = self.nodes_per_block\n        job_config[\"scheduler_options\"] = self.scheduler_options\n        job_config[\"worker_init\"] = self.worker_init\n        job_config[\"user_script\"] = command\n        job_config[\"tasks_per_node\"] = tasks_per_node\n        job_config[\"requirements\"] = self.requirements\n        job_config[\"environment\"] = ' '.join(['{}={}'.format(key, value) for key, value in self.environment.items()])\n\n        # Move the user script\n        # This is where the command should be wrapped by the launchers.\n        wrapped_command = self.launcher(command,\n                                        tasks_per_node,\n                                        self.nodes_per_block)\n\n        with open(userscript_path, 'w') as f:\n            f.write(job_config[\"worker_init\"] + '\\n' + wrapped_command)\n\n        user_script_path = self.channel.push_file(userscript_path, self.channel.script_dir)\n        the_input_files = [user_script_path] + self.transfer_input_files\n        job_config[\"input_files\"] = ','.join(the_input_files)\n        job_config[\"job_script\"] = os.path.basename(user_script_path)\n\n        # Construct and move the submit script\n        self._write_submit_script(template_string, script_path, job_name, job_config)\n        channel_script_path = self.channel.push_file(script_path, self.channel.script_dir)\n\n        cmd = \"condor_submit {0}\".format(channel_script_path)\n        retcode, stdout, stderr = super().execute_wait(cmd)\n        logger.debug(\"Retcode:%s STDOUT:%s STDERR:%s\", retcode, stdout.strip(), stderr.strip())\n\n        job_id = []\n\n        if retcode == 0:\n            for line in stdout.split('\\n'):\n                if re.match('^[0-9]', line) is not None:\n                    cluster = line.split(\" \")[5]\n                    # We know the first job id (\"process\" in condor terms) within a\n                    # cluster is 0 and we know the total number of jobs from\n                    # condor_submit, so we use some list comprehensions to expand\n                    # the condor_submit output into job IDs\n                    # e.g., ['118907.0', '118907.1', '118907.2', '118907.3', '118907.4', '118908.0']\n                    processes = [str(x) for x in range(0, int(line[0]))]\n                    job_id += [cluster + process for process in processes]\n\n            self._add_resource(job_id)\n        return job_id[0]\n\n    def cancel(self, job_ids):\n        \"\"\"Cancels the jobs specified by a list of job IDs.\n\n        Parameters\n        ----------\n        job_ids : list of str\n            The job IDs to cancel.\n\n        Returns\n        -------\n        list of bool\n            Each entry in the list will be True if the job is cancelled succesfully, otherwise False.\n        \"\"\"\n\n        job_id_list = ' '.join(job_ids)\n        cmd = \"condor_rm {0}; condor_rm -forcex {0}\".format(job_id_list)\n        logger.debug(\"Attempting removal of jobs : {0}\".format(cmd))\n        retcode, stdout, stderr = super().execute_wait(cmd)\n        rets = None\n        if retcode == 0:\n            for jid in job_ids:\n                self.resources[jid]['status'] = '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    @property\n    def scaling_enabled(self):\n        return True\n\n    @property\n    def current_capacity(self):\n        return self\n\n    def _add_resource(self, job_id):\n        for jid in job_id:\n            self.resources[jid] = {'status': 'PENDING', 'size': 1}\n        return True\n\n\nif __name__ == \"__main__\":\n\n    print(\"None\")\n", "path": "parsl/providers/condor/condor.py"}]}