experimaestro 0.23.0__zip → 0.24.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.

Files changed (189) hide show
  1. {experimaestro-0.23.0 → experimaestro-0.24.0}/CHANGELOG.md +15 -0
  2. {experimaestro-0.23.0 → experimaestro-0.24.0}/PKG-INFO +16 -1
  3. {experimaestro-0.23.0 → experimaestro-0.24.0}/docs/experiments/task.md +45 -7
  4. {experimaestro-0.23.0 → experimaestro-0.24.0}/pyproject.toml +1 -1
  5. {experimaestro-0.23.0 → experimaestro-0.24.0}/requirements.txt +3 -0
  6. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/__init__.py +3 -3
  7. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/__main__.py +2 -2
  8. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/core/objects.py +167 -129
  9. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/core/objects.pyi +2 -1
  10. experimaestro-0.24.0/src/experimaestro/core/serializers.py +52 -0
  11. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/huggingface.py +2 -2
  12. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/test_identifier.py +33 -6
  13. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/test_instance.py +18 -15
  14. experimaestro-0.24.0/src/experimaestro/tests/test_outputs.py +50 -0
  15. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/test_progress.py +7 -9
  16. experimaestro-0.24.0/src/experimaestro/tests/test_serializers.py +54 -0
  17. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/utils/jobs.py +2 -2
  18. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/version.py +2 -2
  19. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro.egg-info/PKG-INFO +16 -1
  20. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro.egg-info/SOURCES.txt +2 -1
  21. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro.egg-info/requires.txt +2 -0
  22. experimaestro-0.23.0/src/experimaestro/tests/test_outputs.py +0 -88
  23. experimaestro-0.23.0/src/experimaestro/tests/test_serialization.py +0 -45
  24. {experimaestro-0.23.0 → experimaestro-0.24.0}/.circleci/config.yml +0 -0
  25. {experimaestro-0.23.0 → experimaestro-0.24.0}/.flake8 +0 -0
  26. {experimaestro-0.23.0 → experimaestro-0.24.0}/.github/release.yaml +0 -0
  27. {experimaestro-0.23.0 → experimaestro-0.24.0}/.github/workflows/pytest.yml +0 -0
  28. {experimaestro-0.23.0 → experimaestro-0.24.0}/.github/workflows/python-publish.yml +0 -0
  29. {experimaestro-0.23.0 → experimaestro-0.24.0}/.gitignore +0 -0
  30. {experimaestro-0.23.0 → experimaestro-0.24.0}/.gitmodules +0 -0
  31. {experimaestro-0.23.0 → experimaestro-0.24.0}/.pre-commit-config.yaml +0 -0
  32. {experimaestro-0.23.0 → experimaestro-0.24.0}/.prettierignore +0 -0
  33. {experimaestro-0.23.0 → experimaestro-0.24.0}/.readthedocs.yml +0 -0
  34. {experimaestro-0.23.0 → experimaestro-0.24.0}/LICENSE +0 -0
  35. {experimaestro-0.23.0 → experimaestro-0.24.0}/MANIFEST.in +0 -0
  36. {experimaestro-0.23.0 → experimaestro-0.24.0}/README.md +0 -0
  37. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/.gitignore +0 -0
  38. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/.nolluprc.js +0 -0
  39. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/CHANGELOG.md +0 -0
  40. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/README.md +0 -0
  41. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/package-lock.json +0 -0
  42. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/package.json +0 -0
  43. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/postcss.config.js +0 -0
  44. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/public/favicon.ico +0 -0
  45. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/public/index.html +0 -0
  46. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/public/login.html +0 -0
  47. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/public/manifest.json +0 -0
  48. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/src/App.tsx +0 -0
  49. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/src/Experiments.tsx +0 -0
  50. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/src/Services.tsx +0 -0
  51. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/src/TaskDetail.tsx +0 -0
  52. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/src/TaskJobs.tsx +0 -0
  53. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/src/Tasks.tsx +0 -0
  54. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/src/client.ts +0 -0
  55. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/src/clipboard.ts +0 -0
  56. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/src/index.css +0 -0
  57. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/src/index.tsx +0 -0
  58. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/src/logo.png +0 -0
  59. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/src/logo.pxm +0 -0
  60. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/src/reducers.ts +0 -0
  61. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/src/store.ts +0 -0
  62. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/src/theme/_jobs.scss +0 -0
  63. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/src/theme/theme.scss +0 -0
  64. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/src/ui/messages.tsx +0 -0
  65. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/tsconfig.json +0 -0
  66. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/webpack.config.ts +0 -0
  67. {experimaestro-0.23.0 → experimaestro-0.24.0}/app/xp/run.py +0 -0
  68. {experimaestro-0.23.0 → experimaestro-0.24.0}/docs/changelog.md +0 -0
  69. {experimaestro-0.23.0 → experimaestro-0.24.0}/docs/cli.md +0 -0
  70. {experimaestro-0.23.0 → experimaestro-0.24.0}/docs/concepts.md +0 -0
  71. {experimaestro-0.23.0 → experimaestro-0.24.0}/docs/configuration.md +0 -0
  72. {experimaestro-0.23.0 → experimaestro-0.24.0}/docs/connectors/index.md +0 -0
  73. {experimaestro-0.23.0 → experimaestro-0.24.0}/docs/documenting.md +0 -0
  74. {experimaestro-0.23.0 → experimaestro-0.24.0}/docs/experiments/config.md +0 -0
  75. {experimaestro-0.23.0 → experimaestro-0.24.0}/docs/experiments/overview.md +0 -0
  76. {experimaestro-0.23.0 → experimaestro-0.24.0}/docs/experiments/plan.md +0 -0
  77. {experimaestro-0.23.0 → experimaestro-0.24.0}/docs/faq.md +0 -0
  78. {experimaestro-0.23.0 → experimaestro-0.24.0}/docs/index.md +0 -0
  79. {experimaestro-0.23.0 → experimaestro-0.24.0}/docs/jupyter.md +0 -0
  80. {experimaestro-0.23.0 → experimaestro-0.24.0}/docs/launchers/index.md +0 -0
  81. {experimaestro-0.23.0 → experimaestro-0.24.0}/docs/requirements.txt +0 -0
  82. {experimaestro-0.23.0 → experimaestro-0.24.0}/docs/serialization.md +0 -0
  83. {experimaestro-0.23.0 → experimaestro-0.24.0}/docs/tutorial.md +0 -0
  84. {experimaestro-0.23.0 → experimaestro-0.24.0}/mkdocs.yml +0 -0
  85. {experimaestro-0.23.0 → experimaestro-0.24.0}/pytest.ini +0 -0
  86. {experimaestro-0.23.0 → experimaestro-0.24.0}/scripts/longtask.py +0 -0
  87. {experimaestro-0.23.0 → experimaestro-0.24.0}/setup.cfg +0 -0
  88. {experimaestro-0.23.0 → experimaestro-0.24.0}/setup.py +0 -0
  89. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/annotations.py +0 -0
  90. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/checkers.py +0 -0
  91. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/click.py +0 -0
  92. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/commandline.py +0 -0
  93. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/compat.py +0 -0
  94. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/connectors/__init__.py +0 -0
  95. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/connectors/local.py +0 -0
  96. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/connectors/ssh.py +0 -0
  97. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/core/__init__.py +0 -0
  98. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/core/arguments.py +0 -0
  99. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/core/context.py +0 -0
  100. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/core/types.py +0 -0
  101. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/filter.py +0 -0
  102. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/generators.py +0 -0
  103. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/ipc.py +0 -0
  104. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/launcherfinder/__init__.py +0 -0
  105. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/launcherfinder/base.py +0 -0
  106. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/launcherfinder/parser.py +0 -0
  107. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/launcherfinder/registry.py +0 -0
  108. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/launcherfinder/specs.py +0 -0
  109. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/launchers/__init__.py +0 -0
  110. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/launchers/direct.py +0 -0
  111. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/launchers/oar.py +0 -0
  112. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/launchers/slurm.py +0 -0
  113. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/locking.py +0 -0
  114. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/mkdocs/__init__.py +0 -0
  115. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/mkdocs/annotations.py +0 -0
  116. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/mkdocs/base.py +0 -0
  117. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/mkdocs/metaloader.py +0 -0
  118. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/mkdocs/style.css +0 -0
  119. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/mypy.py +0 -0
  120. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/notifications.py +0 -0
  121. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/rpyc.py +0 -0
  122. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/run.py +0 -0
  123. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/scheduler/__init__.py +0 -0
  124. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/scheduler/base.py +0 -0
  125. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/scheduler/dependencies.py +0 -0
  126. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/scheduler/environment.py +0 -0
  127. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/scheduler/services.py +0 -0
  128. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/scheduler/workspace.py +0 -0
  129. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/scriptbuilder.py +0 -0
  130. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/server/__init__.py +0 -0
  131. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/settings.py +0 -0
  132. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/sphinx/__init__.py +0 -0
  133. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/sphinx/static/experimaestro.css +0 -0
  134. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/taskglobals.py +0 -0
  135. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/__init__.py +0 -0
  136. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/conftest.py +0 -0
  137. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/connectors/bin/executable.py +0 -0
  138. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/connectors/test_local.py +0 -0
  139. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/connectors/utils.py +0 -0
  140. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/definitions_types.py +0 -0
  141. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/launchers/__init__.py +0 -0
  142. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/launchers/bin/sacct +0 -0
  143. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/launchers/bin/sbatch +0 -0
  144. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/launchers/bin/test.py +0 -0
  145. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/launchers/common.py +0 -0
  146. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/launchers/config_slurm/__init__.py +0 -0
  147. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/launchers/config_slurm/launchers.yaml +0 -0
  148. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/launchers/test_local.py +0 -0
  149. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/launchers/test_slurm.py +0 -0
  150. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/restart.py +0 -0
  151. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/restart_main.py +0 -0
  152. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/scripts/notifyandwait.py +0 -0
  153. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/scripts/waitforfile.py +0 -0
  154. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/task_tokens.py +0 -0
  155. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/tasks/__init__.py +0 -0
  156. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/tasks/all.py +0 -0
  157. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/tasks/foreign.py +0 -0
  158. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/tasks/subparams.py +0 -0
  159. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/test_checkers.py +0 -0
  160. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/test_findlauncher.py +0 -0
  161. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/test_forward.py +0 -0
  162. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/test_objects.py +0 -0
  163. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/test_param.py +0 -0
  164. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/test_snippets.py +0 -0
  165. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/test_ssh.py +0 -0
  166. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/test_tags.py +0 -0
  167. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/test_tasks.py +0 -0
  168. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/test_tokens.py +0 -0
  169. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/test_types.py +0 -0
  170. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/test_validation.py +0 -0
  171. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/token_reschedule.py +0 -0
  172. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tests/utils.py +0 -0
  173. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tokens.py +0 -0
  174. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tools/__init__.py +0 -0
  175. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tools/diff.py +0 -0
  176. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/tools/jobs.py +0 -0
  177. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/typingutils.py +0 -0
  178. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/utils/__init__.py +0 -0
  179. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/utils/asyncio.py +0 -0
  180. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/utils/jupyter.py +0 -0
  181. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/utils/resources.py +0 -0
  182. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/utils/settings.py +0 -0
  183. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/utils/yaml.py +0 -0
  184. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro/xpmutils.py +0 -0
  185. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro.egg-info/dependency_links.txt +0 -0
  186. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro.egg-info/entry_points.txt +0 -0
  187. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro.egg-info/not-zip-safe +0 -0
  188. {experimaestro-0.23.0 → experimaestro-0.24.0}/src/experimaestro.egg-info/top_level.txt +0 -0
  189. {experimaestro-0.23.0 → experimaestro-0.24.0}/tox.ini +0 -0
