cmd-queue 0.1.19__py3-none-any.whl → 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of cmd-queue might be problematic. Click here for more details.

cmd_queue/__init__.py CHANGED
@@ -306,7 +306,7 @@ Example:
306
306
  __mkinit__ = """
307
307
  mkinit -m cmd_queue
308
308
  """
309
- __version__ = '0.1.19'
309
+ __version__ = '0.2.0'
310
310
 
311
311
 
312
312
  __submodules__ = {
cmd_queue/__main__.pyi ADDED
@@ -0,0 +1,3 @@
1
+ from _typeshed import Incomplete
2
+
3
+ main: Incomplete
@@ -0,0 +1,84 @@
1
+ from _typeshed import Incomplete
2
+ from cmd_queue import base_queue
3
+
4
+
5
+ class AirflowJob(base_queue.Job):
6
+ unused_kwargs: Incomplete
7
+ command: Incomplete
8
+ name: Incomplete
9
+ output_fpath: Incomplete
10
+ depends: Incomplete
11
+ cpus: Incomplete
12
+ gpus: Incomplete
13
+ mem: Incomplete
14
+ begin: Incomplete
15
+ shell: Incomplete
16
+
17
+ def __init__(self,
18
+ command,
19
+ name: Incomplete | None = ...,
20
+ output_fpath: Incomplete | None = ...,
21
+ depends: Incomplete | None = ...,
22
+ partition: Incomplete | None = ...,
23
+ cpus: Incomplete | None = ...,
24
+ gpus: Incomplete | None = ...,
25
+ mem: Incomplete | None = ...,
26
+ begin: Incomplete | None = ...,
27
+ shell: Incomplete | None = ...,
28
+ **kwargs) -> None:
29
+ ...
30
+
31
+ def __nice__(self):
32
+ ...
33
+
34
+ def finalize_text(self):
35
+ ...
36
+
37
+
38
+ class AirflowQueue(base_queue.Queue):
39
+ jobs: Incomplete
40
+ name: Incomplete
41
+ unused_kwargs: Incomplete
42
+ queue_id: Incomplete
43
+ dpath: Incomplete
44
+ log_dpath: Incomplete
45
+ fpath: Incomplete
46
+ shell: Incomplete
47
+ header_commands: Incomplete
48
+ all_depends: Incomplete
49
+
50
+ def __init__(self,
51
+ name: Incomplete | None = ...,
52
+ shell: Incomplete | None = ...,
53
+ **kwargs) -> None:
54
+ ...
55
+
56
+ @classmethod
57
+ def is_available(cls):
58
+ ...
59
+
60
+ def run(self, block: bool = ..., system: bool = ...) -> None:
61
+ ...
62
+
63
+ def finalize_text(self):
64
+ ...
65
+
66
+ def submit(self, command, **kwargs):
67
+ ...
68
+
69
+ def print_commands(self,
70
+ with_status: bool = ...,
71
+ with_gaurds: bool = ...,
72
+ with_locks: int = ...,
73
+ exclude_tags: Incomplete | None = ...,
74
+ style: str = ...,
75
+ with_rich: Incomplete | None = ...,
76
+ colors: int = ...,
77
+ **kwargs) -> None:
78
+ ...
79
+
80
+ rprint = print_commands
81
+
82
+
83
+ def demo() -> None:
84
+ ...
cmd_queue/base_queue.py CHANGED
@@ -135,6 +135,11 @@ class Queue(ub.NiceRepr):
135
135
  name = kwargs.get('name', None)
136
136
  if name is None:
137
137
  name = kwargs['name'] = self.name + '-job-{}'.format(self.num_real_jobs)
138
+
139
+ # TODO: make sure name is path safe.
140
+ if ':' in name:
141
+ raise ValueError('Name must be path-safe')
142
+
138
143
  if self.all_depends:
139
144
  depends = kwargs.get('depends', None)
140
145
  if depends is None:
@@ -0,0 +1,86 @@
1
+ from typing import List
2
+ import ubelt as ub
3
+ from _typeshed import Incomplete
4
+
5
+
6
+ class DuplicateJobError(KeyError):
7
+ ...
8
+
9
+
10
+ class UnknownBackendError(KeyError):
11
+ ...
12
+
13
+
14
+ class Job(ub.NiceRepr):
15
+ name: Incomplete
16
+ command: Incomplete
17
+ depends: Incomplete
18
+ kwargs: Incomplete
19
+
20
+ def __init__(self,
21
+ command: Incomplete | None = ...,
22
+ name: Incomplete | None = ...,
23
+ depends: Incomplete | None = ...,
24
+ **kwargs) -> None:
25
+ ...
26
+
27
+ def __nice__(self):
28
+ ...
29
+
30
+
31
+ class Queue(ub.NiceRepr):
32
+ num_real_jobs: int
33
+ all_depends: Incomplete
34
+ named_jobs: Incomplete
35
+
36
+ def __init__(self) -> None:
37
+ ...
38
+
39
+ def change_backend(self, backend, **kwargs):
40
+ ...
41
+
42
+ def __len__(self):
43
+ ...
44
+
45
+ def sync(self) -> Queue:
46
+ ...
47
+
48
+ def write(self):
49
+ ...
50
+
51
+ def submit(self, command, **kwargs):
52
+ ...
53
+
54
+ @classmethod
55
+ def available_backends(cls):
56
+ ...
57
+
58
+ @classmethod
59
+ def create(cls, backend: str = ..., **kwargs):
60
+ ...
61
+
62
+ def write_network_text(self,
63
+ reduced: bool = ...,
64
+ rich: str = ...,
65
+ vertical_chains: bool = ...) -> None:
66
+ ...
67
+
68
+ def print_commands(self,
69
+ with_status: bool = False,
70
+ with_gaurds: bool = False,
71
+ with_locks: bool | int = 1,
72
+ exclude_tags: List[str] | None = None,
73
+ style: str = 'colors',
74
+ **kwargs) -> None:
75
+ ...
76
+
77
+ def rprint(self, **kwargs) -> None:
78
+ ...
79
+
80
+ def print_graph(self,
81
+ reduced: bool = True,
82
+ vertical_chains: bool = ...) -> None:
83
+ ...
84
+
85
+ def monitor(self) -> None:
86
+ ...
@@ -0,0 +1,32 @@
1
+ from typing import Dict
2
+ import scriptconfig as scfg
3
+ from _typeshed import Incomplete
4
+
5
+ import cmd_queue
6
+
7
+ __docstubs__: str
8
+
9
+
10
+ class CMDQueueConfig(scfg.DataConfig):
11
+ run: Incomplete
12
+ backend: Incomplete
13
+ queue_name: Incomplete
14
+ print_commands: Incomplete
15
+ print_queue: Incomplete
16
+ with_textual: Incomplete
17
+ other_session_handler: Incomplete
18
+ virtualenv_cmd: Incomplete
19
+ tmux_workers: Incomplete
20
+ slurm_options: Incomplete
21
+
22
+ def __post_init__(self) -> None:
23
+ ...
24
+
25
+ def create_queue(config, **kwargs) -> cmd_queue.Queue:
26
+ ...
27
+
28
+ def run_queue(config,
29
+ queue: cmd_queue.Queue,
30
+ print_kwargs: None | Dict = None,
31
+ **kwargs) -> None:
32
+ ...
cmd_queue/main.py CHANGED
@@ -94,12 +94,15 @@ class CommonShowRun(CommonConfig):
94
94
 
95
95
  backend = scfg.Value('tmux', help='the execution backend to use', choices=['tmux', 'slurm', 'serial', 'airflow'])
96
96
 
97
+ gpus = scfg.Value(None, help='a comma separated list of the gpu numbers to spread across. tmux backend only.')
98
+
97
99
  def _build_queue(config):
98
100
  import cmd_queue
99
101
  import json
100
102
  queue = cmd_queue.Queue.create(size=max(1, config['workers']),
101
103
  backend=config['backend'],
102
- name=config['qname'])
104
+ name=config['qname'],
105
+ gpus=config['gpus'])
103
106
  # Run a new CLI queue
