experimaestro 0.21.0__zip → 0.23.0__zip

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 (186) hide show
  1. {experimaestro-0.21.0 → experimaestro-0.23.0}/CHANGELOG.md +17 -0
  2. {experimaestro-0.21.0 → experimaestro-0.23.0}/PKG-INFO +18 -1
  3. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/Services.tsx +1 -1
  4. {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/experiments/plan.md +6 -6
  5. {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/index.md +2 -1
  6. {experimaestro-0.21.0 → experimaestro-0.23.0}/pyproject.toml +1 -1
  7. {experimaestro-0.21.0 → experimaestro-0.23.0}/requirements.txt +4 -3
  8. {experimaestro-0.21.0 → experimaestro-0.23.0}/setup.cfg +1 -1
  9. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/__init__.py +5 -2
  10. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/__main__.py +1 -1
  11. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/annotations.py +31 -15
  12. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/commandline.py +0 -8
  13. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/core/objects.py +51 -35
  14. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/core/objects.pyi +23 -10
  15. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/core/types.py +44 -2
  16. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/generators.py +7 -6
  17. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/launchers/__init__.py +19 -7
  18. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/scheduler/base.py +21 -3
  19. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/server/__init__.py +12 -4
  20. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/utils/__init__.py +12 -0
  21. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/utils/jobs.py +6 -3
  22. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/utils/jupyter.py +14 -4
  23. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/version.py +2 -2
  24. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/xpmutils.py +3 -3
  25. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro.egg-info/PKG-INFO +18 -1
  26. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro.egg-info/requires.txt +5 -2
  27. {experimaestro-0.21.0 → experimaestro-0.23.0}/.circleci/config.yml +0 -0
  28. {experimaestro-0.21.0 → experimaestro-0.23.0}/.flake8 +0 -0
  29. {experimaestro-0.21.0 → experimaestro-0.23.0}/.github/release.yaml +0 -0
  30. {experimaestro-0.21.0 → experimaestro-0.23.0}/.github/workflows/pytest.yml +0 -0
  31. {experimaestro-0.21.0 → experimaestro-0.23.0}/.github/workflows/python-publish.yml +0 -0
  32. {experimaestro-0.21.0 → experimaestro-0.23.0}/.gitignore +0 -0
  33. {experimaestro-0.21.0 → experimaestro-0.23.0}/.gitmodules +0 -0
  34. {experimaestro-0.21.0 → experimaestro-0.23.0}/.pre-commit-config.yaml +0 -0
  35. {experimaestro-0.21.0 → experimaestro-0.23.0}/.prettierignore +0 -0
  36. {experimaestro-0.21.0 → experimaestro-0.23.0}/.readthedocs.yml +0 -0
  37. {experimaestro-0.21.0 → experimaestro-0.23.0}/LICENSE +0 -0
  38. {experimaestro-0.21.0 → experimaestro-0.23.0}/MANIFEST.in +0 -0
  39. {experimaestro-0.21.0 → experimaestro-0.23.0}/README.md +0 -0
  40. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/.gitignore +0 -0
  41. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/.nolluprc.js +0 -0
  42. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/CHANGELOG.md +0 -0
  43. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/README.md +0 -0
  44. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/package-lock.json +0 -0
  45. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/package.json +0 -0
  46. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/postcss.config.js +0 -0
  47. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/public/favicon.ico +0 -0
  48. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/public/index.html +0 -0
  49. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/public/login.html +0 -0
  50. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/public/manifest.json +0 -0
  51. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/App.tsx +0 -0
  52. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/Experiments.tsx +0 -0
  53. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/TaskDetail.tsx +0 -0
  54. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/TaskJobs.tsx +0 -0
  55. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/Tasks.tsx +0 -0
  56. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/client.ts +0 -0
  57. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/clipboard.ts +0 -0
  58. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/index.css +0 -0
  59. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/index.tsx +0 -0
  60. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/logo.png +0 -0
  61. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/logo.pxm +0 -0
  62. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/reducers.ts +0 -0
  63. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/store.ts +0 -0
  64. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/theme/_jobs.scss +0 -0
  65. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/theme/theme.scss +0 -0
  66. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/ui/messages.tsx +0 -0
  67. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/tsconfig.json +0 -0
  68. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/webpack.config.ts +0 -0
  69. {experimaestro-0.21.0 → experimaestro-0.23.0}/app/xp/run.py +0 -0
  70. {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/changelog.md +0 -0
  71. {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/cli.md +0 -0
  72. {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/concepts.md +0 -0
  73. {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/configuration.md +0 -0
  74. {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/connectors/index.md +0 -0
  75. {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/documenting.md +0 -0
  76. {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/experiments/config.md +0 -0
  77. {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/experiments/overview.md +0 -0
  78. {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/experiments/task.md +0 -0
  79. {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/faq.md +0 -0
  80. {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/jupyter.md +0 -0
  81. {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/launchers/index.md +0 -0
  82. {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/requirements.txt +0 -0
  83. {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/serialization.md +0 -0
  84. {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/tutorial.md +0 -0
  85. {experimaestro-0.21.0 → experimaestro-0.23.0}/mkdocs.yml +0 -0
  86. {experimaestro-0.21.0 → experimaestro-0.23.0}/pytest.ini +0 -0
  87. {experimaestro-0.21.0 → experimaestro-0.23.0}/scripts/longtask.py +0 -0
  88. {experimaestro-0.21.0 → experimaestro-0.23.0}/setup.py +0 -0
  89. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/checkers.py +0 -0
  90. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/click.py +0 -0
  91. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/compat.py +0 -0
  92. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/connectors/__init__.py +0 -0
  93. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/connectors/local.py +0 -0
  94. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/connectors/ssh.py +0 -0
  95. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/core/__init__.py +0 -0
  96. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/core/arguments.py +0 -0
  97. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/core/context.py +0 -0
  98. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/filter.py +0 -0
  99. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/huggingface.py +0 -0
  100. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/ipc.py +0 -0
  101. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/launcherfinder/__init__.py +0 -0
  102. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/launcherfinder/base.py +0 -0
  103. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/launcherfinder/parser.py +0 -0
  104. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/launcherfinder/registry.py +0 -0
  105. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/launcherfinder/specs.py +0 -0
  106. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/launchers/direct.py +0 -0
  107. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/launchers/oar.py +0 -0
  108. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/launchers/slurm.py +0 -0
  109. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/locking.py +0 -0
  110. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/mkdocs/__init__.py +0 -0
  111. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/mkdocs/annotations.py +0 -0
  112. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/mkdocs/base.py +0 -0
  113. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/mkdocs/metaloader.py +0 -0
  114. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/mkdocs/style.css +0 -0
  115. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/mypy.py +0 -0
  116. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/notifications.py +0 -0
  117. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/rpyc.py +0 -0
  118. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/run.py +0 -0
  119. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/scheduler/__init__.py +0 -0
  120. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/scheduler/dependencies.py +0 -0
  121. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/scheduler/environment.py +0 -0
  122. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/scheduler/services.py +0 -0
  123. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/scheduler/workspace.py +0 -0
  124. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/scriptbuilder.py +0 -0
  125. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/settings.py +0 -0
  126. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/sphinx/__init__.py +0 -0
  127. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/sphinx/static/experimaestro.css +0 -0
  128. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/taskglobals.py +0 -0
  129. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/__init__.py +0 -0
  130. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/conftest.py +0 -0
  131. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/connectors/bin/executable.py +0 -0
  132. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/connectors/test_local.py +0 -0
  133. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/connectors/utils.py +0 -0
  134. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/definitions_types.py +0 -0
  135. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/launchers/__init__.py +0 -0
  136. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/launchers/bin/sacct +0 -0
  137. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/launchers/bin/sbatch +0 -0
  138. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/launchers/bin/test.py +0 -0
  139. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/launchers/common.py +0 -0
  140. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/launchers/config_slurm/__init__.py +0 -0
  141. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/launchers/config_slurm/launchers.yaml +0 -0
  142. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/launchers/test_local.py +0 -0
  143. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/launchers/test_slurm.py +0 -0
  144. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/restart.py +0 -0
  145. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/restart_main.py +0 -0
  146. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/scripts/notifyandwait.py +0 -0
  147. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/scripts/waitforfile.py +0 -0
  148. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/task_tokens.py +0 -0
  149. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/tasks/__init__.py +0 -0
  150. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/tasks/all.py +0 -0
  151. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/tasks/foreign.py +0 -0
  152. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/tasks/subparams.py +0 -0
  153. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_checkers.py +0 -0
  154. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_findlauncher.py +0 -0
  155. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_forward.py +0 -0
  156. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_identifier.py +0 -0
  157. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_instance.py +0 -0
  158. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_objects.py +0 -0
  159. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_outputs.py +0 -0
  160. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_param.py +0 -0
  161. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_progress.py +0 -0
  162. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_serialization.py +0 -0
  163. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_snippets.py +0 -0
  164. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_ssh.py +0 -0
  165. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_tags.py +0 -0
  166. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_tasks.py +0 -0
  167. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_tokens.py +0 -0
  168. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_types.py +0 -0
  169. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_validation.py +0 -0
  170. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/token_reschedule.py +0 -0
  171. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/utils.py +0 -0
  172. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tokens.py +0 -0
  173. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tools/__init__.py +0 -0
  174. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tools/diff.py +0 -0
  175. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tools/jobs.py +0 -0
  176. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/typingutils.py +0 -0
  177. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/utils/asyncio.py +0 -0
  178. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/utils/resources.py +0 -0
  179. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/utils/settings.py +0 -0
  180. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/utils/yaml.py +0 -0
  181. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro.egg-info/SOURCES.txt +0 -0
  182. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro.egg-info/dependency_links.txt +0 -0
  183. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro.egg-info/entry_points.txt +0 -0
  184. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro.egg-info/not-zip-safe +0 -0
  185. {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro.egg-info/top_level.txt +0 -0
  186. {experimaestro-0.21.0 → experimaestro-0.23.0}/tox.ini +0 -0
@@ -1,6 +1,7 @@
1
+ from abc import ABC, abstractmethod
1
2
  import inspect
2
3
  import sys
3
- from typing import Union, Dict, Iterator, List
4
+ from typing import Set, Union, Dict, Iterator, List
4
5
  from collections import ChainMap
5
6
  from pathlib import Path
6
7
  import typing
@@ -17,6 +18,11 @@ if sys.version_info.major == 3 and sys.version_info.minor < 9:
17
18
  else:
18
19
  from typing import _AnnotatedAlias, get_type_hints
19
20
 
21
+ if typing.TYPE_CHECKING:
22
+ from experimaestro.scheduler.base import Job
23
+ from experimaestro.launchers import Launcher
24
+ from experimaestro.core.objects import Config
25
+
20
26
 
21
27
  class Identifier:
22
28
  def __init__(self, name: str):
@@ -143,7 +149,42 @@ class DeprecatedAttribute:
143
149
  self.fn(instance, value)
144
150
 
145
151
 
152
+ class SubmitHook(ABC):
153
+ """Hook called before the job is submitted to the scheduler
154
+
155
+ This allows modifying e.g. the run environnement
156
+ """
157
+
158
+ @abstractmethod
159
+ def __call__(self, job: "Job", launcher: "Launcher"):
160
+ ...
161
+
162
+ @abstractmethod
163
+ def __spec__(self):
164
+ """Returns an identifier tuple for hashing/equality"""
165
+ ...
166
+
167
+ def __eq__(self, other):
168
+ if other.__class__ is not self.__class__:
169
+ return False
170
+ return self.__spec__ == other.__spec__
171
+
172
+ def __hash__(self):
173
+ return hash((self.__class__, self.__spec__))
174
+
175
+
176
+ def submit_hook_decorator(hook: SubmitHook):
177
+ def decorator(cls: typing.Type["Config"]):
178
+ cls.__getxpmtype__().submit_hooks.add(hook)
179
+ return cls
180
+
181
+ return decorator
182
+
183
+
146
184
  class ObjectType(Type):
185
+ submit_hooks: Set[SubmitHook]
186
+ """Hooks associated with this configuration"""
187
+
147
188
  """ObjectType contains class-level information about
148
189
  experimaestro configurations and tasks
149
190
 
@@ -167,6 +208,7 @@ class ObjectType(Type):
167
208
  self.taskcommandfactory = None
168
209
  self.task = None
169
210
  self._title = None
211
+ self.submit_hooks = set()
170
212
 
171
213
  # Get the identifier
172
214
  if identifier is None and hasattr(tp, "__xpmid__"):
@@ -219,7 +261,7 @@ class ObjectType(Type):
219
261
  self.configtype.__module__ = tp.__module__
220
262
 
221
263
  # Create the type-specific object class
222
- # (now, the same as basetype - TODO: remove references)
264
+ # (now, the same as basetype - but in the future, remove references)
223
265
  self.objecttype = self.basetype # type: type
224
266
  self.basetype._ = self.configtype
225
267
 
@@ -1,15 +1,16 @@
1
1
  import inspect
2
2
  from pathlib import Path
3
- from typing import Callable, List, Tuple, Union
3
+ from typing import Callable, Union
4
4
  from experimaestro.core.arguments import ArgumentOptions, TypeAnnotation
5
- from experimaestro.core.objects import GenerationContext, Config
5
+ from experimaestro.core.objects import ConfigWalkContext, Config
6
6
 
7
7
 
8
8
  class Generator:
9
9
  """Base class for all generators"""
10
10
 
11
11
  def isoutput(self):
12
- """Returns True if this generator is a task output (e.g. generates a path within the job folder)"""
12
+ """Returns True if this generator is a task output (e.g. generates a
13
+ path within the job folder)"""
13
14
  return False
14
15
 
15
16
 
@@ -17,11 +18,11 @@ class PathGenerator(Generator):
17
18
  """Generates a path"""
18
19
 
19
20
  def __init__(
20
- self, path: Union[str, Path, Callable[[GenerationContext, Config], Path]]
21
+ self, path: Union[str, Path, Callable[[ConfigWalkContext, Config], Path]]
21
22
  ):
22
23
  self.path = path
23
24
 
24
- def __call__(self, context: GenerationContext, config: Config):
25
+ def __call__(self, context: ConfigWalkContext, config: Config):
25
26
  if inspect.isfunction(self.path):
26
27
  path = context.currentpath() / self.path(context, config) # type: Path
27
28
  else:
@@ -34,7 +35,7 @@ class PathGenerator(Generator):
34
35
 
35
36
 
36
37
  class pathgenerator(TypeAnnotation):
37
- def __init__(self, value: Union[str, Callable[[GenerationContext, Config], str]]):
38
+ def __init__(self, value: Union[str, Callable[[ConfigWalkContext, Config], str]]):
38
39
  self.value = value
39
40
 
40
41
  def annotate(self, options: ArgumentOptions):
@@ -1,25 +1,36 @@
1
1
  from pathlib import Path, PosixPath
2
- from typing import Callable, Dict, List, Optional, Protocol
2
+ from typing import Callable, Dict, List, Optional
3
3
  from experimaestro.commandline import AbstractCommand, Job, CommandLineJob
4
4
  from experimaestro.connectors import Connector
5
5
  from experimaestro.connectors.local import ProcessBuilder, LocalConnector
6
6
  from experimaestro.connectors.ssh import SshPath, SshConnector
7
+ from abc import ABC, abstractmethod
7
8
 
8
9
 
9
- class ScriptBuilder:
10
- lockfiles: List[Path]
11
- command: "AbstractCommand"
10
+ class ScriptBuilder(ABC):
12
11
  """A script builder is responsible for generating the script
13
12
  used to launch a command line job"""
14
13
 
14
+ lockfiles: List[Path]
15
+ """The files that must be locked before starting the job"""
16
+
17
+ command: "AbstractCommand"
18
+ """Command to be run"""
19
+
20
+ @abstractmethod
15
21
  def write(self, job: CommandLineJob) -> Path:
16
- raise NotImplementedError()
22
+ """Write the commmand line job
23
+
24
+ :params job: The job to be written
25
+ """
26
+ ...
17
27
 
18
28
 
19
29
  SubmitListener = Callable[[Job], None]
30
+ """Listen to job submissions"""
20
31
 
21
32
 
22
- class Launcher:
33
+ class Launcher(ABC):
23
34
  """A launcher"""
24
35
 
25
36
  submit_listeners: List[SubmitListener]
@@ -36,9 +47,10 @@ class Launcher:
36
47
  def setNotificationURL(self, url: Optional[str]):
37
48
  self.notificationURL = url
38
49
 
50
+ @abstractmethod
39
51
  def scriptbuilder(self) -> ScriptBuilder:
40
52
  """Returns a script builder"""
41
- raise NotImplementedError(f"For class {self.__class__}")
53
+ ...
42
54
 
43
55
  def addListener(self, listener: SubmitListener):
44
56
  self.submit_listeners.append(listener)
@@ -1,4 +1,4 @@
1
- from collections import defaultdict
1
+ from collections import ChainMap, defaultdict
2
2
  import os
3
3
  from pathlib import Path
4
4
  from shutil import rmtree
@@ -14,7 +14,7 @@ from experimaestro.scheduler.services import Service
14
14
  from experimaestro.settings import get_settings
15
15
 
16
16
 
17
- from experimaestro.core.objects import Config, GenerationContext
17
+ from experimaestro.core.objects import Config, ConfigWalkContext
18
18
  from experimaestro.utils import logger
19
19
  from experimaestro.locking import Locks, LockError, Lock
20
20
  from experimaestro.tokens import ProcessCounterToken
@@ -151,6 +151,23 @@ class Job(Resource):
151
151
  assert self._future, "Cannot wait a not submitted job"
152
152
  return self._future.result()
153
153
 
154
+ @property
155
+ def environ(self):
156
+ """Returns the job environment
157
+
158
+ It is made of (by order of priority):
159
+
160
+ 1. The job environment
161
+ 1. The launcher environment
162
+ 1. The workspace environment
163
+
164
+ """
165
+ return ChainMap(
166
+ {},
167
+ self.launcher.environ if self.launcher else {},
168
+ self.workspace.environment.environ,
169
+ )
170
+
154
171
  @property
155
172
  def progress(self):
156
173
  return self._progress
@@ -292,7 +309,7 @@ class Job(Resource):
292
309
  return self._future
293
310
 
294
311
 
295
- class JobContext(GenerationContext):
312
+ class JobContext(ConfigWalkContext):
296
313
  def __init__(self, job: Job):
297
314
  super().__init__()
298
315
  self.job = job
@@ -839,6 +856,7 @@ class experiment:
839
856
  def __enter__(self):
840
857
  logger.info("Locking experiment %s", self.xplockpath)
841
858
  self.xplock = self.workspace.connector.lock(self.xplockpath, 0).__enter__()
859
+ logger.info("Experiment locked")
842
860
 
843
861
  # Move old jobs into "jobs.bak"
844
862
  if self.workspace.run_mode == RunMode.NORMAL:
@@ -90,7 +90,7 @@ class Listener(BaseListener, ServiceListener):
90
90
  )
91
91
 
92
92
  def service_state_changed(self, service: Service):
93
- self.socketio.emit("service.update", {"state": service.state})
93
+ self.socketio.emit("service.update", {"state": service.state.name})
94
94
 
95
95
 
96
96
  MIMETYPES = {
@@ -143,10 +143,15 @@ def proxy_response(base_url: str, request: Request, path: str):
143
143
 
144
144
 
145
145
  def start_app(server: "Server"):
146
+ logging.debug("Starting Flask server...")
146
147
  app = Flask("experimaestro")
147
- socketio = SocketIO(app, path="/api", async_mode="eventlet")
148
+
149
+ logging.debug("Starting Flask server (SocketIO)...")
150
+ socketio = SocketIO(app, path="/api", async_mode="gevent")
148
151
  listener = Listener(server.scheduler, socketio)
149
152
 
153
+ logging.debug("Starting Flask server (setting up socketio)...")
154
+
150
155
  @socketio.on("connect")
151
156
  def handle_connect():
152
157
  if server.token != request.cookies.get("experimaestro_token", None):
@@ -183,6 +188,8 @@ def start_app(server: "Server"):
183
188
  if process is not None:
184
189
  process.kill()
185
190
 
191
+ logging.debug("Starting Flask server (setting up routes)...")
192
+
186
193
  @app.route("/services/<path:path>", methods=["GET", "POST"])
187
194
  def route_service(path):
188
195
  service, *path = path.split("/", 1)
@@ -256,13 +263,14 @@ def start_app(server: "Server"):
256
263
 
257
264
  # Start the app
258
265
  if server.port is None or server.port == 0:
266
+ logging.info("Searching for an available port")
259
267
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
260
- sock.bind(("localhost", 0))
268
+ sock.bind(("", 0))
261
269
  server.port = sock.getsockname()[1]
262
270
  sock.close()
263
271
 
264
272
  logging.info(
265
- "Web server started on http://%s:%d?token=%s",
273
+ "Web server started on http://%s:%d/auth?xpm-token=%s",
266
274
  server.host,
267
275
  server.port,
268
276
  server.token,
@@ -27,6 +27,18 @@ def cleanupdir(path: Path):
27
27
  return path
28
28
 
29
29
 
30
+ def is_notebook():
31
+ """Returns true if running in a notebook"""
32
+ try:
33
+ shell = get_ipython().__class__.__module__ # noqa: F841
34
+ if shell is not None and shell in ["ipykernel.zmqshell", "google.colab._shell"]:
35
+ return True
36
+ except NameError:
37
+ pass
38
+
39
+ return False
40
+
41
+
30
42
  class ThreadingCondition(threading.Condition):
31
43
  # Useful to debug lock problems
32
44
  TIMEOUT = float(os.environ.get("XPM_LOCK_TIMEOUT", "-1"))
@@ -21,6 +21,7 @@ def jobmonitor(*outputs: TaskOutput):
21
21
 
22
22
  for output in outputs:
23
23
  try:
24
+ job = None
24
25
  job = output.__xpm__.job
25
26
  lastprogress = 0
26
27
  while job.scheduler is None:
@@ -34,7 +35,7 @@ def jobmonitor(*outputs: TaskOutput):
34
35
 
35
36
  # Job already completed
36
37
  if job.state.value == JobState.DONE.value:
37
- print("Job already completed")
38
+ print("Job already completed") # noqa: T201
38
39
  else:
39
40
  with tqdm(total=100, unit_scale=True, unit="%") as reporter:
40
41
  progress = 0
@@ -60,8 +61,10 @@ def jobmonitor(*outputs: TaskOutput):
60
61
  reporter.update(100 - progress)
61
62
  else:
62
63
  raise RuntimeError(
63
- f"Job did not complete successfully ({job.state.name}). Check the error log {job.stderr}"
64
+ f"Job did not complete successfully ({job.state.name})."
65
+ f"Check the error log {job.stderr}"
64
66
  )
65
67
 
66
68
  finally:
67
- job.scheduler.removelistener(listener)
69
+ if job is not None:
70
+ job.scheduler.removelistener(listener)
@@ -1,4 +1,5 @@
1
1
  from typing import Callable, Dict, Optional
2
+ import uuid
2
3
  import ipywidgets as widgets
3
4
  from experimaestro import experiment
4
5
  from IPython.display import display
@@ -6,6 +7,8 @@ from .jobs import jobmonitor # noqa: F401
6
7
 
7
8
 
8
9
  class serverwidget:
10
+ TOKEN = uuid.uuid4().hex
11
+
9
12
  def __init__(
10
13
  self,
11
14
  name,
@@ -32,10 +35,13 @@ class serverwidget:
32
35
  with self.output:
33
36
  if experiment.CURRENT:
34
37
  self.button.description = "Stop experimaestro server"
35
- print(f"Server started : http://localhost:{self.port}")
38
+ print( # noqa: T201
39
+ "Server started : "
40
+ f"http://localhost:{self.port}/auth?xpm-token={serverwidget.TOKEN}"
41
+ )
36
42
  else:
37
43
  self.button.description = "Start experimaestro server"
38
- print("Server stopped")
44
+ print("Server stopped") # noqa: T201
39
45
 
40
46
  def on_button_clicked(self, b):
41
47
  with self.output:
@@ -43,11 +49,15 @@ class serverwidget:
43
49
  try:
44
50
  experiment.CURRENT.__exit__(None, None, None)
45
51
  except Exception:
46
- print("Error while stopping experimaestro")
52
+ print("Error while stopping experimaestro") # noqa: T201
47
53
  self.current = experiment.CURRENT
48
54
  else:
49
55
  self.current = experiment(
50
- self.name, self.name, host="localhost", port=self.port
56
+ self.name,
57
+ self.name,
58
+ host="localhost",
59
+ port=self.port,
60
+ token=serverwidget.TOKEN,
51
61
  ).__enter__()
52
62
  for key, value in self.environment.items():
53
63
  self.current.setenv(key, value)
@@ -1,4 +1,4 @@
1
1
  # file generated by setuptools_scm
2
2
  # don't change, don't track in version control
3
- __version__ = version = '0.21.0'
4
- __version_tuple__ = version_tuple = (0, 21, 0)
3
+ __version__ = version = '0.23.0'
4
+ __version_tuple__ = version_tuple = (0, 23, 0)
@@ -1,10 +1,10 @@
1
1
  """Utilities exposed to users of the experimaestro API"""
2
2
 
3
3
  from pathlib import Path
4
- from experimaestro.core.objects import GenerationContext
4
+ from experimaestro.core.objects import ConfigWalkContext
5
5
 
6
6
 
7
- class DirectoryContext(GenerationContext):
7
+ class DirectoryContext(ConfigWalkContext):
8
8
  """Special generation context used for debugging and testing"""
9
9
 
10
10
  def __init__(self, path: Path):
@@ -16,7 +16,7 @@ class DirectoryContext(GenerationContext):
16
16
  return self._path
17
17
 
18
18
 
19
- class EmptyContext(GenerationContext):
19
+ class EmptyContext(ConfigWalkContext):
20
20
  """Special generation context used for debugging and testing"""
21
21
 
22
22
  @property
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: experimaestro
3
- Version: 0.21.0
3
+ Version: 0.23.0
4
4
  Summary: "Experimaestro is a computer science experiment manager"
5
5
  Home-page: https://github.com/experimaestro/experimaestro-python
6
6
  Author: Benjamin Piwowarski
@@ -127,6 +127,23 @@ if __name__ == "__main__":
127
127
 
128
128
  which can be launched with `python test.py /tmp/helloworld-workdir`
129
129
 
130
+ ## 0.23.0 (2023-04-07)
131
+
132
+ ### Feat
133
+
134
+ - submit hooks to allow e.g. changing the environment variables
135
+
136
+ ## 0.22.0 (2023-04-05)
137
+
138
+ ### Feat
139
+
140
+ - tags as immutable and hashable dicts
141
+
142
+ ### Fix
143
+
144
+ - corrected service status update for servers
145
+ - improved server
146
+
130
147
  ## 0.21.0 (2023-03-28)
131
148
 
132
149
  ### Feat
@@ -8,10 +8,11 @@ tqdm
8
8
  docstring_parser
9
9
  termcolor>=2.0.0
10
10
  requests
11
+ sortedcontainers
11
12
  pyparsing
12
13
  humanfriendly
13
14
  huggingface_hub~=0.11.1
14
- eventlet
15
+ gevent
15
16
  flask
16
17
  flask-socketio
17
18
  Arpeggio>=2.0
@@ -20,8 +21,10 @@ marshmallow
20
21
  fabric
21
22
  rpyc
22
23
 
24
+ [:python_version < "3.11"]
25
+ typing_extensions>=4.2
26
+
23
27
  [:python_version < "3.9"]
24
- typing_extensions>=3.7.4.3
25
28
  cached_property
26
29
 
27
30
  [dev]
File without changes
File without changes
File without changes
File without changes