experimaestro 1.5.0__tar.gz → 1.5.1__tar.gz

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.

Files changed (147) hide show
  1. {experimaestro-1.5.0 → experimaestro-1.5.1}/PKG-INFO +1 -1
  2. {experimaestro-1.5.0 → experimaestro-1.5.1}/pyproject.toml +2 -2
  3. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/experiments/cli.py +16 -6
  4. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/launcherfinder/parser.py +8 -1
  5. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/launcherfinder/registry.py +7 -4
  6. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/launchers/slurm/base.py +30 -5
  7. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/scriptbuilder.py +12 -8
  8. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/settings.py +8 -2
  9. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/test_findlauncher.py +1 -1
  10. {experimaestro-1.5.0 → experimaestro-1.5.1}/LICENSE +0 -0
  11. {experimaestro-1.5.0 → experimaestro-1.5.1}/README.md +0 -0
  12. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/__init__.py +0 -0
  13. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/__main__.py +0 -0
  14. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/annotations.py +0 -0
  15. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/checkers.py +0 -0
  16. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/click.py +0 -0
  17. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/commandline.py +0 -0
  18. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/compat.py +0 -0
  19. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/connectors/__init__.py +0 -0
  20. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/connectors/local.py +0 -0
  21. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/connectors/ssh.py +0 -0
  22. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/core/__init__.py +0 -0
  23. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/core/arguments.py +0 -0
  24. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/core/context.py +0 -0
  25. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/core/objects.py +0 -0
  26. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/core/objects.pyi +0 -0
  27. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/core/serialization.py +0 -0
  28. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/core/serializers.py +0 -0
  29. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/core/types.py +0 -0
  30. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/core/utils.py +0 -0
  31. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/exceptions.py +0 -0
  32. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/experiments/__init__.py +0 -0
  33. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/experiments/configuration.py +0 -0
  34. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/filter.py +0 -0
  35. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/generators.py +0 -0
  36. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/huggingface.py +0 -0
  37. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/ipc.py +0 -0
  38. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/launcherfinder/__init__.py +0 -0
  39. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/launcherfinder/base.py +0 -0
  40. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/launcherfinder/specs.py +0 -0
  41. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/launchers/__init__.py +0 -0
  42. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/launchers/direct.py +0 -0
  43. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/launchers/oar.py +0 -0
  44. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/launchers/slurm/__init__.py +0 -0
  45. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/launchers/slurm/cli.py +0 -0
  46. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/launchers/slurm/configuration.py +0 -0
  47. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/locking.py +0 -0
  48. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/mkdocs/__init__.py +0 -0
  49. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/mkdocs/annotations.py +0 -0
  50. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/mkdocs/base.py +0 -0
  51. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/mkdocs/metaloader.py +0 -0
  52. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/mkdocs/style.css +0 -0
  53. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/mypy.py +0 -0
  54. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/notifications.py +0 -0
  55. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/py.typed +0 -0
  56. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/rpyc.py +0 -0
  57. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/run.py +0 -0
  58. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/scheduler/__init__.py +0 -0
  59. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/scheduler/base.py +0 -0
  60. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/scheduler/dependencies.py +0 -0
  61. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/scheduler/environment.py +0 -0
  62. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/scheduler/services.py +0 -0
  63. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/scheduler/workspace.py +0 -0
  64. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/__init__.py +0 -0
  65. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/016b4a6cdced82ab3aa1.ttf +0 -0
  66. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/0c35d18bf06992036b69.woff2 +0 -0
  67. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/219aa9140e099e6c72ed.woff2 +0 -0
  68. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/3a4004a46a653d4b2166.woff +0 -0
  69. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/3baa5b8f3469222b822d.woff +0 -0
  70. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/4d73cb90e394b34b7670.woff +0 -0
  71. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/4ef4218c522f1eb6b5b1.woff2 +0 -0
  72. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/50701fbb8177c2dde530.ttf +0 -0
  73. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/5d681e2edae8c60630db.woff +0 -0
  74. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/6f420cf17cc0d7676fad.woff2 +0 -0
  75. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/878f31251d960bd6266f.woff2 +0 -0
  76. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/b041b1fa4fe241b23445.woff2 +0 -0
  77. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/b6879d41b0852f01ed5b.woff2 +0 -0
  78. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/c380809fd3677d7d6903.woff2 +0 -0
  79. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/d75e3fd1eb12e9bd6655.ttf +0 -0
  80. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/f882956fd323fd322f31.woff +0 -0
  81. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/favicon.ico +0 -0
  82. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/index.css +0 -0
  83. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/index.css.map +0 -0
  84. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/index.html +0 -0
  85. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/index.js +0 -0
  86. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/index.js.map +0 -0
  87. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/login.html +0 -0
  88. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/server/data/manifest.json +0 -0
  89. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/sphinx/__init__.py +0 -0
  90. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/sphinx/static/experimaestro.css +0 -0
  91. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/taskglobals.py +0 -0
  92. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/__init__.py +0 -0
  93. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/conftest.py +0 -0
  94. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/connectors/bin/executable.py +0 -0
  95. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/connectors/test_local.py +0 -0
  96. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/connectors/utils.py +0 -0
  97. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/definitions_types.py +0 -0
  98. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/launchers/__init__.py +0 -0
  99. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/launchers/bin/sacct +0 -0
  100. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/launchers/bin/sbatch +0 -0
  101. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/launchers/bin/test.py +0 -0
  102. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/launchers/common.py +0 -0
  103. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/launchers/config_slurm/__init__.py +0 -0
  104. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/launchers/config_slurm/launchers.yaml +0 -0
  105. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/launchers/test_local.py +0 -0
  106. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/launchers/test_slurm.py +0 -0
  107. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/restart.py +0 -0
  108. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/restart_main.py +0 -0
  109. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/scripts/notifyandwait.py +0 -0
  110. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/scripts/waitforfile.py +0 -0
  111. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/task_tokens.py +0 -0
  112. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/tasks/__init__.py +0 -0
  113. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/tasks/all.py +0 -0
  114. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/tasks/foreign.py +0 -0
  115. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/test_checkers.py +0 -0
  116. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/test_dependencies.py +0 -0
  117. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/test_forward.py +0 -0
  118. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/test_identifier.py +0 -0
  119. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/test_instance.py +0 -0
  120. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/test_objects.py +0 -0
  121. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/test_outputs.py +0 -0
  122. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/test_param.py +0 -0
  123. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/test_progress.py +0 -0
  124. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/test_serializers.py +0 -0
  125. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/test_snippets.py +0 -0
  126. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/test_ssh.py +0 -0
  127. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/test_tags.py +0 -0
  128. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/test_tasks.py +0 -0
  129. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/test_tokens.py +0 -0
  130. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/test_types.py +0 -0
  131. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/test_validation.py +0 -0
  132. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/token_reschedule.py +0 -0
  133. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tests/utils.py +0 -0
  134. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tokens.py +0 -0
  135. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tools/__init__.py +0 -0
  136. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tools/diff.py +0 -0
  137. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tools/documentation.py +0 -0
  138. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/tools/jobs.py +0 -0
  139. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/typingutils.py +0 -0
  140. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/utils/__init__.py +0 -0
  141. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/utils/asyncio.py +0 -0
  142. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/utils/jobs.py +0 -0
  143. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/utils/jupyter.py +0 -0
  144. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/utils/resources.py +0 -0
  145. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/utils/settings.py +0 -0
  146. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/utils/yaml.py +0 -0
  147. {experimaestro-1.5.0 → experimaestro-1.5.1}/src/experimaestro/xpmutils.py +0 -0
@@ -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 @@ include = [
19
19
  "src/experimaestro/sphinx/static/experimaestro.css",
20
20
  "src/experimaestro/mkdocs/style.css"
21
21
  ]
22
- version = "1.5.0"
22
+ version = "1.5.1"
23
23
  repository = "https://github.com/experimaestro/experimaestro-python"
24
24
  documentation = "https://experimaestro-python.readthedocs.io/"
25
25
 
@@ -123,7 +123,7 @@ warn_unused_ignores = true
123
123
 
124
124
  [tool.commitizen]
125
125
  name = "cz_conventional_commits"
126
- version = "1.5.0"
126
+ version = "1.5.1"
127
127
  changelog_start_rev = "0.15.0"
128
128
  tag_format = "v$version"
129
129
  update_changelog_on_bump = true
@@ -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
 
@@ -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
File without changes
File without changes