experimaestro 1.7.0rc3__tar.gz → 1.8.0rc0__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 (155) hide show
  1. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/PKG-INFO +1 -1
  2. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/pyproject.toml +5 -5
  3. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/__init__.py +2 -1
  4. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/core/context.py +3 -9
  5. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/core/objects.py +2 -2
  6. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/core/serialization.py +9 -6
  7. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/experiments/cli.py +44 -19
  8. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/scheduler/base.py +9 -0
  9. experimaestro-1.8.0rc0/src/experimaestro/scheduler/state.py +75 -0
  10. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/sphinx/__init__.py +2 -5
  11. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/launchers/bin/sbatch +1 -1
  12. experimaestro-1.8.0rc0/src/experimaestro/tests/test_experiment.py +50 -0
  13. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/typingutils.py +1 -8
  14. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/LICENSE +0 -0
  15. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/README.md +0 -0
  16. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/__main__.py +0 -0
  17. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/annotations.py +0 -0
  18. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/checkers.py +0 -0
  19. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/cli/__init__.py +0 -0
  20. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/cli/filter.py +0 -0
  21. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/cli/jobs.py +0 -0
  22. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/click.py +0 -0
  23. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/commandline.py +0 -0
  24. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/compat.py +0 -0
  25. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/connectors/__init__.py +0 -0
  26. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/connectors/local.py +0 -0
  27. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/connectors/ssh.py +0 -0
  28. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/core/__init__.py +0 -0
  29. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/core/arguments.py +0 -0
  30. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/core/objects.pyi +0 -0
  31. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/core/serializers.py +0 -0
  32. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/core/types.py +0 -0
  33. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/core/utils.py +0 -0
  34. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/exceptions.py +0 -0
  35. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/experiments/__init__.py +0 -0
  36. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/experiments/configuration.py +0 -0
  37. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/generators.py +0 -0
  38. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/huggingface.py +0 -0
  39. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/ipc.py +0 -0
  40. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/launcherfinder/__init__.py +0 -0
  41. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/launcherfinder/base.py +0 -0
  42. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/launcherfinder/parser.py +0 -0
  43. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/launcherfinder/registry.py +0 -0
  44. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/launcherfinder/specs.py +0 -0
  45. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/launchers/__init__.py +0 -0
  46. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/launchers/direct.py +0 -0
  47. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/launchers/oar.py +0 -0
  48. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/launchers/slurm/__init__.py +0 -0
  49. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/launchers/slurm/base.py +0 -0
  50. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/locking.py +0 -0
  51. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/mkdocs/__init__.py +0 -0
  52. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/mkdocs/annotations.py +0 -0
  53. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/mkdocs/base.py +0 -0
  54. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/mkdocs/metaloader.py +0 -0
  55. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/mkdocs/style.css +0 -0
  56. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/mypy.py +0 -0
  57. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/notifications.py +0 -0
  58. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/py.typed +0 -0
  59. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/rpyc.py +0 -0
  60. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/run.py +0 -0
  61. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/scheduler/__init__.py +0 -0
  62. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/scheduler/dependencies.py +0 -0
  63. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/scheduler/dynamic_outputs.py +0 -0
  64. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/scheduler/services.py +0 -0
  65. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/scheduler/workspace.py +0 -0
  66. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/scriptbuilder.py +0 -0
  67. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/__init__.py +0 -0
  68. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/016b4a6cdced82ab3aa1.ttf +0 -0
  69. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/0c35d18bf06992036b69.woff2 +0 -0
  70. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/1815e00441357e01619e.ttf +0 -0
  71. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/219aa9140e099e6c72ed.woff2 +0 -0
  72. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/2463b90d9a316e4e5294.woff2 +0 -0
  73. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/2582b0e4bcf85eceead0.ttf +0 -0
  74. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/3a4004a46a653d4b2166.woff +0 -0
  75. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/3baa5b8f3469222b822d.woff +0 -0
  76. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/4d73cb90e394b34b7670.woff +0 -0
  77. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/4ef4218c522f1eb6b5b1.woff2 +0 -0
  78. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/50701fbb8177c2dde530.ttf +0 -0
  79. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/5d681e2edae8c60630db.woff +0 -0
  80. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/6f420cf17cc0d7676fad.woff2 +0 -0
  81. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/878f31251d960bd6266f.woff2 +0 -0
  82. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/89999bdf5d835c012025.woff2 +0 -0
  83. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/914997e1bdfc990d0897.ttf +0 -0
  84. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/b041b1fa4fe241b23445.woff2 +0 -0
  85. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/b6879d41b0852f01ed5b.woff2 +0 -0
  86. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/c210719e60948b211a12.woff2 +0 -0
  87. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/c380809fd3677d7d6903.woff2 +0 -0
  88. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/d75e3fd1eb12e9bd6655.ttf +0 -0
  89. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/f882956fd323fd322f31.woff +0 -0
  90. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/favicon.ico +0 -0
  91. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/index.css +0 -0
  92. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/index.css.map +0 -0
  93. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/index.html +0 -0
  94. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/index.js +0 -0
  95. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/index.js.map +0 -0
  96. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/login.html +0 -0
  97. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/server/data/manifest.json +0 -0
  98. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/settings.py +0 -0
  99. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/sphinx/static/experimaestro.css +0 -0
  100. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/taskglobals.py +0 -0
  101. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/__init__.py +0 -0
  102. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/conftest.py +0 -0
  103. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/connectors/bin/executable.py +0 -0
  104. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/connectors/test_local.py +0 -0
  105. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/connectors/utils.py +0 -0
  106. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/definitions_types.py +0 -0
  107. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/launchers/__init__.py +0 -0
  108. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/launchers/bin/sacct +0 -0
  109. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/launchers/bin/srun +0 -0
  110. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/launchers/bin/test.py +0 -0
  111. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/launchers/common.py +0 -0
  112. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/launchers/config_slurm/__init__.py +0 -0
  113. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/launchers/config_slurm/launchers.py +0 -0
  114. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/launchers/test_local.py +0 -0
  115. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/launchers/test_slurm.py +0 -0
  116. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/restart.py +0 -0
  117. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/restart_main.py +0 -0
  118. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/scripts/notifyandwait.py +0 -0
  119. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/scripts/waitforfile.py +0 -0
  120. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/task_tokens.py +0 -0
  121. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/tasks/__init__.py +0 -0
  122. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/tasks/all.py +0 -0
  123. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/tasks/foreign.py +0 -0
  124. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/test_checkers.py +0 -0
  125. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/test_dependencies.py +0 -0
  126. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/test_findlauncher.py +0 -0
  127. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/test_forward.py +0 -0
  128. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/test_identifier.py +0 -0
  129. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/test_instance.py +0 -0
  130. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/test_objects.py +0 -0
  131. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/test_outputs.py +0 -0
  132. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/test_param.py +0 -0
  133. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/test_progress.py +0 -0
  134. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/test_serializers.py +0 -0
  135. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/test_snippets.py +0 -0
  136. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/test_ssh.py +0 -0
  137. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/test_tags.py +0 -0
  138. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/test_tasks.py +0 -0
  139. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/test_tokens.py +0 -0
  140. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/test_types.py +0 -0
  141. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/test_validation.py +0 -0
  142. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/token_reschedule.py +0 -0
  143. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tests/utils.py +0 -0
  144. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tokens.py +0 -0
  145. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tools/__init__.py +0 -0
  146. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tools/diff.py +0 -0
  147. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tools/documentation.py +0 -0
  148. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/tools/jobs.py +0 -0
  149. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/utils/__init__.py +0 -0
  150. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/utils/asyncio.py +0 -0
  151. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/utils/jobs.py +0 -0
  152. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/utils/jupyter.py +0 -0
  153. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/utils/resources.py +0 -0
  154. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/utils/settings.py +0 -0
  155. {experimaestro-1.7.0rc3 → experimaestro-1.8.0rc0}/src/experimaestro/xpmutils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: experimaestro