@@ -2,6 +2,12 @@
2
2
 
3
3
  from functools import cached_property
4
4
  import json
5
+
6
+ try:
7
+ from types import NoneType
8
+ except Exception:
9
+ # compatibility: python-3.8
10
+ NoneType = type(None)
5
11
  from termcolor import cprint
6
12
  import os
7
13
  from pathlib import Path
@@ -14,7 +20,6 @@ import inspect
14
20
  import importlib
15
21
  from typing import (
16
22
  Any,
17
- Callable,
18
23
  ClassVar,
19
24
  Dict,
20
25
  List,
@@ -169,7 +174,7 @@ class HashComputer:
169
174
  for key, value in items:
170
175
  self.update(key, subparam=subparam)
171
176
  self.update(value, subparam=subparam)
172
- elif isinstance(value, TaskOutput):
177
+ elif isinstance(value, ConfigWrapper):
173
178
  # Add the task ID...
174
179
  self.update(value.__xpm__.task, subparam=subparam)
175
180
 
@@ -278,8 +283,14 @@ def updatedependencies(
278
283
  elif isinstance(value, (list, set)):
279
284
  for el in value:
280
285
  updatedependencies(dependencies, el, path, taskids)
281
- elif isinstance(value, TaskOutput):
282
- dependencies.add(value.__xpm__.task.__xpm__.dependency())
286
+ elif isinstance(value, ConfigWrapper):
287
+ # Add the base value (if any)
288
+ if value.__xpm__.base is not None:
289
+ value.__xpm__.base.__xpm__.updatedependencies(dependencies, path, taskids)
290
+
291
+ # Add the task (if any)
292
+ if value.__xpm__.task is not None:
293
+ dependencies.add(value.__xpm__.task.__xpm__.dependency())
283
294
  elif isinstance(value, (dict,)):
284
295
  for key, val in value.items():
285
296
  updatedependencies(dependencies, key, path, taskids)
@@ -419,9 +430,13 @@ class ConfigWalk:
419
430
  result[key] = self(value)
420
431
  return result
421
432
 
422
- if isinstance(x, TaskOutput):
433
+ if isinstance(x, ConfigWrapper):
423
434
  # Process task if different
424
- if self.recurse_task and x.__xpm__.task is not x.__unwrap__():
435
+ if (
436
+ x.__xpm__.task is not None
437
+ and self.recurse_task
438
+ and x.__xpm__.task is not x.__unwrap__()
439
+ ):
425
440
  self(x.__xpm__.task)
426
441
 
427
442
  # Processed the wrapped config
@@ -430,6 +445,9 @@ class ConfigWalk:
430
445
  if isinstance(x, (float, int, str, Path, Enum)):
431
446
  return x
432
447
 
448
+ if isinstance(x, Proxy):
449
+ return self(x.__unwrap__())
450
+
433
451
  raise NotImplementedError(f"Cannot handle a value of type {type(x)}")
434
452
 
435
453
 
@@ -448,7 +466,7 @@ class ConfigInformation:
448
466
  """Forces this configuration to be a meta-parameter"""
449
467
 
450
468
  # Set to true when loading from JSON
451
- LOADING = False
469
+ LOADING: ClassVar[bool] = False
452
470
 
453
471
  def __init__(self, pyobject: "TypeConfig"):
454
472
  # The underlying pyobject and XPM type
@@ -477,6 +495,7 @@ class ConfigInformation:
477
495
  self._meta = None
478
496
 
479
497
  def set_meta(self, value: Optional[bool]):
498
+ """Sets the meta flag"""
480
499
  assert not self._sealed, "Configuration is sealed"
481
500
  self._meta = value
482
501
 
@@ -672,12 +691,17 @@ class ConfigInformation:
672
691
  hook(job)
673
692
 
674
693
  def submit(
675
- self, workspace: "Workspace", launcher: "Launcher", run_mode=None
676
- ) -> "TaskOutput":
694
+ self, workspace: "Workspace", launcher: "Launcher", *, run_mode=None, pre=None
695
+ ) -> "ConfigWrapper":
677
696
  from experimaestro.scheduler import experiment, JobContext
678
697
  from experimaestro.scheduler.workspace import RunMode
679
698
 
699
+ # --- Handle default values
700
+
701
+ pre = pre or []
702
+
680
703
  # --- Prepare the object
704
+
681
705
  if self.job:
682
706
  raise Exception("task %s was already submitted" % self)
683
707
  if not self.xpmtype.task:
@@ -685,6 +709,7 @@ class ConfigInformation:
685
709
 
686
710
  # --- Submit the job
687
711
 
712
+ # Creates a new job
688
713
  self.job = self.xpmtype.task(
689
714
  self.pyobject, launcher=launcher, workspace=workspace, run_mode=run_mode
690
715
  )
@@ -759,16 +784,20 @@ class ConfigInformation:
759
784
  hints = get_type_hints(self.pyobject.config)
760
785
  config = hints["return"](**config)
761
786
  config.__xpm__.validate()
762
- self._taskoutput = TaskOutput(config, self.pyobject)
787
+ self._taskoutput = ConfigWrapper.__create_taskoutput__(
788
+ config, self.pyobject
789
+ )
763
790
 
764
791
  # New way to handle outputs
765
792
  elif hasattr(self.pyobject, "taskoutputs"):
766
793
  value = self.pyobject.taskoutputs()
767
- self._taskoutput = TaskOutput(value, self.pyobject)
794
+ self._taskoutput = ConfigWrapper.__create_taskoutput__(value, self.pyobject)
768
795
 
769
796
  # Otherwise, the output is just the config
770
797
  else:
771
- self._taskoutput = TaskOutput(self.pyobject, self.pyobject)
798
+ self._taskoutput = ConfigWrapper.__create_taskoutput__(
799
+ self.pyobject, self.pyobject
800
+ )
772
801
 
773
802
  return self._taskoutput
774
803
 
@@ -810,20 +839,13 @@ class ConfigInformation:
810
839
  "value": value.name,
811
840
  }
