hpc-runner 0.2.1__py3-none-any.whl → 0.3.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/_version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.2.1'
32
- __version_tuple__ = version_tuple = (0, 2, 1)
31
+ __version__ = version = '0.3.0'
32
+ __version_tuple__ = version_tuple = (0, 3, 0)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -1 +1 @@
1
- """CLI for hpc-tools."""
1
+ """CLI for hpc-runner."""
hpc_runner/cli/config.py CHANGED
@@ -29,10 +29,10 @@ def show(ctx: Context) -> None:
29
29
  console.print("[yellow]No configuration file found[/yellow]")
30
30
  console.print("Using default settings")
31
31
  console.print("\nSearch locations:")
32
- console.print(" 1. ./hpc-tools.toml")
33
- console.print(" 2. ./pyproject.toml [tool.hpc-tools]")
34
- console.print(" 3. <git root>/hpc-tools.toml")
35
- console.print(" 4. ~/.config/hpc-tools/config.toml")
32
+ console.print(" 1. ./hpc-runner.toml")
33
+ console.print(" 2. ./pyproject.toml [tool.hpc-runner]")
34
+ console.print(" 3. <git root>/hpc-runner.toml")
35
+ console.print(" 4. ~/.config/hpc-runner/config.toml")
36
36
  return
37
37
 
38
38
  console.print(f"[bold]Config file:[/bold] {config_path}")
@@ -45,16 +45,16 @@ def show(ctx: Context) -> None:
45
45
 
46
46
 
47
47
  @config_cmd.command("init")
48
- @click.option("--global", "global_config", is_flag=True, help="Create in ~/.config/hpc-tools/")
48
+ @click.option("--global", "global_config", is_flag=True, help="Create in ~/.config/hpc-runner/")
49
49
  @pass_context
50
50
  def init(ctx: Context, global_config: bool) -> None:
51
51
  """Create a new configuration file."""
52
52
  if global_config:
53
- config_dir = Path.home() / ".config" / "hpc-tools"
53
+ config_dir = Path.home() / ".config" / "hpc-runner"
54
54
  config_dir.mkdir(parents=True, exist_ok=True)
55
55
  config_path = config_dir / "config.toml"
56
56
  else:
57
- config_path = Path.cwd() / "hpc-tools.toml"
57
+ config_path = Path.cwd() / "hpc-runner.toml"
58
58
 
59
59
  if config_path.exists():
60
60
  if not click.confirm(f"{config_path} already exists. Overwrite?"):
@@ -62,7 +62,10 @@ def init(ctx: Context, global_config: bool) -> None:
62
62
  return
63
63
 
64
64
  # Write default config
65
- default_config = '''# hpc-tools configuration
65
+ default_config = '''# hpc-runner configuration
66
+ #
67
+ # This file is safe to commit to a project repo (for shared defaults).
68
+ # For a per-user config, run: hpc config init --global
66
69
 
67
70
  [defaults]
68
71
  # Default job settings
hpc_runner/cli/main.py CHANGED
@@ -52,6 +52,12 @@ def cli(ctx: Context, config: Path | None, scheduler: str | None, verbose: bool)
52
52
  ctx.scheduler = scheduler
53
53
  ctx.verbose = verbose
54
54
 
55
+ # Ensure the config cache reflects CLI selection / CWD discovery.
56
+ # Without this, --config would only affect `hpc config ...` commands.
57
+ from hpc_runner.core.config import reload_config
58
+
59
+ reload_config(config)
60
+
55
61
 
56
62
  # Import and register subcommands (must be after cli is defined to avoid circular imports)
57
63
  from hpc_runner.cli.cancel import cancel # noqa: E402