104
107
  data = json.loads(config.cli_queue_fpath.read_text())
105
108
  print('data = {}'.format(ub.urepr(data, nl=1)))
cmd_queue/main.pyi ADDED
@@ -0,0 +1,66 @@
1
+ import scriptconfig as scfg
2
+ from _typeshed import Incomplete
3
+
4
+
5
+ class CommonConfig(scfg.DataConfig):
6
+ qname: Incomplete
7
+ dpath: Incomplete
8
+
9
+ def __post_init__(config) -> None:
10
+ ...
11
+
12
+ @classmethod
13
+ def main(cls, cmdline: int = ..., **kwargs) -> None:
14
+ ...
15
+
16
+
17
+ class CommonShowRun(CommonConfig):
18
+ workers: Incomplete
19
+ backend: Incomplete
20
+
21
+
22
+ class CmdQueueCLI(scfg.ModalCLI):
23
+
24
+ class cleanup(CommonConfig):
25
+ yes: Incomplete
26
+ __command__: str
27
+
28
+ def run(config) -> None:
29
+ ...
30
+
31
+ class run(CommonShowRun):
32
+ __command__: str
33
+
34
+ def run(config) -> None:
35
+ ...
36
+
37
+ class show(CommonShowRun):
38
+ __command__: str
39
+
40
+ def run(config) -> None:
41
+ ...
42
+
43
+ class submit(CommonConfig):
44
+ jobname: Incomplete
45
+ depends: Incomplete
46
+ command: Incomplete
47
+ __command__: str
48
+
49
+ def run(config) -> None:
50
+ ...
51
+
52
+ class new(CommonConfig):
53
+ __command__: str
54
+ header: Incomplete
55
+
56
+ def run(config) -> None:
57
+ ...
58
+
59
+ class list(CommonConfig):
60
+ __command__: str
61
+
62
+ def run(config) -> None:
63
+ ...
64
+
65
+
66
+ main: Incomplete
@@ -0,0 +1,41 @@
1
+ from _typeshed import Incomplete
2
+ from cmd_queue.util.textual_extensions import InstanceRunnableApp
3
+ from textual.widget import Widget
4
+
5
+
6
+ class JobTable(Widget):
7
+ table_fn: Incomplete
8
+
9
+ def __init__(self, table_fn: Incomplete | None = ..., **kwargs) -> None:
10
+ ...
11
+
12
+ def on_mount(self) -> None:
13
+ ...
14
+
15
+ def render(self):
16
+ ...
17
+
18
+
19
+ class CmdQueueMonitorApp(InstanceRunnableApp):
20
+ job_table: Incomplete
21
+ kill_fn: Incomplete
22
+ graceful_exit: bool
23
+
24
+ def __init__(self,
25
+ table_fn,
26
+ kill_fn: Incomplete | None = ...,
27
+ **kwargs) -> None:
28
+ ...
29
+
30
+ @classmethod
31
+ def demo(CmdQueueMonitorApp):
32
+ ...
33
+
34
+ async def on_load(self, event) -> None:
35
+ ...
36
+
37
+ async def action_quit(self) -> None:
38
+ ...
39
+
40
+ async def on_mount(self, event) -> None:
41
+ ...
cmd_queue/py.typed ADDED
File without changes
@@ -0,0 +1,124 @@
1
+ from typing import List
2
+ from os import PathLike
3
+ from _typeshed import Incomplete
4
+ from cmd_queue import base_queue
5
+
6
+
7
+ def indent(text: str, prefix: str = ' '):
8
+ ...
9
+
10
+
11
+ class BashJob(base_queue.Job):
12
+ name: str
13
+ pathid: str
14
+ command: str
15
+ depends: List[BashJob] | None
16
+ bookkeeper: bool
17
+ info_dpath: PathLike | None
18
+ log: bool
19
+ tags: List[str] | str | None
20
+ allow_indent: bool
21
+ kwargs: Incomplete
22
+ pass_fpath: Incomplete
23
+ fail_fpath: Incomplete
24
+ stat_fpath: Incomplete
25
+ log_fpath: Incomplete
26
+
27
+ def __init__(self,
28
+ command,
29
+ name: Incomplete | None = ...,
30
+ depends: Incomplete | None = ...,
31
+ gpus: Incomplete | None = ...,
32
+ cpus: Incomplete | None = ...,
33
+ mem: Incomplete | None = ...,
34
+ bookkeeper: int = ...,
35
+ info_dpath: Incomplete | None = ...,
36
+ log: bool = ...,
37
+ tags: Incomplete | None = ...,
38
+ allow_indent: bool = ...,
39
+ **kwargs) -> None:
40
+ ...
41
+
42
+ def finalize_text(self,
43
+ with_status: bool = ...,
44
+ with_gaurds: bool = ...,
45
+ conditionals: Incomplete | None = ...,
46
+ **kwargs):
47
+ ...
48
+
49
+ def print_commands(self,
50
+ with_status: bool = False,
51
+ with_gaurds: bool = False,
52
+ with_rich: Incomplete | None = ...,
53
+ style: str = 'colors',
54
+ **kwargs) -> None:
55
+ ...
56
+
57
+
58
+ class SerialQueue(base_queue.Queue):
59
+ name: Incomplete
60
+ rootid: Incomplete
61
+ dpath: Incomplete
62
+ unused_kwargs: Incomplete
63
+ fpath: Incomplete
64
+ state_fpath: Incomplete
65
+ environ: Incomplete
66
+ header: str
67
+ header_commands: Incomplete
68
+ jobs: Incomplete
69
+ cwd: Incomplete
70
+ job_info_dpath: Incomplete
71
+
72
+ def __init__(self,
73
+ name: str = ...,
74
+ dpath: Incomplete | None = ...,
75
+ rootid: Incomplete | None = ...,
76
+ environ: Incomplete | None = ...,
77
+ cwd: Incomplete | None = ...,
78
+ **kwargs) -> None:
79
+ ...
80
+
81
+ @property
82
+ def pathid(self):
83
+ ...
84
+
85
+ def __nice__(self):
86
+ ...
87
+
88
+ @classmethod
89
+ def is_available(cls):
90
+ ...
91
+
92
+ def order_jobs(self) -> None:
93
+ ...
94
+
95
+ def finalize_text(self,
96
+ with_status: bool = ...,
97
+ with_gaurds: bool = ...,
98
+ with_locks: bool = ...,
99
+ exclude_tags: Incomplete | None = ...):
100
+ ...
101
+
102
+ def add_header_command(self, command) -> None:
103
+ ...
104
+
105
+ def print_commands(self, *args, **kwargs):
106
+ ...
107
+
108
+ rprint = print_commands
109
+
110
+ def run(self,
111
+ block: bool = ...,
112
+ system: bool = ...,
113
+ shell: int = ...,
114
+ capture: bool = ...,
115
+ mode: str = ...,
116
+ verbose: int = ...,
117
+ **kw) -> None:
118
+ ...
119
+
120
+ def job_details(self) -> None:
121
+ ...
122
+
123
+ def read_state(self):
124
+ ...
cmd_queue/slurm_queue.py CHANGED
@@ -41,23 +41,51 @@ from cmd_queue import base_queue # NOQA
41
41
  from cmd_queue.util import util_tags