812
841
 
813
- elif isinstance(value, SerializedTaskOutput):
814
- # Reference to a serialized object
815
- return {
816
- "type": "serialized",
817
- "value": id(value.__xpm__.serialized.loader),
818
- "path": [c.toJSON() for c in value.__xpm__.path],
819
- }
820
-
821
- elif isinstance(value, TaskOutput):
842
+ elif isinstance(value, ConfigWrapper):
822
843
  return {
823
844
  "type": "python",
824
845
  "value": id(value.__unwrap__()),
825
846
  # We add the task for identifier computation
826
847
  "task": id(value.__xpm__.task),
848
+ "path": [c.toJSON() for c in value.__xpm__.path or []],
827
849
  }
828
850
 
829
851
  elif isinstance(value, Config):
@@ -892,25 +914,18 @@ class ConfigInformation:
892
914
  def __collect_objects__(value, objects: List[Dict], context: SerializationContext):
893
915
  """Serialize all needed configuration objects, looking at sub
894
916
  configurations if necessary"""
895
- # objects
896
- if isinstance(value, SerializedTaskOutput):
897
- loader = value.__xpm__.serialized.loader
898
- if id(loader) not in context.serialized:
899
- objects.append(
900
- {
901
- "id": id(loader),
902
- "serialized": True,
903
- "module": loader.__class__.__module__,
904
- "type": loader.__class__.__qualname__,
905
- "value": loader.toJSON(),
906
- }
907
- )
908
- return
909
-
910
917
  # Unwrap if needed
