Skip to content

Commit c952604

Browse files
authored
Merge branch 'main' into hostlist
2 parents 37591e0 + d9d2370 commit c952604

29 files changed

+690
-289
lines changed

.mypy

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ ignore_missing_imports = True
1717
[mypy-pystache.*]
1818
ignore_missing_imports = True
1919

20+
[mypy-typing_compat.*]
21+
ignore_missing_imports = True

docs/api.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ terminal:
8787
8888
8989
JobExecutor Base Class
90-
^^^^^^^^^^^^^^
90+
^^^^^^^^^^^^^^^^^^^^^^
9191

9292
The ``psij.JobExecutor`` class is abstract, but offers concrete static methods
9393
for registering, fetching, and listing subclasses of itself.
@@ -216,7 +216,7 @@ multiple
216216
:noindex:
217217

218218
Other Package Contents
219-
----------------
219+
----------------------
220220

221221
.. automodule:: psij.exceptions
222222
:members:

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ filelock~=3.4
22
psutil~=5.9
33
pystache>=0.6.0
44
typeguard~=2.12
5+
typing-compat

src/psij/__init__.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from typing import Callable, TypeVar
88

99
from psij.descriptor import Descriptor
10-
from .exceptions import SubmitException, InvalidJobException, UnreachableStateException
10+
from .exceptions import SubmitException, InvalidJobException
1111
from .job import Job, JobStatusCallback
1212
from .job_attributes import JobAttributes
1313
from .job_executor import JobExecutor
@@ -17,15 +17,14 @@
1717
from .job_state import JobState
1818
from .job_status import JobStatus
1919
from .resource_spec import ResourceSpec, ResourceSpecV1
20-
from .serialize import Export, Import
2120
from .version import VERSION
2221

2322
__version__ = VERSION
2423

2524
__all__ = [
2625
'JobExecutor', 'JobExecutorConfig', 'Job', 'JobStatusCallback', 'JobSpec', 'JobAttributes',
2726
'JobStatus', 'JobState', 'ResourceSpec', 'ResourceSpecV1', 'Launcher', 'SubmitException',
28-
'InvalidJobException', 'UnreachableStateException', 'Export', 'Import'
27+
'InvalidJobException', 'UnreachableStateException'
2928
]
3029

3130
logger = logging.getLogger(__name__)