3
- Version: 1.7.0rc3
3
+ Version: 1.8.0rc0
4
4
  Summary: "Experimaestro is a computer science experiment manager"
5
5
  License: GPL-3
6
6
  Keywords: experiment manager
@@ -20,7 +20,7 @@ include = [
20
20
  "src/experimaestro/mkdocs/style.css",
21
21
  { path="src/experimaestro/server/data/*", format=['sdist', 'wheel']}
22
22
  ]
23
- version = "1.7.0-rc3"
23
+ version = "1.8.0-rc0"
24
24
  repository = "https://github.com/experimaestro/experimaestro-python"
25
25
  documentation = "https://experimaestro-python.readthedocs.io/"
26
26
 
@@ -122,7 +122,7 @@ warn_unused_ignores = true
122
122
 
123
123
  [tool.commitizen]
124
124
  name = "cz_conventional_commits"
125
- version = "1.7.0rc3"
126
- changelog_start_rev = "0.15.0"
127
- tag_format = "v$version"
128
- update_changelog_on_bump = true
125
+ version = "1.8.0rc0"
126
+ changelog_start_rev = "v1.0.0"
127
+ tag_format = "v$major.$minor.$patch$prerelease"
128
+ # update_changelog_on_bump = true
@@ -55,8 +55,9 @@ from .core.context import SerializationContext
55
55
  from .core.serializers import SerializationLWTask, PathSerializationLWTask