911
- if isinstance(value, TaskOutput):
918
+ if isinstance(value, ConfigWrapper):
912
919
  # We will need to output the task configuration objects
913
- ConfigInformation.__collect_objects__(value.__xpm__.task, objects, context)
920
+ if value.__xpm__.task is not None:
921
+ ConfigInformation.__collect_objects__(
922
+ value.__xpm__.task, objects, context
923
+ )
924
+
925
+ if value.__xpm__.base is not None:
926
+ ConfigInformation.__collect_objects__(
927
+ value.__xpm__.base, objects, context
928
+ )
914
929
 
915
930
  # Unwrap the value to output it
916
931
  value = value.__unwrap__()
@@ -1040,7 +1055,7 @@ class ConfigInformation:
1040
1055
  if not as_instance:
1041
1056
  if task_id := value.get("task", None):
1042
1057
  task = objects[task_id]
1043
- return TaskOutput(obj, task)
1058
+ return ConfigWrapper.__create_taskoutput__(obj, task)
1044
1059
  return obj
1045
1060
 
1046
1061
  if value["type"] == "serialized":
@@ -1102,6 +1117,7 @@ class ConfigInformation:
1102
1117
  o = None
1103
1118
  objects = {}
1104
1119
  import experimaestro.taskglobals as taskglobals
