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.
- {experimaestro-1.5.3 → experimaestro-1.6.0}/PKG-INFO +4 -5
- {experimaestro-1.5.3 → experimaestro-1.6.0}/pyproject.toml +4 -8
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/__init__.py +0 -1
- experimaestro-1.6.0/src/experimaestro/__main__.py +12 -0
- experimaestro-1.5.3/src/experimaestro/__main__.py → experimaestro-1.6.0/src/experimaestro/cli/__init__.py +8 -128
- {experimaestro-1.5.3/src/experimaestro → experimaestro-1.6.0/src/experimaestro/cli}/filter.py +4 -4
- experimaestro-1.6.0/src/experimaestro/cli/jobs.py +261 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/click.py +0 -35
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/connectors/ssh.py +26 -7
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/core/objects.py +13 -6
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/core/types.py +8 -3
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/experiments/cli.py +97 -63
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/experiments/configuration.py +7 -1
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/launcherfinder/__init__.py +1 -1
- experimaestro-1.6.0/src/experimaestro/launcherfinder/base.py +17 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/launcherfinder/registry.py +22 -129
- experimaestro-1.6.0/src/experimaestro/launchers/direct.py +10 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/launchers/slurm/base.py +3 -1
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/notifications.py +24 -8
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/run.py +23 -5
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/scheduler/base.py +26 -15
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/scheduler/workspace.py +26 -8
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/scriptbuilder.py +5 -1
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/settings.py +43 -5
- experimaestro-1.6.0/src/experimaestro/tests/launchers/config_slurm/launchers.py +25 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_findlauncher.py +1 -1
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_ssh.py +7 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_tags.py +35 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tokens.py +8 -8
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/utils/resources.py +5 -1
- experimaestro-1.5.3/src/experimaestro/launcherfinder/base.py +0 -33
- experimaestro-1.5.3/src/experimaestro/launchers/direct.py +0 -57
- experimaestro-1.5.3/src/experimaestro/launchers/slurm/cli.py +0 -29
- experimaestro-1.5.3/src/experimaestro/launchers/slurm/configuration.py +0 -597
- experimaestro-1.5.3/src/experimaestro/scheduler/environment.py +0 -94
- experimaestro-1.5.3/src/experimaestro/tests/launchers/config_slurm/launchers.yaml +0 -134
- experimaestro-1.5.3/src/experimaestro/utils/yaml.py +0 -202
- {experimaestro-1.5.3 → experimaestro-1.6.0}/LICENSE +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/README.md +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/annotations.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/checkers.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/commandline.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/compat.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/connectors/__init__.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/connectors/local.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/core/__init__.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/core/arguments.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/core/context.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/core/objects.pyi +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/core/serialization.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/core/serializers.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/core/utils.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/exceptions.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/experiments/__init__.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/generators.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/huggingface.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/ipc.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/launcherfinder/parser.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/launcherfinder/specs.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/launchers/__init__.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/launchers/oar.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/launchers/slurm/__init__.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/locking.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/mkdocs/__init__.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/mkdocs/annotations.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/mkdocs/base.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/mkdocs/metaloader.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/mkdocs/style.css +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/mypy.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/py.typed +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/rpyc.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/scheduler/__init__.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/scheduler/dependencies.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/scheduler/services.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/__init__.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/016b4a6cdced82ab3aa1.ttf +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/0c35d18bf06992036b69.woff2 +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/219aa9140e099e6c72ed.woff2 +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/3a4004a46a653d4b2166.woff +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/3baa5b8f3469222b822d.woff +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/4d73cb90e394b34b7670.woff +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/4ef4218c522f1eb6b5b1.woff2 +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/50701fbb8177c2dde530.ttf +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/5d681e2edae8c60630db.woff +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/6f420cf17cc0d7676fad.woff2 +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/878f31251d960bd6266f.woff2 +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/b041b1fa4fe241b23445.woff2 +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/b6879d41b0852f01ed5b.woff2 +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/c380809fd3677d7d6903.woff2 +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/d75e3fd1eb12e9bd6655.ttf +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/f882956fd323fd322f31.woff +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/favicon.ico +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/index.css +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/index.css.map +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/index.html +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/index.js +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/index.js.map +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/login.html +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/server/data/manifest.json +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/sphinx/__init__.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/sphinx/static/experimaestro.css +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/taskglobals.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/__init__.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/conftest.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/connectors/bin/executable.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/connectors/test_local.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/connectors/utils.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/definitions_types.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/launchers/__init__.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/launchers/bin/sacct +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/launchers/bin/sbatch +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/launchers/bin/test.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/launchers/common.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/launchers/config_slurm/__init__.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/launchers/test_local.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/launchers/test_slurm.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/restart.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/restart_main.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/scripts/notifyandwait.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/scripts/waitforfile.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/task_tokens.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/tasks/__init__.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/tasks/all.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/tasks/foreign.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_checkers.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_dependencies.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_forward.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_identifier.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_instance.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_objects.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_outputs.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_param.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_progress.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_serializers.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_snippets.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_tasks.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_tokens.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_types.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/test_validation.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/token_reschedule.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tests/utils.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tools/__init__.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tools/diff.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tools/documentation.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/tools/jobs.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/typingutils.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/utils/__init__.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/utils/asyncio.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/utils/jobs.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/utils/jupyter.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/utils/settings.py +0 -0
- {experimaestro-1.5.3 → experimaestro-1.6.0}/src/experimaestro/xpmutils.py +0 -0
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: experimaestro
|
|
3
|
-
Version: 1.
|
|
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,<
|
|
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.
|
|
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 = "
|
|
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.
|
|
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
|
|
@@ -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
|
|
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.
|
|
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
|
-
|
|
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()
|
{experimaestro-1.5.3/src/experimaestro → experimaestro-1.6.0/src/experimaestro/cli}/filter.py
RENAMED
|
@@ -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}.
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
194
|
+
except Failure:
|
|
176
195
|
raise
|
|
177
196
|
|
|
178
197
|
|