hpc-runner 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.
- hpc_runner/__init__.py +57 -0
- hpc_runner/_version.py +34 -0
- hpc_runner/cli/__init__.py +1 -0
- hpc_runner/cli/cancel.py +38 -0
- hpc_runner/cli/config.py +109 -0
- hpc_runner/cli/main.py +76 -0
- hpc_runner/cli/monitor.py +30 -0
- hpc_runner/cli/run.py +292 -0
- hpc_runner/cli/status.py +66 -0
- hpc_runner/core/__init__.py +31 -0
- hpc_runner/core/config.py +177 -0
- hpc_runner/core/descriptors.py +110 -0
- hpc_runner/core/exceptions.py +38 -0
- hpc_runner/core/job.py +328 -0
- hpc_runner/core/job_array.py +58 -0
- hpc_runner/core/job_info.py +104 -0
- hpc_runner/core/resources.py +49 -0
- hpc_runner/core/result.py +161 -0
- hpc_runner/core/types.py +13 -0
- hpc_runner/py.typed +0 -0
- hpc_runner/schedulers/__init__.py +60 -0
- hpc_runner/schedulers/base.py +194 -0
- hpc_runner/schedulers/detection.py +52 -0
- hpc_runner/schedulers/local/__init__.py +5 -0
- hpc_runner/schedulers/local/scheduler.py +354 -0
- hpc_runner/schedulers/local/templates/job.sh.j2 +28 -0
- hpc_runner/schedulers/sge/__init__.py +5 -0
- hpc_runner/schedulers/sge/args.py +232 -0
- hpc_runner/schedulers/sge/parser.py +287 -0
- hpc_runner/schedulers/sge/scheduler.py +881 -0
- hpc_runner/schedulers/sge/templates/batch.sh.j2 +82 -0
- hpc_runner/schedulers/sge/templates/interactive.sh.j2 +78 -0
- hpc_runner/templates/__init__.py +5 -0
- hpc_runner/templates/engine.py +55 -0
- hpc_runner/tui/__init__.py +5 -0
- hpc_runner/tui/app.py +436 -0
- hpc_runner/tui/components/__init__.py +17 -0
- hpc_runner/tui/components/detail_panel.py +187 -0
- hpc_runner/tui/components/filter_bar.py +174 -0
- hpc_runner/tui/components/filter_popup.py +345 -0
- hpc_runner/tui/components/job_table.py +260 -0
- hpc_runner/tui/providers/__init__.py +5 -0
- hpc_runner/tui/providers/jobs.py +197 -0
- hpc_runner/tui/screens/__init__.py +7 -0
- hpc_runner/tui/screens/confirm.py +67 -0
- hpc_runner/tui/screens/job_details.py +210 -0
- hpc_runner/tui/screens/log_viewer.py +170 -0
- hpc_runner/tui/snapshot.py +153 -0
- hpc_runner/tui/styles/monitor.tcss +567 -0
- hpc_runner/workflow/__init__.py +6 -0
- hpc_runner/workflow/dependency.py +20 -0
- hpc_runner/workflow/pipeline.py +180 -0
- hpc_runner-0.2.0.dist-info/METADATA +285 -0
- hpc_runner-0.2.0.dist-info/RECORD +56 -0
- hpc_runner-0.2.0.dist-info/WHEEL +4 -0
- hpc_runner-0.2.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"""Pipeline API for job workflows with dependencies."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
|
+
|
|
8
|
+
from hpc_runner.core.job import Job
|
|
9
|
+
from hpc_runner.workflow.dependency import DependencyType
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from hpc_runner.core.result import JobResult
|
|
13
|
+
from hpc_runner.schedulers.base import BaseScheduler
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class PipelineJob:
|
|
18
|
+
"""A job within a pipeline."""
|
|
19
|
+
|
|
20
|
+
job: Job
|
|
21
|
+
name: str
|
|
22
|
+
depends_on: list[PipelineJob] = field(default_factory=list)
|
|
23
|
+
result: JobResult | None = None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Pipeline:
|
|
27
|
+
"""Workflow pipeline with job dependencies.
|
|
28
|
+
|
|
29
|
+
Example:
|
|
30
|
+
with Pipeline("build-test") as p:
|
|
31
|
+
build = p.add("make build", name="build", cpu=4)
|
|
32
|
+
test = p.add("make test", name="test", depends_on=["build"])
|
|
33
|
+
package = p.add("make package", name="package", depends_on=["test"])
|
|
34
|
+
|
|
35
|
+
results = p.submit()
|
|
36
|
+
p.wait()
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def __init__(self, name: str = "pipeline") -> None:
|
|
40
|
+
self.name = name
|
|
41
|
+
self.jobs: list[PipelineJob] = []
|
|
42
|
+
self._name_map: dict[str, PipelineJob] = {}
|
|
43
|
+
self._submitted = False
|
|
44
|
+
|
|
45
|
+
def add(
|
|
46
|
+
self,
|
|
47
|
+
command: str,
|
|
48
|
+
name: str | None = None,
|
|
49
|
+
depends_on: list[str | PipelineJob] | None = None,
|
|
50
|
+
**job_kwargs: Any,
|
|
51
|
+
) -> PipelineJob:
|
|
52
|
+
"""Add a job to the pipeline.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
command: Command to execute
|
|
56
|
+
name: Job name (auto-generated if None)
|
|
57
|
+
depends_on: List of job names or PipelineJob objects
|
|
58
|
+
**job_kwargs: Additional Job parameters
|
|
59
|
+
"""
|
|
60
|
+
if name is None:
|
|
61
|
+
name = f"step_{len(self.jobs) + 1}"
|
|
62
|
+
|
|
63
|
+
if name in self._name_map:
|
|
64
|
+
raise ValueError(f"Job name '{name}' already exists in pipeline")
|
|
65
|
+
|
|
66
|
+
job = Job(command=command, name=f"{self.name}_{name}", **job_kwargs)
|
|
67
|
+
|
|
68
|
+
dependencies: list[PipelineJob] = []
|
|
69
|
+
if depends_on:
|
|
70
|
+
for dep in depends_on:
|
|
71
|
+
if isinstance(dep, str):
|
|
72
|
+
if dep not in self._name_map:
|
|
73
|
+
raise ValueError(f"Unknown dependency: {dep}")
|
|
74
|
+
dependencies.append(self._name_map[dep])
|
|
75
|
+
else:
|
|
76
|
+
dependencies.append(dep)
|
|
77
|
+
|
|
78
|
+
pipeline_job = PipelineJob(job=job, name=name, depends_on=dependencies)
|
|
79
|
+
self.jobs.append(pipeline_job)
|
|
80
|
+
self._name_map[name] = pipeline_job
|
|
81
|
+
|
|
82
|
+
return pipeline_job
|
|
83
|
+
|
|
84
|
+
def submit(
|
|
85
|
+
self,
|
|
86
|
+
scheduler: BaseScheduler | None = None,
|
|
87
|
+
dependency_type: DependencyType = DependencyType.AFTEROK,
|
|
88
|
+
) -> dict[str, JobResult]:
|
|
89
|
+
"""Submit all jobs respecting dependencies.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
scheduler: Scheduler to use (auto-detect if None)
|
|
93
|
+
dependency_type: Type of dependency to use
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
Dict mapping job names to results
|
|
97
|
+
"""
|
|
98
|
+
from hpc_runner.schedulers import get_scheduler
|
|
99
|
+
|
|
100
|
+
if self._submitted:
|
|
101
|
+
raise RuntimeError("Pipeline has already been submitted")
|
|
102
|
+
|
|
103
|
+
if scheduler is None:
|
|
104
|
+
scheduler = get_scheduler()
|
|
105
|
+
|
|
106
|
+
results: dict[str, JobResult] = {}
|
|
107
|
+
|
|
108
|
+
for pjob in self._topological_sort():
|
|
109
|
+
# Set up dependencies
|
|
110
|
+
if pjob.depends_on:
|
|
111
|
+
dep_results = [results[d.name] for d in pjob.depends_on]
|
|
112
|
+
pjob.job.dependencies = dep_results
|
|
113
|
+
pjob.job.dependency_type = str(dependency_type)
|
|
114
|
+
|
|
115
|
+
# Submit
|
|
116
|
+
result = scheduler.submit(pjob.job)
|
|
117
|
+
pjob.result = result
|
|
118
|
+
results[pjob.name] = result
|
|
119
|
+
|
|
120
|
+
self._submitted = True
|
|
121
|
+
return results
|
|
122
|
+
|
|
123
|
+
def _topological_sort(self) -> list[PipelineJob]:
|
|
124
|
+
"""Sort jobs by dependency order (Kahn's algorithm)."""
|
|
125
|
+
# Build in-degree map
|
|
126
|
+
in_degree: dict[str, int] = {pj.name: 0 for pj in self.jobs}
|
|
127
|
+
for pj in self.jobs:
|
|
128
|
+
for dep in pj.depends_on:
|
|
129
|
+
in_degree[pj.name] += 1
|
|
130
|
+
|
|
131
|
+
# Find all jobs with no dependencies
|
|
132
|
+
queue = [pj for pj in self.jobs if in_degree[pj.name] == 0]
|
|
133
|
+
result: list[PipelineJob] = []
|
|
134
|
+
|
|
135
|
+
while queue:
|
|
136
|
+
pj = queue.pop(0)
|
|
137
|
+
result.append(pj)
|
|
138
|
+
|
|
139
|
+
# Reduce in-degree for dependent jobs
|
|
140
|
+
for other_pj in self.jobs:
|
|
141
|
+
if pj in other_pj.depends_on:
|
|
142
|
+
in_degree[other_pj.name] -= 1
|
|
143
|
+
if in_degree[other_pj.name] == 0:
|
|
144
|
+
queue.append(other_pj)
|
|
145
|
+
|
|
146
|
+
if len(result) != len(self.jobs):
|
|
147
|
+
raise ValueError("Circular dependency detected in pipeline")
|
|
148
|
+
|
|
149
|
+
return result
|
|
150
|
+
|
|
151
|
+
def wait(self, poll_interval: float = 5.0) -> dict[str, JobResult]:
|
|
152
|
+
"""Wait for all jobs to complete.
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
Dict mapping job names to results
|
|
156
|
+
"""
|
|
157
|
+
if not self._submitted:
|
|
158
|
+
raise RuntimeError("Pipeline has not been submitted")
|
|
159
|
+
|
|
160
|
+
for pjob in self.jobs:
|
|
161
|
+
if pjob.result:
|
|
162
|
+
pjob.result.wait(poll_interval=poll_interval)
|
|
163
|
+
|
|
164
|
+
return {pj.name: pj.result for pj in self.jobs if pj.result}
|
|
165
|
+
|
|
166
|
+
def get_job(self, name: str) -> PipelineJob | None:
|
|
167
|
+
"""Get a job by name."""
|
|
168
|
+
return self._name_map.get(name)
|
|
169
|
+
|
|
170
|
+
def __enter__(self) -> Pipeline:
|
|
171
|
+
return self
|
|
172
|
+
|
|
173
|
+
def __exit__(self, *args: Any) -> None:
|
|
174
|
+
pass
|
|
175
|
+
|
|
176
|
+
def __len__(self) -> int:
|
|
177
|
+
return len(self.jobs)
|
|
178
|
+
|
|
179
|
+
def __iter__(self):
|
|
180
|
+
return iter(self.jobs)
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hpc-runner
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Unified HPC job submission across multiple schedulers
|
|
5
|
+
Project-URL: Homepage, https://github.com/sjalloq/hpc-runner
|
|
6
|
+
Project-URL: Repository, https://github.com/sjalloq/hpc-runner
|
|
7
|
+
Author: Shareef Jalloq
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Keywords: cluster,hpc,job-submission,pbs,sge,slurm
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: System :: Clustering
|
|
21
|
+
Classifier: Topic :: System :: Distributed Computing
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: jinja2>=3.0
|
|
24
|
+
Requires-Dist: rich-click>=1.7
|
|
25
|
+
Requires-Dist: textual>=6.11
|
|
26
|
+
Requires-Dist: tomli>=2.0; python_version < '3.11'
|
|
27
|
+
Provides-Extra: all
|
|
28
|
+
Requires-Dist: build; extra == 'all'
|
|
29
|
+
Requires-Dist: hatch-vcs; extra == 'all'
|
|
30
|
+
Requires-Dist: mypy; extra == 'all'
|
|
31
|
+
Requires-Dist: pytest-cov; extra == 'all'
|
|
32
|
+
Requires-Dist: pytest>=7.0; extra == 'all'
|
|
33
|
+
Requires-Dist: ruff; extra == 'all'
|
|
34
|
+
Requires-Dist: twine; extra == 'all'
|
|
35
|
+
Provides-Extra: dev
|
|
36
|
+
Requires-Dist: build; extra == 'dev'
|
|
37
|
+
Requires-Dist: hatch-vcs; extra == 'dev'
|
|
38
|
+
Requires-Dist: mypy; extra == 'dev'
|
|
39
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
40
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
41
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
42
|
+
Requires-Dist: twine; extra == 'dev'
|
|
43
|
+
Description-Content-Type: text/markdown
|
|
44
|
+
|
|
45
|
+
# hpc-runner
|
|
46
|
+
|
|
47
|
+
**Unified HPC job submission across multiple schedulers**
|
|
48
|
+
|
|
49
|
+
Write your jobs once, run them on any cluster - SGE, Slurm, PBS, or locally for testing.
|
|
50
|
+
|
|
51
|
+
## Features
|
|
52
|
+
|
|
53
|
+
- **Unified CLI** - Same commands work across SGE, Slurm, PBS
|
|
54
|
+
- **Python API** - Programmatic job submission with dependencies and pipelines
|
|
55
|
+
- **Auto-detection** - Automatically finds your cluster's scheduler
|
|
56
|
+
- **Interactive TUI** - Monitor jobs with a terminal dashboard
|
|
57
|
+
- **Job Dependencies** - Chain jobs with afterok, afterany, afternotok
|
|
58
|
+
- **Array Jobs** - Batch processing with throttling support
|
|
59
|
+
- **Virtual Environment Handling** - Automatic venv activation on compute nodes
|
|
60
|
+
- **Module Integration** - Load environment modules in job scripts
|
|
61
|
+
- **Dry-run Mode** - Preview generated scripts before submission
|
|
62
|
+
|
|
63
|
+
## Installation
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
pip install hpc-runner
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Or with uv:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
uv pip install hpc-runner
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Quick Start
|
|
76
|
+
|
|
77
|
+
### CLI
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Basic job submission
|
|
81
|
+
hpc run python train.py
|
|
82
|
+
|
|
83
|
+
# With resources
|
|
84
|
+
hpc run --cpu 4 --mem 16G --time 4:00:00 "python train.py"
|
|
85
|
+
|
|
86
|
+
# GPU job
|
|
87
|
+
hpc run --queue gpu --cpu 4 --mem 32G "python train.py --epochs 100"
|
|
88
|
+
|
|
89
|
+
# Preview without submitting
|
|
90
|
+
hpc run --dry-run --cpu 8 "make -j8"
|
|
91
|
+
|
|
92
|
+
# Interactive session
|
|
93
|
+
hpc run --interactive bash
|
|
94
|
+
|
|
95
|
+
# Array job
|
|
96
|
+
hpc run --array 1-100 "python process.py --task-id \$SGE_TASK_ID"
|
|
97
|
+
|
|
98
|
+
# Wait for completion
|
|
99
|
+
hpc run --wait python long_job.py
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Python API
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from hpc_runner import Job
|
|
106
|
+
|
|
107
|
+
# Create and submit a job
|
|
108
|
+
job = Job(
|
|
109
|
+
command="python train.py",
|
|
110
|
+
cpu=4,
|
|
111
|
+
mem="16G",
|
|
112
|
+
time="4:00:00",
|
|
113
|
+
queue="gpu",
|
|
114
|
+
)
|
|
115
|
+
result = job.submit()
|
|
116
|
+
|
|
117
|
+
# Wait for completion
|
|
118
|
+
status = result.wait()
|
|
119
|
+
print(f"Exit code: {result.returncode}")
|
|
120
|
+
|
|
121
|
+
# Read output
|
|
122
|
+
print(result.read_stdout())
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Job Dependencies
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from hpc_runner import Job
|
|
129
|
+
|
|
130
|
+
# First job
|
|
131
|
+
preprocess = Job(command="python preprocess.py", cpu=8, mem="32G")
|
|
132
|
+
result1 = preprocess.submit()
|
|
133
|
+
|
|
134
|
+
# Second job runs after first succeeds
|
|
135
|
+
train = Job(command="python train.py", cpu=4, mem="48G", queue="gpu")
|
|
136
|
+
train.after(result1, type="afterok")
|
|
137
|
+
result2 = train.submit()
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Pipelines
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
from hpc_runner import Pipeline
|
|
144
|
+
|
|
145
|
+
with Pipeline("ml_workflow") as p:
|
|
146
|
+
p.add("python preprocess.py", name="preprocess", cpu=8)
|
|
147
|
+
p.add("python train.py", name="train", depends_on=["preprocess"], queue="gpu")
|
|
148
|
+
p.add("python evaluate.py", name="evaluate", depends_on=["train"])
|
|
149
|
+
|
|
150
|
+
results = p.submit()
|
|
151
|
+
p.wait()
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Scheduler Support
|
|
155
|
+
|
|
156
|
+
| Scheduler | Status | Notes |
|
|
157
|
+
|-----------|--------|-------|
|
|
158
|
+
| SGE | Fully implemented | qsub, qstat, qdel, qrsh |
|
|
159
|
+
| Local | Fully implemented | Run as subprocess (for testing) |
|
|
160
|
+
| Slurm | Planned | sbatch, squeue, scancel |
|
|
161
|
+
| PBS | Planned | qsub, qstat, qdel |
|
|
162
|
+
|
|
163
|
+
### Auto-detection Priority
|
|
164
|
+
|
|
165
|
+
1. `HPC_SCHEDULER` environment variable
|
|
166
|
+
2. SGE (`SGE_ROOT` or `qstat` available)
|
|
167
|
+
3. Slurm (`sbatch` available)
|
|
168
|
+
4. PBS (`qsub` with PBS)
|
|
169
|
+
5. Local fallback
|
|
170
|
+
|
|
171
|
+
## Configuration
|
|
172
|
+
|
|
173
|
+
hpc-runner uses TOML configuration files. Location priority:
|
|
174
|
+
|
|
175
|
+
1. `--config /path/to/config.toml`
|
|
176
|
+
2. `./hpc-tools.toml`
|
|
177
|
+
3. `./pyproject.toml` under `[tool.hpc-tools]`
|
|
178
|
+
4. Git repository root `hpc-tools.toml`
|
|
179
|
+
5. `~/.config/hpc-tools/config.toml`
|
|
180
|
+
6. Package defaults
|
|
181
|
+
|
|
182
|
+
### Example Configuration
|
|
183
|
+
|
|
184
|
+
```toml
|
|
185
|
+
[defaults]
|
|
186
|
+
cpu = 1
|
|
187
|
+
mem = "4G"
|
|
188
|
+
time = "1:00:00"
|
|
189
|
+
inherit_env = true
|
|
190
|
+
|
|
191
|
+
[schedulers.sge]
|
|
192
|
+
parallel_environment = "smp"
|
|
193
|
+
memory_resource = "mem_free"
|
|
194
|
+
purge_modules = true
|
|
195
|
+
|
|
196
|
+
[types.gpu]
|
|
197
|
+
queue = "gpu"
|
|
198
|
+
resources = [{name = "gpu", value = 1}]
|
|
199
|
+
|
|
200
|
+
[types.interactive]
|
|
201
|
+
queue = "interactive"
|
|
202
|
+
time = "8:00:00"
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Use named job types:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
hpc run --job-type gpu "python train.py"
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## TUI Monitor
|
|
212
|
+
|
|
213
|
+
Launch the interactive job monitor:
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
hpc monitor
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Key bindings:
|
|
220
|
+
- `q` - Quit
|
|
221
|
+
- `r` - Refresh
|
|
222
|
+
- `u` - Toggle user filter (my jobs / all)
|
|
223
|
+
- `/` - Search
|
|
224
|
+
- `Enter` - View job details
|
|
225
|
+
- `Tab` - Switch tabs
|
|
226
|
+
|
|
227
|
+
## CLI Reference
|
|
228
|
+
|
|
229
|
+
```
|
|
230
|
+
hpc run [OPTIONS] COMMAND
|
|
231
|
+
|
|
232
|
+
Options:
|
|
233
|
+
--job-name TEXT Job name
|
|
234
|
+
--cpu INTEGER Number of CPUs
|
|
235
|
+
--mem TEXT Memory (e.g., 16G, 4096M)
|
|
236
|
+
--time TEXT Time limit (e.g., 4:00:00)
|
|
237
|
+
--queue TEXT Queue/partition name
|
|
238
|
+
--directory PATH Working directory
|
|
239
|
+
--module TEXT Module to load (repeatable)
|
|
240
|
+
--array TEXT Array spec (e.g., 1-100, 1-100%5)
|
|
241
|
+
--depend TEXT Job dependencies
|
|
242
|
+
--inherit-env Inherit environment (default: true)
|
|
243
|
+
--no-inherit-env Don't inherit environment
|
|
244
|
+
--interactive Run interactively (qrsh/srun)
|
|
245
|
+
--local Run locally (no scheduler)
|
|
246
|
+
--dry-run Show script without submitting
|
|
247
|
+
--wait Wait for completion
|
|
248
|
+
--keep-script Keep job script for debugging
|
|
249
|
+
-h, --help Show help
|
|
250
|
+
|
|
251
|
+
Other commands:
|
|
252
|
+
hpc status [JOB_ID] Check job status
|
|
253
|
+
hpc cancel JOB_ID Cancel a job
|
|
254
|
+
hpc monitor Interactive TUI
|
|
255
|
+
hpc config show Show active configuration
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Development
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
# Setup environment
|
|
262
|
+
source sourceme
|
|
263
|
+
source sourceme --clean # Clean rebuild
|
|
264
|
+
|
|
265
|
+
# Run tests
|
|
266
|
+
pytest
|
|
267
|
+
pytest -v
|
|
268
|
+
pytest -k "test_job"
|
|
269
|
+
|
|
270
|
+
# Type checking
|
|
271
|
+
mypy src/hpc_runner
|
|
272
|
+
|
|
273
|
+
# Linting
|
|
274
|
+
ruff check src/hpc_runner
|
|
275
|
+
ruff format src/hpc_runner
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Documentation
|
|
279
|
+
|
|
280
|
+
- [Programmatic API Reference](docs/programmatic_api.md)
|
|
281
|
+
- [TUI Styling Guide](docs/TEXTUAL_STYLING_COOKBOOK.md)
|
|
282
|
+
|
|
283
|
+
## License
|
|
284
|
+
|
|
285
|
+
MIT License - see LICENSE file for details.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
hpc_runner/__init__.py,sha256=1xnewzCt8FVqseOG5PRmLbiMz0I8V8_TrTyIjW0Q8_A,1414
|
|
2
|
+
hpc_runner/_version.py,sha256=Dg8AmJomLVpjKL6prJylOONZAPRtB86LOce7dorQS_A,704
|
|
3
|
+
hpc_runner/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
hpc_runner/cli/__init__.py,sha256=SkyeG7kzxbBGgO9fU96VvHjMjLaSdGI3KFVcqeUAYtg,25
|
|
5
|
+
hpc_runner/cli/cancel.py,sha256=8qRkPjlSGs6OGs7-_ilwpUlWpGQe7ch8aB_rEWiiLAI,901
|
|
6
|
+
hpc_runner/cli/config.py,sha256=dxNNOyuUyzuk9UUUaELp5WkhHrkZnXGi7zQkJdUl4YA,2920
|
|
7
|
+
hpc_runner/cli/main.py,sha256=Did1C3P0Cz7VjuR_a4a0dgHD9u_an_kxaBLNcMWYHR4,2061
|
|
8
|
+
hpc_runner/cli/monitor.py,sha256=aqr39IqwEUz_eczDLMw1dyfs_Gz6mtqKM2eMHI80f4g,698
|
|
9
|
+
hpc_runner/cli/run.py,sha256=fGK0gwIiQdUl0i2aC5FnwSs9MmuKF6ZZFgg7pn2NitU,9646
|
|
10
|
+
hpc_runner/cli/status.py,sha256=LMKvfIiR2U-r8kZOLw1L1-Xfli0mCtX-sSqI6_gy0i0,1957
|
|
11
|
+
hpc_runner/core/__init__.py,sha256=C6R3f_AWv5KOfZ3p2iJiht2B2r1LC62atHWntz51o9c,643
|
|
12
|
+
hpc_runner/core/config.py,sha256=UTbJnIveShGAS_YtS_tRT8H-_Jzq1qGidg3qSQZL6_Q,5184
|
|
13
|
+
hpc_runner/core/descriptors.py,sha256=xaoK3-YbVUcBdeumaY4JZ9noq-d5fqglIwZQqsWvYzU,3307
|
|
14
|
+
hpc_runner/core/exceptions.py,sha256=Z5JIzbpznCCx-wT4uZtHtwxstKZGIAxMubCJV64QzOc,889
|
|
15
|
+
hpc_runner/core/job.py,sha256=N_7HpDzxJipbJU0nVHOoYuaVAGjEXfMzgxJ9ve54mok,11052
|
|
16
|
+
hpc_runner/core/job_array.py,sha256=7VHoZHRzN5JvzWZ_e5pAMeTrNB7-OZw06A8548oK8_c,1595
|
|
17
|
+
hpc_runner/core/job_info.py,sha256=QE4iHH3uqYp4KdvZmBtfFUUaZfmPLkrF6LtlK4RuSJM,2858
|
|
18
|
+
hpc_runner/core/resources.py,sha256=ng1biVsXgGy6AWG50I50aC4LWB1pd60qFLpj5FjIpQc,1275
|
|
19
|
+
hpc_runner/core/result.py,sha256=UGw6ZRmdGI4oVD5ENzrSK72Igx7QNo-OJX9hLVyldp8,4914
|
|
20
|
+
hpc_runner/core/types.py,sha256=a6Yq7vhcpBwgA_hGZwGXiZgCy8wG87FIXBT3LN5qHw8,251
|
|
21
|
+
hpc_runner/schedulers/__init__.py,sha256=v55_DYgiigiFjXJhI7_XFtvxHoyDFWOntWRB9-HWMrM,1623
|
|
22
|
+
hpc_runner/schedulers/base.py,sha256=vhugT9lFrSZb8BMDO_x-h4nSF2oLg2nOvd347g3qfUY,6223
|
|
23
|
+
hpc_runner/schedulers/detection.py,sha256=b5_qdyroMQsvIf_DYY_RDoje6ozKLA3RS-fWWNR9qUU,1467
|
|
24
|
+
hpc_runner/schedulers/local/__init__.py,sha256=bM0RT5SBxs7TsGDUeUi--Z_vlVt9dgokJcftX92VE58,147
|
|
25
|
+
hpc_runner/schedulers/local/scheduler.py,sha256=tTq_5uZEIYCjK3PmPjI_iBAPijwUlTmSaLNoy4_AB5c,13310
|
|
26
|
+
hpc_runner/schedulers/local/templates/job.sh.j2,sha256=pv_R20o5G3LU-DIEIC7gpt7fYIZJmzkrIQEwmVkUWUI,522
|
|
27
|
+
hpc_runner/schedulers/sge/__init__.py,sha256=aR_jJD-YA0HOYPaBwW_CEwi3PASXY2x9sOfmrj6-cjM,144
|
|
28
|
+
hpc_runner/schedulers/sge/args.py,sha256=LBRj4UUDJ5jR8tEoCVF4ivjEKjqDI6LMvFsFzTgtOwk,6553
|
|
29
|
+
hpc_runner/schedulers/sge/parser.py,sha256=P6bG7II2icqSrnzgxGanPITV12X1zMvWYV04L6RIH2c,8381
|
|
30
|
+
hpc_runner/schedulers/sge/scheduler.py,sha256=-vz58MQzaJD97TqE4KfrnR3drLhQgHy8bpjpNwpHt2s,31998
|
|
31
|
+
hpc_runner/schedulers/sge/templates/batch.sh.j2,sha256=au-Hr7o55J1SutLLlpcTBJhRvQYHM4d9bSHk95u3nv4,1696
|
|
32
|
+
hpc_runner/schedulers/sge/templates/interactive.sh.j2,sha256=CY_hcmWoK8EuBNHmP7_lrfMf_i5BjZn8YY9Fi4ousZI,1622
|
|
33
|
+
hpc_runner/templates/__init__.py,sha256=kiaaYBS4QXfGie83SS0rfmZtlbyRUkGkR_yw04oExNQ,137
|
|
34
|
+
hpc_runner/templates/engine.py,sha256=XDW9C51rz9O2rcB3mpjVHQ0qkeG4386gXa8fwaDYsxs,1393
|
|
35
|
+
hpc_runner/tui/__init__.py,sha256=xuet6Iz1ZL6Ys5h95DMcuiapZNo8QA-sFU3R0NflbgE,136
|
|
36
|
+
hpc_runner/tui/app.py,sha256=rsiA2ViNGkfo6pWf2lvVRM3LVM1MunLB8CcNMLHRzso,16466
|
|
37
|
+
hpc_runner/tui/snapshot.py,sha256=sAcxdGaKsFXQMByPip-o1YwFaU-MLf_jGwDlZvEYTxY,5194
|
|
38
|
+
hpc_runner/tui/components/__init__.py,sha256=cS1VT2uhaWDq18-FvT9Hje_Uev7pI8WGFgWVNERfJMQ,303
|
|
39
|
+
hpc_runner/tui/components/detail_panel.py,sha256=3sRxO8J6ceBUctKm-LSF_aujIa63TEdWZJt2v08ae28,6983
|
|
40
|
+
hpc_runner/tui/components/filter_bar.py,sha256=v3YqUnieTzipJCaUHsVIcXc1VwTM3TorYBW-H6Ai5vo,4965
|
|
41
|
+
hpc_runner/tui/components/filter_popup.py,sha256=_car5ic8SS32183XWvbvVX8q1paNoX2Un-Ohy3z2vwo,10428
|
|
42
|
+
hpc_runner/tui/components/job_table.py,sha256=3gqYey0L9i2WInKl7Hknh31_E_PEPSKdFvVwSsG7uuY,9444
|
|
43
|
+
hpc_runner/tui/providers/__init__.py,sha256=iLzT7HR2ETSf6MxDw64yVn99kiHqzEDOHqNU7XLAEME,100
|
|
44
|
+
hpc_runner/tui/providers/jobs.py,sha256=YjhufHvBJu6QICIZLs5FhFBAcQMEyEhw-heSzYxYwvo,6340
|
|
45
|
+
hpc_runner/tui/screens/__init__.py,sha256=EoyZZGr_fruzDuDXtsKXyY5QhHbEFVbm820eiRtciBc,221
|
|
46
|
+
hpc_runner/tui/screens/confirm.py,sha256=ZBjrqcIk6f_5KGLzsSCfewZdyERnR0x2W2A34KYlkbI,2101
|
|
47
|
+
hpc_runner/tui/screens/job_details.py,sha256=B7KiZunhfM7QW3xVvmEBQnOB5CQfxYpH9Td0JC6M29A,7488
|
|
48
|
+
hpc_runner/tui/screens/log_viewer.py,sha256=II6B2Vj4KY-nx1wWWq_5K2gsmi6dSyQm-suaEzauEcM,5888
|
|
49
|
+
hpc_runner/tui/styles/monitor.tcss,sha256=-XJ_mF02AlaEuX81N6tkYKhKYDcBKYTDKXejJO5efkI,11349
|
|
50
|
+
hpc_runner/workflow/__init__.py,sha256=Y5h7wfnlWcav_f2USZaP6r5m7I5KFam8eEJGo4UqJ0w,221
|
|
51
|
+
hpc_runner/workflow/dependency.py,sha256=PjhgCurnlfcKYO_arlUDLCKOpwqq324l09Sj0v-iwOU,639
|
|
52
|
+
hpc_runner/workflow/pipeline.py,sha256=MYV95Kp-5m2YVxYDk_zIYUsyt31ctl7jnVA10F2OJgg,5540
|
|
53
|
+
hpc_runner-0.2.0.dist-info/METADATA,sha256=5wCFmYvXMhg6Y2RQS66K3cUvjML64lRsulpgyRf_5O8,7015
|
|
54
|
+
hpc_runner-0.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
55
|
+
hpc_runner-0.2.0.dist-info/entry_points.txt,sha256=Ou3LsalLkY9mNOrUwyCDN8Q4PekM1K5h52hAU6fADk8,48
|
|
56
|
+
hpc_runner-0.2.0.dist-info/RECORD,,
|