1120
+ from .serializers import SerializedConfig
1105
1121
 
1106
1122
  for definition in definitions:
1107
1123
  module_name = definition["module"]
@@ -1184,7 +1200,10 @@ class ConfigInformation:
1184
1200
  assert isinstance(v, Path), "Excepted Path, got {type(v)}"
1185
1201
 
1186
1202
  if as_instance:
1203
+ # Unwrap the value if needed
1204
+ v = unwrap(v)
1187
1205
  setattr(o, name, v)
1206
+
1188
1207
  assert (
1189
1208
  getattr(o, name) is v
1190
1209
  ), f"Problem with deserialization {name} of {o.__class__}"
@@ -1194,6 +1213,8 @@ class ConfigInformation:
1194
1213
  if as_instance:
1195
1214
  # Calls post-init
1196
1215
  o.__post_init__()
1216
+ if isinstance(o, SerializedConfig):
1217
+ o.initialize()
1197
1218
  else:
1198
1219
  # Seal and set the identifier
1199
1220
  if not discard_id:
@@ -1247,6 +1268,13 @@ class ConfigInformation:
1247
1268
  # Call __post_init__
1248
1269
  o.__post_init__()
1249
1270
 
1271
+ # Process a serialized configuration
1272
+ from .serializers import SerializedConfig
1273
+
1274
+ if isinstance(o, SerializedConfig):
1275
+ o.initialize()
1276
+ o = o.__unwrap__()
1277
+
1250
1278
  return o
1251
1279
 
1252
1280
  def fromConfig(self, context: ConfigWalkContext):
@@ -1406,15 +1434,18 @@ class TypeConfig:
1406
1434
  ), f"{context.__class__} is not an instance of ConfigWalkContext"
1407
1435
  return self.__xpm__.fromConfig(context) # type: ignore
1408
1436
 
1409
- def submit(self, *, workspace=None, launcher=None, run_mode: "RunMode" = None):
1437
+ def submit(
1438
+ self, *, workspace=None, launcher=None, run_mode: "RunMode" = None, pre=None
1439
+ ):
1410
1440
  """Submit this task
1411
1441
 
1412
1442
  :param workspace: the workspace, defaults to None
1413
1443
  :param launcher: The launcher, defaults to None
1414
1444
  :param run_mode: Run mode (if None, uses the workspace default)
1415
- :return: a :py:class:TaskOutput object
1445
+ :param pre: Pre-tasks to execute before
1446
+ :return: a :py:class:ConfigWrapper object
1416
1447
  """
1417
- return self.__xpm__.submit(workspace, launcher, run_mode=run_mode)
1448
+ return self.__xpm__.submit(workspace, launcher, run_mode=run_mode, pre=pre)
1418
1449
 
1419
1450
  def stdout(self):
1420
1451
  return self.__xpm__.job.stdout
@@ -1515,9 +1546,6 @@ class Task(Config):
1515
1546
  raise NotImplementedError()
1516
1547
 
1517
1548
 
1518
- # --- Output proxy
1519
-
1520
-
1521
1549
  class Proxy:
1522
1550
  """A proxy for a value"""
1523
1551
 
@@ -1525,7 +1553,29 @@ class Proxy:
1525
1553
  raise NotImplementedError()
1526
1554
 
1527
1555
 
1556
+ def unwrap(v: Any):
1557
+ """Unwrap all proxies"""
1558
+ while isinstance(v, Proxy):
1559
+ v = v.__unwrap__()
1560
+ return v
1561
+
1562
+
1563
+ class AttrAccessor:
1564
+ """Access an attribute"""
1565
+
1566
+ def __init__(self, key: str):
1567
+ self.key = key
1568
+
1569
+ def get(self, value):
1570
+ return getattr(value, self.key)
1571
+
1572
+ def toJSON(self):
1573
+ return {"type": "attr", "name": self.key}
1574
+
1575
+
1528
1576
  class ItemAccessor:
1577
+ """Access an array item"""
1578
+
1529
1579
  def __init__(self, key: Any):
1530
1580
  self.key = key
1531
1581
 
@@ -1536,49 +1586,65 @@ class ItemAccessor:
1536
1586
  return value.__getitem__(self.key)
1537
1587
 
1538
1588
 
1539
- class AttrAccessor:
1540
- def __init__(self, key: Any, default: Any):
1541
- self.key = key
1542
- self.default = default
1543
-
1544
- def get(self, value):
1545
- return getattr(value, self.key, self.default)
1546
-
1547
- def toJSON(self):
1548
- return {"type": "attr", "name": self.key}
1589
+ class ConfigWrapperInfo:
1590
+ """Global information about the Configuration wrapper"""
1549
1591
 