src/psij/exceptions.py

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -66,26 +66,3 @@ def __init__(self, message: str, exception: Optional[Exception] = None,
6666
conditions such an error would persist across subsequent re-tries until correct credentials
6767
are used.
6868
"""
69-
70-
71-
class UnreachableStateException(Exception):
72-
"""
73-
Indicates that a job state being waited for cannot be reached.
74-
75-
This exception is thrown when the :func:`~psij.Job.wait` method is called with a set of
76-
states that cannot be reached by the job when the call is made.
77-
"""
78-
79-
def __init__(self, status: 'psij.JobStatus') -> None:
80-
"""
81-
Constructs an `UnreachableStateException`.
82-
83-
:param status: The :class:`~psij.JobStatus` that the job was in when
84-
:func:`~psij.Job.wait` was called and which prevents the desired states to be
85-
reached.
86-
"""
87-
self.status = status
88-
"""
89-
Returns the job status that has caused an implementation to determine that the desired
90-
states passed to the :func:`~psij.Job.wait` method cannot be reached.
91-
"""

src/psij/executors/batch/batch_scheduler_executor.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from datetime import timedelta
88
from pathlib import Path
99
from threading import Thread, RLock
10-
from typing import Optional, List, Dict, Collection, cast, TextIO, Union
10+
from typing import Optional, List, Dict, Collection, cast, Union, IO
1111

1212
from .escape_functions import bash_escape
1313
from psij.launchers.script_based_launcher import ScriptBasedLauncher
@@ -38,6 +38,8 @@ def _attrs_to_mustache(job: Job) -> Dict[str, Union[object, List[Dict[str, objec
3838
for k, v in job.spec.attributes._custom_attributes.items():
3939
ks = k.split('.', maxsplit=1)
4040
if len(ks) == 2:
41+
# always use lower case here
42+
ks[0] = ks[0].lower()
4143
if ks[0] not in r:
4244
r[ks[0]] = []
4345
cast(List[Dict[str, object]], r[ks[0]]).append({'key': ks[1], 'value': v})
@@ -272,7 +274,7 @@ def attach(self, job: Job, native_id: str) -> None:
272274

273275
@abstractmethod
274276
def generate_submit_script(self, job: Job, context: Dict[str, object],
275-
submit_file: TextIO) -> None:
277+
submit_file: IO[str]) -> None:
276278
"""Called to generate a submit script for a job.
277279
278280
Concrete implementations of batch scheduler executors must override this method in

src/psij/executors/batch/cobalt.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""Defines a JobExecutor for the Cobalt resource manager."""
22
from datetime import timedelta
33
from pathlib import Path
4-
from typing import Optional, Collection, List, Dict, TextIO
4+
from typing import Optional, Collection, List, Dict, IO
55
import re
66
import os
77
import stat
@@ -59,7 +59,7 @@ def __init__(
5959
)
6060

6161
def generate_submit_script(
62-
self, job: Job, context: Dict[str, object], submit_file: TextIO
62+
self, job: Job, context: Dict[str, object], submit_file: IO[str]
6363
) -> None:
6464
"""See :meth:`~.BatchSchedulerExecutor.generate_submit_script`."""
6565
self.generator.generate_submit_script(job, context, submit_file)

src/psij/executors/batch/cobalt/cobalt.mustache

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,23 @@
2020
{{#queue_name}}
2121
#COBALT --queue={{.}}
2222
{{/queue_name}}
23+
{{!Like PBS, Cobalt uses specially named queues for reservations, so we send the job to the
24+
respective queue when a reservation ID is specified.}}
25+
{{#reservation_id}}
26+
#COBALT --queue={{.}}
27+
{{/reservation_id}}
2328
{{#project_name}}
2429
#COBALT --project={{.}}
2530
{{/project_name}}
26-
{{#custom_attributes.COBALT}}
27-
#COBALT --{{key}}="{{value}}"
28-
{{/custom_attributes.COBALT}}
2931
{{/job.spec.attributes}}
3032

33+
{{#custom_attributes}}
34+
{{#cobalt}}
35+
#COBALT --{{key}}="{{value}}"
36+
{{/cobalt}}
37+
{{/custom_attributes}}
38+
39+
3140
{{#env}}
3241
#COBALT --env {{name}}={{value}}
3342
{{/env}}

src/psij/executors/batch/lsf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from pathlib import Path
44
import re
55
import json
6-
from typing import Optional, Collection, List, Dict, TextIO
6+
from typing import Optional, Collection, List, Dict, IO
77

88
from psij import Job, JobStatus, JobState, SubmitException
99
from psij.executors.batch.batch_scheduler_executor import (
@@ -62,7 +62,7 @@ def __init__(self, url: Optional[str], config: Optional[LsfExecutorConfig] = Non
6262
)
6363

6464
def generate_submit_script(
65-
self, job: Job, context: Dict[str, object], submit_file: TextIO
65+
self, job: Job, context: Dict[str, object], submit_file: IO[str]
6666
) -> None:
6767
"""See :meth:`~.BatchSchedulerExecutor.generate_submit_script`."""
6868
assert job.spec is not None

src/psij/executors/batch/lsf/lsf.mustache

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@
5959

6060
{{/job.spec.attributes}}
6161

62+
{{#custom_attributes}}
63+
{{#lsf}}
64+
#BSUB -{{key}} "{{value}}"
65+
{{/lsf}}
66+
{{/custom_attributes}}
67+
68+
6269
{{!since we redirect the output manually, below, tell LSF not to do its own thing, since it
6370
only results in empty files that are not cleaned up}}
6471
#BSUB -e /dev/null

0 commit comments

Comments
 (0)