experimaestro 1.5.3__tar.gz → 1.6.0__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 (152) hide show
  1. {experimaestro-1.5.3 → experimaestro-1.6.0}/PKG-INFO +4 -5
  2. {experimaestro-1.5.3 → experimaestro-1.6.0}/pyproject.toml +4 -8
  3. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/__init__.py +0 -1
  4. experimaestro-1.6.0/src/experimaestro/__main__.py +12 -0
  5. experimaestro-1.5.3/src/experimaestro/__main__.py → experimaestro-1.6.0/src/experimaestro/cli/__init__.py +8 -128
  6. {experimaestro-1.5.3/src/experimaestro → experimaestro-1.6.0/src/experimaestro/cli}/filter.py +4 -4
  7. experimaestro-1.6.0/src/experimaestro/cli/jobs.py +261 -0
  8. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/click.py +0 -35
  9. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/connectors/ssh.py +26 -7
  10. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/core/objects.py +13 -6
  11. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/core/types.py +8 -3
  12. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/experiments/cli.py +97 -63
  13. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/experiments/configuration.py +7 -1
  14. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/launcherfinder/__init__.py +1 -1
  15. experimaestro-1.6.0/src/experimaestro/launcherfinder/base.py +17 -0
  16. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/launcherfinder/registry.py +22 -129
  17. experimaestro-1.6.0/src/experimaestro/launchers/direct.py +10 -0
  18. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/launchers/slurm/base.py +3 -1
  19. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/notifications.py +24 -8
  20. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/run.py +23 -5
  21. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/scheduler/base.py +26 -15
  22. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/scheduler/workspace.py +26 -8
  23. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/scriptbuilder.py +5 -1
  24. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/settings.py +43 -5
  25. experimaestro-1.6.0/src/experimaestro/tests/launchers/config_slurm/launchers.py +25 -0
  26. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_findlauncher.py +1 -1
  27. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_ssh.py +7 -0
  28. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_tags.py +35 -0
  29. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tokens.py +8 -8
  30. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/utils/resources.py +5 -1
  31. experimaestro-1.5.3/src/experimaestro/launcherfinder/base.py +0 -33
  32. experimaestro-1.5.3/src/experimaestro/launchers/direct.py +0 -57
  33. experimaestro-1.5.3/src/experimaestro/launchers/slurm/cli.py +0 -29
  34. experimaestro-1.5.3/src/experimaestro/launchers/slurm/configuration.py +0 -597
  35. experimaestro-1.5.3/src/experimaestro/scheduler/environment.py +0 -94
  36. experimaestro-1.5.3/src/experimaestro/tests/launchers/config_slurm/launchers.yaml +0 -134
  37. experimaestro-1.5.3/src/experimaestro/utils/yaml.py +0 -202
  38. {experimaestro-1.5.3 → experimaestro-1.6.0}/LICENSE +0 -0
  39. {experimaestro-1.5.3 → experimaestro-1.6.0}/README.md +0 -0
  40. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/annotations.py +0 -0
  41. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/checkers.py +0 -0
  42. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/commandline.py +0 -0
  43. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/compat.py +0 -0
  44. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/connectors/__init__.py +0 -0
  45. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/connectors/local.py +0 -0
  46. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/core/__init__.py +0 -0
  47. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/core/arguments.py +0 -0
  48. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/core/context.py +0 -0
  49. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/core/objects.pyi +0 -0
  50. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/core/serialization.py +0 -0
  51. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/core/serializers.py +0 -0
  52. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/core/utils.py +0 -0
  53. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/exceptions.py +0 -0
  54. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/experiments/__init__.py +0 -0
  55. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/generators.py +0 -0
  56. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/huggingface.py +0 -0
  57. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/ipc.py +0 -0
  58. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/launcherfinder/parser.py +0 -0
  59. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/launcherfinder/specs.py +0 -0
  60. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/launchers/__init__.py +0 -0
  61. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/launchers/oar.py +0 -0
  62. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/launchers/slurm/__init__.py +0 -0
  63. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/locking.py +0 -0
  64. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/mkdocs/__init__.py +0 -0
  65. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/mkdocs/annotations.py +0 -0
  66. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/mkdocs/base.py +0 -0
  67. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/mkdocs/metaloader.py +0 -0
  68. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/mkdocs/style.css +0 -0
  69. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/mypy.py +0 -0
  70. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/py.typed +0 -0
  71. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/rpyc.py +0 -0
  72. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/scheduler/__init__.py +0 -0
  73. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/scheduler/dependencies.py +0 -0
  74. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/scheduler/services.py +0 -0
  75. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/__init__.py +0 -0
  76. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/016b4a6cdced82ab3aa1.ttf +0 -0
  77. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/0c35d18bf06992036b69.woff2 +0 -0
  78. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/219aa9140e099e6c72ed.woff2 +0 -0
  79. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/3a4004a46a653d4b2166.woff +0 -0
  80. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/3baa5b8f3469222b822d.woff +0 -0
  81. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/4d73cb90e394b34b7670.woff +0 -0
  82. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/4ef4218c522f1eb6b5b1.woff2 +0 -0
  83. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/50701fbb8177c2dde530.ttf +0 -0
  84. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/5d681e2edae8c60630db.woff +0 -0
  85. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/6f420cf17cc0d7676fad.woff2 +0 -0
  86. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/878f31251d960bd6266f.woff2 +0 -0
  87. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/b041b1fa4fe241b23445.woff2 +0 -0
  88. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/b6879d41b0852f01ed5b.woff2 +0 -0
  89. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/c380809fd3677d7d6903.woff2 +0 -0
  90. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/d75e3fd1eb12e9bd6655.ttf +0 -0
  91. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/f882956fd323fd322f31.woff +0 -0
  92. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/favicon.ico +0 -0
  93. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/index.css +0 -0
  94. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/index.css.map +0 -0
  95. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/index.html +0 -0
  96. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/index.js +0 -0
  97. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/index.js.map +0 -0
  98. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/login.html +0 -0
  99. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/manifest.json +0 -0
  100. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/sphinx/__init__.py +0 -0
  101. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/sphinx/static/experimaestro.css +0 -0
  102. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/taskglobals.py +0 -0
  103. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/__init__.py +0 -0
  104. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/conftest.py +0 -0
  105. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/connectors/bin/executable.py +0 -0
  106. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/connectors/test_local.py +0 -0
  107. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/connectors/utils.py +0 -0
  108. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/definitions_types.py +0 -0
  109. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/launchers/__init__.py +0 -0
  110. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/launchers/bin/sacct +0 -0
  111. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/launchers/bin/sbatch +0 -0
  112. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/launchers/bin/test.py +0 -0
  113. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/launchers/common.py +0 -0
  114. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/launchers/config_slurm/__init__.py +0 -0
  115. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/launchers/test_local.py +0 -0
  116. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/launchers/test_slurm.py +0 -0
  117. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/restart.py +0 -0
  118. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/restart_main.py +0 -0
  119. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/scripts/notifyandwait.py +0 -0
  120. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/scripts/waitforfile.py +0 -0
  121. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/task_tokens.py +0 -0
  122. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/tasks/__init__.py +0 -0
  123. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/tasks/all.py +0 -0
  124. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/tasks/foreign.py +0 -0
  125. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_checkers.py +0 -0
  126. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_dependencies.py +0 -0
  127. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_forward.py +0 -0
  128. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_identifier.py +0 -0
  129. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_instance.py +0 -0
  130. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_objects.py +0 -0
  131. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_outputs.py +0 -0
  132. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_param.py +0 -0
  133. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_progress.py +0 -0
  134. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_serializers.py +0 -0
  135. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_snippets.py +0 -0
  136. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_tasks.py +0 -0
  137. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_tokens.py +0 -0
  138. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_types.py +0 -0
  139. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_validation.py +0 -0
  140. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/token_reschedule.py +0 -0
  141. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/utils.py +0 -0
  142. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tools/__init__.py +0 -0
  143. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tools/diff.py +0 -0
  144. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tools/documentation.py +0 -0
  145. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tools/jobs.py +0 -0
  146. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/typingutils.py +0 -0
  147. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/utils/__init__.py +0 -0
  148. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/utils/asyncio.py +0 -0
  149. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/utils/jobs.py +0 -0
  150. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/utils/jupyter.py +0 -0
  151. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/utils/settings.py +0 -0
  152. {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/xpmutils.py +0 -0
@@ -1,8 +1,7 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: experimaestro
3
- Version: 1.5.3
3
+ Version: 1.6.0
4
4
  Summary: "Experimaestro is a computer science experiment manager"
5
- Home-page: https://github.com/experimaestro/experimaestro-python
6
5
  License: GPL-3
7
6
  Keywords: experiment manager
8
7
  Author: Benjamin Piwowarski
@@ -20,13 +19,13 @@ Classifier: Programming Language :: Python :: 3.9
20
19
  Classifier: Programming Language :: Python :: 3.10
21
20
  Classifier: Programming Language :: Python :: 3.11
22
21
  Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
23
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
24
  Requires-Dist: arpeggio (>=2,<3)
25
25
  Requires-Dist: attrs (>=23.1.0,<24.0.0)
26
26
  Requires-Dist: click (>=8)
27
27
  Requires-Dist: decorator (>=5,<6)
28
28
  Requires-Dist: docstring-parser (>=0.15,<0.16)
29
- Requires-Dist: fabric (>=3,<4)
30
29
  Requires-Dist: fasteners (>=0.19,<0.20)
31
30
  Requires-Dist: flask (>=2.3,<3.0)
32
31
  Requires-Dist: flask-socketio (>=5.3,<6.0)
@@ -41,7 +40,7 @@ Requires-Dist: pyparsing (>=3.1,<4.0)
41
40
  Requires-Dist: pytools (>=2023.1.1,<2024.0.0)
42
41
  Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
43
42
  Requires-Dist: requests (>=2.31,<3.0)
44
- Requires-Dist: rpyc (>=5,<6)
43
+ Requires-Dist: rpyc (>=5,<7)
45
44
  Requires-Dist: sortedcontainers (>=2.4,<3.0)
46
45
  Requires-Dist: termcolor (>=2.3)
47
46
  Requires-Dist: tqdm (>=4.66.1,<5.0.0)
@@ -19,7 +19,7 @@ include = [
19
19
  "src/experimaestro/sphinx/static/experimaestro.css",
20
20
  "src/experimaestro/mkdocs/style.css"
21
21
  ]
22
- version = "1.5.3"
22
+ version = "1.6.0"
23
23
  repository = "https://github.com/experimaestro/experimaestro-python"
24
24
  documentation = "https://experimaestro-python.readthedocs.io/"
25
25
 
@@ -59,15 +59,15 @@ flask-socketio = "^5.3"
59
59
  arpeggio = "^2"
60
60
  watchdog = "^2"
61
61
  marshmallow = "^3.20"
62
- fabric = "^3"
63
62
  decorator = "^5"
64
- rpyc = "^5"
63
+ rpyc = ">=5,<7"
65
64
 
66
65
  [tool.poetry.group.ssh]
67
66
  optional = true
68
67
 
69
68
  [tool.poetry.group.ssh.dependencies]
70
69
  paramiko = "^3.3"
70
+ fabric = "^3"
71
71
 
72
72
  [tool.poetry.group.dev]
73
73
  optional = true
@@ -90,10 +90,6 @@ slurm = "experimaestro.launchers.slurm:BatchSlurmProcess"
90
90
  local = "experimaestro.connectors.local:LocalConnector"
91
91
  ssh = "experimaestro.connectors.ssh:SshConnector"
92
92
 
93
- [tool.poetry.plugins."experimaestro.launchers"]
94
- unix = "experimaestro.launchers.direct:DirectLauncher"
95
- slurm = "experimaestro.launchers.slurm:SlurmLauncher"
96
-
97
93
  [tool.poetry.plugins."experimaestro.tokens"]
98
94
  unix = "experimaestro.tokens:CounterToken"
99
95
 
@@ -123,7 +119,7 @@ warn_unused_ignores = true
123
119
 
124
120
  [tool.commitizen]
125
121
  name = "cz_conventional_commits"
126
- version = "1.5.3"
122
+ version = "1.6.0"
127
123
  changelog_start_rev = "0.15.0"
128
124
  tag_format = "v$version"
129
125
  update_changelog_on_bump = true
@@ -53,7 +53,6 @@ from .core.context import SerializationContext
53
53
  from .core.serializers import SerializationLWTask, PathSerializationLWTask
54
54
  from .core.types import Any, SubmitHook
55
55
  from .launchers import Launcher
56
- from .scheduler.environment import Environment
57
56
  from .scheduler.workspace import Workspace, RunMode
58
57
  from .scheduler import Scheduler, experiment, FailedExperiment
59
58
  from .notifications import progress, tqdm
@@ -0,0 +1,12 @@
1
+ from experimaestro.cli import cli
2
+
3
+ # flake8: noqa: F401
4
+ import experimaestro.cli.jobs
5
+
6
+
7
+ def main():
8
+ cli(obj=None)
9
+
10
+
11
+ if __name__ == "__main__":
12
+ main()
@@ -1,6 +1,5 @@
1
1
  # flake8: noqa: T201
2
2
  import sys
3
- from types import ModuleType
4
3
  from typing import Set, Optional
5
4
  import pkg_resources
6
5
  from itertools import chain
@@ -10,11 +9,12 @@ import logging
10
9
  from functools import cached_property, update_wrapper
11
10
  from pathlib import Path
12
11
  import subprocess
13
- from termcolor import colored, cprint
12
+ from termcolor import cprint
14
13
 
15
14
  import experimaestro
16
15
  from experimaestro.experiments.cli import experiments_cli
17
16
  import experimaestro.launcherfinder.registry as launcher_registry
17
+ from experimaestro.settings import find_workspace
18
18
 
19
19
  # --- Command line main options
20
20
  logging.basicConfig(level=logging.INFO)
@@ -175,121 +175,6 @@ def diff(path: Path):
175
175
  check(".", job, new_job, set())
176
176
 
177
177
 
178
- @click.argument("path", type=Path, callback=check_xp_path)
179
- @click.option("--experiment", default=None, help="Restrict to this experiment")
180
- @click.option("--tags", is_flag=True, help="Show tags")
181
- @click.option("--ready", is_flag=True, help="Include tasks which are not yet scheduled")
182
- @click.option("--filter", default="", help="Filter expression")
183
- @click.option(
184
- "--force",
185
- is_flag=True,
186
- help="Force operation even if experiment has not been completed yet",
187
- )
188
- @click.option("--kill", is_flag=True, help="Kill filtered tasks (when/before running)")
189
- @click.option("--clean", is_flag=True, help="Remove finished tasks directories")
190
- @cli.command()
191
- def jobs(
192
- path: Path,
193
- experiment: str,
194
- filter: str,
195
- tags: bool,
196
- ready: bool,
197
- kill: bool,
198
- clean: bool,
199
- force: bool,
200
- ):
201
- """Job control: list, kill and clean
202
-
203
- The job filter is a boolean expression where tags (alphanumeric)
204
- and special job information (@state for job state, @name for job full
205
- name) can be compared to a given value (using '~' for regex matching,
206
- '=', 'not in', or 'in')
207
-
208
- For instance,
209
-
210
- model = "bm25" and mode in ["a", b"] and @state = "RUNNING"
211
-
212
- selects jobs where the tag model is "bm25", the tag mode is either
213
- "a" or "b", and the state is running.
214
-
215
- """
216
- for p in (path / "xp").glob("*"):
217
- if experiment and p.name != experiment:
218
- continue
219
-
220
- from .filter import createFilter, JobInformation
221
- from experimaestro.scheduler import JobState
222
-
223
- _filter = createFilter(filter) if filter else lambda x: True
224
-
225
- print(f"* Experiment {p.name}")
226
- if (p / "jobs.bak").is_dir():
227
- cprint(" Experiment has not finished yet", "red")
228
- if not force and (kill or clean):
229
- cprint(" Preventing kill/clean (use --force if you want to)", "yellow")
230
- kill = False
231
- clean = False
232
- print()
233
-
234
- for job in p.glob("jobs/*/*"):
235
- info = None
236
- p = job.resolve()
237
- if p.is_dir():
238
- *_, scriptname = p.parent.name.rsplit(".", 1)
239
-
240
- info = JobInformation(p, scriptname)
241
- if filter:
242
- if not _filter(info):
243
- continue
244
-
245
- if info.state is None:
246
- print(
247
- colored(f"NODIR {job.parent.name}/{job.name}", "red"), end=""
248
- )
249
- elif info.state.running():
250
- if kill:
251
- process = info.getprocess()
252
- print("KILLING", process)
253
- process.kill()
254
- print(
255
- colored(
256
- f"{info.state.name:8}{job.parent.name}/{job.name}", "yellow"
257
- ),
258
- end="",
259
- )
260
- elif info.state == JobState.DONE:
261
- print(
262
- colored(f"DONE {job.parent.name}/{job.name}", "green"),
263
- end="",
264
- )
265
- elif info.state == JobState.ERROR:
266
- print(
267
- colored(f"FAIL {job.parent.name}/{job.name}", "red"), end=""
268
- )
269
- else:
270
- print(
271
- colored(
272
- f"{info.state.name:8}{job.parent.name}/{job.name}", "red"
273
- ),
274
- end="",
275
- )
276
-
277
- else:
278
- if not ready:
279
- continue
280
- print(colored(f"READY {job.parent.name}/{job.name}", "yellow"), end="")
281
-
282
- if tags:
283
- print(f""" {" ".join(f"{k}={v}" for k, v in info.tags.items())}""")
284
- else:
285
- print()
286
-
287
- if clean and info.state and info.state.finished():
288
- cprint("Cleaning...", "red")
289
- rmtree(p)
290
- print()
291
-
292
-
293
178
  @click.option("--show-all", is_flag=True, help="Show even not orphans")
294
179
  @click.option(
295
180
  "--ignore-old", is_flag=True, help="Ignore old jobs for unfinished experiments"
@@ -407,11 +292,14 @@ cli.add_command(Launchers("tokens", help="Token specific commands"))
407
292
 
408
293
 
409
294
  @cli.group()
410
- @click.argument("workdir", type=Path, callback=check_xp_path)
295
+ @click.option("--workdir", type=Path, default=None)
296
+ @click.option("--workspace", type=str, default=None)
411
297
  @click.pass_context
412
- def experiments(ctx, workdir):
298
+ def experiments(ctx, workdir, workspace):
413
299
  """Manage experiments"""
414
- ctx.obj = workdir
300
+ ws = find_workspace(workdir=workdir, workspace=workspace)
301
+ path = check_xp_path(None, None, ws.path)
302
+ ctx.obj = path
415
303
 
416
304
 
417
305
  @experiments.command()
@@ -422,11 +310,3 @@ def list(workdir: Path):
422
310
  cprint(f"[unfinished] {p.name}", "yellow")
423
311
  else:
424
312
  cprint(p.name, "cyan")
425
-
426
-
427
- def main():
428
- cli(obj=None)
429
-
430
-
431
- if __name__ == "__main__":
432
- main()
@@ -22,12 +22,12 @@ class JobInformation:
22
22
 
23
23
  @cached_property
24
24
  def state(self) -> Optional[JobState]:
25
- if (self.path / f"{self.scriptname}.pid").is_file():
26
- return JobState.RUNNING
27
- elif (self.path / f"{self.scriptname}.done").is_file():
25
+ if (self.path / f"{self.scriptname}.done").is_file():
28
26
  return JobState.DONE
29
- elif (self.path / f"{self.scriptname}.failed").is_file():
27
+ if (self.path / f"{self.scriptname}.failed").is_file():
30
28
  return JobState.ERROR
29
+ if (self.path / f"{self.scriptname}.pid").is_file():
30
+ return JobState.RUNNING
31
31
  else:
32
32
  return None
33
33
 
@@ -0,0 +1,261 @@
1
+ # flake8: noqa: T201
2
+ import subprocess
3
+ from typing import Optional
4
+ from shutil import rmtree
5
+ import click
6
+ from pathlib import Path
7
+ from termcolor import colored, cprint
8
+
9
+ from experimaestro.settings import find_workspace
10
+ from . import check_xp_path, cli
11
+
12
+
13
+ @click.option("--workspace", default="", help="Experimaestro workspace")
14
+ @click.option("--workdir", type=Path, default=None)
15
+ @cli.group()
16
+ @click.pass_context
17
+ def jobs(
18
+ ctx,
19
+ workdir: Optional[Path],
20
+ workspace: Optional[str],
21
+ ):
22
+ """Job control: list, kill and clean
23
+
24
+ The job filter is a boolean expression where tags (alphanumeric)
25
+ and special job information (@state for job state, @name for job full
26
+ name) can be compared to a given value (using '~' for regex matching,
27
+ '=', 'not in', or 'in')
28
+
29
+ For instance,
30
+
31
+ model = "bm25" and mode in ["a", b"] and @state = "RUNNING"
32
+
33
+ selects jobs where the tag model is "bm25", the tag mode is either
34
+ "a" or "b", and the state is running.
35
+
36
+ """
37
+ ws = ctx.obj.workspace = find_workspace(workdir=workdir, workspace=workspace)
38
+ check_xp_path(ctx, None, ws.path)
39
+
40
+
41
+ def process(
42
+ workspace,
43
+ *,
44
+ experiment="",
45
+ tags="",
46
+ ready=False,
47
+ clean=False,
48
+ kill=False,
49
+ filter="",
50
+ perform=False,
51
+ fullpath=False,
52
+ ):
53
+ from .filter import createFilter, JobInformation
54
+ from experimaestro.scheduler import JobState
55
+
56
+ _filter = createFilter(filter) if filter else lambda x: True
57
+
58
+ # Get all jobs from experiments
59
+ job2xp = {}
60
+
61
+ path = workspace.path
62
+ for p in (path / "xp").glob("*"):
63
+ for job in p.glob("jobs/*/*"):
64
+ job_path = job.resolve()
65
+ if job_path.is_dir():
66
+ *_, scriptname = job_path.parent.name.rsplit(".", 1)
67
+ job2xp.setdefault(scriptname, set()).add(p.name)
68
+
69
+ if (p / "jobs.bak").is_dir():
70
+ cprint(f" Experiment {p.name} has not finished yet", "red")
71
+ if (not perform) and (kill or clean):
72
+ cprint(" Preventing kill/clean (use --force if you want to)", "yellow")
73
+ kill = False
74
+ clean = False
75
+
76
+ # Now, process jobs
77
+ for job in path.glob("jobs/*/*"):
78
+ info = None
79
+ p = job.resolve()
80
+ if p.is_dir():
81
+ *_, scriptname = p.parent.name.rsplit(".", 1)
82
+ xps = job2xp.get(scriptname, set())
83
+ if experiment and experiment not in xps:
84
+ continue
85
+
86
+ info = JobInformation(p, scriptname)
87
+ job_str = (
88
+ (str(job.resolve()) if fullpath else f"{job.parent.name}/{job.name}")
89
+ + " "
90
+ + ",".join(xps)
91
+ )
92
+
93
+ if filter:
94
+ if not _filter(info):
95
+ continue
96
+
97
+ if info.state is None:
98
+ print(colored(f"NODIR {job_str}", "red"), end="")
99
+ elif info.state.running():
100
+ if kill:
101
+ if perform:
102
+ process = info.getprocess()
103
+ if process is None:
104
+ cprint(
105
+ "internal error – no process could be retrieved",
106
+ "red",
107
+ )
108
+ else:
109
+ cprint(f"KILLING {process}", "light_red")
110
+ process.kill()
111
+ else:
112
+ print("KILLING (not performing)", process)
113
+ print(
114
+ colored(f"{info.state.name:8}{job_str}", "yellow"),
115
+ end="",
116
+ )
117
+ elif info.state == JobState.DONE:
118
+ print(
119
+ colored(f"DONE {job_str}", "green"),
120
+ end="",
121
+ )
122
+ elif info.state == JobState.ERROR:
123
+ print(colored(f"FAIL {job_str}", "red"), end="")
124
+ else:
125
+ print(
126
+ colored(f"{info.state.name:8}{job_str}", "red"),
127
+ end="",
128
+ )
129
+
130
+ else:
131
+ if not ready:
132
+ continue
133
+ print(colored(f"READY {job_path}", "yellow"), end="")
134
+
135
+ if tags:
136
+ print(f""" {" ".join(f"{k}={v}" for k, v in info.tags.items())}""")
137
+ else:
138
+ print()
139
+
140
+ if clean and info.state and info.state.finished():
141
+ if perform:
142
+ cprint("Cleaning...", "red")
143
+ rmtree(p)
144
+ else:
145
+ cprint("Cleaning... (not performed)", "red")
146
+ print()
147
+
148
+
149
+ @click.option("--experiment", default=None, help="Restrict to this experiment")
150
+ @click.option("--tags", is_flag=True, help="Show tags")
151
+ @click.option("--ready", is_flag=True, help="Include tasks which are not yet scheduled")
152
+ @click.option("--filter", default="", help="Filter expression")
153
+ @click.option("--fullpath", is_flag=True, help="Prints full paths")
154
+ @jobs.command()
155
+ @click.pass_context
156
+ def list(
157
+ ctx,
158
+ experiment: str,
159
+ filter: str,
160
+ tags: bool,
161
+ ready: bool,
162
+ fullpath: bool,
163
+ ):
164
+ process(
165
+ ctx.obj.workspace,
166
+ experiment=experiment,
167
+ filter=filter,
168
+ tags=tags,
169
+ ready=ready,
170
+ fullpath=fullpath,
171
+ )
172
+
173
+
174
+ @click.option("--experiment", default=None, help="Restrict to this experiment")
175
+ @click.option("--tags", is_flag=True, help="Show tags")
176
+ @click.option("--ready", is_flag=True, help="Include tasks which are not yet scheduled")
177
+ @click.option("--filter", default="", help="Filter expression")
178
+ @click.option("--perform", is_flag=True, help="Really perform the killing")
179
+ @click.option("--fullpath", is_flag=True, help="Prints full paths")
180
+ @jobs.command()
181
+ @click.pass_context
182
+ def kill(
183
+ ctx,
184
+ experiment: str,
185
+ filter: str,
186
+ tags: bool,
187
+ ready: bool,
188
+ fullpath: bool,
189
+ perform: bool,
190
+ ):
191
+ process(
192
+ ctx.obj.workspace,
193
+ experiment=experiment,
194
+ filter=filter,
195
+ tags=tags,
196
+ ready=ready,
197
+ kill=True,
198
+ perform=perform,
199
+ fullpath=fullpath,
200
+ )
201
+
202
+
203
+ @click.option("--experiment", default=None, help="Restrict to this experiment")
204
+ @click.option("--tags", is_flag=True, help="Show tags")
205
+ @click.option("--ready", is_flag=True, help="Include tasks which are not yet scheduled")
206
+ @click.option("--filter", default="", help="Filter expression")
207
+ @click.option("--perform", is_flag=True, help="Really perform the cleaning")
208
+ @click.option("--fullpath", is_flag=True, help="Prints full paths")
209
+ @jobs.command()
210
+ @click.pass_context
211
+ def clean(
212
+ ctx,
213
+ experiment: str,
214
+ filter: str,
215
+ tags: bool,
216
+ ready: bool,
217
+ fullpath: bool,
218
+ perform: bool,
219
+ ):
220
+ process(
221
+ ctx.obj.workspace,
222
+ experiment=experiment,
223
+ filter=filter,
224
+ tags=tags,
225
+ ready=ready,
226
+ clean=True,
227
+ perform=perform,
228
+ fullpath=fullpath,
229
+ )
230
+
231
+
232
+ @click.argument("jobid", type=str)
233
+ @click.option(
234
+ "--follow", "-f", help="Use tail instead of less to follow changes", is_flag=True
235
+ )
236
+ @click.option("--std", help="Follow stdout instead of stderr", is_flag=True)
237
+ @jobs.command()
238
+ @click.pass_context
239
+ def log(ctx, jobid: str, follow: bool, std: bool):
240
+ task_name, task_hash = jobid.split("/")
241
+ _, name = task_name.rsplit(".", 1)
242
+ path = (
243
+ ctx.obj.workspace.path
244
+ / "jobs"
245
+ / task_name
246
+ / task_hash
247
+ / f"""{name}.{'out' if std else 'err'}"""
248
+ )
249
+ if follow:
250
+ subprocess.run(["tail", "-f", path])
251
+ else:
252
+ subprocess.run(["less", "-r", path])
253
+
254
+
255
+ @click.argument("jobid", type=str)
256
+ @jobs.command()
257
+ @click.pass_context
258
+ def path(ctx, jobid: str):
259
+ task_name, task_hash = jobid.split("/")
260
+ path = ctx.obj.workspace.path / "jobs" / task_name / task_hash
261
+ print(path)
@@ -1,6 +1,4 @@
1
1
  import click
2
- from experimaestro import Environment
3
- from experimaestro.run import parse_commandline
4
2
 
5
3
  """Defines the task command line argument prefix for experimaestro-handled command lines"""
6
4
 
@@ -45,36 +43,3 @@ class forwardoption(metaclass=forwardoptionMetaclass):
45
43
  def __getattr__(self, key):
46
44
  """Access to a class field"""
47
45
  return forwardoption([key])
48
-
49
-
50
- def environment(name: str):
51
- def annotate(f):
52
- def callback_env(ctx, name, value):
53
- if value:
54
- assert name not in ctx.params, "Environment has already been set"
55
- else:
56
- return ctx.params.get(name, None)
57
- return Environment.get(value)
58
-
59
- def callback(ctx, param, value):
60
- if value:
61
- if name not in ctx.params:
62
- ctx.params[name] = Environment()
63
- ctx.params[name].workdir = value
64
-
65
- f = click.option(
66
- f"--{name}-workdir",
67
- type=str,
68
- callback=callback,
69
- expose_value=False,
70
- help="Experimaestro environment",
71
- )(f)
72
- f = click.option(
73
- f"--{name}",
74
- type=str,
75
- callback=callback_env,
76
- help="Experimaestro environment",
77
- )(f)
78
- return f
79
-
80
- return annotate
@@ -1,12 +1,15 @@
1
+ try:
2
+ from pathlib import Path, _posix_flavour
3
+ except ImportError:
4
+ # Avoids problem with python 3.12 where this module does not work
5
+ # anyways
6
+ _posix_flavour = None
7
+
1
8
  from dataclasses import dataclass
2
- from pathlib import Path, _posix_flavour
3
9
  import io
4
10
  import os
5
11
  import re
6
- from experimaestro.launcherfinder import LauncherRegistry, YAMLDataClass
7
- from fabric import Connection
8
- from invoke import Promise
9
- import invoke.exceptions
12
+ from experimaestro.launcherfinder import LauncherRegistry
10
13
  from urllib.parse import urlparse
11
14
  from itertools import chain
12
15
  from . import Connector
@@ -19,6 +22,22 @@ from . import (
19
22
  from experimaestro.locking import Lock
20
23
  from experimaestro.tokens import Token
21
24
 
25
+ try:
26
+ from fabric import Connection
27
+ from invoke import Promise
28
+ from invoke.exceptions import Failure
29
+ except Exception:
30
+ # Just define placeholders
31
+ class Connection:
32
+ pass
33
+
34
+ class Promise:
35
+ pass
36
+
37
+ class Failure(Exception):
38
+ pass
39
+
40
+
22
41
  # Might be wise to switch to https://github.com/marian-code/ssh-utilities
23
42
 
24
43
 
@@ -132,7 +151,7 @@ class SshPath(Path):
132
151
 
133
152
 
134
153
  @dataclass
135
- class SshConfiguration(YAMLDataClass):
154
+ class SshConfiguration:
136
155
  hostname: str
137
156
 
138
157
  def create(self, registry: LauncherRegistry):
@@ -172,7 +191,7 @@ class SshProcess(Process):
172
191
  def wait(self) -> int:
173
192
  try:
174
193
  self.promise.join()
175
- except invoke.exceptions.Failure:
194
+ except Failure:
176
195
  raise
177
196
 
178
197