torchx-nightly 2025.9.3__py3-none-any.whl → 2025.9.4__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 torchx-nightly might be problematic. Click here for more details.

torchx/cli/cmd_run.py CHANGED
@@ -7,6 +7,7 @@
7
7
  # pyre-strict
8
8
 
9
9
  import argparse
10
+ import json
10
11
  import logging
11
12
  import os
12
13
  import sys
@@ -41,6 +42,12 @@ MISSING_COMPONENT_ERROR_MSG = (
41
42
  "missing component name, either provide it from the CLI or in .torchxconfig"
42
43
  )
43
44
 
45
+ LOCAL_SCHEDULER_WARNING_MSG = (
46
+ "`local` scheduler is deprecated and will be"
47
+ " removed in the near future,"
48
+ " please use other variants of the local scheduler"
49
+ " (e.g. `local_cwd`)"
50
+ )
44
51
 
45
52
  logger: logging.Logger = logging.getLogger(__name__)
46
53
 
@@ -54,7 +61,7 @@ class TorchXRunArgs:
54
61
  dryrun: bool = False
55
62
  wait: bool = False
56
63
  log: bool = False
57
- workspace: str = f"file://{Path.cwd()}"
64
+ workspace: str = ""
58
65
  parent_run_id: Optional[str] = None
59
66
  tee_logs: bool = False
60
67
  component_args: Dict[str, Any] = field(default_factory=dict)
@@ -83,7 +90,10 @@ def torchx_run_args_from_json(json_data: Dict[str, Any]) -> TorchXRunArgs:
83
90
  "Please check your JSON and try launching again.",
84
91
  )
85
92
 
86
- return TorchXRunArgs(**filtered_json_data)
93
+ torchx_args = TorchXRunArgs(**filtered_json_data)
94
+ if torchx_args.workspace == "":
95
+ torchx_args.workspace = f"file://{Path.cwd()}"
96
+ return torchx_args
87
97
 
88
98
 
89
99
  def torchx_run_args_from_argparse(
@@ -256,35 +266,35 @@ class CmdRun(SubCommand):
256
266
  default=False,
257
267
  help="Add additional prefix to log lines to indicate which replica is printing the log",
258
268
  )
269
+ subparser.add_argument(
270
+ "--stdin",
271
+ action="store_true",
272
+ default=False,
273
+ help="Read JSON input from stdin to parse into torchx run args and run the component.",
274
+ )
259
275
  subparser.add_argument(
260
276
  "component_name_and_args",
261
277
  nargs=argparse.REMAINDER,
262
278
  )
263
279
 
264
- def _run(self, runner: Runner, args: argparse.Namespace) -> None:
280
+ def _run_inner(self, runner: Runner, args: TorchXRunArgs) -> None:
265
281
  if args.scheduler == "local":
266
- logger.warning(
267
- "`local` scheduler is deprecated and will be"
268
- " removed in the near future,"
269
- " please use other variants of the local scheduler"
270
- " (e.g. `local_cwd`)"
271
- )
272
-
273
- cfg = dict(runner.cfg_from_str(args.scheduler, args.scheduler_args))
274
- config.apply(scheduler=args.scheduler, cfg=cfg)
282
+ logger.warning(LOCAL_SCHEDULER_WARNING_MSG)
275
283
 
