experimaestro 1.13.0__tar.gz → 1.14.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of experimaestro might be problematic. Click here for more details.

Files changed (159) hide show
  1. {experimaestro-1.13.0 → experimaestro-1.14.0}/PKG-INFO +1 -1
  2. {experimaestro-1.13.0 → experimaestro-1.14.0}/pyproject.toml +2 -2
  3. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/core/arguments.py +10 -1
  4. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/core/objects/config.py +73 -16
  5. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/core/objects/config_walk.py +3 -1
  6. experimaestro-1.14.0/src/experimaestro/tests/test_generators.py +93 -0
  7. experimaestro-1.13.0/src/experimaestro/tests/test_generators.py +0 -33
  8. {experimaestro-1.13.0 → experimaestro-1.14.0}/LICENSE +0 -0
  9. {experimaestro-1.13.0 → experimaestro-1.14.0}/README.md +0 -0
  10. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/__init__.py +0 -0
  11. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/__main__.py +0 -0
  12. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/annotations.py +0 -0
  13. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/checkers.py +0 -0
  14. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/cli/__init__.py +0 -0
  15. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/cli/filter.py +0 -0
  16. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/cli/jobs.py +0 -0
  17. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/click.py +0 -0
  18. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/commandline.py +0 -0
  19. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/compat.py +0 -0
  20. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/connectors/__init__.py +0 -0
  21. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/connectors/local.py +0 -0
  22. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/connectors/ssh.py +0 -0
  23. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/core/__init__.py +0 -0
  24. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/core/callbacks.py +0 -0
  25. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/core/context.py +0 -0
  26. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/core/identifier.py +0 -0
  27. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/core/objects/__init__.py +0 -0
  28. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/core/objects/config_utils.py +0 -0
  29. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/core/objects.pyi +0 -0
  30. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/core/serialization.py +0 -0
  31. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/core/serializers.py +0 -0
  32. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/core/types.py +0 -0
  33. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/core/utils.py +0 -0
  34. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/exceptions.py +0 -0
  35. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/experiments/__init__.py +0 -0
  36. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/experiments/cli.py +0 -0
  37. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/experiments/configuration.py +0 -0
  38. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/generators.py +0 -0
  39. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/huggingface.py +0 -0
  40. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/ipc.py +0 -0
  41. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/launcherfinder/__init__.py +0 -0
  42. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/launcherfinder/base.py +0 -0
  43. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/launcherfinder/parser.py +0 -0
  44. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/launcherfinder/registry.py +0 -0
  45. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/launcherfinder/specs.py +0 -0
  46. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/launchers/__init__.py +0 -0
  47. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/launchers/direct.py +0 -0
  48. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/launchers/oar.py +0 -0
  49. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/launchers/slurm/__init__.py +0 -0
  50. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/launchers/slurm/base.py +0 -0
  51. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/locking.py +0 -0
  52. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/mkdocs/__init__.py +0 -0
  53. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/mkdocs/annotations.py +0 -0
  54. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/mkdocs/base.py +0 -0
  55. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/mkdocs/metaloader.py +0 -0
  56. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/mkdocs/style.css +0 -0
  57. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/mypy.py +0 -0
  58. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/notifications.py +0 -0
  59. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/py.typed +0 -0
  60. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/rpyc.py +0 -0
  61. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/run.py +0 -0
  62. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/scheduler/__init__.py +0 -0
  63. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/scheduler/base.py +0 -0
  64. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/scheduler/dependencies.py +0 -0
  65. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/scheduler/dynamic_outputs.py +0 -0
  66. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/scheduler/services.py +0 -0
  67. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/scheduler/state.py +0 -0
  68. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/scheduler/workspace.py +0 -0
  69. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/scriptbuilder.py +0 -0
  70. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/__init__.py +0 -0
  71. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/0c35d18bf06992036b69.woff2 +0 -0
  72. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/1815e00441357e01619e.ttf +0 -0
  73. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/219aa9140e099e6c72ed.woff2 +0 -0
  74. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/2463b90d9a316e4e5294.woff2 +0 -0
  75. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/2582b0e4bcf85eceead0.ttf +0 -0
  76. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/3a4004a46a653d4b2166.woff +0 -0
  77. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/3baa5b8f3469222b822d.woff +0 -0
  78. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/4d73cb90e394b34b7670.woff +0 -0
  79. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/4ef4218c522f1eb6b5b1.woff2 +0 -0
  80. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/5d681e2edae8c60630db.woff +0 -0
  81. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/6f420cf17cc0d7676fad.woff2 +0 -0
  82. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/89999bdf5d835c012025.woff2 +0 -0
  83. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/914997e1bdfc990d0897.ttf +0 -0
  84. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/c210719e60948b211a12.woff2 +0 -0
  85. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/c380809fd3677d7d6903.woff2 +0 -0
  86. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/f882956fd323fd322f31.woff +0 -0
  87. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/favicon.ico +0 -0
  88. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/index.css +0 -0
  89. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/index.css.map +0 -0
  90. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/index.html +0 -0
  91. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/index.js +0 -0
  92. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/index.js.map +0 -0
  93. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/login.html +0 -0
  94. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/server/data/manifest.json +0 -0
  95. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/settings.py +0 -0
  96. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/sphinx/__init__.py +0 -0
  97. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/sphinx/static/experimaestro.css +0 -0
  98. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/taskglobals.py +0 -0
  99. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/__init__.py +0 -0
  100. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/conftest.py +0 -0
  101. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/connectors/bin/executable.py +0 -0
  102. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/connectors/test_local.py +0 -0
  103. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/connectors/utils.py +0 -0
  104. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/core/__init__.py +0 -0
  105. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/core/test_generics.py +0 -0
  106. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/definitions_types.py +0 -0
  107. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/launchers/__init__.py +0 -0
  108. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/launchers/bin/sacct +0 -0
  109. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/launchers/bin/sbatch +0 -0
  110. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/launchers/bin/srun +0 -0
  111. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/launchers/bin/test.py +0 -0
  112. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/launchers/common.py +0 -0
  113. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/launchers/config_slurm/__init__.py +0 -0
  114. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/launchers/config_slurm/launchers.py +0 -0
  115. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/launchers/test_local.py +0 -0
  116. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/launchers/test_slurm.py +0 -0
  117. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/restart.py +0 -0
  118. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/restart_main.py +0 -0
  119. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/scripts/notifyandwait.py +0 -0
  120. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/scripts/waitforfile.py +0 -0
  121. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/task_tokens.py +0 -0
  122. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/tasks/__init__.py +0 -0
  123. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/tasks/all.py +0 -0
  124. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/tasks/foreign.py +0 -0
  125. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/test_checkers.py +0 -0
  126. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/test_dependencies.py +0 -0
  127. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/test_experiment.py +0 -0
  128. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/test_findlauncher.py +0 -0
  129. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/test_forward.py +0 -0
  130. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/test_identifier.py +0 -0
  131. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/test_instance.py +0 -0
  132. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/test_objects.py +0 -0
  133. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/test_outputs.py +0 -0
  134. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/test_param.py +0 -0
  135. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/test_progress.py +0 -0
  136. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/test_serializers.py +0 -0
  137. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/test_snippets.py +0 -0
  138. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/test_ssh.py +0 -0
  139. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/test_tags.py +0 -0
  140. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/test_tasks.py +0 -0
  141. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/test_tokens.py +0 -0
  142. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/test_types.py +0 -0
  143. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/test_validation.py +0 -0
  144. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/token_reschedule.py +0 -0
  145. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tests/utils.py +0 -0
  146. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tokens.py +0 -0
  147. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tools/__init__.py +0 -0
  148. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tools/diff.py +0 -0
  149. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tools/documentation.py +0 -0
  150. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/tools/jobs.py +0 -0
  151. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/typingutils.py +0 -0
  152. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/utils/__init__.py +0 -0
  153. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/utils/asyncio.py +0 -0
  154. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/utils/jobs.py +0 -0
  155. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/utils/jupyter.py +0 -0
  156. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/utils/multiprocessing.py +0 -0
  157. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/utils/resources.py +0 -0
  158. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/utils/settings.py +0 -0
  159. {experimaestro-1.13.0 → experimaestro-1.14.0}/src/experimaestro/xpmutils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: experimaestro
3
- Version: 1.13.0
3
+ Version: 1.14.0
4
4
  Summary: "Experimaestro is a computer science experiment manager"
5
5
  License: GPL-3
6
6
  License-File: LICENSE
@@ -48,7 +48,7 @@ dependencies = [
48
48
  "typing-extensions >=4.2; python_version < \"3.12\"",
49
49
  "watchdog >=2"
50
50
  ]
51
- version = "1.13.0"
51
+ version = "1.14.0"
52
52
 
53
53
  [tool.poetry-dynamic-versioning]
54
54
  enable = false
@@ -140,7 +140,7 @@ warn_unused_ignores = true
140
140
 
141
141
  [tool.commitizen]
142
142
  name = "cz_conventional_commits"
143
- version = "1.13.0"
143
+ version = "1.14.0"
144
144
  changelog_start_rev = "v1.0.0"
145
145
  tag_format = "v$major.$minor.$patch$prerelease"
146
146
  # update_changelog_on_bump = true
@@ -80,10 +80,12 @@ class Argument:
80
80
 
81
81
  self.generator = generator
82
82
  self.default = None
83
+ self.ignore_generated = False
83
84
 
84
85
  if default is not None:
85
86
  assert self.generator is None, "generator and default are exclusive options"
86
87
  if isinstance(default, field):
88
+ self.ignore_generated = default.ignore_generated
87
89
  if default.default is not None:
88
90
  self.default = default.default
89
91
  elif default.default_factory is not None:
@@ -184,13 +186,20 @@ DataPath = Annotated[Path, dataHint]
184
186
  class field:
185
187
  """Extra information for a given experimaestro field (param or meta)"""
186
188
 
187
- def __init__(self, *, default: Any = None, default_factory: Callable = None):
189
+ def __init__(
190
+ self,
191
+ *,
192
+ default: Any = None,
193
+ default_factory: Callable = None,
194
+ ignore_generated=False,
195
+ ):
188
196
  assert not (
189
197
  (default is not None) and (default_factory is not None)
190
198
  ), "default and default_factory are mutually exclusive options"
191
199
 
192
200
  self.default_factory = default_factory
193
201
  self.default = default
202
+ self.ignore_generated = ignore_generated
194
203
 
195
204
 
196
205
  class help(TypeAnnotation):
@@ -170,10 +170,33 @@ class ConfigInformation:
170
170
  self._sealed = False
171
171
  self._meta = None
172
172
 
173
- #: This flags is True when a value in this configuration,
174
- #: or any sub-configuration, is generated. This prevents problem
175
- #: when a configuration with generated values is re-used
176
- self._has_generated_value = False
173
+ # This contains the list of generated values (using context) in this
174
+ # configuration or any sub-configuration, is generated. This prevents
175
+ # problem when a configuration with generated values is re-used.
176
+ self._generated_values = []
177
+
178
+ def get_generated_paths(
179
+ self, path: list[str] = None, paths: list[str] = None
180
+ ) -> list[str]:
181
+ """Get the list of generated paths, useful to track down those
182
+
183
+ :param path: The current path
184
+ :param paths: The list of generated paths so far, defaults to None
185
+ :return: The full list of generated paths
186
+ """
187
+ paths = [] if paths is None else paths
188
+ path = [] if path is None else path
189
+
190
+ for key in self._generated_values:
191
+ value = self.values[key]
192
+ if isinstance(value, ConfigMixin) and value.__xpm__._generated_values:
193
+ path.append(key)
194
+ value.__xpm__.get_generated_paths(path, paths)
195
+ path.pop()
196
+ else:
197
+ paths.append(".".join(path + [key]))
198
+
199
+ return paths
177
200
 
178
201
  def set_meta(self, value: Optional[bool]):
179
202
  """Sets the meta flag"""
@@ -192,6 +215,31 @@ class ConfigInformation:
192
215
  # Not an argument, bypass
193
216
  return object.__getattribute__(self.pyobject, name)
194
217
 
218
+ @staticmethod
219
+ def is_generated_value(argument, value):
220
+ if argument.ignore_generated:
221
+ return False
222
+
223
+ if value is None:
224
+ return False
225
+
226
+ if isinstance(value, (int, str, float, bool, Path)):
227
+ return False
228
+
229
+ if isinstance(value, ConfigMixin):
230
+ return value.__xpm__._generated_values and value.__xpm__.task is None
231
+
232
+ if isinstance(value, list):
233
+ return any(ConfigInformation.is_generated_value(argument, x) for x in value)
234
+
235
+ if isinstance(value, dict):
236
+ return any(
237
+ ConfigInformation.is_generated_value(argument, x)
238
+ for x in value.values()
239
+ )
240
+
241
+ return False
242
+
195
243
  def set(self, k, v, bypass=False):
196
244
  from experimaestro.generators import Generator
197
245
 
@@ -208,18 +256,16 @@ class ConfigInformation:
208
256
  "Configuration (and not objects) should be used. Consider using .C(...)"
209
257
  )
210
258
 
211
- if (
212
- isinstance(v, ConfigMixin)
213
- and v.__xpm__._has_generated_value
214
- and v.__xpm__.task is None
215
- ):
216
- raise AttributeError(
217
- f"Cannot set {k} to a configuration with generated values"
218
- )
219
-
220
259
  try:
221
260
  argument = self.xpmtype.arguments.get(k, None)
222
261
  if argument:
262
+ if ConfigInformation.is_generated_value(argument, v):
263
+ raise AttributeError(
264
+ f"Cannot set {k} to a configuration with generated values. "
265
+ "Here is the list of paths to help you: "
266
+ f"""{', '.join(v.__xpm__.get_generated_paths([k]))}"""
267
+ )
268
+
223
269
  if not bypass and (
224
270
  (isinstance(argument.generator, Generator)) or argument.constant
225
271
  ):
@@ -345,6 +391,15 @@ class ConfigInformation:
345
391
  Arguments:
346
392
  - context: the generation context
347
393
  """
394
+ if generated_keys := [
395
+ k
396
+ for k, v in self.values.items()
397
+ if ConfigInformation.is_generated_value(self.xpmtype.arguments[k], v)
398
+ ]:
399
+ raise AttributeError(
400
+ "Cannot seal a configuration with generated values:"
401
+ f"""{",".join(generated_keys)} in {context.currentpath}"""
402
+ )
348
403
 
349
404
  class Sealer(ConfigWalk):
350
405
  def preprocess(self, config: ConfigMixin):
@@ -368,13 +423,15 @@ class ConfigInformation:
368
423
  if len(sig.parameters) == 0:
369
424
  value = argument.generator()
370
425
  elif len(sig.parameters) == 2:
426
+ # Only in that case do we need to flag this configuration
427
+ # as containing generated values
428
+ config.__xpm__._generated_values.append(k)
371
429
  value = argument.generator(self.context, config)
372
430
  else:
373
431
  assert (
374
432
  False
375
433
  ), "generator has either two parameters (context and config), or none"
376
434
  config.__xpm__.set(k, value, bypass=True)
377
- config.__xpm__._has_generated_value = True
378
435
  else:
379
436
  value = config.__xpm__.values.get(k)
380
437
  except Exception:
@@ -387,9 +444,9 @@ class ConfigInformation:
387
444
  if (
388
445
  (value is not None)
389
446
  and isinstance(value, ConfigMixin)
390
- and value.__xpm__._has_generated_value
447
+ and value.__xpm__._generated_values
391
448
  ):
392
- self._has_generated_value = True
449
+ config.__xpm__._generated_values.append(k)
393
450
 
394
451
  config.__xpm__._sealed = True
395
452
 
@@ -71,6 +71,7 @@ class ConfigWalk:
71
71
  return self.context.push(str(i))
72
72
 
73
73
  def map(self, k: str):
74
+ """Provides a path context when processing a tree"""
74
75
  return self.context.push(k)
75
76
 
76
77
  def stub(self, config):
@@ -123,7 +124,8 @@ class ConfigWalk:
123
124
  and self.recurse_task
124
125
  and x.__xpm__.task is not x
125
126
  ):
126
- self(x.__xpm__.task)
127
+ with self.map("__task__"):
128
+ self(x.__xpm__.task)
127
129
 
128
130
  processed = self.postprocess(stub, x, result)
129
131
  self.visited[xid] = processed
@@ -0,0 +1,93 @@
1
+ from experimaestro import Config, Task, Param, Meta, Path, field, PathGenerator
2
+ from experimaestro.scheduler.workspace import Workspace
3
+ from experimaestro.settings import Settings, WorkspaceSettings
4
+ import pytest
5
+ from experimaestro.scheduler import RunMode
6
+
7
+
8
+ class Validation(Config):
9
+ best_checkpoint: Meta[Path] = field(default_factory=PathGenerator("index"))
10
+
11
+
12
+ class Learner(Task):
13
+ validation: Param[Validation]
14
+ x: Param[int]
15
+
16
+ @staticmethod
17
+ def create(x: int, validation: Param[Validation]):
18
+ return Learner.C(x=x, validation=validation)
19
+
20
+
21
+ class LearnerList(Task):
22
+ validation: Param[list[Validation]]
23
+ x: Param[int]
24
+
25
+ @staticmethod
26
+ def create(x: int, validation: Param[Validation]):
27
+ return LearnerList.C(x=x, validation=[validation])
28
+
29
+
30
+ class LearnerDict(Task):
31
+ validation: Param[dict[str, Validation]]
32
+ x: Param[int]
33
+
34
+ @staticmethod
35
+ def create(x: int, validation: Param[Validation]):
36
+ return LearnerDict.C(x=x, validation={"key": validation})
37
+
38
+
39
+ class ModuleLoader(Task):
40
+ validation: Param[Validation] = field(ignore_generated=True)
41
+
42
+
43
+ @pytest.mark.parametrize("cls", [Learner, LearnerDict, LearnerList])
44
+ def test_generators_reuse_on_submit(cls):
45
+ # We have one way to select the best model
46
+ validation = Validation.C()
47
+
48
+ workspace = Workspace(
49
+ Settings(),
50
+ WorkspaceSettings("test_generators_reuse", path=Path("/tmp")),
51
+ run_mode=RunMode.DRY_RUN,
52
+ )
53
+
54
+ # OK, the path is generated depending on Learner with x=1
55
+ cls.create(1, validation).submit(workspace=workspace)
56
+
57
+ with pytest.raises((AttributeError)):
58
+ # Here we have a problem...
59
+ # the path is still the previous one
60
+ cls.create(2, validation).submit(workspace=workspace)
61
+
62
+
63
+ @pytest.mark.parametrize("cls", [Learner, LearnerDict, LearnerList])
64
+ def test_generators_delayed_submit(cls):
65
+ workspace = Workspace(
66
+ Settings(),
67
+ WorkspaceSettings("test_generators_simple", path=Path("/tmp")),
68
+ run_mode=RunMode.DRY_RUN,
69
+ )
70
+ validation = Validation.C()
71
+ task1 = cls.create(1, validation)
72
+ task2 = cls.create(2, validation)
73
+ task1.submit(workspace=workspace)
74
+ with pytest.raises((AttributeError)):
75
+ task2.submit(workspace=workspace)
76
+
77
+
78
+ @pytest.mark.parametrize("cls", [Learner, LearnerDict, LearnerList])
79
+ def test_generators_reuse_on_set(cls):
80
+ workspace = Workspace(
81
+ Settings(),
82
+ WorkspaceSettings("test_generators_simple", path=Path("/tmp")),
83
+ run_mode=RunMode.DRY_RUN,
84
+ )
85
+ validation = Validation.C()
86
+ cls.create(1, validation).submit(workspace=workspace)
87
+ with pytest.raises((AttributeError)):
88
+ # We should not be able to *create* a second task with the same validation,
89
+ # even without submitting it
90
+ cls.create(2, validation)
91
+
92
+ # This should run OK
93
+ ModuleLoader.C(validation=validation)
@@ -1,33 +0,0 @@
1
- from experimaestro import Config, Task, Param, Meta, Path, field, PathGenerator
2
- from experimaestro.scheduler.workspace import Workspace
3
- from experimaestro.settings import Settings, WorkspaceSettings
4
- import pytest
5
- from experimaestro.scheduler import RunMode
6
-
7
-
8
- class Validation(Config):
9
- best_checkpoint: Meta[Path] = field(default_factory=PathGenerator("index"))
10
-
11
-
12
- class Learner(Task):
13
- validation: Param[Validation]
14
- x: Param[int]
15
-
16
-
17
- def test_generators_reuse():
18
- # We have one way to select the best model
19
- validation = Validation.C()
20
-
21
- workspace = Workspace(
22
- Settings(),
23
- WorkspaceSettings("test_generators_reuse", path=Path("/tmp")),
24
- run_mode=RunMode.DRY_RUN,
25
- )
26
-
27
- # OK, the path is generated depending on Learner with x=1
28
- Learner.C(x=1, validation=validation).submit(workspace=workspace)
29
-
30
- with pytest.raises((AttributeError)):
31
- # Here we have a problem...
32
- # the path is still the previous one
33
- Learner.C(x=2, validation=validation).submit(workspace=workspace)
File without changes
File without changes