experimaestro 0.21.0__zip → 0.23.0__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of experimaestro might be problematic. Click here for more details.
- {experimaestro-0.21.0 → experimaestro-0.23.0}/CHANGELOG.md +17 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/PKG-INFO +18 -1
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/Services.tsx +1 -1
- {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/experiments/plan.md +6 -6
- {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/index.md +2 -1
- {experimaestro-0.21.0 → experimaestro-0.23.0}/pyproject.toml +1 -1
- {experimaestro-0.21.0 → experimaestro-0.23.0}/requirements.txt +4 -3
- {experimaestro-0.21.0 → experimaestro-0.23.0}/setup.cfg +1 -1
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/__init__.py +5 -2
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/__main__.py +1 -1
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/annotations.py +31 -15
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/commandline.py +0 -8
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/core/objects.py +51 -35
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/core/objects.pyi +23 -10
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/core/types.py +44 -2
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/generators.py +7 -6
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/launchers/__init__.py +19 -7
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/scheduler/base.py +21 -3
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/server/__init__.py +12 -4
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/utils/__init__.py +12 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/utils/jobs.py +6 -3
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/utils/jupyter.py +14 -4
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/version.py +2 -2
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/xpmutils.py +3 -3
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro.egg-info/PKG-INFO +18 -1
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro.egg-info/requires.txt +5 -2
- {experimaestro-0.21.0 → experimaestro-0.23.0}/.circleci/config.yml +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/.flake8 +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/.github/release.yaml +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/.github/workflows/pytest.yml +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/.github/workflows/python-publish.yml +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/.gitignore +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/.gitmodules +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/.pre-commit-config.yaml +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/.prettierignore +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/.readthedocs.yml +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/LICENSE +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/MANIFEST.in +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/README.md +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/.gitignore +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/.nolluprc.js +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/CHANGELOG.md +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/README.md +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/package-lock.json +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/package.json +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/postcss.config.js +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/public/favicon.ico +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/public/index.html +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/public/login.html +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/public/manifest.json +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/App.tsx +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/Experiments.tsx +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/TaskDetail.tsx +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/TaskJobs.tsx +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/Tasks.tsx +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/client.ts +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/clipboard.ts +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/index.css +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/index.tsx +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/logo.png +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/logo.pxm +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/reducers.ts +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/store.ts +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/theme/_jobs.scss +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/theme/theme.scss +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/src/ui/messages.tsx +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/tsconfig.json +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/webpack.config.ts +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/app/xp/run.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/changelog.md +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/cli.md +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/concepts.md +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/configuration.md +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/connectors/index.md +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/documenting.md +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/experiments/config.md +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/experiments/overview.md +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/experiments/task.md +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/faq.md +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/jupyter.md +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/launchers/index.md +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/requirements.txt +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/serialization.md +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/docs/tutorial.md +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/mkdocs.yml +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/pytest.ini +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/scripts/longtask.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/setup.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/checkers.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/click.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/compat.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/connectors/__init__.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/connectors/local.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/connectors/ssh.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/core/__init__.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/core/arguments.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/core/context.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/filter.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/huggingface.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/ipc.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/launcherfinder/__init__.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/launcherfinder/base.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/launcherfinder/parser.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/launcherfinder/registry.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/launcherfinder/specs.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/launchers/direct.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/launchers/oar.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/launchers/slurm.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/locking.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/mkdocs/__init__.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/mkdocs/annotations.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/mkdocs/base.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/mkdocs/metaloader.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/mkdocs/style.css +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/mypy.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/notifications.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/rpyc.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/run.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/scheduler/__init__.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/scheduler/dependencies.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/scheduler/environment.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/scheduler/services.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/scheduler/workspace.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/scriptbuilder.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/settings.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/sphinx/__init__.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/sphinx/static/experimaestro.css +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/taskglobals.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/__init__.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/conftest.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/connectors/bin/executable.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/connectors/test_local.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/connectors/utils.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/definitions_types.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/launchers/__init__.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/launchers/bin/sacct +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/launchers/bin/sbatch +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/launchers/bin/test.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/launchers/common.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/launchers/config_slurm/__init__.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/launchers/config_slurm/launchers.yaml +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/launchers/test_local.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/launchers/test_slurm.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/restart.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/restart_main.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/scripts/notifyandwait.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/scripts/waitforfile.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/task_tokens.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/tasks/__init__.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/tasks/all.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/tasks/foreign.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/tasks/subparams.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_checkers.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_findlauncher.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_forward.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_identifier.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_instance.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_objects.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_outputs.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_param.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_progress.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_serialization.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_snippets.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_ssh.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_tags.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_tasks.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_tokens.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_types.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/test_validation.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/token_reschedule.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tests/utils.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tokens.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tools/__init__.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tools/diff.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/tools/jobs.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/typingutils.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/utils/asyncio.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/utils/resources.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/utils/settings.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro/utils/yaml.py +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro.egg-info/SOURCES.txt +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro.egg-info/dependency_links.txt +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro.egg-info/entry_points.txt +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro.egg-info/not-zip-safe +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/src/experimaestro.egg-info/top_level.txt +0 -0
- {experimaestro-0.21.0 → experimaestro-0.23.0}/tox.ini +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
1
2
|
import inspect
|
|
2
3
|
import sys
|
|
3
|
-
from typing import Union, Dict, Iterator, List
|
|
4
|
+
from typing import Set, Union, Dict, Iterator, List
|
|
4
5
|
from collections import ChainMap
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
import typing
|
|
@@ -17,6 +18,11 @@ if sys.version_info.major == 3 and sys.version_info.minor < 9:
|
|
|
17
18
|
else:
|
|
18
19
|
from typing import _AnnotatedAlias, get_type_hints
|
|
19
20
|
|
|
21
|
+
if typing.TYPE_CHECKING:
|
|
22
|
+
from experimaestro.scheduler.base import Job
|
|
23
|
+
from experimaestro.launchers import Launcher
|
|
24
|
+
from experimaestro.core.objects import Config
|
|
25
|
+
|
|
20
26
|
|
|
21
27
|
class Identifier:
|
|
22
28
|
def __init__(self, name: str):
|
|
@@ -143,7 +149,42 @@ class DeprecatedAttribute:
|
|
|
143
149
|
self.fn(instance, value)
|
|
144
150
|
|
|
145
151
|
|
|
152
|
+
class SubmitHook(ABC):
|
|
153
|
+
"""Hook called before the job is submitted to the scheduler
|
|
154
|
+
|
|
155
|
+
This allows modifying e.g. the run environnement
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
@abstractmethod
|
|
159
|
+
def __call__(self, job: "Job", launcher: "Launcher"):
|
|
160
|
+
...
|
|
161
|
+
|
|
162
|
+
@abstractmethod
|
|
163
|
+
def __spec__(self):
|
|
164
|
+
"""Returns an identifier tuple for hashing/equality"""
|
|
165
|
+
...
|
|
166
|
+
|
|
167
|
+
def __eq__(self, other):
|
|
168
|
+
if other.__class__ is not self.__class__:
|
|
169
|
+
return False
|
|
170
|
+
return self.__spec__ == other.__spec__
|
|
171
|
+
|
|
172
|
+
def __hash__(self):
|
|
173
|
+
return hash((self.__class__, self.__spec__))
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def submit_hook_decorator(hook: SubmitHook):
|
|
177
|
+
def decorator(cls: typing.Type["Config"]):
|
|
178
|
+
cls.__getxpmtype__().submit_hooks.add(hook)
|
|
179
|
+
return cls
|
|
180
|
+
|
|
181
|
+
return decorator
|
|
182
|
+
|
|
183
|
+
|
|
146
184
|
class ObjectType(Type):
|
|
185
|
+
submit_hooks: Set[SubmitHook]
|
|
186
|
+
"""Hooks associated with this configuration"""
|
|
187
|
+
|
|
147
188
|
"""ObjectType contains class-level information about
|
|
148
189
|
experimaestro configurations and tasks
|
|
149
190
|
|
|
@@ -167,6 +208,7 @@ class ObjectType(Type):
|
|
|
167
208
|
self.taskcommandfactory = None
|
|
168
209
|
self.task = None
|
|
169
210
|
self._title = None
|
|
211
|
+
self.submit_hooks = set()
|
|
170
212
|
|
|
171
213
|
# Get the identifier
|
|
172
214
|
if identifier is None and hasattr(tp, "__xpmid__"):
|
|
@@ -219,7 +261,7 @@ class ObjectType(Type):
|
|
|
219
261
|
self.configtype.__module__ = tp.__module__
|
|
220
262
|
|
|
221
263
|
# Create the type-specific object class
|
|
222
|
-
# (now, the same as basetype -
|
|
264
|
+
# (now, the same as basetype - but in the future, remove references)
|
|
223
265
|
self.objecttype = self.basetype # type: type
|
|
224
266
|
self.basetype._ = self.configtype
|
|
225
267
|
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import inspect
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
from typing import Callable,
|
|
3
|
+
from typing import Callable, Union
|
|
4
4
|
from experimaestro.core.arguments import ArgumentOptions, TypeAnnotation
|
|
5
|
-
from experimaestro.core.objects import
|
|
5
|
+
from experimaestro.core.objects import ConfigWalkContext, Config
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class Generator:
|
|
9
9
|
"""Base class for all generators"""
|
|
10
10
|
|
|
11
11
|
def isoutput(self):
|
|
12
|
-
"""Returns True if this generator is a task output (e.g. generates a
|
|
12
|
+
"""Returns True if this generator is a task output (e.g. generates a
|
|
13
|
+
path within the job folder)"""
|
|
13
14
|
return False
|
|
14
15
|
|
|
15
16
|
|
|
@@ -17,11 +18,11 @@ class PathGenerator(Generator):
|
|
|
17
18
|
"""Generates a path"""
|
|
18
19
|
|
|
19
20
|
def __init__(
|
|
20
|
-
self, path: Union[str, Path, Callable[[
|
|
21
|
+
self, path: Union[str, Path, Callable[[ConfigWalkContext, Config], Path]]
|
|
21
22
|
):
|
|
22
23
|
self.path = path
|
|
23
24
|
|
|
24
|
-
def __call__(self, context:
|
|
25
|
+
def __call__(self, context: ConfigWalkContext, config: Config):
|
|
25
26
|
if inspect.isfunction(self.path):
|
|
26
27
|
path = context.currentpath() / self.path(context, config) # type: Path
|
|
27
28
|
else:
|
|
@@ -34,7 +35,7 @@ class PathGenerator(Generator):
|
|
|
34
35
|
|
|
35
36
|
|
|
36
37
|
class pathgenerator(TypeAnnotation):
|
|
37
|
-
def __init__(self, value: Union[str, Callable[[
|
|
38
|
+
def __init__(self, value: Union[str, Callable[[ConfigWalkContext, Config], str]]):
|
|
38
39
|
self.value = value
|
|
39
40
|
|
|
40
41
|
def annotate(self, options: ArgumentOptions):
|
|
@@ -1,25 +1,36 @@
|
|
|
1
1
|
from pathlib import Path, PosixPath
|
|
2
|
-
from typing import Callable, Dict, List, Optional
|
|
2
|
+
from typing import Callable, Dict, List, Optional
|
|
3
3
|
from experimaestro.commandline import AbstractCommand, Job, CommandLineJob
|
|
4
4
|
from experimaestro.connectors import Connector
|
|
5
5
|
from experimaestro.connectors.local import ProcessBuilder, LocalConnector
|
|
6
6
|
from experimaestro.connectors.ssh import SshPath, SshConnector
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
7
8
|
|
|
8
9
|
|
|
9
|
-
class ScriptBuilder:
|
|
10
|
-
lockfiles: List[Path]
|
|
11
|
-
command: "AbstractCommand"
|
|
10
|
+
class ScriptBuilder(ABC):
|
|
12
11
|
"""A script builder is responsible for generating the script
|
|
13
12
|
used to launch a command line job"""
|
|
14
13
|
|
|
14
|
+
lockfiles: List[Path]
|
|
15
|
+
"""The files that must be locked before starting the job"""
|
|
16
|
+
|
|
17
|
+
command: "AbstractCommand"
|
|
18
|
+
"""Command to be run"""
|
|
19
|
+
|
|
20
|
+
@abstractmethod
|
|
15
21
|
def write(self, job: CommandLineJob) -> Path:
|
|
16
|
-
|
|
22
|
+
"""Write the commmand line job
|
|
23
|
+
|
|
24
|
+
:params job: The job to be written
|
|
25
|
+
"""
|
|
26
|
+
...
|
|
17
27
|
|
|
18
28
|
|
|
19
29
|
SubmitListener = Callable[[Job], None]
|
|
30
|
+
"""Listen to job submissions"""
|
|
20
31
|
|
|
21
32
|
|
|
22
|
-
class Launcher:
|
|
33
|
+
class Launcher(ABC):
|
|
23
34
|
"""A launcher"""
|
|
24
35
|
|
|
25
36
|
submit_listeners: List[SubmitListener]
|
|
@@ -36,9 +47,10 @@ class Launcher:
|
|
|
36
47
|
def setNotificationURL(self, url: Optional[str]):
|
|
37
48
|
self.notificationURL = url
|
|
38
49
|
|
|
50
|
+
@abstractmethod
|
|
39
51
|
def scriptbuilder(self) -> ScriptBuilder:
|
|
40
52
|
"""Returns a script builder"""
|
|
41
|
-
|
|
53
|
+
...
|
|
42
54
|
|
|
43
55
|
def addListener(self, listener: SubmitListener):
|
|
44
56
|
self.submit_listeners.append(listener)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from collections import defaultdict
|
|
1
|
+
from collections import ChainMap, defaultdict
|
|
2
2
|
import os
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from shutil import rmtree
|
|
@@ -14,7 +14,7 @@ from experimaestro.scheduler.services import Service
|
|
|
14
14
|
from experimaestro.settings import get_settings
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
from experimaestro.core.objects import Config,
|
|
17
|
+
from experimaestro.core.objects import Config, ConfigWalkContext
|
|
18
18
|
from experimaestro.utils import logger
|
|
19
19
|
from experimaestro.locking import Locks, LockError, Lock
|
|
20
20
|
from experimaestro.tokens import ProcessCounterToken
|
|
@@ -151,6 +151,23 @@ class Job(Resource):
|
|
|
151
151
|
assert self._future, "Cannot wait a not submitted job"
|
|
152
152
|
return self._future.result()
|
|
153
153
|
|
|
154
|
+
@property
|
|
155
|
+
def environ(self):
|
|
156
|
+
"""Returns the job environment
|
|
157
|
+
|
|
158
|
+
It is made of (by order of priority):
|
|
159
|
+
|
|
160
|
+
1. The job environment
|
|
161
|
+
1. The launcher environment
|
|
162
|
+
1. The workspace environment
|
|
163
|
+
|
|
164
|
+
"""
|
|
165
|
+
return ChainMap(
|
|
166
|
+
{},
|
|
167
|
+
self.launcher.environ if self.launcher else {},
|
|
168
|
+
self.workspace.environment.environ,
|
|
169
|
+
)
|
|
170
|
+
|
|
154
171
|
@property
|
|
155
172
|
def progress(self):
|
|
156
173
|
return self._progress
|
|
@@ -292,7 +309,7 @@ class Job(Resource):
|
|
|
292
309
|
return self._future
|
|
293
310
|
|
|
294
311
|
|
|
295
|
-
class JobContext(
|
|
312
|
+
class JobContext(ConfigWalkContext):
|
|
296
313
|
def __init__(self, job: Job):
|
|
297
314
|
super().__init__()
|
|
298
315
|
self.job = job
|
|
@@ -839,6 +856,7 @@ class experiment:
|
|
|
839
856
|
def __enter__(self):
|
|
840
857
|
logger.info("Locking experiment %s", self.xplockpath)
|
|
841
858
|
self.xplock = self.workspace.connector.lock(self.xplockpath, 0).__enter__()
|
|
859
|
+
logger.info("Experiment locked")
|
|
842
860
|
|
|
843
861
|
# Move old jobs into "jobs.bak"
|
|
844
862
|
if self.workspace.run_mode == RunMode.NORMAL:
|
|
@@ -90,7 +90,7 @@ class Listener(BaseListener, ServiceListener):
|
|
|
90
90
|
)
|
|
91
91
|
|
|
92
92
|
def service_state_changed(self, service: Service):
|
|
93
|
-
self.socketio.emit("service.update", {"state": service.state})
|
|
93
|
+
self.socketio.emit("service.update", {"state": service.state.name})
|
|
94
94
|
|
|
95
95
|
|
|
96
96
|
MIMETYPES = {
|
|
@@ -143,10 +143,15 @@ def proxy_response(base_url: str, request: Request, path: str):
|
|
|
143
143
|
|
|
144
144
|
|
|
145
145
|
def start_app(server: "Server"):
|
|
146
|
+
logging.debug("Starting Flask server...")
|
|
146
147
|
app = Flask("experimaestro")
|
|
147
|
-
|
|
148
|
+
|
|
149
|
+
logging.debug("Starting Flask server (SocketIO)...")
|
|
150
|
+
socketio = SocketIO(app, path="/api", async_mode="gevent")
|
|
148
151
|
listener = Listener(server.scheduler, socketio)
|
|
149
152
|
|
|
153
|
+
logging.debug("Starting Flask server (setting up socketio)...")
|
|
154
|
+
|
|
150
155
|
@socketio.on("connect")
|
|
151
156
|
def handle_connect():
|
|
152
157
|
if server.token != request.cookies.get("experimaestro_token", None):
|
|
@@ -183,6 +188,8 @@ def start_app(server: "Server"):
|
|
|
183
188
|
if process is not None:
|
|
184
189
|
process.kill()
|
|
185
190
|
|
|
191
|
+
logging.debug("Starting Flask server (setting up routes)...")
|
|
192
|
+
|
|
186
193
|
@app.route("/services/<path:path>", methods=["GET", "POST"])
|
|
187
194
|
def route_service(path):
|
|
188
195
|
service, *path = path.split("/", 1)
|
|
@@ -256,13 +263,14 @@ def start_app(server: "Server"):
|
|
|
256
263
|
|
|
257
264
|
# Start the app
|
|
258
265
|
if server.port is None or server.port == 0:
|
|
266
|
+
logging.info("Searching for an available port")
|
|
259
267
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
260
|
-
sock.bind(("
|
|
268
|
+
sock.bind(("", 0))
|
|
261
269
|
server.port = sock.getsockname()[1]
|
|
262
270
|
sock.close()
|
|
263
271
|
|
|
264
272
|
logging.info(
|
|
265
|
-
"Web server started on http://%s:%d?token=%s",
|
|
273
|
+
"Web server started on http://%s:%d/auth?xpm-token=%s",
|
|
266
274
|
server.host,
|
|
267
275
|
server.port,
|
|
268
276
|
server.token,
|
|
@@ -27,6 +27,18 @@ def cleanupdir(path: Path):
|
|
|
27
27
|
return path
|
|
28
28
|
|
|
29
29
|
|
|
30
|
+
def is_notebook():
|
|
31
|
+
"""Returns true if running in a notebook"""
|
|
32
|
+
try:
|
|
33
|
+
shell = get_ipython().__class__.__module__ # noqa: F841
|
|
34
|
+
if shell is not None and shell in ["ipykernel.zmqshell", "google.colab._shell"]:
|
|
35
|
+
return True
|
|
36
|
+
except NameError:
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
return False
|
|
40
|
+
|
|
41
|
+
|
|
30
42
|
class ThreadingCondition(threading.Condition):
|
|
31
43
|
# Useful to debug lock problems
|
|
32
44
|
TIMEOUT = float(os.environ.get("XPM_LOCK_TIMEOUT", "-1"))
|
|
@@ -21,6 +21,7 @@ def jobmonitor(*outputs: TaskOutput):
|
|
|
21
21
|
|
|
22
22
|
for output in outputs:
|
|
23
23
|
try:
|
|
24
|
+
job = None
|
|
24
25
|
job = output.__xpm__.job
|
|
25
26
|
lastprogress = 0
|
|
26
27
|
while job.scheduler is None:
|
|
@@ -34,7 +35,7 @@ def jobmonitor(*outputs: TaskOutput):
|
|
|
34
35
|
|
|
35
36
|
# Job already completed
|
|
36
37
|
if job.state.value == JobState.DONE.value:
|
|
37
|
-
print("Job already completed")
|
|
38
|
+
print("Job already completed") # noqa: T201
|
|
38
39
|
else:
|
|
39
40
|
with tqdm(total=100, unit_scale=True, unit="%") as reporter:
|
|
40
41
|
progress = 0
|
|
@@ -60,8 +61,10 @@ def jobmonitor(*outputs: TaskOutput):
|
|
|
60
61
|
reporter.update(100 - progress)
|
|
61
62
|
else:
|
|
62
63
|
raise RuntimeError(
|
|
63
|
-
f"Job did not complete successfully ({job.state.name}).
|
|
64
|
+
f"Job did not complete successfully ({job.state.name})."
|
|
65
|
+
f"Check the error log {job.stderr}"
|
|
64
66
|
)
|
|
65
67
|
|
|
66
68
|
finally:
|
|
67
|
-
job
|
|
69
|
+
if job is not None:
|
|
70
|
+
job.scheduler.removelistener(listener)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from typing import Callable, Dict, Optional
|
|
2
|
+
import uuid
|
|
2
3
|
import ipywidgets as widgets
|
|
3
4
|
from experimaestro import experiment
|
|
4
5
|
from IPython.display import display
|
|
@@ -6,6 +7,8 @@ from .jobs import jobmonitor # noqa: F401
|
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class serverwidget:
|
|
10
|
+
TOKEN = uuid.uuid4().hex
|
|
11
|
+
|
|
9
12
|
def __init__(
|
|
10
13
|
self,
|
|
11
14
|
name,
|
|
@@ -32,10 +35,13 @@ class serverwidget:
|
|
|
32
35
|
with self.output:
|
|
33
36
|
if experiment.CURRENT:
|
|
34
37
|
self.button.description = "Stop experimaestro server"
|
|
35
|
-
print(
|
|
38
|
+
print( # noqa: T201
|
|
39
|
+
"Server started : "
|
|
40
|
+
f"http://localhost:{self.port}/auth?xpm-token={serverwidget.TOKEN}"
|
|
41
|
+
)
|
|
36
42
|
else:
|
|
37
43
|
self.button.description = "Start experimaestro server"
|
|
38
|
-
print("Server stopped")
|
|
44
|
+
print("Server stopped") # noqa: T201
|
|
39
45
|
|
|
40
46
|
def on_button_clicked(self, b):
|
|
41
47
|
with self.output:
|
|
@@ -43,11 +49,15 @@ class serverwidget:
|
|
|
43
49
|
try:
|
|
44
50
|
experiment.CURRENT.__exit__(None, None, None)
|
|
45
51
|
except Exception:
|
|
46
|
-
print("Error while stopping experimaestro")
|
|
52
|
+
print("Error while stopping experimaestro") # noqa: T201
|
|
47
53
|
self.current = experiment.CURRENT
|
|
48
54
|
else:
|
|
49
55
|
self.current = experiment(
|
|
50
|
-
self.name,
|
|
56
|
+
self.name,
|
|
57
|
+
self.name,
|
|
58
|
+
host="localhost",
|
|
59
|
+
port=self.port,
|
|
60
|
+
token=serverwidget.TOKEN,
|
|
51
61
|
).__enter__()
|
|
52
62
|
for key, value in self.environment.items():
|
|
53
63
|
self.current.setenv(key, value)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"""Utilities exposed to users of the experimaestro API"""
|
|
2
2
|
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from experimaestro.core.objects import
|
|
4
|
+
from experimaestro.core.objects import ConfigWalkContext
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
class DirectoryContext(
|
|
7
|
+
class DirectoryContext(ConfigWalkContext):
|
|
8
8
|
"""Special generation context used for debugging and testing"""
|
|
9
9
|
|
|
10
10
|
def __init__(self, path: Path):
|
|
@@ -16,7 +16,7 @@ class DirectoryContext(GenerationContext):
|
|
|
16
16
|
return self._path
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
class EmptyContext(
|
|
19
|
+
class EmptyContext(ConfigWalkContext):
|
|
20
20
|
"""Special generation context used for debugging and testing"""
|
|
21
21
|
|
|
22
22
|
@property
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: experimaestro
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.23.0
|
|
4
4
|
Summary: "Experimaestro is a computer science experiment manager"
|
|
5
5
|
Home-page: https://github.com/experimaestro/experimaestro-python
|
|
6
6
|
Author: Benjamin Piwowarski
|
|
@@ -127,6 +127,23 @@ if __name__ == "__main__":
|
|
|
127
127
|
|
|
128
128
|
which can be launched with `python test.py /tmp/helloworld-workdir`
|
|
129
129
|
|
|
130
|
+
## 0.23.0 (2023-04-07)
|
|
131
|
+
|
|
132
|
+
### Feat
|
|
133
|
+
|
|
134
|
+
- submit hooks to allow e.g. changing the environment variables
|
|
135
|
+
|
|
136
|
+
## 0.22.0 (2023-04-05)
|
|
137
|
+
|
|
138
|
+
### Feat
|
|
139
|
+
|
|
140
|
+
- tags as immutable and hashable dicts
|
|
141
|
+
|
|
142
|
+
### Fix
|
|
143
|
+
|
|
144
|
+
- corrected service status update for servers
|
|
145
|
+
- improved server
|
|
146
|
+
|
|
130
147
|
## 0.21.0 (2023-03-28)
|
|
131
148
|
|
|
132
149
|
### Feat
|
|
@@ -8,10 +8,11 @@ tqdm
|
|
|
8
8
|
docstring_parser
|
|
9
9
|
termcolor>=2.0.0
|
|
10
10
|
requests
|
|
11
|
+
sortedcontainers
|
|
11
12
|
pyparsing
|
|
12
13
|
humanfriendly
|
|
13
14
|
huggingface_hub~=0.11.1
|
|
14
|
-
|
|
15
|
+
gevent
|
|
15
16
|
flask
|
|
16
17
|
flask-socketio
|
|
17
18
|
Arpeggio>=2.0
|
|
@@ -20,8 +21,10 @@ marshmallow
|
|
|
20
21
|
fabric
|
|
21
22
|
rpyc
|
|
22
23
|
|
|
24
|
+
[:python_version < "3.11"]
|
|
25
|
+
typing_extensions>=4.2
|
|
26
|
+
|
|
23
27
|
[:python_version < "3.9"]
|
|
24
|
-
typing_extensions>=3.7.4.3
|
|
25
28
|
cached_property
|
|
26
29
|
|
|
27
30
|
[dev]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|