1592
+ def __init__(
1593
+ self,
1594
+ value: Any,
1595
+ *,
1596
+ task: Optional[Task] = None,
1597
+ parent: Optional["ConfigWrapperInfo"] = None,
1598
+ base: Optional[Config] = None,
1599
+ path: Optional[List[Path]] = None,
1600
+ ):
1601
+ # Current value
1602
+ self.value = value
1603
+ self.parent = parent
1550
1604
 
1551
- class Serialized:
1552
- """Simple serialization object"""
1605
+ # The task
1606
+ if isinstance(value, Task):
1607
+ self.task = value
1608
+ else:
1609
+ self.task = task
1553
1610
 
1554
- def __init__(self, value):
1555
- self.value = value
1611
+ # Holds serialized config information
1612
+ from .serializers import SerializedConfig
1556
1613
 
1557
- def toJSON(self):
1558
- return self.value
1614
+ if isinstance(value, SerializedConfig):
1615
+ self.base = value
1616
+ self.value = value.config
1617
+ self.path = [AttrAccessor("config")]
1618
+ else:
1619
+ self.base = base
1620
+ self.path = path
1559
1621
 
1622
+ def __state_dict__(self):
1623
+ return {"task": self.task, "base": self.base, "path": self.path}
1560
1624
 
1561
- class SerializedConfig:
1562
- """A serializable configuration
1625
+ def __getitem__(self, key: Any):
1626
+ kwargs = self.__state_dict__()
1627
+ value = self.value.__getitem__(key)
1563
1628
 
1564
- This can be used to define a loading mechanism when instanciating the
1565
- configuration
1566
- """
1629
+ if self.path:
1630
+ kwargs["path"].append(ItemAccessor(key))
1567
1631
 
1568
- pyobject: Config
1569
- """The configuration that will be serialized"""
1632
+ return ConfigWrapperInfo(value, **kwargs)
1570
1633
 
1571
- def __init__(self, pyobject: Config, loader: Callable[[Path], Config]):
1572
- self.pyobject = pyobject
1573
- self.loader = loader
1634
+ def __getattr__(self, key: str, *default) -> Any:
1635
+ kwargs = self.__state_dict__()
1636
+ value = getattr(self.value, key, *default)
1637
+ if self.path:
1638
+ kwargs["path"].append(AttrAccessor(key, *default))
1639
+ return ConfigWrapperInfo(value, parent=self, **kwargs)
1574
1640
 
1641
+ def wrap(self):
1642
+ """Wrap a value if needed"""
1643
+ if isinstance(self.value, (str, int, float, Path, bool, NoneType)):
1644
+ return self.value
1575
1645
 
1576
- class TaskOutputInfo:
1577
- def __init__(self, task: Task):
1578
- self.task = task
1579
- self.value = None
1580
- self.path = None
1581
- self.serialized = None
1646
+ # Returns a new config wrapper
1647
+ return ConfigWrapper(self)
1582
1648
 
1583
1649
  @property
1584
1650
  def identifier(self):
@@ -1589,92 +1655,64 @@ class TaskOutputInfo:
1589
1655
  return self.task.__xpm__.job
1590
1656
 
1591
1657
  def tags(self):
1658
+ """Returns the tags of the task"""
1592
1659
  tags = self.task.__xpm__.tags()
1593
1660
  return tags
1594
1661
 
1595
1662
  def stdout(self):
1663
+ """Returns the standard output of the associated task"""
1596
1664
  return self.task.__xpm__.job.stdout
1597
1665
 
1598
1666
  def stderr(self):
1667
+ """Returns the standard error of the associated task"""
1599
1668
  return self.task.__xpm__.job.stderr
1600
1669
 
1601
1670
  def wait(self):
1671
+ """Wait for the task to end
1672
+
1673
+ :return: True if the task completed without error
1674
+ """
1602
1675
  from experimaestro.scheduler import JobState
1603
1676
 
1604
1677
  return self.task.__xpm__.job.wait() == JobState.DONE
1605
1678
 
1606
1679
 
1607
- class TaskOutput(Proxy):
1680
+ # Cleanup into just one
1681
+ class ConfigWrapper(Proxy):
1608
1682
  """Task proxy
1609
1683
 
1610
1684
  This is used when accessing properties *after* having submitted a task,
1611
- to keep track of the dependencies
1685
+ to keep track of the dependencies, and/or as an accessor when dealing with
1686
+ a serialized config
1612
1687
  """
1613
1688
 
1614
- def __init__(self, value: Any, task: Union[Task, TaskOutputInfo]):
1615
- self.__xpm__ = (
1616
- task if isinstance(task, TaskOutputInfo) else TaskOutputInfo(task)
1617
- )
1618
- self.__xpm__.value = value
1619
-
1620
- def _wrap(self, value):
1621
- if isinstance(value, SerializedConfig):
1622
- return SerializedTaskOutput(value.pyobject, value, self.__xpm__.task, [])
1623
-
1624
- if isinstance(value, (str, int, float, Path, bool)):
1625
- # No need to wrap if direct
1626
- return value
1689
+ def __init__(self, info: ConfigWrapperInfo):
1690
+ self.__xpm__ = info
1627
1691
 
1628
- return TaskOutput(value, self.__xpm__.task)
1692
+ @staticmethod
1693
+ def __create_taskoutput__(value: Any, task: Task):
1694
+ return ConfigWrapperInfo(value, task=task).wrap()
1629
1695
 
1630
1696
  def __getitem__(self, key: Any):
1631
- return self._wrap(self.__xpm__.value.__getitem__(key))
1697
+ return self.__xpm__[key].wrap()
1632
1698
 
1633
- def __getattr__(self, key: str, default=None) -> Any:
1634
- return self._wrap(getattr(self.__xpm__.value, key, default))
1699
+ def __getattr__(self, key: str, *default) -> Any:
1700
+ return self.__xpm__.__getattr__(key, *default).wrap()
1635
1701
 
1636
1702
  def __unwrap__(self):
1637
1703
  return self.__xpm__.value
1638
1704
 
1639
1705
  def __call__(self, *args, **kwargs):
1640
1706
  assert callable(self.__xpm__.value), "Attribute is not a function"
1641
- __self__ = TaskOutput(self.__xpm__.value.__self__, self.__xpm__.task)
1642
- return self.__xpm__.value.__func__(__self__, *args, **kwargs)
1643
-
1644
1707
 
1645
- class SerializedTaskOutput(TaskOutput):
1646
- """Used when serializing a configuration
1647
-
1648
- Here, we need to keep track of the path to the value we need
1649
- """
1650
-
1651
- def __init__(
1652
- self, value, serialized: SerializedConfig, task: Task, path: List[Any]
1653
- ):
1654
- super().__init__(value, task)
1655
- self.__xpm__.serialized = serialized
1656
- self.__xpm__.path = path
1657
-
1658
- def __getitem__(self, key: Any):
1659
- value = self.__xpm__.value.__getitem__(key)
1660
- return SerializedTaskOutput(
1661
- value, self.serialized, self.__xpm__.task, self.path + [ItemAccessor(key)]
1662
- )
1663
-
1664
- def __getattr__(self, key: str, default=None) -> Any:
1665
- value = getattr(self.__xpm__.value, key, default)
1666
- return SerializedTaskOutput(
1667
- value,
1668
- self.__xpm__.serialized,
1669
- self.__xpm__.task,
1670
- self.__xpm__.path + [AttrAccessor(key, default)],
1671
- )
1708
+ __self__ = self.__xpm__.parent.wrap()
1709
+ return self.__xpm__.value.__func__(__self__, *args, **kwargs)
1672
1710
 
1673
1711
 
1674
1712
  # --- Utility functions
1675
1713
 
1676
1714
 
1677
- def copyconfig(config_or_output: Union[Config, TaskOutput], **kwargs):
1715
+ def copyconfig(config_or_output: Union[Config, ConfigWrapper], **kwargs):
1678
1716
  """Copy a configuration or task output
1679
1717
 
1680
1718
  Useful to modify a configuration that can be potentially
@@ -1682,7 +1720,7 @@ def copyconfig(config_or_output: Union[Config, TaskOutput], **kwargs):
1682
1720
  a task output).
1683
1721
  """
1684
1722
 
1685
- if isinstance(config_or_output, TaskOutput):
1723
+ if isinstance(config_or_output, ConfigWrapper):
1686
1724
  output = config_or_output
1687
1725
  config = config_or_output.__unwrap__()
1688
1726
  assert isinstance(config, Config)
@@ -1702,7 +1740,7 @@ def copyconfig(config_or_output: Union[Config, TaskOutput], **kwargs):
1702
1740
  return copy
1703
1741
 
1704
1742
  # wrap in Task output
1705
- return TaskOutput(copy, output.__xpm__)
1743
+ return ConfigWrapper(copy, output.__xpm__)
1706
1744
 
1707
1745
 
1708
1746
  def setmeta(config: Config, flag: bool):
@@ -181,7 +181,8 @@ class TypeConfig:
181
181
  *,
182
182
  workspace: Incomplete | None = ...,
183
183
  launcher: Incomplete | None = ...,
184
- run_mode: RunMode = ...
184
+ run_mode: RunMode = ...,
185
+ pre: List[Task] = []
185
186
  ): ...
186
187
  def stdout(self): ...
187
188
  def stderr(self): ...
