experimaestro 1.5.0__py3-none-any.whl → 1.5.1__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.

@@ -1,4 +1,5 @@
1
1
  import inspect
2
+ import itertools
2
3
  import json
3
4
  import logging
4
5
  import sys
@@ -11,7 +12,7 @@ import yaml
11
12
  from experimaestro import LauncherRegistry, RunMode, experiment
12
13
  from experimaestro.experiments.configuration import ConfigurationBase
13
14
  from experimaestro.exceptions import HandledException
14
- from experimaestro.settings import get_workspace
15
+ from experimaestro.settings import get_settings, get_workspace
15
16
  from omegaconf import OmegaConf, SCMode
16
17
  from termcolor import cprint
17
18
 
@@ -219,21 +220,30 @@ def experiments_cli( # noqa: C901
219
220
  sys.exit(0)
220
221
 
221
222
  # Move to an object container
222
- configuration: schema = OmegaConf.to_container(
223
+ configuration = OmegaConf.to_container(
223
224
  configuration, structured_config_mode=SCMode.INSTANTIATE
224
225
  )
225
226
 
226
227
  # Get the working directory
227
- if workdir is None or not Path(workdir).is_dir():
228
- workdir = get_workspace(workdir).path.expanduser().resolve()
229
- logging.info("Using working directory %s", workdir)
228
+ settings = get_settings()
229
+ ws_env = {}
230
+ workdir = Path(workdir) if workdir else None
231
+ if (workdir is None) or (not workdir.is_dir()):
232
+ logging.info("Searching for workspace %s", workdir)
233
+ ws_settings = get_workspace(str(workdir))
234
+ workdir = ws_settings.path.expanduser()
235
+ ws_env = ws_settings.env
236
+
237
+ logging.info("Using working directory %s", str(workdir.resolve()))
230
238
 
231
239
  # --- Runs the experiment
232
240
  with experiment(
233
241
  workdir, configuration.id, host=host, port=port, run_mode=run_mode
234
242
  ) as xp:
235
243
  # Set up the environment
236
- for key, value in env:
244
+ # (1) global settings (2) workspace settings and (3) command line settings
245
+ for key, value in itertools.chain(settings.env.items(), ws_env.items(), env):
246
+ logging.info("Setting environment: %s=%s", key, value)
237
247
  xp.setenv(key, value)
238
248
 
239
249
  try:
@@ -54,8 +54,12 @@ def duration():
54
54
  return "duration", "=", RegExMatch(r"\d+"), RegExMatch(r"h(ours)?|d(ays)?")
55
55
 
56
56
 
57
+ def one_spec():
58
+ return OneOrMore(OrderedChoice([duration, cuda, cpu]), sep="&")
59
+
60
+
57
61
  def grammar():
58
- return OneOrMore(OrderedChoice([duration, cuda, cpu]), sep="&"), EndOfFile()
62
+ return OneOrMore(one_spec, sep="|"), EndOfFile()
59
63
 
60
64
 
61
65
  # ---- Visitor
@@ -63,6 +67,9 @@ def grammar():
63
67
 
64
68
  class Visitor(PTNodeVisitor):
65
69
  def visit_grammar(self, node, children):
70
+ return [child for child in children]
71
+
72
+ def visit_one_spec(self, node, children):
66
73
  return reduce(lambda x, el: x & el, children)
67
74
 
68
75
  def visit_duration(self, node, children):
@@ -219,7 +219,7 @@ class LauncherRegistry:
219
219
  raise AssertionError(f"No connector with identifier {identifier}")
220
220
 
221
221
  def find(
222
- self, *specs: Union[HostRequirement, str], tags: Set[str] = set()
222
+ self, *input_specs: Union[HostRequirement, str], tags: Set[str] = set()
223
223
  ) -> Optional["Launcher"]:
224
224
  """ "
225
225
  Arguments:
@@ -237,7 +237,12 @@ class LauncherRegistry:
237
237
  # Parse specs
238
238
  from .parser import parse
239
239
 
240
- specs = [parse(spec) if isinstance(spec, str) else spec for spec in specs]
240
+ specs = []
241
+ for spec in input_specs:
242
+ if isinstance(spec, str):
243
+ specs.extend(parse(spec))
244
+ else:
245
+ specs.append(spec)
241
246
 
242
247
  # Use launcher function
243
248
  if self.find_launcher_fn is not None:
@@ -247,8 +252,6 @@ class LauncherRegistry:
247
252
 
248
253
  # We have registered launchers
249
254
  for spec in specs:
250
- if isinstance(spec, str):
251
- spec = parse(spec)
252
255
  for handler in self.launchers:
253
256
  if (not tags) or any((tag in tags) for tag in handler.tags):
254
257
  if launcher := handler.get(self, spec):
@@ -92,6 +92,8 @@ class SlurmProcessWatcher(threading.Thread):
92
92
  self.jobs: Dict[str, SlurmJobState] = {}
93
93
 
94
94
  self.cv = ThreadingCondition()
95
+ self.fetched_event = threading.Event()
96
+ self.updating_jobs = threading.Lock()
95
97
  self.start()
96
98
 
97
99
  @staticmethod
@@ -109,10 +111,18 @@ class SlurmProcessWatcher(threading.Thread):
109
111
  with watcher.cv:
110
112
  watcher.cv.notify()
111
113
 
112
- def getjob(self, jobid):
114
+ def getjob(self, jobid, timeout=None):
113
115
  """Allows to share the calls to sacct"""
116
+
117
+ # Ensures that we have fetched at least once
118
+ self.fetched_event.wait()
119
+
120
+ # Waits that jobs are refreshed (with a timeout)
114
121
  with self.cv:
115
- self.cv.wait()
122
+ self.cv.wait(timeout=timeout)
123
+
124
+ # Ensures jobs are not updated right now
125
+ with self.updating_jobs:
116
126
  return self.jobs.get(jobid)
117
127
 
118
128
  def run(self):
@@ -129,9 +139,9 @@ class SlurmProcessWatcher(threading.Thread):
129
139
  builder.stdout = Redirect.pipe(handler)
130
140
  builder.environ = self.launcher.launcherenv
131
141
  logger.debug("Checking SLURM state with sacct")
132
- builder.start()
142
+ process = builder.start()
133
143
 
134
- with self.cv:
144
+ with self.updating_jobs:
135
145
  self.jobs = {}
136
146
  output = handler.output.decode("utf-8")
137
147
  for line in output.split("\n"):
@@ -143,7 +153,11 @@ class SlurmProcessWatcher(threading.Thread):
143
153
  logger.debug("Parsed line: %s", line)
144
154
  except ValueError:
145
155
  logger.error("Could not parse line %s", line)
156
+ process.kill()
157
+
158
+ with self.cv:
146
159
  logger.debug("Jobs %s", self.jobs)
160
+ self.fetched_event.set()
147
161
  self.cv.notify_all()
148
162
 
149
163
  self.cv.wait_for(
@@ -193,7 +207,18 @@ class BatchSlurmProcess(Process):
193
207
  def fromspec(cls, connector: Connector, spec: Dict[str, Any]):
194
208
  options = {k: v for k, v in spec.get("options", ())}
195
209
  launcher = SlurmLauncher(connector=connector, **options)
196
- return BatchSlurmProcess(launcher, spec["pid"])
210
+ process = BatchSlurmProcess(launcher, spec["pid"])
211
+
212
+ # Checks that the process is running
213
+ with SlurmProcessWatcher.get(launcher) as watcher:
214
+ logger.info("Checking SLURM job %s", process.jobid)
215
+ jobinfo = watcher.getjob(process.jobid, timeout=0.1)
216
+ if jobinfo and jobinfo.state.running:
217
+ logger.debug(
218
+ "SLURM job is running (%s), returning process", process.jobid
219
+ )
220
+ return process
221
+ return None
197
222
 
198
223
 
199
224
  def addstream(command: List[str], option: str, redirect: Redirect):
@@ -91,24 +91,28 @@ class PythonScriptBuilder:
91
91
  logger.debug("Writing script %s", scriptpath)
92
92
  with scriptpath.open("wt") as out:
93
93
  out.write("#!{}\n".format(self.pythonpath))
94
- out.write("# Experimaestro generated task\n")
94
+ out.write("# Experimaestro generated task\n\n")
95
+ out.write("""import logging\nlogging.basicConfig(level=logging.INFO)\n\n""")
96
+
97
+ out.write("\nif __name__ == '__main__':\n\n" "")
95
98
 
96
99
  # --- Checks locks right away
97
100
 
98
- out.write("""import logging\nlogging.basicConfig(level=logging.INFO)\n\n""")
99
- out.write("""from experimaestro.run import TaskRunner\nimport os\n\n""")
101
+ out.write(
102
+ """ from experimaestro.run import TaskRunner\n import os\n\n"""
103
+ )
100
104
 
101
- out.write("lockfiles = [\n")
105
+ out.write(" lockfiles = [\n")
102
106
  for path in self.lockfiles:
103
- out.write(f" '''{relpath(path)}''',\n")
104
- out.write("]\n")
107
+ out.write(f" '''{relpath(path)}''',\n")
108
+ out.write(" ]\n")
105
109
 
106
110
  for name, value in job.environ.items():
107
- out.write(f"""os.environ["{name}"] = "{shquote(value)}"\n""")
111
+ out.write(f""" os.environ["{name}"] = "{shquote(value)}"\n""")
108
112
  out.write("\n")
109
113
 
110
114
  out.write(
111
- f"""TaskRunner("{shquote(connector.resolve(scriptpath))}","""
115
+ f""" TaskRunner("{shquote(connector.resolve(scriptpath))}","""
112
116
  """ lockfiles).run()\n"""
113
117
  )
114
118
 
experimaestro/settings.py CHANGED
@@ -1,9 +1,9 @@
1
1
  import os
2
2
  from omegaconf import OmegaConf
3
- from dataclasses import dataclass, field
3
+ from dataclasses import field, dataclass
4
4
  from functools import lru_cache
5
5
  from pathlib import Path
6
- from typing import Optional, List
6
+ from typing import Dict, Optional, List
7
7
 
8
8
 
9
9
  @dataclass
@@ -29,12 +29,18 @@ class WorkspaceSettings:
29
29
  path: Path
30
30
  """The workspace path"""
31
31
 
32
+ env: Dict[str, str] = field(default_factory=dict)
33
+ """Workspace specific environment variables"""
34
+
32
35
 
33
36
  @dataclass
34
37
  class Settings:
35
38
  server: ServerSettings = field(default_factory=ServerSettings)
36
39
  workspaces: List[WorkspaceSettings] = field(default_factory=list)
37
40
 
41
+ env: Dict[str, str] = field(default_factory=dict)
42
+ """Default environment variables"""
43
+
38
44
 
39
45
  @lru_cache()
40
46
  def get_settings(path: Optional[Path] = None) -> Settings:
@@ -60,7 +60,7 @@ def test_findlauncher_specs_gpu_mem():
60
60
 
61
61
 
62
62
  def test_findlauncher_parse():
63
- r = parse("""duration=4 d & cuda(mem=4G) * 2 & cpu(mem=400M, cores=4)""")
63
+ (r,) = parse("""duration=4 d & cuda(mem=4G) * 2 & cpu(mem=400M, cores=4)""")
64
64
  assert isinstance(r, HostSimpleRequirement)
65
65
 
66
66
  assert len(r.cuda_gpus) == 2
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: experimaestro
3
- Version: 1.5.0
3
+ Version: 1.5.1
4
4
  Summary: "Experimaestro is a computer science experiment manager"
5
5
  Home-page: https://github.com/experimaestro/experimaestro-python
6
6
  License: GPL-3
@@ -19,7 +19,7 @@ experimaestro/core/types.py,sha256=oTXD4UjMVoYn_Usxn2C4h6IGhYDTtekKB3O3hfeOynQ,2
19
19
  experimaestro/core/utils.py,sha256=JfC3qGUS9b6FUHc2VxIYUI9ysNpXSQ1LjOBkjfZ8n7o,495
20
20
  experimaestro/exceptions.py,sha256=cUy83WHM3GeynxmMk6QRr5xsnpqUAdAoc-m3KQVrE2o,44
21
21
  experimaestro/experiments/__init__.py,sha256=GcpDUIbCvhnv6rxFdAp4wTffCVNTv-InY6fbQAlTy-o,159
22
- experimaestro/experiments/cli.py,sha256=vne6skjbNmMIIgmlEJY0b_xoJIxgIjis07xL4byr-0o,7080
22
+ experimaestro/experiments/cli.py,sha256=MXJNRCvSuespStK8BSR82q-3NSPPXm6jq0Rsui4V2BU,7535
23
23
  experimaestro/experiments/configuration.py,sha256=8GRqyLG1leF_NbvbFzqpm0yM24O0WjSNmQzvnuLnxxw,1150
24
24
  experimaestro/filter.py,sha256=DN1PrmS9yXoOa5Xnv001zbxzpdzvcVZFI9xZFKZ1-6g,5794
25
25
  experimaestro/generators.py,sha256=9NQ_TfDfASkArLnO4PF7s5Yoo9KWjlna2DCPzk5gJOI,1230
@@ -27,14 +27,14 @@ experimaestro/huggingface.py,sha256=gnVlr6SZnbutYz4PLH0Q77n1TRF-uk-dR-3UFzFqAY0,
27
27
  experimaestro/ipc.py,sha256=ltYqybPm_XfcQC3yiskMfhfI_1dREs-XRu0F83YsNws,1490
28
28
  experimaestro/launcherfinder/__init__.py,sha256=jIeT9uRKsIjUv-oyKt0MhFzXJJrSdpJKwM2vL9Sk5YY,294
29
29
  experimaestro/launcherfinder/base.py,sha256=NptPJ0e8CktdhOPejocSfI_B4mloeH_EmJrbXruUCSA,1020
30
- experimaestro/launcherfinder/parser.py,sha256=0qDXgdPce_PsWDy-hKTfxxjXjTAu4FA8moKtyllB2-Q,2129
31
- experimaestro/launcherfinder/registry.py,sha256=KxlKZDl0PbBIh-JUnn0U8JYSHVt14L3Qox0DKJefwoc,8892
30
+ experimaestro/launcherfinder/parser.py,sha256=pYbfEJw7osnqZWm7fkVhQawhpNU8dLU_6vEjtXdc8E8,2279
31
+ experimaestro/launcherfinder/registry.py,sha256=FKoacw7sIFxfYTRvaJpQs6o67qtBIDJobX0nmEUBU1Y,8927
32
32
  experimaestro/launcherfinder/specs.py,sha256=G8za6mEmkVxuZY_ab3OhWJIpONpcBMO_iXeB30sUbhI,6448
33
33
  experimaestro/launchers/__init__.py,sha256=lXn544sgJExr6uirILWzAXu_IfmfyqFZOt4OzRnjHXg,2525
34
34
  experimaestro/launchers/direct.py,sha256=VJzQNrUGnh-1Ovt6uw4yYIjXNu45QpR-_6V45lcZAfQ,1967
35
35
  experimaestro/launchers/oar.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
36
  experimaestro/launchers/slurm/__init__.py,sha256=R1Zwd4phZaXV8FwCYhzfB44n0V4cf-hBQzOc6NkFQ0s,41
37
- experimaestro/launchers/slurm/base.py,sha256=NoOO4Dj_KP9A0wjVthmDT6PoOquc21JbVsh_hKsmGiU,13200
37
+ experimaestro/launchers/slurm/base.py,sha256=nMoSBMbA901OcneSHVXj8PXGqfv4mVN5G-NPDZ0HXO0,14135
38
38
  experimaestro/launchers/slurm/cli.py,sha256=c-S0TImvhZ-ZxFs5-5T2GRDm5manRYRiYudpQLHwsrQ,818
39
39
  experimaestro/launchers/slurm/configuration.py,sha256=mtozeuvIZmEfHlvEylwCgBrlVRFHT_jWNAKVxR4Tz1E,19357
40
40
  experimaestro/locking.py,sha256=hPT-LuDGZTijpbme8O0kEoB9a3WjdVzI2h31OT44UxE,1477
@@ -54,7 +54,7 @@ experimaestro/scheduler/dependencies.py,sha256=n9XegwrmjayOIxt3xhuTEBVEBGSq4oeVd
54
54
  experimaestro/scheduler/environment.py,sha256=ZaSHSgAcZBmIj7b_eS1OvNQOuVLFvuw-qvqtYrc3Vms,2393
55
55
  experimaestro/scheduler/services.py,sha256=aCKkNZMULlceabqf-kOs_-C7KPINnjU3Q-I00o5x6iY,2189
56
56
  experimaestro/scheduler/workspace.py,sha256=xATJi6-GJcpdwB4alliJnmAuvwt-URUiUKUfq5scUac,1731
57
- experimaestro/scriptbuilder.py,sha256=-wq4jgH8eKpjKWyU_7SxU7MNJLfPqZ0VdERv6rrkJ88,4235
57
+ experimaestro/scriptbuilder.py,sha256=AYh2LdO__mrCWuFa1JWvdfKm_wnk5hHDr_OjHo1voIE,4357
58
58
  experimaestro/server/__init__.py,sha256=F2bzLf2q29Haj2OIbPA26r5WVbaipBNylIozg-As758,10854
59
59
  experimaestro/server/data/016b4a6cdced82ab3aa1.ttf,sha256=AD8RVBhWpkmmyCNcYmbIk2IkxdYJ5RRC2iTcVVbRT78,189684
60
60
  experimaestro/server/data/0c35d18bf06992036b69.woff2,sha256=gmX2R4Y5fWuDLRygqv3xSa2E5ydZ__qfcnLpGg-wFdE,128352
@@ -80,7 +80,7 @@ experimaestro/server/data/index.js,sha256=f0GvRsfsQ4ayP4en7Q-raZ6buwRXLCswCbzVax
80
80
  experimaestro/server/data/index.js.map,sha256=za3MUIjzyyGRI6F5KuBFMTgrFU55xgt0LBrw-4YPHag,3904832
81
81
  experimaestro/server/data/login.html,sha256=4dvhSOn6DHp_tbmzqIKrqq2uAo0sAUbgLVD0lTnPp4s,511
82
82
  experimaestro/server/data/manifest.json,sha256=EpzHQZzrGh9c1Kf63nrqvI33H1cm0nLYfdh5lDm8ijI,318
83
- experimaestro/settings.py,sha256=YTUHZROgrGuSAhZIke74bhBrF2CBH7eSj98ZNjmnMsU,1600
83
+ experimaestro/settings.py,sha256=nZO-667XgM-aC6A-RHw1C4gglDlDeIIIJAxs83IgRyI,1807
84
84
  experimaestro/sphinx/__init__.py,sha256=heovvtwbYToZM-b6HNi4pJdBoo_97usdEawhMGSK3bk,9560
85
85
  experimaestro/sphinx/static/experimaestro.css,sha256=0rEgt1LoDdD-a_R5rVfWZ19zD1gR-1L7q3f4UibIB58,294
86
86
  experimaestro/taskglobals.py,sha256=aBjPpo4HQp6E6M3GQ8L6PR4rK2Lu0kD5dS1WjnaGgDc,499
@@ -109,7 +109,7 @@ experimaestro/tests/tasks/all.py,sha256=hrI2CDyeaYrp2IPzXWif-Uu1Uirkndmuih3Jj09C
109
109
  experimaestro/tests/tasks/foreign.py,sha256=7IAF525mmMORxSPKQmU1z1B84XPmwsO8PGdxBvYknwU,153
110
110
  experimaestro/tests/test_checkers.py,sha256=Kg5frDNRE3pvWVmmYzyk0tJFNO885KOrK48lSu-NlYA,403
111
111
  experimaestro/tests/test_dependencies.py,sha256=xfWrSkvjT45G4FSCL535m1huLT2ghmyW7kvP_XvvCJQ,2005
112
- experimaestro/tests/test_findlauncher.py,sha256=twliDFFI75KPuUJE6EgJwDMf8u3ic1LAOyNOwufFtTw,2964
112
+ experimaestro/tests/test_findlauncher.py,sha256=r34dci01FK9YpjtTHR9fIQ7AMHaMXQOrWtarytcf_Us,2967
113
113
  experimaestro/tests/test_forward.py,sha256=XkZ2iOPETVj-kbTyniOQU9gyHXdfvn89GTwpMq9J6qc,780
114
114
  experimaestro/tests/test_identifier.py,sha256=fnl7jCUAg86npRrS3yeXtb9JysSKhs5czgFzW9yJ9Q8,13397
115
115
  experimaestro/tests/test_instance.py,sha256=awIIMnhiec_qDO6jZBqWDR13ReTzh3arK_60QDY6TLQ,1540
@@ -141,8 +141,8 @@ experimaestro/utils/resources.py,sha256=gDjkrRjo7GULWyXmNXm_u1uqzEIAoAvJydICk56n
141
141
  experimaestro/utils/settings.py,sha256=jpFMqF0DLL4_P1xGal0zVR5cOrdD8O0Y2IOYvnRgN3k,793
142
142
  experimaestro/utils/yaml.py,sha256=jEjqXqUtJ333wNUdIc0o3LGvdsTQ9AKW9a9CCd-bmGU,6766
143
143
  experimaestro/xpmutils.py,sha256=S21eMbDYsHfvmZ1HmKpq5Pz5O-1HnCLYxKbyTBbASyQ,638
144
- experimaestro-1.5.0.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
145
- experimaestro-1.5.0.dist-info/METADATA,sha256=Mf0BErVRpCxCp2hnBnbH42ZE1cuK56TUSCO-WG4xMBQ,6265
146
- experimaestro-1.5.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
147
- experimaestro-1.5.0.dist-info/entry_points.txt,sha256=PhaEili_fDgn5q7rBJGip_uhGkRBq5l3Yuhg91zkcbk,574
148
- experimaestro-1.5.0.dist-info/RECORD,,
144
+ experimaestro-1.5.1.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
145
+ experimaestro-1.5.1.dist-info/METADATA,sha256=A79XLTCvr5By9ybZMel3_0FZduD20ww4kOamF-4xeQA,6265
146
+ experimaestro-1.5.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
147
+ experimaestro-1.5.1.dist-info/entry_points.txt,sha256=PhaEili_fDgn5q7rBJGip_uhGkRBq5l3Yuhg91zkcbk,574
148
+ experimaestro-1.5.1.dist-info/RECORD,,