hyperun 0.2.4__tar.gz → 0.2.5__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyperun
3
- Version: 0.2.4
3
+ Version: 0.2.5
4
4
  Summary: Submit a GPU job and get results back. No kubectl, no cloud account.
5
5
  Author: DDPS Lab
6
6
  License-Expression: Apache-2.0
@@ -114,12 +114,13 @@ def job_arguments() -> argparse.ArgumentParser:
114
114
  # first time a vendor is added.
115
115
  shared.add_argument(
116
116
  "--vendor", action="append", metavar="NAME",
117
- help="who the machine may be bought from. Repeat it to allow several; "
118
- "omit it entirely for no restriction, which is what every job did before "
119
- "this flag existed. aws, runpod and shadeform can actually run a job, "
120
- "and `hyperun estimate` prices all three and names the cheapest; gcp, "
121
- "azure, lambda and nebius can only be PRICED, so name one of those only "
122
- "with --placement-mode compare.",
117
+ help="who the machine may be bought from, in the order they are asked. "
118
+ "Repeat it to allow several. Omit it, and --region, and the job is sent "
119
+ "with shadeform, runpod and aws in that order (a spot job goes to aws "
120
+ "alone); add --placement-mode cheapest to buy the cheapest of them "
121
+ "instead of the first that answers. aws, runpod and shadeform can "
122
+ "actually run a job; gcp, azure, lambda and nebius can only be PRICED, "
123
+ "so name one of those only with --placement-mode compare.",
123
124
  )
124
125
  # DDPSRUN-REGIONS. Missing until 2026-09-08, so every job this CLI submitted
125
126
  # ran in the operator's one default region and there was no way to say
@@ -1055,9 +1056,19 @@ def cmd_status(args: argparse.Namespace) -> int:
1055
1056
  if view.get("gpu"):
1056
1057
  vendor = f" ({view['vendor']})" if view.get("vendor") else ""
1057
1058
  print(f" running on {view['gpu']}{vendor}")
1059
+ # HYPERUN-PLACEMENT-NOTE. Where the job was asked to go, next to where it went,
1060
+ # so a person -- or an agent relaying to one -- sees a vendor that differs from
1061
+ # the one they chose. An older server sends no note, and nothing is printed.
1062
+ if view.get("placement_note"):
1063
+ print(f" placement {view['placement_note']}")
1058
1064
  if view.get("recovery_count"):
1059
- # Not a failure. Rented capacity is taken back, and the job is restarted.
1060
- print(f" restarts {view['recovery_count']} (the machine was reclaimed)")
1065
+ # Not a failure: the job was restarted. It used to say "the machine was
1066
+ # reclaimed" every time, which was wrong for job-a9ea30b8ba7a -- its three
1067
+ # restarts were offerings that failed to START, not machines taken back.
1068
+ failed = view.get("failed_offerings") or 0
1069
+ why = (f"{failed} offering(s) failed to start or were lost, and were skipped"
1070
+ if failed else "the machine was lost and the job was restarted")
1071
+ print(f" restarts {view['recovery_count']} ({why})")
1061
1072
  if view.get("message"):
1062
1073
  print(f" message {view['message']}")
1063
1074
  if view.get("result_path"):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyperun
3
- Version: 0.2.4
3
+ Version: 0.2.5
4
4
  Summary: Submit a GPU job and get results back. No kubectl, no cloud account.
5
5
  Author: DDPS Lab
6
6
  License-Expression: Apache-2.0
@@ -34,7 +34,7 @@ build-backend = "setuptools.build_meta"
34
34
 
35
35
  [project]
36
36
  name = "hyperun"
37
- version = "0.2.4"
37
+ version = "0.2.5"
38
38
  description = "Submit a GPU job and get results back. No kubectl, no cloud account."
39
39
  requires-python = ">=3.9"
40
40
  dependencies = ["requests>=2.31", "PyYAML>=6.0"]
@@ -268,7 +268,26 @@ def test_status_calls_a_restart_what_it_is(fake, capsys):
268
268
  run(["status", "job-a8acdef80a07"])
269
269
  printed = capsys.readouterr().out
270
270
  assert "L40S (runpod)" in printed
271
- assert "the machine was reclaimed" in printed
271
+ # With no failed offerings the restarts were machines lost mid-run.
272
+ assert "the machine was lost and the job was restarted" in printed
273
+
274
+
275
+ def test_status_says_offerings_failed_and_where_the_job_was_asked_to_go(fake, capsys):
276
+ # job-a9ea30b8ba7a: three g6.xlarge zones failed to START, and the CLI called
277
+ # it "the machine was reclaimed". The server's note is printed as it is, so the
278
+ # person sees the job asked AWS alone while they had chosen "any vendor".
279
+ fake.status_result = {
280
+ "job_id": "job-a9ea30b8ba7a", "name": "x", "phase": "Running",
281
+ "recovery_count": 3, "failed_offerings": 3, "gpu": "g6.xlarge", "vendor": "aws",
282
+ "placement_note": "The job named no vendor and no region, so the operator's one "
283
+ "default region (AWS) was the only candidate; it runs on aws "
284
+ "g6.xlarge.",
285
+ }
286
+ run(["status", "job-a9ea30b8ba7a"])
287
+ printed = capsys.readouterr().out
288
+ assert "3 offering(s) failed to start or were lost" in printed
289
+ assert "reclaimed" not in printed
290
+ assert "placement The job named no vendor" in printed
272
291
 
273
292
 
274
293
  def test_logs_prints_every_line_without_its_timestamp(fake, capsys):
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes