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,3 +1,20 @@
1
+ ## 0.23.0 (2023-04-07)
2
+
3
+ ### Feat
4
+
5
+ - submit hooks to allow e.g. changing the environment variables
6
+
7
+ ## 0.22.0 (2023-04-05)
8
+
9
+ ### Feat
10
+
11
+ - tags as immutable and hashable dicts
12
+
13
+ ### Fix
14
+
15
+ - corrected service status update for servers
16
+ - improved server
17
+
1
18
  ## 0.21.0 (2023-03-28)
2
19
 
3
20
  ### Feat
@@ -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
@@ -17,7 +17,7 @@ const Services = () => {
17
17
  }
18
18
  return <NavDropdown title="Services" id="basic-nav-dropdown">{
19
19
  services.ids.map(id =>
20
- <NavDropdown.Item key={id} href={`/services/${id}`}>
20
+ <NavDropdown.Item key={id} href={`/services/${id}`} target='_blank'>
21
21
  <code>{id}</code> {services.byId[id].description}{" "}
22
22
  {STATE_COMPONENTS[services.byId[id].state] ?? services.byId[id].state}
23
23
  </NavDropdown.Item>
@@ -10,13 +10,13 @@ the config/task instance, as in the example below:
10
10
 
11
11
  !!! example
12
12
 
13
- ````py3 linenums="1"
13
+ ```py3 linenums="1"
14
14
 
15
- model = Model1(layers=3)
16
- learnedmodel = Learn(epochs=100)
17
- learnedmodel.model = model
18
- learnedmodel.submit()
19
- ```
15
+ model = Model1(layers=3)
16
+ learnedmodel = Learn(epochs=100)
17
+ learnedmodel.model = model
18
+ learnedmodel.submit()
19
+ ```
20
20
 
21
21
  - line 1: the `Model1` configuration is set with argument `layers` set to `3`.
22
22
  - line 2: the `Learn` task is configured with parameter `epochs` set to 100
@@ -34,7 +34,8 @@ features. More precisely, it
34
34
  importantly, it defines experiments imperatively and not declaratively.
35
35
 
36
36
  !!! note
37
- Experimaestro and datamaestro are described in the following paper
37
+
38
+ Experimaestro and datamaestro are described in the following paper
38
39
 
39
40
  Benjamin Piwowarski. 2020.
40
41
  [Experimaestro and Datamaestro: Experiment and Dataset Managers (for IR).](https://doi.org/10.1145/3397271.3401410)
@@ -4,7 +4,7 @@ fallback_version = "0.0.0-dev"
4
4
 
5
5
  [tool.commitizen]
6
6
  name = "cz_conventional_commits"
7
- version = "0.21.0"
7
+ version = "0.23.0"
8
8
  changelog_start_rev = "0.15.0"
9
9
  tag_format = "$version"
10
10
  update_changelog_on_bump = true
@@ -2,8 +2,8 @@
2
2
  click
3
3
  omegaconf
4
4
 
5
- # Supports Annotated[T, ...]
6
- typing_extensions >= 3.7.4.3; python_version < "3.9"
5
+ # Supports recent typing
6
+ typing_extensions >= 4.2; python_version < "3.11"
7
7
  cached_property; python_version < "3.9"
8
8
 
9
9
  # Other
@@ -15,13 +15,14 @@ tqdm
15
15
  docstring_parser
16
16
  termcolor >= 2.0.0
17
17
  requests
18
+ sortedcontainers
18
19
  pyparsing
19
20
  # Parse size
20
21
  humanfriendly
21
22
  huggingface_hub ~= 0.11.1
22
23
 
23
24
  # server
24
- eventlet
25
+ gevent
25
26
  flask
26
27
  flask-socketio
27
28
 
@@ -70,7 +70,7 @@ ignore = D200, D203, D213, D406, D407 # Google conventions
70
70
 
71
71
  [flake8]
72
72
  doctests = True
73
- exclude = .git, .eggs, __pycache__, tests/, docs/, build/, dist/
73
+ exclude = .git, .eggs, __pycache__, tests/, docs/, build/, dist/, app/
74
74
  max-line-length = 88
75
75
  extend-ignore = E203
76
76
 
@@ -15,6 +15,7 @@ from .annotations import (
15
15
  cache,
16
16
  Identifier,
17
17
  Array,
18
+ TagDict,
18
19
  tag,
19
20
  tags,
20
21
  tagspath,
@@ -48,17 +49,19 @@ from .core.objects import (
48
49
  SerializedConfig,
49
50
  Serialized,
50
51
  )
52
+ from .core.types import Any, SubmitHook, submit_hook_decorator
53
+ from .launchers import Launcher
51
54
  from .scheduler.environment import Environment
52
55
  from .scheduler.workspace import Workspace, RunMode
53
56
  from .scheduler import Scheduler, experiment, FailedExperiment
54
57
  from .notifications import progress, tqdm
55
- from .core.types import Any
56
58
  from .checkers import Choices
57
59
  from .xpmutils import DirectoryContext
58
60
  from .mkdocs.annotations import documentation
61
+ from .scheduler.base import Job
59
62
 
60
63
 
61
- def set_launcher(launcher):
64
+ def set_launcher(launcher: Launcher):
62
65
  Workspace.CURRENT.launcher = launcher
63
66
 
64
67
 
@@ -125,7 +125,7 @@ def diff(path: Path):
125
125
  """Show the reason of the identifier change for a job"""
126
126
  from experimaestro.tools.jobs import load_job
127
127
  from experimaestro import Config
128
- from experimaestro.core.objects import GenerationContext
128
+ from experimaestro.core.objects import ConfigWalkContext
129
129
 
130
130
  _, job = load_job(path / "params.json", discard_id=False)
131
131
  _, new_job = load_job(path / "params.json")
@@ -1,11 +1,9 @@
1
1
  # Import Python modules
2
2
 
3
- import sys
4
3
  import inspect
5
- import logging
6
4
  from pathlib import Path
7
5
  from typing import Callable, Type as TypingType, Optional, TypeVar, Union
8
-
6
+ from sortedcontainers import SortedDict
9
7
  import experimaestro.core.objects as objects
10
8
  import experimaestro.core.types as types
11
9
  from experimaestro.generators import PathGenerator
@@ -33,12 +31,18 @@ class config:
33
31
  """[summary]
34
32
 
35
33
  Keyword Arguments:
36
- identifier {Identifier, str} -- Unique identifier of the type, generate by default (None)
37
- description {str} -- (deprecated, use comments) Description of the config/task, use comments with (default) None
38
- register {bool} -- False if the type should not be registered (debug only)
34
+ identifier {Identifier, str} -- Unique identifier of the type,
35
+ generate by default (None)
36
+
37
+ description {str} -- (deprecated, use
38
+ comments) Description of the config/task, use comments with
39
+ (default) None
40
+
41
+ register {bool} -- False if the type should not be
42
+ registered (debug only)
39
43
 
40
- The identifier, if not specified, will be set to `X.CLASSNAME`(by order of priority),
41
- where X is:
44
+ The identifier, if not specified, will be set to `X.CLASSNAME`(by order
45
+ of priority), where X is:
42
46
  - the parent identifier
43
47
  - the module qualified name
44
48
  """
@@ -207,8 +211,12 @@ class pathoption(param):
207
211
  self.generator = PathGenerator(path)
208
212
 
209
213
 
210
- STDERR = lambda jobcontext, config: "%s.err" % jobcontext.name
211
- STDOUT = lambda jobcontext, config: "%s.out" % jobcontext.name
214
+ def STDERR(jobcontext, config):
215
+ return "%s.err" % jobcontext.name
216
+
217
+
218
+ def STDOUT(jobcontext, config):
219
+ return "%s.out" % jobcontext.name
212
220
 
213
221
 
214
222
  class constant(param):
@@ -229,7 +237,6 @@ def cache(name: str):
229
237
  """Use a cache path for a given config"""
230
238
 
231
239
  def annotate(method):
232
-
233
240
  return objects.cache(method, name)
234
241
 
235
242
  return annotate
@@ -243,9 +250,19 @@ def tag(value):
243
250
  return objects.TaggedValue(value)
244
251
 
245
252
 
246
- def tags(value):
253
+ class TagDict(SortedDict):
254
+ """A hashable dictionary"""
255
+
256
+ def __hash__(self):
257
+ return hash(tuple((key, value) for key, value in self.items()))
258
+
259
+ def __setitem__(self, key, value):
260
+ raise Exception("A tag dictionary is not mutable")
261
+
262
+
263
+ def tags(value) -> TagDict:
247
264
  """Return the tags associated with a value"""
248
- return value.__xpm__.tags()
265
+ return TagDict(value.__xpm__.tags())
249
266
 
250
267
 
251
268
  def _normalizepathcomponent(v: Any):
@@ -256,10 +273,9 @@ def _normalizepathcomponent(v: Any):
256
273
 
257
274
  def tagspath(value: Config):
258
275
  """Return a unique path made of tags and their values"""
259
- sortedtags = sorted(value.__xpm__.tags().items(), key=lambda x: x[0])
260
276
  return "_".join(
261
277
  f"""{_normalizepathcomponent(key)}={_normalizepathcomponent(value)}"""
262
- for key, value in sortedtags
278
+ for key, value in tags(value).items()
263
279
  )
264
280
 
265
281
 
@@ -1,6 +1,5 @@
1
1
  """Command line jobs"""
2
2
 
3
- from collections import ChainMap
4
3
  import json
5
4
  import io
6
5
  from pathlib import Path
@@ -260,13 +259,6 @@ class CommandLineJob(Job):
260
259
 
261
260
  return None
262
261
 
263
- @property
264
- def environ(self):
265
- return ChainMap(
266
- self.workspace.environment.environ,
267
- self.launcher.environ if self.launcher else {},
268
- )
269
-
270
262
  @property
271
263
  def notificationURL(self):
272
264
  if self.launcher and self.launcher.notificationURL:
@@ -20,6 +20,7 @@ from typing import (
20
20
  List,
21
21
  Optional,
22
22
  Set,
23
+ Tuple,
23
24
  Type,
24
25
  TypeVar,
25
26
  Union,
@@ -35,6 +36,7 @@ from experimaestro.core.types import DeprecatedAttribute, ObjectType
35
36
  from .context import SerializationContext, SerializedPath, SerializedPathLoader
36
37
 
37
38
  if TYPE_CHECKING:
39
+ from experimaestro.scheduler.base import Job
38
40
  from experimaestro.scheduler.workspace import RunMode
39
41
  from experimaestro.launchers import Launcher
40
42
  from experimaestro.scheduler import Workspace
@@ -307,7 +309,7 @@ def add_to_path(p):
307
309
  sys.path = old_path
308
310
 
309
311
 
310
- class GenerationContext:
312
+ class ConfigWalkContext:
311
313
  """Context when generating values in configurations"""
312
314
 
313
315
  @property
@@ -342,33 +344,38 @@ class GenerationContext:
342
344
  NOT_SET = object()
343
345
 
344
346
 
345
- class ConfigProcessing:
347
+ class ConfigWalk:
346
348
  """Allows to perform an operation on all nested configurations"""
347
349
 
348
- def __init__(self, recurse_task=False):
350
+ def __init__(self, context: ConfigWalkContext = None, recurse_task=False):
349
351
  """
350
352
 
351
- Parameters:
352
- recurse_task: Recurse into linked tasks
353
+ :param recurse_task: Recurse into linked tasks
354
+ :param context: The context, by default only tracks the position in the
355
+ config tree
353
356
  """
354
357
  self.recurse_task = recurse_task
358
+ self.context = ConfigWalkContext() if context is None else context
355
359
 
356
360
  # Stores already visited nodes
357
361
  self.visited = {}
358
362
 
359
- def preprocess(self, config: "Config"):
363
+ def preprocess(self, config: "Config") -> Tuple[bool, Any]:
364
+ """Returns a tuple boolean/value
365
+
366
+ The boolean value is used to stop the processing if False.
367
+ The value is returned
368
+ """
360
369
  return True, None
361
370
 
362
371
  def postprocess(self, config: "Config", values: Dict[str, Any]):
363
372
  return config
364
373
 
365
- @contextmanager
366
374
  def list(self, i: int):
367
- yield i
375
+ return self.context.push(str(i))
368
376
 
369
- @contextmanager
370
377
  def map(self, k: str):
371
- yield k
378
+ return self.context.push(k)
372
379
 
373
380
  def __call__(self, x):
374
381
  if isinstance(x, Config):
@@ -426,18 +433,6 @@ class ConfigProcessing:
426
433
  raise NotImplementedError(f"Cannot handle a value of type {type(x)}")
427
434
 
428
435
 
429
- class GenerationConfigProcessing(ConfigProcessing):
430
- def __init__(self, context: GenerationContext, recurse_task=False):
431
- super().__init__(recurse_task=recurse_task)
432
- self.context = context
433
-
434
- def list(self, i: int):
435
- return self.context.push(str(i))
436
-
437
- def map(self, k: str):
438
- return self.context.push(k)
439
-
440
-
441
436
  def getqualattr(module, qualname):
442
437
  """Get a qualified attributed value"""
443
438
  cls = module
@@ -464,6 +459,7 @@ class ConfigInformation:
464
459
  # Meta-informations
465
460
  self._tags = {}
466
461
  self._initinfo = ""
462
+ self.submit_hooks = set()
467
463
 
468
464
  # Generated task
469
465
  self._taskoutput = None
@@ -534,7 +530,7 @@ class ConfigInformation:
534
530
  yield argument, self.values[argument.name]
535
531
 
536
532
  def tags(self):
537
- class TagFinder(ConfigProcessing):
533
+ class TagFinder(ConfigWalk):
538
534
  def __init__(self):
539
535
  super().__init__(recurse_task=True)
540
536
  self.tags = {}
@@ -578,7 +574,7 @@ class ConfigInformation:
578
574
  )
579
575
  raise
580
576
 
581
- def seal(self, context: GenerationContext):
577
+ def seal(self, context: ConfigWalkContext):
582
578
  """Seal the object, generating values when needed,
583
579
  before scheduling the associated job(s)
584
580
 
@@ -586,7 +582,7 @@ class ConfigInformation:
586
582
  - context: the generation context
587
583
  """
588
584
 
589
- class Sealer(GenerationConfigProcessing):
585
+ class Sealer(ConfigWalk):
590
586
  def preprocess(self, config: Config):
591
587
  return not config.__xpm__._sealed, config
592
588
 
@@ -607,9 +603,9 @@ class ConfigInformation:
607
603
 
608
604
  Internal API - do not use
609
605
  """
610
- context = GenerationContext()
606
+ context = ConfigWalkContext()
611
607
 
612
- class Unsealer(GenerationConfigProcessing):
608
+ class Unsealer(ConfigWalk):
613
609
  def preprocess(self, config: Config):
614
610
  return config.__xpm__._sealed, config
615
611
 
@@ -658,6 +654,23 @@ class ConfigInformation:
658
654
  logger.error("While setting %s", path + [argument.name])
659
655
  raise
660
656
 
657
+ def apply_submit_hooks(self, job: "Job"):
658
+ """Apply configuration hooks"""
659
+ context = ConfigWalkContext()
660
+
661
+ class HookGatherer(ConfigWalk):
662
+ def __init__(self, *args, **kwargs):
663
+ super().__init__(*args, **kwargs)
664
+ self.hooks = set()
665
+
666
+ def postprocess(self, config: "Config", values: Dict[str, Any]):
667
+ self.hooks.update(config.__xpm__.submit_hooks)
668
+
669
+ gatherer = HookGatherer(context, recurse_task=False)
670
+ gatherer(self.pyobject)
671
+ for hook in gatherer.hooks:
672
+ hook(job)
673
+
661
674
  def submit(
662
675
  self, workspace: "Workspace", launcher: "Launcher", run_mode=None
663
676
  ) -> "TaskOutput":
@@ -696,7 +709,7 @@ class ConfigInformation:
696
709
  experiment.CURRENT.workspace if experiment.CURRENT else None
697
710
  )
698
711
 
699
- # Call onSubmit
712
+ # Call onSubmit hooks
700
713
  launcher = (
701
714
  launcher
702
715
  or (workspace and workspace.launcher)
@@ -705,6 +718,9 @@ class ConfigInformation:
705
718
  if launcher:
706
719
  launcher.onSubmit(self.job)
707
720
 
721
+ # Apply submit hooks
722
+ self.apply_submit_hooks(self.job)
723
+
708
724
  # Add job dependencies
709
725
  self.updatedependencies(self.job.dependencies, [], set([id(self.pyobject)]))
710
726
 
@@ -1194,8 +1210,8 @@ class ConfigInformation:
1194
1210
 
1195
1211
  return o
1196
1212
 
1197
- class FromPython(GenerationConfigProcessing):
1198
- def __init__(self, context: GenerationContext):
1213
+ class FromPython(ConfigWalk):
1214
+ def __init__(self, context: ConfigWalkContext):
1199
1215
  super().__init__(context)
1200
1216
  self.objects = {}
1201
1217
 
@@ -1233,7 +1249,7 @@ class ConfigInformation:
1233
1249
 
1234
1250
  return o
1235
1251
 
1236
- def fromConfig(self, context: GenerationContext):
1252
+ def fromConfig(self, context: ConfigWalkContext):
1237
1253
  """Generate an instance given the current configuration"""
1238
1254
  self.validate()
1239
1255
  processor = ConfigInformation.FromPython(context)
@@ -1378,7 +1394,7 @@ class TypeConfig:
1378
1394
  self.__xpm__.add_dependencies(*dependencies)
1379
1395
  return self
1380
1396
 
1381
- def instance(self, context: GenerationContext = None) -> T:
1397
+ def instance(self, context: ConfigWalkContext = None) -> T:
1382
1398
  """Return an instance with the current values"""
1383
1399
  if context is None:
1384
1400
  from experimaestro.xpmutils import EmptyContext
@@ -1386,8 +1402,8 @@ class TypeConfig:
1386
1402
  context = EmptyContext()
1387
1403
  else:
1388
1404
  assert isinstance(
1389
- context, GenerationContext
1390
- ), f"{context.__class__} is not an instance of GenerationContext"
1405
+ context, ConfigWalkContext
1406
+ ), f"{context.__class__} is not an instance of ConfigWalkContext"
1391
1407
  return self.__xpm__.fromConfig(context) # type: ignore
1392
1408
 
1393
1409
  def submit(self, *, workspace=None, launcher=None, run_mode: "RunMode" = None):
@@ -1434,7 +1450,7 @@ class Config:
1434
1450
  configuration/task"""
1435
1451
 
1436
1452
  @classmethod
1437
- def __getxpmtype__(cls):
1453
+ def __getxpmtype__(cls) -> "ObjectType":
1438
1454
  """Get (and create if necessary) the Object type of this"""
1439
1455
  xpmtype = cls.__dict__.get("__xpmtype__", None)
1440
1456
  if xpmtype is None:
@@ -1,8 +1,10 @@
1
+ from abc import ABC
1
2
  import typing_extensions
2
3
 
3
4
  from experimaestro.core.types import ObjectType
4
5
  import experimaestro
5
6
  import io
7
+ from experimaestro.launchers import Launcher
6
8
  from experimaestro.scheduler.base import Job
7
9
 
8
10
  from experimaestro.scheduler.workspace import RunMode
@@ -20,7 +22,18 @@ from experimaestro.core.types import (
20
22
  from experimaestro.utils import logger as logger
21
23
  from functools import cached_property as cached_property
22
24
  from pathlib import Path
23
- from typing import Any, ClassVar, Dict, List, Optional, Set, TypeVar, Union, overload
25
+ from typing import (
26
+ Any,
27
+ Callable,
28
+ ClassVar,
29
+ Dict,
30
+ List,
31
+ Optional,
32
+ Set,
33
+ TypeVar,
34
+ Union,
35
+ overload,
36
+ )
24
37
 
25
38
  T = TypeVar("T", bound="Config")
26
39
 
@@ -62,7 +75,7 @@ class TaggedValue:
62
75
 
63
76
  def add_to_path(p) -> Generator[None, None, None]: ...
64
77
 
65
- class GenerationContext:
78
+ class ConfigWalkContext:
66
79
  @property
67
80
  def path(self) -> None: ...
68
81
  def __init__(self) -> None: ...
@@ -83,9 +96,9 @@ class ConfigProcessing:
83
96
  def map(self, k: str): ...
84
97
  def __call__(self, x): ...
85
98
 
86
- class GenerationConfigProcessing(ConfigProcessing):
99
+ class ConfigWalk(ConfigProcessing):
87
100
  context: Incomplete
88
- def __init__(self, context: GenerationContext) -> None: ...
101
+ def __init__(self, context: ConfigWalkContext) -> None: ...
89
102
  def list(self, i: int): ...
90
103
  def map(self, k: str): ...
91
104
 
@@ -108,7 +121,7 @@ class ConfigInformation:
108
121
  def xpmvalues(self, generated: bool = ...) -> Generator[Incomplete, None, None]: ...
109
122
  def tags(self): ...
110
123
  def validate(self) -> None: ...
111
- def seal(self, context: GenerationContext): ...
124
+ def seal(self, context: ConfigWalkContext): ...
112
125
  @property
113
126
  def identifier(self) -> Identifier: ...
114
127
  def dependency(self): ...
@@ -141,13 +154,13 @@ class ConfigInformation:
141
154
  save_directory: Optional[Path] = ...,
142
155
  ) -> Config: ...
143
156
 
144
- class FromPython(GenerationConfigProcessing):
157
+ class FromPython(ConfigWalk):
145
158
  objects: Incomplete
146
- def __init__(self, context: GenerationContext) -> None: ...
159
+ def __init__(self, context: ConfigWalkContext) -> None: ...
147
160
  def preprocess(self, config: Config): ...
148
161
  def postprocess(self, config: Config, values: Dict[str, Any]): ...
149
162
 
150
- def fromConfig(self, context: GenerationContext): ...
163
+ def fromConfig(self, context: ConfigWalkContext): ...
151
164
  def add_dependencies(self, *dependencies) -> None: ...
152
165
 
153
166
  def clone(v): ...
@@ -162,7 +175,7 @@ class TypeConfig:
162
175
  def __arguments__(self): ...
163
176
  def tags(self): ...
164
177
  def add_dependencies(self, *dependencies): ...
165
- def instance(self, context: GenerationContext = ...) -> T: ...
178
+ def instance(self, context: ConfigWalkContext = ...) -> T: ...
166
179
  def submit(
167
180
  self,
168
181
  *,
@@ -183,7 +196,7 @@ class Config:
183
196
  __xpmtype__: ClassVar[ObjectType]
184
197
  __xpm__: ConfigInformation
185
198
  @classmethod
186
- def __getxpmtype__(cls): ...
199
+ def __getxpmtype__(cls) -> ObjectType: ...
187
200
  def __getnewargs_ex__(self): ...
188
201
  @classmethod
189
202
  def c(cls, **kwargs) -> T: ...