experimaestro 1.5.7__py3-none-any.whl → 1.5.9__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 experimaestro might be problematic. Click here for more details.
- experimaestro/cli/jobs.py +8 -2
- experimaestro/connectors/ssh.py +2 -2
- experimaestro/core/types.py +8 -3
- experimaestro/experiments/cli.py +17 -20
- experimaestro/launcherfinder/__init__.py +1 -1
- experimaestro/launcherfinder/base.py +2 -18
- experimaestro/launcherfinder/registry.py +22 -129
- experimaestro/launchers/direct.py +0 -47
- experimaestro/scheduler/base.py +1 -1
- experimaestro/tests/launchers/config_slurm/launchers.py +25 -0
- experimaestro/tests/test_findlauncher.py +1 -1
- experimaestro/tokens.py +8 -8
- experimaestro/utils/resources.py +5 -1
- {experimaestro-1.5.7.dist-info → experimaestro-1.5.9.dist-info}/METADATA +1 -1
- {experimaestro-1.5.7.dist-info → experimaestro-1.5.9.dist-info}/RECORD +18 -21
- {experimaestro-1.5.7.dist-info → experimaestro-1.5.9.dist-info}/entry_points.txt +0 -4
- experimaestro/launchers/slurm/cli.py +0 -29
- experimaestro/launchers/slurm/configuration.py +0 -597
- experimaestro/tests/launchers/config_slurm/launchers.yaml +0 -134
- experimaestro/utils/yaml.py +0 -202
- {experimaestro-1.5.7.dist-info → experimaestro-1.5.9.dist-info}/LICENSE +0 -0
- {experimaestro-1.5.7.dist-info → experimaestro-1.5.9.dist-info}/WHEEL +0 -0
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
local: []
|
|
2
|
-
slurm:
|
|
3
|
-
-
|
|
4
|
-
id: "test_slurm"
|
|
5
|
-
|
|
6
|
-
features_regex:
|
|
7
|
-
- GPU(?P<cuda_count>\d+)
|
|
8
|
-
- GPUM(?P<cuda_memory>\d+G)
|
|
9
|
-
|
|
10
|
-
connector: local
|
|
11
|
-
configuration:
|
|
12
|
-
gpu:
|
|
13
|
-
# At least 40% of the memory should be requested
|
|
14
|
-
min_mem_ratio: 0.4
|
|
15
|
-
|
|
16
|
-
partitions:
|
|
17
|
-
electronic:
|
|
18
|
-
configuration: null
|
|
19
|
-
disabled: false
|
|
20
|
-
nodes:
|
|
21
|
-
- count: 0
|
|
22
|
-
features:
|
|
23
|
-
- GPU4
|
|
24
|
-
- RTX
|
|
25
|
-
- GPUM24G
|
|
26
|
-
hosts:
|
|
27
|
-
- daft
|
|
28
|
-
- kavinsky
|
|
29
|
-
- modjo
|
|
30
|
-
- punk
|
|
31
|
-
priority: 0
|
|
32
|
-
funky:
|
|
33
|
-
configuration: null
|
|
34
|
-
disabled: false
|
|
35
|
-
nodes:
|
|
36
|
-
- count: 0
|
|
37
|
-
features:
|
|
38
|
-
- GPU4
|
|
39
|
-
- TITANV
|
|
40
|
-
- GPUM12G
|
|
41
|
-
hosts:
|
|
42
|
-
- bernard
|
|
43
|
-
- count: 0
|
|
44
|
-
features:
|
|
45
|
-
- GPU4
|
|
46
|
-
- TITANX
|
|
47
|
-
- GPUM12G
|
|
48
|
-
hosts:
|
|
49
|
-
- chic
|
|
50
|
-
- edwards
|
|
51
|
-
- nile
|
|
52
|
-
- rodgers
|
|
53
|
-
- count: 0
|
|
54
|
-
features:
|
|
55
|
-
- GPU8
|
|
56
|
-
- TITANX
|
|
57
|
-
- GPUM12G
|
|
58
|
-
hosts:
|
|
59
|
-
- pascal
|
|
60
|
-
priority: 0
|
|
61
|
-
hard:
|
|
62
|
-
configuration: null
|
|
63
|
-
disabled: false
|
|
64
|
-
nodes:
|
|
65
|
-
- count: 0
|
|
66
|
-
features:
|
|
67
|
-
- GPU2
|
|
68
|
-
- A6000
|
|
69
|
-
- GPUM48G
|
|
70
|
-
hosts:
|
|
71
|
-
- aerosmith
|
|
72
|
-
- count: 0
|
|
73
|
-
features:
|
|
74
|
-
- GPU3
|
|
75
|
-
- A5000
|
|
76
|
-
- GPUM24G
|
|
77
|
-
hosts:
|
|
78
|
-
- led
|
|
79
|
-
- zeppelin
|
|
80
|
-
- count: 0
|
|
81
|
-
features:
|
|
82
|
-
- GPU3
|
|
83
|
-
- A6000
|
|
84
|
-
- GPUM48G
|
|
85
|
-
hosts:
|
|
86
|
-
- top
|
|
87
|
-
- zz
|
|
88
|
-
priority: 0
|
|
89
|
-
heavy:
|
|
90
|
-
configuration: null
|
|
91
|
-
disabled: true
|
|
92
|
-
nodes:
|
|
93
|
-
- count: 0
|
|
94
|
-
features:
|
|
95
|
-
- GPU8
|
|
96
|
-
- A100
|
|
97
|
-
- GPUM40G
|
|
98
|
-
hosts:
|
|
99
|
-
- a7x
|
|
100
|
-
priority: 0
|
|
101
|
-
jazzy:
|
|
102
|
-
configuration: null
|
|
103
|
-
disabled: false
|
|
104
|
-
nodes:
|
|
105
|
-
- count: 0
|
|
106
|
-
features:
|
|
107
|
-
- GPU4
|
|
108
|
-
- TITANX
|
|
109
|
-
- GPUM12G
|
|
110
|
-
hosts:
|
|
111
|
-
- cal
|
|
112
|
-
- pas
|
|
113
|
-
- titan
|
|
114
|
-
- count: 0
|
|
115
|
-
features:
|
|
116
|
-
- GPU2
|
|
117
|
-
- '3080'
|
|
118
|
-
- GPUM10G
|
|
119
|
-
hosts:
|
|
120
|
-
- project
|
|
121
|
-
- count: 0
|
|
122
|
-
features:
|
|
123
|
-
- GPU3
|
|
124
|
-
- '2080'
|
|
125
|
-
- GPUM11G
|
|
126
|
-
hosts:
|
|
127
|
-
- sister
|
|
128
|
-
- sledge
|
|
129
|
-
priority: 0
|
|
130
|
-
query_slurm: false
|
|
131
|
-
tags: []
|
|
132
|
-
use_features: true
|
|
133
|
-
use_hosts: true
|
|
134
|
-
weight: 0
|
experimaestro/utils/yaml.py
DELETED
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
from typing import Any, ClassVar, Dict, List, Optional, Type, TypeVar
|
|
3
|
-
import typing
|
|
4
|
-
from yaml import Loader, Dumper, MappingNode
|
|
5
|
-
|
|
6
|
-
from experimaestro import typingutils
|
|
7
|
-
|
|
8
|
-
logger = logging.getLogger("xpm.yaml")
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class YAMLException(Exception):
|
|
12
|
-
def __init__(self, key: str, name: str, line: int, column: int, message: str):
|
|
13
|
-
super().__init__(
|
|
14
|
-
f"Exception while setting {key} in {name}:{line}:{column}: {message}"
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def check_type(object, typehint):
|
|
19
|
-
typehint = typingutils.get_type(typehint)
|
|
20
|
-
if list_type := typingutils.get_list(typehint):
|
|
21
|
-
assert isinstance(object, list), f"{object} is not a list"
|
|
22
|
-
for el in object:
|
|
23
|
-
check_type(el, list_type)
|
|
24
|
-
elif dict_type := typingutils.get_dict(typehint):
|
|
25
|
-
assert isinstance(object, dict)
|
|
26
|
-
for key, value in object.items():
|
|
27
|
-
check_type(key, dict_type[0])
|
|
28
|
-
check_type(value, dict_type[1])
|
|
29
|
-
else:
|
|
30
|
-
assert isinstance(
|
|
31
|
-
object, typehint
|
|
32
|
-
), f"{type(object)} is not a subtype of {typehint}"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def register_yaml(
|
|
36
|
-
cls, yaml_loader: Type[Loader], yaml_dumper: Optional[Type[Dumper]] = None
|
|
37
|
-
):
|
|
38
|
-
yaml_tag = getattr(cls, "yaml_tag", None)
|
|
39
|
-
if yaml_tag is None and getattr(cls, "from_yaml", None):
|
|
40
|
-
cls.yaml_tag = f"!{cls.__module__}.{cls.__qualname__}"
|
|
41
|
-
logger.debug("Registering constructor %s / cls %s", cls.yaml_tag, cls.from_yaml)
|
|
42
|
-
yaml_loader.add_constructor(cls.yaml_tag, cls.from_yaml)
|
|
43
|
-
if yaml_dumper and (to_yaml := getattr(cls, "to_yaml", None)):
|
|
44
|
-
logger.debug("Registering YAML dumper for %s", cls)
|
|
45
|
-
yaml_dumper.add_representer(cls, to_yaml)
|
|
46
|
-
return True
|
|
47
|
-
|
|
48
|
-
# None when no from_yaml
|
|
49
|
-
return yaml_tag is not None
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
class YAMLDataClass:
|
|
53
|
-
"""Base class for dataclass driven YAML objects"""
|
|
54
|
-
|
|
55
|
-
__dataclass_fields__: ClassVar[Dict[str, Any]]
|
|
56
|
-
yaml_tag: ClassVar[str]
|
|
57
|
-
|
|
58
|
-
@classmethod
|
|
59
|
-
def to_yaml(cls, dumper: Dumper, data):
|
|
60
|
-
return dumper.represent_dict(
|
|
61
|
-
{key: getattr(data, key) for key, value in cls.__dataclass_fields__.items()}
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
@classmethod
|
|
65
|
-
def from_yaml(cls, loader: Loader, node):
|
|
66
|
-
kwargs = {}
|
|
67
|
-
for key, value in node.value:
|
|
68
|
-
try:
|
|
69
|
-
assert isinstance(key.value, str)
|
|
70
|
-
assert (
|
|
71
|
-
key.value in cls.__dataclass_fields__
|
|
72
|
-
), f"{key.value} is not a valid field for {cls}"
|
|
73
|
-
|
|
74
|
-
v = loader.construct_object(value, deep=True)
|
|
75
|
-
|
|
76
|
-
fieldtype = cls.__dataclass_fields__[key.value].type
|
|
77
|
-
if typingutils.is_annotated(fieldtype):
|
|
78
|
-
initializers = [
|
|
79
|
-
x
|
|
80
|
-
for x in typingutils.get_args(fieldtype)
|
|
81
|
-
if isinstance(x, Initialize)
|
|
82
|
-
]
|
|
83
|
-
assert (
|
|
84
|
-
len(initializers) <= 1
|
|
85
|
-
), "Too many initializers for this field"
|
|
86
|
-
if initializers:
|
|
87
|
-
v = initializers[0].fn(v)
|
|
88
|
-
|
|
89
|
-
# Cast if needed
|
|
90
|
-
origin = typingutils.get_type(fieldtype)
|
|
91
|
-
origin = typing.get_origin(origin) or origin
|
|
92
|
-
if origin and not isinstance(v, origin):
|
|
93
|
-
v = origin(v)
|
|
94
|
-
|
|
95
|
-
check_type(v, fieldtype)
|
|
96
|
-
kwargs[key.value] = v
|
|
97
|
-
except YAMLException:
|
|
98
|
-
raise
|
|
99
|
-
except Exception as e:
|
|
100
|
-
raise YAMLException(
|
|
101
|
-
key.value,
|
|
102
|
-
node.start_mark.name,
|
|
103
|
-
node.start_mark.line,
|
|
104
|
-
node.start_mark.column,
|
|
105
|
-
str(e),
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
return cls(**kwargs)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
T = TypeVar("T")
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
class YAMLList(List[T]):
|
|
115
|
-
@classmethod
|
|
116
|
-
def from_yaml(cls, loader, node):
|
|
117
|
-
array = [loader.construct_object(el, deep=True) for el in node.value]
|
|
118
|
-
ctype = cls.get_ctype()
|
|
119
|
-
for el in array:
|
|
120
|
-
assert isinstance(el, ctype)
|
|
121
|
-
|
|
122
|
-
return cls(array)
|
|
123
|
-
|
|
124
|
-
@classmethod
|
|
125
|
-
def get_ctype(cls):
|
|
126
|
-
(list_type,) = [
|
|
127
|
-
p for p in cls.__orig_bases__ if typing.get_origin(p) is YAMLList
|
|
128
|
-
]
|
|
129
|
-
(list_element_type,) = typingutils.get_args(list_type)
|
|
130
|
-
return list_element_type
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
class YAMLDict(Dict[str, T]):
|
|
134
|
-
@classmethod
|
|
135
|
-
def from_yaml(cls, loader, node):
|
|
136
|
-
map = {}
|
|
137
|
-
ctype = cls.get_ctype()
|
|
138
|
-
|
|
139
|
-
for node_key, node_value in node.value:
|
|
140
|
-
key = loader.construct_scalar(node_key)
|
|
141
|
-
value = loader.construct_object(node_value, deep=True)
|
|
142
|
-
assert isinstance(value, ctype), f"{value} is not of type {ctype}"
|
|
143
|
-
map[key] = value
|
|
144
|
-
|
|
145
|
-
print(map)
|
|
146
|
-
return cls(**map)
|
|
147
|
-
|
|
148
|
-
@classmethod
|
|
149
|
-
def get_ctype(cls):
|
|
150
|
-
(list_type,) = [
|
|
151
|
-
p for p in cls.__orig_bases__ if typing.get_origin(p) is YAMLDict
|
|
152
|
-
]
|
|
153
|
-
(value_type,) = typingutils.get_args(list_type)
|
|
154
|
-
return value_type
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
class Initialize:
|
|
158
|
-
def __init__(self, fn):
|
|
159
|
-
self.fn = fn
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
def add_path_resolvers(
|
|
163
|
-
loader: Type[Loader],
|
|
164
|
-
path: List[Optional[str]],
|
|
165
|
-
cls: typing.Type,
|
|
166
|
-
dumper: Optional[Type[Dumper]] = None,
|
|
167
|
-
):
|
|
168
|
-
cls = typingutils.get_type(cls) or cls
|
|
169
|
-
|
|
170
|
-
if list_type := typingutils.get_list(cls):
|
|
171
|
-
add_path_resolvers(loader, path + [None], list_type, dumper=dumper)
|
|
172
|
-
|
|
173
|
-
elif dict_type := typingutils.get_dict(cls):
|
|
174
|
-
key_type, value_type = dict_type
|
|
175
|
-
assert issubclass(key_type, str), f"Key of dict must be a string ({key_type})"
|
|
176
|
-
add_path_resolvers(loader, path + [None], value_type, dumper=dumper)
|
|
177
|
-
|
|
178
|
-
else:
|
|
179
|
-
if register_yaml(cls, loader, yaml_dumper=dumper):
|
|
180
|
-
logger.debug(f"Adding {cls.yaml_tag} -> {path}")
|
|
181
|
-
|
|
182
|
-
if issubclass(cls, YAMLDataClass):
|
|
183
|
-
# Add others
|
|
184
|
-
loader.add_path_resolver(cls.yaml_tag, path, dict)
|
|
185
|
-
for field in cls.__dataclass_fields__.values():
|
|
186
|
-
# logger.debug("Processing %s", field)
|
|
187
|
-
field_type = typingutils.get_type(field.type) or field.type
|
|
188
|
-
add_path_resolvers(
|
|
189
|
-
loader, path + [field.name], field_type, dumper=dumper
|
|
190
|
-
)
|
|
191
|
-
|
|
192
|
-
elif issubclass(cls, YAMLDict):
|
|
193
|
-
loader.add_path_resolver(cls.yaml_tag, path + [None], dict)
|
|
194
|
-
add_path_resolvers(
|
|
195
|
-
loader, path + [None], cls.get_ctype(), dumper=dumper
|
|
196
|
-
)
|
|
197
|
-
|
|
198
|
-
elif issubclass(cls, YAMLList):
|
|
199
|
-
loader.add_path_resolver(cls.yaml_tag, path, list)
|
|
200
|
-
add_path_resolvers(
|
|
201
|
-
loader, path + [None], cls.get_ctype(), dumper=dumper
|
|
202
|
-
)
|
|
File without changes
|
|
File without changes
|