experimaestro 1.3.6__py3-none-any.whl → 1.4.0__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/__main__.py +5 -0
- experimaestro/experiments/__init__.py +2 -0
- experimaestro/experiments/cli.py +220 -0
- experimaestro/experiments/configuration.py +32 -0
- {experimaestro-1.3.6.dist-info → experimaestro-1.4.0.dist-info}/METADATA +1 -1
- {experimaestro-1.3.6.dist-info → experimaestro-1.4.0.dist-info}/RECORD +9 -6
- {experimaestro-1.3.6.dist-info → experimaestro-1.4.0.dist-info}/LICENSE +0 -0
- {experimaestro-1.3.6.dist-info → experimaestro-1.4.0.dist-info}/WHEEL +0 -0
- {experimaestro-1.3.6.dist-info → experimaestro-1.4.0.dist-info}/entry_points.txt +0 -0
experimaestro/__main__.py
CHANGED
|
@@ -13,6 +13,7 @@ import subprocess
|
|
|
13
13
|
from termcolor import colored, cprint
|
|
14
14
|
|
|
15
15
|
import experimaestro
|
|
16
|
+
from experimaestro.experiments.cli import experiments_cli
|
|
16
17
|
import experimaestro.launcherfinder.registry as launcher_registry
|
|
17
18
|
|
|
18
19
|
# --- Command line main options
|
|
@@ -74,6 +75,10 @@ def cli(ctx, quiet, debug, traceback):
|
|
|
74
75
|
ctx.obj.traceback = traceback
|
|
75
76
|
|
|
76
77
|
|
|
78
|
+
# Adds the run-experiment command
|
|
79
|
+
cli.add_command(experiments_cli, "run-experiment")
|
|
80
|
+
|
|
81
|
+
|
|
77
82
|
@cli.command(help="Get version")
|
|
78
83
|
def version():
|
|
79
84
|
print(experimaestro.__version__)
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
import json
|
|
3
|
+
import logging
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any, List, Optional, Protocol, Tuple, Dict
|
|
7
|
+
|
|
8
|
+
import click
|
|
9
|
+
import omegaconf
|
|
10
|
+
import yaml
|
|
11
|
+
from experimaestro import LauncherRegistry, RunMode, experiment
|
|
12
|
+
from experimaestro.experiments.configuration import ConfigurationBase
|
|
13
|
+
from experimaestro.settings import get_workspace
|
|
14
|
+
from omegaconf import OmegaConf, SCMode
|
|
15
|
+
from termcolor import cprint
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ExperimentHelper:
|
|
19
|
+
"""Helper for experiments"""
|
|
20
|
+
|
|
21
|
+
# The experiment
|
|
22
|
+
xp: experiment
|
|
23
|
+
|
|
24
|
+
#: Run function
|
|
25
|
+
callable: "ExperimentCallable"
|
|
26
|
+
|
|
27
|
+
def __init__(self, callable: "ExperimentCallable"):
|
|
28
|
+
self.callable = callable
|
|
29
|
+
|
|
30
|
+
"""Handles extra arguments"""
|
|
31
|
+
|
|
32
|
+
def run(self, args: List[str], configuration: ConfigurationBase):
|
|
33
|
+
assert len(args) == 0
|
|
34
|
+
self.callable(self, configuration)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class ExperimentCallable(Protocol):
|
|
38
|
+
"""Protocol for the run function"""
|
|
39
|
+
|
|
40
|
+
def __call__(self, helper: ExperimentHelper, configuration: Any):
|
|
41
|
+
...
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def load(yaml_file: Path):
|
|
45
|
+
"""Loads a YAML file, and parents one if they exist"""
|
|
46
|
+
if not yaml_file.exists() and yaml_file.suffix != ".yaml":
|
|
47
|
+
yaml_file = yaml_file.with_suffix(".yaml")
|
|
48
|
+
|
|
49
|
+
with yaml_file.open("rt") as fp:
|
|
50
|
+
_data = yaml.full_load(fp)
|
|
51
|
+
data = [_data]
|
|
52
|
+
if parent := _data.get("parent", None):
|
|
53
|
+
data.extend(load(yaml_file.parent / parent))
|
|
54
|
+
|
|
55
|
+
return data
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@click.option("--debug", is_flag=True, help="Print debug information")
|
|
59
|
+
@click.option("--show", is_flag=True, help="Print configuration and exits")
|
|
60
|
+
@click.option(
|
|
61
|
+
"--env",
|
|
62
|
+
help="Define one environment variable",
|
|
63
|
+
type=(str, str),
|
|
64
|
+
multiple=True,
|
|
65
|
+
)
|
|
66
|
+
@click.option(
|
|
67
|
+
"--host",
|
|
68
|
+
type=str,
|
|
69
|
+
default=None,
|
|
70
|
+
help="Server hostname (default to localhost,"
|
|
71
|
+
" not suitable if your jobs are remote)",
|
|
72
|
+
)
|
|
73
|
+
@click.option(
|
|
74
|
+
"--run-mode",
|
|
75
|
+
type=click.Choice(RunMode),
|
|
76
|
+
default=RunMode.NORMAL,
|
|
77
|
+
help="Sets the run mode",
|
|
78
|
+
)
|
|
79
|
+
@click.option(
|
|
80
|
+
"--xpm-config-dir",
|
|
81
|
+
type=Path,
|
|
82
|
+
default=None,
|
|
83
|
+
help="Path for the experimaestro config directory "
|
|
84
|
+
"(if not specified, use $HOME/.config/experimaestro)",
|
|
85
|
+
)
|
|
86
|
+
@click.option(
|
|
87
|
+
"--port",
|
|
88
|
+
type=int,
|
|
89
|
+
default=None,
|
|
90
|
+
help="Port for monitoring (can be defined in the settings.yaml file)",
|
|
91
|
+
)
|
|
92
|
+
@click.option(
|
|
93
|
+
"--file", "xp_file", help="The file containing the main experimental code"
|
|
94
|
+
)
|
|
95
|
+
@click.option(
|
|
96
|
+
"--workdir",
|
|
97
|
+
type=str,
|
|
98
|
+
default=None,
|
|
99
|
+
help="Working directory - if None, uses the default XPM " "working directory",
|
|
100
|
+
)
|
|
101
|
+
@click.option("--conf", "-c", "extra_conf", type=str, multiple=True)
|
|
102
|
+
@click.argument("args", nargs=-1, type=click.UNPROCESSED)
|
|
103
|
+
@click.argument("yaml_file", metavar="YAML file", type=str)
|
|
104
|
+
@click.command()
|
|
105
|
+
def experiments_cli(
|
|
106
|
+
yaml_file: str,
|
|
107
|
+
xp_file: str,
|
|
108
|
+
host: str,
|
|
109
|
+
port: int,
|
|
110
|
+
xpm_config_dir: Path,
|
|
111
|
+
workdir: Optional[Path],
|
|
112
|
+
env: List[Tuple[str, str]],
|
|
113
|
+
run_mode: RunMode,
|
|
114
|
+
extra_conf: List[str],
|
|
115
|
+
args: List[str],
|
|
116
|
+
show: bool,
|
|
117
|
+
debug: bool,
|
|
118
|
+
):
|
|
119
|
+
"""Run an experiment"""
|
|
120
|
+
# --- Set the logger
|
|
121
|
+
logging.getLogger().setLevel(logging.DEBUG if debug else logging.INFO)
|
|
122
|
+
logging.getLogger("xpm.hash").setLevel(logging.INFO)
|
|
123
|
+
|
|
124
|
+
# --- Loads the YAML
|
|
125
|
+
yamls = load(Path(yaml_file))
|
|
126
|
+
|
|
127
|
+
# --- Get the XP file
|
|
128
|
+
if xp_file is None:
|
|
129
|
+
for data in yamls:
|
|
130
|
+
if xp_file := data.get("file"):
|
|
131
|
+
del data["file"]
|
|
132
|
+
break
|
|
133
|
+
|
|
134
|
+
if xp_file is None:
|
|
135
|
+
raise ValueError("No experiment file given")
|
|
136
|
+
|
|
137
|
+
# --- Set some options
|
|
138
|
+
|
|
139
|
+
if xpm_config_dir is not None:
|
|
140
|
+
assert xpm_config_dir.is_dir()
|
|
141
|
+
LauncherRegistry.set_config_dir(xpm_config_dir)
|
|
142
|
+
|
|
143
|
+
# --- Loads the XP file
|
|
144
|
+
xp_file = Path(xp_file)
|
|
145
|
+
if not xp_file.exists() and xp_file.suffix != ".py":
|
|
146
|
+
xp_file = xp_file.with_suffix(".py")
|
|
147
|
+
xp_file = Path(yaml_file).parent / xp_file
|
|
148
|
+
|
|
149
|
+
with open(xp_file, "r") as f:
|
|
150
|
+
source = f.read()
|
|
151
|
+
if sys.version_info < (3, 9):
|
|
152
|
+
the__file__ = str(xp_file)
|
|
153
|
+
else:
|
|
154
|
+
the__file__ = str(xp_file.absolute())
|
|
155
|
+
|
|
156
|
+
code = compile(source, filename=the__file__, mode="exec")
|
|
157
|
+
_locals: Dict[str, Any] = {}
|
|
158
|
+
|
|
159
|
+
sys.path.append(str(xp_file.parent.absolute()))
|
|
160
|
+
try:
|
|
161
|
+
exec(code, _locals, _locals)
|
|
162
|
+
finally:
|
|
163
|
+
sys.path.pop()
|
|
164
|
+
|
|
165
|
+
# --- ... and runs it
|
|
166
|
+
helper = _locals.get("run", None)
|
|
167
|
+
if helper is None:
|
|
168
|
+
raise ValueError(f"Could not find run function in {the__file__}")
|
|
169
|
+
|
|
170
|
+
if not isinstance(helper, ExperimentHelper):
|
|
171
|
+
helper = ExperimentHelper(helper)
|
|
172
|
+
|
|
173
|
+
parameters = inspect.signature(helper.callable).parameters
|
|
174
|
+
list_parameters = list(parameters.values())
|
|
175
|
+
assert len(list_parameters) == 2, (
|
|
176
|
+
"Callable function should only "
|
|
177
|
+
f"have two arguments (got {len(list_parameters)})"
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
schema = list_parameters[1].annotation
|
|
181
|
+
omegaconf_schema = OmegaConf.structured(schema())
|
|
182
|
+
|
|
183
|
+
configuration = OmegaConf.merge(*yamls)
|
|
184
|
+
if extra_conf:
|
|
185
|
+
configuration.merge_with(OmegaConf.from_dotlist(extra_conf))
|
|
186
|
+
if omegaconf_schema is not None:
|
|
187
|
+
try:
|
|
188
|
+
configuration = OmegaConf.merge(omegaconf_schema, configuration)
|
|
189
|
+
except omegaconf.errors.ConfigKeyError as e:
|
|
190
|
+
cprint(f"Error in configuration:\n\n{e}", "red", file=sys.stderr)
|
|
191
|
+
sys.exit(1)
|
|
192
|
+
|
|
193
|
+
# Move to an object container
|
|
194
|
+
configuration: schema = OmegaConf.to_container(
|
|
195
|
+
configuration, structured_config_mode=SCMode.INSTANTIATE
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
if show:
|
|
199
|
+
print(json.dumps(OmegaConf.to_container(configuration))) # noqa: T201
|
|
200
|
+
sys.exit(0)
|
|
201
|
+
|
|
202
|
+
# Get the working directory
|
|
203
|
+
if workdir is None or not Path(workdir).is_dir():
|
|
204
|
+
workdir = get_workspace(workdir).path.expanduser().resolve()
|
|
205
|
+
logging.info("Using working directory %s", workdir)
|
|
206
|
+
|
|
207
|
+
# --- Runs the experiment
|
|
208
|
+
with experiment(
|
|
209
|
+
workdir, configuration.id, host=host, port=port, run_mode=run_mode
|
|
210
|
+
) as xp:
|
|
211
|
+
# Set up the environment
|
|
212
|
+
for key, value in env:
|
|
213
|
+
xp.setenv(key, value)
|
|
214
|
+
|
|
215
|
+
# Run the experiment
|
|
216
|
+
helper.xp = xp
|
|
217
|
+
helper.run(list(args), configuration)
|
|
218
|
+
|
|
219
|
+
# ... and wait
|
|
220
|
+
xp.wait()
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
import attr
|
|
3
|
+
|
|
4
|
+
try:
|
|
5
|
+
from typing import dataclass_transform
|
|
6
|
+
except ImportError:
|
|
7
|
+
from typing_extensions import dataclass_transform
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass_transform(kw_only_default=True)
|
|
11
|
+
def configuration(*args, **kwargs):
|
|
12
|
+
"""Method to define keyword only dataclasses
|
|
13
|
+
|
|
14
|
+
Configurations are keyword-only
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
return attr.define(*args, kw_only=True, slots=False, hash=True, eq=True, **kwargs)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@configuration()
|
|
21
|
+
class ConfigurationBase:
|
|
22
|
+
id: str
|
|
23
|
+
"""ID of the experiment"""
|
|
24
|
+
|
|
25
|
+
description: str = ""
|
|
26
|
+
"""Description of the experiment"""
|
|
27
|
+
|
|
28
|
+
file: str = "experiment"
|
|
29
|
+
"""qualified name (relative to the module) for the file containing a run function"""
|
|
30
|
+
|
|
31
|
+
parent: Optional[str]
|
|
32
|
+
"""Relative path of a YAML file that should be merged"""
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
experimaestro/__init__.py,sha256=TURptLVx9XunBd01lO4TYZACrP5rnMRnh_XE0T0_MwQ,1533
|
|
2
|
-
experimaestro/__main__.py,sha256=
|
|
2
|
+
experimaestro/__main__.py,sha256=iRi6yRJVcthXRTVnHQB0TNOKTRmKjdnX6yIQaf-z79o,13528
|
|
3
3
|
experimaestro/annotations.py,sha256=dcpFmo01T12S_y5nIBIQjiXsGsq5S80ZB-58o8tW9wA,8450
|
|
4
4
|
experimaestro/checkers.py,sha256=ZCMbnE_GFC5compWjt-fuHhPImi9fCPjImF8Ow9NqK8,696
|
|
5
5
|
experimaestro/click.py,sha256=HTfjm4poqfG69MIYztrPWEei5OVnd154UCr2pJm6yp8,2390
|
|
@@ -17,6 +17,9 @@ experimaestro/core/serialization.py,sha256=nLlSSqerH9lqiWvqkCxz0YRRW8M1y56ainZ9_
|
|
|
17
17
|
experimaestro/core/serializers.py,sha256=R_CAMyjjfU1oi-eHU6VlEUixJpFayGqEPaYu7VsD9xA,1197
|
|
18
18
|
experimaestro/core/types.py,sha256=jQGlyC1xnsZ5NKct3FELIcXcXQMvNQvauCEuumyfBz8,19253
|
|
19
19
|
experimaestro/core/utils.py,sha256=jKmZqovj5BhmWQ0rXd3YFToSbIFTylC48NhCwxo3QfU,493
|
|
20
|
+
experimaestro/experiments/__init__.py,sha256=GcpDUIbCvhnv6rxFdAp4wTffCVNTv-InY6fbQAlTy-o,159
|
|
21
|
+
experimaestro/experiments/cli.py,sha256=QJ04wB0O3O0X0SEHM-Y8peA74lE1WIDesbk9_RsghL0,6216
|
|
22
|
+
experimaestro/experiments/configuration.py,sha256=bwoszuFWFT2fmaL7RNefNschBGpydDQkSgcSmLJ8gek,787
|
|
20
23
|
experimaestro/filter.py,sha256=DN1PrmS9yXoOa5Xnv001zbxzpdzvcVZFI9xZFKZ1-6g,5794
|
|
21
24
|
experimaestro/generators.py,sha256=9NQ_TfDfASkArLnO4PF7s5Yoo9KWjlna2DCPzk5gJOI,1230
|
|
22
25
|
experimaestro/huggingface.py,sha256=gnVlr6SZnbutYz4PLH0Q77n1TRF-uk-dR-3UFzFqAY0,2956
|
|
@@ -137,8 +140,8 @@ experimaestro/utils/resources.py,sha256=gDjkrRjo7GULWyXmNXm_u1uqzEIAoAvJydICk56n
|
|
|
137
140
|
experimaestro/utils/settings.py,sha256=jpFMqF0DLL4_P1xGal0zVR5cOrdD8O0Y2IOYvnRgN3k,793
|
|
138
141
|
experimaestro/utils/yaml.py,sha256=jEjqXqUtJ333wNUdIc0o3LGvdsTQ9AKW9a9CCd-bmGU,6766
|
|
139
142
|
experimaestro/xpmutils.py,sha256=S21eMbDYsHfvmZ1HmKpq5Pz5O-1HnCLYxKbyTBbASyQ,638
|
|
140
|
-
experimaestro-1.
|
|
141
|
-
experimaestro-1.
|
|
142
|
-
experimaestro-1.
|
|
143
|
-
experimaestro-1.
|
|
144
|
-
experimaestro-1.
|
|
143
|
+
experimaestro-1.4.0.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
144
|
+
experimaestro-1.4.0.dist-info/METADATA,sha256=XWQCmuYMI4mGENdtGlEA7p0D4enym4BV3laNFmW8Kc0,5336
|
|
145
|
+
experimaestro-1.4.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
146
|
+
experimaestro-1.4.0.dist-info/entry_points.txt,sha256=PhaEili_fDgn5q7rBJGip_uhGkRBq5l3Yuhg91zkcbk,574
|
|
147
|
+
experimaestro-1.4.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|