56
56
  from .core.types import Any, SubmitHook
57
57
  from .launchers import Launcher
58
- from .scheduler.workspace import Workspace, RunMode
59
58
  from .scheduler import Scheduler, experiment, FailedExperiment
59
+ from .scheduler.workspace import Workspace, RunMode
60
+ from .scheduler.state import get_experiment
60
61
  from .notifications import progress, tqdm
61
62
  from .checkers import Choices
62
63
  from .xpmutils import DirectoryContext
@@ -1,22 +1,16 @@
1
1
  from contextlib import contextmanager
2
- from pathlib import Path
2
+ from pathlib import Path, UnsupportedOperation
3
3
  import shutil
4
4
  from typing import List, Optional, Protocol, Set, Union
5
5
  import os
6
- import sys
7
-
8
- has_hardlink_to = sys.version_info.major == 3 and sys.version_info.minor >= 10
9
6
 
10
7
 
11
8
  def shallow_copy(src_path: Path, dest_path: Path):
12
9
  """Copy a directory or file, trying to use hard links if possible"""
13
10
  if src_path.is_file():
14
11
  try:
15
- if has_hardlink_to:
16
- dest_path.hardlink_to(src_path)
17
- else:
18
- dest_path.link_to(src_path)
19
- except OSError:
12
+ dest_path.hardlink_to(src_path)
13
+ except (NotImplementedError, UnsupportedOperation, OSError):
20
14
  shutil.copy(src_path, dest_path)
21
15
  else:
22
16
  if dest_path.exists():
@@ -1079,7 +1079,7 @@ class ConfigInformation:
1079
1079
  if value is None:
1080
1080
  return None
1081
1081
 
1082
- elif isinstance(value, list):
1082
+ elif isinstance(value, (list, tuple)):
1083
1083
  return [ConfigInformation._outputjsonvalue(el, context) for el in value]
1084
1084
 
1085
1085
  elif isinstance(value, dict):
@@ -1196,7 +1196,7 @@ class ConfigInformation:
1196
1196
  configurations if necessary"""
1197
1197
  if isinstance(value, Config):
1198
1198
  value.__xpm__.__get_objects__(objects, context)
1199
- elif isinstance(value, list):
1199
+ elif isinstance(value, (list, tuple)):
1200
1200
  for el in value:
1201
1201
  ConfigInformation.__collect_objects__(el, objects, context)
1202
1202
  elif isinstance(value, dict):
@@ -1,6 +1,6 @@
1
1
  import json
2
2
  from pathlib import Path
3
- from typing import Any, Dict, List, Tuple, Union, TYPE_CHECKING
3
+ from typing import Any, Dict, List, Optional, Tuple, Union, TYPE_CHECKING
4
4
  from experimaestro.core.context import (
5
5
  SerializationContext,
6
6
  SerializedPath,
@@ -41,17 +41,20 @@ def state_dict(context: SerializationContext, obj: Any):
41
41
  return {"objects": objects, "data": data}
42
42
 
43
43
 
44
- def save(obj: Any, save_directory: Path):
44
+ def save_definition(obj: Any, context: SerializationContext, path: Path):
45
+ data = state_dict(context, obj)
46
+ with path.open("wt") as out:
47
+ json.dump(data, out)
48
+
49
+
50
+ def save(obj: Any, save_directory: Optional[Path]):
45
51
  """Saves an object into a disk file
46
52
 
47
53
  :param save_directory: The directory in which the object and its data will
48
54
  be saved (by default, the object is saved in "definition.json")