276
- component, component_args = _parse_component_name_and_args(
277
- args.component_name_and_args,
278
- none_throws(self._subparser),
284
+ config.apply(scheduler=args.scheduler, cfg=args.scheduler_cfg)
285
+ component_args = (
286
+ args.component_args_str
287
+ if args.component_args_str != []
288
+ else args.component_args
279
289
  )
280
290
  try:
281
291
  if args.dryrun:
282
292
  dryrun_info = runner.dryrun_component(
283
- component,
293
+ args.component_name,
284
294
  component_args,
285
295
  args.scheduler,
286
296
  workspace=args.workspace,
287
- cfg=cfg,
297
+ cfg=args.scheduler_cfg,
288
298
  parent_run_id=args.parent_run_id,
289
299
  )
290
300
  print(
@@ -295,11 +305,11 @@ class CmdRun(SubCommand):
295
305
  print("\n=== SCHEDULER REQUEST ===\n" f"{dryrun_info}")
296
306
  else:
297
307
  app_handle = runner.run_component(
298
- component,
308
+ args.component_name,
299
309
  component_args,
300
310
  args.scheduler,
301
311
  workspace=args.workspace,
302
- cfg=cfg,
312
+ cfg=args.scheduler_cfg,
303
313
  parent_run_id=args.parent_run_id,
304
314
  )
305
315
  # DO NOT delete this line. It is used by slurm tests to retrieve the app id
@@ -320,7 +330,9 @@ class CmdRun(SubCommand):
320
330
  )
321
331
 
322
332
  except (ComponentValidationException, ComponentNotFoundException) as e:
323
- error_msg = f"\nFailed to run component `{component}` got errors: \n {e}"
333
+ error_msg = (
334
+ f"\nFailed to run component `{args.component_name}` got errors: \n {e}"
335
+ )
324
336
  logger.error(error_msg)
325
337
  sys.exit(1)
326
338
  except specs.InvalidRunConfigException as e:
@@ -335,6 +347,86 @@ class CmdRun(SubCommand):
335
347
  print(error_msg % (e, args.scheduler, args.scheduler), file=sys.stderr)
336
348
  sys.exit(1)
337
349
 
350
+ def _run_from_cli_args(self, runner: Runner, args: argparse.Namespace) -> None:
351
+ scheduler_opts = runner.scheduler_run_opts(args.scheduler)
352
+ cfg = scheduler_opts.cfg_from_str(args.scheduler_args)
353
+
354
+ component, component_args = _parse_component_name_and_args(
355
+ args.component_name_and_args,
356
+ none_throws(self._subparser),
357
+ )
358
+ torchx_run_args = torchx_run_args_from_argparse(
359
+ args, component, component_args, cfg
360
+ )
361
+ self._run_inner(runner, torchx_run_args)
362
+
363
+ def _run_from_stdin_args(self, runner: Runner, stdin_data: Dict[str, Any]) -> None:
364
+ torchx_run_args = torchx_run_args_from_json(stdin_data)
365
+ scheduler_opts = runner.scheduler_run_opts(torchx_run_args.scheduler)
366
+ cfg = scheduler_opts.cfg_from_json_repr(
367
+ json.dumps(torchx_run_args.scheduler_args)
368
+ )
369
+ torchx_run_args.scheduler_cfg = cfg
370
+ self._run_inner(runner, torchx_run_args)
371
+
372
+ def torchx_json_from_stdin(self) -> Dict[str, Any]:
373
+ try:
374
+ stdin_data_json = json.load(sys.stdin)
375
+ if not isinstance(stdin_data_json, dict):
376
+ logger.error(
377
+ "Invalid JSON input for `torchx run` command. Expected a dictionary."
378
+ )
379
+ sys.exit(1)
380
+ return stdin_data_json
381
+ except (json.JSONDecodeError, EOFError):
382
+ logger.error(
383
+ "Unable to parse JSON input for `torchx run` command, please make sure it's a valid JSON input."
384
+ )
385
+ sys.exit(1)
386
+
387
+ def verify_no_extra_args(self, args: argparse.Namespace) -> None:
388
+ """
389
+ Verifies that only --stdin was provided when using stdin mode.
390
+ """
391
+ if not args.stdin:
392
+ return
393
+
394
+ subparser = none_throws(self._subparser)
395
+ conflicting_args = []
396
+
397
+ # Check each argument against its default value
398
+ for action in subparser._actions:
399
+ if action.dest == "stdin": # Skip stdin itself
400
+ continue
401
+ if action.dest == "help": # Skip help
402
+ continue
403
+
404
+ current_value = getattr(args, action.dest, None)
405
+ default_value = action.default
406
+
407
+ # For arguments that differ from default
408
+ if current_value != default_value:
409
+ # Handle special cases where non-default doesn't mean explicitly set
410
+ if action.dest == "component_name_and_args" and current_value == []:
411
+ continue # Empty list is still default
412
+ print(f"*********\n {default_value} = {current_value}")
413
+ conflicting_args.append(f"--{action.dest.replace('_', '-')}")
414
+
415
+ if conflicting_args:
416
+ subparser.error(
417
+ f"Cannot specify {', '.join(conflicting_args)} when using --stdin. "
418
+ "All configuration should be provided in JSON input."
419
+ )
420
+
421
+ def _run(self, runner: Runner, args: argparse.Namespace) -> None:
422
+ # Verify no conflicting arguments when using to loop over the stdin
423
+ self.verify_no_extra_args(args)
424
+ if args.stdin:
425
+ stdin_data_json = self.torchx_json_from_stdin()
426
+ self._run_from_stdin_args(runner, stdin_data_json)
427
+ else:
428
+ self._run_from_cli_args(runner, args)
429
+
338
430
  def run(self, args: argparse.Namespace) -> None:
339
431
  os.environ["TORCHX_CONTEXT_NAME"] = os.getenv("TORCHX_CONTEXT_NAME", "cli_run")
340
432
  component_defaults = load_sections(prefix="component")
torchx/runner/api.py CHANGED
@@ -25,6 +25,7 @@ from typing import (
25
25
  Type,
26
26
  TYPE_CHECKING,
27
27
  TypeVar,
28
+ Union,
28
29
  )
29
30
 
30
31
  from torchx.runner.events import log_event
@@ -167,7 +168,7 @@ class Runner:
167
168
  def run_component(
168
169
  self,
169
170
  component: str,
170
- component_args: List[str],
171
+ component_args: Union[list[str], dict[str, Any]],
171
172
  scheduler: str,
172
173
  cfg: Optional[Mapping[str, CfgVal]] = None,
173
174
  workspace: Optional[str] = None,
@@ -226,7 +227,7 @@ class Runner:
226
227
  def dryrun_component(
227
228
  self,
228
229
  component: str,
229
- component_args: List[str],
230
+ component_args: Union[list[str], dict[str, Any]],
230
231
  scheduler: str,
231
232
  cfg: Optional[Mapping[str, CfgVal]] = None,
232
233
  workspace: Optional[str] = None,
@@ -237,10 +238,13 @@ class Runner:
237
238
  component, but just returns what "would" have run.
238
239
  """
239
240
  component_def = get_component(component)
241
+ args_from_cli = component_args if isinstance(component_args, list) else []
242
+ args_from_json = component_args if isinstance(component_args, dict) else {}
240
243
  app = materialize_appdef(
241
244
  component_def.fn,
242
- component_args,
245
+ args_from_cli,
243
246
  self._component_defaults.get(component, None),
247
+ args_from_json,
244
248
  )
245
249
  return self.dryrun(
246
250
  app,
torchx/specs/__init__.py CHANGED
@@ -225,5 +225,8 @@ __all__ = [
225
225
  "make_app_handle",
226
226
  "materialize_appdef",
227
227
  "parse_mounts",
228
+ "torchx_run_args_from_argparse",
229
+ "torchx_run_args_from_json",
230
+ "TorchXRunArgs",
228
231
  "ALL",
229
232
  ]
torchx/specs/builders.py CHANGED
@@ -213,7 +213,11 @@ def component_args_from_str(
213
213
  arg_value = getattr(parsed_args, param_name)
214
214
  parameter_type = parameter.annotation
215
215
  parameter_type = decode_optional(parameter_type)
216
- arg_value = decode(arg_value, parameter_type)
216
+ if (
217
+ parameter_type != arg_value.__class__
218
+ and parameter.kind != inspect.Parameter.VAR_POSITIONAL
219
+ ):
220
+ arg_value = decode(arg_value, parameter_type)
217
221
  if parameter.kind == inspect.Parameter.VAR_POSITIONAL:
218
222
  var_args = arg_value
219
223
  elif parameter.kind == inspect.Parameter.KEYWORD_ONLY:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: torchx-nightly
3
- Version: 2025.9.3
3
+ Version: 2025.9.4
4
4
  Summary: TorchX SDK and Components
5
5
  Home-page: https://github.com/pytorch/torchx
6
6
  Author: TorchX Devs
@@ -16,7 +16,7 @@ torchx/cli/cmd_configure.py,sha256=1kTv0qbsbV44So74plAySwWu56pQrqjhfW_kbfdC3Rw,1
16
16
  torchx/cli/cmd_describe.py,sha256=E5disbHoKTsqYKp2s3DaFW9GDLCCOgdOc3pQoHKoyCs,1283
17
17
  torchx/cli/cmd_list.py,sha256=4Y1ZOq-kqJbztoBt56hAW_InJEaJuDAjpKWgMhBw4II,1507
18
18
  torchx/cli/cmd_log.py,sha256=v-EZYUDOcG95rEgTnrsmPJMUyxM9Mk8YFAJtUxtgViE,5475
19
- torchx/cli/cmd_run.py,sha256=xSWo1IZB5Nife3AGExalW8DthPlT91xQCf3bdOYOeQQ,14419
19
+ torchx/cli/cmd_run.py,sha256=BtLl-FBVnf1B5VjyCMFgJrL20-PQN9k9akN6Oa3RGgg,18126
20
20
  torchx/cli/cmd_runopts.py,sha256=NWZiP8XpQjfTDJgays2c6MgL_8wxFoeDge6NstaZdKk,1302
21
21
  torchx/cli/cmd_status.py,sha256=22IAEmKs0qkG6kJi83u9dRX2Q-ntT7yehVx7FxtY-vQ,2114
22
22
  torchx/cli/cmd_tracker.py,sha256=RfLxE4Cq1wfk7k051RtZ8RPJp0pEKSCa3KmTeRs3LF8,5218
@@ -56,7 +56,7 @@ torchx/pipelines/kfp/__init__.py,sha256=8iJ8lql_fxwuk9VCYSxXnX6tPL228fB5mDZpOs-k
56
56
  torchx/pipelines/kfp/adapter.py,sha256=5GeHULjb1kxG6wJtYVLpNkgdzUi4iYEaR42VFOwT6fY,9045
57
57
  torchx/pipelines/kfp/version.py,sha256=mYBxd6bm4MeR34D--xo-JLQ9wHeAl_ZQLwbItCf9tr0,539
58
58
  torchx/runner/__init__.py,sha256=x8Sz7s_tLxPgJgvWIhK4ju9BNZU61uBFywGwDY6CqJs,315
59
- torchx/runner/api.py,sha256=I72ecOkUVqq7iMI_6H2_e0TJjU_URh-wLdLVLd5AYX8,30308
59
+ torchx/runner/api.py,sha256=CJmTjoV2kB0FVqeE9B-bYaFyiMuQsZCY32kY13CIk6I,30559
60
60
  torchx/runner/config.py,sha256=CBuYQCBj52fs4NclxJbdx5xtDdgNnfDd7XSdHPE1IGo,18267
61
61
  torchx/runner/events/__init__.py,sha256=1_y0bojXl3FL0zlAj7BI4Dg5cXKXUmaa2jZbVH0EDUA,5268
62
62
  torchx/runner/events/api.py,sha256=pPLfowWTXtN_XcrEDNI45pE6Ijvdc_Gdxq76RduqgGE,2664
@@ -82,9 +82,9 @@ torchx/schedulers/streams.py,sha256=8_SLezgnWgfv_zXUsJCUM34-h2dtv25NmZuxEwkzmxw,
82
82
  torchx/schedulers/ray/__init__.py,sha256=fE0IHi1JJpxsNVBNzWNee2thrNXFFRhY94c80RxNSIE,231
83
83
  torchx/schedulers/ray/ray_common.py,sha256=pyNYFvTKVwdjDAeCBNbPwAWwVNmlLOJWExfn90XY8u8,610
84
84
  torchx/schedulers/ray/ray_driver.py,sha256=RdaCLfth16ky-5PDVOWRe_RuheWJu9xufWux2F9T7iw,12302
85
- torchx/specs/__init__.py,sha256=c2ALDbqHIhNBhrYxwXXURRwu1Rg5jcwukWF8emEO1Bk,6347
85
+ torchx/specs/__init__.py,sha256=Gw_2actqR_oWFtxEkGXCxGk_yrWK5JDZzwysyyqmXao,6438
86
86
  torchx/specs/api.py,sha256=wkhHOxeWH_tFO3npKqPhNg4VX2NH5gPIFEylkPBo3AU,41315
87
- torchx/specs/builders.py,sha256=R60CdQvHhpGJ83_cwnJDVa_WAf1E_0Sqm92htJKFZsQ,13665
87
+ torchx/specs/builders.py,sha256=aozVl4q3h0mY5DDJCY1M1CyLC9SW66KJy8JIih8bZJo,13810
88
88
  torchx/specs/file_linter.py,sha256=QCwob5STTBuy8RsxaevTI-Dk6R8siDJn81LyaOwazes,12333
89
89
  torchx/specs/finder.py,sha256=lMCS1hUR-x7j4sAjfJZnKFeS1RlkFTeJtit4EL_ErIo,18182
90
90
  torchx/specs/named_resources_aws.py,sha256=ISjHtifRJqB8u7PeAMiyLyO_S0WCaZiK-CFF3qe6JDU,11415
@@ -115,9 +115,9 @@ torchx/workspace/__init__.py,sha256=FqN8AN4VhR1C_SBY10MggQvNZmyanbbuPuE-JCjkyUY,
115
115
  torchx/workspace/api.py,sha256=PtDkGTC5lX03pRoYpuMz2KCmM1ZOycRP1UknqvNb97Y,6341
116
116
  torchx/workspace/dir_workspace.py,sha256=npNW_IjUZm_yS5r-8hrRkH46ndDd9a_eApT64m1S1T4,2268
117
117
  torchx/workspace/docker_workspace.py,sha256=PFu2KQNVC-0p2aKJ-W_BKA9ZOmXdCY2ABEkCExp3udQ,10269
118
- torchx_nightly-2025.9.3.dist-info/LICENSE,sha256=WVHfXhFC0Ia8LTKt_nJVYobdqTJVg_4J3Crrfm2A8KQ,1721
119
- torchx_nightly-2025.9.3.dist-info/METADATA,sha256=xcGwmuaw3N3-9s2p4kLPrRRugzoq7xOcyrzIZugKAws,6103
120
- torchx_nightly-2025.9.3.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
121
- torchx_nightly-2025.9.3.dist-info/entry_points.txt,sha256=T328AMXeKI3JZnnxfkEew2ZcMN1oQDtkXjMz7lkV-P4,169
122
- torchx_nightly-2025.9.3.dist-info/top_level.txt,sha256=pxew3bc2gsiViS0zADs0jb6kC5v8o_Yy_85fhHj_J1A,7
123
- torchx_nightly-2025.9.3.dist-info/RECORD,,
118
+ torchx_nightly-2025.9.4.dist-info/LICENSE,sha256=WVHfXhFC0Ia8LTKt_nJVYobdqTJVg_4J3Crrfm2A8KQ,1721
119
+ torchx_nightly-2025.9.4.dist-info/METADATA,sha256=JbjR1Xl4KB9UbvnpQyD7EXmVS9xI376IdmQh8L7Hdqc,6103
120
+ torchx_nightly-2025.9.4.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
121
+ torchx_nightly-2025.9.4.dist-info/entry_points.txt,sha256=T328AMXeKI3JZnnxfkEew2ZcMN1oQDtkXjMz7lkV-P4,169
122
+ torchx_nightly-2025.9.4.dist-info/top_level.txt,sha256=pxew3bc2gsiViS0zADs0jb6kC5v8o_Yy_85fhHj_J1A,7
123
+ torchx_nightly-2025.9.4.dist-info/RECORD,,