experimaestro 1.6.2__py3-none-any.whl → 1.7.0rc0__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/__init__.py +3 -1
- experimaestro/annotations.py +13 -3
- experimaestro/cli/filter.py +3 -3
- experimaestro/cli/jobs.py +1 -1
- experimaestro/connectors/__init__.py +17 -8
- experimaestro/connectors/local.py +8 -3
- experimaestro/core/arguments.py +26 -3
- experimaestro/core/objects.py +90 -6
- experimaestro/core/objects.pyi +7 -1
- experimaestro/core/types.py +33 -2
- experimaestro/generators.py +6 -1
- experimaestro/ipc.py +4 -1
- experimaestro/launcherfinder/registry.py +7 -4
- experimaestro/notifications.py +1 -1
- experimaestro/run.py +1 -1
- experimaestro/scheduler/base.py +94 -10
- experimaestro/scheduler/dynamic_outputs.py +184 -0
- experimaestro/server/data/016b4a6cdced82ab3aa1.ttf +0 -0
- 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/50701fbb8177c2dde530.ttf +0 -0
- experimaestro/server/data/5d681e2edae8c60630db.woff +0 -0
- experimaestro/server/data/6f420cf17cc0d7676fad.woff2 +0 -0
- experimaestro/server/data/878f31251d960bd6266f.woff2 +0 -0
- experimaestro/server/data/89999bdf5d835c012025.woff2 +0 -0
- experimaestro/server/data/914997e1bdfc990d0897.ttf +0 -0
- experimaestro/server/data/b041b1fa4fe241b23445.woff2 +0 -0
- experimaestro/server/data/b6879d41b0852f01ed5b.woff2 +0 -0
- experimaestro/server/data/c210719e60948b211a12.woff2 +0 -0
- experimaestro/server/data/c380809fd3677d7d6903.woff2 +0 -0
- experimaestro/server/data/d75e3fd1eb12e9bd6655.ttf +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/taskglobals.py +7 -2
- experimaestro/tests/definitions_types.py +5 -3
- experimaestro/tests/launchers/bin/sbatch +18 -5
- experimaestro/tests/launchers/common.py +11 -3
- experimaestro/tests/restart.py +6 -3
- experimaestro/tests/tasks/all.py +16 -10
- experimaestro/tests/tasks/foreign.py +2 -4
- experimaestro/tests/test_forward.py +5 -5
- experimaestro/tests/test_identifier.py +61 -66
- experimaestro/tests/test_instance.py +3 -6
- experimaestro/tests/test_param.py +40 -22
- experimaestro/tests/test_tags.py +5 -11
- experimaestro/tests/test_tokens.py +3 -2
- experimaestro/tests/test_types.py +17 -14
- experimaestro/tests/test_validation.py +48 -91
- experimaestro/tokens.py +16 -5
- experimaestro/typingutils.py +7 -0
- experimaestro/utils/asyncio.py +6 -2
- experimaestro/utils/resources.py +7 -3
- {experimaestro-1.6.2.dist-info → experimaestro-1.7.0rc0.dist-info}/METADATA +3 -4
- {experimaestro-1.6.2.dist-info → experimaestro-1.7.0rc0.dist-info}/RECORD +71 -40
- {experimaestro-1.6.2.dist-info → experimaestro-1.7.0rc0.dist-info}/WHEEL +1 -1
- {experimaestro-1.6.2.dist-info → experimaestro-1.7.0rc0.dist-info}/LICENSE +0 -0
- {experimaestro-1.6.2.dist-info → experimaestro-1.7.0rc0.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta
|
|
6
|
+
name="viewport"
|
|
7
|
+
content="width=device-width, initial-scale=1, shrink-to-fit=no"
|
|
8
|
+
/>
|
|
9
|
+
<meta name="theme-color" content="#000000" />
|
|
10
|
+
<title>Experimaestro</title>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<h1>Experimaestro</h1>
|
|
14
|
+
<form action="/auth" method="GET">
|
|
15
|
+
<div>
|
|
16
|
+
Token
|
|
17
|
+
<input type="text" name="xpm-token" />
|
|
18
|
+
<input type="submit" value="submit" />
|
|
19
|
+
</div>
|
|
20
|
+
</form>
|
|
21
|
+
</body>
|
|
22
|
+
</html>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"short_name": "Experimaestro",
|
|
3
|
+
"name": "Experimaestro Client",
|
|
4
|
+
"icons": [
|
|
5
|
+
{
|
|
6
|
+
"src": "favicon.ico",
|
|
7
|
+
"sizes": "64x64 32x32 24x24 16x16",
|
|
8
|
+
"type": "image/x-icon"
|
|
9
|
+
}
|
|
10
|
+
],
|
|
11
|
+
"start_url": "./index.html",
|
|
12
|
+
"display": "standalone",
|
|
13
|
+
"theme_color": "#000000",
|
|
14
|
+
"background_color": "#ffffff"
|
|
15
|
+
}
|
experimaestro/taskglobals.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
+
from functools import cached_property
|
|
1
2
|
from pathlib import Path
|
|
2
3
|
from typing import Optional
|
|
3
|
-
import os
|
|
4
|
-
import logging
|
|
5
4
|
|
|
6
5
|
|
|
7
6
|
class Env:
|
|
@@ -18,6 +17,12 @@ class Env:
|
|
|
18
17
|
# - no progress report
|
|
19
18
|
slave: bool = False
|
|
20
19
|
|
|
20
|
+
@cached_property
|
|
21
|
+
def xpm_path(self):
|
|
22
|
+
path = self.taskpath / ".experimaestro"
|
|
23
|
+
path.mkdir(exist_ok=True)
|
|
24
|
+
return path
|
|
25
|
+
|
|
21
26
|
@staticmethod
|
|
22
27
|
def instance():
|
|
23
28
|
if Env._instance is None:
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
from experimaestro import
|
|
1
|
+
from experimaestro import Param, Task
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
@argument("value", type=int)
|
|
5
4
|
class IntegerTask(Task):
|
|
5
|
+
value: Param[int]
|
|
6
|
+
|
|
6
7
|
def execute(self):
|
|
7
8
|
if not isinstance(self.value, int):
|
|
8
9
|
raise AssertionError("Not an integer")
|
|
9
10
|
|
|
10
11
|
|
|
11
|
-
@argument("value", type=float)
|
|
12
12
|
class FloatTask(Task):
|
|
13
|
+
value: Param[float]
|
|
14
|
+
|
|
13
15
|
def execute(self):
|
|
14
16
|
if not isinstance(self.value, float):
|
|
15
17
|
raise AssertionError("Not a float but %s" % type(self.value))
|
|
@@ -10,7 +10,17 @@ if ! test -d "$XPM_SLURM_DIR"; then
|
|
|
10
10
|
fi
|
|
11
11
|
|
|
12
12
|
mkdir -p "$XPM_SLURM_DIR/jobs"
|
|
13
|
-
echo "Slurm directory: $XPM_SLURM_DIR" >&2
|
|
13
|
+
echo "Slurm directory: $XPM_SLURM_DIR" >&2
|
|
14
|
+
|
|
15
|
+
RED='\033[0;31m'
|
|
16
|
+
NC='\033[0m' # No Color
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
if ! which flock > /dev/null; then
|
|
20
|
+
echo -e "[${RED}ERROR${NC}] flock is not installed on this system" 1>&2
|
|
21
|
+
exit 1
|
|
22
|
+
fi
|
|
23
|
+
|
|
14
24
|
|
|
15
25
|
lockpath() {
|
|
16
26
|
fid="$1"
|
|
@@ -18,7 +28,7 @@ lockpath() {
|
|
|
18
28
|
|
|
19
29
|
echo "Locking $path..." 1>&2
|
|
20
30
|
eval exec "$fid<>" $path
|
|
21
|
-
if ! flock --timeout 2 $fid; then
|
|
31
|
+
if ! flock --timeout 2 $fid; then
|
|
22
32
|
echo Could not lock "$path" - stopping 1>&2
|
|
23
33
|
exit 017
|
|
24
34
|
fi
|
|
@@ -37,12 +47,15 @@ while true; do
|
|
|
37
47
|
-o) shift; stdout="$1"; shift;;
|
|
38
48
|
-e) shift; stderr="$1"; shift;;
|
|
39
49
|
--*) args+=("$1"); shift;;
|
|
40
|
-
*) break 2;;
|
|
50
|
+
*) break 2;;
|
|
41
51
|
esac
|
|
42
52
|
done
|
|
43
53
|
|
|
44
54
|
echo "Starting $@ ${args[@]} > $stdout" >&2
|
|
45
|
-
(
|
|
55
|
+
(
|
|
56
|
+
eval "$@" "${args[@]}"
|
|
57
|
+
echo $? > "$XPM_SLURM_DIR/jobs/$$.status"
|
|
58
|
+
) > $stdout 2> $stderr &
|
|
46
59
|
JOBID="$$"
|
|
47
60
|
date > "$XPM_SLURM_DIR/jobs/$JOBID.start"
|
|
48
61
|
disown
|
|
@@ -51,4 +64,4 @@ if test "$parsable" == 0; then
|
|
|
51
64
|
echo "Submitted batch job ${JOBID}"
|
|
52
65
|
else
|
|
53
66
|
echo "${JOBID};cluster"
|
|
54
|
-
fi
|
|
67
|
+
fi
|
|
@@ -68,24 +68,32 @@ class WaitUntilTouched(Task):
|
|
|
68
68
|
|
|
69
69
|
|
|
70
70
|
def takeback(launcher, datapath, txp1, txp2):
|
|
71
|
+
"""Launch two times the same task (with two experiments)
|
|
72
|
+
|
|
73
|
+
:param launcher: The launcher
|
|
74
|
+
:param datapath: The path containing the two files that control the task, namely (1) touching which is created by the task when starting, (2) waiting which is controlled here
|
|
75
|
+
:param txp1: The first experiment
|
|
76
|
+
:param txp2: The second experiment
|
|
77
|
+
"""
|
|
71
78
|
datapath.mkdir()
|
|
72
79
|
touching = datapath / "touching"
|
|
73
80
|
waiting = datapath / "waiting"
|
|
74
81
|
|
|
75
|
-
with txp1
|
|
82
|
+
with txp1:
|
|
76
83
|
WaitUntilTouched(touching=touching, waiting=waiting).submit(launcher=launcher)
|
|
77
84
|
|
|
78
85
|
logger.debug("Waiting for task to create 'touching' file")
|
|
79
86
|
while not touching.is_file():
|
|
80
87
|
time.sleep(0.01)
|
|
81
88
|
|
|
82
|
-
with txp2
|
|
89
|
+
with txp2:
|
|
83
90
|
result = WaitUntilTouched(touching=touching, waiting=waiting).submit(
|
|
84
91
|
launcher=launcher
|
|
85
92
|
)
|
|
86
93
|
|
|
87
|
-
logger.debug("Waiting for job to be
|
|
94
|
+
logger.debug("Waiting for job to be running (scheduler)")
|
|
88
95
|
while result.__xpm__.job.state != JobState.RUNNING:
|
|
89
96
|
time.sleep(0.1)
|
|
90
97
|
|
|
98
|
+
logger.debug("OK, no we can notify the task")
|
|
91
99
|
waiting.touch()
|
experimaestro/tests/restart.py
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import time
|
|
2
|
+
from pathlib import Path
|
|
2
3
|
import sys
|
|
3
4
|
from typing import Callable
|
|
4
|
-
from experimaestro import Task,
|
|
5
|
+
from experimaestro import Task, Meta, field, PathGenerator
|
|
5
6
|
import psutil
|
|
6
7
|
import logging
|
|
7
8
|
import subprocess
|
|
8
9
|
import json
|
|
9
10
|
import signal
|
|
11
|
+
|
|
10
12
|
from experimaestro.scheduler.workspace import RunMode
|
|
11
13
|
from experimaestro.tests.utils import TemporaryExperiment, is_posix
|
|
12
14
|
from experimaestro.scheduler import JobState
|
|
@@ -26,9 +28,10 @@ if is_posix():
|
|
|
26
28
|
TERMINATES_FUNC.append(sigint)
|
|
27
29
|
|
|
28
30
|
|
|
29
|
-
@pathoption("touch", "touch")
|
|
30
|
-
@pathoption("wait", "wait")
|
|
31
31
|
class Restart(Task):
|
|
32
|
+
touch: Meta[Path] = field(default_factory=PathGenerator("touch"))
|
|
33
|
+
wait: Meta[Path] = field(default_factory=PathGenerator("wait"))
|
|
34
|
+
|
|
32
35
|
def execute(self):
|
|
33
36
|
# Write the file "touch" to notify that we started
|
|
34
37
|
with open(self.touch, "w") as out:
|
experimaestro/tests/tasks/all.py
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
from pathlib import Path
|
|
1
2
|
import time
|
|
2
3
|
from typing import List
|
|
3
4
|
from experimaestro import (
|
|
4
|
-
|
|
5
|
+
Meta,
|
|
5
6
|
Param,
|
|
7
|
+
field,
|
|
6
8
|
Task,
|
|
9
|
+
PathGenerator,
|
|
7
10
|
Config,
|
|
8
|
-
pathoption,
|
|
9
11
|
STDOUT,
|
|
10
12
|
cache,
|
|
11
13
|
)
|
|
@@ -18,8 +20,8 @@ class SimpleTask(Task):
|
|
|
18
20
|
print(self.x) # noqa: T201
|
|
19
21
|
|
|
20
22
|
|
|
21
|
-
@pathoption("out", STDOUT)
|
|
22
23
|
class Say(Task):
|
|
24
|
+
out: Meta[Path] = field(default_factory=PathGenerator(STDOUT))
|
|
23
25
|
word: Param[str]
|
|
24
26
|
|
|
25
27
|
def execute(self):
|
|
@@ -38,19 +40,20 @@ class Concat(Task):
|
|
|
38
40
|
print(" ".join(says)) # noqa: T201
|
|
39
41
|
|
|
40
42
|
|
|
41
|
-
@param("x", type=int)
|
|
42
43
|
class ForeignClassB1(Config):
|
|
43
|
-
|
|
44
|
+
x: Param[int]
|
|
44
45
|
|
|
45
46
|
|
|
46
|
-
@param("b", type=ForeignClassB1)
|
|
47
47
|
class ForeignTaskA(Task):
|
|
48
|
+
b: Param[ForeignClassB1]
|
|
49
|
+
|
|
48
50
|
def execute(self):
|
|
49
51
|
print(self.b.x) # noqa: T201
|
|
50
52
|
|
|
51
53
|
|
|
52
|
-
@pathoption("wait", "wait")
|
|
53
54
|
class Fail(Task):
|
|
55
|
+
wait: Meta[Path] = field(default_factory=PathGenerator("wait"))
|
|
56
|
+
|
|
54
57
|
def execute(self):
|
|
55
58
|
while not self.wait.is_file():
|
|
56
59
|
time.sleep(0.01)
|
|
@@ -64,14 +67,16 @@ class Fail(Task):
|
|
|
64
67
|
out.write("hello")
|
|
65
68
|
|
|
66
69
|
|
|
67
|
-
@param("fail", Fail)
|
|
68
70
|
class FailConsumer(Task):
|
|
71
|
+
fail: Param[Fail]
|
|
72
|
+
|
|
69
73
|
def execute(self):
|
|
70
74
|
return True
|
|
71
75
|
|
|
72
76
|
|
|
73
|
-
@param("a", int)
|
|
74
77
|
class Method(Task):
|
|
78
|
+
a: Param[int]
|
|
79
|
+
|
|
75
80
|
def execute(self):
|
|
76
81
|
assert self.a == 1
|
|
77
82
|
|
|
@@ -92,7 +97,8 @@ class CacheConfig(Config):
|
|
|
92
97
|
return path.read_text()
|
|
93
98
|
|
|
94
99
|
|
|
95
|
-
@param("data", type=CacheConfig)
|
|
96
100
|
class CacheConfigTask(Task):
|
|
101
|
+
data: Param[CacheConfig]
|
|
102
|
+
|
|
97
103
|
def execute(self):
|
|
98
104
|
assert self.data.get() == "hello"
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
from experimaestro import
|
|
1
|
+
from experimaestro import Param, Config
|
|
2
2
|
from experimaestro.click import forwardoption
|
|
3
3
|
import click
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
def test_main():
|
|
7
|
-
@argument("epochs", type=int, default=100, help="Number of learning epochs")
|
|
8
7
|
class MyModel(Config):
|
|
9
|
-
|
|
8
|
+
epochs: Param[int] = 100
|
|
9
|
+
"""Number of learning epochs"""
|
|
10
10
|
|
|
11
11
|
@forwardoption.epochs(MyModel)
|
|
12
12
|
@click.command()
|
|
@@ -18,9 +18,9 @@ def test_main():
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
def test_rename():
|
|
21
|
-
@argument("epochs", type=int, default=100, help="Number of learning epochs")
|
|
22
21
|
class MyModel(Config):
|
|
23
|
-
|
|
22
|
+
epochs: Param[int] = 100
|
|
23
|
+
"""Number of learning epochs"""
|
|
24
24
|
|
|
25
25
|
@forwardoption.epochs(MyModel, "my-epochs")
|
|
26
26
|
@click.command()
|
|
@@ -4,16 +4,14 @@ import json
|
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
from typing import Dict, List, Optional
|
|
6
6
|
from experimaestro import (
|
|
7
|
-
config,
|
|
8
7
|
Param,
|
|
9
|
-
param,
|
|
10
8
|
deprecate,
|
|
11
9
|
Config,
|
|
12
10
|
Constant,
|
|
13
11
|
Meta,
|
|
14
12
|
Option,
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
PathGenerator,
|
|
14
|
+
field,
|
|
17
15
|
Task,
|
|
18
16
|
LightweightTask,
|
|
19
17
|
)
|
|
@@ -48,8 +46,7 @@ class Float(Config):
|
|
|
48
46
|
value: Param[float]
|
|
49
47
|
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
class Values:
|
|
49
|
+
class Values(Config):
|
|
53
50
|
value1: Param[float]
|
|
54
51
|
value2: Param[float]
|
|
55
52
|
|
|
@@ -66,50 +63,50 @@ def assert_notequal(a, b, message=""):
|
|
|
66
63
|
assert getidentifier(a) != getidentifier(b), message
|
|
67
64
|
|
|
68
65
|
|
|
69
|
-
def
|
|
66
|
+
def test_param_int():
|
|
70
67
|
assert_equal(A(a=1), A(a=1))
|
|
71
68
|
|
|
72
69
|
|
|
73
|
-
def
|
|
70
|
+
def test_param_different_type():
|
|
74
71
|
assert_notequal(A(a=1), B(a=1))
|
|
75
72
|
|
|
76
73
|
|
|
77
|
-
def
|
|
74
|
+
def test_param_order():
|
|
78
75
|
assert_equal(Values(value1=1, value2=2), Values(value2=2, value1=1))
|
|
79
76
|
|
|
80
77
|
|
|
81
|
-
def
|
|
78
|
+
def test_param_default():
|
|
82
79
|
assert_equal(C(a=1, b=2), C(b=2))
|
|
83
80
|
|
|
84
81
|
|
|
85
|
-
def
|
|
82
|
+
def test_param_inner_eq():
|
|
86
83
|
assert_equal(D(a=A(a=1)), D(a=A(a=1)))
|
|
87
84
|
|
|
88
85
|
|
|
89
|
-
def
|
|
86
|
+
def test_param_float():
|
|
90
87
|
assert_equal(Float(value=1), Float(value=1))
|
|
91
88
|
|
|
92
89
|
|
|
93
|
-
def
|
|
90
|
+
def test_param_float2():
|
|
94
91
|
assert_equal(Float(value=1.0), Float(value=1))
|
|
95
92
|
|
|
96
93
|
|
|
97
94
|
# --- Argument name
|
|
98
95
|
|
|
99
96
|
|
|
100
|
-
def
|
|
97
|
+
def test_param_name():
|
|
101
98
|
"""The identifier fully determines the hash code"""
|
|
102
99
|
|
|
103
|
-
|
|
104
|
-
|
|
100
|
+
class Config0(Config):
|
|
101
|
+
__xpmid__ = "test.identifier.argumentname"
|
|
105
102
|
a: Param[int]
|
|
106
103
|
|
|
107
|
-
|
|
108
|
-
|
|
104
|
+
class Config1(Config):
|
|
105
|
+
__xpmid__ = "test.identifier.argumentname"
|
|
109
106
|
b: Param[int]
|
|
110
107
|
|
|
111
|
-
|
|
112
|
-
|
|
108
|
+
class Config3(Config):
|
|
109
|
+
__xpmid__ = "test.identifier.argumentname"
|
|
113
110
|
a: Param[int]
|
|
114
111
|
|
|
115
112
|
assert_notequal(Config0(a=2), Config1(b=2))
|
|
@@ -119,9 +116,9 @@ def test_name():
|
|
|
119
116
|
# --- Test option
|
|
120
117
|
|
|
121
118
|
|
|
122
|
-
def
|
|
123
|
-
|
|
124
|
-
|
|
119
|
+
def test_param_option():
|
|
120
|
+
class OptionConfig(Config):
|
|
121
|
+
__xpmid__ = "test.identifier.option"
|
|
125
122
|
a: Param[int]
|
|
126
123
|
b: Option[int] = 1
|
|
127
124
|
|
|
@@ -133,7 +130,7 @@ def test_option():
|
|
|
133
130
|
# --- Dictionnary
|
|
134
131
|
|
|
135
132
|
|
|
136
|
-
def
|
|
133
|
+
def test_param_identifier_dict():
|
|
137
134
|
"""Test identifiers of dictionary structures"""
|
|
138
135
|
|
|
139
136
|
class B(Config):
|
|
@@ -152,13 +149,12 @@ def test_identifier_dict():
|
|
|
152
149
|
# --- Ignore paths
|
|
153
150
|
|
|
154
151
|
|
|
155
|
-
|
|
156
|
-
class TypeWithPath:
|
|
152
|
+
class TypeWithPath(Config):
|
|
157
153
|
a: Param[int]
|
|
158
154
|
path: Param[Path]
|
|
159
155
|
|
|
160
156
|
|
|
161
|
-
def
|
|
157
|
+
def test_param_identifier_path():
|
|
162
158
|
"""Path should be ignored"""
|
|
163
159
|
assert_equal(TypeWithPath(a=1, path="/a/b"), TypeWithPath(a=1, path="/c/d"))
|
|
164
160
|
assert_notequal(TypeWithPath(a=2, path="/a/b"), TypeWithPath(a=1, path="/c/d"))
|
|
@@ -167,23 +163,23 @@ def test_path():
|
|
|
167
163
|
# --- Test with added arguments
|
|
168
164
|
|
|
169
165
|
|
|
170
|
-
def
|
|
166
|
+
def test_param_identifier_pathoption():
|
|
171
167
|
"""Path arguments should be ignored"""
|
|
172
168
|
|
|
173
|
-
|
|
174
|
-
|
|
169
|
+
class A_with_path(Config):
|
|
170
|
+
__xpmid__ = "pathoption_test"
|
|
175
171
|
a: Param[int]
|
|
176
|
-
path:
|
|
172
|
+
path: Meta[Path] = field(default_factory=PathGenerator("path"))
|
|
177
173
|
|
|
178
|
-
|
|
179
|
-
|
|
174
|
+
class A_without_path(Config):
|
|
175
|
+
__xpmid__ = "pathoption_test"
|
|
180
176
|
a: Param[int]
|
|
181
177
|
|
|
182
178
|
assert_equal(A_with_path(a=1), A_without_path(a=1))
|
|
183
179
|
|
|
184
180
|
|
|
185
|
-
def
|
|
186
|
-
"""
|
|
181
|
+
def test_param_identifier_enum():
|
|
182
|
+
"""test enum parameters"""
|
|
187
183
|
from enum import Enum
|
|
188
184
|
|
|
189
185
|
class EnumParam(Enum):
|
|
@@ -197,7 +193,7 @@ def test_identifier_enum():
|
|
|
197
193
|
assert_equal(EnumConfig(a=EnumParam.FIRST), EnumConfig(a=EnumParam.FIRST))
|
|
198
194
|
|
|
199
195
|
|
|
200
|
-
def
|
|
196
|
+
def test_param_identifier_addnone():
|
|
201
197
|
"""Test the case of new parameter (with None default)"""
|
|
202
198
|
|
|
203
199
|
class B(Config):
|
|
@@ -214,25 +210,24 @@ def test_identifier_addnone():
|
|
|
214
210
|
assert_notequal(A_with_b(b=B(x=1)), A())
|
|
215
211
|
|
|
216
212
|
|
|
217
|
-
def
|
|
213
|
+
def test_param_defaultnew():
|
|
218
214
|
"""Path arguments should be ignored"""
|
|
219
215
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
@config("defaultnew")
|
|
223
|
-
class A_with_b:
|
|
224
|
-
pass
|
|
216
|
+
class A_with_b(Config):
|
|
217
|
+
__xpmid__ = "defaultnew"
|
|
225
218
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
219
|
+
a: Param[int]
|
|
220
|
+
b: Param[int] = 1
|
|
221
|
+
|
|
222
|
+
class A(Config):
|
|
223
|
+
__xpmid__ = "defaultnew"
|
|
224
|
+
a: Param[int]
|
|
230
225
|
|
|
231
226
|
assert_equal(A_with_b(a=1, b=1), A(a=1))
|
|
232
227
|
assert_equal(A_with_b(a=1), A(a=1))
|
|
233
228
|
|
|
234
229
|
|
|
235
|
-
def
|
|
230
|
+
def test_param_taskconfigidentifier():
|
|
236
231
|
"""Test whether the embedded task arguments make the configuration different"""
|
|
237
232
|
|
|
238
233
|
class MyConfig(Config):
|
|
@@ -254,27 +249,27 @@ def test_taskconfigidentifier():
|
|
|
254
249
|
)
|
|
255
250
|
|
|
256
251
|
|
|
257
|
-
def
|
|
252
|
+
def test_param_constant():
|
|
258
253
|
"""Test if constants are taken into account for signature computation"""
|
|
259
254
|
|
|
260
|
-
|
|
261
|
-
|
|
255
|
+
class A1(Config):
|
|
256
|
+
__xpmid__ = "test.constant"
|
|
262
257
|
version: Constant[int] = 1
|
|
263
258
|
|
|
264
|
-
|
|
265
|
-
|
|
259
|
+
class A1bis(Config):
|
|
260
|
+
__xpmid__ = "test.constant"
|
|
266
261
|
version: Constant[int] = 1
|
|
267
262
|
|
|
268
263
|
assert_equal(A1(), A1bis())
|
|
269
264
|
|
|
270
|
-
|
|
271
|
-
|
|
265
|
+
class A2(Config):
|
|
266
|
+
__xpmid__ = "test.constant"
|
|
272
267
|
version: Constant[int] = 2
|
|
273
268
|
|
|
274
269
|
assert_notequal(A1(), A2())
|
|
275
270
|
|
|
276
271
|
|
|
277
|
-
def
|
|
272
|
+
def test_param_identifier_deprecated_class():
|
|
278
273
|
"""Test that when submitting the task, the computed identifier is the one of
|
|
279
274
|
the new class"""
|
|
280
275
|
|
|
@@ -296,7 +291,7 @@ def test_identifier_deprecated_class():
|
|
|
296
291
|
)
|
|
297
292
|
|
|
298
293
|
|
|
299
|
-
def
|
|
294
|
+
def test_param_identifier_deprecated_attribute():
|
|
300
295
|
class Values(Config):
|
|
301
296
|
values: Param[List[int]] = []
|
|
302
297
|
|
|
@@ -311,7 +306,7 @@ class MetaA(Config):
|
|
|
311
306
|
x: Param[int]
|
|
312
307
|
|
|
313
308
|
|
|
314
|
-
def
|
|
309
|
+
def test_param_identifier_meta():
|
|
315
310
|
"""Test forced meta-parameter"""
|
|
316
311
|
|
|
317
312
|
class B(Config):
|
|
@@ -350,7 +345,7 @@ def test_identifier_meta():
|
|
|
350
345
|
)
|
|
351
346
|
|
|
352
347
|
|
|
353
|
-
def
|
|
348
|
+
def test_param_identifier_meta_default_dict():
|
|
354
349
|
class DictConfig(Config):
|
|
355
350
|
params: Param[Dict[str, MetaA]] = {}
|
|
356
351
|
|
|
@@ -366,7 +361,7 @@ def test_identifier_meta_default_dict():
|
|
|
366
361
|
)
|
|
367
362
|
|
|
368
363
|
|
|
369
|
-
def
|
|
364
|
+
def test_param_identifier_meta_default_array():
|
|
370
365
|
class ArrayConfigWithDefault(Config):
|
|
371
366
|
array: Param[List[MetaA]] = []
|
|
372
367
|
|
|
@@ -382,7 +377,7 @@ def test_identifier_meta_default_array():
|
|
|
382
377
|
)
|
|
383
378
|
|
|
384
379
|
|
|
385
|
-
def
|
|
380
|
+
def test_param_identifier_pre_task():
|
|
386
381
|
class MyConfig(Config):
|
|
387
382
|
pass
|
|
388
383
|
|
|
@@ -412,7 +407,7 @@ def test_identifier_pre_task():
|
|
|
412
407
|
assert_equal(task_with_pre, task_with_pre_3, "Pre-tasks are order-less")
|
|
413
408
|
|
|
414
409
|
|
|
415
|
-
def
|
|
410
|
+
def test_param_identifier_init_task():
|
|
416
411
|
class MyConfig(Config):
|
|
417
412
|
pass
|
|
418
413
|
|
|
@@ -469,7 +464,7 @@ class IdentifierReloadConfig(Config):
|
|
|
469
464
|
id: Param[str]
|
|
470
465
|
|
|
471
466
|
|
|
472
|
-
def
|
|
467
|
+
def test_param_identifier_reload_config():
|
|
473
468
|
# Creates the configuration
|
|
474
469
|
check_reload(IdentifierReloadConfig(id="123"))
|
|
475
470
|
|
|
@@ -485,7 +480,7 @@ class IdentifierReloadDerived(Config):
|
|
|
485
480
|
task: Param[IdentifierReloadConfig]
|
|
486
481
|
|
|
487
482
|
|
|
488
|
-
def
|
|
483
|
+
def test_param_identifier_reload_taskoutput():
|
|
489
484
|
"""When using a task output, the identifier should not be different"""
|
|
490
485
|
|
|
491
486
|
# Creates the configuration
|
|
@@ -507,7 +502,7 @@ class IdentifierReloadTaskDerived(Config):
|
|
|
507
502
|
other: Param[IdentifierReloadTaskConfig]
|
|
508
503
|
|
|
509
504
|
|
|
510
|
-
def
|
|
505
|
+
def test_param_identifier_reload_task_direct():
|
|
511
506
|
"""When using a direct task output, the identifier should not be different"""
|
|
512
507
|
|
|
513
508
|
# Creates the configuration
|
|
@@ -518,7 +513,7 @@ def test_identifier_reload_task_direct():
|
|
|
518
513
|
check_reload(config)
|
|
519
514
|
|
|
520
515
|
|
|
521
|
-
def
|
|
516
|
+
def test_param_identifier_reload_meta():
|
|
522
517
|
"""Test identifier don't change when using meta"""
|
|
523
518
|
# Creates the configuration
|
|
524
519
|
task = IdentifierReloadTask(id="123").submit(run_mode=RunMode.DRY_RUN)
|
|
@@ -541,7 +536,7 @@ class LoopC(Config):
|
|
|
541
536
|
param_b: Param["LoopB"]
|
|
542
537
|
|
|
543
538
|
|
|
544
|
-
def
|
|
539
|
+
def test_param_identifier_loop():
|
|
545
540
|
c = LoopC()
|
|
546
541
|
b = LoopB(param_c=c)
|
|
547
542
|
a = LoopA(param_b=b)
|
|
@@ -1,21 +1,18 @@
|
|
|
1
1
|
from typing import Optional
|
|
2
|
-
from experimaestro import
|
|
2
|
+
from experimaestro import Param, Config
|
|
3
3
|
from experimaestro.core.objects import TypeConfig
|
|
4
4
|
from experimaestro.core.serializers import SerializationLWTask
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
class A:
|
|
7
|
+
class A(Config):
|
|
9
8
|
x: Param[int] = 1
|
|
10
9
|
|
|
11
10
|
|
|
12
|
-
@config()
|
|
13
11
|
class A1(A):
|
|
14
12
|
pass
|
|
15
13
|
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
class B:
|
|
15
|
+
class B(Config):
|
|
19
16
|
a: Param[A]
|
|
20
17
|
|
|
21
18
|
|