49
55
  """
50
56
  context = SerializationContext(save_directory=save_directory)
51
-
52
- data = state_dict(context, obj)
53
- with (save_directory / "definition.json").open("wt") as out:
54
- json.dump(data, out)
57
+ save_definition(obj, context, save_directory / "definition.json")
55
58
 
56
59
 
57
60
  def get_data_loader(path: Union[str, Path, SerializedPathLoader]):
@@ -1,4 +1,3 @@
1
- import imp
2
1
  import importlib
3
2
  import inspect
4
3
  import json
@@ -60,6 +59,7 @@ class ConfigurationLoader:
60
59
  def __init__(self):
61
60
  self.yamls = []
62
61
  self.python_path = set()
62
+ self.yaml_module_file: None | Path = None
63
63
 
64
64
  def load(self, yaml_file: Path):
65
65
  """Loads a YAML file, and parents one if they exist"""
@@ -68,6 +68,16 @@ class ConfigurationLoader:
68
68
 
69
69
  with yaml_file.open("rt") as fp:
70
70
  _data = yaml.full_load(fp)
71
+
72
+ if "file" in _data:
73
+ path = Path(_data["file"])
74
+ if not path.is_absolute():
75
+ _data["file"] = str((yaml_file.parent / path).resolve())
76
+
77
+ if "module" in _data:
78
+ # Keeps track of the YAML file where the module was defined
79
+ self.yaml_module_file = yaml_file
80
+
71
81
  if parent := _data.get("parent", None):
72
82
  self.load(yaml_file.parent / parent)
73
83
 
@@ -116,7 +126,10 @@ class ConfigurationLoader:
116
126
  help="Port for monitoring (can be defined in the settings.yaml file)",
117
127
  )
118
128
  @click.option(
119
- "--file", "xp_file", help="The file containing the main experimental code"
129
+ "--file",
130
+ "xp_file",
131
+ type=Path,
132
+ help="The file containing the main experimental code",
120
133
  )
121
134
  @click.option(
122
135
  "--module-name", "module_name", help="Module containing the experimental code"
@@ -193,12 +206,10 @@ def experiments_cli( # noqa: C901
193
206
  ), "Module name and experiment file are mutually exclusive options"
194
207
  xp_file = Path(xp_file)
195
208
  if not python_path:
196
- python_path.append(xp_file.parent)
209
+ python_path.append(xp_file.parent.absolute())
197
210
  logging.info(
198
211
  "Using python path: %s", ", ".join(str(s) for s in python_path)
199
212
  )
200
- else:
201
- xp_file = Path(xp_file)
202
213
 
203
214
  assert (
204
215
  module_name or xp_file
@@ -216,18 +227,29 @@ def experiments_cli( # noqa: C901
216
227
  for path in python_path:
217
228
  sys.path.append(str(path))
218
229
 
230
+ # --- Adds automatically the experiment module if not found
231
+ if module_name and conf_loader.yaml_module_file:
232
+ try:
233
+ importlib.import_module(module_name)
234
+ except ModuleNotFoundError:
235
+ # Try to setup a path
236
+ path = conf_loader.yaml_module_file.resolve()
237
+ for _ in range(len(module_name.split("."))):
238
+ path = path.parent
239
+
240
+ logging.info("Appending %s to python path", path)
241
+ sys.path.append(str(path))
242
+
219
243
  if xp_file:
220
244
  if not xp_file.exists() and xp_file.suffix != ".py":
221
245
  xp_file = xp_file.with_suffix(".py")
222
246
  xp_file: Path = Path(yaml_file).parent / xp_file
223
- with open(xp_file) as src:
224
- module_name = xp_file.with_suffix("").name
225
- mod = imp.load_module(
226
- module_name,
227
- src,
228
- str(xp_file.absolute()),
229
- (".py", "r", imp.PY_SOURCE),
230
- )
247
+ module_name = xp_file.with_suffix("").name
248
+ spec = importlib.util.spec_from_file_location(
249
+ module_name, str(xp_file.absolute())
250
+ )
251
+ mod = importlib.util.module_from_spec(spec)
252
+ spec.loader.exec_module(mod)
231
253
  else:
232
254
  # Module
233
255
  try:
@@ -240,17 +262,20 @@ def experiments_cli( # noqa: C901
240
262
 
241
263
  # --- ... and runs it
242
264
  if helper is None:
243
- raise ValueError(f"Could not find run function in {xp_file}")
265
+ raise click.ClickException(
266
+ f"Could not find run function in {xp_file if xp_file else module_name}"
267
+ )
244
268
 
245
269
  if not isinstance(helper, ExperimentHelper):
246
270
  helper = ExperimentHelper(helper)
247
271
 
248
272
  parameters = inspect.signature(helper.callable).parameters
249
273
  list_parameters = list(parameters.values())
250
- assert len(list_parameters) == 2, (
251
- "Callable function should only "
252
- f"have two arguments (got {len(list_parameters)})"
253
- )
274
+ if len(list_parameters) != 2:
275
+ raise click.ClickException(
276
+ f"run in {xp_file if xp_file else module_name} function should only "
277
+ f"have two arguments (got {len(list_parameters)}), "
278
+ )
254
279
 
255
280
  schema = list_parameters[1].annotation
256
281
  omegaconf_schema = OmegaConf.structured(schema())
@@ -260,7 +285,7 @@ def experiments_cli( # noqa: C901
260
285
  configuration = OmegaConf.merge(omegaconf_schema, configuration)
261
286
  except omegaconf.errors.ConfigKeyError as e:
262
287
  cprint(f"Error in configuration:\n\n{e}", "red", file=sys.stderr)
263
- sys.exit(1)
288
+ raise click.ClickException("Error in configuration")
264
289
 
265
290
  if show:
266
291
  print(json.dumps(OmegaConf.to_container(configuration))) # noqa: T201
@@ -1057,6 +1057,15 @@ class experiment:
1057
1057
  logger.info("Stopping web server")
1058
1058
  self.server.stop()
1059
1059
 
1060
+ if self.workspace.run_mode == RunMode.NORMAL:
1061
+ # Write the state
1062
+ logging.info("Saving the experiment state")
1063
+ from experimaestro.scheduler.state import ExperimentState
1064
+
1065
+ ExperimentState.save(
1066
+ self.workdir / "state.json", self.scheduler.jobs.values()
1067
+ )
1068
+
1060
1069
  async def update_task_output_count(self, delta: int):
1061
1070
  """Change in the number of task outputs to process"""
1062
1071
  async with self.central.exitCondition:
@@ -0,0 +1,75 @@
1
+ from dataclasses import dataclass, field
2
+ import json
3
+ from pathlib import Path
4
+ from typing import Iterable, Optional, Type
5
+ from experimaestro import Task
6
+
7
+ from experimaestro.core.context import SerializationContext
8
+ from experimaestro.scheduler.base import Job, JobDependency
9
+ from experimaestro.settings import find_workspace
10
+ from experimaestro.core.serialization import from_state_dict, save_definition
11
+
12
+
13
+ @dataclass
14
+ class JobInformation:
15
+ id: str
16
+ path: Path
17
+ task: Task
18
+ tags: dict[str, str]
19
+ depends_on: list["JobInformation"] = field(default_factory=list)
20
+
21
+ def __post_init__(self):
22
+ self.path = Path(self.path)
23
+
24
+
25
+ class ExperimentState:
26
+ def __init__(self, workdir: Path, name: str):
27
+ path = workdir / "xp" / name / "state.json"
28
+ with path.open("rt") as fh:
29
+ content = json.load(fh)
30
+
31
+ self.states: dict[str, JobInformation] = {
32
+ state_dict["id"]: JobInformation(**state_dict)
33
+ for state_dict in from_state_dict(content, as_instance=False)
34
+ }
35
+
36
+ for state in self.states.values():
37
+ state.depends_on = [self.states[key] for key in state.depends_on]
38
+
39
+ def get_jobs(self, task_class: Type[Task]) -> list[JobInformation]:
40
+ if task_class is None:
41
+ return list(self.data.values())
42
+
43
+ tasks = []
44
+ for job_state in self.states.values():
45
+ if isinstance(job_state.task, task_class):
46
+ tasks.append(job_state)
47
+ return tasks
48
+
49
+ @staticmethod
50
+ def save(path: Path, jobs: Iterable[Job]):
51
+ save_definition(
52
+ [
53
+ {
54
+ "id": job.identifier,
55
+ "path": str(job.path),
56
+ "task": job.config,
57
+ "tags": job.config.__xpm__.tags(),
58
+ "depends_on": list(
59
+ dep.origin.identifier
60
+ for dep in job.dependencies
61
+ if isinstance(dep, JobDependency)
62
+ ),
63
+ }
64
+ for job in jobs
65
+ ],
66
+ SerializationContext(),
67
+ path,
68
+ )
69
+
70
+
71
+ def get_experiment(
72
+ name: str, *, workspace: Optional[str] = None, workdir: Optional[Path] = None
73
+ ) -> ExperimentState:
74
+ ws = find_workspace(workspace=workspace, workdir=workdir)
75
+ return ExperimentState(ws.path, name)
@@ -12,11 +12,8 @@ from sphinx import addnodes
12
12
  from sphinx.ext.autodoc import ClassDocumenter, Documenter, restify
13
13
  from sphinx.locale import _
14
14
  from sphinx.util import inspect, logging
15
- from sphinx.domains.python import (
16
- PyClasslike,
17
- PyAttribute,
18
- directives, # noqa: F401
19
- )
15
+ from sphinx.domains.python import PyClasslike, PyAttribute, directives
16
+ from sphinx.domains.python import PyObject # noqa: F401
20
17
  from sphinx.addnodes import desc_signature
21
18
  from sphinx.util.typing import OptionSpec
22
19
  from docutils.statemachine import StringList
@@ -63,9 +63,9 @@ while IFS= read -r line; do
63
63
  esac
64
64
  done < "$1"
65
65
 
66
+ cd "$chdir"
66
67
  echo "Starting $@ ${args[@]} > $stdout 2> $stderr" >&2
67
68
  (
68
- if test "$chdir"; then cd "$chdir"; fi
69
69
  export PATH="${CURDIR}/bin:$PATH"
70
70
  eval "$@" "${args[@]}"
71
71
  echo $? > "$XPM_SLURM_DIR/jobs/$$.status"
@@ -0,0 +1,50 @@
1
+ from experimaestro import Task, Param, get_experiment, tag
2
+ from experimaestro.tests.utils import TemporaryDirectory, TemporaryExperiment
3
+
4
+
5
+ class TaskA(Task):
6
+ def execute(self):
7
+ pass
8
+
9
+
10
+ class TaskB(Task):
11
+ task_a: Param[TaskA]
12
+ x: Param[int]
13
+
14
+ def execute(self):
15
+ pass
16
+
17
+
18
+ # xp = get_experiment(id="my-xp-1")
19
+
20
+ # # Returns a list of tasks which were submitted and successful
21
+ # tasks = xp.get_tasks(myxps.evaluation.Evaluation, status=Job.DONE)
22
+
23
+ # for task in tasks:
24
+ # # Look at the tags
25
+ # print(task.tags)
26
+
27
+ # # Get some information
28
+ # print("Task ran in {task.workdir}")
29
+
30
+ # # Look at the parent jobs
31
+ # print(task.depends_on)
32
+
33
+ # # Look at the dependant
34
+ # print(task.dependents)
35
+
36
+
37
+ def test_experiment_history():
38
+ """Test retrieving experiment history"""
39
+ with TemporaryDirectory() as workdir:
40
+ with TemporaryExperiment("experiment", workdir=workdir):
41
+ task_a = TaskA().submit()
42
+ TaskB(task_a=task_a, x=tag(1)).submit()
43
+
44
+ # Look at the experiment
45
+ xp = get_experiment("experiment", workdir=workdir)
46
+
47
+ (task_a_info,) = xp.get_jobs(TaskA)
48
+ (task_b_info,) = xp.get_jobs(TaskB)
49
+ assert task_b_info.tags == {"x": 1}
50
+ assert task_b_info.depends_on == [task_a_info]
@@ -8,14 +8,7 @@ if sys.version_info.major == 3:
8
8
  else:
9
9
  from typing import _collect_parameters
10
10
 
11
- if sys.version_info.minor < 9:
12
- from typing_extensions import (
13
- _AnnotatedAlias as AnnotatedAlias,
14
- get_args,
15
- get_origin,
16
- )
17
- else:
18
- from typing import _AnnotatedAlias as AnnotatedAlias, get_args, get_origin
11
+ from typing import _AnnotatedAlias as AnnotatedAlias, get_args, get_origin
19
12
 
20
13
  GenericAlias = typing._GenericAlias
21
14