42
42
 
43
43
 
44
- def _coerce_mem(mem):
44
+ try:
45
+ from functools import cache # Python 3.9+ only
46
+ except ImportError:
47
+ from ubelt import memoize as cache
48
+
49
+
50
+ @cache
51
+ def _unit_registery():
52
+ import sys
53
+ if sys.version_info[0:2] == (3, 9):
54
+ # backwards compatability support for numpy 2.0 and pint on cp39
55
+ try:
56
+ import numpy as np
57
+ except ImportError:
58
+ ...
59
+ else:
60
+ if not np.__version__.startswith('1.'):
61
+ np.cumproduct = np.cumprod
62
+ import pint
63
+ reg = pint.UnitRegistry()
64
+ return reg
65
+
66
+
67
+ def _coerce_mem_megabytes(mem):
45
68
  """
69
+ Transform input into an integer representing amount of megabytes.
70
+
46
71
  Args:
47
72
  mem (int | str): integer number of megabytes or a parseable string
48
73
 
74
+ Returns:
75
+ int: number of megabytes
76
+
49
77
  Example:
78
+ >>> # xdoctest: +REQUIRES(module:pint)
50
79
  >>> from cmd_queue.slurm_queue import * # NOQA
51
- >>> print(_coerce_mem(30602))
52
- >>> print(_coerce_mem('4GB'))
53
- >>> print(_coerce_mem('32GB'))
54
- >>> print(_coerce_mem('300000000 bytes'))
80
+ >>> print(_coerce_mem_megabytes(30602))
81
+ >>> print(_coerce_mem_megabytes('4GB'))
82
+ >>> print(_coerce_mem_megabytes('32GB'))
83
+ >>> print(_coerce_mem_megabytes('300000000 bytes'))
55
84
  """