@@ -0,0 +1,52 @@
1
+ from abc import ABC, abstractmethod
2
+ from pathlib import Path
3
+ from typing import List, TypeVar
4
+
5
+ from experimaestro import Param
6
+
7
+ from .objects import Config, Proxy
8
+ from .arguments import DataPath
9
+
10
+ T = TypeVar("T")
11
+
12
+
13
+ class SerializedConfig(Config, Proxy, ABC):
14
+ """A serializable configuration
15
+
16
+ This can be used to define a loading mechanism when instanciating the
17
+ configuration
18
+ """
19
+
20
+ config: Param[Config]
21
+ """The configuration that will be serialized"""
22
+
23
+ registered: List[Config]
24
+ """(execution only) List of configurations that use this serialized config"""
25
+
26
+ def __post_init__(self):
27
+ super().__post_init__()
28
+ self.registered = []
29
+
30
+ def register(self, config: Config):
31
+ self.registered.append(config)
32
+
33
+ def __unwrap__(self):
34
+ return self.config
35
+
36
+ @abstractmethod
37
+ def initialize(self):
38
+ """Initialize the object
39
+
40
+ This might imply loading saved data (e.g. learned models)
41
+ """
42
+ ...
43
+
44
+
45
+ class PathBasedSerializedConfig(SerializedConfig):
46
+ """A path based serialized configuration
47
+
48
+ The most common case it to have
49
+ """
50
+
51
+ path: DataPath[Path]
52
+ """Path containing the data"""
@@ -1,6 +1,6 @@
1
1
  from pathlib import Path
2
2
  from typing import Optional, Union
3
- from experimaestro import Config, TaskOutput
3
+ from experimaestro import Config, ConfigWrapper
4
4
  from experimaestro.core.context import SerializedPath
5
5
  from experimaestro.core.objects import ConfigInformation
6
6
  from huggingface_hub import ModelHubMixin, hf_hub_download, snapshot_download
@@ -11,7 +11,7 @@ class ExperimaestroHFHub(ModelHubMixin):
11
11
  """Defines models that can be uploaded/downloaded from the Hub"""
12
12
 
13
13
  def __init__(
14
- self, config: Union[Config, TaskOutput], variant: Optional[str] = None
14
+ self, config: Union[Config, ConfigWrapper], variant: Optional[str] = None
15
15
  ):
16
16
  self.config = config if isinstance(config, Config) else config.__unwrap__()
17
17
  self.variant = variant
@@ -17,7 +17,8 @@ from experimaestro import (
17
17
  Annotated,
18
18
  Task,
19
19
  )
20
- from experimaestro.core.objects import ConfigInformation, TaskOutput, setmeta
20
+ from experimaestro.core.objects import ConfigInformation, ConfigWrapper, setmeta
21
+ from experimaestro.core.serializers import SerializedConfig
21
22
  from experimaestro.scheduler.workspace import RunMode
22
23
 
23
24
 
@@ -56,7 +57,7 @@ class Values:
56
57
 
57
58
 
58
59
  def getidentifier(x):
59
- if isinstance(x, TaskOutput):
60
+ if isinstance(x, ConfigWrapper):
60
61
  return x.__xpm__.identifier.all
61
62
  return x.__xpm__.identifier.all
62
63
 
@@ -387,6 +388,32 @@ def test_identifier_meta_default_array():
387
388
  )
388
389
 
389
390
 
391
+ # --- Check ConfigWrapper
392
+
393
+
394
+ class Model(Config):
395
+ def __post_init__(self):
396
+ self.initialized = False
397
+
398
+
399
+ class Trainer(Config):
400
+ model: Param[Model]
401
+
402
+
403
+ class SerializedModel(SerializedConfig):
404
+ def initialize(self):
405
+ self.config.initialized = True
406
+
407
+
408
+ def test_identifier_serialized_config():
409
+ trainer1 = Trainer(model=Model())
410
+ trainer2 = Trainer(model=SerializedModel(config=Model()))
411
+ assert_notequal(trainer1, trainer2)
412
+
413
+
414
+ # --- Check configuration reloads
415
+
416
+
390
417
  def check_reload(config):
391
418
  old_identifier = config.__xpm__.identifier.all
392
419
 
@@ -412,14 +439,14 @@ def test_identifier_reload_config():
412
439
  check_reload(IdentifierReloadConfig(id="123"))
413
440
 
414
441
 
415
- class IdentifierReloadTaskOutput(Task):
442
+ class IdentifierReloadConfigWrapper(Task):
416
443
  id: Param[str]
417
444
 
418
445
  def taskoutputs(self):
419
446
  return IdentifierReloadConfig(id=self.id)
420
447
 
421
448
 
422
- class IdentifierReloadTaskOutputDerived(Config):
449
+ class IdentifierReloadConfigWrapperDerived(Config):
423
450
  task: Param[IdentifierReloadConfig]
424
451
 
425
452
 
@@ -427,8 +454,8 @@ def test_identifier_reload_taskoutput():
427
454
  """When using a task output, the identifier should not be different"""
428
455
 
429
456
  # Creates the configuration
430
- task = IdentifierReloadTaskOutput(id="123").submit(run_mode=RunMode.DRY_RUN)
431
- config = IdentifierReloadTaskOutputDerived(task=task)
457
+ task = IdentifierReloadConfigWrapper(id="123").submit(run_mode=RunMode.DRY_RUN)
458
+ config = IdentifierReloadConfigWrapperDerived(task=task)
432
459
  check_reload(config)
433
460
 
434
461