torchx-nightly 2025.7.2__py3-none-any.whl → 2025.7.3__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.

@@ -30,8 +30,6 @@ from dataclasses import dataclass
30
30
  from pathlib import Path
31
31
  from typing import Optional
32
32
 
33
- from pyre_extensions import none_throws
34
-
35
33
  from torchx import specs
36
34
 
37
35
 
@@ -148,7 +146,8 @@ class StructuredNameArgument:
148
146
  if m: # use the last module name
149
147
  run_name = m.rpartition(".")[2]
150
148
  else: # use script name w/ no extension
151
- run_name = Path(none_throws(script)).stem
149
+ assert script, "`script` can't be `None` here due checks above"
150
+ run_name = Path(script).stem
152
151
  return StructuredNameArgument(
153
152
  experiment_name or default_experiment_name, run_name
154
153
  )
torchx/runner/api.py CHANGED
@@ -14,7 +14,18 @@ import time
14
14
  import warnings
15
15
  from datetime import datetime
16
16
  from types import TracebackType
17
- from typing import Any, Dict, Iterable, List, Mapping, Optional, Tuple, Type, TypeVar
17
+ from typing import (
18
+ Any,
19
+ Dict,
20
+ Iterable,
21
+ List,
22
+ Mapping,
23
+ Optional,
24
+ Tuple,
25
+ Type,
26
+ TYPE_CHECKING,
27
+ TypeVar,
28
+ )
18
29
 
19
30
  from torchx.runner.events import log_event
20
31
  from torchx.schedulers import get_scheduler_factories, SchedulerFactory
@@ -43,7 +54,9 @@ from torchx.util.session import get_session_id_or_create_new, TORCHX_INTERNAL_SE
43
54
 
44
55
  from torchx.util.types import none_throws
45
56
  from torchx.workspace.api import PkgInfo, WorkspaceBuilder, WorkspaceMixin
46
- from typing_extensions import Self
57
+
58
+ if TYPE_CHECKING:
59
+ from typing_extensions import Self
47
60
 
48
61
  from .config import get_config, get_configs
49
62
 
@@ -121,7 +134,7 @@ class Runner:
121
134
  scheduler_params[lower_case_key.strip("torchx_")] = value
122
135
  return scheduler_params
123
136
 
124
- def __enter__(self) -> Self:
137
+ def __enter__(self) -> "Self":
125
138
  return self
126
139
 