56
85
  if isinstance(mem, int):
57
86
  assert mem > 0
58
87
  elif isinstance(mem, str):
59
- import pint
60
- reg = pint.UnitRegistry()
88
+ reg = _unit_registery()
61
89
  mem = reg.parse_expression(mem)
62
90
  mem = int(mem.to('megabytes').m)
63
91
  else:
@@ -190,6 +218,7 @@ class SlurmJob(base_queue.Job):
190
218
  Represents a slurm job that hasn't been submitted yet
191
219
 
192
220
  Example:
221
+ >>> # xdoctest: +REQUIRES(module:pint)
193
222
  >>> from cmd_queue.slurm_queue import * # NOQA
194
223
  >>> self = SlurmJob('python -c print("hello world")', 'hi', cpus=5, gpus=1, mem='10GB')
195
224
  >>> command = self._build_sbatch_args()
@@ -245,7 +274,7 @@ class SlurmJob(base_queue.Job):
245
274
  if self.cpus:
246
275
  sbatch_args.append(f'--cpus-per-task={self.cpus}')
247
276
  if self.mem:
248
- mem = _coerce_mem(self.mem)
277
+ mem = _coerce_mem_megabytes(self.mem)
249
278
  sbatch_args.append(f'--mem={mem}')
250
279
  if self.gpus and 'gres' not in self._sbatch_kvargs:
251
280
  ub.schedule_deprecation(
@@ -0,0 +1,97 @@
1
+ from _typeshed import Incomplete
2
+ from cmd_queue import base_queue
3
+
4
+ __dev__: str
5
+ SLURM_SBATCH_KVARGS: Incomplete
6
+ SLURM_SBATCH_FLAGS: Incomplete
7
+
8
+
9
+ class SlurmJob(base_queue.Job):
10
+ unused_kwargs: Incomplete
11
+ command: Incomplete
12
+ name: Incomplete
13
+ output_fpath: Incomplete
14
+ depends: Incomplete
15
+ cpus: Incomplete
16
+ gpus: Incomplete
17
+ mem: Incomplete
18
+ begin: Incomplete
19
+ shell: Incomplete
20
+ tags: Incomplete
21
+ jobid: Incomplete
22
+
23
+ def __init__(self,
24
+ command,
25
+ name: Incomplete | None = ...,
26
+ output_fpath: Incomplete | None = ...,
27
+ depends: Incomplete | None = ...,
28
+ cpus: Incomplete | None = ...,
29
+ gpus: Incomplete | None = ...,
30
+ mem: Incomplete | None = ...,
31
+ begin: Incomplete | None = ...,
32
+ shell: Incomplete | None = ...,
33
+ tags: Incomplete | None = ...,
34
+ **kwargs) -> None:
35
+ ...
36
+
37
+ def __nice__(self):
38
+ ...
39
+
40
+
41
+ class SlurmQueue(base_queue.Queue):
42
+ jobs: Incomplete
43
+ unused_kwargs: Incomplete
44
+ queue_id: Incomplete
45
+ dpath: Incomplete
46
+ log_dpath: Incomplete
47
+ fpath: Incomplete
48
+ shell: Incomplete
49
+ header_commands: Incomplete
50
+ all_depends: Incomplete
51
+
52
+ def __init__(self,
53
+ name: Incomplete | None = ...,
54
+ shell: Incomplete | None = ...,
55
+ **kwargs) -> None:
56
+ ...
57
+
58
+ def __nice__(self):
59
+ ...
60
+
61
+ @classmethod
62
+ def is_available(cls):
63
+ ...
64
+
65
+ def submit(self, command, **kwargs):
66
+ ...
67
+
68
+ def add_header_command(self, command) -> None:
69
+ ...
70
+
71
+ def order_jobs(self):
72
+ ...
73
+
74
+ jobname_to_varname: Incomplete
75
+
76
+ def finalize_text(self, exclude_tags: Incomplete | None = ..., **kwargs):
77
+ ...
78
+
79
+ def run(self, block: bool = ..., system: bool = ..., **kw):
80
+ ...
81
+
82
+ def monitor(self, refresh_rate: float = ...):
83
+ ...
84
+
85
+ def kill(self) -> None:
86
+ ...
87
+
88
+ def read_state(self):
89
+ ...
90
+
91
+ def print_commands(self, *args, **kwargs):
92
+ ...
93
+
94
+ rprint = print_commands
95
+
96
+
97
+ SLURM_NOTES: str
cmd_queue/tmux_queue.py CHANGED
@@ -1055,4 +1055,24 @@ if 0:
1055
1055
  tmux kill-session -t my_session_id
1056
1056
 
1057
1057
  tmux new-session -d -s my_session_id -e "MYVAR1" -- "bash"
1058
+
1059
+
1060
+
1061
+ #### to start a tmux session with 4 panes
1062
+ tmux new-session -d -s my_session_id1 "bash"
1063
+ tmux send -t my_session_id1 "tmux split-window -h -t 0" Enter
1064
+ tmux send -t my_session_id1 "tmux split-window -v -t 0" Enter
1065
+ tmux send -t my_session_id1 "tmux split-window -v -t 2" Enter
1066
+
1067
+ # Now send a command to each pane
1068
+ tmux send -t my_session_id1 "tmux select-pane -t 0" Enter
1069
+ tmux send -t my_session_id1 "echo pane0" Enter
1070
+ tmux send -t my_session_id1 "tmux select-pane -t 1" Enter
1071
+ tmux send -t my_session_id1 "echo pane1" Enter
1072
+ tmux send -t my_session_id1 "tmux select-pane -t 2" Enter
1073
+ tmux send -t my_session_id1 "echo pane2" Enter
1074
+ tmux send -t my_session_id1 "tmux select-pane -t 3" Enter
1075
+ tmux send -t my_session_id1 "echo pane3" Enter
1076
+
1077
+
1058
1078
  """