@@ -0,0 +1,72 @@
1
+ """Entry point that behaves like `hpc run ...`."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+ from typing import Final
7
+
8
+
9
+ _GLOBAL_FLAGS: Final[set[str]] = {"--config", "--scheduler", "--verbose", "-h", "--help"}
10
+
11
+
12
+ def _split_global_flags(argv: list[str]) -> tuple[list[str], list[str]]:
13
+ """Split argv into (global_opts, rest) for the `submit` shim.
14
+
15
+ We only recognize the top-level CLI flags supported by `hpc`:
16
+ --config PATH, --scheduler NAME, --verbose, -h/--help.
17
+
18
+ Anything else is treated as part of the `run` command (including scheduler
19
+ passthrough flags like `-q`, `-l`, etc.).
20
+ """
21
+ global_opts: list[str] = []
22
+ rest: list[str] = []
23
+
24
+ i = 0
25
+ while i < len(argv):
26
+ arg = argv[i]
27
+
28
+ # Support --opt=value forms
29
+ if arg.startswith("--config=") or arg.startswith("--scheduler="):
30
+ global_opts.append(arg)
31
+ i += 1
32
+ continue
33
+
34
+ if arg not in _GLOBAL_FLAGS:
35
+ rest = argv[i:]
36
+ break
37
+
38
+ global_opts.append(arg)
39
+
40
+ # Options with a value
41
+ if arg in {"--config", "--scheduler"}:
42
+ if i + 1 >= len(argv):
43
+ # Let click surface the error message (missing value)
44
+ break
45
+ global_opts.append(argv[i + 1])
46
+ i += 2
47
+ continue
48
+
49
+ # Flags with no value
50
+ i += 1
51
+
52
+ return global_opts, rest
53
+
54
+
55
+ def main() -> None:
56
+ """Console script for `submit`.
57
+
58
+ This is a convenience alias for `hpc run ...`, but keeps support for
59
+ top-level flags like `submit --config ...`.
60
+ """
61
+ from hpc_runner.cli.main import cli
62
+
63
+ argv = sys.argv[1:]
64
+
65
+ # `submit --help` should show the run help (not just the group help)
66
+ if not argv or argv == ["--help"] or argv == ["-h"]:
67
+ cli.main(args=["run", "--help"], prog_name="submit")
68
+ return
69
+
70
+ global_opts, rest = _split_global_flags(argv)
71
+ cli.main(args=[*global_opts, "run", *rest], prog_name="submit")
72
+
@@ -1,4 +1,4 @@
1
- """Core models and abstractions for hpc-tools."""
1
+ """Core models and abstractions for hpc-runner."""
2
2
 
3
3
  from .exceptions import (
4
4
  AccountingNotAvailable,
hpc_runner/core/config.py CHANGED
@@ -78,33 +78,33 @@ def find_config_file() -> Path | None:
78
78
  """Find configuration file in priority order.
79
79
 
80
80
  Search order:
81
- 1. ./hpc-tools.toml (current directory)
82
- 2. ./pyproject.toml [tool.hpc-tools] section
83
- 3. Git repository root hpc-tools.toml
84
- 4. ~/.config/hpc-tools/config.toml
81
+ 1. ./hpc-runner.toml (current directory)
82
+ 2. ./pyproject.toml [tool.hpc-runner] section
83
+ 3. Git repository root hpc-runner.toml
84
+ 4. ~/.config/hpc-runner/config.toml
85
85
  5. Package defaults
