experimaestro 1.6.1__py3-none-any.whl → 1.15.2__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.
- experimaestro/__init__.py +14 -3
- experimaestro/annotations.py +13 -3
- experimaestro/cli/filter.py +19 -5
- experimaestro/cli/jobs.py +12 -5
- experimaestro/commandline.py +3 -7
- experimaestro/connectors/__init__.py +27 -12
- experimaestro/connectors/local.py +19 -10
- experimaestro/connectors/ssh.py +1 -1
- experimaestro/core/arguments.py +35 -3
- experimaestro/core/callbacks.py +52 -0
- experimaestro/core/context.py +8 -9
- experimaestro/core/identifier.py +301 -0
- experimaestro/core/objects/__init__.py +44 -0
- experimaestro/core/{objects.py → objects/config.py} +364 -716
- experimaestro/core/objects/config_utils.py +58 -0
- experimaestro/core/objects/config_walk.py +151 -0
- experimaestro/core/objects.pyi +15 -45
- experimaestro/core/serialization.py +63 -9
- experimaestro/core/serializers.py +1 -8
- experimaestro/core/types.py +61 -6
- experimaestro/experiments/cli.py +79 -29
- experimaestro/experiments/configuration.py +3 -0
- experimaestro/generators.py +6 -1
- experimaestro/ipc.py +4 -1
- experimaestro/launcherfinder/parser.py +8 -3
- experimaestro/launcherfinder/registry.py +29 -10
- experimaestro/launcherfinder/specs.py +49 -10
- experimaestro/launchers/slurm/base.py +51 -13
- experimaestro/mkdocs/__init__.py +1 -1
- experimaestro/notifications.py +2 -1
- experimaestro/run.py +3 -1
- experimaestro/scheduler/base.py +114 -6
- experimaestro/scheduler/dynamic_outputs.py +184 -0
- experimaestro/scheduler/state.py +75 -0
- experimaestro/scheduler/workspace.py +2 -1
- experimaestro/scriptbuilder.py +13 -2
- experimaestro/server/data/0c35d18bf06992036b69.woff2 +0 -0
- experimaestro/server/data/1815e00441357e01619e.ttf +0 -0
- experimaestro/server/data/219aa9140e099e6c72ed.woff2 +0 -0
- experimaestro/server/data/2463b90d9a316e4e5294.woff2 +0 -0
- experimaestro/server/data/2582b0e4bcf85eceead0.ttf +0 -0
- experimaestro/server/data/3a4004a46a653d4b2166.woff +0 -0
- experimaestro/server/data/3baa5b8f3469222b822d.woff +0 -0
- experimaestro/server/data/4d73cb90e394b34b7670.woff +0 -0
- experimaestro/server/data/4ef4218c522f1eb6b5b1.woff2 +0 -0
- experimaestro/server/data/5d681e2edae8c60630db.woff +0 -0
- experimaestro/server/data/6f420cf17cc0d7676fad.woff2 +0 -0
- experimaestro/server/data/89999bdf5d835c012025.woff2 +0 -0
- experimaestro/server/data/914997e1bdfc990d0897.ttf +0 -0
- experimaestro/server/data/c210719e60948b211a12.woff2 +0 -0
- experimaestro/server/data/c380809fd3677d7d6903.woff2 +0 -0
- experimaestro/server/data/f882956fd323fd322f31.woff +0 -0
- experimaestro/server/data/favicon.ico +0 -0
- experimaestro/server/data/index.css +22963 -0
- experimaestro/server/data/index.css.map +1 -0
- experimaestro/server/data/index.html +27 -0
- experimaestro/server/data/index.js +101770 -0
- experimaestro/server/data/index.js.map +1 -0
- experimaestro/server/data/login.html +22 -0
- experimaestro/server/data/manifest.json +15 -0
- experimaestro/settings.py +2 -2
- experimaestro/sphinx/__init__.py +7 -17
- experimaestro/taskglobals.py +7 -2
- experimaestro/tests/core/__init__.py +0 -0
- experimaestro/tests/core/test_generics.py +206 -0
- experimaestro/tests/definitions_types.py +5 -3
- experimaestro/tests/launchers/bin/sbatch +34 -7
- experimaestro/tests/launchers/bin/srun +5 -0
- experimaestro/tests/launchers/common.py +16 -4
- experimaestro/tests/restart.py +9 -4
- experimaestro/tests/tasks/all.py +23 -10
- experimaestro/tests/tasks/foreign.py +2 -4
- experimaestro/tests/test_dependencies.py +0 -6
- experimaestro/tests/test_experiment.py +73 -0
- experimaestro/tests/test_findlauncher.py +11 -4
- experimaestro/tests/test_forward.py +5 -5
- experimaestro/tests/test_generators.py +93 -0
- experimaestro/tests/test_identifier.py +114 -99
- experimaestro/tests/test_instance.py +6 -21
- experimaestro/tests/test_objects.py +20 -4
- experimaestro/tests/test_param.py +60 -22
- experimaestro/tests/test_serializers.py +24 -64
- experimaestro/tests/test_tags.py +5 -11
- experimaestro/tests/test_tasks.py +10 -23
- experimaestro/tests/test_tokens.py +3 -2
- experimaestro/tests/test_types.py +20 -17
- experimaestro/tests/test_validation.py +48 -91
- experimaestro/tokens.py +16 -5
- experimaestro/typingutils.py +8 -8
- experimaestro/utils/asyncio.py +6 -2
- experimaestro/utils/multiprocessing.py +44 -0
- experimaestro/utils/resources.py +7 -3
- {experimaestro-1.6.1.dist-info → experimaestro-1.15.2.dist-info}/METADATA +27 -34
- experimaestro-1.15.2.dist-info/RECORD +159 -0
- {experimaestro-1.6.1.dist-info → experimaestro-1.15.2.dist-info}/WHEEL +1 -1
- experimaestro-1.6.1.dist-info/RECORD +0 -122
- {experimaestro-1.6.1.dist-info → experimaestro-1.15.2.dist-info}/entry_points.txt +0 -0
- {experimaestro-1.6.1.dist-info → experimaestro-1.15.2.dist-info/licenses}/LICENSE +0 -0
|
@@ -2,18 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import pytest
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from experimaestro import
|
|
6
|
-
config,
|
|
7
|
-
Task,
|
|
8
|
-
Identifier,
|
|
9
|
-
argument,
|
|
10
|
-
pathoption,
|
|
11
|
-
ConstantParam,
|
|
12
|
-
Param,
|
|
13
|
-
Config,
|
|
14
|
-
)
|
|
5
|
+
from experimaestro import Task, field, Identifier, Constant, Param, Config, Meta
|
|
15
6
|
from enum import Enum
|
|
16
|
-
|
|
7
|
+
from experimaestro.generators import PathGenerator
|
|
17
8
|
from experimaestro.scheduler import Job, JobContext
|
|
18
9
|
from experimaestro.scheduler.workspace import RunMode
|
|
19
10
|
from .utils import TemporaryExperiment
|
|
@@ -31,57 +22,50 @@ def expect_notvalidate(value):
|
|
|
31
22
|
value.__xpm__.validate()
|
|
32
23
|
|
|
33
24
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class A:
|
|
37
|
-
pass
|
|
25
|
+
class A(Config):
|
|
26
|
+
value: Param[int]
|
|
38
27
|
|
|
39
28
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
class B:
|
|
43
|
-
pass
|
|
29
|
+
class B(Config):
|
|
30
|
+
a: Param[A]
|
|
44
31
|
|
|
45
32
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
class C:
|
|
33
|
+
class C(Config):
|
|
34
|
+
path: Meta[Path] = field(default_factory=PathGenerator("outdir"))
|
|
49
35
|
pass
|
|
50
36
|
|
|
51
37
|
|
|
52
|
-
def
|
|
38
|
+
def test_validation_simple():
|
|
53
39
|
expect_validate(A(value=1))
|
|
54
40
|
|
|
55
41
|
|
|
56
|
-
def
|
|
42
|
+
def test_validation_missing():
|
|
57
43
|
expect_notvalidate(A())
|
|
58
44
|
|
|
59
45
|
|
|
60
|
-
def
|
|
46
|
+
def test_validation_simple_nested():
|
|
61
47
|
b = B()
|
|
62
48
|
b.a = A(value=1)
|
|
63
49
|
expect_validate(b)
|
|
64
50
|
|
|
65
51
|
|
|
66
|
-
def
|
|
52
|
+
def test_validation_missing_nested():
|
|
67
53
|
b = B()
|
|
68
54
|
b.a = A()
|
|
69
55
|
expect_notvalidate(b)
|
|
70
56
|
|
|
71
57
|
|
|
72
|
-
def
|
|
73
|
-
|
|
74
|
-
|
|
58
|
+
def test_validation_type():
|
|
59
|
+
class A(Config):
|
|
60
|
+
__xpmid__ = valns.type.a
|
|
75
61
|
pass
|
|
76
62
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
pass
|
|
63
|
+
class B(Config):
|
|
64
|
+
__xpmid__ = valns.type.b
|
|
80
65
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
pass
|
|
66
|
+
class C(Config):
|
|
67
|
+
a: Param[A]
|
|
68
|
+
__xpmid__ = valns.type.c
|
|
85
69
|
|
|
86
70
|
with pytest.raises(ValueError):
|
|
87
71
|
C(a=B())
|
|
@@ -91,30 +75,26 @@ def test_type():
|
|
|
91
75
|
c.a = B()
|
|
92
76
|
|
|
93
77
|
|
|
94
|
-
def
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
pass
|
|
78
|
+
def test_validation_subtype():
|
|
79
|
+
class A(Config):
|
|
80
|
+
__xpmid__ = valns.subtype.a
|
|
98
81
|
|
|
99
|
-
@config(valns.subtype.a1)
|
|
100
82
|
class A1(A):
|
|
101
|
-
|
|
83
|
+
__xpmid__ = valns.subtype.a1
|
|
102
84
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
pass
|
|
85
|
+
class B(Config):
|
|
86
|
+
__xpmid__ = valns.subtype.b
|
|
87
|
+
a: Param[A]
|
|
107
88
|
|
|
108
89
|
expect_validate(B(a=A1()))
|
|
109
90
|
|
|
110
91
|
|
|
111
|
-
def
|
|
112
|
-
"""Test of
|
|
92
|
+
def test_validation_path_generator():
|
|
93
|
+
"""Test of path generator"""
|
|
113
94
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
pass
|
|
95
|
+
class A(Config):
|
|
96
|
+
__xpmid__ = valns.path.a
|
|
97
|
+
value: Meta[Path] = field(default_factory=PathGenerator("file.txt"))
|
|
118
98
|
|
|
119
99
|
a = A()
|
|
120
100
|
a.__xpm__.validate()
|
|
@@ -129,13 +109,12 @@ def test_path():
|
|
|
129
109
|
assert a.value.parents[3] == xp.workspace.path
|
|
130
110
|
|
|
131
111
|
|
|
132
|
-
def
|
|
133
|
-
"""Test of
|
|
112
|
+
def test_validation_constant():
|
|
113
|
+
"""Test of constant"""
|
|
134
114
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
pass
|
|
115
|
+
class A(Config):
|
|
116
|
+
__xpmid__ = valns.constant.a
|
|
117
|
+
value: Constant[int] = 1
|
|
139
118
|
|
|
140
119
|
a = A()
|
|
141
120
|
a.__xpm__.validate()
|
|
@@ -145,31 +124,26 @@ def test_constant():
|
|
|
145
124
|
assert a.value == 1
|
|
146
125
|
|
|
147
126
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
class Parent:
|
|
151
|
-
pass
|
|
127
|
+
class Parent(Config):
|
|
128
|
+
x: Param[int]
|
|
152
129
|
|
|
153
130
|
|
|
154
|
-
@config()
|
|
155
131
|
class Child(Parent):
|
|
156
132
|
pass
|
|
157
133
|
|
|
158
134
|
|
|
159
|
-
def
|
|
135
|
+
def test_validation_child():
|
|
160
136
|
expect_validate(Child(x=1))
|
|
161
137
|
|
|
162
138
|
|
|
163
139
|
# --- Path argument checks
|
|
164
140
|
|
|
165
141
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
class PathParent:
|
|
169
|
-
pass
|
|
142
|
+
class PathParent(Config):
|
|
143
|
+
x: Meta[Path] = field(default_factory=PathGenerator("x"))
|
|
170
144
|
|
|
171
145
|
|
|
172
|
-
def
|
|
146
|
+
def test_validation_path_option():
|
|
173
147
|
c = PathParent()
|
|
174
148
|
expect_validate(c)
|
|
175
149
|
|
|
@@ -177,28 +151,11 @@ def test_path_option():
|
|
|
177
151
|
# --- Default value
|
|
178
152
|
|
|
179
153
|
|
|
180
|
-
|
|
181
|
-
"value,apitype",
|
|
182
|
-
[(1.5, types.FloatType), (1, types.IntType), (False, types.BoolType)],
|
|
183
|
-
)
|
|
184
|
-
def test_default(value, apitype):
|
|
185
|
-
@argument("default", default=value)
|
|
186
|
-
@config(valns.default[str(type(value))])
|
|
187
|
-
class Default:
|
|
188
|
-
pass
|
|
189
|
-
|
|
190
|
-
value = Default()
|
|
191
|
-
expect_validate(value)
|
|
192
|
-
assert Default.__xpmtype__.arguments["default"].type.__class__ == apitype
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
def test_seal():
|
|
154
|
+
def test_validation_seal():
|
|
196
155
|
"""Test value sealing"""
|
|
197
156
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
class A:
|
|
201
|
-
pass
|
|
157
|
+
class A(Config):
|
|
158
|
+
a: Param[int]
|
|
202
159
|
|
|
203
160
|
a = A(a=2)
|
|
204
161
|
a.__xpm__.seal(EmptyContext())
|
|
@@ -207,7 +164,7 @@ def test_seal():
|
|
|
207
164
|
a.a = 1
|
|
208
165
|
|
|
209
166
|
|
|
210
|
-
def
|
|
167
|
+
def test_validation_validation_enum():
|
|
211
168
|
"""Path arguments should be ignored"""
|
|
212
169
|
|
|
213
170
|
class EnumParam(Enum):
|
|
@@ -241,7 +198,7 @@ class TaskConfigConsumer(Config):
|
|
|
241
198
|
x: Param[TaskParentConfig]
|
|
242
199
|
|
|
243
200
|
|
|
244
|
-
def
|
|
201
|
+
def test_validation_taskargument():
|
|
245
202
|
x = taskconfig()
|
|
246
203
|
with TemporaryExperiment("fake"):
|
|
247
204
|
x.submit(run_mode=RunMode.DRY_RUN)
|
experimaestro/tokens.py
CHANGED
|
@@ -59,6 +59,8 @@ class CounterTokenLock(Lock):
|
|
|
59
59
|
|
|
60
60
|
|
|
61
61
|
class CounterTokenDependency(Dependency):
|
|
62
|
+
"""A dependency onto a token"""
|
|
63
|
+
|
|
62
64
|
def __init__(self, token: "CounterToken", count: int):
|
|
63
65
|
super().__init__(token)
|
|
64
66
|
self._token = token
|
|
@@ -66,6 +68,7 @@ class CounterTokenDependency(Dependency):
|
|
|
66
68
|
|
|
67
69
|
@property
|
|
68
70
|
def name(self):
|
|
71
|
+
"""The (file) name for this dependency, when taken"""
|
|
69
72
|
return f"{self.target.identifier}.token"
|
|
70
73
|
|
|
71
74
|
def status(self) -> DependencyStatus:
|
|
@@ -165,7 +168,7 @@ class CounterToken(Token, FileSystemEventHandler):
|
|
|
165
168
|
- TIMESTAMP.token contains (1) the number of tokens (2) the job URI
|
|
166
169
|
"""
|
|
167
170
|
|
|
168
|
-
"""Maps
|
|
171
|
+
"""Maps token keys to CounterToken instances"""
|
|
169
172
|
TOKENS: Dict[str, "CounterToken"] = {}
|
|
170
173
|
|
|
171
174
|
@staticmethod
|
|
@@ -193,7 +196,7 @@ class CounterToken(Token, FileSystemEventHandler):
|
|
|
193
196
|
"""[summary]
|
|
194
197
|
|
|
195
198
|
Arguments:
|
|
196
|
-
path {Path} -- The file path of the token
|
|
199
|
+
path {Path} -- The file path of the token directory
|
|
197
200
|
count {int} -- Number of tokens (overrides previous definitions)
|
|
198
201
|
force -- If the token has already been created, force to write the maximum
|
|
199
202
|
number of tokens
|
|
@@ -298,6 +301,9 @@ class CounterToken(Token, FileSystemEventHandler):
|
|
|
298
301
|
tokenfile = TokenFile(path)
|
|
299
302
|
tokenfile.watch()
|
|
300
303
|
self.cache[path.name] = tokenfile
|
|
304
|
+
except FileNotFoundError:
|
|
305
|
+
# We did not find the token file... just ignore
|
|
306
|
+
pass
|
|
301
307
|
except Exception:
|
|
302
308
|
logger.exception("Uncaught exception in on_modified handler")
|
|
303
309
|
raise
|
|
@@ -336,13 +342,18 @@ class CounterToken(Token, FileSystemEventHandler):
|
|
|
336
342
|
for dependency in dependents:
|
|
337
343
|
dependency.check()
|
|
338
344
|
|
|
345
|
+
# A modified dependency not in cache
|
|
339
346
|
elif path.name.endswith(".token") and path.name not in self.cache:
|
|
340
347
|
with self.lock:
|
|
341
348
|
if path.name not in self.cache:
|
|
342
349
|
logger.debug("Token file not in cache %s", path.name)
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
350
|
+
try:
|
|
351
|
+
tokenfile = TokenFile(path)
|
|
352
|
+
tokenfile.watch()
|
|
353
|
+
self.cache[path.name] = tokenfile
|
|
354
|
+
except FileNotFoundError:
|
|
355
|
+
# Well, the file did not exist anymore...
|
|
356
|
+
pass
|
|
346
357
|
except Exception:
|
|
347
358
|
logger.exception("Uncaught exception in on_modified handler")
|
|
348
359
|
raise
|
experimaestro/typingutils.py
CHANGED
|
@@ -8,14 +8,7 @@ if sys.version_info.major == 3:
|
|
|
8
8
|
else:
|
|
9
9
|
from typing import _collect_parameters
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
from typing_extensions import (
|
|
13
|
-
_AnnotatedAlias as AnnotatedAlias,
|
|
14
|
-
get_args,
|
|
15
|
-
get_origin,
|
|
16
|
-
)
|
|
17
|
-
else:
|
|
18
|
-
from typing import _AnnotatedAlias as AnnotatedAlias, get_args, get_origin
|
|
11
|
+
from typing import _AnnotatedAlias as AnnotatedAlias, get_args, get_origin
|
|
19
12
|
|
|
20
13
|
GenericAlias = typing._GenericAlias
|
|
21
14
|
|
|
@@ -26,6 +19,13 @@ def isgenericalias(typehint):
|
|
|
26
19
|
return isinstance(typehint, GenericAlias)
|
|
27
20
|
|
|
28
21
|
|
|
22
|
+
def get_union(typehint):
|
|
23
|
+
"""Return the list of types of a union (or the type itself if it is not an union)"""
|
|
24
|
+
if isgenericalias(typehint) and typehint.__origin__ == typing.Union:
|
|
25
|
+
return typehint.__args__
|
|
26
|
+
return None
|
|
27
|
+
|
|
28
|
+
|
|
29
29
|
def get_optional(typehint):
|
|
30
30
|
if isgenericalias(typehint) and typehint.__origin__ == typing.Union:
|
|
31
31
|
if len(typehint.__args__) == 2:
|
experimaestro/utils/asyncio.py
CHANGED
|
@@ -10,8 +10,12 @@ def asyncThreadcheck(name, func, *args, **kwargs) -> asyncio.Future:
|
|
|
10
10
|
|
|
11
11
|
def dowait():
|
|
12
12
|
logging.debug("Running %s", func)
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
try:
|
|
14
|
+
result = func(*args, **kwargs)
|
|
15
|
+
logging.debug("Got result from %s", func)
|
|
16
|
+
except Exception:
|
|
17
|
+
logging.exception("Got an error in the thread")
|
|
18
|
+
raise
|
|
15
19
|
loop.call_soon_threadsafe(future.set_result, result)
|
|
16
20
|
|
|
17
21
|
# Start thread
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import multiprocessing as mp
|
|
3
|
+
import time
|
|
4
|
+
import os
|
|
5
|
+
import signal
|
|
6
|
+
import threading
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def delayed_shutdown(delay=60, *, exit_code=1, grace_period=5):
|
|
10
|
+
"""After *delay*'s try a graceful stop, then SIGKILL anything left.
|
|
11
|
+
|
|
12
|
+
:param delay: Delay in seconds before killing
|
|
13
|
+
:param grace_period: Delay in seconds before force-killing a child process
|
|
14
|
+
:param exit_code: The exit code to use
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def _killer():
|
|
18
|
+
time.sleep(delay)
|
|
19
|
+
|
|
20
|
+
logging.info("Stall dectected – killing all subprocesses")
|
|
21
|
+
|
|
22
|
+
# 1️⃣ Try graceful termination
|
|
23
|
+
for p in mp.active_children():
|
|
24
|
+
# sends SIGTERM / TerminateProcess
|
|
25
|
+
p.terminate()
|
|
26
|
+
|
|
27
|
+
alive = mp.active_children()
|
|
28
|
+
deadline = time.time() + grace_period
|
|
29
|
+
while alive and time.time() < deadline:
|
|
30
|
+
alive = [p for p in alive if p.is_alive()]
|
|
31
|
+
time.sleep(0.1)
|
|
32
|
+
|
|
33
|
+
# 2️⃣ Anything still alive? Nuke it.
|
|
34
|
+
for p in alive:
|
|
35
|
+
try:
|
|
36
|
+
os.kill(p.pid, signal.SIGKILL)
|
|
37
|
+
except OSError:
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
# 3️⃣ Finally kill the parent
|
|
41
|
+
os.kill(os.getpid(), signal.SIGKILL)
|
|
42
|
+
|
|
43
|
+
# Start the thread (non blocking)
|
|
44
|
+
threading.Thread(target=_killer, daemon=True).start()
|
experimaestro/utils/resources.py
CHANGED
|
@@ -24,15 +24,19 @@ class ResourcePathWrapper(PathLike):
|
|
|
24
24
|
parents = [s.name for s in reversed(self.path.parents)][1:]
|
|
25
25
|
return ".".join(parents)
|
|
26
26
|
|
|
27
|
-
@
|
|
27
|
+
@cached_property
|
|
28
28
|
def name(self):
|
|
29
29
|
return self.path.name
|
|
30
30
|
|
|
31
31
|
def is_file(self):
|
|
32
|
-
return
|
|
32
|
+
return any(
|
|
33
|
+
traversable.name == self.name and traversable.is_file()
|
|
34
|
+
for traversable in resources.files(self.package).iterdir()
|
|
35
|
+
)
|
|
33
36
|
|
|
34
37
|
def __fspath__(self):
|
|
35
|
-
|
|
38
|
+
"""Return the file system path representation of the object"""
|
|
39
|
+
return resources.as_file(resources.files(self.package) / self.name)
|
|
36
40
|
|
|
37
41
|
@contextmanager
|
|
38
42
|
def open(self, *args, **kwargs):
|
|
@@ -1,53 +1,46 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: experimaestro
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.15.2
|
|
4
4
|
Summary: "Experimaestro is a computer science experiment manager"
|
|
5
5
|
License: GPL-3
|
|
6
|
+
License-File: LICENSE
|
|
6
7
|
Keywords: experiment manager
|
|
7
8
|
Author: Benjamin Piwowarski
|
|
8
9
|
Author-email: benjamin@piwowarski.fr
|
|
9
|
-
Requires-Python: >=3.
|
|
10
|
+
Requires-Python: >=3.10
|
|
10
11
|
Classifier: Development Status :: 4 - Beta
|
|
11
12
|
Classifier: Intended Audience :: Science/Research
|
|
12
13
|
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
13
|
-
Classifier: License :: Other/Proprietary License
|
|
14
14
|
Classifier: Operating System :: OS Independent
|
|
15
15
|
Classifier: Programming Language :: Python
|
|
16
16
|
Classifier: Programming Language :: Python :: 3
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
23
17
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
18
|
Requires-Dist: arpeggio (>=2,<3)
|
|
25
|
-
Requires-Dist: attrs (>=23.1.0,<24
|
|
19
|
+
Requires-Dist: attrs (>=23.1.0,<24)
|
|
26
20
|
Requires-Dist: click (>=8)
|
|
27
21
|
Requires-Dist: decorator (>=5,<6)
|
|
28
|
-
Requires-Dist: docstring-parser (>=0.15,<
|
|
29
|
-
Requires-Dist: fasteners (>=0.19,<
|
|
30
|
-
Requires-Dist: flask (>=2.3
|
|
31
|
-
Requires-Dist: flask-socketio (>=5.3
|
|
32
|
-
Requires-Dist: gevent (>=
|
|
33
|
-
Requires-Dist: gevent-websocket (>=0.10
|
|
22
|
+
Requires-Dist: docstring-parser (>=0.15,<1)
|
|
23
|
+
Requires-Dist: fasteners (>=0.19,<1)
|
|
24
|
+
Requires-Dist: flask (>=2.3)
|
|
25
|
+
Requires-Dist: flask-socketio (>=5.3)
|
|
26
|
+
Requires-Dist: gevent (>=25)
|
|
27
|
+
Requires-Dist: gevent-websocket (>=0.10)
|
|
34
28
|
Requires-Dist: huggingface-hub (>0.17)
|
|
35
|
-
Requires-Dist: humanfriendly (>=10
|
|
36
|
-
Requires-Dist: marshmallow (>=3.20,<4
|
|
37
|
-
Requires-Dist:
|
|
38
|
-
Requires-Dist:
|
|
39
|
-
Requires-Dist:
|
|
40
|
-
Requires-Dist:
|
|
41
|
-
Requires-Dist:
|
|
42
|
-
Requires-Dist:
|
|
29
|
+
Requires-Dist: humanfriendly (>=10)
|
|
30
|
+
Requires-Dist: marshmallow (>=3.20,<4)
|
|
31
|
+
Requires-Dist: mkdocs (>=1.5,<2)
|
|
32
|
+
Requires-Dist: omegaconf (>=2.3,<3)
|
|
33
|
+
Requires-Dist: psutil (>=7,<8)
|
|
34
|
+
Requires-Dist: pyparsing (>=3.1,<4)
|
|
35
|
+
Requires-Dist: pytools (>=2023.1.1,<2024)
|
|
36
|
+
Requires-Dist: pyyaml (>=6.0.1,<7)
|
|
37
|
+
Requires-Dist: requests (>=2.31,<3)
|
|
43
38
|
Requires-Dist: rpyc (>=5,<7)
|
|
44
|
-
Requires-Dist: sortedcontainers (>=2.4,<3
|
|
45
|
-
Requires-Dist: termcolor (>=2.3)
|
|
46
|
-
Requires-Dist: tqdm (>=4.66.1,<5
|
|
39
|
+
Requires-Dist: sortedcontainers (>=2.4,<3)
|
|
40
|
+
Requires-Dist: termcolor (>=2.3,<3)
|
|
41
|
+
Requires-Dist: tqdm (>=4.66.1,<5)
|
|
47
42
|
Requires-Dist: typing-extensions (>=4.2) ; python_version < "3.12"
|
|
48
|
-
Requires-Dist: watchdog (>=2
|
|
49
|
-
Project-URL: Documentation, https://experimaestro-python.readthedocs.io/
|
|
50
|
-
Project-URL: Repository, https://github.com/experimaestro/experimaestro-python
|
|
43
|
+
Requires-Dist: watchdog (>=2)
|
|
51
44
|
Description-Content-Type: text/markdown
|
|
52
45
|
|
|
53
46
|
[](https://badge.fury.io/py/experimaestro)
|
|
@@ -145,11 +138,11 @@ def cli(port, workdir, sleeptime):
|
|
|
145
138
|
# Sets the working directory and the name of the xp
|
|
146
139
|
with experiment(workdir, "helloworld", port=port) as xp:
|
|
147
140
|
# Submit the tasks
|
|
148
|
-
hello = Say(word="hello", sleeptime=sleeptime).submit()
|
|
149
|
-
world = Say(word="world", sleeptime=sleeptime).submit()
|
|
141
|
+
hello = Say.C(word="hello", sleeptime=sleeptime).submit()
|
|
142
|
+
world = Say.C(word="world", sleeptime=sleeptime).submit()
|
|
150
143
|
|
|
151
144
|
# Concat will depend on the two first tasks
|
|
152
|
-
Concat(strings=[hello, world], sleeptime=sleeptime).tag("y", 1).submit()
|
|
145
|
+
Concat.C(strings=[hello, world], sleeptime=sleeptime).tag("y", 1).submit()
|
|
153
146
|
|
|
154
147
|
|
|
155
148
|
if __name__ == "__main__":
|