nemo-evaluator-launcher 0.1.28__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 nemo-evaluator-launcher might be problematic. Click here for more details.

Files changed (60) hide show
  1. nemo_evaluator_launcher/__init__.py +79 -0
  2. nemo_evaluator_launcher/api/__init__.py +24 -0
  3. nemo_evaluator_launcher/api/functional.py +698 -0
  4. nemo_evaluator_launcher/api/types.py +98 -0
  5. nemo_evaluator_launcher/api/utils.py +19 -0
  6. nemo_evaluator_launcher/cli/__init__.py +15 -0
  7. nemo_evaluator_launcher/cli/export.py +267 -0
  8. nemo_evaluator_launcher/cli/info.py +512 -0
  9. nemo_evaluator_launcher/cli/kill.py +41 -0
  10. nemo_evaluator_launcher/cli/ls_runs.py +134 -0
  11. nemo_evaluator_launcher/cli/ls_tasks.py +136 -0
  12. nemo_evaluator_launcher/cli/main.py +226 -0
  13. nemo_evaluator_launcher/cli/run.py +200 -0
  14. nemo_evaluator_launcher/cli/status.py +164 -0
  15. nemo_evaluator_launcher/cli/version.py +55 -0
  16. nemo_evaluator_launcher/common/__init__.py +16 -0
  17. nemo_evaluator_launcher/common/execdb.py +283 -0
  18. nemo_evaluator_launcher/common/helpers.py +366 -0
  19. nemo_evaluator_launcher/common/logging_utils.py +357 -0
  20. nemo_evaluator_launcher/common/mapping.py +295 -0
  21. nemo_evaluator_launcher/common/printing_utils.py +93 -0
  22. nemo_evaluator_launcher/configs/__init__.py +15 -0
  23. nemo_evaluator_launcher/configs/default.yaml +28 -0
  24. nemo_evaluator_launcher/configs/deployment/generic.yaml +33 -0
  25. nemo_evaluator_launcher/configs/deployment/nim.yaml +32 -0
  26. nemo_evaluator_launcher/configs/deployment/none.yaml +16 -0
  27. nemo_evaluator_launcher/configs/deployment/sglang.yaml +38 -0
  28. nemo_evaluator_launcher/configs/deployment/trtllm.yaml +24 -0
  29. nemo_evaluator_launcher/configs/deployment/vllm.yaml +42 -0
  30. nemo_evaluator_launcher/configs/execution/lepton/default.yaml +92 -0
  31. nemo_evaluator_launcher/configs/execution/local.yaml +19 -0
  32. nemo_evaluator_launcher/configs/execution/slurm/default.yaml +34 -0
  33. nemo_evaluator_launcher/executors/__init__.py +22 -0
  34. nemo_evaluator_launcher/executors/base.py +120 -0
  35. nemo_evaluator_launcher/executors/lepton/__init__.py +16 -0
  36. nemo_evaluator_launcher/executors/lepton/deployment_helpers.py +609 -0
  37. nemo_evaluator_launcher/executors/lepton/executor.py +1004 -0
  38. nemo_evaluator_launcher/executors/lepton/job_helpers.py +398 -0
  39. nemo_evaluator_launcher/executors/local/__init__.py +15 -0
  40. nemo_evaluator_launcher/executors/local/executor.py +605 -0
  41. nemo_evaluator_launcher/executors/local/run.template.sh +103 -0
  42. nemo_evaluator_launcher/executors/registry.py +38 -0
  43. nemo_evaluator_launcher/executors/slurm/__init__.py +15 -0
  44. nemo_evaluator_launcher/executors/slurm/executor.py +1147 -0
  45. nemo_evaluator_launcher/exporters/__init__.py +36 -0
  46. nemo_evaluator_launcher/exporters/base.py +121 -0
  47. nemo_evaluator_launcher/exporters/gsheets.py +409 -0
  48. nemo_evaluator_launcher/exporters/local.py +502 -0
  49. nemo_evaluator_launcher/exporters/mlflow.py +619 -0
  50. nemo_evaluator_launcher/exporters/registry.py +40 -0
  51. nemo_evaluator_launcher/exporters/utils.py +624 -0
  52. nemo_evaluator_launcher/exporters/wandb.py +490 -0
  53. nemo_evaluator_launcher/package_info.py +38 -0
  54. nemo_evaluator_launcher/resources/mapping.toml +380 -0
  55. nemo_evaluator_launcher-0.1.28.dist-info/METADATA +494 -0
  56. nemo_evaluator_launcher-0.1.28.dist-info/RECORD +60 -0
  57. nemo_evaluator_launcher-0.1.28.dist-info/WHEEL +5 -0
  58. nemo_evaluator_launcher-0.1.28.dist-info/entry_points.txt +3 -0
  59. nemo_evaluator_launcher-0.1.28.dist-info/licenses/LICENSE +451 -0
  60. nemo_evaluator_launcher-0.1.28.dist-info/top_level.txt +1 -0