86
86
  """
87
87
  # Current directory
88
88
  cwd = Path.cwd()
89
- if (cwd / "hpc-tools.toml").exists():
90
- return cwd / "hpc-tools.toml"
89
+ if (cwd / "hpc-runner.toml").exists():
90
+ return cwd / "hpc-runner.toml"
91
91
 
92
92
  if (cwd / "pyproject.toml").exists():
93
93
  try:
94
94
  with open(cwd / "pyproject.toml", "rb") as f:
95
95
  pyproject = tomllib.load(f)
96
- if "tool" in pyproject and "hpc-tools" in pyproject["tool"]:
96
+ if "tool" in pyproject and "hpc-runner" in pyproject["tool"]:
97
97
  return cwd / "pyproject.toml"
98
98
  except Exception:
99
99
  pass
100
100
 
101
101
  # Git root
102
102
  git_root = _find_git_root(cwd)
103
- if git_root and (git_root / "hpc-tools.toml").exists():
104
- return git_root / "hpc-tools.toml"
103
+ if git_root and (git_root / "hpc-runner.toml").exists():
104
+ return git_root / "hpc-runner.toml"
105
105
 
106
106
  # User config
107
- user_config = Path.home() / ".config" / "hpc-tools" / "config.toml"
107
+ user_config = Path.home() / ".config" / "hpc-runner" / "config.toml"
108
108
  if user_config.exists():
109
109
  return user_config
110
110
 
@@ -145,7 +145,8 @@ def load_config(path: Path | str | None = None) -> HPCConfig:
145
145
 
146
146
  # Handle pyproject.toml
147
147
  if path.name == "pyproject.toml":
148
- data = data.get("tool", {}).get("hpc-tools", {})
148
+ tool_section = data.get("tool", {})
149
+ data = tool_section.get("hpc-runner", {})
149
150
 
150
151
  config = HPCConfig(
151
152
  defaults=data.get("defaults", {}),
@@ -1,8 +1,8 @@
1
- """Custom exceptions for hpc-tools."""
1
+ """Custom exceptions for hpc-runner."""
2
2
 
3
3
 
4
4
  class HPCToolsError(Exception):
5
- """Base exception for hpc-tools."""
5
+ """Base exception for hpc-runner."""
6
6
 
7
7
 
8
8
  class SchedulerError(HPCToolsError):
hpc_runner/core/job.py CHANGED
@@ -123,6 +123,8 @@ class Job:
123
123
  use_cwd: bool = True,
124
124
  venv: str | None = None,
125
125
  env_vars: dict[str, str] | None = None,
126
+ env_prepend: dict[str, str] | None = None,
127
+ env_append: dict[str, str] | None = None,
126
128
  modules: list[str] | None = None,
127
129
  modules_path: list[str] | None = None,
128
130
  resources: ResourceSet | None = None,
@@ -161,6 +163,8 @@ class Job:
161
163
 
162
164
  # Non-descriptor attributes
163
165
  self.env_vars: dict[str, str] = env_vars or {}
166
+ self.env_prepend: dict[str, str] = env_prepend or {}
167
+ self.env_append: dict[str, str] = env_append or {}
164
168
  self.modules: list[str] = modules or []
165
169
  self.modules_path: list[str] = modules_path or []
166
170
  self.resources: ResourceSet = resources or ResourceSet()
hpc_runner/core/types.py CHANGED
@@ -1,4 +1,4 @@
1
- """Type aliases for hpc-tools."""
1
+ """Type aliases for hpc-runner."""
2
2
 
3
3
  from pathlib import Path
4
4
  from typing import TypeAlias
@@ -9,6 +9,7 @@ from datetime import datetime
9
9
  from pathlib import Path
10
10
  from typing import TYPE_CHECKING
11
11
 
12
+ from hpc_runner.core.config import get_config
12
13
  from hpc_runner.core.exceptions import AccountingNotAvailable, JobNotFoundError
13
14
  from hpc_runner.core.job_info import JobInfo
14
15
  from hpc_runner.core.result import ArrayJobResult, JobResult, JobStatus
@@ -26,6 +27,14 @@ class LocalScheduler(BaseScheduler):
26
27
  name = "local"
27
28
 
28
29
  _job_counter: int = 0
30
+
31
+ def __init__(self) -> None:
32
+ """Initialize local scheduler with config-driven settings."""
33
+ config = get_config()
34
+ local_config = config.get_scheduler_config("local")
35
+
36
+ self.module_init_script = local_config.get("module_init_script", "")
37
+
29
38
  _processes: dict[str, subprocess.Popen] = {} # type: ignore[type-arg]
30
39
  _exit_codes: dict[str, int] = {}
31
40
  _output_paths: dict[str, dict[str, Path]] = {}
@@ -37,8 +46,9 @@ class LocalScheduler(BaseScheduler):
37
46
  LocalScheduler._job_counter += 1
38
47
  job_id = f"local_{LocalScheduler._job_counter}_{datetime.now().strftime('%Y%m%d%H%M%S')}"
39
48
 
40
- # Set up environment with modules (modules not actually loaded locally)
49
+ # Set up environment
41
50
  env = os.environ.copy() if job.inherit_env else {}
51
+ env.update(job.env_vars)
42
52
 
43
53
  # Generate and write script
44
54
  script = self.generate_script(job)
@@ -48,69 +58,87 @@ class LocalScheduler(BaseScheduler):
48
58
 
49
59
  workdir = Path(job.workdir) if job.workdir else Path.cwd()
50
60
 
51
- # Determine output paths
52
- stdout_file = job.stdout or f"{job.name}.{job_id}.out"
53
- stdout_path = workdir / stdout_file
54
- if job.merge_output:
55
- stderr_path = stdout_path # Merge stderr into stdout
56
- else:
57
- stderr_file = job.stderr or f"{job.name}.{job_id}.err"
58
- stderr_path = workdir / stderr_file
61
+ # Check if output should pass through to console (no redirection)
62
+ passthrough = job.stdout is None and job.stderr is None
63
+
64
+ if not passthrough:
65
+ # Determine output paths
66
+ stdout_file = job.stdout or f"{job.name}.{job_id}.out"
67
+ stdout_path = workdir / stdout_file
68
+ if job.merge_output:
69
+ stderr_path = stdout_path # Merge stderr into stdout
70
+ else:
71
+ stderr_file = job.stderr or f"{job.name}.{job_id}.err"
72
+ stderr_path = workdir / stderr_file
59
73
 
60
- # Store output paths
61
- LocalScheduler._output_paths[job_id] = {
62
- "stdout": stdout_path,
63
- "stderr": stderr_path,
64
- }
74
+ # Store output paths
75
+ LocalScheduler._output_paths[job_id] = {
76
+ "stdout": stdout_path,
77
+ "stderr": stderr_path,
78
+ }
65
79
 
66
80
  if interactive:
67
81
  # Blocking execution
68
- with open(stdout_path, "w") as stdout_f:
69
- if job.merge_output:
70
- result = subprocess.run(
71
- [str(script_path)],
72
- cwd=workdir,
73
- env=env,
74
- stdout=stdout_f,
75
- stderr=subprocess.STDOUT,
76
- )
77
- else:
78
- with open(stderr_path, "w") as stderr_f:
82
+ if passthrough:
83
+ result = subprocess.run(
84
+ [str(script_path)],
85
+ cwd=workdir,
86
+ env=env,
87
+ )
88
+ else:
89
+ with open(stdout_path, "w") as stdout_f:
90
+ if job.merge_output:
79
91
  result = subprocess.run(
80
92
  [str(script_path)],
81
93
  cwd=workdir,
82
94
  env=env,
83
95
  stdout=stdout_f,
84
- stderr=stderr_f,
96
+ stderr=subprocess.STDOUT,
85
97
  )
98
+ else:
99
+ with open(stderr_path, "w") as stderr_f:
100
+ result = subprocess.run(
101
+ [str(script_path)],
102
+ cwd=workdir,
103
+ env=env,
104
+ stdout=stdout_f,
105
+ stderr=stderr_f,
106
+ )
86
107
  LocalScheduler._exit_codes[job_id] = result.returncode
87
108
  script_path.unlink(missing_ok=True)
88
109
  else:
89
110
  # Background execution
90
- stdout_f = open(stdout_path, "w")
91
- if job.merge_output:
111
+ if passthrough:
92
112
  proc = subprocess.Popen(
93
113
  [str(script_path)],
94
114
  cwd=workdir,
95
115
  env=env,
96
- stdout=stdout_f,
97
- stderr=subprocess.STDOUT,
98
116
  )
99
117
  else:
100
- stderr_f = open(stderr_path, "w")
101
- proc = subprocess.Popen(
102
- [str(script_path)],
103
- cwd=workdir,
104
- env=env,
105
- stdout=stdout_f,
106
- stderr=stderr_f,
107
- )
118
+ stdout_f = open(stdout_path, "w")
119
+ if job.merge_output:
120
+ proc = subprocess.Popen(
121
+ [str(script_path)],
122
+ cwd=workdir,
123
+ env=env,
124
+ stdout=stdout_f,
125
+ stderr=subprocess.STDOUT,
126
+ )
127
+ else:
128
+ stderr_f = open(stderr_path, "w")
129
+ proc = subprocess.Popen(
130
+ [str(script_path)],
131
+ cwd=workdir,
132
+ env=env,
133
+ stdout=stdout_f,
134
+ stderr=stderr_f,
135
+ )
136
+ proc._stdout_file = stdout_f # type: ignore[attr-defined]
137
+ if not job.merge_output:
138
+ proc._stderr_file = stderr_f # type: ignore[attr-defined]
108
139
  LocalScheduler._processes[job_id] = proc
109
140
  # Store script path for cleanup
110
141
  proc._script_path = script_path # type: ignore[attr-defined]
111
- proc._stdout_file = stdout_f # type: ignore[attr-defined]
112
- if not job.merge_output:
113
- proc._stderr_file = stderr_f # type: ignore[attr-defined]
114
142
 
115
143
  return JobResult(job_id=job_id, scheduler=self, job=job)
116
144
 
@@ -137,6 +165,7 @@ class LocalScheduler(BaseScheduler):
137
165
  def _submit_array_task(self, job: "Job", job_id: str, index: int) -> None:
138
166
  """Submit a single array task."""
139
167
  env = os.environ.copy() if job.inherit_env else {}
168
+ env.update(job.env_vars)
140
169
  env["HPC_ARRAY_TASK_ID"] = str(index)
141
170
 
142
171
  script = self.generate_script(job)
@@ -1,20 +1,60 @@
1
1
  #!/bin/bash
2
- # Generated by hpc-tools (local scheduler)
2
+ # Generated by hpc-runner (local scheduler)
3
+ {% set lb = '{' %}
3
4
 
4
5
  # Exit on error
5
6
  set -e
6
7
 
8
+ # Module system initialization
9
+ {% if scheduler.module_init_script %}
10
+ . {{ scheduler.module_init_script }}
11
+ {% else %}
12
+ if [ -f /etc/profile.d/modules.sh ]; then
13
+ . /etc/profile.d/modules.sh
14
+ elif [ -f /usr/share/Modules/init/bash ]; then
15
+ . /usr/share/Modules/init/bash
16
+ elif [ -f /etc/modules/init/bash ]; then
17
+ . /etc/modules/init/bash
18
+ fi
19
+ {% endif %}
20
+
7
21
  {% if job.modules_path %}
8
- # Additional module paths (simulated for local)
22
+ # Additional module paths
9
23
  {% for path in job.modules_path %}
10
- # module use {{ path }}
24
+ module use {{ path }}
11
25
  {% endfor %}
12
26
  {% endif %}
13
27
 
14
28
  {% if job.modules %}
15
- # Modules (simulated for local - not actually loaded)
29
+ # Load modules
16
30
  {% for mod in job.modules %}
17
- # module load {{ mod }}
31
+ module load {{ mod }}
32
+ {% endfor %}
33
+ {% endif %}
34
+
35
+ {% if job.venv %}
36
+ # Activate virtual environment
37
+ source {{ job.venv }}/bin/activate
38
+ {% endif %}
39
+
40
+ {% if job.env_prepend %}
41
+ # Prepend to environment variables
42
+ {% for key, value in job.env_prepend.items() %}
43
+ export {{ key }}="{{ value }}${{ lb }}{{ key }}:+:${{ key }}}"
44
+ {% endfor %}
45
+ {% endif %}
46
+
47
+ {% if job.env_append %}
48
+ # Append to environment variables
49
+ {% for key, value in job.env_append.items() %}
50
+ export {{ key }}="${{ lb }}{{ key }}:+${{ key }}:}{{ value }}"
51
+ {% endfor %}
52
+ {% endif %}
53
+
54
+ {% if job.env_vars %}
55
+ # Set custom environment variables
56
+ {% for key, value in job.env_vars.items() %}
57
+ export {{ key }}="{{ value }}"
18
58
  {% endfor %}
19
59
  {% endif %}
20
60
 
@@ -1,5 +1,6 @@
1
1
  #!/bin/bash
2
- # Generated by hpc-tools (SGE scheduler)
2
+ # Generated by hpc-runner (SGE scheduler)
3
+ {% set lb = '{' %}
3
4
 
4
5
  {% for directive in directives %}
5
6
  {{ directive }}
@@ -51,6 +52,20 @@ unset {{ var }}
51
52
  {% endfor %}
52
53
  {% endif %}
53
54
 
55
+ {% if job.env_prepend %}
56
+ # Prepend to environment variables
57
+ {% for key, value in job.env_prepend.items() %}
58
+ export {{ key }}="{{ value }}${{ lb }}{{ key }}:+:${{ key }}}"
59
+ {% endfor %}
60
+ {% endif %}
61
+
62
+ {% if job.env_append %}
63
+ # Append to environment variables
64
+ {% for key, value in job.env_append.items() %}
65
+ export {{ key }}="${{ lb }}{{ key }}:+${{ key }}:}{{ value }}"
66
+ {% endfor %}
67
+ {% endif %}
68
+
54
69
  {% if job.env_vars %}
55
70
  # Set custom environment variables
56
71
  {% for key, value in job.env_vars.items() %}
@@ -1,5 +1,6 @@
1
1
  #!/bin/bash
2
- # Generated by hpc-tools (SGE interactive job)
2
+ # Generated by hpc-runner (SGE interactive job)
3
+ {% set lb = '{' %}
3
4
 
4
5
  # Exit on error
5
6
  set -e
@@ -47,6 +48,20 @@ unset {{ var }}
47
48
  {% endfor %}
48
49
  {% endif %}
49
50
 
51
+ {% if job.env_prepend %}
52
+ # Prepend to environment variables
53
+ {% for key, value in job.env_prepend.items() %}
54
+ export {{ key }}="{{ value }}${{ lb }}{{ key }}:+:${{ key }}}"
55
+ {% endfor %}
56
+ {% endif %}
57
+
58
+ {% if job.env_append %}
59
+ # Append to environment variables
60
+ {% for key, value in job.env_append.items() %}
61
+ export {{ key }}="${{ lb }}{{ key }}:+${{ key }}:}{{ value }}"
62
+ {% endfor %}
63
+ {% endif %}
64
+
50
65
  {% if job.env_vars %}
51
66
  # Set custom environment variables
52
67
  {% for key, value in job.env_vars.items() %}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hpc-runner
3
- Version: 0.2.1
3
+ Version: 0.3.0
4
4
  Summary: Unified HPC job submission across multiple schedulers
5
5
  Project-URL: Homepage, https://github.com/sjalloq/hpc-runner
6
6
  Project-URL: Repository, https://github.com/sjalloq/hpc-runner
@@ -26,19 +26,25 @@ Requires-Dist: textual>=6.11
26
26
  Requires-Dist: tomli>=2.0; python_version < '3.11'
27
27
  Provides-Extra: all
28
28
  Requires-Dist: build; extra == 'all'
29
+ Requires-Dist: furo>=2024.0.0; extra == 'all'
29
30
  Requires-Dist: hatch-vcs; extra == 'all'
30
31
  Requires-Dist: mypy; extra == 'all'
32
+ Requires-Dist: pytest-asyncio; extra == 'all'
31
33
  Requires-Dist: pytest-cov; extra == 'all'
32
34
  Requires-Dist: pytest>=7.0; extra == 'all'
33
35
  Requires-Dist: ruff; extra == 'all'
36
+ Requires-Dist: sphinx>=7.0; extra == 'all'
34
37
  Requires-Dist: twine; extra == 'all'
35
38
  Provides-Extra: dev
36
39
  Requires-Dist: build; extra == 'dev'
40
+ Requires-Dist: furo>=2024.0.0; extra == 'dev'
37
41
  Requires-Dist: hatch-vcs; extra == 'dev'
38
42
  Requires-Dist: mypy; extra == 'dev'
43
+ Requires-Dist: pytest-asyncio; extra == 'dev'
39
44
  Requires-Dist: pytest-cov; extra == 'dev'
40
45
  Requires-Dist: pytest>=7.0; extra == 'dev'
41
46
  Requires-Dist: ruff; extra == 'dev'
47
+ Requires-Dist: sphinx>=7.0; extra == 'dev'
42
48
  Requires-Dist: twine; extra == 'dev'
43
49
  Description-Content-Type: text/markdown
44
50
 
@@ -173,10 +179,10 @@ p.wait()
173
179
  hpc-runner uses TOML configuration files. Location priority:
174
180
 
175
181
  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`
182
+ 2. `./hpc-runner.toml`
183
+ 3. `./pyproject.toml` under `[tool.hpc-runner]`
184
+ 4. Git repository root `hpc-runner.toml`
185
+ 5. `~/.config/hpc-runner/config.toml`
180
186
  6. Package defaults
181
187
 
182
188
  ### Example Configuration
@@ -275,11 +281,6 @@ ruff check src/hpc_runner
275
281
  ruff format src/hpc_runner
276
282
  ```
277
283
 
278
- ## Documentation
279
-
280
- - [Programmatic API Reference](docs/programmatic_api.md)
281
- - [TUI Styling Guide](docs/TEXTUAL_STYLING_COOKBOOK.md)
282
-
283
284
  ## License
284
285
 
285
286
  MIT License - see LICENSE file for details.
@@ -1,35 +1,36 @@
1
1
  hpc_runner/__init__.py,sha256=1xnewzCt8FVqseOG5PRmLbiMz0I8V8_TrTyIjW0Q8_A,1414
2
- hpc_runner/_version.py,sha256=vYqoJTG51NOUmYyL0xt8asRK8vUT4lGAdal_EZ59mvw,704
2
+ hpc_runner/_version.py,sha256=5zTqm8rgXsWYBpB2M3Zw_K1D-aV8wP7NsBLrmMKkrAQ,704
3
3
  hpc_runner/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- hpc_runner/cli/__init__.py,sha256=SkyeG7kzxbBGgO9fU96VvHjMjLaSdGI3KFVcqeUAYtg,25
4
+ hpc_runner/cli/__init__.py,sha256=qF_2phBjYZc_rHCyJeZevCvbOCfXQbLCwb-DY5mJNUo,26
5
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
6
+ hpc_runner/cli/config.py,sha256=i5dWu4bFjZw5y2EaKxJIsw2SUgEVLJ-zKh2jIRAdh90,3056
7
+ hpc_runner/cli/main.py,sha256=4BnIN3WfOyusa6TJJ555JJ9kyxaNqlT-KxvawX26x0o,2286
8
8
  hpc_runner/cli/monitor.py,sha256=aqr39IqwEUz_eczDLMw1dyfs_Gz6mtqKM2eMHI80f4g,698
9
9
  hpc_runner/cli/run.py,sha256=fGK0gwIiQdUl0i2aC5FnwSs9MmuKF6ZZFgg7pn2NitU,9646
10
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
11
+ hpc_runner/cli/submit.py,sha256=PcSjcVOSxtGCQlUiH56KTfSL_gLt-k879e2ddB9vUCQ,1982
12
+ hpc_runner/core/__init__.py,sha256=dSAYl2aizg-ZpOdD5BfFqd_UWp_9KmVDpRTRzNTn2u8,644
13
+ hpc_runner/core/config.py,sha256=GRLNurLOmgJiBwHN_gCesBhQ1ntg2DIgjkC06d5nB_8,5231
13
14
  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
15
+ hpc_runner/core/exceptions.py,sha256=i7DZoEMYl0MrsT9-6Z0ebrsP3YOLA_6B5THz0LgmNN8,891
16
+ hpc_runner/core/job.py,sha256=wR5rR6c32cZOFgOsn6fGx33FlgWz50RK4xCrjs21y18,11273
16
17
  hpc_runner/core/job_array.py,sha256=7VHoZHRzN5JvzWZ_e5pAMeTrNB7-OZw06A8548oK8_c,1595
17
18
  hpc_runner/core/job_info.py,sha256=QE4iHH3uqYp4KdvZmBtfFUUaZfmPLkrF6LtlK4RuSJM,2858
18
19
  hpc_runner/core/resources.py,sha256=ng1biVsXgGy6AWG50I50aC4LWB1pd60qFLpj5FjIpQc,1275
19
20
  hpc_runner/core/result.py,sha256=UGw6ZRmdGI4oVD5ENzrSK72Igx7QNo-OJX9hLVyldp8,4914
20
- hpc_runner/core/types.py,sha256=a6Yq7vhcpBwgA_hGZwGXiZgCy8wG87FIXBT3LN5qHw8,251
21
+ hpc_runner/core/types.py,sha256=CeLgPLO_ByzdX16UTUrxcgEbA77PKvQJx4x8yXdjNkM,252
21
22
  hpc_runner/schedulers/__init__.py,sha256=v55_DYgiigiFjXJhI7_XFtvxHoyDFWOntWRB9-HWMrM,1623
22
23
  hpc_runner/schedulers/base.py,sha256=vhugT9lFrSZb8BMDO_x-h4nSF2oLg2nOvd347g3qfUY,6223
23
24
  hpc_runner/schedulers/detection.py,sha256=b5_qdyroMQsvIf_DYY_RDoje6ozKLA3RS-fWWNR9qUU,1467
24
25
  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
26
+ hpc_runner/schedulers/local/scheduler.py,sha256=aNfA9XnF8MGWxjhGturO_mzy9MQLVTt0ZN3NzSexGgs,14440
27
+ hpc_runner/schedulers/local/templates/job.sh.j2,sha256=MwQnjW6p6XNHSJ9EbcC0H3H4USHhZbMel1dmvOJj-2Y,1483
27
28
  hpc_runner/schedulers/sge/__init__.py,sha256=aR_jJD-YA0HOYPaBwW_CEwi3PASXY2x9sOfmrj6-cjM,144
28
29
  hpc_runner/schedulers/sge/args.py,sha256=LBRj4UUDJ5jR8tEoCVF4ivjEKjqDI6LMvFsFzTgtOwk,6553
29
30
  hpc_runner/schedulers/sge/parser.py,sha256=P6bG7II2icqSrnzgxGanPITV12X1zMvWYV04L6RIH2c,8381
30
31
  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
32
+ hpc_runner/schedulers/sge/templates/batch.sh.j2,sha256=fqfMIi5bPdkxGARWffYQCTITQczIELAuhXzQ_tYI4d0,2107
33
+ hpc_runner/schedulers/sge/templates/interactive.sh.j2,sha256=hOZzLoJMosbgKRFT0CfTdhW8pS6Q-h74zKdLHoSzY5s,2033
33
34
  hpc_runner/templates/__init__.py,sha256=kiaaYBS4QXfGie83SS0rfmZtlbyRUkGkR_yw04oExNQ,137
34
35
  hpc_runner/templates/engine.py,sha256=XDW9C51rz9O2rcB3mpjVHQ0qkeG4386gXa8fwaDYsxs,1393
35
36
  hpc_runner/tui/__init__.py,sha256=xuet6Iz1ZL6Ys5h95DMcuiapZNo8QA-sFU3R0NflbgE,136
@@ -50,7 +51,7 @@ hpc_runner/tui/styles/monitor.tcss,sha256=-XJ_mF02AlaEuX81N6tkYKhKYDcBKYTDKXejJO
50
51
  hpc_runner/workflow/__init__.py,sha256=Y5h7wfnlWcav_f2USZaP6r5m7I5KFam8eEJGo4UqJ0w,221
51
52
  hpc_runner/workflow/dependency.py,sha256=PjhgCurnlfcKYO_arlUDLCKOpwqq324l09Sj0v-iwOU,639
52
53
  hpc_runner/workflow/pipeline.py,sha256=MYV95Kp-5m2YVxYDk_zIYUsyt31ctl7jnVA10F2OJgg,5540
53
- hpc_runner-0.2.1.dist-info/METADATA,sha256=llf8Y-8fTDy3v0JfLXeBQkR7sG2Wjvs5cxh3xTAewEM,7015
54
- hpc_runner-0.2.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
55
- hpc_runner-0.2.1.dist-info/entry_points.txt,sha256=Ou3LsalLkY9mNOrUwyCDN8Q4PekM1K5h52hAU6fADk8,48
56
- hpc_runner-0.2.1.dist-info/RECORD,,
54
+ hpc_runner-0.3.0.dist-info/METADATA,sha256=2-0_jdDuVnmszJzaJDpDOBW_Zfuasem_vr4vXvXJS9Q,7157
55
+ hpc_runner-0.3.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
56
+ hpc_runner-0.3.0.dist-info/entry_points.txt,sha256=_IpvKqwtDP7R-jxj2p4D8ijKAIJp8eG9lmDZkVtrOkc,84
57
+ hpc_runner-0.3.0.dist-info/RECORD,,
@@ -1,2 +1,3 @@
1
1
  [console_scripts]
2
2
  hpc = hpc_runner.cli.main:cli
3
+ submit = hpc_runner.cli.submit:main