127
140
  def __exit__(
@@ -8,11 +8,10 @@
8
8
  # pyre-strict
9
9
 
10
10
  import importlib
11
- from typing import Dict, Mapping
11
+ from typing import Mapping, Protocol
12
12
 
13
13
  from torchx.schedulers.api import Scheduler
14
14
  from torchx.util.entrypoints import load_group
15
- from typing_extensions import Protocol
16
15
 
17
16
  DEFAULT_SCHEDULER_MODULES: Mapping[str, str] = {
18
17
  "local_docker": "torchx.schedulers.docker_scheduler",
@@ -44,7 +43,7 @@ def _defer_load_scheduler(path: str) -> SchedulerFactory:
44
43
 
45
44
  def get_scheduler_factories(
46
45
  group: str = "torchx.schedulers", skip_defaults: bool = False
47
- ) -> Dict[str, SchedulerFactory]:
46
+ ) -> dict[str, SchedulerFactory]:
48
47
  """
49
48
  get_scheduler_factories returns all the available schedulers names under `group` and the
50
49
  method to instantiate them.
@@ -52,7 +51,7 @@ def get_scheduler_factories(
52
51
  The first scheduler in the dictionary is used as the default scheduler.
53
52
  """
54
53
 
55
- default_schedulers: Dict[str, SchedulerFactory] = {}
54
+ default_schedulers: dict[str, SchedulerFactory] = {}
56
55
  for scheduler, path in DEFAULT_SCHEDULER_MODULES.items():
57
56
  default_schedulers[scheduler] = _defer_load_scheduler(path)
58
57
 
torchx/schedulers/api.py CHANGED
@@ -16,7 +16,6 @@ from typing import Generic, Iterable, List, Optional, TypeVar
16
16
 
17
17
  from torchx.specs import (
18
18
  AppDef,
19
- AppDryRunInfo,
20
19
  AppState,
21
20
  NONE,
22
21
  NULL_RESOURCE,
@@ -53,13 +53,13 @@ from typing import (
53
53
  Optional,
54
54
  Tuple,
55
55
  TYPE_CHECKING,
56
+ TypedDict,
56
57
  TypeVar,
57
58
  )
58
59
 
59
60
  import torchx
60
61
  import yaml
61
62
  from torchx.schedulers.api import (
62
- AppDryRunInfo,
63
63
  DescribeAppResponse,
64
64
  filter_regex,
65
65
  ListAppResponse,
@@ -71,6 +71,7 @@ from torchx.schedulers.devices import get_device_mounts
71
71
  from torchx.schedulers.ids import make_unique
72
72
  from torchx.specs.api import (
73
73
  AppDef,
74
+ AppDryRunInfo,
74
75
  AppState,
75
76
  BindMount,
76
77
  CfgVal,
@@ -86,7 +87,6 @@ from torchx.specs.api import (
86
87
  from torchx.specs.named_resources_aws import instance_type_from_resource
87
88
  from torchx.util.types import none_throws
88
89
  from torchx.workspace.docker_workspace import DockerWorkspaceMixin
89
- from typing_extensions import TypedDict
90
90
 
91
91
  ENV_TORCHX_ROLE_IDX = "TORCHX_ROLE_IDX"
92
92
 
@@ -25,6 +25,7 @@ from typing import (
25
25
  OrderedDict,
26
26
  Tuple,
27
27
  TYPE_CHECKING,
28
+ TypedDict,
28
29
  TypeVar,
29
30
  )
30
31
 
@@ -34,16 +35,14 @@ import yaml
34
35
  from sagemaker.pytorch import PyTorch
35
36
  from torchx.components.structured_arg import StructuredNameArgument
36
37
  from torchx.schedulers.api import (
37
- AppDryRunInfo,
38
38
  DescribeAppResponse,
39
39
  ListAppResponse,
40
40
  Scheduler,
41
41
  Stream,
42
42
  )
43
43
  from torchx.schedulers.ids import make_unique
44
- from torchx.specs.api import AppDef, AppState, CfgVal, runopts
44
+ from torchx.specs.api import AppDef, AppDryRunInfo, AppState, CfgVal, runopts
45
45
  from torchx.workspace.docker_workspace import DockerWorkspaceMixin
46
- from typing_extensions import TypedDict
47
46
 
48
47
 
49
48
  if TYPE_CHECKING:
@@ -13,12 +13,11 @@ import re
13
13
  import tempfile
14
14
  from dataclasses import dataclass
15
15
  from datetime import datetime
16
- from typing import Any, Dict, Iterable, List, Optional, TYPE_CHECKING, Union
16
+ from typing import Any, Dict, Iterable, List, Optional, TYPE_CHECKING, TypedDict, Union
17
17
 
18
18
  import torchx
19
19
  import yaml
20
20
  from torchx.schedulers.api import (
21
- AppDryRunInfo,
22
21
  DescribeAppResponse,
23
22
  filter_regex,
24
23
  ListAppResponse,
@@ -30,6 +29,7 @@ from torchx.schedulers.devices import get_device_mounts
30
29
  from torchx.schedulers.ids import make_unique
31
30
  from torchx.specs.api import (
32
31
  AppDef,
32
+ AppDryRunInfo,
33
33
  AppState,
34
34
  BindMount,
35
35
  DeviceMount,
@@ -42,7 +42,6 @@ from torchx.specs.api import (
42
42
  VolumeMount,
43
43
  )
44
44
  from torchx.workspace.docker_workspace import DockerWorkspaceMixin
45
- from typing_extensions import TypedDict
46
45
 
47
46
 
48
47
  if TYPE_CHECKING:
@@ -24,22 +24,28 @@ See https://cloud.google.com/batch/docs/get-started#prerequisites
24
24
 
25
25
  from dataclasses import dataclass
26
26
  from datetime import datetime
27
- from typing import Any, Dict, Iterable, List, Optional, TYPE_CHECKING
27
+ from typing import Any, Dict, Iterable, List, Optional, TYPE_CHECKING, TypedDict
28
28
 
29
29
  import torchx
30
30
  import yaml
31
31
 
32
32
  from torchx.schedulers.api import (
33
- AppDryRunInfo,
34
33
  DescribeAppResponse,
35
34
  ListAppResponse,
36
35
  Scheduler,
37
36
  Stream,
38
37
  )
39
38
  from torchx.schedulers.ids import make_unique
40
- from torchx.specs.api import AppDef, AppState, macros, Resource, Role, runopts
39
+ from torchx.specs.api import (
40
+ AppDef,
41
+ AppDryRunInfo,
42
+ AppState,
43
+ macros,
44
+ Resource,
45
+ Role,
46
+ runopts,
47
+ )
41
48
  from torchx.util.strings import normalize_str
42
- from typing_extensions import TypedDict
43
49
 
44
50
 
45
51
  if TYPE_CHECKING:
@@ -17,8 +17,8 @@ Prerequisites
17
17
 
18
18
  TorchX Kubernetes_MCAD scheduler depends on AppWrapper + MCAD.
19
19
 
20
- Install MCAD:
21
- See deploying Multi-Cluster-Application-Dispatcher guide
20
+ Install MCAD:
21
+ See deploying Multi-Cluster-Application-Dispatcher guide
22
22
  https://github.com/project-codeflare/multi-cluster-app-dispatcher/blob/main/doc/deploy/deployment.md
23
23
 
24
24
  This implementation requires MCAD v1.34.1 or higher.
@@ -46,12 +46,12 @@ from typing import (
46
46
  Optional,
47
47
  Tuple,
48
48
  TYPE_CHECKING,
49
+ TypedDict,
49
50
  )
50
51
 
51
52
  import torchx
52
53
  import yaml
53
54
  from torchx.schedulers.api import (
54
- AppDryRunInfo,
55
55
  DescribeAppResponse,
56
56
  filter_regex,
57
57
  ListAppResponse,
@@ -62,6 +62,7 @@ from torchx.schedulers.api import (
62
62
  from torchx.schedulers.ids import make_unique
63
63
  from torchx.specs.api import (
64
64
  AppDef,
65
+ AppDryRunInfo,
65
66
  AppState,
66
67
  BindMount,
67
68
  CfgVal,
@@ -78,7 +79,6 @@ from torchx.specs.api import (
78
79
  )
79
80
 
80
81
  from torchx.workspace.docker_workspace import DockerWorkspaceMixin
81
- from typing_extensions import TypedDict
82
82
 
83
83
  if TYPE_CHECKING:
84
84
  from docker import DockerClient
@@ -600,7 +600,7 @@ def app_to_resource(
600
600
 
601
601
  """
602
602
  Create Service:
603
- The selector will have the key 'appwrapper.workload.codeflare.dev', and the value will be
603
+ The selector will have the key 'appwrapper.workload.codeflare.dev', and the value will be
604
604
  the appwrapper name
605
605
  """
606
606
 
@@ -797,7 +797,8 @@ class KubernetesMCADOpts(TypedDict, total=False):
797
797
 
798
798
 
799
799
  class KubernetesMCADScheduler(
800
- DockerWorkspaceMixin, Scheduler[KubernetesMCADOpts, AppDef, AppDryRunInfo]
800
+ DockerWorkspaceMixin,
801
+ Scheduler[KubernetesMCADOpts, AppDef, AppDryRunInfo[KubernetesMCADJob]],
801
802
  ):
802
803
  """
803
804
  KubernetesMCADScheduler is a TorchX scheduling interface to Kubernetes.
@@ -994,7 +995,7 @@ class KubernetesMCADScheduler(
994
995
  if image_secret is not None and service_account is not None:
995
996
  msg = """Service Account and Image Secret names are both provided.
996
997
  Depending on the Service Account configuration, an ImagePullSecret may be defined in your Service Account.
997
- If this is the case, check service account and image secret configurations to understand the expected behavior for
998
+ If this is the case, check service account and image secret configurations to understand the expected behavior for
998
999
  patched image push access."""
999
1000
  warnings.warn(msg)
1000
1001
  namespace = cfg.get("namespace")
@@ -44,12 +44,12 @@ from typing import (
44
44
  Optional,
45
45
  Tuple,
46
46
  TYPE_CHECKING,
47
+ TypedDict,
47
48
  )
48
49
 
49
50
  import torchx
50
51
  import yaml
51
52
  from torchx.schedulers.api import (
52
- AppDryRunInfo,
53
53
  DescribeAppResponse,
54
54
  filter_regex,
55
55
  ListAppResponse,
@@ -60,6 +60,7 @@ from torchx.schedulers.api import (
60
60
  from torchx.schedulers.ids import make_unique
61
61
  from torchx.specs.api import (
62
62
  AppDef,
63
+ AppDryRunInfo,
63
64
  AppState,
64
65
  BindMount,
65
66
  CfgVal,
@@ -75,7 +76,6 @@ from torchx.specs.api import (
75
76
  )
76
77
  from torchx.util.strings import normalize_str
77
78
  from torchx.workspace.docker_workspace import DockerWorkspaceMixin
78
- from typing_extensions import TypedDict
79
79
 
80
80
 
81
81
  if TYPE_CHECKING:
@@ -40,10 +40,10 @@ from typing import (
40
40
  Protocol,
41
41
  TextIO,
42
42
  Tuple,
43
+ TypedDict,
43
44
  )
44
45
 
45
46
  from torchx.schedulers.api import (
46
- AppDryRunInfo,
47
47
  DescribeAppResponse,
48
48
  filter_regex,
49
49
  ListAppResponse,
@@ -53,10 +53,10 @@ from torchx.schedulers.api import (
53
53
  )
54
54
  from torchx.schedulers.ids import make_unique
55
55
  from torchx.schedulers.streams import Tee
56
+ from torchx.specs import AppDryRunInfo
56
57
  from torchx.specs.api import AppDef, AppState, is_terminal, macros, NONE, Role, runopts
57
58
 
58
59
  from torchx.util.types import none_throws
59
- from typing_extensions import TypedDict
60
60
 
61
61
  log: logging.Logger = logging.getLogger(__name__)
62
62
 
@@ -29,11 +29,10 @@ import subprocess
29
29
  import tempfile
30
30
  from dataclasses import dataclass
31
31
  from datetime import datetime
32
- from typing import Any, Dict, Iterable, List, Optional
32
+ from typing import Any, Dict, Iterable, List, Optional, TypedDict
33
33
 
34
34
  import torchx
35
35
  from torchx.schedulers.api import (
36
- AppDryRunInfo,
37
36
  DescribeAppResponse,
38
37
  filter_regex,
39
38
  ListAppResponse,
@@ -45,6 +44,7 @@ from torchx.schedulers.ids import make_unique
45
44
  from torchx.schedulers.local_scheduler import LogIterator
46
45
  from torchx.specs import (
47
46
  AppDef,
47
+ AppDryRunInfo,
48
48
  AppState,
49
49
  BindMount,
50
50
  DeviceMount,
@@ -57,7 +57,6 @@ from torchx.specs import (
57
57
  VolumeMount,
58
58
  )
59
59
  from torchx.util import shlex
60
- from typing_extensions import TypedDict
61
60
 
62
61
  JOB_STATE: Dict[str, AppState] = {
63
62
  "DONE": AppState.SUCCEEDED,
@@ -14,7 +14,17 @@ import time
14
14
  from dataclasses import dataclass, field
15
15
  from datetime import datetime
16
16
  from shutil import copy2, rmtree
17
- from typing import Any, cast, Dict, Final, Iterable, List, Optional, Tuple # noqa
17
+ from typing import ( # noqa
18
+ Any,
19
+ cast,
20
+ Dict,
21
+ Final,
22
+ Iterable,
23
+ List,
24
+ Optional,
25
+ Tuple,
26
+ TypedDict,
27
+ )
18
28
 
19
29
  import urllib3
20
30
 
@@ -23,7 +33,6 @@ from ray.dashboard.modules.job.common import JobStatus
23
33
  from ray.dashboard.modules.job.sdk import JobSubmissionClient
24
34
 
25
35
  from torchx.schedulers.api import (
26
- AppDryRunInfo,
27
36
  AppState,
28
37
  DescribeAppResponse,
29
38
  filter_regex,
@@ -34,9 +43,17 @@ from torchx.schedulers.api import (
34
43
  )
35
44
  from torchx.schedulers.ids import make_unique
36
45
  from torchx.schedulers.ray.ray_common import RayActor, TORCHX_RANK0_HOST
37
- from torchx.specs import AppDef, macros, NONE, ReplicaStatus, Role, RoleStatus, runopts
46
+ from torchx.specs import (
47
+ AppDef,
48
+ AppDryRunInfo,
49
+ macros,
50
+ NONE,
51
+ ReplicaStatus,
52
+ Role,
53
+ RoleStatus,
54
+ runopts,
55
+ )
38
56
  from torchx.workspace.dir_workspace import TmpDirWorkspaceMixin
39
- from typing_extensions import TypedDict
40
57
 
41
58
 
42
59
  class RayOpts(TypedDict, total=False):
@@ -21,11 +21,10 @@ import tempfile
21
21
  from dataclasses import dataclass
22
22
  from datetime import datetime
23
23
  from subprocess import CalledProcessError, PIPE
24
- from typing import Any, Dict, Iterable, List, Mapping, Optional, Tuple
24
+ from typing import Any, Dict, Iterable, List, Mapping, Optional, Tuple, TypedDict
25
25
 
26
26
  import torchx
27
27
  from torchx.schedulers.api import (
28
- AppDryRunInfo,
29
28
  DescribeAppResponse,
30
29
  filter_regex,
31
30
  ListAppResponse,
@@ -36,6 +35,7 @@ from torchx.schedulers.api import (
36
35
  from torchx.schedulers.local_scheduler import LogIterator
37
36
  from torchx.specs import (
38
37
  AppDef,
38
+ AppDryRunInfo,
39
39
  AppState,
40
40
  macros,
41
41
  NONE,
@@ -46,7 +46,6 @@ from torchx.specs import (
46
46
  runopts,
47
47
  )
48
48
  from torchx.workspace.dir_workspace import DirWorkspaceMixin
49
- from typing_extensions import TypedDict
50
49
 
51
50
  SLURM_JOB_DIRS = ".torchxslurmjobdirs"
52
51
 
@@ -5,14 +5,13 @@
5
5
  # LICENSE file in the root directory of this source tree.
6
6
 
7
7
  # pyre-strict
8
+ # pyre-ignore-all-errors[3, 2, 16]
8
9
 
10
+ from importlib import metadata
11
+ from importlib.metadata import EntryPoint
9
12
  from typing import Any, Dict, Optional
10
13
 
11
- import importlib_metadata as metadata
12
- from importlib_metadata import EntryPoint
13
14
 
14
-
15
- # pyre-ignore-all-errors[3, 2]
16
15
  def load(group: str, name: str, default=None):
17
16
  """
18
17
  Loads the entry point specified by
@@ -30,13 +29,34 @@ def load(group: str, name: str, default=None):
30
29
  raises an error.
31
30
  """
32
31
 
33
- entrypoints = metadata.entry_points().select(group=group)
32
+ # [note_on_entrypoints]
33
+ # return type of importlib.metadata.entry_points() is different between python-3.9 and python-3.10
34
+ # https://docs.python.org/3.9/library/importlib.metadata.html#importlib.metadata.entry_points
35
+ # https://docs.python.org/3.10/library/importlib.metadata.html#importlib.metadata.entry_points
36
+ if hasattr(metadata.entry_points(), "select"):
37
+ # python>=3.10
38
+ entrypoints = metadata.entry_points().select(group=group)
34
39
 
35
- if name not in entrypoints.names and default is not None:
36
- return default
40
+ if name not in entrypoints.names and default is not None:
41
+ return default
42
+
43
+ ep = entrypoints[name]
44
+ return ep.load()
37
45
 
38
- ep = entrypoints[name]
39
- return ep.load()
46
+ else:
47
+ # python<3.10 (e.g. 3.9)
48
+ # metadata.entry_points() returns dict[str, tuple[EntryPoint]] (not EntryPoints) in python-3.9
49
+ entrypoints = metadata.entry_points().get(group, ())
50
+
51
+ for ep in entrypoints:
52
+ if ep.name == name:
53
+ return ep.load()
54
+
55
+ # [group].name not found
56
+ if default is not None:
57
+ return default
58
+ else:
59
+ raise KeyError(f"entrypoint {group}.{name} not found")
40
60
 
41
61
 
42
62
  def _defer_load_ep(ep: EntryPoint) -> object:
@@ -49,7 +69,6 @@ def _defer_load_ep(ep: EntryPoint) -> object:
49
69
  return run
50
70
 
51
71
 
52
- # pyre-ignore-all-errors[3, 2]
53
72
  def load_group(
54
73
  group: str, default: Optional[Dict[str, Any]] = None, skip_defaults: bool = False
55
74
  ):
@@ -87,7 +106,13 @@ def load_group(
87
106
 
88
107
  """
89
108
 
90
- entrypoints = metadata.entry_points().select(group=group)
109
+ # see [note_on_entrypoints] above
110
+ if hasattr(metadata.entry_points(), "select"):
111
+ # python>=3.10
112
+ entrypoints = metadata.entry_points().select(group=group)
113
+ else:
114
+ # python<3.10 (e.g. 3.9)
115
+ entrypoints = metadata.entry_points().get(group, ())
91
116
 
92
117
  if len(entrypoints) == 0:
93
118
  if skip_defaults:
torchx/util/types.py CHANGED
@@ -8,12 +8,10 @@
8
8
 
9
9
  import inspect
10
10
  import re
11
- from typing import Any, Callable, Dict, List, Optional, Tuple, Type, TypeVar, Union
11
+ from typing import Any, Callable, Optional, Tuple, TypeVar, Union
12
12
 
13
- import typing_inspect
14
13
 
15
-
16
- def to_list(arg: str) -> List[str]:
14
+ def to_list(arg: str) -> list[str]:
17
15
  conf = []
18
16
  if len(arg.strip()) == 0:
19
17
  return []
@@ -22,9 +20,9 @@ def to_list(arg: str) -> List[str]:
22
20
  return conf
23
21
 
24
22
 
25
- def to_dict(arg: str) -> Dict[str, str]:
23
+ def to_dict(arg: str) -> dict[str, str]:
26
24
  """
27
- Parses the given ``arg`` string literal into a ``Dict[str, str]`` of
25
+ Parses the given ``arg`` string literal into a ``dict[str, str]`` of
28
26
  key-value pairs delimited by ``"="`` (equals). The values may be a
29
27
  list literal where the list elements are delimited by ``","`` (comma)
30
28
  or ``";"`` (semi-colon). The same delimiters (``","`` and ``";"``) are used
@@ -85,14 +83,14 @@ def to_dict(arg: str) -> Dict[str, str]:
85
83
  return val[1:-1]
86
84
  return val if val != '""' and val != "''" else ""
87
85
 
88
- arg_map: Dict[str, str] = {}
86
+ arg_map: dict[str, str] = {}
89
87
 
90
88
  if not arg:
91
89
  return arg_map
92
90
 
93
91
  # find quoted values
94
92
  quoted_pattern = r'([\'"])((?:\\.|(?!\1).)*?)\1'
95
- quoted_values: List[str] = []
93
+ quoted_values: list[str] = []
96
94
 
97
95
  def replace_quoted(match):
98
96
  quoted_values.append(match.group(0))
@@ -133,9 +131,13 @@ def to_dict(arg: str) -> Dict[str, str]:
133
131
 
134
132
  # pyre-ignore-all-errors[3, 2]
135
133
  def _decode_string_to_dict(
136
- encoded_value: str, param_type: Type[Dict[Any, Any]]
137
- ) -> Dict[Any, Any]:
138
- key_type, value_type = typing_inspect.get_args(param_type)
134
+ encoded_value: str, param_type: type[dict[Any, Any]]
135
+ ) -> dict[Any, Any]:
136
+ # pyre-ignore[16]
137
+ if not hasattr(param_type, "__args__") or len(param_type.__args__) != 2:
138
+ raise ValueError(f"param_type must be a `dict` type, but was `{param_type}`")
139
+
140
+ key_type, value_type = param_type.__args__
139
141
  arg_values = {}
140
142
  for key, value in to_dict(encoded_value).items():
141
143
  arg_values[key_type(key)] = value_type(value)
@@ -143,9 +145,12 @@ def _decode_string_to_dict(
143
145
 
144
146
 
145
147
  def _decode_string_to_list(
146
- encoded_value: str, param_type: Type[List[Any]]
147
- ) -> List[Any]:
148
- value_type = typing_inspect.get_args(param_type)[0]
148
+ encoded_value: str, param_type: type[list[Any]]
149
+ ) -> list[Any]:
150
+ # pyre-ignore[16]
151
+ if not hasattr(param_type, "__args__") or len(param_type.__args__) != 1:
152
+ raise ValueError(f"param_type must be a `list` type, but was `{param_type}`")
153
+ value_type = param_type.__args__[0]
149
154
  if not is_primitive(value_type):
150
155
  raise ValueError("List types support only primitives: int, str, float")
151
156
  arg_values = []
@@ -166,7 +171,7 @@ def decode(encoded_value: Any, annotation: Any):
166
171
 
167
172
  def decode_from_string(
168
173
  encoded_value: str, annotation: Any
169
- ) -> Union[Dict[Any, Any], List[Any], None]:
174
+ ) -> Union[dict[Any, Any], list[Any], None]:
170
175
  """Decodes string representation to the underlying type(Dict or List)
171
176
 
172
177
  Given a string representation of the value, the method decodes it according
@@ -191,13 +196,13 @@ def decode_from_string(
191
196
  if not encoded_value:
192
197
  return None
193
198
  value_type = annotation
194
- value_origin = typing_inspect.get_origin(value_type)
195
- if value_origin is dict:
196
- return _decode_string_to_dict(encoded_value, value_type)
197
- elif value_origin is list:
198
- return _decode_string_to_list(encoded_value, value_type)
199
- else:
200
- raise ValueError("Unknown")
199
+ if hasattr(value_type, "__origin__"):
200
+ value_origin = value_type.__origin__
201
+ if value_origin is dict:
202
+ return _decode_string_to_dict(encoded_value, value_type)
203
+ elif value_origin is list:
204
+ return _decode_string_to_list(encoded_value, value_type)
205
+ raise ValueError("Unknown")
201
206
 
202
207
 
203
208
  def is_bool(param_type: Any) -> bool:
@@ -229,12 +234,13 @@ def decode_optional(param_type: Any) -> Any:
229
234
  If ``param_type`` is type Optional[INNER_TYPE], method returns INNER_TYPE
230
235
  Otherwise returns ``param_type``
231
236
  """
232
- param_origin = typing_inspect.get_origin(param_type)
233
- if param_origin is not Union:
237
+ if not hasattr(param_type, "__origin__"):
238
+ return param_type
239
+ if param_type.__origin__ is not Union:
234
240
  return param_type
235
- key_type, value_type = typing_inspect.get_args(param_type)
236
- if value_type is type(None):
237
- return key_type
241
+ args = param_type.__args__
242
+ if len(args) == 2 and args[1] is type(None):
243
+ return args[0]
238
244
  else:
239
245
  return param_type
240
246
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: torchx-nightly
3
- Version: 2025.7.2
3
+ Version: 2025.7.3
4
4
  Summary: TorchX SDK and Components
5
5
  Home-page: https://github.com/pytorch/torchx
6
6
  Author: TorchX Devs
@@ -17,9 +17,7 @@ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
17
17
  Requires-Python: >=3.7
18
18
  Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
- Requires-Dist: pyre-extensions
21
20
  Requires-Dist: docstring-parser>=0.8.1
22
- Requires-Dist: importlib-metadata
23
21
  Requires-Dist: pyyaml
24
22
  Requires-Dist: docker
25
23
  Requires-Dist: filelock
@@ -60,6 +58,7 @@ Requires-Dist: torchmetrics==1.6.3; extra == "dev"
60
58
  Requires-Dist: torchserve>=0.10.0; extra == "dev"
61
59
  Requires-Dist: torchtext==0.18.0; extra == "dev"
62
60
  Requires-Dist: torchvision==0.22.0; extra == "dev"
61
+ Requires-Dist: typing-extensions; extra == "dev"
63
62
  Requires-Dist: ts==0.5.1; extra == "dev"
64
63
  Requires-Dist: ray[default]; extra == "dev"
65
64
  Requires-Dist: wheel; extra == "dev"
@@ -28,7 +28,7 @@ torchx/components/dist.py,sha256=9jECk3jjQ4Yh4oWDK8vnQ7kcI0-OWCbbwj8uvBdI9FU,145
28
28
  torchx/components/interpret.py,sha256=g8gkKdDJvsBfX1ZrpVT7n2bMEtmwRV_1AqDyAnnQ_aA,697
29
29
  torchx/components/metrics.py,sha256=1gbp8BfzZWGa7PD1db5vRADlONzmae4qSBUUdCWayr0,2814
30
30
  torchx/components/serve.py,sha256=uxIC5gU2ecg0EJIPX_oEPzNNOXRAre4j2eXusrgwGAI,2156
31
- torchx/components/structured_arg.py,sha256=etjZ1XRttrolvtr1bFuTi7bVsmvBAgqO0q-TeM3Etxk,9569
31
+ torchx/components/structured_arg.py,sha256=8jMcd0rtUmzCKEQKJ_JYzxSkMMK9q0fYjkwAs6wo78E,9595
32
32
  torchx/components/train.py,sha256=vtrQXRcD7bIcbb3lSeyD9BBlIe1mv1WNW6rnLK9R0Mw,1259
33
33
  torchx/components/utils.py,sha256=QRBxBm1OnNhOhpPs0lKdbJ8_mNhWYMklY6cl1gPIw9A,9363
34
34
  torchx/components/integration_tests/__init__.py,sha256=Md3cCHD7Ano9kV15PqGbicgUO-RMdh4aVy1yKiDt_xE,208
@@ -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=0Qv9X6KYSUUeBkK7RS8u_1Oxk6p_0qZ5BHqb4xvFPvA,30000
59
+ torchx/runner/api.py,sha256=SQPwc_gar6o1qCBfjvG3XS4tQ6qcsNwUPuQTjJ6thXM,30085
60
60
  torchx/runner/config.py,sha256=qpq_RfUSUykquAsEKOhDT3xBsa-m3wc6F6O8oP2QJ7k,18303
61
61
  torchx/runner/events/__init__.py,sha256=1_y0bojXl3FL0zlAj7BI4Dg5cXKXUmaa2jZbVH0EDUA,5268
62
62
  torchx/runner/events/api.py,sha256=pPLfowWTXtN_XcrEDNI45pE6Ijvdc_Gdxq76RduqgGE,2664
@@ -64,20 +64,20 @@ torchx/runner/events/handlers.py,sha256=ThHCIJW21BfBgB7b6ftyjASJmD1KdizpjuTtsyqn
64
64
  torchx/runtime/__init__.py,sha256=Wxje2BryzeQneFu5r6P9JJiEKG-_C9W1CcZ_JNrKT6g,593
65
65
  torchx/runtime/tracking/__init__.py,sha256=dYnAPnrXYREfPXkpHhdOFkcYIODWEbA13PdD-wLQYBo,3055
66
66
  torchx/runtime/tracking/api.py,sha256=SmUQyUKZqG3KlAhT7CJOGqRz1O274E4m63wQeOVq3CU,5472
67
- torchx/schedulers/__init__.py,sha256=gwy1opmKOPzQ_Lqh2GY0chYycLmdissLfd4846mPEMY,2334
68
- torchx/schedulers/api.py,sha256=zUlVtZ8gE4QoNTbd_xCGKQCmGS47jjT-vV-E9mdvEUc,14617
69
- torchx/schedulers/aws_batch_scheduler.py,sha256=h95d3OBhxkB7QJlJaDY3s1H7EG0eLXnCXxAPU8Ume3w,28130
70
- torchx/schedulers/aws_sagemaker_scheduler.py,sha256=spmcTEZ_o05pdTzpXr5gmOA-a9W0xH-YX6AioqX78l8,20950
67
+ torchx/schedulers/__init__.py,sha256=igIBdxGhkuzH7oYVFXIA9xwjkSn3QzWZ_9dhfdl_M0I,2299
68
+ torchx/schedulers/api.py,sha256=FbyG7mNnbXXj2_W1dQ_MnNO6fQe2FAd1rEz1R-BNg-c,14598
69
+ torchx/schedulers/aws_batch_scheduler.py,sha256=06CpJw6Y71-g9CH6A6lul5-WLO5qxINf3UKLyyNmzS0,28105
70
+ torchx/schedulers/aws_sagemaker_scheduler.py,sha256=flN8GumKE2Dz4X_foAt6Jnvt-ZVojWs6pcyrHwB0hz0,20921
71
71
  torchx/schedulers/devices.py,sha256=RjVcu22ZRl_9OKtOtmA1A3vNXgu2qD6A9ST0L0Hsg4I,1734
72
- torchx/schedulers/docker_scheduler.py,sha256=cNFjZm2zv6_v4wtDtou8PJTz0esxnXHc0UbSvrT1ER4,16810
73
- torchx/schedulers/gcp_batch_scheduler.py,sha256=Noul_a01FGjDaa3ohAJbx_Pjhy4SN1TPwl4TyHY75-0,16281
72
+ torchx/schedulers/docker_scheduler.py,sha256=xuK00-dB6o8TV1YaZox7O5P09LHB2KeQ6t4eiNtqMYQ,16781
73
+ torchx/schedulers/gcp_batch_scheduler.py,sha256=JQuaEJVL_7NSa9AeUc_0Qo74XZNJk_kp6XwgunvlUKI,16281
74
74
  torchx/schedulers/ids.py,sha256=3E-_vwVYC-8Tv8kjuY9-W7TbOe_-Laqd8a65uIN3hQY,1798
75
- torchx/schedulers/kubernetes_mcad_scheduler.py,sha256=-NHxKAW9bGnQ-4hpFhciZTlFJryPb3O_9oKv3f7MzuM,42954
76
- torchx/schedulers/kubernetes_scheduler.py,sha256=7AR3ccfta0NXqahxz9LVrv-vkdZnYTAHzw-sh_aLNDs,28242
77
- torchx/schedulers/local_scheduler.py,sha256=JMSGAO9RXeUiEz8BOTA_EnHDOd065oJ_tyV1E__m3OQ,41882
78
- torchx/schedulers/lsf_scheduler.py,sha256=e6BmJC6dNNNzzwATgJu5Sq4HxAPw_hI3EJFRojzAMlE,17690
79
- torchx/schedulers/ray_scheduler.py,sha256=9Sqesw3aOw_Z0gua2TY3aYE3OJ9MCi75hqVl_RUQwQY,15750
80
- torchx/schedulers/slurm_scheduler.py,sha256=Fj9ESKvmHgXagvAR3OHo0GMg7rTyB3L04RWZqtmmRPc,26440
75
+ torchx/schedulers/kubernetes_mcad_scheduler.py,sha256=1tuzq3OutCMdSPqg_dNmCHt_wyuSFKG0-ywLc3qITJo,42949
76
+ torchx/schedulers/kubernetes_scheduler.py,sha256=0_loGJ7WnxEr9dhgFt3Gw-7nVLirMDVN-MAFTCq7erE,28217
77
+ torchx/schedulers/local_scheduler.py,sha256=lOtVtmMIhytdju1Dlc3p99VALMY3qYRDPqjxdyTAbQQ,41877
78
+ torchx/schedulers/lsf_scheduler.py,sha256=YS6Yel8tXJqLPxbcGz95lZG2nCi36AQXdNDyuBJePKg,17661
79
+ torchx/schedulers/ray_scheduler.py,sha256=T-jsGSOa8O-h1kTUU7Q7Fk1RILL1Yzvuos_WFSQF8Fo,15795
80
+ torchx/schedulers/slurm_scheduler.py,sha256=zM_9XYVm7sQ8NGN-N26D-2YIfE83JS3mvpPb40CDKcA,26411
81
81
  torchx/schedulers/streams.py,sha256=8_SLezgnWgfv_zXUsJCUM34-h2dtv25NmZuxEwkzmxw,2007
82
82
  torchx/schedulers/ray/__init__.py,sha256=fE0IHi1JJpxsNVBNzWNee2thrNXFFRhY94c80RxNSIE,231
83
83
  torchx/schedulers/ray/ray_common.py,sha256=pyNYFvTKVwdjDAeCBNbPwAWwVNmlLOJWExfn90XY8u8,610
@@ -103,21 +103,21 @@ torchx/tracker/backend/fsspec.py,sha256=528xKryBE27Rm_OHD7r2R6fmVAclknBtoy1s034N
103
103
  torchx/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
104
104
  torchx/util/cuda.py,sha256=-ZTa1WCLnY2WtSWAdWufLQqZSDCZfZsloBuiS84LIkU,1099
105
105
  torchx/util/datetime.py,sha256=hV6Sg0u5KTBe68yrmy_RGCC5su0i4Tb_mAYphWamiXI,405
106
- torchx/util/entrypoints.py,sha256=J5WSFtCFVZ7ZjlAvzYcdWgVSUKC3aVo1eVmJAbWhpx8,2894
106
+ torchx/util/entrypoints.py,sha256=XgwCjQ5f1xchUVxABiPqODgd3--SrOtUTlgtMlAeKKc,3980
107
107
  torchx/util/io.py,sha256=HNpWLcFUX0WTAP3CsdamHz--FR5A4kSdLCPfNqa2UkA,1807
108
108
  torchx/util/log_tee_helpers.py,sha256=wPyozmh9BOt_2d3Gxa0iNogwnjzwFitIIMBJOJ1arIw,6330
109
109
  torchx/util/modules.py,sha256=o4y_d07gTpJ4nIVBcoUVJ0JtXIHEsEC5kbgBM6NGpgA,2135
110
110
  torchx/util/session.py,sha256=r6M_nyzXgcbk1GgYGZ324F_ehRGCqjjdVk4YgKxMj8M,1214
111
111
  torchx/util/shlex.py,sha256=eXEKu8KC3zIcd8tEy9_s8Ds5oma8BORr-0VGWNpG2dk,463
112
112
  torchx/util/strings.py,sha256=GkLWCmYS89Uv6bWc5hH0XwvHy7oQmprv2U7axC4A2e8,678
113
- torchx/util/types.py,sha256=msyHky81Du45OEzIhbSK-U2zJQyOCTQhRdq1qaYA7Uo,8552
113
+ torchx/util/types.py,sha256=xelu9gOUQ540GvvzDqk1wYb4csB09OgYQJwlVz62O5o,8889
114
114
  torchx/workspace/__init__.py,sha256=FqN8AN4VhR1C_SBY10MggQvNZmyanbbuPuE-JCjkyUY,798
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.7.2.dist-info/LICENSE,sha256=WVHfXhFC0Ia8LTKt_nJVYobdqTJVg_4J3Crrfm2A8KQ,1721
119
- torchx_nightly-2025.7.2.dist-info/METADATA,sha256=W4a8iBTq-BoJkZ6cCc_shSgBOMdMysnBGxK-7VSyxEE,6119
120
- torchx_nightly-2025.7.2.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
121
- torchx_nightly-2025.7.2.dist-info/entry_points.txt,sha256=T328AMXeKI3JZnnxfkEew2ZcMN1oQDtkXjMz7lkV-P4,169
122
- torchx_nightly-2025.7.2.dist-info/top_level.txt,sha256=pxew3bc2gsiViS0zADs0jb6kC5v8o_Yy_85fhHj_J1A,7
123
- torchx_nightly-2025.7.2.dist-info/RECORD,,
118
+ torchx_nightly-2025.7.3.dist-info/LICENSE,sha256=WVHfXhFC0Ia8LTKt_nJVYobdqTJVg_4J3Crrfm2A8KQ,1721
119
+ torchx_nightly-2025.7.3.dist-info/METADATA,sha256=5pjBLvh3OhHCIUn523kGJdXEK5NwRL7zlCipeKAbkpA,6103
120
+ torchx_nightly-2025.7.3.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
121
+ torchx_nightly-2025.7.3.dist-info/entry_points.txt,sha256=T328AMXeKI3JZnnxfkEew2ZcMN1oQDtkXjMz7lkV-P4,169
122
+ torchx_nightly-2025.7.3.dist-info/top_level.txt,sha256=pxew3bc2gsiViS0zADs0jb6kC5v8o_Yy_85fhHj_J1A,7
123
+ torchx_nightly-2025.7.3.dist-info/RECORD,,