experimaestro 1.8.0rc6__tar.gz → 1.8.3__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.8.0rc6 → experimaestro-1.8.3}/PKG-INFO +5 -5
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/README.md +3 -3
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/pyproject.toml +3 -3
- experimaestro-1.8.3/src/experimaestro/core/identifier.py +296 -0
- experimaestro-1.8.3/src/experimaestro/core/objects/__init__.py +44 -0
- experimaestro-1.8.0rc6/src/experimaestro/core/objects.py → experimaestro-1.8.3/src/experimaestro/core/objects/config.py +157 -549
- experimaestro-1.8.3/src/experimaestro/core/objects/config_utils.py +58 -0
- experimaestro-1.8.3/src/experimaestro/core/objects/config_walk.py +150 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/core/objects.pyi +6 -38
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/core/types.py +28 -4
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/notifications.py +1 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/scheduler/base.py +1 -0
- experimaestro-1.8.3/src/experimaestro/tests/core/test_generics.py +206 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/restart.py +3 -1
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/test_instance.py +3 -3
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/test_objects.py +20 -4
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/test_serializers.py +3 -3
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/test_types.py +2 -2
- experimaestro-1.8.3/src/experimaestro/tools/__init__.py +0 -0
- experimaestro-1.8.0rc6/src/experimaestro/server/data/016b4a6cdced82ab3aa1.ttf +0 -0
- experimaestro-1.8.0rc6/src/experimaestro/server/data/50701fbb8177c2dde530.ttf +0 -0
- experimaestro-1.8.0rc6/src/experimaestro/server/data/878f31251d960bd6266f.woff2 +0 -0
- experimaestro-1.8.0rc6/src/experimaestro/server/data/b041b1fa4fe241b23445.woff2 +0 -0
- experimaestro-1.8.0rc6/src/experimaestro/server/data/b6879d41b0852f01ed5b.woff2 +0 -0
- experimaestro-1.8.0rc6/src/experimaestro/server/data/d75e3fd1eb12e9bd6655.ttf +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/LICENSE +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/__init__.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/__main__.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/annotations.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/checkers.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/cli/__init__.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/cli/filter.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/cli/jobs.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/click.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/commandline.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/compat.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/connectors/__init__.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/connectors/local.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/connectors/ssh.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/core/__init__.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/core/arguments.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/core/callbacks.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/core/context.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/core/serialization.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/core/serializers.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/core/utils.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/exceptions.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/experiments/__init__.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/experiments/cli.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/experiments/configuration.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/generators.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/huggingface.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/ipc.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/launcherfinder/__init__.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/launcherfinder/base.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/launcherfinder/parser.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/launcherfinder/registry.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/launcherfinder/specs.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/launchers/__init__.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/launchers/direct.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/launchers/oar.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/launchers/slurm/__init__.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/launchers/slurm/base.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/locking.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/mkdocs/__init__.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/mkdocs/annotations.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/mkdocs/base.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/mkdocs/metaloader.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/mkdocs/style.css +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/mypy.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/py.typed +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/rpyc.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/run.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/scheduler/__init__.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/scheduler/dependencies.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/scheduler/dynamic_outputs.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/scheduler/services.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/scheduler/state.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/scheduler/workspace.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/scriptbuilder.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/__init__.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/0c35d18bf06992036b69.woff2 +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/1815e00441357e01619e.ttf +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/219aa9140e099e6c72ed.woff2 +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/2463b90d9a316e4e5294.woff2 +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/2582b0e4bcf85eceead0.ttf +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/3a4004a46a653d4b2166.woff +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/3baa5b8f3469222b822d.woff +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/4d73cb90e394b34b7670.woff +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/4ef4218c522f1eb6b5b1.woff2 +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/5d681e2edae8c60630db.woff +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/6f420cf17cc0d7676fad.woff2 +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/89999bdf5d835c012025.woff2 +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/914997e1bdfc990d0897.ttf +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/c210719e60948b211a12.woff2 +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/c380809fd3677d7d6903.woff2 +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/f882956fd323fd322f31.woff +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/favicon.ico +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/index.css +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/index.css.map +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/index.html +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/index.js +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/index.js.map +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/login.html +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/server/data/manifest.json +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/settings.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/sphinx/__init__.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/sphinx/static/experimaestro.css +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/taskglobals.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/__init__.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/conftest.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/connectors/bin/executable.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/connectors/test_local.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/connectors/utils.py +0 -0
- {experimaestro-1.8.0rc6/src/experimaestro/tests/launchers → experimaestro-1.8.3/src/experimaestro/tests/core}/__init__.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/definitions_types.py +0 -0
- {experimaestro-1.8.0rc6/src/experimaestro/tests/launchers/config_slurm → experimaestro-1.8.3/src/experimaestro/tests/launchers}/__init__.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/launchers/bin/sacct +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/launchers/bin/sbatch +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/launchers/bin/srun +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/launchers/bin/test.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/launchers/common.py +0 -0
- {experimaestro-1.8.0rc6/src/experimaestro/tests/tasks → experimaestro-1.8.3/src/experimaestro/tests/launchers/config_slurm}/__init__.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/launchers/config_slurm/launchers.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/launchers/test_local.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/launchers/test_slurm.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/restart_main.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/scripts/notifyandwait.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/scripts/waitforfile.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/task_tokens.py +0 -0
- {experimaestro-1.8.0rc6/src/experimaestro/tools → experimaestro-1.8.3/src/experimaestro/tests/tasks}/__init__.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/tasks/all.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/tasks/foreign.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/test_checkers.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/test_dependencies.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/test_experiment.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/test_findlauncher.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/test_forward.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/test_identifier.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/test_outputs.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/test_param.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/test_progress.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/test_snippets.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/test_ssh.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/test_tags.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/test_tasks.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/test_tokens.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/test_validation.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/token_reschedule.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tests/utils.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tokens.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tools/diff.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tools/documentation.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/tools/jobs.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/typingutils.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/utils/__init__.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/utils/asyncio.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/utils/jobs.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/utils/jupyter.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/utils/resources.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/utils/settings.py +0 -0
- {experimaestro-1.8.0rc6 → experimaestro-1.8.3}/src/experimaestro/xpmutils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: experimaestro
|
|
3
|
-
Version: 1.8.
|
|
3
|
+
Version: 1.8.3
|
|
4
4
|
Summary: "Experimaestro is a computer science experiment manager"
|
|
5
5
|
License: GPL-3
|
|
6
6
|
Keywords: experiment manager
|
|
@@ -28,7 +28,7 @@ Requires-Dist: docstring-parser (>=0.15,<0.16)
|
|
|
28
28
|
Requires-Dist: fasteners (>=0.19,<0.20)
|
|
29
29
|
Requires-Dist: flask (>=2.3,<3.0)
|
|
30
30
|
Requires-Dist: flask-socketio (>=5.3,<6.0)
|
|
31
|
-
Requires-Dist: gevent (>=
|
|
31
|
+
Requires-Dist: gevent (>=24.11.1,<25.0.0)
|
|
32
32
|
Requires-Dist: gevent-websocket (>=0.10,<0.11)
|
|
33
33
|
Requires-Dist: huggingface-hub (>0.17)
|
|
34
34
|
Requires-Dist: humanfriendly (>=10,<11)
|
|
@@ -144,11 +144,11 @@ def cli(port, workdir, sleeptime):
|
|
|
144
144
|
# Sets the working directory and the name of the xp
|
|
145
145
|
with experiment(workdir, "helloworld", port=port) as xp:
|
|
146
146
|
# Submit the tasks
|
|
147
|
-
hello = Say(word="hello", sleeptime=sleeptime).submit()
|
|
148
|
-
world = Say(word="world", sleeptime=sleeptime).submit()
|
|
147
|
+
hello = Say.C(word="hello", sleeptime=sleeptime).submit()
|
|
148
|
+
world = Say.C(word="world", sleeptime=sleeptime).submit()
|
|
149
149
|
|
|
150
150
|
# Concat will depend on the two first tasks
|
|
151
|
-
Concat(strings=[hello, world], sleeptime=sleeptime).tag("y", 1).submit()
|
|
151
|
+
Concat.C(strings=[hello, world], sleeptime=sleeptime).tag("y", 1).submit()
|
|
152
152
|
|
|
153
153
|
|
|
154
154
|
if __name__ == "__main__":
|
|
@@ -93,11 +93,11 @@ def cli(port, workdir, sleeptime):
|
|
|
93
93
|
# Sets the working directory and the name of the xp
|
|
94
94
|
with experiment(workdir, "helloworld", port=port) as xp:
|
|
95
95
|
# Submit the tasks
|
|
96
|
-
hello = Say(word="hello", sleeptime=sleeptime).submit()
|
|
97
|
-
world = Say(word="world", sleeptime=sleeptime).submit()
|
|
96
|
+
hello = Say.C(word="hello", sleeptime=sleeptime).submit()
|
|
97
|
+
world = Say.C(word="world", sleeptime=sleeptime).submit()
|
|
98
98
|
|
|
99
99
|
# Concat will depend on the two first tasks
|
|
100
|
-
Concat(strings=[hello, world], sleeptime=sleeptime).tag("y", 1).submit()
|
|
100
|
+
Concat.C(strings=[hello, world], sleeptime=sleeptime).tag("y", 1).submit()
|
|
101
101
|
|
|
102
102
|
|
|
103
103
|
if __name__ == "__main__":
|
|
@@ -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.8.
|
|
23
|
+
version = "1.8.3"
|
|
24
24
|
repository = "https://github.com/experimaestro/experimaestro-python"
|
|
25
25
|
documentation = "https://experimaestro-python.readthedocs.io/"
|
|
26
26
|
|
|
@@ -55,7 +55,7 @@ sortedcontainers = "^2.4"
|
|
|
55
55
|
pyparsing = "^3.1"
|
|
56
56
|
humanfriendly = "^10"
|
|
57
57
|
huggingface-hub = ">0.17"
|
|
58
|
-
gevent = "^
|
|
58
|
+
gevent = "^24.11.1"
|
|
59
59
|
gevent-websocket = "^0.10"
|
|
60
60
|
flask = "^2.3"
|
|
61
61
|
flask-socketio = "^5.3"
|
|
@@ -122,7 +122,7 @@ warn_unused_ignores = true
|
|
|
122
122
|
|
|
123
123
|
[tool.commitizen]
|
|
124
124
|
name = "cz_conventional_commits"
|
|
125
|
-
version = "1.8.
|
|
125
|
+
version = "1.8.3"
|
|
126
126
|
changelog_start_rev = "v1.0.0"
|
|
127
127
|
tag_format = "v$major.$minor.$patch$prerelease"
|
|
128
128
|
# update_changelog_on_bump = true
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
from contextlib import contextmanager
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from functools import cached_property
|
|
4
|
+
import hashlib
|
|
5
|
+
import logging
|
|
6
|
+
import os
|
|
7
|
+
import struct
|
|
8
|
+
from typing import Optional
|
|
9
|
+
from experimaestro.core.objects import Config
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ConfigPath:
|
|
13
|
+
"""Used to keep track of cycles when computing a hash"""
|
|
14
|
+
|
|
15
|
+
def __init__(self):
|
|
16
|
+
self.loops: list[bool] = []
|
|
17
|
+
"""Indicates whether a loop was detected up to this node"""
|
|
18
|
+
|
|
19
|
+
self.config2index = {}
|
|
20
|
+
"""Associate an index in the list with a configuration"""
|
|
21
|
+
|
|
22
|
+
def detect_loop(self, config) -> Optional[int]:
|
|
23
|
+
"""If there is a loop, return the relative index and update the path"""
|
|
24
|
+
index = self.config2index.get(id(config), None)
|
|
25
|
+
if index is not None:
|
|
26
|
+
for i in range(index, self.depth):
|
|
27
|
+
self.loops[i] = True
|
|
28
|
+
return self.depth - index
|
|
29
|
+
return None
|
|
30
|
+
|
|
31
|
+
def has_loop(self):
|
|
32
|
+
return self.loops[-1]
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def depth(self):
|
|
36
|
+
return len(self.loops)
|
|
37
|
+
|
|
38
|
+
@contextmanager
|
|
39
|
+
def push(self, config):
|
|
40
|
+
config_id = id(config)
|
|
41
|
+
assert config_id not in self.config2index
|
|
42
|
+
|
|
43
|
+
self.config2index[config_id] = self.depth
|
|
44
|
+
self.loops.append(False)
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
yield
|
|
48
|
+
finally:
|
|
49
|
+
self.loops.pop()
|
|
50
|
+
del self.config2index[config_id]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
hash_logger = logging.getLogger("xpm.hash")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def is_ignored(value):
|
|
57
|
+
"""Returns True if the value should be ignored by itself"""
|
|
58
|
+
return value is not None and isinstance(value, Config) and (value.__xpm__.meta)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def remove_meta(value):
|
|
62
|
+
"""Cleanup a dict/list by removing ignored values"""
|
|
63
|
+
if isinstance(value, list):
|
|
64
|
+
return [el for el in value if not is_ignored(el)]
|
|
65
|
+
if isinstance(value, dict):
|
|
66
|
+
return {key: value for key, value in value.items() if not is_ignored(value)}
|
|
67
|
+
return value
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class Identifier:
|
|
71
|
+
def __init__(self, main: bytes):
|
|
72
|
+
self.main = main
|
|
73
|
+
self.has_loops = False
|
|
74
|
+
|
|
75
|
+
@cached_property
|
|
76
|
+
def all(self):
|
|
77
|
+
"""Returns the overall identifier"""
|
|
78
|
+
return self.main
|
|
79
|
+
|
|
80
|
+
def __hash__(self) -> int:
|
|
81
|
+
return hash(self.main)
|
|
82
|
+
|
|
83
|
+
def state_dict(self):
|
|
84
|
+
return self.main.hex()
|
|
85
|
+
|
|
86
|
+
def __eq__(self, other: object):
|
|
87
|
+
if not isinstance(other, Identifier):
|
|
88
|
+
return False
|
|
89
|
+
return self.main == other.main
|
|
90
|
+
|
|
91
|
+
@staticmethod
|
|
92
|
+
def from_state_dict(data: dict[str, str] | str):
|
|
93
|
+
if isinstance(data, str):
|
|
94
|
+
return Identifier(bytes.fromhex(data))
|
|
95
|
+
|
|
96
|
+
return Identifier(bytes.fromhex(data["main"]))
|
|
97
|
+
|
|
98
|
+
def __repr__(self):
|
|
99
|
+
return self.main.hex()
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class IdentifierComputer:
|
|
103
|
+
"""This class is in charge of computing a config/task identifier"""
|
|
104
|
+
|
|
105
|
+
OBJECT_ID = b"\x00"
|
|
106
|
+
INT_ID = b"\x01"
|
|
107
|
+
FLOAT_ID = b"\x02"
|
|
108
|
+
STR_ID = b"\x03"
|
|
109
|
+
PATH_ID = b"\x04"
|
|
110
|
+
NAME_ID = b"\x05"
|
|
111
|
+
NONE_ID = b"\x06"
|
|
112
|
+
LIST_ID = b"\x07"
|
|
113
|
+
TASK_ID = b"\x08"
|
|
114
|
+
DICT_ID = b"\x09"
|
|
115
|
+
ENUM_ID = b"\x0a"
|
|
116
|
+
CYCLE_REFERENCE = b"\x0b"
|
|
117
|
+
INIT_TASKS = b"\x0c"
|
|
118
|
+
|
|
119
|
+
def __init__(self, config: "Config", config_path: ConfigPath, *, version=None):
|
|
120
|
+
# Hasher for parameters
|
|
121
|
+
self._hasher = hashlib.sha256()
|
|
122
|
+
self.config = config
|
|
123
|
+
self.config_path = config_path
|
|
124
|
+
self.version = version or int(os.environ.get("XPM_HASH_COMPUTER", 2))
|
|
125
|
+
if hash_logger.isEnabledFor(logging.DEBUG):
|
|
126
|
+
hash_logger.debug(
|
|
127
|
+
"starting hash (%s): %s", hash(str(self.config)), self.config
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
def identifier(self) -> Identifier:
|
|
131
|
+
main = self._hasher.digest()
|
|
132
|
+
if hash_logger.isEnabledFor(logging.DEBUG):
|
|
133
|
+
hash_logger.debug("hash (%s): %s", hash(str(self.config)), str(main))
|
|
134
|
+
return Identifier(main)
|
|
135
|
+
|
|
136
|
+
def _hashupdate(self, bytes: bytes):
|
|
137
|
+
"""Update the hash computers with some bytes"""
|
|
138
|
+
if hash_logger.isEnabledFor(logging.DEBUG):
|
|
139
|
+
hash_logger.debug(
|
|
140
|
+
"updating hash (%s): %s", hash(str(self.config)), str(bytes)
|
|
141
|
+
)
|
|
142
|
+
self._hasher.update(bytes)
|
|
143
|
+
|
|
144
|
+
def update(self, value, *, myself=False): # noqa: C901
|
|
145
|
+
"""Update the hash
|
|
146
|
+
|
|
147
|
+
:param value: The value to add to the hash
|
|
148
|
+
:param myself: True if the value is the configuration for which we wish
|
|
149
|
+
to compute the identifier, defaults to False
|
|
150
|
+
:raises NotImplementedError: If the value cannot be processed
|
|
151
|
+
"""
|
|
152
|
+
if value is None:
|
|
153
|
+
self._hashupdate(IdentifierComputer.NONE_ID)
|
|
154
|
+
elif isinstance(value, float):
|
|
155
|
+
self._hashupdate(IdentifierComputer.FLOAT_ID)
|
|
156
|
+
self._hashupdate(struct.pack("!d", value))
|
|
157
|
+
elif isinstance(value, int):
|
|
158
|
+
self._hashupdate(IdentifierComputer.INT_ID)
|
|
159
|
+
self._hashupdate(struct.pack("!q", value))
|
|
160
|
+
elif isinstance(value, str):
|
|
161
|
+
self._hashupdate(IdentifierComputer.STR_ID)
|
|
162
|
+
self._hashupdate(value.encode("utf-8"))
|
|
163
|
+
elif isinstance(value, list):
|
|
164
|
+
values = [el for el in value if not is_ignored(el)]
|
|
165
|
+
self._hashupdate(IdentifierComputer.LIST_ID)
|
|
166
|
+
self._hashupdate(struct.pack("!d", len(values)))
|
|
167
|
+
for x in values:
|
|
168
|
+
self.update(x)
|
|
169
|
+
elif isinstance(value, Enum):
|
|
170
|
+
self._hashupdate(IdentifierComputer.ENUM_ID)
|
|
171
|
+
k = value.__class__
|
|
172
|
+
self._hashupdate(
|
|
173
|
+
f"{k.__module__}.{k.__qualname__ }:{value.name}".encode("utf-8"),
|
|
174
|
+
)
|
|
175
|
+
elif isinstance(value, dict):
|
|
176
|
+
self._hashupdate(IdentifierComputer.DICT_ID)
|
|
177
|
+
items = [
|
|
178
|
+
(key, value) for key, value in value.items() if not is_ignored(value)
|
|
179
|
+
]
|
|
180
|
+
items.sort(key=lambda x: x[0])
|
|
181
|
+
for key, value in items:
|
|
182
|
+
self.update(key)
|
|
183
|
+
self.update(value)
|
|
184
|
+
|
|
185
|
+
# Handles configurations
|
|
186
|
+
elif isinstance(value, Config):
|
|
187
|
+
# Encodes the identifier
|
|
188
|
+
self._hashupdate(IdentifierComputer.OBJECT_ID)
|
|
189
|
+
|
|
190
|
+
# If we encode another config, then
|
|
191
|
+
if not myself:
|
|
192
|
+
if loop_ix := self.config_path.detect_loop(value):
|
|
193
|
+
# Loop detected: use cycle reference
|
|
194
|
+
self._hashupdate(IdentifierComputer.CYCLE_REFERENCE)
|
|
195
|
+
self._hashupdate(struct.pack("!q", loop_ix))
|
|
196
|
+
|
|
197
|
+
else:
|
|
198
|
+
# Just use the object identifier
|
|
199
|
+
value_id = IdentifierComputer.compute(
|
|
200
|
+
value, version=self.version, config_path=self.config_path
|
|
201
|
+
)
|
|
202
|
+
self._hashupdate(value_id.all)
|
|
203
|
+
|
|
204
|
+
# And that's it!
|
|
205
|
+
return
|
|
206
|
+
|
|
207
|
+
# Process tasks
|
|
208
|
+
if value.__xpm__.task is not None and (value.__xpm__.task is not value):
|
|
209
|
+
hash_logger.debug("Computing hash for task %s", value.__xpm__.task)
|
|
210
|
+
self._hashupdate(IdentifierComputer.TASK_ID)
|
|
211
|
+
self.update(value.__xpm__.task)
|
|
212
|
+
|
|
213
|
+
xpmtype = value.__xpmtype__
|
|
214
|
+
self._hashupdate(xpmtype.identifier.name.encode("utf-8"))
|
|
215
|
+
|
|
216
|
+
# Process arguments (sort by name to ensure uniqueness)
|
|
217
|
+
arguments = sorted(xpmtype.arguments.values(), key=lambda a: a.name)
|
|
218
|
+
for argument in arguments:
|
|
219
|
+
# Ignored argument
|
|
220
|
+
if argument.ignored:
|
|
221
|
+
argvalue = value.__xpm__.values.get(argument.name, None)
|
|
222
|
+
|
|
223
|
+
# ... unless meta is set to false
|
|
224
|
+
if (
|
|
225
|
+
argvalue is None
|
|
226
|
+
or not isinstance(argvalue, Config)
|
|
227
|
+
or (argvalue.__xpm__.meta is not False)
|
|
228
|
+
):
|
|
229
|
+
continue
|
|
230
|
+
|
|
231
|
+
if argument.generator:
|
|
232
|
+
continue
|
|
233
|
+
|
|
234
|
+
# Argument value
|
|
235
|
+
# Skip if the argument is not a constant, and
|
|
236
|
+
# - optional argument: both value and default are None
|
|
237
|
+
# - the argument value is equal to the default value
|
|
238
|
+
argvalue = getattr(value, argument.name, None)
|
|
239
|
+
if not argument.constant and (
|
|
240
|
+
(
|
|
241
|
+
not argument.required
|
|
242
|
+
and argument.default is None
|
|
243
|
+
and argvalue is None
|
|
244
|
+
)
|
|
245
|
+
or (
|
|
246
|
+
argument.default is not None
|
|
247
|
+
and argument.default == remove_meta(argvalue)
|
|
248
|
+
)
|
|
249
|
+
):
|
|
250
|
+
# No update if same value (and not constant)
|
|
251
|
+
continue
|
|
252
|
+
|
|
253
|
+
if (
|
|
254
|
+
argvalue is not None
|
|
255
|
+
and isinstance(argvalue, Config)
|
|
256
|
+
and argvalue.__xpm__.meta
|
|
257
|
+
):
|
|
258
|
+
continue
|
|
259
|
+
|
|
260
|
+
# Hash name
|
|
261
|
+
self.update(argument.name)
|
|
262
|
+
|
|
263
|
+
# Hash value
|
|
264
|
+
self._hashupdate(IdentifierComputer.NAME_ID)
|
|
265
|
+
self.update(argvalue)
|
|
266
|
+
|
|
267
|
+
else:
|
|
268
|
+
raise NotImplementedError("Cannot compute hash of type %s" % type(value))
|
|
269
|
+
|
|
270
|
+
@staticmethod
|
|
271
|
+
def compute(
|
|
272
|
+
config: "Config", config_path: ConfigPath | None = None, version=None
|
|
273
|
+
) -> Identifier:
|
|
274
|
+
"""Compute the identifier for a configuration
|
|
275
|
+
|
|
276
|
+
:param config: the configuration for which we compute the identifier
|
|
277
|
+
:param config_path: used to track down cycles between configurations
|
|
278
|
+
:param version: version for the hash computation (None for the last one)
|
|
279
|
+
"""
|
|
280
|
+
|
|
281
|
+
# Try to use the cached value first
|
|
282
|
+
# (if there are no loops)
|
|
283
|
+
if config.__xpm__._sealed:
|
|
284
|
+
identifier = config.__xpm__._raw_identifier
|
|
285
|
+
if identifier is not None and not identifier.has_loops:
|
|
286
|
+
return identifier
|
|
287
|
+
|
|
288
|
+
config_path = config_path or ConfigPath()
|
|
289
|
+
|
|
290
|
+
with config_path.push(config):
|
|
291
|
+
self = IdentifierComputer(config, config_path, version=version)
|
|
292
|
+
self.update(config, myself=True)
|
|
293
|
+
identifier = self.identifier()
|
|
294
|
+
identifier.has_loops = config_path.has_loop()
|
|
295
|
+
|
|
296
|
+
return identifier
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from .config_walk import ConfigWalkContext, ConfigWalk
|
|
2
|
+
from .config import (
|
|
3
|
+
ConfigMixin,
|
|
4
|
+
Config,
|
|
5
|
+
ConfigInformation,
|
|
6
|
+
Task,
|
|
7
|
+
LightweightTask,
|
|
8
|
+
WatchedOutput,
|
|
9
|
+
DependentMarker,
|
|
10
|
+
copyconfig,
|
|
11
|
+
setmeta,
|
|
12
|
+
cache,
|
|
13
|
+
logger,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from .config_utils import (
|
|
17
|
+
getqualattr,
|
|
18
|
+
add_to_path,
|
|
19
|
+
ObjectStore,
|
|
20
|
+
SealedError,
|
|
21
|
+
TaggedValue,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"ConfigMixin",
|
|
27
|
+
"Config",
|
|
28
|
+
"ConfigInformation",
|
|
29
|
+
"ConfigWalkContext",
|
|
30
|
+
"ConfigWalk",
|
|
31
|
+
"Task",
|
|
32
|
+
"LightweightTask",
|
|
33
|
+
"ObjectStore",
|
|
34
|
+
"WatchedOutput",
|
|
35
|
+
"SealedError",
|
|
36
|
+
"DependentMarker",
|
|
37
|
+
"TaggedValue",
|
|
38
|
+
"getqualattr",
|
|
39
|
+
"copyconfig",
|
|
40
|
+
"setmeta",
|
|
41
|
+
"cache",
|
|
42
|
+
"add_to_path",
|
|
43
|
+
"logger",
|
|
44
|
+
]
|