@@ -0,0 +1,98 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+ """Type definitions for the nemo-evaluator-launcher public API.
17
+
18
+ This module defines data structures and helpers for configuration and type safety in the API layer.
19
+ """
20
+
21
+ import os
22
+ import warnings
23
+ from dataclasses import dataclass
24
+ from typing import cast
25
+
26
+ # ruff: noqa: E402
27
+ # Later when adding optional module to hydra, since the internal package is optional,
28
+ # will generate a hydra warning. We suppress it as distraction and bad UX, before hydra gets invoked.
29
+ warnings.filterwarnings(
30
+ "ignore",
31
+ message="provider=hydra.searchpath.*path=nemo_evaluator_launcher_internal.*is not available\\.",
32
+ )
33
+
34
+ import hydra
35
+ from hydra.core.global_hydra import GlobalHydra
36
+ from omegaconf import DictConfig, OmegaConf
37
+
38
+ from nemo_evaluator_launcher.common.logging_utils import logger
39
+
40
+
41
+ @dataclass
42
+ class RunConfig(DictConfig):
43
+ @staticmethod
44
+ def from_hydra(
45
+ config_name: str = "default",
46
+ config_dir: str | None = None,
47
+ hydra_overrides: list[str] = [],
48
+ dict_overrides: dict = {},
49
+ ) -> "RunConfig":
50
+ """Load configuration from Hydra and merge with dictionary overrides.
51
+
52
+ Args:
53
+ config_name: Name of the Hydra configuration to load.
54
+ hydra_overrides: List of Hydra command-line style overrides.
55
+ dict_overrides: Dictionary of configuration overrides to merge.
56
+ config_dir: Optional path to user config directory. If provided, Hydra will
57
+ search in this directory first, then fall back to internal configs.
58
+
59
+ Returns:
60
+ RunConfig: Merged configuration object.
61
+ """
62
+ overrides = hydra_overrides.copy()
63
+ # Check if a GlobalHydra instance is already initialized and clear it
64
+ if GlobalHydra.instance().is_initialized():
65
+ GlobalHydra.instance().clear()
66
+
67
+ if config_dir:
68
+ # Convert relative path to absolute path if needed
69
+ if not os.path.isabs(config_dir):
70
+ config_dir = os.path.abspath(config_dir)
71
+
72
+ hydra.initialize_config_dir(
73
+ config_dir=config_dir,
74
+ version_base=None,
75
+ )
76
+ else:
77
+ hydra.initialize_config_module(
78
+ config_module="nemo_evaluator_launcher.configs",
79
+ version_base=None,
80
+ )
81
+ overrides = overrides + [
82
+ "hydra.searchpath=[pkg://nemo_evaluator_launcher.configs,pkg://nemo_evaluator_launcher_internal.configs]"
83
+ ]
84
+ cfg = hydra.compose(config_name=config_name, overrides=overrides)
85
+
86
+ # Merge dict_overrides if provided
87
+ if dict_overrides:
88
+ cfg = OmegaConf.merge(cfg, dict_overrides)
89
+
90
+ logger.debug(
91
+ "Loaded run config from hydra",
92
+ config_name=config_name,
93
+ config_dir=config_dir,
94
+ overrides=hydra_overrides,
95
+ dict_overrides=dict_overrides,
96
+ result=cfg,
97
+ )
98
+ return cast("RunConfig", cfg)
@@ -0,0 +1,19 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+ """Configuration validation utilities for nemo-evaluator-launcher.
17
+
18
+ This module provides helper functions to validate configuration objects.
19
+ """
@@ -0,0 +1,15 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
@@ -0,0 +1,267 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+ """Export evaluation results to specified target."""
17
+
18
+ from dataclasses import dataclass
19
+ from typing import Any, List, Optional
20
+
21
+ from simple_parsing import field
22
+
23
+
24
+ @dataclass
25
+ class ExportCmd:
26
+ """Export evaluation results."""
27
+
28
+ # Short usage examples will show up in -h as the class docstring:
29
+ # Examples:
30
+ # nemo-evaluator-launcher export 8abcd123 --dest local --format json --out .
31
+ # nemo-evaluator-launcher export 8abcd123.0 9ef01234 --dest local --format csv --out results/ -fname processed_results.csv
32
+ # nemo-evaluator-launcher export 8abcd123 --dest jet
33
+
34
+ invocation_ids: List[str] = field(
35
+ positional=True,
36
+ help="IDs to export (space-separated). Accepts invocation IDs (xxxxxxxx) and job IDs (xxxxxxxx.n); mixture of both allowed.",
37
+ )
38
+ dest: str = field(
39
+ default="local",
40
+ alias=["--dest"],
41
+ choices=["local", "wandb", "mlflow", "gsheets", "jet"],
42
+ help="Export destination.",
43
+ )
44
+ # overrides for exporter config; use -o similar to run command
45
+ override: List[str] = field(
46
+ default_factory=list,
47
+ action="append",
48
+ nargs="?",
49
+ alias=["-o", "--override"],
50
+ help="Hydra-style overrides for exporter config. Use `export.<dest>.key=value` (e.g., -o export.wandb.entity=org-name).",
51
+ )
52
+ output_dir: Optional[str] = field(
53
+ default=".",
54
+ alias=["--output-dir", "-out"],
55
+ help="Output directory (default: current directory).",
56
+ )
57
+ output_filename: Optional[str] = field(
58
+ default=None,
59
+ alias=["--output-filename", "-fname"],
60
+ help="Summary filename (default: processed_results.json/csv based on --format).",
61
+ )
62
+ format: Optional[str] = field(
63
+ default=None,
64
+ alias=["--format"],
65
+ choices=["json", "csv"],
66
+ help="Summary format for --dest local. Omit to only copy artifacts.",
67
+ )
68
+ copy_logs: bool = field(
69
+ default=False,
70
+ alias=["--copy-logs"],
71
+ help="Include logs when copying locally (default: False).",
72
+ )
73
+ log_metrics: List[str] = field(
74
+ default_factory=list,
75
+ alias=["--log-metrics"],
76
+ help="Filter metrics by name (repeatable). Examples: score, f1, mmlu_score_micro.",
77
+ )
78
+ only_required: Optional[bool] = field(
79
+ default=None,
80
+ alias=["--only-required"],
81
+ help="Copy only required+optional artifacts (default: True). Set to False to copy all available artifacts.",
82
+ )
83
+
84
+ def execute(self) -> None:
85
+ """Execute export."""
86
+ # Import heavy dependencies only when needed
87
+ from omegaconf import OmegaConf
88
+
89
+ from nemo_evaluator_launcher.api.functional import export_results
90
+
91
+ # Validation: ensure IDs are provided
92
+ if not self.invocation_ids:
93
+ print("Error: No IDs provided. Specify one or more invocation or job IDs.")
94
+ print(
95
+ "Usage: nemo-evaluator-launcher export <id> [<id>...] --dest <destination>"
96
+ )
97
+ return
98
+
99
+ config: dict[str, Any] = {
100
+ "copy_logs": self.copy_logs,
101
+ }
102
+
103
+ # Output handling
104
+ if self.output_dir:
105
+ config["output_dir"] = self.output_dir
106
+ if self.output_filename:
107
+ config["output_filename"] = self.output_filename
108
+
109
+ # Format and filters
110
+ if self.format:
111
+ config["format"] = self.format
112
+ if self.log_metrics:
113
+ config["log_metrics"] = self.log_metrics
114
+
115
+ # Add only_required if explicitly passed via CLI
116
+ if self.only_required is not None:
117
+ config["only_required"] = self.only_required
118
+
119
+ # Parse and validate overrides
120
+ if self.override:
121
+ # Flatten possible list-of-lists from parser
122
+ flat_overrides: list[str] = []
123
+ for item in self.override:
124
+ if isinstance(item, list):
125
+ flat_overrides.extend(str(x) for x in item)
126
+ else:
127
+ flat_overrides.append(str(item))
128
+
129
+ try:
130
+ self._validate_overrides(flat_overrides, self.dest)
131
+ except ValueError as e:
132
+ print(f"Error: {e}")
133
+ return
134
+
135
+ # Expand env vars in override vals ($VAR / ${VAR})
136
+ import os
137
+
138
+ from omegaconf import OmegaConf
139
+
140
+ expanded_overrides: list[str] = []
141
+ for ov in flat_overrides:
142
+ if "=" in ov:
143
+ k, v = ov.split("=", 1)
144
+ expanded_overrides.append(f"{k}={os.path.expandvars(v)}")
145
+ else:
146
+ expanded_overrides.append(os.path.expandvars(ov))
147
+
148
+ dot_cfg = OmegaConf.from_dotlist(expanded_overrides)
149
+ as_dict = OmegaConf.to_container(dot_cfg, resolve=True) or {}
150
+ if isinstance(as_dict, dict) and "export" in as_dict:
151
+ export_map = as_dict.get("export") or {}
152
+ if isinstance(export_map, dict) and self.dest in export_map:
153
+ config.update(export_map[self.dest] or {})
154
+ else:
155
+ config.update(as_dict)
156
+ else:
157
+ config.update(as_dict)
158
+
159
+ if self.format and self.dest != "local":
160
+ print(
161
+ "Note: --format is only used by --dest local. It will be ignored for other destinations."
162
+ )
163
+
164
+ if "only_required" in config and self.only_required is True:
165
+ config.pop("only_required", None)
166
+
167
+ print(
168
+ f"Exporting {len(self.invocation_ids)} {'invocations' if len(self.invocation_ids) > 1 else 'invocation'} to {self.dest}..."
169
+ )
170
+
171
+ result = export_results(self.invocation_ids, self.dest, config)
172
+
173
+ if not result.get("success", False):
174
+ err = result.get("error", "Unknown error")
175
+ print(f"\nExport failed: {err}")
176
+ # Provide actionable guidance for common configuration issues
177
+ if self.dest == "mlflow":
178
+ if "tracking_uri" in str(err).lower():
179
+ print("\nMLflow requires 'tracking_uri' to be configured.")
180
+ print(
181
+ "Set it via: -o export.mlflow.tracking_uri=http://mlflow-server:5000"
182
+ )
183
+ elif "not installed" in str(err).lower():
184
+ print("\nMLflow package not installed.")
185
+ print("Install via: pip install nemo-evaluator-launcher[mlflow]")
186
+ elif self.dest == "wandb":
187
+ if "entity" in str(err).lower() or "project" in str(err).lower():
188
+ print("\nW&B requires 'entity' and 'project' to be configured.")
189
+ print(
190
+ "Set via: -o export.wandb.entity=my-org -o export.wandb.project=my-proj"
191
+ )
192
+ elif "not installed" in str(err).lower():
193
+ print("\nW&B package not installed.")
194
+ print("Install via: pip install nemo-evaluator-launcher[wandb]")
195
+ elif self.dest == "gsheets":
196
+ if "not installed" in str(err).lower():
197
+ print("\nGoogle Sheets package not installed.")
198
+ print("Install via: pip install nemo-evaluator-launcher[gsheets]")
199
+ return
200
+
201
+ # Success path
202
+ if len(self.invocation_ids) == 1:
203
+ # Single invocation
204
+ invocation_id = self.invocation_ids[0]
205
+ print(f"Export completed for {invocation_id}")
206
+
207
+ for job_id, job_result in result["jobs"].items():
208
+ if job_result.get("success"):
209
+ print(f" {job_id}: {job_result.get('message', '')}")
210
+ metadata = job_result.get("metadata", {})
211
+ if metadata.get("run_url"):
212
+ print(f" URL: {metadata['run_url']}")
213
+ if metadata.get("summary_path"):
214
+ print(f" Summary: {metadata['summary_path']}")
215
+ path_hint = job_result.get("dest") or metadata.get("output_dir")
216
+ if self.dest == "local" and path_hint:
217
+ print(f" Path: {path_hint}")
218
+ else:
219
+ print(f" {job_id} failed: {job_result.get('message', '')}")
220
+ else:
221
+ # Multiple invocations
222
+ metadata = result.get("metadata", {})
223
+ print(
224
+ f"Export completed: {metadata.get('successful_invocations', 0)}/{metadata.get('total_invocations', 0)} successful"
225
+ )
226
+
227
+ # Show summary path if available
228
+ if metadata.get("summary_path"):
229
+ print(f"Summary: {metadata['summary_path']}")
230
+ # Show per-invocation status
231
+ for invocation_id, inv_result in result["invocations"].items():
232
+ if inv_result.get("success"):
233
+ job_count = len(inv_result.get("jobs", {}))
234
+ print(f" {invocation_id}: {job_count} jobs")
235
+ else:
236
+ print(
237
+ f" {invocation_id}: failed, {inv_result.get('error', 'Unknown error')}"
238
+ )
239
+
240
+ def _validate_overrides(self, overrides: List[str], dest: str) -> None:
241
+ """Validate override list for destination consistency.
242
+
243
+ Raises:
244
+ ValueError: If overrides specify wrong destination or have other issues.
245
+ """
246
+ if not overrides:
247
+ return # nothing to validate
248
+
249
+ # Check each override for destination mismatch
250
+ for override_str in overrides:
251
+ if override_str.startswith(
252
+ "export."
253
+ ): # check if override starts with export.
254
+ # Extract destination from override path
255
+ try:
256
+ key_part = override_str.split("=")[0] # Get left side before =
257
+ parts = key_part.split(".")
258
+ if len(parts) >= 2:
259
+ override_dest = parts[1]
260
+ if override_dest != dest:
261
+ raise ValueError(
262
+ f"Override destination mismatch: override specifies 'export.{override_dest}' but --dest is '{dest}'. "
263
+ f"Either change --dest to '{override_dest}' or use 'export.{dest}' in overrides."
264
+ )
265
+ except (IndexError, AttributeError):
266
+ # miconstructed override -> OmegaConf handles this
267
+ pass